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 " [--pool|-p <pool_name>]\n" \
121 " [--ost|-o <ost_indices>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
125 "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
126 "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \
127 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
128 "\t respectively)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool.\n" \
137 "\tcomp_end: Extent end of component, start after previous end.\n"\
138 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
139 "\t respectively, -1 for EOF). Must be a multiple of\n"\
143 #define MIGRATE_USAGE \
144 SSM_CMD_COMMON("migrate ") \
146 " [--non-block|-n]\n" \
150 "\tblock: Block file access during data migration (default)\n" \
151 "\tnon-block: Abort migrations if concurrent access is detected\n" \
153 #define SETDIRSTRIPE_USAGE \
154 " [--mdt-count|-c stripe_count>\n" \
155 " [--mdt-index|-i mdt_index]\n" \
156 " [--mdt-hash|-H mdt_hash]\n" \
157 " [--default|-D] [--mode|-m mode] <dir>\n" \
158 "\tstripe_count: stripe count of the striped directory\n" \
159 "\tmdt_index: MDT index of first stripe\n" \
160 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
161 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
162 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
163 "\tdefault_stripe: set default dirstripe of the directory\n" \
164 "\tmode: the mode of the directory\n"
166 static const char *progname;
167 static bool file_lease_supported = true;
169 /* all available commands */
170 command_t cmdlist[] = {
171 {"setstripe", lfs_setstripe, 0,
172 "To create a file with specified striping/composite layout, or\n"
173 "create/replace the default layout on an existing directory:\n"
174 SSM_CMD_COMMON("setstripe")
175 " <directory|filename>\n"
177 "To add component(s) to an existing composite file:\n"
178 SSM_CMD_COMMON("setstripe --component-add")
180 "To totally delete the default striping from an existing directory:\n"
181 "usage: setstripe -d <directory>\n"
183 "To delete the last component(s) from an existing composite file\n"
184 "(note that this will also delete any data in those components):\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID to delete\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t '^init' indicating all uninstantiated components\n"
191 "\t-I and -F cannot be specified at the same time\n"},
192 {"getstripe", lfs_getstripe, 0,
193 "To list the striping info for a given file or files in a\n"
194 "directory or recursively for all files in a directory tree.\n"
195 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
196 " [--stripe-count|-c] [--stripe-index|-i]\n"
197 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
198 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
199 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
200 " [--component-id[=comp_id]|-I[comp_id]]\n"
201 " [--component-flags[=comp_flags]]\n"
202 " [--component-count]\n"
203 " [--component-start[=[+-]comp_start]]\n"
204 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
205 " <directory|filename> ..."},
206 {"setdirstripe", lfs_setdirstripe, 0,
207 "To create a striped directory on a specified MDT. This can only\n"
208 "be done on MDT0 with the right of administrator.\n"
209 "usage: setdirstripe [OPTION] <directory>\n"
211 {"getdirstripe", lfs_getdirstripe, 0,
212 "To list the striping info for a given directory\n"
213 "or recursively for all directories in a directory tree.\n"
214 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
215 " [--mdt-index|-i] [--mdt-hash|-t]\n"
216 " [--recursive|-r] [--yaml|-y]\n"
217 " [--default|-D] <dir> ..."},
218 {"mkdir", lfs_setdirstripe, 0,
219 "To create a striped directory on a specified MDT. This can only\n"
220 "be done on MDT0 with the right of administrator.\n"
221 "usage: mkdir [OPTION] <directory>\n"
223 {"rm_entry", lfs_rmentry, 0,
224 "To remove the name entry of the remote directory. Note: This\n"
225 "command will only delete the name entry, i.e. the remote directory\n"
226 "will become inaccessable after this command. This can only be done\n"
227 "by the administrator\n"
228 "usage: rm_entry <dir>\n"},
229 {"pool_list", lfs_poollist, 0,
230 "List pools or pool OSTs\n"
231 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
232 {"find", lfs_find, 0,
233 "find files matching given attributes recursively in directory tree.\n"
234 "usage: find <directory|filename> ...\n"
235 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
236 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
237 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
238 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
239 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
240 " [[!] --stripe-count|-c [+-]<stripes>]\n"
241 " [[!] --stripe-index|-i <index,...>]\n"
242 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
243 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
244 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
245 " [[!] --projid <projid>]\n"
246 " [[!] --layout|-L released,raid0]\n"
247 " [[!] --component-count [+-]<comp_cnt>]\n"
248 " [[!] --component-start [+-]N[kMGTPE]]\n"
249 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
250 " [[!] --component-flags <comp_flags>]\n"
251 " [[!] --mdt-count|-T [+-]<stripes>]\n"
252 " [[!] --mdt-hash|-H <hashtype>\n"
253 "\t !: used before an option indicates 'NOT' requested attribute\n"
254 "\t -: used before a value indicates less than requested value\n"
255 "\t +: used before a value indicates more than requested value\n"
256 "\tmdt-hash: hash type of the striped directory.\n"
257 "\t fnv_1a_64 FNV-1a hash algorithm\n"
258 "\t all_char sum of characters % MDT_COUNT\n"},
259 {"check", lfs_check, 0,
260 "Display the status of MDS or OSTs (as specified in the command)\n"
261 "or all the servers (MDS and OSTs).\n"
262 "usage: check <osts|mds|servers>"},
263 {"osts", lfs_osts, 0, "list OSTs connected to client "
264 "[for specified path only]\n" "usage: osts [path]"},
265 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
266 "[for specified path only]\n" "usage: mdts [path]"},
268 "report filesystem disk space usage or inodes usage"
269 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
270 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
271 {"getname", lfs_getname, 0, "list instances and specified mount points "
272 "[for specified path only]\n"
273 "Usage: getname [-h]|[path ...] "},
274 #ifdef HAVE_SYS_QUOTA_H
275 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
276 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
277 " -b <block-softlimit> -B <block-hardlimit>\n"
278 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
279 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
280 " [--block-softlimit <block-softlimit>]\n"
281 " [--block-hardlimit <block-hardlimit>]\n"
282 " [--inode-softlimit <inode-softlimit>]\n"
283 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
284 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
285 " [--block-grace <block-grace>]\n"
286 " [--inode-grace <inode-grace>] <filesystem>\n"
287 " -b can be used instead of --block-softlimit/--block-grace\n"
288 " -B can be used instead of --block-hardlimit\n"
289 " -i can be used instead of --inode-softlimit/--inode-grace\n"
290 " -I can be used instead of --inode-hardlimit\n\n"
291 "Note: The total quota space will be split into many qunits and\n"
292 " balanced over all server targets, the minimal qunit size is\n"
293 " 1M bytes for block space and 1K inodes for inode space.\n\n"
294 " Quota space rebalancing process will stop when this mininum\n"
295 " value is reached. As a result, quota exceeded can be returned\n"
296 " while many targets still have 1MB or 1K inodes of spare\n"
298 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
299 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
301 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
302 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
304 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
305 "usage: flushctx [-k] [mountpoint...]"},
307 "Remote user copy files and directories.\n"
308 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
310 "Remote user list directory contents.\n"
311 "usage: ls [OPTION]... [FILE]..."},
312 {"changelog", lfs_changelog, 0,
313 "Show the metadata changes on an MDT."
314 "\nusage: changelog <mdtname> [startrec [endrec]]"},
315 {"changelog_clear", lfs_changelog_clear, 0,
316 "Indicate that old changelog records up to <endrec> are no longer of "
317 "interest to consumer <id>, allowing the system to free up space.\n"
318 "An <endrec> of 0 means all records.\n"
319 "usage: changelog_clear <mdtname> <id> <endrec>"},
320 {"fid2path", lfs_fid2path, 0,
321 "Resolve the full path(s) for given FID(s). For a specific hardlink "
322 "specify link number <linkno>.\n"
323 /* "For a historical link name, specify changelog record <recno>.\n" */
324 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
325 /* [ --rec <recno> ] */ },
326 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
327 "usage: path2fid [--parents] <path> ..."},
328 {"data_version", lfs_data_version, 0, "Display file data version for "
329 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
330 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
331 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
332 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
333 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
334 "[--archived] [--lost] <file> ..."},
335 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
337 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
338 "[--archived] [--lost] <file> ..."},
339 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
340 "given files.\n" "usage: hsm_action <file> ..."},
341 {"hsm_archive", lfs_hsm_archive, 0,
342 "Archive file to external storage.\n"
343 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
345 {"hsm_restore", lfs_hsm_restore, 0,
346 "Restore file from external storage.\n"
347 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
348 {"hsm_release", lfs_hsm_release, 0,
349 "Release files from Lustre.\n"
350 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
351 {"hsm_remove", lfs_hsm_remove, 0,
352 "Remove file copy from external storage.\n"
353 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
354 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
356 "Note: To remove files from the archive that have been deleted on\n"
357 "Lustre, set mntpath and optionally archive. In that case, all the\n"
358 "positional arguments and entries in the file list must be FIDs."
360 {"hsm_cancel", lfs_hsm_cancel, 0,
361 "Cancel requests related to specified files.\n"
362 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
363 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
364 "usage: swap_layouts <path1> <path2>"},
365 {"migrate", lfs_setstripe, 0,
366 "migrate a directory between MDTs.\n"
367 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
369 "\tmdt_idx: index of the destination MDT\n"
371 "migrate file objects from one OST "
372 "layout\nto another (may be not safe with concurent writes).\n"
374 "[--stripe-count|-c] <stripe_count>\n"
375 " [--stripe-index|-i] <start_ost_index>\n"
376 " [--stripe-size|-S] <stripe_size>\n"
377 " [--pool|-p] <pool_name>\n"
378 " [--ost-list|-o] <ost_indices>\n"
380 " [--non-block|-n]\n"
381 " <file|directory>\n"
382 "\tstripe_count: number of OSTs to stripe a file over\n"
383 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
384 "\tstripe_size: number of bytes to store before moving to the next OST\n"
385 "\tpool_name: name of the predefined pool of OSTs\n"
386 "\tost_indices: OSTs to stripe over, in order\n"
387 "\tblock: wait for the operation to return before continuing\n"
388 "\tnon-block: do not wait for the operation to return.\n"},
390 "To move directories between MDTs. This command is deprecated, "
391 "use \"migrate\" instead.\n"
392 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
394 {"ladvise", lfs_ladvise, 0,
395 "Provide servers with advice about access patterns for a file.\n"
396 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
397 " [--background|-b] [--unset|-u]\n\n"
398 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
399 " {[--mode|-m [READ,WRITE]}\n"
401 {"help", Parser_help, 0, "help"},
402 {"exit", Parser_quit, 0, "quit"},
403 {"quit", Parser_quit, 0, "quit"},
404 {"--version", Parser_version, 0,
405 "output build version of the utility and exit"},
406 {"--list-commands", lfs_list_commands, 0,
407 "list commands supported by the utility and exit"},
412 #define MIGRATION_NONBLOCK 1
414 static int check_hashtype(const char *hashtype)
418 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
419 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
426 * Internal helper for migrate_copy_data(). Check lease and report error if
429 * \param[in] fd File descriptor on which to check the lease.
430 * \param[out] lease_broken Set to true if the lease was broken.
431 * \param[in] group_locked Whether a group lock was taken or not.
432 * \param[in] path Name of the file being processed, for error
435 * \retval 0 Migration can keep on going.
436 * \retval -errno Error occurred, abort migration.
438 static int check_lease(int fd, bool *lease_broken, bool group_locked,
443 if (!file_lease_supported)
446 rc = llapi_lease_check(fd);
448 return 0; /* llapi_check_lease returns > 0 on success. */
451 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
453 rc = rc ? rc : -EAGAIN;
455 fprintf(stderr, "%s: external attempt to access file '%s' "
456 "blocked until migration ends.\n", progname, path);
459 *lease_broken = true;
463 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
464 bool group_locked, const char *fname)
473 bool lease_broken = false;
475 /* Use a page-aligned buffer for direct I/O */
476 rc = posix_memalign(&buf, getpagesize(), buf_size);
481 /* read new data only if we have written all
482 * previously read data */
485 rc = check_lease(fd_src, &lease_broken,
486 group_locked, fname);
490 rsize = read(fd_src, buf, buf_size);
493 fprintf(stderr, "%s: %s: read failed: %s\n",
494 progname, fname, strerror(-rc));
504 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
508 "%s: %s: write failed on volatile: %s\n",
509 progname, fname, strerror(-rc));
519 fprintf(stderr, "%s: %s: fsync failed: %s\n",
520 progname, fname, strerror(-rc));
528 static int migrate_copy_timestamps(int fdv, const struct stat *st)
530 struct timeval tv[2] = {
531 {.tv_sec = st->st_atime},
532 {.tv_sec = st->st_mtime}
535 return futimes(fdv, tv);
538 static int migrate_block(int fd, int fdv, const struct stat *st,
539 size_t buf_size, const char *name)
546 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
548 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
549 progname, name, strerror(-rc));
557 /* The grouplock blocks all concurrent accesses to the file.
558 * It has to be taken after llapi_get_data_version as it would
560 rc = llapi_group_lock(fd, gid);
562 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
563 progname, name, strerror(-rc));
567 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
569 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
573 /* Make sure we keep original atime/mtime values */
574 rc = migrate_copy_timestamps(fdv, st);
576 fprintf(stderr, "%s: %s: timestamp copy failed\n",
582 * for a migration we need to check data version on file did
585 * Pass in gid=0 since we already own grouplock. */
586 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
587 SWAP_LAYOUTS_CHECK_DV1);
589 fprintf(stderr, "%s: %s: dataversion changed during copy, "
590 "migration aborted\n", progname, name);
593 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
594 name, strerror(-rc));
599 rc2 = llapi_group_unlock(fd, gid);
600 if (rc2 < 0 && rc == 0) {
601 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
602 progname, name, strerror(-rc2));
609 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
610 size_t buf_size, const char *name)
616 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
618 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
619 progname, name, strerror(-rc));
623 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
625 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
629 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
631 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
632 progname, name, strerror(-rc));
638 fprintf(stderr, "%s: %s: data version changed during "
644 /* Make sure we keep original atime/mtime values */
645 rc = migrate_copy_timestamps(fdv, st);
647 fprintf(stderr, "%s: %s: timestamp copy failed\n",
652 /* Atomically put lease, swap layouts and close.
653 * for a migration we need to check data version on file did
655 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
657 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
658 progname, name, strerror(-rc));
665 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
670 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
674 if (flags != 0 && comp_id != 0)
677 /* LCME_FL_INIT is the only supported flag in PFL */
679 if (flags & ~LCME_KNOWN_FLAGS) {
680 fprintf(stderr, "Invalid component flags %#x\n", flags);
683 } else if (comp_id > LCME_ID_MAX) {
684 fprintf(stderr, "Invalid component id %u\n", comp_id);
688 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
690 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
691 comp_id, fname, strerror(errno));
695 static int lfs_component_add(char *fname, struct llapi_layout *layout)
702 rc = llapi_layout_file_comp_add(fname, layout);
704 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
705 fname, strerror(errno));
709 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
710 struct llapi_layout *layout)
718 fd = lstat(fname, &st);
719 if (fd == 0 && S_ISDIR(st.st_mode))
720 open_flags = O_DIRECTORY | O_RDONLY;
722 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
724 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
725 S_ISDIR(st.st_mode) ?
726 "set default composite layout for" :
727 "create composite file",
728 fname, strerror(errno));
732 static int lfs_migrate(char *name, __u64 migration_flags,
733 struct llapi_stripe_param *param,
734 struct llapi_layout *layout)
738 char parent[PATH_MAX];
741 char volatile_file[sizeof(parent) +
742 LUSTRE_VOLATILE_HDR_LEN +
743 2 * sizeof(mdt_index) +
744 2 * sizeof(random_value) + 4];
747 struct lov_user_md *lum = NULL;
749 int buf_size = 1024 * 1024 * 4;
750 bool have_lease_rdlck = false;
754 /* find the right size for the IO and allocate the buffer */
755 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
756 lum = malloc(lum_size);
762 rc = llapi_file_get_stripe(name, lum);
763 /* failure can happen for many reasons and some may be not real errors
765 * in case of a real error, a later call will fail with better
766 * error management */
768 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
769 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
770 lum->lmm_stripe_size != 0)
771 buf_size = lum->lmm_stripe_size;
774 /* open file, direct io */
775 /* even if the file is only read, WR mode is nedeed to allow
776 * layout swap on fd */
777 fd = open(name, O_RDWR | O_DIRECT);
780 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, name,
785 if (file_lease_supported) {
786 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
787 if (rc == -EOPNOTSUPP) {
788 /* Older servers do not support file lease.
789 * Disable related checks. This opens race conditions
790 * as explained in LU-4840 */
791 file_lease_supported = false;
793 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
794 progname, name, strerror(-rc));
797 have_lease_rdlck = true;
801 /* search for file directory pathname */
802 if (strlen(name) > sizeof(parent)-1) {
806 strncpy(parent, name, sizeof(parent));
807 ptr = strrchr(parent, '/');
809 if (getcwd(parent, sizeof(parent)) == NULL) {
820 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
822 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
823 progname, name, strerror(-rc));
828 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
829 mode_t open_mode = S_IRUSR | S_IWUSR;
831 random_value = random();
832 rc = snprintf(volatile_file, sizeof(volatile_file),
833 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
834 mdt_index, random_value);
835 if (rc >= sizeof(volatile_file)) {
840 /* create, open a volatile file, use caching (ie no directio) */
842 fdv = llapi_file_open_param(volatile_file, open_flags,
844 else if (layout != NULL)
845 fdv = lfs_component_create(volatile_file, open_flags,
849 } while (fdv == -EEXIST);
853 fprintf(stderr, "%s: %s: cannot create volatile file in"
855 progname, parent, strerror(-rc));
859 /* In case the MDT does not support creation of volatile files
860 * we should try to unlink it. */
861 (void)unlink(volatile_file);
863 /* Not-owner (root?) special case.
864 * Need to set owner/group of volatile file like original.
865 * This will allow to pass related check during layout_swap.
870 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
874 rc = fstat(fdv, &stv);
877 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
878 volatile_file, strerror(errno));
881 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
882 rc = fchown(fdv, st.st_uid, st.st_gid);
885 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
886 name, strerror(errno));
891 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
892 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
894 have_lease_rdlck = false;
895 fdv = -1; /* The volatile file is closed as we put the
896 * lease in non-blocking mode. */
899 /* Blocking mode (forced if servers do not support file lease).
900 * It is also the default mode, since we cannot distinguish
901 * between a broken lease and a server that does not support
902 * atomic swap/close (LU-6785) */
903 rc = migrate_block(fd, fdv, &st, buf_size, name);
907 if (have_lease_rdlck)
924 * Parse a string containing an OST index list into an array of integers.
926 * The input string contains a comma delimited list of individual
927 * indices and ranges, for example "1,2-4,7". Add the indices into the
928 * \a osts array and remove duplicates.
930 * \param[out] osts array to store indices in
931 * \param[in] size size of \a osts array
932 * \param[in] offset starting index in \a osts
933 * \param[in] arg string containing OST index list
935 * \retval positive number of indices in \a osts
936 * \retval -EINVAL unable to parse \a arg
938 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
942 int slots = size - offset;
950 while (!end_of_loop) {
958 ptr = strchrnul(arg, ',');
960 end_of_loop = *ptr == '\0';
963 start_index = strtol(arg, &endptr, 0);
964 if (endptr == arg) /* no data at all */
966 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
971 end_index = start_index;
972 if (*endptr == '-') {
973 end_index = strtol(endptr + 1, &endptr, 0);
976 if (end_index < start_index)
980 for (i = start_index; i <= end_index && slots > 0; i++) {
983 /* remove duplicate */
984 for (j = 0; j < offset; j++) {
988 if (j == offset) { /* no duplicate */
993 if (slots == 0 && i < end_index)
1001 if (!end_of_loop && ptr != NULL)
1004 return rc < 0 ? rc : nr;
1007 struct lfs_setstripe_args {
1008 unsigned long long lsa_comp_end;
1009 unsigned long long lsa_stripe_size;
1010 int lsa_stripe_count;
1012 __u32 lsa_comp_flags;
1015 char *lsa_pool_name;
1018 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1020 memset(lsa, 0, sizeof(*lsa));
1021 lsa->lsa_stripe_off = -1;
1024 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1026 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1027 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1028 lsa->lsa_comp_end != 0);
1031 static int comp_args_to_layout(struct llapi_layout **composite,
1032 struct lfs_setstripe_args *lsa)
1034 struct llapi_layout *layout = *composite;
1035 uint64_t prev_end = 0;
1038 if (layout == NULL) {
1039 layout = llapi_layout_alloc();
1040 if (layout == NULL) {
1041 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1045 *composite = layout;
1049 /* Get current component extent, current component
1050 * must be the tail component. */
1051 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1053 fprintf(stderr, "Get comp extent failed. %s\n",
1058 rc = llapi_layout_comp_add(layout);
1060 fprintf(stderr, "Add component failed. %s\n",
1066 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1068 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1069 prev_end, lsa->lsa_comp_end, strerror(errno));
1073 if (lsa->lsa_stripe_size != 0) {
1074 rc = llapi_layout_stripe_size_set(layout,
1075 lsa->lsa_stripe_size);
1077 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1078 lsa->lsa_stripe_size, strerror(errno));
1083 if (lsa->lsa_stripe_count != 0) {
1084 rc = llapi_layout_stripe_count_set(layout,
1085 lsa->lsa_stripe_count == -1 ?
1087 lsa->lsa_stripe_count);
1089 fprintf(stderr, "Set stripe count %d failed. %s\n",
1090 lsa->lsa_stripe_count, strerror(errno));
1095 if (lsa->lsa_pool_name != NULL) {
1096 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1098 fprintf(stderr, "Set pool name: %s failed. %s\n",
1099 lsa->lsa_pool_name, strerror(errno));
1104 if (lsa->lsa_nr_osts > 0) {
1105 if (lsa->lsa_stripe_count > 0 &&
1106 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1107 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1108 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1111 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1112 rc = llapi_layout_ost_index_set(layout, i,
1117 } else if (lsa->lsa_stripe_off != -1) {
1118 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1121 fprintf(stderr, "Set ost index %d failed. %s\n",
1122 i, strerror(errno));
1129 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1130 * end of the last component in the existing file, and adjust the
1131 * first extent start of the components to be added accordingly. */
1132 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1134 struct llapi_layout *head;
1135 uint64_t start, end, stripe_size, prev_end = 0;
1142 head = llapi_layout_get_by_path(fname, 0);
1144 fprintf(stderr, "Read layout from %s failed. %s\n",
1145 fname, strerror(errno));
1147 } else if (errno == ENODATA) {
1148 /* file without LOVEA, this component-add will be turned
1149 * into a component-create. */
1150 llapi_layout_free(head);
1152 } else if (!llapi_layout_is_composite(head)) {
1153 fprintf(stderr, "'%s' isn't a composite file.\n",
1155 llapi_layout_free(head);
1159 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1161 fprintf(stderr, "Get prev extent failed. %s\n",
1163 llapi_layout_free(head);
1167 llapi_layout_free(head);
1169 /* Make sure we use the first component of the layout to be added. */
1170 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1172 fprintf(stderr, "Move component cursor failed. %s\n",
1177 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1179 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1183 if (start > prev_end || end <= prev_end) {
1184 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1185 "adjacent with the existing file extent end: %lu\n",
1186 start, end, prev_end);
1190 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1192 fprintf(stderr, "Get stripe size failed. %s\n",
1197 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1198 (prev_end & (stripe_size - 1))) {
1199 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1200 stripe_size, prev_end);
1204 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1206 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1207 prev_end, end, strerror(errno));
1214 static inline bool comp_flags_is_neg(__u32 flags)
1216 return flags & LCME_FL_NEG;
1219 static inline void comp_flags_set_neg(__u32 *flags)
1221 *flags |= LCME_FL_NEG;
1224 static inline void comp_flags_clear_neg(__u32 *flags)
1226 *flags &= ~LCME_FL_NEG;
1229 static int comp_str2flags(__u32 *flags, char *string)
1232 __u32 neg_flags = 0;
1238 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1242 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1243 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1244 const char *comp_name = comp_flags_table[i].cfn_name;
1246 if (strcmp(name, comp_name) == 0) {
1247 *flags |= comp_flag;
1249 } else if (strncmp(name, "^", 1) == 0 &&
1250 strcmp(name + 1, comp_name) == 0) {
1251 neg_flags |= comp_flag;
1256 llapi_printf(LLAPI_MSG_ERROR,
1257 "%s: component flag '%s' not supported\n",
1263 if (*flags == 0 && neg_flags == 0)
1265 /* don't support mixed flags for now */
1266 if (*flags && neg_flags)
1271 comp_flags_set_neg(flags);
1277 static inline bool arg_is_eof(char *arg)
1279 return !strncmp(arg, "-1", strlen("-1")) ||
1280 !strncmp(arg, "EOF", strlen("EOF")) ||
1281 !strncmp(arg, "eof", strlen("eof"));
1296 static int lfs_setstripe(int argc, char **argv)
1298 struct lfs_setstripe_args lsa;
1299 struct llapi_stripe_param *param = NULL;
1300 struct find_param migrate_mdt_param = {
1310 char *mdt_idx_arg = NULL;
1311 unsigned long long size_units = 1;
1312 bool migrate_mode = false;
1313 bool migration_block = false;
1314 __u64 migration_flags = 0;
1315 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1316 int comp_del = 0, comp_set = 0;
1319 struct llapi_layout *layout = NULL;
1321 struct option long_opts[] = {
1322 /* --block is only valid in migrate mode */
1323 { .val = 'b', .name = "block", .has_arg = no_argument},
1324 { .val = LFS_COMP_ADD_OPT,
1325 .name = "comp-add", .has_arg = no_argument},
1326 { .val = LFS_COMP_ADD_OPT,
1327 .name = "component-add",
1328 .has_arg = no_argument},
1329 { .val = LFS_COMP_DEL_OPT,
1330 .name = "comp-del", .has_arg = no_argument},
1331 { .val = LFS_COMP_DEL_OPT,
1332 .name = "component-del",
1333 .has_arg = no_argument},
1334 { .val = LFS_COMP_FLAGS_OPT,
1335 .name = "comp-flags", .has_arg = required_argument},
1336 { .val = LFS_COMP_FLAGS_OPT,
1337 .name = "component-flags",
1338 .has_arg = required_argument},
1339 { .val = LFS_COMP_SET_OPT,
1340 .name = "comp-set", .has_arg = no_argument},
1341 { .val = LFS_COMP_SET_OPT,
1342 .name = "component-set",
1343 .has_arg = no_argument},
1344 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1345 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1346 { .val = 'd', .name = "delete", .has_arg = no_argument},
1347 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1348 { .val = 'E', .name = "component-end",
1349 .has_arg = required_argument},
1350 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1351 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1352 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1353 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1354 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1355 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1356 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1357 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1358 /* --non-block is only valid in migrate mode */
1359 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1360 { .val = 'o', .name = "ost", .has_arg = required_argument},
1361 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1362 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1363 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1365 { .val = 'p', .name = "pool", .has_arg = required_argument },
1366 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1367 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1368 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1369 /* --verbose is only valid in migrate mode */
1370 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1371 { .val = LFS_COMP_ADD_OPT,
1372 .name = "component-add",
1373 .has_arg = no_argument },
1374 { .val = LFS_COMP_DEL_OPT,
1375 .name = "component-del",
1376 .has_arg = no_argument },
1377 { .val = LFS_COMP_FLAGS_OPT,
1378 .name = "component-flags",
1379 .has_arg = required_argument },
1380 { .val = LFS_COMP_SET_OPT,
1381 .name = "component-set",
1382 .has_arg = no_argument },
1385 setstripe_args_init(&lsa);
1387 if (strcmp(argv[0], "migrate") == 0)
1388 migrate_mode = true;
1390 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1391 long_opts, NULL)) >= 0) {
1396 case LFS_COMP_ADD_OPT:
1399 case LFS_COMP_DEL_OPT:
1402 case LFS_COMP_FLAGS_OPT:
1403 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1407 case LFS_COMP_SET_OPT:
1411 if (!migrate_mode) {
1413 "%s %s: -b|--block valid only for migrate command\n",
1417 migration_block = true;
1420 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1423 "%s %s: invalid stripe count '%s'\n",
1424 progname, argv[0], optarg);
1429 /* delete the default striping pattern */
1433 if (lsa.lsa_comp_end != 0) {
1434 result = comp_args_to_layout(&layout, &lsa);
1437 "%s %s: invalid layout\n",
1442 setstripe_args_init(&lsa);
1445 if (arg_is_eof(optarg)) {
1446 lsa.lsa_comp_end = LUSTRE_EOF;
1448 result = llapi_parse_size(optarg,
1453 "%s %s: invalid component end '%s'\n",
1454 progname, argv[0], optarg);
1460 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1463 "%s %s: invalid stripe offset '%s'\n",
1464 progname, argv[0], optarg);
1469 comp_id = strtoul(optarg, &end, 0);
1470 if (*end != '\0' || comp_id == 0 ||
1471 comp_id > LCME_ID_MAX) {
1473 "%s %s: invalid component ID '%s'\n",
1474 progname, argv[0], optarg);
1479 if (!migrate_mode) {
1481 "%s %s: -m|--mdt-index valid only for migrate command\n",
1485 mdt_idx_arg = optarg;
1488 if (!migrate_mode) {
1490 "%s %s: -n|--non-block valid only for migrate command\n",
1494 migration_flags |= MIGRATION_NONBLOCK;
1497 lsa.lsa_nr_osts = parse_targets(osts,
1498 sizeof(osts) / sizeof(__u32),
1499 lsa.lsa_nr_osts, optarg);
1500 if (lsa.lsa_nr_osts < 0) {
1502 "%s %s: invalid OST target(s) '%s'\n",
1503 progname, argv[0], optarg);
1507 lsa.lsa_osts = osts;
1508 if (lsa.lsa_stripe_off == -1)
1509 lsa.lsa_stripe_off = osts[0];
1514 lsa.lsa_pool_name = optarg;
1517 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1521 "%s %s: invalid stripe size '%s'\n",
1522 progname, argv[0], optarg);
1527 if (!migrate_mode) {
1529 "%s %s: -v|--verbose valid only for migrate command\n",
1533 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1536 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
1537 progname, argv[0], argv[optind - 1]);
1542 fname = argv[optind];
1544 if (lsa.lsa_comp_end != 0) {
1545 result = comp_args_to_layout(&layout, &lsa);
1547 fprintf(stderr, "%s %s: invalid component layout\n",
1553 if (optind == argc) {
1554 fprintf(stderr, "%s %s: FILE must be specified\n",
1559 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1560 * altered by user space tool, so we don't need to support the
1561 * --component-set for this moment. */
1562 if (comp_set != 0) {
1563 fprintf(stderr, "%s %s: --component-set not supported\n",
1568 if ((delete + comp_set + comp_del + comp_add) > 1) {
1570 "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
1575 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1576 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1578 "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
1583 if ((comp_set || comp_del) &&
1584 (setstripe_args_specified(&lsa) || layout != NULL)) {
1586 "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
1591 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1593 "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
1598 if (comp_add || comp_del) {
1601 result = lstat(fname, &st);
1602 if (result == 0 && S_ISDIR(st.st_mode)) {
1604 "%s setstripe: cannot use --component-add or --component-del for directory\n",
1611 if (layout == NULL) {
1613 "%s %s: option -E must be specified with --component-add\n",
1617 result = adjust_first_extent(fname, layout);
1618 if (result == -ENODATA)
1620 else if (result != 0)
1624 if (mdt_idx_arg != NULL && optind > 3) {
1626 "%s %s: option -m cannot be used with other options\n",
1631 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1633 "%s %s: options --non-block and --block are mutually exclusive\n",
1638 if (!comp_del && !comp_set && comp_id != 0) {
1640 "%s %s: option -I can only be used with --component-del\n",
1645 if (mdt_idx_arg != NULL) {
1646 /* initialize migrate mdt parameters */
1647 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1649 fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
1650 progname, argv[0], mdt_idx_arg);
1653 migrate_mdt_param.fp_migrate = 1;
1654 } else if (layout == NULL) {
1655 /* initialize stripe parameters */
1656 param = calloc(1, offsetof(typeof(*param),
1657 lsp_osts[lsa.lsa_nr_osts]));
1658 if (param == NULL) {
1660 "%s %s: cannot allocate memory for parameters: %s\n",
1661 progname, argv[0], strerror(ENOMEM));
1666 param->lsp_stripe_size = lsa.lsa_stripe_size;
1667 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1668 param->lsp_stripe_count = lsa.lsa_stripe_count;
1669 param->lsp_stripe_pattern = 0;
1670 param->lsp_pool = lsa.lsa_pool_name;
1671 param->lsp_is_specific = false;
1672 if (lsa.lsa_nr_osts > 0) {
1673 if (lsa.lsa_stripe_count > 0 &&
1674 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1676 "%s %s: stripe count '%d' does not match number of OSTs: %d\n",
1677 progname, argv[0], lsa.lsa_stripe_count,
1683 param->lsp_is_specific = true;
1684 param->lsp_stripe_count = lsa.lsa_nr_osts;
1685 memcpy(param->lsp_osts, osts,
1686 sizeof(*osts) * lsa.lsa_nr_osts);
1690 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1691 if (mdt_idx_arg != NULL) {
1692 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1693 } else if (migrate_mode) {
1694 result = lfs_migrate(fname, migration_flags, param,
1696 } else if (comp_set != 0) {
1697 result = lfs_component_set(fname, comp_id,
1698 lsa.lsa_comp_flags);
1699 } else if (comp_del != 0) {
1700 result = lfs_component_del(fname, comp_id,
1701 lsa.lsa_comp_flags);
1702 } else if (comp_add != 0) {
1703 result = lfs_component_add(fname, layout);
1704 } else if (layout != NULL) {
1705 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1712 result = llapi_file_open_param(fname,
1721 /* Save the first error encountered. */
1729 llapi_layout_free(layout);
1734 llapi_layout_free(layout);
1738 static int lfs_poollist(int argc, char **argv)
1743 return llapi_poollist(argv[1]);
1746 static int set_time(time_t *time, time_t *set, char *str)
1753 else if (str[0] == '-')
1759 t = strtol(str, NULL, 0);
1760 if (*time < t * 24 * 60 * 60) {
1763 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1767 *set = *time - t * 24 * 60 * 60;
1770 static int name2uid(unsigned int *id, const char *name)
1772 struct passwd *passwd;
1774 passwd = getpwnam(name);
1777 *id = passwd->pw_uid;
1782 static int name2gid(unsigned int *id, const char *name)
1784 struct group *group;
1786 group = getgrnam(name);
1789 *id = group->gr_gid;
1794 static inline int name2projid(unsigned int *id, const char *name)
1799 static int uid2name(char **name, unsigned int id)
1801 struct passwd *passwd;
1803 passwd = getpwuid(id);
1806 *name = passwd->pw_name;
1811 static inline int gid2name(char **name, unsigned int id)
1813 struct group *group;
1815 group = getgrgid(id);
1818 *name = group->gr_name;
1823 static int name2layout(__u32 *layout, char *name)
1828 for (ptr = name; ; ptr = NULL) {
1829 lyt = strtok(ptr, ",");
1832 if (strcmp(lyt, "released") == 0)
1833 *layout |= LOV_PATTERN_F_RELEASED;
1834 else if (strcmp(lyt, "raid0") == 0)
1835 *layout |= LOV_PATTERN_RAID0;
1842 static int lfs_find(int argc, char **argv)
1847 struct find_param param = {
1851 struct option long_opts[] = {
1852 { .val = 'A', .name = "atime", .has_arg = required_argument },
1853 { .val = LFS_COMP_COUNT_OPT,
1854 .name = "comp-count", .has_arg = required_argument },
1855 { .val = LFS_COMP_COUNT_OPT,
1856 .name = "component-count",
1857 .has_arg = required_argument },
1858 { .val = LFS_COMP_FLAGS_OPT,
1859 .name = "comp-flags", .has_arg = required_argument },
1860 { .val = LFS_COMP_FLAGS_OPT,
1861 .name = "component-flags",
1862 .has_arg = required_argument },
1863 { .val = LFS_COMP_START_OPT,
1864 .name = "comp-start", .has_arg = required_argument },
1865 { .val = LFS_COMP_START_OPT,
1866 .name = "component-start",
1867 .has_arg = required_argument },
1868 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1869 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1870 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1871 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1872 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1873 { .val = 'E', .name = "component-end",
1874 .has_arg = required_argument },
1875 { .val = 'g', .name = "gid", .has_arg = required_argument },
1876 { .val = 'G', .name = "group", .has_arg = required_argument },
1877 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1878 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1879 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1880 /*{"component-id", required_argument, 0, 'I'},*/
1881 { .val = 'L', .name = "layout", .has_arg = required_argument },
1882 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1883 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1884 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1885 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1886 { .val = 'n', .name = "name", .has_arg = required_argument },
1887 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1888 { .val = 'O', .name = "obd", .has_arg = required_argument },
1889 { .val = 'O', .name = "ost", .has_arg = required_argument },
1890 /* no short option for pool, p/P already used */
1891 { .val = LFS_POOL_OPT,
1892 .name = "pool", .has_arg = required_argument },
1893 { .val = 'p', .name = "print0", .has_arg = no_argument },
1894 { .val = 'P', .name = "print", .has_arg = no_argument },
1895 { .val = LFS_PROJID_OPT,
1896 .name = "projid", .has_arg = required_argument },
1897 { .val = 's', .name = "size", .has_arg = required_argument },
1898 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1899 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1900 { .val = 't', .name = "type", .has_arg = required_argument },
1901 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
1902 { .val = 'u', .name = "uid", .has_arg = required_argument },
1903 { .val = 'U', .name = "user", .has_arg = required_argument },
1915 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1916 while ((c = getopt_long_only(argc, argv,
1917 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1918 long_opts, NULL)) >= 0) {
1923 /* '!' is part of option */
1924 /* when getopt_long_only() finds a string which is not
1925 * an option nor a known option argument it returns 1
1926 * in that case if we already have found pathstart and pathend
1927 * (i.e. we have the list of pathnames),
1928 * the only supported value is "!"
1930 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1931 if (!isoption && pathend != -1) {
1932 fprintf(stderr, "err: %s: filename|dirname must either "
1933 "precede options or follow options\n",
1938 if (!isoption && pathstart == -1)
1939 pathstart = optind - 1;
1940 if (isoption && pathstart != -1 && pathend == -1)
1941 pathend = optind - 2;
1947 /* unknown; opt is "!" or path component,
1948 * checking done above.
1950 if (strcmp(optarg, "!") == 0)
1954 xtime = ¶m.fp_atime;
1955 xsign = ¶m.fp_asign;
1956 param.fp_exclude_atime = !!neg_opt;
1957 /* no break, this falls through to 'C' for ctime */
1960 xtime = ¶m.fp_ctime;
1961 xsign = ¶m.fp_csign;
1962 param.fp_exclude_ctime = !!neg_opt;
1964 /* no break, this falls through to 'M' for mtime */
1967 xtime = ¶m.fp_mtime;
1968 xsign = ¶m.fp_msign;
1969 param.fp_exclude_mtime = !!neg_opt;
1971 rc = set_time(&t, xtime, optarg);
1972 if (rc == INT_MAX) {
1979 case LFS_COMP_COUNT_OPT:
1980 if (optarg[0] == '+') {
1981 param.fp_comp_count_sign = -1;
1983 } else if (optarg[0] == '-') {
1984 param.fp_comp_count_sign = 1;
1988 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1989 if (*endptr != '\0') {
1990 fprintf(stderr, "error: bad component count "
1994 param.fp_check_comp_count = 1;
1995 param.fp_exclude_comp_count = !!neg_opt;
1997 case LFS_COMP_FLAGS_OPT:
1998 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
1999 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2000 fprintf(stderr, "error: bad component flags "
2004 param.fp_check_comp_flags = 1;
2005 param.fp_exclude_comp_flags = !!neg_opt;
2007 case LFS_COMP_START_OPT:
2008 if (optarg[0] == '+') {
2009 param.fp_comp_start_sign = -1;
2011 } else if (optarg[0] == '-') {
2012 param.fp_comp_start_sign = 1;
2016 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2017 ¶m.fp_comp_start_units, 0);
2019 fprintf(stderr, "error: bad component start "
2023 param.fp_check_comp_start = 1;
2024 param.fp_exclude_comp_start = !!neg_opt;
2027 if (optarg[0] == '+') {
2028 param.fp_stripe_count_sign = -1;
2030 } else if (optarg[0] == '-') {
2031 param.fp_stripe_count_sign = 1;
2035 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2036 if (*endptr != '\0') {
2037 fprintf(stderr,"error: bad stripe_count '%s'\n",
2042 param.fp_check_stripe_count = 1;
2043 param.fp_exclude_stripe_count = !!neg_opt;
2046 param.fp_max_depth = strtol(optarg, 0, 0);
2049 if (optarg[0] == '+') {
2050 param.fp_comp_end_sign = -1;
2052 } else if (optarg[0] == '-') {
2053 param.fp_comp_end_sign = 1;
2057 if (arg_is_eof(optarg)) {
2058 param.fp_comp_end = LUSTRE_EOF;
2059 param.fp_comp_end_units = 1;
2062 rc = llapi_parse_size(optarg,
2064 ¶m.fp_comp_end_units, 0);
2067 fprintf(stderr, "error: bad component end "
2071 param.fp_check_comp_end = 1;
2072 param.fp_exclude_comp_end = !!neg_opt;
2076 rc = name2gid(¶m.fp_gid, optarg);
2078 param.fp_gid = strtoul(optarg, &endptr, 10);
2079 if (*endptr != '\0') {
2080 fprintf(stderr, "Group/GID: %s cannot "
2081 "be found.\n", optarg);
2086 param.fp_exclude_gid = !!neg_opt;
2087 param.fp_check_gid = 1;
2090 param.fp_hash_type = check_hashtype(optarg);
2091 if (param.fp_hash_type == 0) {
2092 fprintf(stderr, "error: bad hash_type '%s'\n",
2097 param.fp_check_hash_type = 1;
2098 param.fp_exclude_hash_type = !!neg_opt;
2101 ret = name2layout(¶m.fp_layout, optarg);
2104 param.fp_exclude_layout = !!neg_opt;
2105 param.fp_check_layout = 1;
2109 rc = name2uid(¶m.fp_uid, optarg);
2111 param.fp_uid = strtoul(optarg, &endptr, 10);
2112 if (*endptr != '\0') {
2113 fprintf(stderr, "User/UID: %s cannot "
2114 "be found.\n", optarg);
2119 param.fp_exclude_uid = !!neg_opt;
2120 param.fp_check_uid = 1;
2123 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2125 "Pool name %s is too long"
2126 " (max is %d)\n", optarg,
2131 /* we do check for empty pool because empty pool
2132 * is used to find V1 lov attributes */
2133 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2134 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2135 param.fp_exclude_pool = !!neg_opt;
2136 param.fp_check_pool = 1;
2139 param.fp_pattern = (char *)optarg;
2140 param.fp_exclude_pattern = !!neg_opt;
2145 char *buf, *token, *next, *p;
2149 buf = strdup(optarg);
2155 param.fp_exclude_obd = !!neg_opt;
2158 while (token && *token) {
2159 token = strchr(token, ',');
2166 param.fp_exclude_mdt = !!neg_opt;
2167 param.fp_num_alloc_mdts += len;
2168 tmp = realloc(param.fp_mdt_uuid,
2169 param.fp_num_alloc_mdts *
2170 sizeof(*param.fp_mdt_uuid));
2176 param.fp_mdt_uuid = tmp;
2178 param.fp_exclude_obd = !!neg_opt;
2179 param.fp_num_alloc_obds += len;
2180 tmp = realloc(param.fp_obd_uuid,
2181 param.fp_num_alloc_obds *
2182 sizeof(*param.fp_obd_uuid));
2188 param.fp_obd_uuid = tmp;
2190 for (token = buf; token && *token; token = next) {
2191 struct obd_uuid *puuid;
2194 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2197 ¶m.fp_obd_uuid[param.fp_num_obds++];
2199 p = strchr(token, ',');
2206 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2211 strncpy(puuid->uuid, token,
2212 sizeof(puuid->uuid));
2220 param.fp_zero_end = 1;
2224 case LFS_PROJID_OPT:
2225 rc = name2projid(¶m.fp_projid, optarg);
2227 param.fp_projid = strtoul(optarg, &endptr, 10);
2228 if (*endptr != '\0') {
2230 "Invalid project ID: %s",
2236 param.fp_exclude_projid = !!neg_opt;
2237 param.fp_check_projid = 1;
2240 if (optarg[0] == '+') {
2241 param.fp_size_sign = -1;
2243 } else if (optarg[0] == '-') {
2244 param.fp_size_sign = 1;
2248 ret = llapi_parse_size(optarg, ¶m.fp_size,
2249 ¶m.fp_size_units, 0);
2251 fprintf(stderr, "error: bad file size '%s'\n",
2255 param.fp_check_size = 1;
2256 param.fp_exclude_size = !!neg_opt;
2259 if (optarg[0] == '+') {
2260 param.fp_stripe_size_sign = -1;
2262 } else if (optarg[0] == '-') {
2263 param.fp_stripe_size_sign = 1;
2267 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2268 ¶m.fp_stripe_size_units, 0);
2270 fprintf(stderr, "error: bad stripe_size '%s'\n",
2274 param.fp_check_stripe_size = 1;
2275 param.fp_exclude_stripe_size = !!neg_opt;
2278 param.fp_exclude_type = !!neg_opt;
2279 switch (optarg[0]) {
2281 param.fp_type = S_IFBLK;
2284 param.fp_type = S_IFCHR;
2287 param.fp_type = S_IFDIR;
2290 param.fp_type = S_IFREG;
2293 param.fp_type = S_IFLNK;
2296 param.fp_type = S_IFIFO;
2299 param.fp_type = S_IFSOCK;
2302 fprintf(stderr, "error: %s: bad type '%s'\n",
2309 if (optarg[0] == '+') {
2310 param.fp_mdt_count_sign = -1;
2312 } else if (optarg[0] == '-') {
2313 param.fp_mdt_count_sign = 1;
2317 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2318 if (*endptr != '\0') {
2319 fprintf(stderr, "error: bad mdt_count '%s'\n",
2324 param.fp_check_mdt_count = 1;
2325 param.fp_exclude_mdt_count = !!neg_opt;
2333 if (pathstart == -1) {
2334 fprintf(stderr, "error: %s: no filename|pathname\n",
2338 } else if (pathend == -1) {
2344 rc = llapi_find(argv[pathstart], ¶m);
2345 if (rc != 0 && ret == 0)
2347 } while (++pathstart < pathend);
2350 fprintf(stderr, "error: %s failed for %s.\n",
2351 argv[0], argv[optind - 1]);
2353 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2354 free(param.fp_obd_uuid);
2356 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2357 free(param.fp_mdt_uuid);
2362 static int lfs_getstripe_internal(int argc, char **argv,
2363 struct find_param *param)
2365 struct option long_opts[] = {
2366 { .val = LFS_COMP_COUNT_OPT,
2367 .name = "comp-count", .has_arg = no_argument },
2368 { .val = LFS_COMP_COUNT_OPT,
2369 .name = "component-count", .has_arg = no_argument },
2370 { .val = LFS_COMP_FLAGS_OPT,
2371 .name = "comp-flags", .has_arg = optional_argument },
2372 { .val = LFS_COMP_FLAGS_OPT,
2373 .name = "component-flags", .has_arg = optional_argument },
2374 { .val = LFS_COMP_START_OPT,
2375 .name = "comp-start", .has_arg = optional_argument },
2376 { .val = LFS_COMP_START_OPT,
2377 .name = "component-start", .has_arg = optional_argument },
2378 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2379 /* This formerly implied "stripe-count", but was explicitly
2380 * made "stripe-count" for consistency with other options,
2381 * and to separate it from "mdt-count" when DNE arrives. */
2382 { .val = 'c', .name = "count", .has_arg = no_argument },
2384 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2385 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2386 { .val = 'd', .name = "directory", .has_arg = no_argument },
2387 { .val = 'D', .name = "default", .has_arg = no_argument },
2388 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2389 { .val = 'E', .name = "component-end",
2390 .has_arg = optional_argument },
2391 { .val = 'F', .name = "fid", .has_arg = no_argument },
2392 { .val = 'g', .name = "generation", .has_arg = no_argument },
2393 /* dirstripe { .val = 'H', .name = "mdt-hash",
2394 * .has_arg = required_argument }, */
2395 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2396 /* This formerly implied "stripe-index", but was explicitly
2397 * made "stripe-index" for consistency with other options,
2398 * and to separate it from "mdt-index" when DNE arrives. */
2399 { .val = 'i', .name = "index", .has_arg = no_argument },
2401 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2402 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2403 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2404 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2405 { .val = 'L', .name = "layout", .has_arg = no_argument },
2406 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2407 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2408 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2409 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2410 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2411 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2413 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2414 /* This formerly implied "stripe-index", but was confusing
2415 * with "file offset" (which will eventually be needed for
2416 * with different layouts by offset), so deprecate it. */
2417 { .val = 'o', .name = "offset", .has_arg = no_argument },
2419 { .val = 'O', .name = "obd", .has_arg = required_argument },
2420 { .val = 'O', .name = "ost", .has_arg = required_argument },
2421 { .val = 'p', .name = "pool", .has_arg = no_argument },
2422 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2423 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2424 { .val = 'R', .name = "raw", .has_arg = no_argument },
2425 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2426 /* This formerly implied "--stripe-size", but was confusing
2427 * with "lfs find --size|-s", which means "file size", so use
2428 * the consistent "--stripe-size|-S" for all commands. */
2429 { .val = 's', .name = "size", .has_arg = no_argument },
2431 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2432 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2433 /* dirstripe { .val = 'T', .name = "mdt-count",
2434 * .has_arg = required_argument }, */
2435 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2436 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2441 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2442 long_opts, NULL)) != -1) {
2445 if (strcmp(argv[optind - 1], "--count") == 0)
2446 fprintf(stderr, "warning: '--count' deprecated,"
2447 " use '--stripe-count' instead\n");
2448 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2449 param->fp_verbose |= VERBOSE_COUNT;
2450 param->fp_max_depth = 0;
2453 case LFS_COMP_COUNT_OPT:
2454 param->fp_verbose |= VERBOSE_COMP_COUNT;
2455 param->fp_max_depth = 0;
2457 case LFS_COMP_FLAGS_OPT:
2458 if (optarg != NULL) {
2459 __u32 *flags = ¶m->fp_comp_flags;
2460 rc = comp_str2flags(flags, optarg);
2462 fprintf(stderr, "error: %s bad "
2463 "component flags '%s'.\n",
2467 param->fp_check_comp_flags = 1;
2468 param->fp_exclude_comp_flags =
2469 comp_flags_is_neg(*flags);
2470 comp_flags_clear_neg(flags);
2473 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2474 param->fp_max_depth = 0;
2477 case LFS_COMP_START_OPT:
2478 if (optarg != NULL) {
2480 if (tmp[0] == '+') {
2481 param->fp_comp_start_sign = -1;
2483 } else if (tmp[0] == '-') {
2484 param->fp_comp_start_sign = 1;
2487 rc = llapi_parse_size(tmp,
2488 ¶m->fp_comp_start,
2489 ¶m->fp_comp_start_units, 0);
2491 fprintf(stderr, "error: %s bad "
2492 "component start '%s'.\n",
2496 param->fp_check_comp_start = 1;
2499 param->fp_verbose |= VERBOSE_COMP_START;
2500 param->fp_max_depth = 0;
2504 param->fp_max_depth = 0;
2507 param->fp_get_default_lmv = 1;
2510 if (optarg != NULL) {
2512 if (tmp[0] == '+') {
2513 param->fp_comp_end_sign = -1;
2515 } else if (tmp[0] == '-') {
2516 param->fp_comp_end_sign = 1;
2520 if (arg_is_eof(tmp)) {
2521 param->fp_comp_end = LUSTRE_EOF;
2522 param->fp_comp_end_units = 1;
2525 rc = llapi_parse_size(tmp,
2526 ¶m->fp_comp_end,
2527 ¶m->fp_comp_end_units, 0);
2530 fprintf(stderr, "error: %s bad "
2531 "component end '%s'.\n",
2535 param->fp_check_comp_end = 1;
2537 param->fp_verbose |= VERBOSE_COMP_END;
2538 param->fp_max_depth = 0;
2542 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2543 param->fp_verbose |= VERBOSE_DFID;
2544 param->fp_max_depth = 0;
2548 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2549 param->fp_verbose |= VERBOSE_GENERATION;
2550 param->fp_max_depth = 0;
2553 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2555 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2556 "use '--stripe-index|-i' instead\n");
2559 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2560 if (strcmp(argv[optind - 1], "--index") == 0)
2561 fprintf(stderr, "warning: '--index' deprecated"
2562 ", use '--stripe-index' instead\n");
2564 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2565 param->fp_verbose |= VERBOSE_OFFSET;
2566 param->fp_max_depth = 0;
2570 if (optarg != NULL) {
2571 param->fp_comp_id = strtoul(optarg, &end, 0);
2572 if (*end != '\0' || param->fp_comp_id == 0 ||
2573 param->fp_comp_id > LCME_ID_MAX) {
2574 fprintf(stderr, "error: %s bad "
2575 "component id '%s'\n",
2579 param->fp_check_comp_id = 1;
2582 param->fp_max_depth = 0;
2583 param->fp_verbose |= VERBOSE_COMP_ID;
2587 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2588 param->fp_verbose |= VERBOSE_LAYOUT;
2589 param->fp_max_depth = 0;
2592 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2594 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2595 fprintf(stderr, "warning: '-M' deprecated"
2596 ", use '-m' instead\n");
2600 if (!(param->fp_verbose & VERBOSE_DETAIL))
2601 param->fp_max_depth = 0;
2602 param->fp_verbose |= VERBOSE_MDTINDEX;
2605 if (param->fp_obd_uuid) {
2607 "error: %s: only one obduuid allowed",
2611 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2614 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2615 param->fp_verbose |= VERBOSE_POOL;
2616 param->fp_max_depth = 0;
2623 param->fp_recursive = 1;
2628 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2630 fprintf(stderr, "warning: '--size|-s' deprecated, "
2631 "use '--stripe-size|-S' instead\n");
2632 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2634 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2635 param->fp_verbose |= VERBOSE_SIZE;
2636 param->fp_max_depth = 0;
2640 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2653 if (param->fp_recursive)
2654 param->fp_max_depth = -1;
2655 else if (param->fp_verbose & VERBOSE_DETAIL)
2656 param->fp_max_depth = 1;
2658 if (!param->fp_verbose)
2659 param->fp_verbose = VERBOSE_DEFAULT;
2660 if (param->fp_quiet)
2661 param->fp_verbose = VERBOSE_OBJID;
2664 rc = llapi_getstripe(argv[optind], param);
2665 } while (++optind < argc && !rc);
2668 fprintf(stderr, "error: %s failed for %s.\n",
2669 argv[0], argv[optind - 1]);
2673 static int lfs_tgts(int argc, char **argv)
2675 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2676 struct find_param param;
2677 int index = 0, rc=0;
2682 if (argc == 2 && !realpath(argv[1], path)) {
2684 fprintf(stderr, "error: invalid path '%s': %s\n",
2685 argv[1], strerror(-rc));
2689 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2690 /* Check if we have a mount point */
2691 if (mntdir[0] == '\0')
2694 memset(¶m, 0, sizeof(param));
2695 if (!strcmp(argv[0], "mdts"))
2696 param.fp_get_lmv = 1;
2698 rc = llapi_ostlist(mntdir, ¶m);
2700 fprintf(stderr, "error: %s: failed on %s\n",
2703 if (path[0] != '\0')
2705 memset(mntdir, 0, PATH_MAX);
2711 static int lfs_getstripe(int argc, char **argv)
2713 struct find_param param = { 0 };
2715 param.fp_max_depth = 1;
2716 return lfs_getstripe_internal(argc, argv, ¶m);
2720 static int lfs_getdirstripe(int argc, char **argv)
2722 struct find_param param = { 0 };
2723 struct option long_opts[] = {
2724 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2725 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2727 { .val = 'D', .name = "default", .has_arg = no_argument },
2728 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2729 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2730 { .val = 'O', .name = "obd", .has_arg = required_argument },
2731 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2732 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2733 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2735 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2736 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2740 param.fp_get_lmv = 1;
2742 while ((c = getopt_long(argc, argv,
2743 "cDHiO:rtTy", long_opts, NULL)) != -1)
2747 if (param.fp_obd_uuid) {
2749 "error: %s: only one obduuid allowed",
2753 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2755 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2757 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2758 fprintf(stderr, "warning: '-c' deprecated"
2759 ", use '-T' instead\n");
2763 param.fp_verbose |= VERBOSE_COUNT;
2766 param.fp_verbose |= VERBOSE_OFFSET;
2768 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2772 param.fp_verbose |= VERBOSE_HASH_TYPE;
2775 param.fp_get_default_lmv = 1;
2778 param.fp_recursive = 1;
2791 if (param.fp_recursive)
2792 param.fp_max_depth = -1;
2794 if (!param.fp_verbose)
2795 param.fp_verbose = VERBOSE_DEFAULT;
2798 rc = llapi_getstripe(argv[optind], ¶m);
2799 } while (++optind < argc && !rc);
2802 fprintf(stderr, "error: %s failed for %s.\n",
2803 argv[0], argv[optind - 1]);
2808 static int lfs_setdirstripe(int argc, char **argv)
2812 unsigned int stripe_offset = -1;
2813 unsigned int stripe_count = 1;
2814 enum lmv_hash_type hash_type;
2817 char *stripe_offset_opt = NULL;
2818 char *stripe_count_opt = NULL;
2819 char *stripe_hash_opt = NULL;
2820 char *mode_opt = NULL;
2821 bool default_stripe = false;
2822 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2823 mode_t previous_mode = 0;
2824 bool delete = false;
2826 struct option long_opts[] = {
2827 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2828 { .val = 'c', .name = "count", .has_arg = required_argument },
2830 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2831 { .val = 'd', .name = "delete", .has_arg = no_argument },
2832 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2833 { .val = 'i', .name = "index", .has_arg = required_argument },
2835 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2836 { .val = 'm', .name = "mode", .has_arg = required_argument },
2837 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2838 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2839 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2841 {"mdt-hash", required_argument, 0, 'H'},
2842 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2843 { .val = 'D', .name = "default_stripe",
2844 .has_arg = no_argument },
2846 { .val = 'D', .name = "default", .has_arg = no_argument },
2849 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2856 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2857 if (strcmp(argv[optind - 1], "--count") == 0)
2859 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
2862 stripe_count_opt = optarg;
2866 default_stripe = true;
2869 default_stripe = true;
2872 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2873 if (strcmp(argv[optind - 1], "--index") == 0)
2875 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
2878 stripe_offset_opt = optarg;
2883 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2887 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2888 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2890 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
2893 stripe_hash_opt = optarg;
2896 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2897 progname, argv[0], argv[optind - 1]);
2902 if (optind == argc) {
2903 fprintf(stderr, "%s %s: DIR must be specified\n",
2908 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2910 "%s %s: stripe offset and count must be specified\n",
2915 if (stripe_offset_opt != NULL) {
2916 /* get the stripe offset */
2917 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2920 "%s %s: bad stripe offset '%s'\n",
2921 progname, argv[0], stripe_offset_opt);
2927 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2929 "%s %s: cannot specify -d with -c or -i options\n",
2938 if (mode_opt != NULL) {
2939 mode = strtoul(mode_opt, &end, 8);
2942 "%s %s: bad MODE '%s'\n",
2943 progname, argv[0], mode_opt);
2946 previous_mode = umask(0);
2949 if (stripe_hash_opt == NULL) {
2950 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2952 hash_type = check_hashtype(stripe_hash_opt);
2953 if (hash_type == 0) {
2954 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
2955 progname, argv[0], stripe_hash_opt);
2960 /* get the stripe count */
2961 if (stripe_count_opt != NULL) {
2962 stripe_count = strtoul(stripe_count_opt, &end, 0);
2965 "%s %s: bad stripe count '%s'\n",
2966 progname, argv[0], stripe_count_opt);
2971 dname = argv[optind];
2973 if (default_stripe) {
2974 result = llapi_dir_set_default_lmv_stripe(dname,
2975 stripe_offset, stripe_count,
2978 result = llapi_dir_create_pool(dname, mode,
2980 stripe_count, hash_type,
2986 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
2987 progname, dname, strerror(-result));
2990 dname = argv[++optind];
2991 } while (dname != NULL);
2993 if (mode_opt != NULL)
2994 umask(previous_mode);
3000 static int lfs_rmentry(int argc, char **argv)
3007 fprintf(stderr, "error: %s: missing dirname\n",
3013 dname = argv[index];
3014 while (dname != NULL) {
3015 result = llapi_direntry_remove(dname);
3017 fprintf(stderr, "error: %s: remove dir entry '%s' "
3018 "failed\n", argv[0], dname);
3021 dname = argv[++index];
3026 static int lfs_mv(int argc, char **argv)
3028 struct find_param param = {
3035 struct option long_opts[] = {
3036 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3037 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3040 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3043 param.fp_mdt_index = strtoul(optarg, &end, 0);
3045 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3052 param.fp_verbose = VERBOSE_DETAIL;
3056 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3057 argv[0], argv[optind - 1]);
3062 if (param.fp_mdt_index == -1) {
3063 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3067 if (optind >= argc) {
3068 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3072 param.fp_migrate = 1;
3073 rc = llapi_migrate_mdt(argv[optind], ¶m);
3075 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3076 argv[0], argv[optind], param.fp_mdt_index,
3081 static int lfs_osts(int argc, char **argv)
3083 return lfs_tgts(argc, argv);
3086 static int lfs_mdts(int argc, char **argv)
3088 return lfs_tgts(argc, argv);
3091 #define COOK(value) \
3094 while (value > 1024) { \
3102 #define CDF "%11llu"
3103 #define HDF "%8.1f%c"
3108 MNTDF_INODES = 0x0001,
3109 MNTDF_COOKED = 0x0002,
3110 MNTDF_LAZY = 0x0004,
3111 MNTDF_VERBOSE = 0x0008,
3114 static int showdf(char *mntdir, struct obd_statfs *stat,
3115 char *uuid, enum mntdf_flags flags,
3116 char *type, int index, int rc)
3118 long long avail, used, total;
3120 char *suffix = "KMGTPEZY";
3121 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3122 char tbuf[3 * sizeof(__u64)];
3123 char ubuf[3 * sizeof(__u64)];
3124 char abuf[3 * sizeof(__u64)];
3125 char rbuf[3 * sizeof(__u64)];
3132 if (flags & MNTDF_INODES) {
3133 avail = stat->os_ffree;
3134 used = stat->os_files - stat->os_ffree;
3135 total = stat->os_files;
3137 int shift = flags & MNTDF_COOKED ? 0 : 10;
3139 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3140 used = ((stat->os_blocks - stat->os_bfree) *
3141 stat->os_bsize) >> shift;
3142 total = (stat->os_blocks * stat->os_bsize) >> shift;
3145 if ((used + avail) > 0)
3146 ratio = (double)used / (double)(used + avail);
3148 if (flags & MNTDF_COOKED) {
3152 cook_val = (double)total;
3155 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3158 snprintf(tbuf, sizeof(tbuf), CDF, total);
3160 cook_val = (double)used;
3163 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3166 snprintf(ubuf, sizeof(ubuf), CDF, used);
3168 cook_val = (double)avail;
3171 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3174 snprintf(abuf, sizeof(abuf), CDF, avail);
3176 snprintf(tbuf, sizeof(tbuf), CDF, total);
3177 snprintf(ubuf, sizeof(tbuf), CDF, used);
3178 snprintf(abuf, sizeof(tbuf), CDF, avail);
3181 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3182 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3183 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3185 printf("[%s:%d]", type, index);
3187 if (stat->os_state) {
3189 * Each character represents the matching
3192 const char state_names[] = "DRSI";
3197 for (i = 0, state = stat->os_state;
3198 state && i < sizeof(state_names); i++) {
3199 if (!(state & (1 << i)))
3201 printf("%c", state_names[i]);
3209 printf(UUF": inactive device\n", uuid);
3212 printf(UUF": %s\n", uuid, strerror(-rc));
3219 struct ll_stat_type {
3224 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3226 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3227 struct obd_uuid uuid_buf;
3228 char *poolname = NULL;
3229 struct ll_stat_type types[] = {
3230 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3231 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3232 { .st_name = NULL } };
3233 struct ll_stat_type *tp;
3234 __u64 ost_ffree = 0;
3242 poolname = strchr(pool, '.');
3243 if (poolname != NULL) {
3244 if (strncmp(fsname, pool, strlen(fsname))) {
3245 fprintf(stderr, "filesystem name incorrect\n");
3253 fd = open(mntdir, O_RDONLY);
3256 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3261 if (flags & MNTDF_INODES)
3262 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3263 "UUID", "Inodes", "IUsed", "IFree",
3264 "IUse%", "Mounted on");
3266 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3267 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3268 "Used", "Available", "Use%", "Mounted on");
3270 for (tp = types; tp->st_name != NULL; tp++) {
3271 for (index = 0; ; index++) {
3272 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3273 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3274 type = flags & MNTDF_LAZY ?
3275 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3276 rc2 = llapi_obd_fstatfs(fd, type, index,
3277 &stat_buf, &uuid_buf);
3282 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3283 if (!(flags & MNTDF_VERBOSE))
3285 } else if (rc2 < 0 && rc == 0) {
3289 if (poolname && tp->st_op == LL_STATFS_LOV &&
3290 llapi_search_ost(fsname, poolname,
3291 obd_uuid2str(&uuid_buf)) != 1)
3294 /* the llapi_obd_statfs() call may have returned with
3295 * an error, but if it filled in uuid_buf we will at
3296 * lease use that to print out a message for that OBD.
3297 * If we didn't get anything in the uuid_buf, then fill
3298 * it in so that we can print an error message. */
3299 if (uuid_buf.uuid[0] == '\0')
3300 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3301 "%s%04x", tp->st_name, index);
3302 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3303 flags, tp->st_name, index, rc2);
3306 if (tp->st_op == LL_STATFS_LMV) {
3307 sum.os_ffree += stat_buf.os_ffree;
3308 sum.os_files += stat_buf.os_files;
3309 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3310 sum.os_blocks += stat_buf.os_blocks *
3312 sum.os_bfree += stat_buf.os_bfree *
3314 sum.os_bavail += stat_buf.os_bavail *
3316 ost_ffree += stat_buf.os_ffree;
3324 /* If we don't have as many objects free on the OST as inodes
3325 * on the MDS, we reduce the total number of inodes to
3326 * compensate, so that the "inodes in use" number is correct.
3327 * Matches ll_statfs_internal() so the results are consistent. */
3328 if (ost_ffree < sum.os_ffree) {
3329 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3330 sum.os_ffree = ost_ffree;
3333 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3339 static int lfs_df(int argc, char **argv)
3341 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3342 enum mntdf_flags flags = 0;
3343 int c, rc = 0, index = 0;
3344 char fsname[PATH_MAX] = "", *pool_name = NULL;
3345 struct option long_opts[] = {
3346 { .val = 'h', .name = "human-readable",
3347 .has_arg = no_argument },
3348 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3349 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3350 { .val = 'p', .name = "pool", .has_arg = required_argument },
3351 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3354 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3357 flags |= MNTDF_COOKED;
3360 flags |= MNTDF_INODES;
3363 flags |= MNTDF_LAZY;
3369 flags |= MNTDF_VERBOSE;
3375 if (optind < argc && !realpath(argv[optind], path)) {
3377 fprintf(stderr, "error: invalid path '%s': %s\n",
3378 argv[optind], strerror(-rc));
3382 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3383 /* Check if we have a mount point */
3384 if (mntdir[0] == '\0')
3387 rc = mntdf(mntdir, fsname, pool_name, flags);
3388 if (rc || path[0] != '\0')
3390 fsname[0] = '\0'; /* avoid matching in next loop */
3391 mntdir[0] = '\0'; /* avoid matching in next loop */
3397 static int lfs_getname(int argc, char **argv)
3399 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3400 int rc = 0, index = 0, c;
3401 char buf[sizeof(struct obd_uuid)];
3403 while ((c = getopt(argc, argv, "h")) != -1)
3406 if (optind == argc) { /* no paths specified, get all paths. */
3407 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3408 rc = llapi_getname(mntdir, buf, sizeof(buf));
3411 "cannot get name for `%s': %s\n",
3412 mntdir, strerror(-rc));
3416 printf("%s %s\n", buf, mntdir);
3418 path[0] = fsname[0] = mntdir[0] = 0;
3420 } else { /* paths specified, only attempt to search these. */
3421 for (; optind < argc; optind++) {
3422 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3425 "cannot get name for `%s': %s\n",
3426 argv[optind], strerror(-rc));
3430 printf("%s %s\n", buf, argv[optind]);
3436 static int lfs_check(int argc, char **argv)
3439 char mntdir[PATH_MAX] = {'\0'};
3448 obd_types[0] = obd_type1;
3449 obd_types[1] = obd_type2;
3451 if (strcmp(argv[1], "osts") == 0) {
3452 strcpy(obd_types[0], "osc");
3453 } else if (strcmp(argv[1], "mds") == 0) {
3454 strcpy(obd_types[0], "mdc");
3455 } else if (strcmp(argv[1], "servers") == 0) {
3457 strcpy(obd_types[0], "osc");
3458 strcpy(obd_types[1], "mdc");
3460 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3465 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3466 if (rc < 0 || mntdir[0] == '\0') {
3467 fprintf(stderr, "No suitable Lustre mount found\n");
3471 rc = llapi_target_check(num_types, obd_types, mntdir);
3473 fprintf(stderr, "error: %s: %s status failed\n",
3480 #ifdef HAVE_SYS_QUOTA_H
3481 #define ARG2INT(nr, str, msg) \
3484 nr = strtol(str, &endp, 0); \
3486 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3491 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3493 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3494 * returns the value or ULONG_MAX on integer overflow or incorrect format
3496 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3497 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3498 * 3. empty integer value is interpreted as 0
3500 static unsigned long str2sec(const char* timestr)
3502 const char spec[] = "smhdw";
3503 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3504 unsigned long val = 0;
3507 if (strpbrk(timestr, spec) == NULL) {
3508 /* no specifiers inside the time string,
3509 should treat it as an integer value */
3510 val = strtoul(timestr, &tail, 10);
3511 return *tail ? ULONG_MAX : val;
3514 /* format string is XXwXXdXXhXXmXXs */
3520 v = strtoul(timestr, &tail, 10);
3521 if (v == ULONG_MAX || *tail == '\0')
3522 /* value too large (ULONG_MAX or more)
3523 or missing specifier */
3526 ptr = strchr(spec, *tail);
3528 /* unknown specifier */
3533 /* check if product will overflow the type */
3534 if (!(v < ULONG_MAX / mult[ind]))
3537 ADD_OVERFLOW(val, mult[ind] * v);
3538 if (val == ULONG_MAX)
3550 #define ARG2ULL(nr, str, def_units) \
3552 unsigned long long limit, units = def_units; \
3555 rc = llapi_parse_size(str, &limit, &units, 1); \
3557 fprintf(stderr, "error: bad limit value %s\n", str); \
3563 static inline int has_times_option(int argc, char **argv)
3567 for (i = 1; i < argc; i++)
3568 if (!strcmp(argv[i], "-t"))
3574 int lfs_setquota_times(int argc, char **argv)
3577 struct if_quotactl qctl;
3578 char *mnt, *obd_type = (char *)qctl.obd_type;
3579 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3580 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3581 struct option long_opts[] = {
3582 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3583 { .val = 'g', .name = "group", .has_arg = no_argument },
3584 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3585 { .val = 'p', .name = "projid", .has_arg = no_argument },
3586 { .val = 't', .name = "times", .has_arg = no_argument },
3587 { .val = 'u', .name = "user", .has_arg = no_argument },
3591 memset(&qctl, 0, sizeof(qctl));
3592 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3593 qctl.qc_type = ALLQUOTA;
3595 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3596 long_opts, NULL)) != -1) {
3607 if (qctl.qc_type != ALLQUOTA) {
3608 fprintf(stderr, "error: -u/g/p can't be used "
3609 "more than once\n");
3612 qctl.qc_type = qtype;
3615 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3616 fprintf(stderr, "error: bad block-grace: %s\n",
3620 dqb->dqb_valid |= QIF_BTIME;
3623 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3624 fprintf(stderr, "error: bad inode-grace: %s\n",
3628 dqb->dqb_valid |= QIF_ITIME;
3630 case 't': /* Yes, of course! */
3632 default: /* getopt prints error message for us when opterr != 0 */
3637 if (qctl.qc_type == ALLQUOTA) {
3638 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3642 if (optind != argc - 1) {
3643 fprintf(stderr, "error: unexpected parameters encountered\n");
3648 rc = llapi_quotactl(mnt, &qctl);
3651 fprintf(stderr, "%s %s ", obd_type,
3652 obd_uuid2str(&qctl.obd_uuid));
3653 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3660 #define BSLIMIT (1 << 0)
3661 #define BHLIMIT (1 << 1)
3662 #define ISLIMIT (1 << 2)
3663 #define IHLIMIT (1 << 3)
3665 int lfs_setquota(int argc, char **argv)
3668 struct if_quotactl qctl;
3669 char *mnt, *obd_type = (char *)qctl.obd_type;
3670 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3671 struct option long_opts[] = {
3672 { .val = 'b', .name = "block-softlimit",
3673 .has_arg = required_argument },
3674 { .val = 'B', .name = "block-hardlimit",
3675 .has_arg = required_argument },
3676 { .val = 'g', .name = "group", .has_arg = required_argument },
3677 { .val = 'i', .name = "inode-softlimit",
3678 .has_arg = required_argument },
3679 { .val = 'I', .name = "inode-hardlimit",
3680 .has_arg = required_argument },
3681 { .val = 'p', .name = "projid", .has_arg = required_argument },
3682 { .val = 'u', .name = "user", .has_arg = required_argument },
3684 unsigned limit_mask = 0;
3688 if (has_times_option(argc, argv))
3689 return lfs_setquota_times(argc, argv);
3691 memset(&qctl, 0, sizeof(qctl));
3692 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3693 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3694 * so it can be used as a marker that qc_type
3695 * isn't reinitialized from command line */
3697 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3698 long_opts, NULL)) != -1) {
3702 rc = name2uid(&qctl.qc_id, optarg);
3706 rc = name2gid(&qctl.qc_id, optarg);
3710 rc = name2projid(&qctl.qc_id, optarg);
3712 if (qctl.qc_type != ALLQUOTA) {
3713 fprintf(stderr, "error: -u and -g can't be used"
3714 " more than once\n");
3717 qctl.qc_type = qtype;
3719 qctl.qc_id = strtoul(optarg, &endptr, 10);
3720 if (*endptr != '\0') {
3721 fprintf(stderr, "error: can't find id "
3722 "for name %s\n", optarg);
3728 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3729 dqb->dqb_bsoftlimit >>= 10;
3730 limit_mask |= BSLIMIT;
3731 if (dqb->dqb_bsoftlimit &&
3732 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3733 fprintf(stderr, "warning: block softlimit is "
3734 "smaller than the miminal qunit size, "
3735 "please see the help of setquota or "
3736 "Lustre manual for details.\n");
3739 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3740 dqb->dqb_bhardlimit >>= 10;
3741 limit_mask |= BHLIMIT;
3742 if (dqb->dqb_bhardlimit &&
3743 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3744 fprintf(stderr, "warning: block hardlimit is "
3745 "smaller than the miminal qunit size, "
3746 "please see the help of setquota or "
3747 "Lustre manual for details.\n");
3750 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3751 limit_mask |= ISLIMIT;
3752 if (dqb->dqb_isoftlimit &&
3753 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3754 fprintf(stderr, "warning: inode softlimit is "
3755 "smaller than the miminal qunit size, "
3756 "please see the help of setquota or "
3757 "Lustre manual for details.\n");
3760 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3761 limit_mask |= IHLIMIT;
3762 if (dqb->dqb_ihardlimit &&
3763 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3764 fprintf(stderr, "warning: inode hardlimit is "
3765 "smaller than the miminal qunit size, "
3766 "please see the help of setquota or "
3767 "Lustre manual for details.\n");
3769 default: /* getopt prints error message for us when opterr != 0 */
3774 if (qctl.qc_type == ALLQUOTA) {
3775 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3779 if (limit_mask == 0) {
3780 fprintf(stderr, "error: at least one limit must be specified\n");
3784 if (optind != argc - 1) {
3785 fprintf(stderr, "error: unexpected parameters encountered\n");
3791 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3792 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3793 /* sigh, we can't just set blimits/ilimits */
3794 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3795 .qc_type = qctl.qc_type,
3796 .qc_id = qctl.qc_id};
3798 rc = llapi_quotactl(mnt, &tmp_qctl);
3800 fprintf(stderr, "error: setquota failed while retrieving"
3801 " current quota settings (%s)\n",
3806 if (!(limit_mask & BHLIMIT))
3807 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3808 if (!(limit_mask & BSLIMIT))
3809 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3810 if (!(limit_mask & IHLIMIT))
3811 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3812 if (!(limit_mask & ISLIMIT))
3813 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3815 /* Keep grace times if we have got no softlimit arguments */
3816 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3817 dqb->dqb_valid |= QIF_BTIME;
3818 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3821 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3822 dqb->dqb_valid |= QIF_ITIME;
3823 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3827 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3828 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3830 rc = llapi_quotactl(mnt, &qctl);
3833 fprintf(stderr, "%s %s ", obd_type,
3834 obd_uuid2str(&qctl.obd_uuid));
3835 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3842 /* Converts seconds value into format string
3843 * result is returned in buf
3845 * 1. result is in descenting order: 1w2d3h4m5s
3846 * 2. zero fields are not filled (except for p. 3): 5d1s
3847 * 3. zero seconds value is presented as "0s"
3849 static char * __sec2str(time_t seconds, char *buf)
3851 const char spec[] = "smhdw";
3852 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3857 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3858 c = seconds / mult[i];
3860 if (c > 0 || (i == 0 && buf == tail))
3861 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3869 static void sec2str(time_t seconds, char *buf, int rc)
3876 tail = __sec2str(seconds, tail);
3878 if (rc && tail - buf < 39) {
3884 static void diff2str(time_t seconds, char *buf, time_t now)
3890 if (seconds <= now) {
3891 strcpy(buf, "none");
3894 __sec2str(seconds - now, buf);
3897 static void print_quota_title(char *name, struct if_quotactl *qctl,
3898 bool human_readable)
3900 printf("Disk quotas for %s %s (%cid %u):\n",
3901 qtype_name(qctl->qc_type), name,
3902 *qtype_name(qctl->qc_type), qctl->qc_id);
3903 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3904 "Filesystem", human_readable ? "used" : "kbytes",
3905 "quota", "limit", "grace",
3906 "files", "quota", "limit", "grace");
3909 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3912 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3915 snprintf(buf, buflen, "%5.4gP",
3916 (double)num / ((__u64)1 << 40));
3918 snprintf(buf, buflen, "%5.4gT",
3919 (double)num / (1 << 30));
3921 snprintf(buf, buflen, "%5.4gG",
3922 (double)num / (1 << 20));
3924 snprintf(buf, buflen, "%5.4gM",
3925 (double)num / (1 << 10));
3927 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3931 #define STRBUF_LEN 32
3932 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3939 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3940 int bover = 0, iover = 0;
3941 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3942 char numbuf[3][STRBUF_LEN];
3944 char strbuf[STRBUF_LEN];
3946 if (dqb->dqb_bhardlimit &&
3947 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3949 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3950 if (dqb->dqb_btime > now) {
3957 if (dqb->dqb_ihardlimit &&
3958 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3960 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3961 if (dqb->dqb_itime > now) {
3969 if (strlen(mnt) > 15)
3970 printf("%s\n%15s", mnt, "");
3972 printf("%15s", mnt);
3975 diff2str(dqb->dqb_btime, timebuf, now);
3977 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3978 strbuf, sizeof(strbuf), h);
3979 if (rc == -EREMOTEIO)
3980 sprintf(numbuf[0], "%s*", strbuf);
3982 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3983 "%s" : "[%s]", strbuf);
3985 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3986 if (type == QC_GENERAL)
3987 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3988 "%s" : "[%s]", strbuf);
3990 sprintf(numbuf[1], "%s", "-");
3992 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3993 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3994 "%s" : "[%s]", strbuf);
3996 printf(" %7s%c %6s %7s %7s",
3997 numbuf[0], bover ? '*' : ' ', numbuf[1],
3998 numbuf[2], bover > 1 ? timebuf : "-");
4001 diff2str(dqb->dqb_itime, timebuf, now);
4003 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4004 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4006 if (type == QC_GENERAL)
4007 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4009 (uintmax_t)dqb->dqb_isoftlimit);
4011 sprintf(numbuf[1], "%s", "-");
4013 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4014 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4016 if (type != QC_OSTIDX)
4017 printf(" %7s%c %6s %7s %7s",
4018 numbuf[0], iover ? '*' : ' ', numbuf[1],
4019 numbuf[2], iover > 1 ? timebuf : "-");
4021 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4024 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4025 qctl->qc_cmd == Q_GETOINFO) {
4029 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4030 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4031 printf("Block grace time: %s; Inode grace time: %s\n",
4032 bgtimebuf, igtimebuf);
4036 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4037 bool h, __u64 *total)
4039 int rc = 0, rc1 = 0, count = 0;
4040 __u32 valid = qctl->qc_valid;
4042 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4044 fprintf(stderr, "can not get %s count: %s\n",
4045 is_mdt ? "mdt": "ost", strerror(-rc));
4049 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4050 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4051 rc = llapi_quotactl(mnt, qctl);
4053 /* It is remote client case. */
4054 if (rc == -EOPNOTSUPP) {
4061 fprintf(stderr, "quotactl %s%d failed.\n",
4062 is_mdt ? "mdt": "ost", qctl->qc_idx);
4066 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4067 qctl->qc_valid, 0, h);
4068 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4069 qctl->qc_dqblk.dqb_bhardlimit;
4072 qctl->qc_valid = valid;
4076 static int lfs_quota(int argc, char **argv)
4079 char *mnt, *name = NULL;
4080 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4081 .qc_type = ALLQUOTA };
4082 char *obd_type = (char *)qctl.obd_type;
4083 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4084 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4085 verbose = 0, pass = 0, quiet = 0, inacc;
4087 __u32 valid = QC_GENERAL, idx = 0;
4088 __u64 total_ialloc = 0, total_balloc = 0;
4089 bool human_readable = false;
4092 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4103 if (qctl.qc_type != ALLQUOTA) {
4104 fprintf(stderr, "error: use either -u or -g\n");
4107 qctl.qc_type = qtype;
4110 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4113 valid = qctl.qc_valid = QC_UUID;
4114 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4117 valid = qctl.qc_valid = QC_MDTIDX;
4118 idx = qctl.qc_idx = atoi(optarg);
4121 valid = qctl.qc_valid = QC_OSTIDX;
4122 idx = qctl.qc_idx = atoi(optarg);
4131 human_readable = true;
4134 fprintf(stderr, "error: %s: option '-%c' "
4135 "unrecognized\n", argv[0], c);
4140 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4141 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4142 optind == argc - 1) {
4144 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4145 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4146 qctl.qc_valid = valid;
4148 qctl.qc_type = pass;
4149 switch (qctl.qc_type) {
4151 qctl.qc_id = geteuid();
4152 rc = uid2name(&name, qctl.qc_id);
4155 qctl.qc_id = getegid();
4156 rc = gid2name(&name, qctl.qc_id);
4166 /* lfs quota -u username /path/to/lustre/mount */
4167 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4168 /* options should be followed by u/g-name and mntpoint */
4169 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4170 fprintf(stderr, "error: missing quota argument(s)\n");
4174 name = argv[optind++];
4175 switch (qctl.qc_type) {
4177 rc = name2uid(&qctl.qc_id, name);
4180 rc = name2gid(&qctl.qc_id, name);
4183 rc = name2projid(&qctl.qc_id, name);
4190 qctl.qc_id = strtoul(name, &endptr, 10);
4191 if (*endptr != '\0') {
4192 fprintf(stderr, "error: can't find id for name: %s\n",
4197 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4198 fprintf(stderr, "error: missing quota info argument(s)\n");
4203 rc1 = llapi_quotactl(mnt, &qctl);
4207 fprintf(stderr, "%s quotas are not enabled.\n",
4208 qtype_name(qctl.qc_type));
4211 fprintf(stderr, "Permission denied.\n");
4214 /* We already got error message. */
4217 fprintf(stderr, "Unexpected quotactl error: %s\n",
4222 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4223 print_quota_title(name, &qctl, human_readable);
4225 if (rc1 && *obd_type)
4226 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4228 if (qctl.qc_valid != QC_GENERAL)
4231 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4232 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4233 (QIF_LIMITS|QIF_USAGE));
4235 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4237 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4239 char strbuf[STRBUF_LEN];
4241 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4243 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4245 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4247 printf("Total allocated inode limit: %ju, total "
4248 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4252 if (rc1 || rc2 || rc3 || inacc)
4253 printf("Some errors happened when getting quota info. "
4254 "Some devices may be not working or deactivated. "
4255 "The data in \"[]\" is inaccurate.\n");
4258 if (pass > 0 && pass < LL_MAXQUOTAS)
4263 #endif /* HAVE_SYS_QUOTA_H! */
4265 static int flushctx_ioctl(char *mp)
4269 fd = open(mp, O_RDONLY);
4271 fprintf(stderr, "flushctx: error open %s: %s\n",
4272 mp, strerror(errno));
4276 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4278 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4279 mp, strerror(errno));
4285 static int lfs_flushctx(int argc, char **argv)
4287 int kdestroy = 0, c;
4288 char mntdir[PATH_MAX] = {'\0'};
4292 while ((c = getopt(argc, argv, "k")) != -1) {
4298 fprintf(stderr, "error: %s: option '-%c' "
4299 "unrecognized\n", argv[0], c);
4305 if ((rc = system("kdestroy > /dev/null")) != 0) {
4306 rc = WEXITSTATUS(rc);
4307 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4311 if (optind >= argc) {
4312 /* flush for all mounted lustre fs. */
4313 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4314 /* Check if we have a mount point */
4315 if (mntdir[0] == '\0')
4318 if (flushctx_ioctl(mntdir))
4321 mntdir[0] = '\0'; /* avoid matching in next loop */
4324 /* flush fs as specified */
4325 while (optind < argc) {
4326 if (flushctx_ioctl(argv[optind++]))
4333 static int lfs_cp(int argc, char **argv)
4335 fprintf(stderr, "remote client copy file(s).\n"
4336 "obsolete, does not support it anymore.\n");
4340 static int lfs_ls(int argc, char **argv)
4342 fprintf(stderr, "remote client lists directory contents.\n"
4343 "obsolete, does not support it anymore.\n");
4347 static int lfs_changelog(int argc, char **argv)
4349 void *changelog_priv;
4350 struct changelog_rec *rec;
4351 long long startrec = 0, endrec = 0;
4353 struct option long_opts[] = {
4354 { .val = 'f', .name = "follow", .has_arg = no_argument },
4356 char short_opts[] = "f";
4359 while ((rc = getopt_long(argc, argv, short_opts,
4360 long_opts, NULL)) != -1) {
4368 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4369 argv[0], argv[optind - 1]);
4376 mdd = argv[optind++];
4378 startrec = strtoll(argv[optind++], NULL, 10);
4380 endrec = strtoll(argv[optind++], NULL, 10);
4382 rc = llapi_changelog_start(&changelog_priv,
4383 CHANGELOG_FLAG_BLOCK |
4384 CHANGELOG_FLAG_JOBID |
4385 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4388 fprintf(stderr, "Can't start changelog: %s\n",
4389 strerror(errno = -rc));
4393 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4397 if (endrec && rec->cr_index > endrec) {
4398 llapi_changelog_free(&rec);
4401 if (rec->cr_index < startrec) {
4402 llapi_changelog_free(&rec);
4406 secs = rec->cr_time >> 30;
4407 gmtime_r(&secs, &ts);
4408 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4409 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4410 changelog_type2str(rec->cr_type),
4411 ts.tm_hour, ts.tm_min, ts.tm_sec,
4412 (int)(rec->cr_time & ((1 << 30) - 1)),
4413 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4414 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4416 if (rec->cr_flags & CLF_JOBID) {
4417 struct changelog_ext_jobid *jid =
4418 changelog_rec_jobid(rec);
4420 if (jid->cr_jobid[0] != '\0')
4421 printf(" j=%s", jid->cr_jobid);
4424 if (rec->cr_namelen)
4425 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4426 rec->cr_namelen, changelog_rec_name(rec));
4428 if (rec->cr_flags & CLF_RENAME) {
4429 struct changelog_ext_rename *rnm =
4430 changelog_rec_rename(rec);
4432 if (!fid_is_zero(&rnm->cr_sfid))
4433 printf(" s="DFID" sp="DFID" %.*s",
4434 PFID(&rnm->cr_sfid),
4435 PFID(&rnm->cr_spfid),
4436 (int)changelog_rec_snamelen(rec),
4437 changelog_rec_sname(rec));
4441 llapi_changelog_free(&rec);
4444 llapi_changelog_fini(&changelog_priv);
4447 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4449 return (rc == 1 ? 0 : rc);
4452 static int lfs_changelog_clear(int argc, char **argv)
4460 endrec = strtoll(argv[3], NULL, 10);
4462 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4465 fprintf(stderr, "%s: record out of range: %llu\n",
4467 else if (rc == -ENOENT)
4468 fprintf(stderr, "%s: no changelog user: %s\n",
4471 fprintf(stderr, "%s error: %s\n", argv[0],
4480 static int lfs_fid2path(int argc, char **argv)
4482 struct option long_opts[] = {
4483 { .val = 'c', .name = "cur", .has_arg = no_argument },
4484 { .val = 'l', .name = "link", .has_arg = required_argument },
4485 { .val = 'r', .name = "rec", .has_arg = required_argument },
4487 char short_opts[] = "cl:r:";
4488 char *device, *fid, *path;
4489 long long recno = -1;
4495 while ((rc = getopt_long(argc, argv, short_opts,
4496 long_opts, NULL)) != -1) {
4502 linkno = strtol(optarg, NULL, 10);
4505 recno = strtoll(optarg, NULL, 10);
4510 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4511 argv[0], argv[optind - 1]);
4519 device = argv[optind++];
4520 path = calloc(1, PATH_MAX);
4522 fprintf(stderr, "error: Not enough memory\n");
4527 while (optind < argc) {
4528 fid = argv[optind++];
4530 lnktmp = (linkno >= 0) ? linkno : 0;
4532 int oldtmp = lnktmp;
4533 long long rectmp = recno;
4535 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4538 fprintf(stderr, "%s: error on FID %s: %s\n",
4539 argv[0], fid, strerror(errno = -rc2));
4546 fprintf(stdout, "%lld ", rectmp);
4547 if (device[0] == '/') {
4548 fprintf(stdout, "%s", device);
4549 if (device[strlen(device) - 1] != '/')
4550 fprintf(stdout, "/");
4551 } else if (path[0] == '\0') {
4552 fprintf(stdout, "/");
4554 fprintf(stdout, "%s\n", path);
4557 /* specified linkno */
4559 if (oldtmp == lnktmp)
4569 static int lfs_path2fid(int argc, char **argv)
4571 struct option long_opts[] = {
4572 { .val = 'p', .name = "parents", .has_arg = no_argument },
4575 const char short_opts[] = "p";
4576 const char *sep = "";
4579 bool show_parents = false;
4581 while ((rc = getopt_long(argc, argv, short_opts,
4582 long_opts, NULL)) != -1) {
4585 show_parents = true;
4588 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4589 argv[0], argv[optind - 1]);
4594 if (optind > argc - 1)
4596 else if (optind < argc - 1)
4600 for (path = argv + optind; *path != NULL; path++) {
4602 if (!show_parents) {
4603 err = llapi_path2fid(*path, &fid);
4605 printf("%s%s"DFID"\n",
4606 *sep != '\0' ? *path : "", sep,
4609 char name[NAME_MAX + 1];
4610 unsigned int linkno = 0;
4612 while ((err = llapi_path2parent(*path, linkno, &fid,
4613 name, sizeof(name))) == 0) {
4614 if (*sep != '\0' && linkno == 0)
4615 printf("%s%s", *path, sep);
4617 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4622 /* err == -ENODATA is end-of-loop */
4623 if (linkno > 0 && err == -ENODATA) {
4630 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4631 argv[0], show_parents ? "parent " : "", *path,
4643 static int lfs_data_version(int argc, char **argv)
4650 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4655 while ((c = getopt(argc, argv, "nrw")) != -1) {
4658 data_version_flags = 0;
4661 data_version_flags |= LL_DV_RD_FLUSH;
4664 data_version_flags |= LL_DV_WR_FLUSH;
4673 path = argv[optind];
4674 fd = open(path, O_RDONLY);
4676 err(errno, "cannot open file %s", path);
4678 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4680 err(errno, "cannot get version for %s", path);
4682 printf("%ju" "\n", (uintmax_t)data_version);
4688 static int lfs_hsm_state(int argc, char **argv)
4693 struct hsm_user_state hus;
4701 rc = llapi_hsm_state_get(path, &hus);
4703 fprintf(stderr, "can't get hsm state for %s: %s\n",
4704 path, strerror(errno = -rc));
4708 /* Display path name and status flags */
4709 printf("%s: (0x%08x)", path, hus.hus_states);
4711 if (hus.hus_states & HS_RELEASED)
4712 printf(" released");
4713 if (hus.hus_states & HS_EXISTS)
4715 if (hus.hus_states & HS_DIRTY)
4717 if (hus.hus_states & HS_ARCHIVED)
4718 printf(" archived");
4719 /* Display user-settable flags */
4720 if (hus.hus_states & HS_NORELEASE)
4721 printf(" never_release");
4722 if (hus.hus_states & HS_NOARCHIVE)
4723 printf(" never_archive");
4724 if (hus.hus_states & HS_LOST)
4725 printf(" lost_from_hsm");
4727 if (hus.hus_archive_id != 0)
4728 printf(", archive_id:%d", hus.hus_archive_id);
4731 } while (++i < argc);
4736 #define LFS_HSM_SET 0
4737 #define LFS_HSM_CLEAR 1
4740 * Generic function to set or clear HSM flags.
4741 * Used by hsm_set and hsm_clear.
4743 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4745 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4747 struct option long_opts[] = {
4748 { .val = 'A', .name = "archived", .has_arg = no_argument },
4749 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4750 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4751 { .val = 'e', .name = "exists", .has_arg = no_argument },
4752 { .val = 'l', .name = "lost", .has_arg = no_argument },
4753 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4755 char short_opts[] = "lraAde";
4763 while ((c = getopt_long(argc, argv, short_opts,
4764 long_opts, NULL)) != -1) {
4770 mask |= HS_NOARCHIVE;
4773 mask |= HS_ARCHIVED;
4776 mask |= HS_NORELEASE;
4787 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4788 argv[0], argv[optind - 1]);
4793 /* User should have specified a flag */
4797 while (optind < argc) {
4799 path = argv[optind];
4801 /* If mode == 0, this means we apply the mask. */
4802 if (mode == LFS_HSM_SET)
4803 rc = llapi_hsm_state_set(path, mask, 0, 0);
4805 rc = llapi_hsm_state_set(path, 0, mask, 0);
4808 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4809 path, strerror(errno = -rc));
4818 static int lfs_hsm_action(int argc, char **argv)
4823 struct hsm_current_action hca;
4824 struct hsm_extent he;
4825 enum hsm_user_action hua;
4826 enum hsm_progress_states hps;
4834 rc = llapi_hsm_current_action(path, &hca);
4836 fprintf(stderr, "can't get hsm action for %s: %s\n",
4837 path, strerror(errno = -rc));
4840 he = hca.hca_location;
4841 hua = hca.hca_action;
4842 hps = hca.hca_state;
4844 printf("%s: %s", path, hsm_user_action2name(hua));
4846 /* Skip file without action */
4847 if (hca.hca_action == HUA_NONE) {
4852 printf(" %s ", hsm_progress_state2name(hps));
4854 if ((hps == HPS_RUNNING) &&
4855 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4856 printf("(%llu bytes moved)\n",
4857 (unsigned long long)he.length);
4858 else if ((he.offset + he.length) == LUSTRE_EOF)
4859 printf("(from %llu to EOF)\n",
4860 (unsigned long long)he.offset);
4862 printf("(from %llu to %llu)\n",
4863 (unsigned long long)he.offset,
4864 (unsigned long long)(he.offset + he.length));
4866 } while (++i < argc);
4871 static int lfs_hsm_set(int argc, char **argv)
4873 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4876 static int lfs_hsm_clear(int argc, char **argv)
4878 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4882 * Check file state and return its fid, to be used by lfs_hsm_request().
4884 * \param[in] file Path to file to check
4885 * \param[in,out] fid Pointer to allocated lu_fid struct.
4886 * \param[in,out] last_dev Pointer to last device id used.
4888 * \return 0 on success.
4890 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4896 rc = lstat(file, &st);
4898 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4901 /* Checking for regular file as archiving as posix copytool
4902 * rejects archiving files other than regular files
4904 if (!S_ISREG(st.st_mode)) {
4905 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4908 /* A request should be ... */
4909 if (*last_dev != st.st_dev && *last_dev != 0) {
4910 fprintf(stderr, "All files should be "
4911 "on the same filesystem: %s\n", file);
4914 *last_dev = st.st_dev;
4916 rc = llapi_path2fid(file, fid);
4918 fprintf(stderr, "Cannot read FID of %s: %s\n",
4919 file, strerror(-rc));
4925 /* Fill an HSM HUR item with a given file name.
4927 * If mntpath is set, then the filename is actually a FID, and no
4928 * lookup on the filesystem will be performed.
4930 * \param[in] hur the user request to fill
4931 * \param[in] idx index of the item inside the HUR to fill
4932 * \param[in] mntpath mountpoint of Lustre
4933 * \param[in] fname filename (if mtnpath is NULL)
4934 * or FID (if mntpath is set)
4935 * \param[in] last_dev pointer to last device id used
4937 * \retval 0 on success
4938 * \retval CMD_HELP or a negative errno on error
4940 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4941 const char *mntpath, const char *fname,
4944 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4947 hui->hui_extent.length = -1;
4949 if (mntpath != NULL) {
4952 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4956 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4961 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4965 hur->hur_request.hr_itemcount++;
4970 static int lfs_hsm_request(int argc, char **argv, int action)
4972 struct option long_opts[] = {
4973 { .val = 'a', .name = "archive", .has_arg = required_argument },
4974 { .val = 'D', .name = "data", .has_arg = required_argument },
4975 { .val = 'l', .name = "filelist", .has_arg = required_argument },
4976 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
4979 char short_opts[] = "l:D:a:m:";
4980 struct hsm_user_request *hur, *oldhur;
4985 char *filelist = NULL;
4986 char fullpath[PATH_MAX];
4987 char *opaque = NULL;
4991 int nbfile_alloc = 0;
4992 char *some_file = NULL;
4993 char *mntpath = NULL;
4999 while ((c = getopt_long(argc, argv, short_opts,
5000 long_opts, NULL)) != -1) {
5009 if (action != HUA_ARCHIVE &&
5010 action != HUA_REMOVE) {
5012 "error: -a is supported only "
5013 "when archiving or removing\n");
5016 archive_id = atoi(optarg);
5019 if (some_file == NULL) {
5021 some_file = strdup(optarg);
5027 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5028 argv[0], argv[optind - 1]);
5033 /* All remaining args are files, so we have at least nbfile */
5034 nbfile = argc - optind;
5036 if ((nbfile == 0) && (filelist == NULL))
5040 opaque_len = strlen(opaque);
5042 /* Alloc the request structure with enough place to store all files
5043 * from command line. */
5044 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5046 fprintf(stderr, "Cannot create the request: %s\n",
5050 nbfile_alloc = nbfile;
5052 hur->hur_request.hr_action = action;
5053 hur->hur_request.hr_archive_id = archive_id;
5054 hur->hur_request.hr_flags = 0;
5056 /* All remaining args are files, add them */
5057 if (nbfile != 0 && some_file == NULL)
5058 some_file = strdup(argv[optind]);
5060 for (i = 0; i < nbfile; i++) {
5061 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5067 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5069 /* If a filelist was specified, read the filelist from it. */
5070 if (filelist != NULL) {
5071 fp = fopen(filelist, "r");
5073 fprintf(stderr, "Cannot read the file list %s: %s\n",
5074 filelist, strerror(errno));
5079 while ((rc = getline(&line, &len, fp)) != -1) {
5080 /* If allocated buffer was too small, get something
5082 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5085 nbfile_alloc = nbfile_alloc * 2 + 1;
5087 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5090 fprintf(stderr, "hsm: cannot allocate "
5091 "the request: %s\n",
5098 size = hur_len(oldhur);
5100 fprintf(stderr, "hsm: cannot allocate "
5101 "%u files + %u bytes data\n",
5102 oldhur->hur_request.hr_itemcount,
5103 oldhur->hur_request.hr_data_len);
5110 memcpy(hur, oldhur, size);
5115 if (line[strlen(line) - 1] == '\n')
5116 line[strlen(line) - 1] = '\0';
5118 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5119 mntpath, line, &last_dev);
5125 if (some_file == NULL) {
5135 /* If a --data was used, add it to the request */
5136 hur->hur_request.hr_data_len = opaque_len;
5138 memcpy(hur_data(hur), opaque, opaque_len);
5140 /* Send the HSM request */
5141 if (realpath(some_file, fullpath) == NULL) {
5142 fprintf(stderr, "Could not find path '%s': %s\n",
5143 some_file, strerror(errno));
5145 rc = llapi_hsm_request(fullpath, hur);
5147 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5148 some_file, strerror(-rc));
5158 static int lfs_hsm_archive(int argc, char **argv)
5160 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5163 static int lfs_hsm_restore(int argc, char **argv)
5165 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5168 static int lfs_hsm_release(int argc, char **argv)
5170 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5173 static int lfs_hsm_remove(int argc, char **argv)
5175 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5178 static int lfs_hsm_cancel(int argc, char **argv)
5180 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5183 static int lfs_swap_layouts(int argc, char **argv)
5188 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5189 SWAP_LAYOUTS_KEEP_MTIME |
5190 SWAP_LAYOUTS_KEEP_ATIME);
5193 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5195 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5197 static const char *const lockahead_results[] = {
5198 [LLA_RESULT_SENT] = "Lock request sent",
5199 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5200 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5203 int lfs_get_mode(const char *string)
5205 enum lock_mode_user mode;
5207 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5208 if (lock_mode_names[mode] == NULL)
5210 if (strcmp(string, lock_mode_names[mode]) == 0)
5217 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5219 enum lu_ladvise_type advice;
5222 advice < ARRAY_SIZE(ladvise_names); advice++) {
5223 if (ladvise_names[advice] == NULL)
5225 if (strcmp(string, ladvise_names[advice]) == 0)
5229 return LU_LADVISE_INVALID;
5232 static int lfs_ladvise(int argc, char **argv)
5234 struct option long_opts[] = {
5235 { .val = 'a', .name = "advice", .has_arg = required_argument },
5236 { .val = 'b', .name = "background", .has_arg = no_argument },
5237 { .val = 'e', .name = "end", .has_arg = required_argument },
5238 { .val = 'l', .name = "length", .has_arg = required_argument },
5239 { .val = 'm', .name = "mode", .has_arg = required_argument },
5240 { .val = 's', .name = "start", .has_arg = required_argument },
5241 { .val = 'u', .name = "unset", .has_arg = no_argument },
5243 char short_opts[] = "a:be:l:m:s:u";
5248 struct llapi_lu_ladvise advice;
5249 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5250 unsigned long long start = 0;
5251 unsigned long long end = LUSTRE_EOF;
5252 unsigned long long length = 0;
5253 unsigned long long size_units;
5254 unsigned long long flags = 0;
5258 while ((c = getopt_long(argc, argv, short_opts,
5259 long_opts, NULL)) != -1) {
5262 advice_type = lfs_get_ladvice(optarg);
5263 if (advice_type == LU_LADVISE_INVALID) {
5264 fprintf(stderr, "%s: invalid advice type "
5265 "'%s'\n", argv[0], optarg);
5266 fprintf(stderr, "Valid types:");
5268 for (advice_type = 0;
5269 advice_type < ARRAY_SIZE(ladvise_names);
5271 if (ladvise_names[advice_type] == NULL)
5273 fprintf(stderr, " %s",
5274 ladvise_names[advice_type]);
5276 fprintf(stderr, "\n");
5289 rc = llapi_parse_size(optarg, &end,
5292 fprintf(stderr, "%s: bad end offset '%s'\n",
5299 rc = llapi_parse_size(optarg, &start,
5302 fprintf(stderr, "%s: bad start offset "
5303 "'%s'\n", argv[0], optarg);
5309 rc = llapi_parse_size(optarg, &length,
5312 fprintf(stderr, "%s: bad length '%s'\n",
5318 mode = lfs_get_mode(optarg);
5320 fprintf(stderr, "%s: bad mode '%s', valid "
5321 "modes are READ or WRITE\n",
5329 fprintf(stderr, "%s: option '%s' unrecognized\n",
5330 argv[0], argv[optind - 1]);
5335 if (advice_type == LU_LADVISE_INVALID) {
5336 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5337 fprintf(stderr, "Valid types:");
5338 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5340 if (ladvise_names[advice_type] == NULL)
5342 fprintf(stderr, " %s", ladvise_names[advice_type]);
5344 fprintf(stderr, "\n");
5348 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
5349 fprintf(stderr, "%s: Lock no expand advice is a per file "
5350 "descriptor advice, so when called from lfs, "
5351 "it does nothing.\n", argv[0]);
5355 if (argc <= optind) {
5356 fprintf(stderr, "%s: please give one or more file names\n",
5361 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5362 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5367 if (end == LUSTRE_EOF && length != 0)
5368 end = start + length;
5371 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5372 argv[0], start, end);
5376 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
5377 fprintf(stderr, "%s: mode is only valid with lockahead\n",
5382 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
5383 fprintf(stderr, "%s: mode is required with lockahead\n",
5388 while (optind < argc) {
5391 path = argv[optind++];
5393 fd = open(path, O_RDONLY);
5395 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5396 argv[0], path, strerror(errno));
5401 advice.lla_start = start;
5402 advice.lla_end = end;
5403 advice.lla_advice = advice_type;
5404 advice.lla_value1 = 0;
5405 advice.lla_value2 = 0;
5406 advice.lla_value3 = 0;
5407 advice.lla_value4 = 0;
5408 if (advice_type == LU_LADVISE_LOCKAHEAD) {
5409 advice.lla_lockahead_mode = mode;
5410 advice.lla_peradvice_flags = flags;
5413 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5416 fprintf(stderr, "%s: cannot give advice '%s' to file "
5417 "'%s': %s\n", argv[0],
5418 ladvise_names[advice_type],
5419 path, strerror(errno));
5425 if (rc == 0 && rc2 < 0)
5431 static int lfs_list_commands(int argc, char **argv)
5433 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5435 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5440 int main(int argc, char **argv)
5444 /* Ensure that liblustreapi constructor has run */
5445 if (!liblustreapi_initialized)
5446 fprintf(stderr, "liblustreapi was not properly initialized\n");
5451 Parser_init("lfs > ", cmdlist);
5453 progname = argv[0]; /* Used in error messages */
5455 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5457 rc = Parser_commands();
5459 return rc < 0 ? -rc : rc;
5462 #ifdef _LUSTRE_IDL_H_
5463 /* Everything we need here should be included by lustreapi.h. */
5464 # error "lfs should not depend on lustre_idl.h"
5465 #endif /* _LUSTRE_IDL_H_ */