4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <linux/lustre/lustre_ver.h>
69 #include <linux/lustre/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--component-end|-E <comp_end>]\n" \
117 " [--stripe-count|-c <stripe_count>]\n" \
118 " [--stripe-index|-i <start_ost_idx>]\n" \
119 " [--stripe-size|-S <stripe_size>]\n" \
120 " [--layout|-L <pattern>]\n" \
121 " [--pool|-p <pool_name>]\n" \
122 " [--ost|-o <ost_indices>]\n"
124 #define SSM_HELP_COMMON \
125 "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
126 "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
127 "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \
128 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
129 "\t respectively)\n" \
130 "\tpool_name: Name of OST pool to use (default none)\n" \
131 "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\
132 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
133 "\t Indices be specified in a format of:\n" \
134 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
136 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
137 "\t If --pool is set with --ost, then the OSTs\n" \
138 "\t must be the members of the pool.\n" \
139 "\tcomp_end: Extent end of component, start after previous end.\n"\
140 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
141 "\t respectively, -1 for EOF). Must be a multiple of\n"\
145 #define MIGRATE_USAGE \
146 SSM_CMD_COMMON("migrate ") \
148 " [--non-block|-n]\n" \
152 "\tblock: Block file access during data migration (default)\n" \
153 "\tnon-block: Abort migrations if concurrent access is detected\n" \
155 #define SETDIRSTRIPE_USAGE \
156 " [--mdt-count|-c stripe_count>\n" \
157 " [--mdt-index|-i mdt_index]\n" \
158 " [--mdt-hash|-H mdt_hash]\n" \
159 " [--default|-D] [--mode|-m mode] <dir>\n" \
160 "\tstripe_count: stripe count of the striped directory\n" \
161 "\tmdt_index: MDT index of first stripe\n" \
162 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
163 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
164 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
165 "\tdefault_stripe: set default dirstripe of the directory\n" \
166 "\tmode: the mode of the directory\n"
168 static const char *progname;
169 static bool file_lease_supported = true;
171 /* all available commands */
172 command_t cmdlist[] = {
173 {"setstripe", lfs_setstripe, 0,
174 "To create a file with specified striping/composite layout, or\n"
175 "create/replace the default layout on an existing directory:\n"
176 SSM_CMD_COMMON("setstripe")
177 " <directory|filename>\n"
179 "To add component(s) to an existing composite file:\n"
180 SSM_CMD_COMMON("setstripe --component-add")
182 "To totally delete the default striping from an existing directory:\n"
183 "usage: setstripe -d <directory>\n"
185 "To delete the last component(s) from an existing composite file\n"
186 "(note that this will also delete any data in those components):\n"
187 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
188 " [--component-flags|-F <comp_flags>]\n"
190 "\tcomp_id: Unique component ID to delete\n"
191 "\tcomp_flags: 'init' indicating all instantiated components\n"
192 "\t '^init' indicating all uninstantiated components\n"
193 "\t-I and -F cannot be specified at the same time\n"},
194 {"getstripe", lfs_getstripe, 0,
195 "To list the striping info for a given file or files in a\n"
196 "directory or recursively for all files in a directory tree.\n"
197 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
198 " [--stripe-count|-c] [--stripe-index|-i]\n"
199 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
200 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
201 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
202 " [--component-id[=comp_id]|-I[comp_id]]\n"
203 " [--component-flags[=comp_flags]]\n"
204 " [--component-count]\n"
205 " [--component-start[=[+-]comp_start]]\n"
206 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
207 " <directory|filename> ..."},
208 {"setdirstripe", lfs_setdirstripe, 0,
209 "To create a striped directory on a specified MDT. This can only\n"
210 "be done on MDT0 with the right of administrator.\n"
211 "usage: setdirstripe [OPTION] <directory>\n"
213 {"getdirstripe", lfs_getdirstripe, 0,
214 "To list the striping info for a given directory\n"
215 "or recursively for all directories in a directory tree.\n"
216 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
217 " [--mdt-index|-i] [--mdt-hash|-t]\n"
218 " [--recursive|-r] [--yaml|-y]\n"
219 " [--default|-D] <dir> ..."},
220 {"mkdir", lfs_setdirstripe, 0,
221 "To create a striped directory on a specified MDT. This can only\n"
222 "be done on MDT0 with the right of administrator.\n"
223 "usage: mkdir [OPTION] <directory>\n"
225 {"rm_entry", lfs_rmentry, 0,
226 "To remove the name entry of the remote directory. Note: This\n"
227 "command will only delete the name entry, i.e. the remote directory\n"
228 "will become inaccessable after this command. This can only be done\n"
229 "by the administrator\n"
230 "usage: rm_entry <dir>\n"},
231 {"pool_list", lfs_poollist, 0,
232 "List pools or pool OSTs\n"
233 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
234 {"find", lfs_find, 0,
235 "find files matching given attributes recursively in directory tree.\n"
236 "usage: find <directory|filename> ...\n"
237 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
238 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
239 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
240 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
241 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
242 " [[!] --stripe-count|-c [+-]<stripes>]\n"
243 " [[!] --stripe-index|-i <index,...>]\n"
244 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
245 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
246 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
247 " [[!] --projid <projid>]\n"
248 " [[!] --layout|-L released,raid0,mdt]\n"
249 " [[!] --component-count [+-]<comp_cnt>]\n"
250 " [[!] --component-start [+-]N[kMGTPE]]\n"
251 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
252 " [[!] --component-flags <comp_flags>]\n"
253 " [[!] --mdt-count|-T [+-]<stripes>]\n"
254 " [[!] --mdt-hash|-H <hashtype>\n"
255 "\t !: used before an option indicates 'NOT' requested attribute\n"
256 "\t -: used before a value indicates less than requested value\n"
257 "\t +: used before a value indicates more than requested value\n"
258 "\tmdt-hash: hash type of the striped directory.\n"
259 "\t fnv_1a_64 FNV-1a hash algorithm\n"
260 "\t all_char sum of characters % MDT_COUNT\n"},
261 {"check", lfs_check, 0,
262 "Display the status of MDS or OSTs (as specified in the command)\n"
263 "or all the servers (MDS and OSTs).\n"
264 "usage: check <osts|mds|servers>"},
265 {"osts", lfs_osts, 0, "list OSTs connected to client "
266 "[for specified path only]\n" "usage: osts [path]"},
267 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
268 "[for specified path only]\n" "usage: mdts [path]"},
270 "report filesystem disk space usage or inodes usage"
271 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
272 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
273 {"getname", lfs_getname, 0, "list instances and specified mount points "
274 "[for specified path only]\n"
275 "Usage: getname [-h]|[path ...] "},
276 #ifdef HAVE_SYS_QUOTA_H
277 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
278 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
279 " -b <block-softlimit> -B <block-hardlimit>\n"
280 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
281 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
282 " [--block-softlimit <block-softlimit>]\n"
283 " [--block-hardlimit <block-hardlimit>]\n"
284 " [--inode-softlimit <inode-softlimit>]\n"
285 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
286 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
287 " [--block-grace <block-grace>]\n"
288 " [--inode-grace <inode-grace>] <filesystem>\n"
289 " -b can be used instead of --block-softlimit/--block-grace\n"
290 " -B can be used instead of --block-hardlimit\n"
291 " -i can be used instead of --inode-softlimit/--inode-grace\n"
292 " -I can be used instead of --inode-hardlimit\n\n"
293 "Note: The total quota space will be split into many qunits and\n"
294 " balanced over all server targets, the minimal qunit size is\n"
295 " 1M bytes for block space and 1K inodes for inode space.\n\n"
296 " Quota space rebalancing process will stop when this mininum\n"
297 " value is reached. As a result, quota exceeded can be returned\n"
298 " while many targets still have 1MB or 1K inodes of spare\n"
300 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
301 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
303 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
304 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
306 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
307 "usage: flushctx [-k] [mountpoint...]"},
309 "Remote user copy files and directories.\n"
310 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
312 "Remote user list directory contents.\n"
313 "usage: ls [OPTION]... [FILE]..."},
314 {"changelog", lfs_changelog, 0,
315 "Show the metadata changes on an MDT."
316 "\nusage: changelog <mdtname> [startrec [endrec]]"},
317 {"changelog_clear", lfs_changelog_clear, 0,
318 "Indicate that old changelog records up to <endrec> are no longer of "
319 "interest to consumer <id>, allowing the system to free up space.\n"
320 "An <endrec> of 0 means all records.\n"
321 "usage: changelog_clear <mdtname> <id> <endrec>"},
322 {"fid2path", lfs_fid2path, 0,
323 "Resolve the full path(s) for given FID(s). For a specific hardlink "
324 "specify link number <linkno>.\n"
325 /* "For a historical link name, specify changelog record <recno>.\n" */
326 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
327 /* [ --rec <recno> ] */ },
328 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
329 "usage: path2fid [--parents] <path> ..."},
330 {"data_version", lfs_data_version, 0, "Display file data version for "
331 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
332 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
333 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
334 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
335 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
336 "[--archived] [--lost] <file> ..."},
337 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
339 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
340 "[--archived] [--lost] <file> ..."},
341 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
342 "given files.\n" "usage: hsm_action <file> ..."},
343 {"hsm_archive", lfs_hsm_archive, 0,
344 "Archive file to external storage.\n"
345 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
347 {"hsm_restore", lfs_hsm_restore, 0,
348 "Restore file from external storage.\n"
349 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
350 {"hsm_release", lfs_hsm_release, 0,
351 "Release files from Lustre.\n"
352 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
353 {"hsm_remove", lfs_hsm_remove, 0,
354 "Remove file copy from external storage.\n"
355 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
356 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
358 "Note: To remove files from the archive that have been deleted on\n"
359 "Lustre, set mntpath and optionally archive. In that case, all the\n"
360 "positional arguments and entries in the file list must be FIDs."
362 {"hsm_cancel", lfs_hsm_cancel, 0,
363 "Cancel requests related to specified files.\n"
364 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
365 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
366 "usage: swap_layouts <path1> <path2>"},
367 {"migrate", lfs_setstripe, 0,
368 "migrate a directory between MDTs.\n"
369 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
371 "\tmdt_idx: index of the destination MDT\n"
373 "migrate file objects from one OST "
374 "layout\nto another (may be not safe with concurent writes).\n"
376 "[--stripe-count|-c] <stripe_count>\n"
377 " [--stripe-index|-i] <start_ost_index>\n"
378 " [--stripe-size|-S] <stripe_size>\n"
379 " [--pool|-p] <pool_name>\n"
380 " [--ost-list|-o] <ost_indices>\n"
382 " [--non-block|-n]\n"
383 " <file|directory>\n"
384 "\tstripe_count: number of OSTs to stripe a file over\n"
385 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
386 "\tstripe_size: number of bytes to store before moving to the next OST\n"
387 "\tpool_name: name of the predefined pool of OSTs\n"
388 "\tost_indices: OSTs to stripe over, in order\n"
389 "\tblock: wait for the operation to return before continuing\n"
390 "\tnon-block: do not wait for the operation to return.\n"},
392 "To move directories between MDTs. This command is deprecated, "
393 "use \"migrate\" instead.\n"
394 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
396 {"ladvise", lfs_ladvise, 0,
397 "Provide servers with advice about access patterns for a file.\n"
398 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
399 " [--background|-b] [--unset|-u]\n\n"
400 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
401 " {[--mode|-m [READ,WRITE]}\n"
403 {"help", Parser_help, 0, "help"},
404 {"exit", Parser_quit, 0, "quit"},
405 {"quit", Parser_quit, 0, "quit"},
406 {"--version", Parser_version, 0,
407 "output build version of the utility and exit"},
408 {"--list-commands", lfs_list_commands, 0,
409 "list commands supported by the utility and exit"},
414 #define MIGRATION_NONBLOCK 1
416 static int check_hashtype(const char *hashtype)
420 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
421 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
428 * Internal helper for migrate_copy_data(). Check lease and report error if
431 * \param[in] fd File descriptor on which to check the lease.
432 * \param[out] lease_broken Set to true if the lease was broken.
433 * \param[in] group_locked Whether a group lock was taken or not.
434 * \param[in] path Name of the file being processed, for error
437 * \retval 0 Migration can keep on going.
438 * \retval -errno Error occurred, abort migration.
440 static int check_lease(int fd, bool *lease_broken, bool group_locked,
445 if (!file_lease_supported)
448 rc = llapi_lease_check(fd);
450 return 0; /* llapi_check_lease returns > 0 on success. */
453 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
455 rc = rc ? rc : -EAGAIN;
457 fprintf(stderr, "%s: external attempt to access file '%s' "
458 "blocked until migration ends.\n", progname, path);
461 *lease_broken = true;
465 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
466 bool group_locked, const char *fname)
475 bool lease_broken = false;
477 /* Use a page-aligned buffer for direct I/O */
478 rc = posix_memalign(&buf, getpagesize(), buf_size);
483 /* read new data only if we have written all
484 * previously read data */
487 rc = check_lease(fd_src, &lease_broken,
488 group_locked, fname);
492 rsize = read(fd_src, buf, buf_size);
495 fprintf(stderr, "%s: %s: read failed: %s\n",
496 progname, fname, strerror(-rc));
506 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
510 "%s: %s: write failed on volatile: %s\n",
511 progname, fname, strerror(-rc));
521 fprintf(stderr, "%s: %s: fsync failed: %s\n",
522 progname, fname, strerror(-rc));
530 static int migrate_copy_timestamps(int fdv, const struct stat *st)
532 struct timeval tv[2] = {
533 {.tv_sec = st->st_atime},
534 {.tv_sec = st->st_mtime}
537 return futimes(fdv, tv);
540 static int migrate_block(int fd, int fdv, const struct stat *st,
541 size_t buf_size, const char *name)
548 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
550 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
551 progname, name, strerror(-rc));
559 /* The grouplock blocks all concurrent accesses to the file.
560 * It has to be taken after llapi_get_data_version as it would
562 rc = llapi_group_lock(fd, gid);
564 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
565 progname, name, strerror(-rc));
569 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
571 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
575 /* Make sure we keep original atime/mtime values */
576 rc = migrate_copy_timestamps(fdv, st);
578 fprintf(stderr, "%s: %s: timestamp copy failed\n",
584 * for a migration we need to check data version on file did
587 * Pass in gid=0 since we already own grouplock. */
588 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
589 SWAP_LAYOUTS_CHECK_DV1);
591 fprintf(stderr, "%s: %s: dataversion changed during copy, "
592 "migration aborted\n", progname, name);
595 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
596 name, strerror(-rc));
601 rc2 = llapi_group_unlock(fd, gid);
602 if (rc2 < 0 && rc == 0) {
603 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
604 progname, name, strerror(-rc2));
611 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
612 size_t buf_size, const char *name)
618 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
620 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
621 progname, name, strerror(-rc));
625 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
627 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
631 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
633 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
634 progname, name, strerror(-rc));
640 fprintf(stderr, "%s: %s: data version changed during "
646 /* Make sure we keep original atime/mtime values */
647 rc = migrate_copy_timestamps(fdv, st);
649 fprintf(stderr, "%s: %s: timestamp copy failed\n",
654 /* Atomically put lease, swap layouts and close.
655 * for a migration we need to check data version on file did
657 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
659 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
660 progname, name, strerror(-rc));
667 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
672 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
676 if (flags != 0 && comp_id != 0)
679 /* LCME_FL_INIT is the only supported flag in PFL */
681 if (flags & ~LCME_KNOWN_FLAGS) {
682 fprintf(stderr, "Invalid component flags %#x\n", flags);
685 } else if (comp_id > LCME_ID_MAX) {
686 fprintf(stderr, "Invalid component id %u\n", comp_id);
690 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
692 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
693 comp_id, fname, strerror(errno));
697 static int lfs_component_add(char *fname, struct llapi_layout *layout)
704 rc = llapi_layout_file_comp_add(fname, layout);
706 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
707 fname, strerror(errno));
711 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
712 struct llapi_layout *layout)
720 fd = lstat(fname, &st);
721 if (fd == 0 && S_ISDIR(st.st_mode))
722 open_flags = O_DIRECTORY | O_RDONLY;
724 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
726 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
727 S_ISDIR(st.st_mode) ?
728 "set default composite layout for" :
729 "create composite file",
730 fname, strerror(errno));
734 static int lfs_migrate(char *name, __u64 migration_flags,
735 struct llapi_stripe_param *param,
736 struct llapi_layout *layout)
740 char parent[PATH_MAX];
743 char volatile_file[sizeof(parent) +
744 LUSTRE_VOLATILE_HDR_LEN +
745 2 * sizeof(mdt_index) +
746 2 * sizeof(random_value) + 4];
749 struct lov_user_md *lum = NULL;
751 int buf_size = 1024 * 1024 * 4;
752 bool have_lease_rdlck = false;
756 /* find the right size for the IO and allocate the buffer */
757 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
758 lum = malloc(lum_size);
764 rc = llapi_file_get_stripe(name, lum);
765 /* failure can happen for many reasons and some may be not real errors
767 * in case of a real error, a later call will fail with better
768 * error management */
770 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
771 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
772 lum->lmm_stripe_size != 0)
773 buf_size = lum->lmm_stripe_size;
776 /* open file, direct io */
777 /* even if the file is only read, WR mode is nedeed to allow
778 * layout swap on fd */
779 fd = open(name, O_RDWR | O_DIRECT);
782 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, name,
787 if (file_lease_supported) {
788 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
789 if (rc == -EOPNOTSUPP) {
790 /* Older servers do not support file lease.
791 * Disable related checks. This opens race conditions
792 * as explained in LU-4840 */
793 file_lease_supported = false;
795 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
796 progname, name, strerror(-rc));
799 have_lease_rdlck = true;
803 /* search for file directory pathname */
804 if (strlen(name) > sizeof(parent)-1) {
808 strncpy(parent, name, sizeof(parent));
809 ptr = strrchr(parent, '/');
811 if (getcwd(parent, sizeof(parent)) == NULL) {
822 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
824 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
825 progname, name, strerror(-rc));
830 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
831 mode_t open_mode = S_IRUSR | S_IWUSR;
833 random_value = random();
834 rc = snprintf(volatile_file, sizeof(volatile_file),
835 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
836 mdt_index, random_value);
837 if (rc >= sizeof(volatile_file)) {
842 /* create, open a volatile file, use caching (ie no directio) */
844 fdv = llapi_file_open_param(volatile_file, open_flags,
846 else if (layout != NULL)
847 fdv = lfs_component_create(volatile_file, open_flags,
851 } while (fdv == -EEXIST);
855 fprintf(stderr, "%s: %s: cannot create volatile file in"
857 progname, parent, strerror(-rc));
861 /* In case the MDT does not support creation of volatile files
862 * we should try to unlink it. */
863 (void)unlink(volatile_file);
865 /* Not-owner (root?) special case.
866 * Need to set owner/group of volatile file like original.
867 * This will allow to pass related check during layout_swap.
872 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
876 rc = fstat(fdv, &stv);
879 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
880 volatile_file, strerror(errno));
883 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
884 rc = fchown(fdv, st.st_uid, st.st_gid);
887 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
888 name, strerror(errno));
893 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
894 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
896 have_lease_rdlck = false;
897 fdv = -1; /* The volatile file is closed as we put the
898 * lease in non-blocking mode. */
901 /* Blocking mode (forced if servers do not support file lease).
902 * It is also the default mode, since we cannot distinguish
903 * between a broken lease and a server that does not support
904 * atomic swap/close (LU-6785) */
905 rc = migrate_block(fd, fdv, &st, buf_size, name);
909 if (have_lease_rdlck)
926 * Parse a string containing an OST index list into an array of integers.
928 * The input string contains a comma delimited list of individual
929 * indices and ranges, for example "1,2-4,7". Add the indices into the
930 * \a osts array and remove duplicates.
932 * \param[out] osts array to store indices in
933 * \param[in] size size of \a osts array
934 * \param[in] offset starting index in \a osts
935 * \param[in] arg string containing OST index list
937 * \retval positive number of indices in \a osts
938 * \retval -EINVAL unable to parse \a arg
940 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
944 int slots = size - offset;
952 while (!end_of_loop) {
960 ptr = strchrnul(arg, ',');
962 end_of_loop = *ptr == '\0';
965 start_index = strtol(arg, &endptr, 0);
966 if (endptr == arg) /* no data at all */
968 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
973 end_index = start_index;
974 if (*endptr == '-') {
975 end_index = strtol(endptr + 1, &endptr, 0);
978 if (end_index < start_index)
982 for (i = start_index; i <= end_index && slots > 0; i++) {
985 /* remove duplicate */
986 for (j = 0; j < offset; j++) {
990 if (j == offset) { /* no duplicate */
995 if (slots == 0 && i < end_index)
1003 if (!end_of_loop && ptr != NULL)
1006 return rc < 0 ? rc : nr;
1009 struct lfs_setstripe_args {
1010 unsigned long long lsa_comp_end;
1011 unsigned long long lsa_stripe_size;
1012 int lsa_stripe_count;
1014 __u32 lsa_comp_flags;
1018 char *lsa_pool_name;
1021 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1023 memset(lsa, 0, sizeof(*lsa));
1024 lsa->lsa_stripe_off = -1;
1027 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1029 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1030 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1031 lsa->lsa_comp_end != 0 || lsa->lsa_pattern != 0);
1034 static int comp_args_to_layout(struct llapi_layout **composite,
1035 struct lfs_setstripe_args *lsa)
1037 struct llapi_layout *layout = *composite;
1038 uint64_t prev_end = 0;
1041 if (layout == NULL) {
1042 layout = llapi_layout_alloc();
1043 if (layout == NULL) {
1044 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1048 *composite = layout;
1052 /* Get current component extent, current component
1053 * must be the tail component. */
1054 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1056 fprintf(stderr, "Get comp extent failed. %s\n",
1061 rc = llapi_layout_comp_add(layout);
1063 fprintf(stderr, "Add component failed. %s\n",
1069 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1071 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1072 prev_end, lsa->lsa_comp_end, strerror(errno));
1076 /* Data-on-MDT component setting */
1077 if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1078 /* In case of Data-on-MDT patterns the only extra option
1079 * applicable is stripe size option. */
1080 if (lsa->lsa_stripe_count) {
1081 fprintf(stderr, "Option 'stripe-count' can't be "
1082 "specified with Data-on-MDT component: %i\n",
1083 lsa->lsa_stripe_count);
1086 if (lsa->lsa_stripe_size) {
1087 fprintf(stderr, "Option 'stripe-size' can't be "
1088 "specified with Data-on-MDT component: %llu\n",
1089 lsa->lsa_stripe_size);
1092 if (lsa->lsa_nr_osts != 0) {
1093 fprintf(stderr, "Option 'ost-list' can't be specified "
1094 "with Data-on-MDT component: '%i'\n",
1098 if (lsa->lsa_stripe_off != -1) {
1099 fprintf(stderr, "Option 'stripe-offset' can't be "
1100 "specified with Data-on-MDT component: %i\n",
1101 lsa->lsa_stripe_off);
1104 if (lsa->lsa_pool_name != 0) {
1105 fprintf(stderr, "Option 'pool' can't be specified "
1106 "with Data-on-MDT component: '%s'\n",
1107 lsa->lsa_pool_name);
1111 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1113 fprintf(stderr, "Set stripe pattern %#x failed. %s\n",
1114 lsa->lsa_pattern, strerror(errno));
1117 /* Data-on-MDT component has always single stripe up to end */
1118 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1121 if (lsa->lsa_stripe_size != 0) {
1122 rc = llapi_layout_stripe_size_set(layout,
1123 lsa->lsa_stripe_size);
1125 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1126 lsa->lsa_stripe_size, strerror(errno));
1131 if (lsa->lsa_stripe_count != 0) {
1132 rc = llapi_layout_stripe_count_set(layout,
1133 lsa->lsa_stripe_count == -1 ?
1135 lsa->lsa_stripe_count);
1137 fprintf(stderr, "Set stripe count %d failed. %s\n",
1138 lsa->lsa_stripe_count, strerror(errno));
1143 if (lsa->lsa_pool_name != NULL) {
1144 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1146 fprintf(stderr, "Set pool name: %s failed. %s\n",
1147 lsa->lsa_pool_name, strerror(errno));
1152 if (lsa->lsa_nr_osts > 0) {
1153 if (lsa->lsa_stripe_count > 0 &&
1154 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1155 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1156 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1159 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1160 rc = llapi_layout_ost_index_set(layout, i,
1165 } else if (lsa->lsa_stripe_off != -1) {
1166 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1169 fprintf(stderr, "Set ost index %d failed. %s\n",
1170 i, strerror(errno));
1177 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1178 * end of the last component in the existing file, and adjust the
1179 * first extent start of the components to be added accordingly. */
1180 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1182 struct llapi_layout *head;
1183 uint64_t start, end, stripe_size, prev_end = 0;
1190 head = llapi_layout_get_by_path(fname, 0);
1192 fprintf(stderr, "Read layout from %s failed. %s\n",
1193 fname, strerror(errno));
1195 } else if (errno == ENODATA) {
1196 /* file without LOVEA, this component-add will be turned
1197 * into a component-create. */
1198 llapi_layout_free(head);
1200 } else if (!llapi_layout_is_composite(head)) {
1201 fprintf(stderr, "'%s' isn't a composite file.\n",
1203 llapi_layout_free(head);
1207 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1209 fprintf(stderr, "Get prev extent failed. %s\n",
1211 llapi_layout_free(head);
1215 llapi_layout_free(head);
1217 /* Make sure we use the first component of the layout to be added. */
1218 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1220 fprintf(stderr, "Move component cursor failed. %s\n",
1225 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1227 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1231 if (start > prev_end || end <= prev_end) {
1232 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1233 "adjacent with the existing file extent end: %lu\n",
1234 start, end, prev_end);
1238 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1240 fprintf(stderr, "Get stripe size failed. %s\n",
1245 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1246 (prev_end & (stripe_size - 1))) {
1247 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1248 stripe_size, prev_end);
1252 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1254 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1255 prev_end, end, strerror(errno));
1262 static inline bool comp_flags_is_neg(__u32 flags)
1264 return flags & LCME_FL_NEG;
1267 static inline void comp_flags_set_neg(__u32 *flags)
1269 *flags |= LCME_FL_NEG;
1272 static inline void comp_flags_clear_neg(__u32 *flags)
1274 *flags &= ~LCME_FL_NEG;
1277 static int comp_str2flags(__u32 *flags, char *string)
1280 __u32 neg_flags = 0;
1286 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1290 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1291 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1292 const char *comp_name = comp_flags_table[i].cfn_name;
1294 if (strcmp(name, comp_name) == 0) {
1295 *flags |= comp_flag;
1297 } else if (strncmp(name, "^", 1) == 0 &&
1298 strcmp(name + 1, comp_name) == 0) {
1299 neg_flags |= comp_flag;
1304 llapi_printf(LLAPI_MSG_ERROR,
1305 "%s: component flag '%s' not supported\n",
1311 if (*flags == 0 && neg_flags == 0)
1313 /* don't support mixed flags for now */
1314 if (*flags && neg_flags)
1319 comp_flags_set_neg(flags);
1325 static inline bool arg_is_eof(char *arg)
1327 return !strncmp(arg, "-1", strlen("-1")) ||
1328 !strncmp(arg, "EOF", strlen("EOF")) ||
1329 !strncmp(arg, "eof", strlen("eof"));
1344 static int lfs_setstripe(int argc, char **argv)
1346 struct lfs_setstripe_args lsa;
1347 struct llapi_stripe_param *param = NULL;
1348 struct find_param migrate_mdt_param = {
1358 char *mdt_idx_arg = NULL;
1359 unsigned long long size_units = 1;
1360 bool migrate_mode = false;
1361 bool migration_block = false;
1362 __u64 migration_flags = 0;
1363 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1364 int comp_del = 0, comp_set = 0;
1367 struct llapi_layout *layout = NULL;
1369 struct option long_opts[] = {
1370 /* --block is only valid in migrate mode */
1371 { .val = 'b', .name = "block", .has_arg = no_argument},
1372 { .val = LFS_COMP_ADD_OPT,
1373 .name = "comp-add", .has_arg = no_argument},
1374 { .val = LFS_COMP_ADD_OPT,
1375 .name = "component-add",
1376 .has_arg = no_argument},
1377 { .val = LFS_COMP_DEL_OPT,
1378 .name = "comp-del", .has_arg = no_argument},
1379 { .val = LFS_COMP_DEL_OPT,
1380 .name = "component-del",
1381 .has_arg = no_argument},
1382 { .val = LFS_COMP_FLAGS_OPT,
1383 .name = "comp-flags", .has_arg = required_argument},
1384 { .val = LFS_COMP_FLAGS_OPT,
1385 .name = "component-flags",
1386 .has_arg = required_argument},
1387 { .val = LFS_COMP_SET_OPT,
1388 .name = "comp-set", .has_arg = no_argument},
1389 { .val = LFS_COMP_SET_OPT,
1390 .name = "component-set",
1391 .has_arg = no_argument},
1392 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1393 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1394 { .val = 'd', .name = "delete", .has_arg = no_argument},
1395 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1396 { .val = 'E', .name = "component-end",
1397 .has_arg = required_argument},
1398 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1399 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1400 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1401 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1402 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1403 { .val = 'L', .name = "layout", .has_arg = required_argument },
1404 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1405 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1406 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1407 /* --non-block is only valid in migrate mode */
1408 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1409 { .val = 'o', .name = "ost", .has_arg = required_argument},
1410 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1411 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1412 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1414 { .val = 'p', .name = "pool", .has_arg = required_argument },
1415 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1416 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1417 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1418 /* --verbose is only valid in migrate mode */
1419 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1420 { .val = LFS_COMP_ADD_OPT,
1421 .name = "component-add",
1422 .has_arg = no_argument },
1423 { .val = LFS_COMP_DEL_OPT,
1424 .name = "component-del",
1425 .has_arg = no_argument },
1426 { .val = LFS_COMP_FLAGS_OPT,
1427 .name = "component-flags",
1428 .has_arg = required_argument },
1429 { .val = LFS_COMP_SET_OPT,
1430 .name = "component-set",
1431 .has_arg = no_argument },
1434 setstripe_args_init(&lsa);
1436 if (strcmp(argv[0], "migrate") == 0)
1437 migrate_mode = true;
1439 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:L:s:S:v",
1440 long_opts, NULL)) >= 0) {
1445 case LFS_COMP_ADD_OPT:
1448 case LFS_COMP_DEL_OPT:
1451 case LFS_COMP_FLAGS_OPT:
1452 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1456 case LFS_COMP_SET_OPT:
1460 if (!migrate_mode) {
1462 "%s %s: -b|--block valid only for migrate command\n",
1466 migration_block = true;
1469 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1472 "%s %s: invalid stripe count '%s'\n",
1473 progname, argv[0], optarg);
1478 /* delete the default striping pattern */
1482 if (lsa.lsa_comp_end != 0) {
1483 result = comp_args_to_layout(&layout, &lsa);
1486 "%s %s: invalid layout\n",
1491 setstripe_args_init(&lsa);
1494 if (arg_is_eof(optarg)) {
1495 lsa.lsa_comp_end = LUSTRE_EOF;
1497 result = llapi_parse_size(optarg,
1502 "%s %s: invalid component end '%s'\n",
1503 progname, argv[0], optarg);
1509 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1512 "%s %s: invalid stripe offset '%s'\n",
1513 progname, argv[0], optarg);
1518 comp_id = strtoul(optarg, &end, 0);
1519 if (*end != '\0' || comp_id == 0 ||
1520 comp_id > LCME_ID_MAX) {
1522 "%s %s: invalid component ID '%s'\n",
1523 progname, argv[0], optarg);
1528 if (strcmp(argv[optind - 1], "mdt") == 0) {
1529 /* Can be only the first component */
1530 if (layout != NULL) {
1532 fprintf(stderr, "error: 'mdt' layout "
1533 "can be only the first one\n");
1536 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
1538 fprintf(stderr, "error: 'mdt' layout "
1539 "size is too big\n");
1542 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
1543 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
1545 fprintf(stderr, "error: layout '%s' is "
1546 "unknown, supported layouts are: "
1547 "'mdt', 'raid0'\n", argv[optind]);
1552 if (!migrate_mode) {
1554 "%s %s: -m|--mdt-index valid only for migrate command\n",
1558 mdt_idx_arg = optarg;
1561 if (!migrate_mode) {
1563 "%s %s: -n|--non-block valid only for migrate command\n",
1567 migration_flags |= MIGRATION_NONBLOCK;
1570 lsa.lsa_nr_osts = parse_targets(osts,
1571 sizeof(osts) / sizeof(__u32),
1572 lsa.lsa_nr_osts, optarg);
1573 if (lsa.lsa_nr_osts < 0) {
1575 "%s %s: invalid OST target(s) '%s'\n",
1576 progname, argv[0], optarg);
1580 lsa.lsa_osts = osts;
1581 if (lsa.lsa_stripe_off == -1)
1582 lsa.lsa_stripe_off = osts[0];
1587 lsa.lsa_pool_name = optarg;
1590 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1594 "%s %s: invalid stripe size '%s'\n",
1595 progname, argv[0], optarg);
1600 if (!migrate_mode) {
1602 "%s %s: -v|--verbose valid only for migrate command\n",
1606 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1609 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
1610 progname, argv[0], argv[optind - 1]);
1615 fname = argv[optind];
1617 if (lsa.lsa_comp_end != 0) {
1618 result = comp_args_to_layout(&layout, &lsa);
1620 fprintf(stderr, "%s %s: invalid component layout\n",
1626 if (optind == argc) {
1627 fprintf(stderr, "%s %s: FILE must be specified\n",
1632 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1633 * altered by user space tool, so we don't need to support the
1634 * --component-set for this moment. */
1635 if (comp_set != 0) {
1636 fprintf(stderr, "%s %s: --component-set not supported\n",
1641 if ((delete + comp_set + comp_del + comp_add) > 1) {
1643 "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
1648 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1649 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1651 "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
1656 if ((comp_set || comp_del) &&
1657 (setstripe_args_specified(&lsa) || layout != NULL)) {
1659 "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
1664 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1666 "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
1671 if (comp_add || comp_del) {
1674 result = lstat(fname, &st);
1675 if (result == 0 && S_ISDIR(st.st_mode)) {
1677 "%s setstripe: cannot use --component-add or --component-del for directory\n",
1684 if (layout == NULL) {
1686 "%s %s: option -E must be specified with --component-add\n",
1690 result = adjust_first_extent(fname, layout);
1691 if (result == -ENODATA)
1693 else if (result != 0)
1697 if (mdt_idx_arg != NULL && optind > 3) {
1699 "%s %s: option -m cannot be used with other options\n",
1704 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1706 "%s %s: options --non-block and --block are mutually exclusive\n",
1711 if (!comp_del && !comp_set && comp_id != 0) {
1713 "%s %s: option -I can only be used with --component-del\n",
1718 if (mdt_idx_arg != NULL) {
1719 /* initialize migrate mdt parameters */
1720 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1722 fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
1723 progname, argv[0], mdt_idx_arg);
1726 migrate_mdt_param.fp_migrate = 1;
1727 } else if (layout == NULL) {
1728 /* initialize stripe parameters */
1729 param = calloc(1, offsetof(typeof(*param),
1730 lsp_osts[lsa.lsa_nr_osts]));
1731 if (param == NULL) {
1733 "%s %s: cannot allocate memory for parameters: %s\n",
1734 progname, argv[0], strerror(ENOMEM));
1739 param->lsp_stripe_size = lsa.lsa_stripe_size;
1740 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1741 param->lsp_stripe_count = lsa.lsa_stripe_count;
1742 param->lsp_pool = lsa.lsa_pool_name;
1743 param->lsp_is_specific = false;
1744 if (lsa.lsa_nr_osts > 0) {
1745 if (lsa.lsa_stripe_count > 0 &&
1746 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1748 "%s %s: stripe count '%d' does not match number of OSTs: %d\n",
1749 progname, argv[0], lsa.lsa_stripe_count,
1755 param->lsp_is_specific = true;
1756 param->lsp_stripe_count = lsa.lsa_nr_osts;
1757 memcpy(param->lsp_osts, osts,
1758 sizeof(*osts) * lsa.lsa_nr_osts);
1762 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1763 if (mdt_idx_arg != NULL) {
1764 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1765 } else if (migrate_mode) {
1766 result = lfs_migrate(fname, migration_flags, param,
1768 } else if (comp_set != 0) {
1769 result = lfs_component_set(fname, comp_id,
1770 lsa.lsa_comp_flags);
1771 } else if (comp_del != 0) {
1772 result = lfs_component_del(fname, comp_id,
1773 lsa.lsa_comp_flags);
1774 } else if (comp_add != 0) {
1775 result = lfs_component_add(fname, layout);
1776 } else if (layout != NULL) {
1777 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1784 result = llapi_file_open_param(fname,
1793 /* Save the first error encountered. */
1801 llapi_layout_free(layout);
1806 llapi_layout_free(layout);
1810 static int lfs_poollist(int argc, char **argv)
1815 return llapi_poollist(argv[1]);
1818 static int set_time(time_t *time, time_t *set, char *str)
1825 else if (str[0] == '-')
1831 t = strtol(str, NULL, 0);
1832 if (*time < t * 24 * 60 * 60) {
1835 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1839 *set = *time - t * 24 * 60 * 60;
1842 static int name2uid(unsigned int *id, const char *name)
1844 struct passwd *passwd;
1846 passwd = getpwnam(name);
1849 *id = passwd->pw_uid;
1854 static int name2gid(unsigned int *id, const char *name)
1856 struct group *group;
1858 group = getgrnam(name);
1861 *id = group->gr_gid;
1866 static inline int name2projid(unsigned int *id, const char *name)
1871 static int uid2name(char **name, unsigned int id)
1873 struct passwd *passwd;
1875 passwd = getpwuid(id);
1878 *name = passwd->pw_name;
1883 static inline int gid2name(char **name, unsigned int id)
1885 struct group *group;
1887 group = getgrgid(id);
1890 *name = group->gr_name;
1895 static int name2layout(__u32 *layout, char *name)
1897 char *ptr, *layout_name;
1900 for (ptr = name; ; ptr = NULL) {
1901 layout_name = strtok(ptr, ",");
1902 if (layout_name == NULL)
1904 if (strcmp(layout_name, "released") == 0)
1905 *layout |= LOV_PATTERN_F_RELEASED;
1906 else if (strcmp(layout_name, "raid0") == 0)
1907 *layout |= LOV_PATTERN_RAID0;
1908 else if (strcmp(layout_name, "mdt") == 0)
1909 *layout |= LOV_PATTERN_MDT;
1916 static int lfs_find(int argc, char **argv)
1921 struct find_param param = {
1925 struct option long_opts[] = {
1926 { .val = 'A', .name = "atime", .has_arg = required_argument },
1927 { .val = LFS_COMP_COUNT_OPT,
1928 .name = "comp-count", .has_arg = required_argument },
1929 { .val = LFS_COMP_COUNT_OPT,
1930 .name = "component-count",
1931 .has_arg = required_argument },
1932 { .val = LFS_COMP_FLAGS_OPT,
1933 .name = "comp-flags", .has_arg = required_argument },
1934 { .val = LFS_COMP_FLAGS_OPT,
1935 .name = "component-flags",
1936 .has_arg = required_argument },
1937 { .val = LFS_COMP_START_OPT,
1938 .name = "comp-start", .has_arg = required_argument },
1939 { .val = LFS_COMP_START_OPT,
1940 .name = "component-start",
1941 .has_arg = required_argument },
1942 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1943 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1944 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1945 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1946 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1947 { .val = 'E', .name = "component-end",
1948 .has_arg = required_argument },
1949 { .val = 'g', .name = "gid", .has_arg = required_argument },
1950 { .val = 'G', .name = "group", .has_arg = required_argument },
1951 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1952 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1953 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1954 /*{"component-id", required_argument, 0, 'I'},*/
1955 { .val = 'L', .name = "layout", .has_arg = required_argument },
1956 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1957 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1958 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1959 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1960 { .val = 'n', .name = "name", .has_arg = required_argument },
1961 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1962 { .val = 'O', .name = "obd", .has_arg = required_argument },
1963 { .val = 'O', .name = "ost", .has_arg = required_argument },
1964 /* no short option for pool, p/P already used */
1965 { .val = LFS_POOL_OPT,
1966 .name = "pool", .has_arg = required_argument },
1967 { .val = 'p', .name = "print0", .has_arg = no_argument },
1968 { .val = 'P', .name = "print", .has_arg = no_argument },
1969 { .val = LFS_PROJID_OPT,
1970 .name = "projid", .has_arg = required_argument },
1971 { .val = 's', .name = "size", .has_arg = required_argument },
1972 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1973 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1974 { .val = 't', .name = "type", .has_arg = required_argument },
1975 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
1976 { .val = 'u', .name = "uid", .has_arg = required_argument },
1977 { .val = 'U', .name = "user", .has_arg = required_argument },
1989 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1990 while ((c = getopt_long_only(argc, argv,
1991 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1992 long_opts, NULL)) >= 0) {
1997 /* '!' is part of option */
1998 /* when getopt_long_only() finds a string which is not
1999 * an option nor a known option argument it returns 1
2000 * in that case if we already have found pathstart and pathend
2001 * (i.e. we have the list of pathnames),
2002 * the only supported value is "!"
2004 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2005 if (!isoption && pathend != -1) {
2006 fprintf(stderr, "err: %s: filename|dirname must either "
2007 "precede options or follow options\n",
2012 if (!isoption && pathstart == -1)
2013 pathstart = optind - 1;
2014 if (isoption && pathstart != -1 && pathend == -1)
2015 pathend = optind - 2;
2021 /* unknown; opt is "!" or path component,
2022 * checking done above.
2024 if (strcmp(optarg, "!") == 0)
2028 xtime = ¶m.fp_atime;
2029 xsign = ¶m.fp_asign;
2030 param.fp_exclude_atime = !!neg_opt;
2031 /* no break, this falls through to 'C' for ctime */
2034 xtime = ¶m.fp_ctime;
2035 xsign = ¶m.fp_csign;
2036 param.fp_exclude_ctime = !!neg_opt;
2038 /* no break, this falls through to 'M' for mtime */
2041 xtime = ¶m.fp_mtime;
2042 xsign = ¶m.fp_msign;
2043 param.fp_exclude_mtime = !!neg_opt;
2045 rc = set_time(&t, xtime, optarg);
2046 if (rc == INT_MAX) {
2053 case LFS_COMP_COUNT_OPT:
2054 if (optarg[0] == '+') {
2055 param.fp_comp_count_sign = -1;
2057 } else if (optarg[0] == '-') {
2058 param.fp_comp_count_sign = 1;
2062 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2063 if (*endptr != '\0') {
2064 fprintf(stderr, "error: bad component count "
2068 param.fp_check_comp_count = 1;
2069 param.fp_exclude_comp_count = !!neg_opt;
2071 case LFS_COMP_FLAGS_OPT:
2072 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2073 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2074 fprintf(stderr, "error: bad component flags "
2078 param.fp_check_comp_flags = 1;
2079 param.fp_exclude_comp_flags = !!neg_opt;
2081 case LFS_COMP_START_OPT:
2082 if (optarg[0] == '+') {
2083 param.fp_comp_start_sign = -1;
2085 } else if (optarg[0] == '-') {
2086 param.fp_comp_start_sign = 1;
2090 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2091 ¶m.fp_comp_start_units, 0);
2093 fprintf(stderr, "error: bad component start "
2097 param.fp_check_comp_start = 1;
2098 param.fp_exclude_comp_start = !!neg_opt;
2101 if (optarg[0] == '+') {
2102 param.fp_stripe_count_sign = -1;
2104 } else if (optarg[0] == '-') {
2105 param.fp_stripe_count_sign = 1;
2109 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2110 if (*endptr != '\0') {
2111 fprintf(stderr,"error: bad stripe_count '%s'\n",
2116 param.fp_check_stripe_count = 1;
2117 param.fp_exclude_stripe_count = !!neg_opt;
2120 param.fp_max_depth = strtol(optarg, 0, 0);
2123 if (optarg[0] == '+') {
2124 param.fp_comp_end_sign = -1;
2126 } else if (optarg[0] == '-') {
2127 param.fp_comp_end_sign = 1;
2131 if (arg_is_eof(optarg)) {
2132 param.fp_comp_end = LUSTRE_EOF;
2133 param.fp_comp_end_units = 1;
2136 rc = llapi_parse_size(optarg,
2138 ¶m.fp_comp_end_units, 0);
2141 fprintf(stderr, "error: bad component end "
2145 param.fp_check_comp_end = 1;
2146 param.fp_exclude_comp_end = !!neg_opt;
2150 rc = name2gid(¶m.fp_gid, optarg);
2152 param.fp_gid = strtoul(optarg, &endptr, 10);
2153 if (*endptr != '\0') {
2154 fprintf(stderr, "Group/GID: %s cannot "
2155 "be found.\n", optarg);
2160 param.fp_exclude_gid = !!neg_opt;
2161 param.fp_check_gid = 1;
2164 param.fp_hash_type = check_hashtype(optarg);
2165 if (param.fp_hash_type == 0) {
2166 fprintf(stderr, "error: bad hash_type '%s'\n",
2171 param.fp_check_hash_type = 1;
2172 param.fp_exclude_hash_type = !!neg_opt;
2175 ret = name2layout(¶m.fp_layout, optarg);
2178 param.fp_exclude_layout = !!neg_opt;
2179 param.fp_check_layout = 1;
2183 rc = name2uid(¶m.fp_uid, optarg);
2185 param.fp_uid = strtoul(optarg, &endptr, 10);
2186 if (*endptr != '\0') {
2187 fprintf(stderr, "User/UID: %s cannot "
2188 "be found.\n", optarg);
2193 param.fp_exclude_uid = !!neg_opt;
2194 param.fp_check_uid = 1;
2197 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2199 "Pool name %s is too long"
2200 " (max is %d)\n", optarg,
2205 /* we do check for empty pool because empty pool
2206 * is used to find V1 lov attributes */
2207 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2208 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2209 param.fp_exclude_pool = !!neg_opt;
2210 param.fp_check_pool = 1;
2213 param.fp_pattern = (char *)optarg;
2214 param.fp_exclude_pattern = !!neg_opt;
2219 char *buf, *token, *next, *p;
2223 buf = strdup(optarg);
2229 param.fp_exclude_obd = !!neg_opt;
2232 while (token && *token) {
2233 token = strchr(token, ',');
2240 param.fp_exclude_mdt = !!neg_opt;
2241 param.fp_num_alloc_mdts += len;
2242 tmp = realloc(param.fp_mdt_uuid,
2243 param.fp_num_alloc_mdts *
2244 sizeof(*param.fp_mdt_uuid));
2250 param.fp_mdt_uuid = tmp;
2252 param.fp_exclude_obd = !!neg_opt;
2253 param.fp_num_alloc_obds += len;
2254 tmp = realloc(param.fp_obd_uuid,
2255 param.fp_num_alloc_obds *
2256 sizeof(*param.fp_obd_uuid));
2262 param.fp_obd_uuid = tmp;
2264 for (token = buf; token && *token; token = next) {
2265 struct obd_uuid *puuid;
2268 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2271 ¶m.fp_obd_uuid[param.fp_num_obds++];
2273 p = strchr(token, ',');
2280 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2285 strncpy(puuid->uuid, token,
2286 sizeof(puuid->uuid));
2294 param.fp_zero_end = 1;
2298 case LFS_PROJID_OPT:
2299 rc = name2projid(¶m.fp_projid, optarg);
2301 param.fp_projid = strtoul(optarg, &endptr, 10);
2302 if (*endptr != '\0') {
2304 "Invalid project ID: %s",
2310 param.fp_exclude_projid = !!neg_opt;
2311 param.fp_check_projid = 1;
2314 if (optarg[0] == '+') {
2315 param.fp_size_sign = -1;
2317 } else if (optarg[0] == '-') {
2318 param.fp_size_sign = 1;
2322 ret = llapi_parse_size(optarg, ¶m.fp_size,
2323 ¶m.fp_size_units, 0);
2325 fprintf(stderr, "error: bad file size '%s'\n",
2329 param.fp_check_size = 1;
2330 param.fp_exclude_size = !!neg_opt;
2333 if (optarg[0] == '+') {
2334 param.fp_stripe_size_sign = -1;
2336 } else if (optarg[0] == '-') {
2337 param.fp_stripe_size_sign = 1;
2341 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2342 ¶m.fp_stripe_size_units, 0);
2344 fprintf(stderr, "error: bad stripe_size '%s'\n",
2348 param.fp_check_stripe_size = 1;
2349 param.fp_exclude_stripe_size = !!neg_opt;
2352 param.fp_exclude_type = !!neg_opt;
2353 switch (optarg[0]) {
2355 param.fp_type = S_IFBLK;
2358 param.fp_type = S_IFCHR;
2361 param.fp_type = S_IFDIR;
2364 param.fp_type = S_IFREG;
2367 param.fp_type = S_IFLNK;
2370 param.fp_type = S_IFIFO;
2373 param.fp_type = S_IFSOCK;
2376 fprintf(stderr, "error: %s: bad type '%s'\n",
2383 if (optarg[0] == '+') {
2384 param.fp_mdt_count_sign = -1;
2386 } else if (optarg[0] == '-') {
2387 param.fp_mdt_count_sign = 1;
2391 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2392 if (*endptr != '\0') {
2393 fprintf(stderr, "error: bad mdt_count '%s'\n",
2398 param.fp_check_mdt_count = 1;
2399 param.fp_exclude_mdt_count = !!neg_opt;
2407 if (pathstart == -1) {
2408 fprintf(stderr, "error: %s: no filename|pathname\n",
2412 } else if (pathend == -1) {
2418 rc = llapi_find(argv[pathstart], ¶m);
2419 if (rc != 0 && ret == 0)
2421 } while (++pathstart < pathend);
2424 fprintf(stderr, "error: %s failed for %s.\n",
2425 argv[0], argv[optind - 1]);
2427 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2428 free(param.fp_obd_uuid);
2430 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2431 free(param.fp_mdt_uuid);
2436 static int lfs_getstripe_internal(int argc, char **argv,
2437 struct find_param *param)
2439 struct option long_opts[] = {
2440 { .val = LFS_COMP_COUNT_OPT,
2441 .name = "comp-count", .has_arg = no_argument },
2442 { .val = LFS_COMP_COUNT_OPT,
2443 .name = "component-count", .has_arg = no_argument },
2444 { .val = LFS_COMP_FLAGS_OPT,
2445 .name = "comp-flags", .has_arg = optional_argument },
2446 { .val = LFS_COMP_FLAGS_OPT,
2447 .name = "component-flags", .has_arg = optional_argument },
2448 { .val = LFS_COMP_START_OPT,
2449 .name = "comp-start", .has_arg = optional_argument },
2450 { .val = LFS_COMP_START_OPT,
2451 .name = "component-start", .has_arg = optional_argument },
2452 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2453 /* This formerly implied "stripe-count", but was explicitly
2454 * made "stripe-count" for consistency with other options,
2455 * and to separate it from "mdt-count" when DNE arrives. */
2456 { .val = 'c', .name = "count", .has_arg = no_argument },
2458 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2459 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2460 { .val = 'd', .name = "directory", .has_arg = no_argument },
2461 { .val = 'D', .name = "default", .has_arg = no_argument },
2462 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2463 { .val = 'E', .name = "component-end",
2464 .has_arg = optional_argument },
2465 { .val = 'F', .name = "fid", .has_arg = no_argument },
2466 { .val = 'g', .name = "generation", .has_arg = no_argument },
2467 /* dirstripe { .val = 'H', .name = "mdt-hash",
2468 * .has_arg = required_argument }, */
2469 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2470 /* This formerly implied "stripe-index", but was explicitly
2471 * made "stripe-index" for consistency with other options,
2472 * and to separate it from "mdt-index" when DNE arrives. */
2473 { .val = 'i', .name = "index", .has_arg = no_argument },
2475 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2476 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2477 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2478 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2479 { .val = 'L', .name = "layout", .has_arg = no_argument },
2480 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2481 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2482 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2483 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2484 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2485 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2487 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2488 /* This formerly implied "stripe-index", but was confusing
2489 * with "file offset" (which will eventually be needed for
2490 * with different layouts by offset), so deprecate it. */
2491 { .val = 'o', .name = "offset", .has_arg = no_argument },
2493 { .val = 'O', .name = "obd", .has_arg = required_argument },
2494 { .val = 'O', .name = "ost", .has_arg = required_argument },
2495 { .val = 'p', .name = "pool", .has_arg = no_argument },
2496 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2497 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2498 { .val = 'R', .name = "raw", .has_arg = no_argument },
2499 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2500 /* This formerly implied "--stripe-size", but was confusing
2501 * with "lfs find --size|-s", which means "file size", so use
2502 * the consistent "--stripe-size|-S" for all commands. */
2503 { .val = 's', .name = "size", .has_arg = no_argument },
2505 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2506 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2507 /* dirstripe { .val = 'T', .name = "mdt-count",
2508 * .has_arg = required_argument }, */
2509 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2510 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2515 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2516 long_opts, NULL)) != -1) {
2519 if (strcmp(argv[optind - 1], "--count") == 0)
2520 fprintf(stderr, "warning: '--count' deprecated,"
2521 " use '--stripe-count' instead\n");
2522 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2523 param->fp_verbose |= VERBOSE_COUNT;
2524 param->fp_max_depth = 0;
2527 case LFS_COMP_COUNT_OPT:
2528 param->fp_verbose |= VERBOSE_COMP_COUNT;
2529 param->fp_max_depth = 0;
2531 case LFS_COMP_FLAGS_OPT:
2532 if (optarg != NULL) {
2533 __u32 *flags = ¶m->fp_comp_flags;
2534 rc = comp_str2flags(flags, optarg);
2536 fprintf(stderr, "error: %s bad "
2537 "component flags '%s'.\n",
2541 param->fp_check_comp_flags = 1;
2542 param->fp_exclude_comp_flags =
2543 comp_flags_is_neg(*flags);
2544 comp_flags_clear_neg(flags);
2547 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2548 param->fp_max_depth = 0;
2551 case LFS_COMP_START_OPT:
2552 if (optarg != NULL) {
2554 if (tmp[0] == '+') {
2555 param->fp_comp_start_sign = -1;
2557 } else if (tmp[0] == '-') {
2558 param->fp_comp_start_sign = 1;
2561 rc = llapi_parse_size(tmp,
2562 ¶m->fp_comp_start,
2563 ¶m->fp_comp_start_units, 0);
2565 fprintf(stderr, "error: %s bad "
2566 "component start '%s'.\n",
2570 param->fp_check_comp_start = 1;
2573 param->fp_verbose |= VERBOSE_COMP_START;
2574 param->fp_max_depth = 0;
2578 param->fp_max_depth = 0;
2581 param->fp_get_default_lmv = 1;
2584 if (optarg != NULL) {
2586 if (tmp[0] == '+') {
2587 param->fp_comp_end_sign = -1;
2589 } else if (tmp[0] == '-') {
2590 param->fp_comp_end_sign = 1;
2594 if (arg_is_eof(tmp)) {
2595 param->fp_comp_end = LUSTRE_EOF;
2596 param->fp_comp_end_units = 1;
2599 rc = llapi_parse_size(tmp,
2600 ¶m->fp_comp_end,
2601 ¶m->fp_comp_end_units, 0);
2604 fprintf(stderr, "error: %s bad "
2605 "component end '%s'.\n",
2609 param->fp_check_comp_end = 1;
2611 param->fp_verbose |= VERBOSE_COMP_END;
2612 param->fp_max_depth = 0;
2616 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2617 param->fp_verbose |= VERBOSE_DFID;
2618 param->fp_max_depth = 0;
2622 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2623 param->fp_verbose |= VERBOSE_GENERATION;
2624 param->fp_max_depth = 0;
2627 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2629 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2630 "use '--stripe-index|-i' instead\n");
2633 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2634 if (strcmp(argv[optind - 1], "--index") == 0)
2635 fprintf(stderr, "warning: '--index' deprecated"
2636 ", use '--stripe-index' instead\n");
2638 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2639 param->fp_verbose |= VERBOSE_OFFSET;
2640 param->fp_max_depth = 0;
2644 if (optarg != NULL) {
2645 param->fp_comp_id = strtoul(optarg, &end, 0);
2646 if (*end != '\0' || param->fp_comp_id == 0 ||
2647 param->fp_comp_id > LCME_ID_MAX) {
2648 fprintf(stderr, "error: %s bad "
2649 "component id '%s'\n",
2653 param->fp_check_comp_id = 1;
2656 param->fp_max_depth = 0;
2657 param->fp_verbose |= VERBOSE_COMP_ID;
2661 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2662 param->fp_verbose |= VERBOSE_LAYOUT;
2663 param->fp_max_depth = 0;
2666 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2668 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2669 fprintf(stderr, "warning: '-M' deprecated"
2670 ", use '-m' instead\n");
2674 if (!(param->fp_verbose & VERBOSE_DETAIL))
2675 param->fp_max_depth = 0;
2676 param->fp_verbose |= VERBOSE_MDTINDEX;
2679 if (param->fp_obd_uuid) {
2681 "error: %s: only one obduuid allowed",
2685 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2688 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2689 param->fp_verbose |= VERBOSE_POOL;
2690 param->fp_max_depth = 0;
2697 param->fp_recursive = 1;
2702 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2704 fprintf(stderr, "warning: '--size|-s' deprecated, "
2705 "use '--stripe-size|-S' instead\n");
2706 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2708 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2709 param->fp_verbose |= VERBOSE_SIZE;
2710 param->fp_max_depth = 0;
2714 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2727 if (param->fp_recursive)
2728 param->fp_max_depth = -1;
2729 else if (param->fp_verbose & VERBOSE_DETAIL)
2730 param->fp_max_depth = 1;
2732 if (!param->fp_verbose)
2733 param->fp_verbose = VERBOSE_DEFAULT;
2734 if (param->fp_quiet)
2735 param->fp_verbose = VERBOSE_OBJID;
2738 rc = llapi_getstripe(argv[optind], param);
2739 } while (++optind < argc && !rc);
2742 fprintf(stderr, "error: %s failed for %s.\n",
2743 argv[0], argv[optind - 1]);
2747 static int lfs_tgts(int argc, char **argv)
2749 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2750 struct find_param param;
2751 int index = 0, rc=0;
2756 if (argc == 2 && !realpath(argv[1], path)) {
2758 fprintf(stderr, "error: invalid path '%s': %s\n",
2759 argv[1], strerror(-rc));
2763 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2764 /* Check if we have a mount point */
2765 if (mntdir[0] == '\0')
2768 memset(¶m, 0, sizeof(param));
2769 if (!strcmp(argv[0], "mdts"))
2770 param.fp_get_lmv = 1;
2772 rc = llapi_ostlist(mntdir, ¶m);
2774 fprintf(stderr, "error: %s: failed on %s\n",
2777 if (path[0] != '\0')
2779 memset(mntdir, 0, PATH_MAX);
2785 static int lfs_getstripe(int argc, char **argv)
2787 struct find_param param = { 0 };
2789 param.fp_max_depth = 1;
2790 return lfs_getstripe_internal(argc, argv, ¶m);
2794 static int lfs_getdirstripe(int argc, char **argv)
2796 struct find_param param = { 0 };
2797 struct option long_opts[] = {
2798 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2799 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2801 { .val = 'D', .name = "default", .has_arg = no_argument },
2802 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2803 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2804 { .val = 'O', .name = "obd", .has_arg = required_argument },
2805 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2806 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2807 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2809 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2810 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2814 param.fp_get_lmv = 1;
2816 while ((c = getopt_long(argc, argv,
2817 "cDHiO:rtTy", long_opts, NULL)) != -1)
2821 if (param.fp_obd_uuid) {
2823 "error: %s: only one obduuid allowed",
2827 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2829 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2831 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2832 fprintf(stderr, "warning: '-c' deprecated"
2833 ", use '-T' instead\n");
2837 param.fp_verbose |= VERBOSE_COUNT;
2840 param.fp_verbose |= VERBOSE_OFFSET;
2842 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2846 param.fp_verbose |= VERBOSE_HASH_TYPE;
2849 param.fp_get_default_lmv = 1;
2852 param.fp_recursive = 1;
2865 if (param.fp_recursive)
2866 param.fp_max_depth = -1;
2868 if (!param.fp_verbose)
2869 param.fp_verbose = VERBOSE_DEFAULT;
2872 rc = llapi_getstripe(argv[optind], ¶m);
2873 } while (++optind < argc && !rc);
2876 fprintf(stderr, "error: %s failed for %s.\n",
2877 argv[0], argv[optind - 1]);
2882 static int lfs_setdirstripe(int argc, char **argv)
2886 unsigned int stripe_offset = -1;
2887 unsigned int stripe_count = 1;
2888 enum lmv_hash_type hash_type;
2891 char *stripe_offset_opt = NULL;
2892 char *stripe_count_opt = NULL;
2893 char *stripe_hash_opt = NULL;
2894 char *mode_opt = NULL;
2895 bool default_stripe = false;
2896 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2897 mode_t previous_mode = 0;
2898 bool delete = false;
2900 struct option long_opts[] = {
2901 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2902 { .val = 'c', .name = "count", .has_arg = required_argument },
2904 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2905 { .val = 'd', .name = "delete", .has_arg = no_argument },
2906 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2907 { .val = 'i', .name = "index", .has_arg = required_argument },
2909 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2910 { .val = 'm', .name = "mode", .has_arg = required_argument },
2911 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2912 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2913 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2915 {"mdt-hash", required_argument, 0, 'H'},
2916 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2917 { .val = 'D', .name = "default_stripe",
2918 .has_arg = no_argument },
2920 { .val = 'D', .name = "default", .has_arg = no_argument },
2923 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2930 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2931 if (strcmp(argv[optind - 1], "--count") == 0)
2933 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
2936 stripe_count_opt = optarg;
2940 default_stripe = true;
2943 default_stripe = true;
2946 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2947 if (strcmp(argv[optind - 1], "--index") == 0)
2949 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
2952 stripe_offset_opt = optarg;
2957 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2961 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2962 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2964 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
2967 stripe_hash_opt = optarg;
2970 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2971 progname, argv[0], argv[optind - 1]);
2976 if (optind == argc) {
2977 fprintf(stderr, "%s %s: DIR must be specified\n",
2982 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2984 "%s %s: stripe offset and count must be specified\n",
2989 if (stripe_offset_opt != NULL) {
2990 /* get the stripe offset */
2991 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2994 "%s %s: bad stripe offset '%s'\n",
2995 progname, argv[0], stripe_offset_opt);
3001 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3003 "%s %s: cannot specify -d with -c or -i options\n",
3012 if (mode_opt != NULL) {
3013 mode = strtoul(mode_opt, &end, 8);
3016 "%s %s: bad MODE '%s'\n",
3017 progname, argv[0], mode_opt);
3020 previous_mode = umask(0);
3023 if (stripe_hash_opt == NULL) {
3024 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3026 hash_type = check_hashtype(stripe_hash_opt);
3027 if (hash_type == 0) {
3028 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3029 progname, argv[0], stripe_hash_opt);
3034 /* get the stripe count */
3035 if (stripe_count_opt != NULL) {
3036 stripe_count = strtoul(stripe_count_opt, &end, 0);
3039 "%s %s: bad stripe count '%s'\n",
3040 progname, argv[0], stripe_count_opt);
3045 dname = argv[optind];
3047 if (default_stripe) {
3048 result = llapi_dir_set_default_lmv_stripe(dname,
3049 stripe_offset, stripe_count,
3052 result = llapi_dir_create_pool(dname, mode,
3054 stripe_count, hash_type,
3060 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3061 progname, dname, strerror(-result));
3064 dname = argv[++optind];
3065 } while (dname != NULL);
3067 if (mode_opt != NULL)
3068 umask(previous_mode);
3074 static int lfs_rmentry(int argc, char **argv)
3081 fprintf(stderr, "error: %s: missing dirname\n",
3087 dname = argv[index];
3088 while (dname != NULL) {
3089 result = llapi_direntry_remove(dname);
3091 fprintf(stderr, "error: %s: remove dir entry '%s' "
3092 "failed\n", argv[0], dname);
3095 dname = argv[++index];
3100 static int lfs_mv(int argc, char **argv)
3102 struct find_param param = {
3109 struct option long_opts[] = {
3110 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3111 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3114 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3117 param.fp_mdt_index = strtoul(optarg, &end, 0);
3119 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3126 param.fp_verbose = VERBOSE_DETAIL;
3130 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3131 argv[0], argv[optind - 1]);
3136 if (param.fp_mdt_index == -1) {
3137 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3141 if (optind >= argc) {
3142 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3146 param.fp_migrate = 1;
3147 rc = llapi_migrate_mdt(argv[optind], ¶m);
3149 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3150 argv[0], argv[optind], param.fp_mdt_index,
3155 static int lfs_osts(int argc, char **argv)
3157 return lfs_tgts(argc, argv);
3160 static int lfs_mdts(int argc, char **argv)
3162 return lfs_tgts(argc, argv);
3165 #define COOK(value) \
3168 while (value > 1024) { \
3176 #define CDF "%11llu"
3177 #define HDF "%8.1f%c"
3182 MNTDF_INODES = 0x0001,
3183 MNTDF_COOKED = 0x0002,
3184 MNTDF_LAZY = 0x0004,
3185 MNTDF_VERBOSE = 0x0008,
3188 static int showdf(char *mntdir, struct obd_statfs *stat,
3189 char *uuid, enum mntdf_flags flags,
3190 char *type, int index, int rc)
3192 long long avail, used, total;
3194 char *suffix = "KMGTPEZY";
3195 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3196 char tbuf[3 * sizeof(__u64)];
3197 char ubuf[3 * sizeof(__u64)];
3198 char abuf[3 * sizeof(__u64)];
3199 char rbuf[3 * sizeof(__u64)];
3206 if (flags & MNTDF_INODES) {
3207 avail = stat->os_ffree;
3208 used = stat->os_files - stat->os_ffree;
3209 total = stat->os_files;
3211 int shift = flags & MNTDF_COOKED ? 0 : 10;
3213 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3214 used = ((stat->os_blocks - stat->os_bfree) *
3215 stat->os_bsize) >> shift;
3216 total = (stat->os_blocks * stat->os_bsize) >> shift;
3219 if ((used + avail) > 0)
3220 ratio = (double)used / (double)(used + avail);
3222 if (flags & MNTDF_COOKED) {
3226 cook_val = (double)total;
3229 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3232 snprintf(tbuf, sizeof(tbuf), CDF, total);
3234 cook_val = (double)used;
3237 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3240 snprintf(ubuf, sizeof(ubuf), CDF, used);
3242 cook_val = (double)avail;
3245 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3248 snprintf(abuf, sizeof(abuf), CDF, avail);
3250 snprintf(tbuf, sizeof(tbuf), CDF, total);
3251 snprintf(ubuf, sizeof(tbuf), CDF, used);
3252 snprintf(abuf, sizeof(tbuf), CDF, avail);
3255 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3256 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3257 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3259 printf("[%s:%d]", type, index);
3261 if (stat->os_state) {
3263 * Each character represents the matching
3266 const char state_names[] = "DRSI";
3271 for (i = 0, state = stat->os_state;
3272 state && i < sizeof(state_names); i++) {
3273 if (!(state & (1 << i)))
3275 printf("%c", state_names[i]);
3283 printf(UUF": inactive device\n", uuid);
3286 printf(UUF": %s\n", uuid, strerror(-rc));
3293 struct ll_stat_type {
3298 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3300 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3301 struct obd_uuid uuid_buf;
3302 char *poolname = NULL;
3303 struct ll_stat_type types[] = {
3304 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3305 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3306 { .st_name = NULL } };
3307 struct ll_stat_type *tp;
3308 __u64 ost_ffree = 0;
3316 poolname = strchr(pool, '.');
3317 if (poolname != NULL) {
3318 if (strncmp(fsname, pool, strlen(fsname))) {
3319 fprintf(stderr, "filesystem name incorrect\n");
3327 fd = open(mntdir, O_RDONLY);
3330 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3335 if (flags & MNTDF_INODES)
3336 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3337 "UUID", "Inodes", "IUsed", "IFree",
3338 "IUse%", "Mounted on");
3340 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3341 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3342 "Used", "Available", "Use%", "Mounted on");
3344 for (tp = types; tp->st_name != NULL; tp++) {
3345 for (index = 0; ; index++) {
3346 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3347 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3348 type = flags & MNTDF_LAZY ?
3349 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3350 rc2 = llapi_obd_fstatfs(fd, type, index,
3351 &stat_buf, &uuid_buf);
3356 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3357 if (!(flags & MNTDF_VERBOSE))
3359 } else if (rc2 < 0 && rc == 0) {
3363 if (poolname && tp->st_op == LL_STATFS_LOV &&
3364 llapi_search_ost(fsname, poolname,
3365 obd_uuid2str(&uuid_buf)) != 1)
3368 /* the llapi_obd_statfs() call may have returned with
3369 * an error, but if it filled in uuid_buf we will at
3370 * lease use that to print out a message for that OBD.
3371 * If we didn't get anything in the uuid_buf, then fill
3372 * it in so that we can print an error message. */
3373 if (uuid_buf.uuid[0] == '\0')
3374 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3375 "%s%04x", tp->st_name, index);
3376 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3377 flags, tp->st_name, index, rc2);
3380 if (tp->st_op == LL_STATFS_LMV) {
3381 sum.os_ffree += stat_buf.os_ffree;
3382 sum.os_files += stat_buf.os_files;
3383 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3384 sum.os_blocks += stat_buf.os_blocks *
3386 sum.os_bfree += stat_buf.os_bfree *
3388 sum.os_bavail += stat_buf.os_bavail *
3390 ost_ffree += stat_buf.os_ffree;
3398 /* If we don't have as many objects free on the OST as inodes
3399 * on the MDS, we reduce the total number of inodes to
3400 * compensate, so that the "inodes in use" number is correct.
3401 * Matches ll_statfs_internal() so the results are consistent. */
3402 if (ost_ffree < sum.os_ffree) {
3403 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3404 sum.os_ffree = ost_ffree;
3407 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3413 static int lfs_df(int argc, char **argv)
3415 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3416 enum mntdf_flags flags = 0;
3417 int c, rc = 0, index = 0;
3418 char fsname[PATH_MAX] = "", *pool_name = NULL;
3419 struct option long_opts[] = {
3420 { .val = 'h', .name = "human-readable",
3421 .has_arg = no_argument },
3422 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3423 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3424 { .val = 'p', .name = "pool", .has_arg = required_argument },
3425 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3428 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3431 flags |= MNTDF_COOKED;
3434 flags |= MNTDF_INODES;
3437 flags |= MNTDF_LAZY;
3443 flags |= MNTDF_VERBOSE;
3449 if (optind < argc && !realpath(argv[optind], path)) {
3451 fprintf(stderr, "error: invalid path '%s': %s\n",
3452 argv[optind], strerror(-rc));
3456 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3457 /* Check if we have a mount point */
3458 if (mntdir[0] == '\0')
3461 rc = mntdf(mntdir, fsname, pool_name, flags);
3462 if (rc || path[0] != '\0')
3464 fsname[0] = '\0'; /* avoid matching in next loop */
3465 mntdir[0] = '\0'; /* avoid matching in next loop */
3471 static int lfs_getname(int argc, char **argv)
3473 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3474 int rc = 0, index = 0, c;
3475 char buf[sizeof(struct obd_uuid)];
3477 while ((c = getopt(argc, argv, "h")) != -1)
3480 if (optind == argc) { /* no paths specified, get all paths. */
3481 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3482 rc = llapi_getname(mntdir, buf, sizeof(buf));
3485 "cannot get name for `%s': %s\n",
3486 mntdir, strerror(-rc));
3490 printf("%s %s\n", buf, mntdir);
3492 path[0] = fsname[0] = mntdir[0] = 0;
3494 } else { /* paths specified, only attempt to search these. */
3495 for (; optind < argc; optind++) {
3496 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3499 "cannot get name for `%s': %s\n",
3500 argv[optind], strerror(-rc));
3504 printf("%s %s\n", buf, argv[optind]);
3510 static int lfs_check(int argc, char **argv)
3513 char mntdir[PATH_MAX] = {'\0'};
3522 obd_types[0] = obd_type1;
3523 obd_types[1] = obd_type2;
3525 if (strcmp(argv[1], "osts") == 0) {
3526 strcpy(obd_types[0], "osc");
3527 } else if (strcmp(argv[1], "mds") == 0) {
3528 strcpy(obd_types[0], "mdc");
3529 } else if (strcmp(argv[1], "servers") == 0) {
3531 strcpy(obd_types[0], "osc");
3532 strcpy(obd_types[1], "mdc");
3534 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3539 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3540 if (rc < 0 || mntdir[0] == '\0') {
3541 fprintf(stderr, "No suitable Lustre mount found\n");
3545 rc = llapi_target_check(num_types, obd_types, mntdir);
3547 fprintf(stderr, "error: %s: %s status failed\n",
3554 #ifdef HAVE_SYS_QUOTA_H
3555 #define ARG2INT(nr, str, msg) \
3558 nr = strtol(str, &endp, 0); \
3560 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3565 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3567 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3568 * returns the value or ULONG_MAX on integer overflow or incorrect format
3570 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3571 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3572 * 3. empty integer value is interpreted as 0
3574 static unsigned long str2sec(const char* timestr)
3576 const char spec[] = "smhdw";
3577 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3578 unsigned long val = 0;
3581 if (strpbrk(timestr, spec) == NULL) {
3582 /* no specifiers inside the time string,
3583 should treat it as an integer value */
3584 val = strtoul(timestr, &tail, 10);
3585 return *tail ? ULONG_MAX : val;
3588 /* format string is XXwXXdXXhXXmXXs */
3594 v = strtoul(timestr, &tail, 10);
3595 if (v == ULONG_MAX || *tail == '\0')
3596 /* value too large (ULONG_MAX or more)
3597 or missing specifier */
3600 ptr = strchr(spec, *tail);
3602 /* unknown specifier */
3607 /* check if product will overflow the type */
3608 if (!(v < ULONG_MAX / mult[ind]))
3611 ADD_OVERFLOW(val, mult[ind] * v);
3612 if (val == ULONG_MAX)
3624 #define ARG2ULL(nr, str, def_units) \
3626 unsigned long long limit, units = def_units; \
3629 rc = llapi_parse_size(str, &limit, &units, 1); \
3631 fprintf(stderr, "error: bad limit value %s\n", str); \
3637 static inline int has_times_option(int argc, char **argv)
3641 for (i = 1; i < argc; i++)
3642 if (!strcmp(argv[i], "-t"))
3648 int lfs_setquota_times(int argc, char **argv)
3651 struct if_quotactl qctl;
3652 char *mnt, *obd_type = (char *)qctl.obd_type;
3653 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3654 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3655 struct option long_opts[] = {
3656 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3657 { .val = 'g', .name = "group", .has_arg = no_argument },
3658 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3659 { .val = 'p', .name = "projid", .has_arg = no_argument },
3660 { .val = 't', .name = "times", .has_arg = no_argument },
3661 { .val = 'u', .name = "user", .has_arg = no_argument },
3665 memset(&qctl, 0, sizeof(qctl));
3666 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3667 qctl.qc_type = ALLQUOTA;
3669 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3670 long_opts, NULL)) != -1) {
3681 if (qctl.qc_type != ALLQUOTA) {
3682 fprintf(stderr, "error: -u/g/p can't be used "
3683 "more than once\n");
3686 qctl.qc_type = qtype;
3689 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3690 fprintf(stderr, "error: bad block-grace: %s\n",
3694 dqb->dqb_valid |= QIF_BTIME;
3697 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3698 fprintf(stderr, "error: bad inode-grace: %s\n",
3702 dqb->dqb_valid |= QIF_ITIME;
3704 case 't': /* Yes, of course! */
3706 default: /* getopt prints error message for us when opterr != 0 */
3711 if (qctl.qc_type == ALLQUOTA) {
3712 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3716 if (optind != argc - 1) {
3717 fprintf(stderr, "error: unexpected parameters encountered\n");
3722 rc = llapi_quotactl(mnt, &qctl);
3725 fprintf(stderr, "%s %s ", obd_type,
3726 obd_uuid2str(&qctl.obd_uuid));
3727 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3734 #define BSLIMIT (1 << 0)
3735 #define BHLIMIT (1 << 1)
3736 #define ISLIMIT (1 << 2)
3737 #define IHLIMIT (1 << 3)
3739 int lfs_setquota(int argc, char **argv)
3742 struct if_quotactl qctl;
3743 char *mnt, *obd_type = (char *)qctl.obd_type;
3744 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3745 struct option long_opts[] = {
3746 { .val = 'b', .name = "block-softlimit",
3747 .has_arg = required_argument },
3748 { .val = 'B', .name = "block-hardlimit",
3749 .has_arg = required_argument },
3750 { .val = 'g', .name = "group", .has_arg = required_argument },
3751 { .val = 'i', .name = "inode-softlimit",
3752 .has_arg = required_argument },
3753 { .val = 'I', .name = "inode-hardlimit",
3754 .has_arg = required_argument },
3755 { .val = 'p', .name = "projid", .has_arg = required_argument },
3756 { .val = 'u', .name = "user", .has_arg = required_argument },
3758 unsigned limit_mask = 0;
3762 if (has_times_option(argc, argv))
3763 return lfs_setquota_times(argc, argv);
3765 memset(&qctl, 0, sizeof(qctl));
3766 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3767 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3768 * so it can be used as a marker that qc_type
3769 * isn't reinitialized from command line */
3771 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3772 long_opts, NULL)) != -1) {
3776 rc = name2uid(&qctl.qc_id, optarg);
3780 rc = name2gid(&qctl.qc_id, optarg);
3784 rc = name2projid(&qctl.qc_id, optarg);
3786 if (qctl.qc_type != ALLQUOTA) {
3787 fprintf(stderr, "error: -u and -g can't be used"
3788 " more than once\n");
3791 qctl.qc_type = qtype;
3793 qctl.qc_id = strtoul(optarg, &endptr, 10);
3794 if (*endptr != '\0') {
3795 fprintf(stderr, "error: can't find id "
3796 "for name %s\n", optarg);
3802 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3803 dqb->dqb_bsoftlimit >>= 10;
3804 limit_mask |= BSLIMIT;
3805 if (dqb->dqb_bsoftlimit &&
3806 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3807 fprintf(stderr, "warning: block softlimit is "
3808 "smaller than the miminal qunit size, "
3809 "please see the help of setquota or "
3810 "Lustre manual for details.\n");
3813 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3814 dqb->dqb_bhardlimit >>= 10;
3815 limit_mask |= BHLIMIT;
3816 if (dqb->dqb_bhardlimit &&
3817 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3818 fprintf(stderr, "warning: block hardlimit is "
3819 "smaller than the miminal qunit size, "
3820 "please see the help of setquota or "
3821 "Lustre manual for details.\n");
3824 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3825 limit_mask |= ISLIMIT;
3826 if (dqb->dqb_isoftlimit &&
3827 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3828 fprintf(stderr, "warning: inode softlimit is "
3829 "smaller than the miminal qunit size, "
3830 "please see the help of setquota or "
3831 "Lustre manual for details.\n");
3834 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3835 limit_mask |= IHLIMIT;
3836 if (dqb->dqb_ihardlimit &&
3837 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3838 fprintf(stderr, "warning: inode hardlimit is "
3839 "smaller than the miminal qunit size, "
3840 "please see the help of setquota or "
3841 "Lustre manual for details.\n");
3843 default: /* getopt prints error message for us when opterr != 0 */
3848 if (qctl.qc_type == ALLQUOTA) {
3849 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3853 if (limit_mask == 0) {
3854 fprintf(stderr, "error: at least one limit must be specified\n");
3858 if (optind != argc - 1) {
3859 fprintf(stderr, "error: unexpected parameters encountered\n");
3865 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3866 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3867 /* sigh, we can't just set blimits/ilimits */
3868 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3869 .qc_type = qctl.qc_type,
3870 .qc_id = qctl.qc_id};
3872 rc = llapi_quotactl(mnt, &tmp_qctl);
3874 fprintf(stderr, "error: setquota failed while retrieving"
3875 " current quota settings (%s)\n",
3880 if (!(limit_mask & BHLIMIT))
3881 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3882 if (!(limit_mask & BSLIMIT))
3883 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3884 if (!(limit_mask & IHLIMIT))
3885 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3886 if (!(limit_mask & ISLIMIT))
3887 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3889 /* Keep grace times if we have got no softlimit arguments */
3890 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3891 dqb->dqb_valid |= QIF_BTIME;
3892 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3895 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3896 dqb->dqb_valid |= QIF_ITIME;
3897 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3901 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3902 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3904 rc = llapi_quotactl(mnt, &qctl);
3907 fprintf(stderr, "%s %s ", obd_type,
3908 obd_uuid2str(&qctl.obd_uuid));
3909 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3916 /* Converts seconds value into format string
3917 * result is returned in buf
3919 * 1. result is in descenting order: 1w2d3h4m5s
3920 * 2. zero fields are not filled (except for p. 3): 5d1s
3921 * 3. zero seconds value is presented as "0s"
3923 static char * __sec2str(time_t seconds, char *buf)
3925 const char spec[] = "smhdw";
3926 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3931 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3932 c = seconds / mult[i];
3934 if (c > 0 || (i == 0 && buf == tail))
3935 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3943 static void sec2str(time_t seconds, char *buf, int rc)
3950 tail = __sec2str(seconds, tail);
3952 if (rc && tail - buf < 39) {
3958 static void diff2str(time_t seconds, char *buf, time_t now)
3964 if (seconds <= now) {
3965 strcpy(buf, "none");
3968 __sec2str(seconds - now, buf);
3971 static void print_quota_title(char *name, struct if_quotactl *qctl,
3972 bool human_readable)
3974 printf("Disk quotas for %s %s (%cid %u):\n",
3975 qtype_name(qctl->qc_type), name,
3976 *qtype_name(qctl->qc_type), qctl->qc_id);
3977 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3978 "Filesystem", human_readable ? "used" : "kbytes",
3979 "quota", "limit", "grace",
3980 "files", "quota", "limit", "grace");
3983 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3986 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3989 snprintf(buf, buflen, "%5.4gP",
3990 (double)num / ((__u64)1 << 40));
3992 snprintf(buf, buflen, "%5.4gT",
3993 (double)num / (1 << 30));
3995 snprintf(buf, buflen, "%5.4gG",
3996 (double)num / (1 << 20));
3998 snprintf(buf, buflen, "%5.4gM",
3999 (double)num / (1 << 10));
4001 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4005 #define STRBUF_LEN 32
4006 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4013 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4014 int bover = 0, iover = 0;
4015 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4016 char numbuf[3][STRBUF_LEN];
4018 char strbuf[STRBUF_LEN];
4020 if (dqb->dqb_bhardlimit &&
4021 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4023 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4024 if (dqb->dqb_btime > now) {
4031 if (dqb->dqb_ihardlimit &&
4032 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4034 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4035 if (dqb->dqb_itime > now) {
4043 if (strlen(mnt) > 15)
4044 printf("%s\n%15s", mnt, "");
4046 printf("%15s", mnt);
4049 diff2str(dqb->dqb_btime, timebuf, now);
4051 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4052 strbuf, sizeof(strbuf), h);
4053 if (rc == -EREMOTEIO)
4054 sprintf(numbuf[0], "%s*", strbuf);
4056 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4057 "%s" : "[%s]", strbuf);
4059 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4060 if (type == QC_GENERAL)
4061 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4062 "%s" : "[%s]", strbuf);
4064 sprintf(numbuf[1], "%s", "-");
4066 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4067 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4068 "%s" : "[%s]", strbuf);
4070 printf(" %7s%c %6s %7s %7s",
4071 numbuf[0], bover ? '*' : ' ', numbuf[1],
4072 numbuf[2], bover > 1 ? timebuf : "-");
4075 diff2str(dqb->dqb_itime, timebuf, now);
4077 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4078 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4080 if (type == QC_GENERAL)
4081 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4083 (uintmax_t)dqb->dqb_isoftlimit);
4085 sprintf(numbuf[1], "%s", "-");
4087 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4088 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4090 if (type != QC_OSTIDX)
4091 printf(" %7s%c %6s %7s %7s",
4092 numbuf[0], iover ? '*' : ' ', numbuf[1],
4093 numbuf[2], iover > 1 ? timebuf : "-");
4095 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4098 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4099 qctl->qc_cmd == Q_GETOINFO) {
4103 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4104 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4105 printf("Block grace time: %s; Inode grace time: %s\n",
4106 bgtimebuf, igtimebuf);
4110 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4111 bool h, __u64 *total)
4113 int rc = 0, rc1 = 0, count = 0;
4114 __u32 valid = qctl->qc_valid;
4116 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4118 fprintf(stderr, "can not get %s count: %s\n",
4119 is_mdt ? "mdt": "ost", strerror(-rc));
4123 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4124 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4125 rc = llapi_quotactl(mnt, qctl);
4127 /* It is remote client case. */
4128 if (rc == -EOPNOTSUPP) {
4135 fprintf(stderr, "quotactl %s%d failed.\n",
4136 is_mdt ? "mdt": "ost", qctl->qc_idx);
4140 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4141 qctl->qc_valid, 0, h);
4142 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4143 qctl->qc_dqblk.dqb_bhardlimit;
4146 qctl->qc_valid = valid;
4150 static int lfs_quota(int argc, char **argv)
4153 char *mnt, *name = NULL;
4154 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4155 .qc_type = ALLQUOTA };
4156 char *obd_type = (char *)qctl.obd_type;
4157 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4158 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4159 verbose = 0, pass = 0, quiet = 0, inacc;
4161 __u32 valid = QC_GENERAL, idx = 0;
4162 __u64 total_ialloc = 0, total_balloc = 0;
4163 bool human_readable = false;
4166 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4177 if (qctl.qc_type != ALLQUOTA) {
4178 fprintf(stderr, "error: use either -u or -g\n");
4181 qctl.qc_type = qtype;
4184 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4187 valid = qctl.qc_valid = QC_UUID;
4188 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4191 valid = qctl.qc_valid = QC_MDTIDX;
4192 idx = qctl.qc_idx = atoi(optarg);
4195 valid = qctl.qc_valid = QC_OSTIDX;
4196 idx = qctl.qc_idx = atoi(optarg);
4205 human_readable = true;
4208 fprintf(stderr, "error: %s: option '-%c' "
4209 "unrecognized\n", argv[0], c);
4214 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4215 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4216 optind == argc - 1) {
4218 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4219 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4220 qctl.qc_valid = valid;
4222 qctl.qc_type = pass;
4223 switch (qctl.qc_type) {
4225 qctl.qc_id = geteuid();
4226 rc = uid2name(&name, qctl.qc_id);
4229 qctl.qc_id = getegid();
4230 rc = gid2name(&name, qctl.qc_id);
4240 /* lfs quota -u username /path/to/lustre/mount */
4241 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4242 /* options should be followed by u/g-name and mntpoint */
4243 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4244 fprintf(stderr, "error: missing quota argument(s)\n");
4248 name = argv[optind++];
4249 switch (qctl.qc_type) {
4251 rc = name2uid(&qctl.qc_id, name);
4254 rc = name2gid(&qctl.qc_id, name);
4257 rc = name2projid(&qctl.qc_id, name);
4264 qctl.qc_id = strtoul(name, &endptr, 10);
4265 if (*endptr != '\0') {
4266 fprintf(stderr, "error: can't find id for name: %s\n",
4271 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4272 fprintf(stderr, "error: missing quota info argument(s)\n");
4277 rc1 = llapi_quotactl(mnt, &qctl);
4281 fprintf(stderr, "%s quotas are not enabled.\n",
4282 qtype_name(qctl.qc_type));
4285 fprintf(stderr, "Permission denied.\n");
4288 /* We already got error message. */
4291 fprintf(stderr, "Unexpected quotactl error: %s\n",
4296 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4297 print_quota_title(name, &qctl, human_readable);
4299 if (rc1 && *obd_type)
4300 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4302 if (qctl.qc_valid != QC_GENERAL)
4305 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4306 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4307 (QIF_LIMITS|QIF_USAGE));
4309 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4311 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4313 char strbuf[STRBUF_LEN];
4315 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4317 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4319 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4321 printf("Total allocated inode limit: %ju, total "
4322 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4326 if (rc1 || rc2 || rc3 || inacc)
4327 printf("Some errors happened when getting quota info. "
4328 "Some devices may be not working or deactivated. "
4329 "The data in \"[]\" is inaccurate.\n");
4332 if (pass > 0 && pass < LL_MAXQUOTAS)
4337 #endif /* HAVE_SYS_QUOTA_H! */
4339 static int flushctx_ioctl(char *mp)
4343 fd = open(mp, O_RDONLY);
4345 fprintf(stderr, "flushctx: error open %s: %s\n",
4346 mp, strerror(errno));
4350 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4352 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4353 mp, strerror(errno));
4359 static int lfs_flushctx(int argc, char **argv)
4361 int kdestroy = 0, c;
4362 char mntdir[PATH_MAX] = {'\0'};
4366 while ((c = getopt(argc, argv, "k")) != -1) {
4372 fprintf(stderr, "error: %s: option '-%c' "
4373 "unrecognized\n", argv[0], c);
4379 if ((rc = system("kdestroy > /dev/null")) != 0) {
4380 rc = WEXITSTATUS(rc);
4381 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4385 if (optind >= argc) {
4386 /* flush for all mounted lustre fs. */
4387 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4388 /* Check if we have a mount point */
4389 if (mntdir[0] == '\0')
4392 if (flushctx_ioctl(mntdir))
4395 mntdir[0] = '\0'; /* avoid matching in next loop */
4398 /* flush fs as specified */
4399 while (optind < argc) {
4400 if (flushctx_ioctl(argv[optind++]))
4407 static int lfs_cp(int argc, char **argv)
4409 fprintf(stderr, "remote client copy file(s).\n"
4410 "obsolete, does not support it anymore.\n");
4414 static int lfs_ls(int argc, char **argv)
4416 fprintf(stderr, "remote client lists directory contents.\n"
4417 "obsolete, does not support it anymore.\n");
4421 static int lfs_changelog(int argc, char **argv)
4423 void *changelog_priv;
4424 struct changelog_rec *rec;
4425 long long startrec = 0, endrec = 0;
4427 struct option long_opts[] = {
4428 { .val = 'f', .name = "follow", .has_arg = no_argument },
4430 char short_opts[] = "f";
4433 while ((rc = getopt_long(argc, argv, short_opts,
4434 long_opts, NULL)) != -1) {
4442 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4443 argv[0], argv[optind - 1]);
4450 mdd = argv[optind++];
4452 startrec = strtoll(argv[optind++], NULL, 10);
4454 endrec = strtoll(argv[optind++], NULL, 10);
4456 rc = llapi_changelog_start(&changelog_priv,
4457 CHANGELOG_FLAG_BLOCK |
4458 CHANGELOG_FLAG_JOBID |
4459 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4462 fprintf(stderr, "Can't start changelog: %s\n",
4463 strerror(errno = -rc));
4467 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4471 if (endrec && rec->cr_index > endrec) {
4472 llapi_changelog_free(&rec);
4475 if (rec->cr_index < startrec) {
4476 llapi_changelog_free(&rec);
4480 secs = rec->cr_time >> 30;
4481 gmtime_r(&secs, &ts);
4482 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4483 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4484 changelog_type2str(rec->cr_type),
4485 ts.tm_hour, ts.tm_min, ts.tm_sec,
4486 (int)(rec->cr_time & ((1 << 30) - 1)),
4487 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4488 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4490 if (rec->cr_flags & CLF_JOBID) {
4491 struct changelog_ext_jobid *jid =
4492 changelog_rec_jobid(rec);
4494 if (jid->cr_jobid[0] != '\0')
4495 printf(" j=%s", jid->cr_jobid);
4498 if (rec->cr_namelen)
4499 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4500 rec->cr_namelen, changelog_rec_name(rec));
4502 if (rec->cr_flags & CLF_RENAME) {
4503 struct changelog_ext_rename *rnm =
4504 changelog_rec_rename(rec);
4506 if (!fid_is_zero(&rnm->cr_sfid))
4507 printf(" s="DFID" sp="DFID" %.*s",
4508 PFID(&rnm->cr_sfid),
4509 PFID(&rnm->cr_spfid),
4510 (int)changelog_rec_snamelen(rec),
4511 changelog_rec_sname(rec));
4515 llapi_changelog_free(&rec);
4518 llapi_changelog_fini(&changelog_priv);
4521 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4523 return (rc == 1 ? 0 : rc);
4526 static int lfs_changelog_clear(int argc, char **argv)
4534 endrec = strtoll(argv[3], NULL, 10);
4536 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4539 fprintf(stderr, "%s: record out of range: %llu\n",
4541 else if (rc == -ENOENT)
4542 fprintf(stderr, "%s: no changelog user: %s\n",
4545 fprintf(stderr, "%s error: %s\n", argv[0],
4554 static int lfs_fid2path(int argc, char **argv)
4556 struct option long_opts[] = {
4557 { .val = 'c', .name = "cur", .has_arg = no_argument },
4558 { .val = 'l', .name = "link", .has_arg = required_argument },
4559 { .val = 'r', .name = "rec", .has_arg = required_argument },
4561 char short_opts[] = "cl:r:";
4562 char *device, *fid, *path;
4563 long long recno = -1;
4569 while ((rc = getopt_long(argc, argv, short_opts,
4570 long_opts, NULL)) != -1) {
4576 linkno = strtol(optarg, NULL, 10);
4579 recno = strtoll(optarg, NULL, 10);
4584 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4585 argv[0], argv[optind - 1]);
4593 device = argv[optind++];
4594 path = calloc(1, PATH_MAX);
4596 fprintf(stderr, "error: Not enough memory\n");
4601 while (optind < argc) {
4602 fid = argv[optind++];
4604 lnktmp = (linkno >= 0) ? linkno : 0;
4606 int oldtmp = lnktmp;
4607 long long rectmp = recno;
4609 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4612 fprintf(stderr, "%s: error on FID %s: %s\n",
4613 argv[0], fid, strerror(errno = -rc2));
4620 fprintf(stdout, "%lld ", rectmp);
4621 if (device[0] == '/') {
4622 fprintf(stdout, "%s", device);
4623 if (device[strlen(device) - 1] != '/')
4624 fprintf(stdout, "/");
4625 } else if (path[0] == '\0') {
4626 fprintf(stdout, "/");
4628 fprintf(stdout, "%s\n", path);
4631 /* specified linkno */
4633 if (oldtmp == lnktmp)
4643 static int lfs_path2fid(int argc, char **argv)
4645 struct option long_opts[] = {
4646 { .val = 'p', .name = "parents", .has_arg = no_argument },
4649 const char short_opts[] = "p";
4650 const char *sep = "";
4653 bool show_parents = false;
4655 while ((rc = getopt_long(argc, argv, short_opts,
4656 long_opts, NULL)) != -1) {
4659 show_parents = true;
4662 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4663 argv[0], argv[optind - 1]);
4668 if (optind > argc - 1)
4670 else if (optind < argc - 1)
4674 for (path = argv + optind; *path != NULL; path++) {
4676 if (!show_parents) {
4677 err = llapi_path2fid(*path, &fid);
4679 printf("%s%s"DFID"\n",
4680 *sep != '\0' ? *path : "", sep,
4683 char name[NAME_MAX + 1];
4684 unsigned int linkno = 0;
4686 while ((err = llapi_path2parent(*path, linkno, &fid,
4687 name, sizeof(name))) == 0) {
4688 if (*sep != '\0' && linkno == 0)
4689 printf("%s%s", *path, sep);
4691 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4696 /* err == -ENODATA is end-of-loop */
4697 if (linkno > 0 && err == -ENODATA) {
4704 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4705 argv[0], show_parents ? "parent " : "", *path,
4717 static int lfs_data_version(int argc, char **argv)
4724 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4729 while ((c = getopt(argc, argv, "nrw")) != -1) {
4732 data_version_flags = 0;
4735 data_version_flags |= LL_DV_RD_FLUSH;
4738 data_version_flags |= LL_DV_WR_FLUSH;
4747 path = argv[optind];
4748 fd = open(path, O_RDONLY);
4750 err(errno, "cannot open file %s", path);
4752 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4754 err(errno, "cannot get version for %s", path);
4756 printf("%ju" "\n", (uintmax_t)data_version);
4762 static int lfs_hsm_state(int argc, char **argv)
4767 struct hsm_user_state hus;
4775 rc = llapi_hsm_state_get(path, &hus);
4777 fprintf(stderr, "can't get hsm state for %s: %s\n",
4778 path, strerror(errno = -rc));
4782 /* Display path name and status flags */
4783 printf("%s: (0x%08x)", path, hus.hus_states);
4785 if (hus.hus_states & HS_RELEASED)
4786 printf(" released");
4787 if (hus.hus_states & HS_EXISTS)
4789 if (hus.hus_states & HS_DIRTY)
4791 if (hus.hus_states & HS_ARCHIVED)
4792 printf(" archived");
4793 /* Display user-settable flags */
4794 if (hus.hus_states & HS_NORELEASE)
4795 printf(" never_release");
4796 if (hus.hus_states & HS_NOARCHIVE)
4797 printf(" never_archive");
4798 if (hus.hus_states & HS_LOST)
4799 printf(" lost_from_hsm");
4801 if (hus.hus_archive_id != 0)
4802 printf(", archive_id:%d", hus.hus_archive_id);
4805 } while (++i < argc);
4810 #define LFS_HSM_SET 0
4811 #define LFS_HSM_CLEAR 1
4814 * Generic function to set or clear HSM flags.
4815 * Used by hsm_set and hsm_clear.
4817 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4819 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4821 struct option long_opts[] = {
4822 { .val = 'A', .name = "archived", .has_arg = no_argument },
4823 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4824 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4825 { .val = 'e', .name = "exists", .has_arg = no_argument },
4826 { .val = 'l', .name = "lost", .has_arg = no_argument },
4827 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4829 char short_opts[] = "lraAde";
4837 while ((c = getopt_long(argc, argv, short_opts,
4838 long_opts, NULL)) != -1) {
4844 mask |= HS_NOARCHIVE;
4847 mask |= HS_ARCHIVED;
4850 mask |= HS_NORELEASE;
4861 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4862 argv[0], argv[optind - 1]);
4867 /* User should have specified a flag */
4871 while (optind < argc) {
4873 path = argv[optind];
4875 /* If mode == 0, this means we apply the mask. */
4876 if (mode == LFS_HSM_SET)
4877 rc = llapi_hsm_state_set(path, mask, 0, 0);
4879 rc = llapi_hsm_state_set(path, 0, mask, 0);
4882 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4883 path, strerror(errno = -rc));
4892 static int lfs_hsm_action(int argc, char **argv)
4897 struct hsm_current_action hca;
4898 struct hsm_extent he;
4899 enum hsm_user_action hua;
4900 enum hsm_progress_states hps;
4908 rc = llapi_hsm_current_action(path, &hca);
4910 fprintf(stderr, "can't get hsm action for %s: %s\n",
4911 path, strerror(errno = -rc));
4914 he = hca.hca_location;
4915 hua = hca.hca_action;
4916 hps = hca.hca_state;
4918 printf("%s: %s", path, hsm_user_action2name(hua));
4920 /* Skip file without action */
4921 if (hca.hca_action == HUA_NONE) {
4926 printf(" %s ", hsm_progress_state2name(hps));
4928 if ((hps == HPS_RUNNING) &&
4929 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4930 printf("(%llu bytes moved)\n",
4931 (unsigned long long)he.length);
4932 else if ((he.offset + he.length) == LUSTRE_EOF)
4933 printf("(from %llu to EOF)\n",
4934 (unsigned long long)he.offset);
4936 printf("(from %llu to %llu)\n",
4937 (unsigned long long)he.offset,
4938 (unsigned long long)(he.offset + he.length));
4940 } while (++i < argc);
4945 static int lfs_hsm_set(int argc, char **argv)
4947 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4950 static int lfs_hsm_clear(int argc, char **argv)
4952 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4956 * Check file state and return its fid, to be used by lfs_hsm_request().
4958 * \param[in] file Path to file to check
4959 * \param[in,out] fid Pointer to allocated lu_fid struct.
4960 * \param[in,out] last_dev Pointer to last device id used.
4962 * \return 0 on success.
4964 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4970 rc = lstat(file, &st);
4972 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4975 /* Checking for regular file as archiving as posix copytool
4976 * rejects archiving files other than regular files
4978 if (!S_ISREG(st.st_mode)) {
4979 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4982 /* A request should be ... */
4983 if (*last_dev != st.st_dev && *last_dev != 0) {
4984 fprintf(stderr, "All files should be "
4985 "on the same filesystem: %s\n", file);
4988 *last_dev = st.st_dev;
4990 rc = llapi_path2fid(file, fid);
4992 fprintf(stderr, "Cannot read FID of %s: %s\n",
4993 file, strerror(-rc));
4999 /* Fill an HSM HUR item with a given file name.
5001 * If mntpath is set, then the filename is actually a FID, and no
5002 * lookup on the filesystem will be performed.
5004 * \param[in] hur the user request to fill
5005 * \param[in] idx index of the item inside the HUR to fill
5006 * \param[in] mntpath mountpoint of Lustre
5007 * \param[in] fname filename (if mtnpath is NULL)
5008 * or FID (if mntpath is set)
5009 * \param[in] last_dev pointer to last device id used
5011 * \retval 0 on success
5012 * \retval CMD_HELP or a negative errno on error
5014 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5015 const char *mntpath, const char *fname,
5018 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5021 hui->hui_extent.length = -1;
5023 if (mntpath != NULL) {
5026 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5030 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5035 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5039 hur->hur_request.hr_itemcount++;
5044 static int lfs_hsm_request(int argc, char **argv, int action)
5046 struct option long_opts[] = {
5047 { .val = 'a', .name = "archive", .has_arg = required_argument },
5048 { .val = 'D', .name = "data", .has_arg = required_argument },
5049 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5050 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5053 char short_opts[] = "l:D:a:m:";
5054 struct hsm_user_request *hur, *oldhur;
5059 char *filelist = NULL;
5060 char fullpath[PATH_MAX];
5061 char *opaque = NULL;
5065 int nbfile_alloc = 0;
5066 char *some_file = NULL;
5067 char *mntpath = NULL;
5073 while ((c = getopt_long(argc, argv, short_opts,
5074 long_opts, NULL)) != -1) {
5083 if (action != HUA_ARCHIVE &&
5084 action != HUA_REMOVE) {
5086 "error: -a is supported only "
5087 "when archiving or removing\n");
5090 archive_id = atoi(optarg);
5093 if (some_file == NULL) {
5095 some_file = strdup(optarg);
5101 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5102 argv[0], argv[optind - 1]);
5107 /* All remaining args are files, so we have at least nbfile */
5108 nbfile = argc - optind;
5110 if ((nbfile == 0) && (filelist == NULL))
5114 opaque_len = strlen(opaque);
5116 /* Alloc the request structure with enough place to store all files
5117 * from command line. */
5118 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5120 fprintf(stderr, "Cannot create the request: %s\n",
5124 nbfile_alloc = nbfile;
5126 hur->hur_request.hr_action = action;
5127 hur->hur_request.hr_archive_id = archive_id;
5128 hur->hur_request.hr_flags = 0;
5130 /* All remaining args are files, add them */
5131 if (nbfile != 0 && some_file == NULL)
5132 some_file = strdup(argv[optind]);
5134 for (i = 0; i < nbfile; i++) {
5135 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5141 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5143 /* If a filelist was specified, read the filelist from it. */
5144 if (filelist != NULL) {
5145 fp = fopen(filelist, "r");
5147 fprintf(stderr, "Cannot read the file list %s: %s\n",
5148 filelist, strerror(errno));
5153 while ((rc = getline(&line, &len, fp)) != -1) {
5154 /* If allocated buffer was too small, get something
5156 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5159 nbfile_alloc = nbfile_alloc * 2 + 1;
5161 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5164 fprintf(stderr, "hsm: cannot allocate "
5165 "the request: %s\n",
5172 size = hur_len(oldhur);
5174 fprintf(stderr, "hsm: cannot allocate "
5175 "%u files + %u bytes data\n",
5176 oldhur->hur_request.hr_itemcount,
5177 oldhur->hur_request.hr_data_len);
5184 memcpy(hur, oldhur, size);
5189 if (line[strlen(line) - 1] == '\n')
5190 line[strlen(line) - 1] = '\0';
5192 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5193 mntpath, line, &last_dev);
5199 if (some_file == NULL) {
5209 /* If a --data was used, add it to the request */
5210 hur->hur_request.hr_data_len = opaque_len;
5212 memcpy(hur_data(hur), opaque, opaque_len);
5214 /* Send the HSM request */
5215 if (realpath(some_file, fullpath) == NULL) {
5216 fprintf(stderr, "Could not find path '%s': %s\n",
5217 some_file, strerror(errno));
5219 rc = llapi_hsm_request(fullpath, hur);
5221 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5222 some_file, strerror(-rc));
5232 static int lfs_hsm_archive(int argc, char **argv)
5234 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5237 static int lfs_hsm_restore(int argc, char **argv)
5239 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5242 static int lfs_hsm_release(int argc, char **argv)
5244 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5247 static int lfs_hsm_remove(int argc, char **argv)
5249 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5252 static int lfs_hsm_cancel(int argc, char **argv)
5254 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5257 static int lfs_swap_layouts(int argc, char **argv)
5262 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5263 SWAP_LAYOUTS_KEEP_MTIME |
5264 SWAP_LAYOUTS_KEEP_ATIME);
5267 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5269 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5271 static const char *const lockahead_results[] = {
5272 [LLA_RESULT_SENT] = "Lock request sent",
5273 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5274 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5277 int lfs_get_mode(const char *string)
5279 enum lock_mode_user mode;
5281 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5282 if (lock_mode_names[mode] == NULL)
5284 if (strcmp(string, lock_mode_names[mode]) == 0)
5291 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5293 enum lu_ladvise_type advice;
5296 advice < ARRAY_SIZE(ladvise_names); advice++) {
5297 if (ladvise_names[advice] == NULL)
5299 if (strcmp(string, ladvise_names[advice]) == 0)
5303 return LU_LADVISE_INVALID;
5306 static int lfs_ladvise(int argc, char **argv)
5308 struct option long_opts[] = {
5309 { .val = 'a', .name = "advice", .has_arg = required_argument },
5310 { .val = 'b', .name = "background", .has_arg = no_argument },
5311 { .val = 'e', .name = "end", .has_arg = required_argument },
5312 { .val = 'l', .name = "length", .has_arg = required_argument },
5313 { .val = 'm', .name = "mode", .has_arg = required_argument },
5314 { .val = 's', .name = "start", .has_arg = required_argument },
5315 { .val = 'u', .name = "unset", .has_arg = no_argument },
5317 char short_opts[] = "a:be:l:m:s:u";
5322 struct llapi_lu_ladvise advice;
5323 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5324 unsigned long long start = 0;
5325 unsigned long long end = LUSTRE_EOF;
5326 unsigned long long length = 0;
5327 unsigned long long size_units;
5328 unsigned long long flags = 0;
5332 while ((c = getopt_long(argc, argv, short_opts,
5333 long_opts, NULL)) != -1) {
5336 advice_type = lfs_get_ladvice(optarg);
5337 if (advice_type == LU_LADVISE_INVALID) {
5338 fprintf(stderr, "%s: invalid advice type "
5339 "'%s'\n", argv[0], optarg);
5340 fprintf(stderr, "Valid types:");
5342 for (advice_type = 0;
5343 advice_type < ARRAY_SIZE(ladvise_names);
5345 if (ladvise_names[advice_type] == NULL)
5347 fprintf(stderr, " %s",
5348 ladvise_names[advice_type]);
5350 fprintf(stderr, "\n");
5363 rc = llapi_parse_size(optarg, &end,
5366 fprintf(stderr, "%s: bad end offset '%s'\n",
5373 rc = llapi_parse_size(optarg, &start,
5376 fprintf(stderr, "%s: bad start offset "
5377 "'%s'\n", argv[0], optarg);
5383 rc = llapi_parse_size(optarg, &length,
5386 fprintf(stderr, "%s: bad length '%s'\n",
5392 mode = lfs_get_mode(optarg);
5394 fprintf(stderr, "%s: bad mode '%s', valid "
5395 "modes are READ or WRITE\n",
5403 fprintf(stderr, "%s: option '%s' unrecognized\n",
5404 argv[0], argv[optind - 1]);
5409 if (advice_type == LU_LADVISE_INVALID) {
5410 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5411 fprintf(stderr, "Valid types:");
5412 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5414 if (ladvise_names[advice_type] == NULL)
5416 fprintf(stderr, " %s", ladvise_names[advice_type]);
5418 fprintf(stderr, "\n");
5422 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
5423 fprintf(stderr, "%s: Lock no expand advice is a per file "
5424 "descriptor advice, so when called from lfs, "
5425 "it does nothing.\n", argv[0]);
5429 if (argc <= optind) {
5430 fprintf(stderr, "%s: please give one or more file names\n",
5435 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5436 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5441 if (end == LUSTRE_EOF && length != 0)
5442 end = start + length;
5445 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5446 argv[0], start, end);
5450 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
5451 fprintf(stderr, "%s: mode is only valid with lockahead\n",
5456 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
5457 fprintf(stderr, "%s: mode is required with lockahead\n",
5462 while (optind < argc) {
5465 path = argv[optind++];
5467 fd = open(path, O_RDONLY);
5469 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5470 argv[0], path, strerror(errno));
5475 advice.lla_start = start;
5476 advice.lla_end = end;
5477 advice.lla_advice = advice_type;
5478 advice.lla_value1 = 0;
5479 advice.lla_value2 = 0;
5480 advice.lla_value3 = 0;
5481 advice.lla_value4 = 0;
5482 if (advice_type == LU_LADVISE_LOCKAHEAD) {
5483 advice.lla_lockahead_mode = mode;
5484 advice.lla_peradvice_flags = flags;
5487 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5490 fprintf(stderr, "%s: cannot give advice '%s' to file "
5491 "'%s': %s\n", argv[0],
5492 ladvise_names[advice_type],
5493 path, strerror(errno));
5499 if (rc == 0 && rc2 < 0)
5505 static int lfs_list_commands(int argc, char **argv)
5507 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5509 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5514 int main(int argc, char **argv)
5518 /* Ensure that liblustreapi constructor has run */
5519 if (!liblustreapi_initialized)
5520 fprintf(stderr, "liblustreapi was not properly initialized\n");
5525 Parser_init("lfs > ", cmdlist);
5527 progname = argv[0]; /* Used in error messages */
5529 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5531 rc = Parser_commands();
5533 return rc < 0 ? -rc : rc;
5536 #ifdef _LUSTRE_IDL_H_
5537 /* Everything we need here should be included by lustreapi.h. */
5538 # error "lfs should not depend on lustre_idl.h"
5539 #endif /* _LUSTRE_IDL_H_ */