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>
63 #ifdef HAVE_SYS_QUOTA_H
64 # include <sys/quota.h>
67 #include <libcfs/util/string.h>
68 #include <libcfs/util/ioctl.h>
69 #include <libcfs/util/parser.h>
70 #include <lustre/lustreapi.h>
71 #include <lustre_ver.h>
72 #include <lustre_param.h>
75 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
76 #endif /* !ARRAY_SIZE */
79 static int lfs_setstripe(int argc, char **argv);
80 static int lfs_find(int argc, char **argv);
81 static int lfs_getstripe(int argc, char **argv);
82 static int lfs_getdirstripe(int argc, char **argv);
83 static int lfs_setdirstripe(int argc, char **argv);
84 static int lfs_rmentry(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_mdts(int argc, char **argv);
87 static int lfs_df(int argc, char **argv);
88 static int lfs_getname(int argc, char **argv);
89 static int lfs_check(int argc, char **argv);
90 #ifdef HAVE_SYS_QUOTA_H
91 static int lfs_setquota(int argc, char **argv);
92 static int lfs_quota(int argc, char **argv);
94 static int lfs_flushctx(int argc, char **argv);
95 static int lfs_cp(int argc, char **argv);
96 static int lfs_ls(int argc, char **argv);
97 static int lfs_poollist(int argc, char **argv);
98 static int lfs_changelog(int argc, char **argv);
99 static int lfs_changelog_clear(int argc, char **argv);
100 static int lfs_fid2path(int argc, char **argv);
101 static int lfs_path2fid(int argc, char **argv);
102 static int lfs_data_version(int argc, char **argv);
103 static int lfs_hsm_state(int argc, char **argv);
104 static int lfs_hsm_set(int argc, char **argv);
105 static int lfs_hsm_clear(int argc, char **argv);
106 static int lfs_hsm_action(int argc, char **argv);
107 static int lfs_hsm_archive(int argc, char **argv);
108 static int lfs_hsm_restore(int argc, char **argv);
109 static int lfs_hsm_release(int argc, char **argv);
110 static int lfs_hsm_remove(int argc, char **argv);
111 static int lfs_hsm_cancel(int argc, char **argv);
112 static int lfs_swap_layouts(int argc, char **argv);
113 static int lfs_mv(int argc, char **argv);
114 static int lfs_ladvise(int argc, char **argv);
115 static int lfs_list_commands(int argc, char **argv);
117 /* Setstripe and migrate share mostly the same parameters */
118 #define SSM_CMD_COMMON(cmd) \
119 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
120 " [--stripe-index|-i <start_ost_idx>]\n" \
121 " [--stripe-size|-S <stripe_size>]\n" \
122 " [--pool|-p <pool_name>]\n" \
123 " [--ost|-o <ost_indices>]\n" \
124 " [--component-end|-E <comp_end>]\n"
126 #define SSM_HELP_COMMON \
127 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
128 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
129 "\t respectively)\n" \
130 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
131 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
132 "\tpool_name: Name of OST pool to use (default none)\n" \
133 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
134 "\t Indices be specified in a format of:\n" \
135 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
137 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
138 "\t If --pool is set with --ost, then the OSTs\n" \
139 "\t must be the members of the pool." \
140 "\tcomp_end: Extent end of the component\n" \
141 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
142 "\t respectively, -1 for EOF), it must be aligned with\n"\
143 "\t the stripe_size\n"
145 #define SETSTRIPE_USAGE \
146 SSM_CMD_COMMON("setstripe") \
147 " <directory|filename>\n" \
150 #define MIGRATE_USAGE \
151 SSM_CMD_COMMON("migrate ") \
153 " [--non-block|-n]\n" \
157 "\tblock: Block file access during data migration (default)\n" \
158 "\tnon-block: Abort migrations if concurrent access is detected\n" \
160 #define SETDIRSTRIPE_USAGE \
161 " [--mdt-count|-c stripe_count>\n" \
162 " [--mdt-index|-i mdt_index]\n" \
163 " [--mdt-hash|-t mdt_hash]\n" \
164 " [--default|-D] [--mode|-m mode] <dir>\n" \
165 "\tstripe_count: stripe count of the striped directory\n" \
166 "\tmdt_index: MDT index of first stripe\n" \
167 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
168 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
169 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
170 "\tdefault_stripe: set default dirstripe of the directory\n" \
171 "\tmode: the mode of the directory\n"
173 static const char *progname;
174 static bool file_lease_supported = true;
176 /* all available commands */
177 command_t cmdlist[] = {
178 {"setstripe", lfs_setstripe, 0,
179 "Create a new file with a specific striping pattern or\n"
180 "set the default striping pattern on an existing directory or\n"
181 "delete the default striping pattern from an existing directory or\n"
182 "add layout component(s) to an existing composite file or\n"
183 "delete specified component(s) from an existing composite file\n\n"
184 "To delete default striping from an existing directory:\n"
185 "usage: setstripe -d <directory>\n"
187 "To delete component(s) from an existing composite file:\n"
188 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
189 " [--component-flags|-F <comp_flags>]\n"
191 "\tcomp_id: Unique component ID\n"
192 "\tcomp_flags: 'init' indicating all instantiated components\n"
193 "\t-I and -F can't be specified at the same time\n"
195 "To add component(s) to an existing composite file:\n"
196 SSM_CMD_COMMON("setstripe --component-add")
198 "To create a file with specified striping/composite layout:\n"
200 {"getstripe", lfs_getstripe, 0,
201 "To list the striping info for a given file or files in a\n"
202 "directory or recursively for all files in a directory tree.\n"
203 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
204 " [--stripe-count|-c] [--stripe-index|-i]\n"
205 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
206 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
207 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
208 " [--component-id|-I [comp_id]]\n"
209 " [--component-flags [comp_flags]]\n"
210 " [--component-count [comp_count]]\n"
211 " [--component-start [comp_start]]\n"
212 " [--component-end|-E [comp_end]]\n"
213 " <directory|filename> ..."},
214 {"setdirstripe", lfs_setdirstripe, 0,
215 "To create a striped directory on a specified MDT. This can only\n"
216 "be done on MDT0 with the right of administrator.\n"
217 "usage: setdirstripe [OPTION] <directory>\n"
219 {"getdirstripe", lfs_getdirstripe, 0,
220 "To list the striping info for a given directory\n"
221 "or recursively for all directories in a directory tree.\n"
222 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
223 " [--mdt-index|-i] [--mdt-hash|-t]\n"
224 " [--recursive|-r] [--default|-D] <dir> ..."},
225 {"mkdir", lfs_setdirstripe, 0,
226 "To create a striped directory on a specified MDT. This can only\n"
227 "be done on MDT0 with the right of administrator.\n"
228 "usage: mkdir [OPTION] <directory>\n"
230 {"rm_entry", lfs_rmentry, 0,
231 "To remove the name entry of the remote directory. Note: This\n"
232 "command will only delete the name entry, i.e. the remote directory\n"
233 "will become inaccessable after this command. This can only be done\n"
234 "by the administrator\n"
235 "usage: rm_entry <dir>\n"},
236 {"pool_list", lfs_poollist, 0,
237 "List pools or pool OSTs\n"
238 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
239 {"find", lfs_find, 0,
240 "find files matching given attributes recursively in directory tree.\n"
241 "usage: find <directory|filename> ...\n"
242 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
243 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
244 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
245 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
246 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
247 " [[!] --stripe-count|-c [+-]<stripes>]\n"
248 " [[!] --stripe-index|-i <index,...>]\n"
249 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
250 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
251 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
252 " [[!] --layout|-L released,raid0]\n"
253 " [[!] --component-count [+-]<comp_cnt>]\n"
254 " [[!] --component-start [+-]N[kMGTPE]]\n"
255 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
256 " [[!] --component-flags <comp_flags>]\n"
257 "\t !: used before an option indicates 'NOT' requested attribute\n"
258 "\t -: used before a value indicates 'AT MOST' requested value\n"
259 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
260 {"check", lfs_check, 0,
261 "Display the status of MDS or OSTs (as specified in the command)\n"
262 "or all the servers (MDS and OSTs).\n"
263 "usage: check <osts|mds|servers>"},
264 {"osts", lfs_osts, 0, "list OSTs connected to client "
265 "[for specified path only]\n" "usage: osts [path]"},
266 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
267 "[for specified path only]\n" "usage: mdts [path]"},
269 "report filesystem disk space usage or inodes usage"
270 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
271 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
272 {"getname", lfs_getname, 0, "list instances and specified mount points "
273 "[for specified path only]\n"
274 "Usage: getname [-h]|[path ...] "},
275 #ifdef HAVE_SYS_QUOTA_H
276 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
277 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
278 " -b <block-softlimit> -B <block-hardlimit>\n"
279 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
280 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
281 " [--block-softlimit <block-softlimit>]\n"
282 " [--block-hardlimit <block-hardlimit>]\n"
283 " [--inode-softlimit <inode-softlimit>]\n"
284 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
285 " setquota [-t] <-u|--user|-g|--group>\n"
286 " [--block-grace <block-grace>]\n"
287 " [--inode-grace <inode-grace>] <filesystem>\n"
288 " -b can be used instead of --block-softlimit/--block-grace\n"
289 " -B can be used instead of --block-hardlimit\n"
290 " -i can be used instead of --inode-softlimit/--inode-grace\n"
291 " -I can be used instead of --inode-hardlimit\n\n"
292 "Note: The total quota space will be split into many qunits and\n"
293 " balanced over all server targets, the minimal qunit size is\n"
294 " 1M bytes for block space and 1K inodes for inode space.\n\n"
295 " Quota space rebalancing process will stop when this mininum\n"
296 " value is reached. As a result, quota exceeded can be returned\n"
297 " while many targets still have 1MB or 1K inodes of spare\n"
299 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
300 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
302 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
303 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
305 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
306 "usage: flushctx [-k] [mountpoint...]"},
308 "Remote user copy files and directories.\n"
309 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
311 "Remote user list directory contents.\n"
312 "usage: ls [OPTION]... [FILE]..."},
313 {"changelog", lfs_changelog, 0,
314 "Show the metadata changes on an MDT."
315 "\nusage: changelog <mdtname> [startrec [endrec]]"},
316 {"changelog_clear", lfs_changelog_clear, 0,
317 "Indicate that old changelog records up to <endrec> are no longer of "
318 "interest to consumer <id>, allowing the system to free up space.\n"
319 "An <endrec> of 0 means all records.\n"
320 "usage: changelog_clear <mdtname> <id> <endrec>"},
321 {"fid2path", lfs_fid2path, 0,
322 "Resolve the full path(s) for given FID(s). For a specific hardlink "
323 "specify link number <linkno>.\n"
324 /* "For a historical link name, specify changelog record <recno>.\n" */
325 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
326 /* [ --rec <recno> ] */ },
327 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
328 "usage: path2fid [--parents] <path> ..."},
329 {"data_version", lfs_data_version, 0, "Display file data version for "
330 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
331 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
332 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
333 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
334 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
335 "[--archived] [--lost] <file> ..."},
336 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
338 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
339 "[--archived] [--lost] <file> ..."},
340 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
341 "given files.\n" "usage: hsm_action <file> ..."},
342 {"hsm_archive", lfs_hsm_archive, 0,
343 "Archive file to external storage.\n"
344 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
346 {"hsm_restore", lfs_hsm_restore, 0,
347 "Restore file from external storage.\n"
348 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
349 {"hsm_release", lfs_hsm_release, 0,
350 "Release files from Lustre.\n"
351 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
352 {"hsm_remove", lfs_hsm_remove, 0,
353 "Remove file copy from external storage.\n"
354 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
355 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
357 "Note: To remove files from the archive that have been deleted on\n"
358 "Lustre, set mntpath and optionally archive. In that case, all the\n"
359 "positional arguments and entries in the file list must be FIDs."
361 {"hsm_cancel", lfs_hsm_cancel, 0,
362 "Cancel requests related to specified files.\n"
363 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
364 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
365 "usage: swap_layouts <path1> <path2>"},
366 {"migrate", lfs_setstripe, 0,
367 "migrate a directory between MDTs.\n"
368 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
370 "\tmdt_idx: index of the destination MDT\n"
372 "migrate file objects from one OST "
373 "layout\nto another (may be not safe with concurent writes).\n"
375 "[--stripe-count|-c] <stripe_count>\n"
376 " [--stripe-index|-i] <start_ost_index>\n"
377 " [--stripe-size|-S] <stripe_size>\n"
378 " [--pool|-p] <pool_name>\n"
379 " [--ost-list|-o] <ost_indices>\n"
381 " [--non-block|-n]\n"
382 " <file|directory>\n"
383 "\tstripe_count: number of OSTs to stripe a file over\n"
384 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
385 "\tstripe_size: number of bytes to store before moving to the next OST\n"
386 "\tpool_name: name of the predefined pool of OSTs\n"
387 "\tost_indices: OSTs to stripe over, in order\n"
388 "\tblock: wait for the operation to return before continuing\n"
389 "\tnon-block: do not wait for the operation to return.\n"},
391 "To move directories between MDTs. This command is deprecated, "
392 "use \"migrate\" instead.\n"
393 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
395 {"ladvise", lfs_ladvise, 0,
396 "Provide servers with advice about access patterns for a file.\n"
397 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
398 " [--background|-b]\n"
399 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\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
415 * Internal helper for migrate_copy_data(). Check lease and report error if
418 * \param[in] fd File descriptor on which to check the lease.
419 * \param[out] lease_broken Set to true if the lease was broken.
420 * \param[in] group_locked Whether a group lock was taken or not.
421 * \param[in] path Name of the file being processed, for error
424 * \retval 0 Migration can keep on going.
425 * \retval -errno Error occurred, abort migration.
427 static int check_lease(int fd, bool *lease_broken, bool group_locked,
432 if (!file_lease_supported)
435 rc = llapi_lease_check(fd);
437 return 0; /* llapi_check_lease returns > 0 on success. */
440 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
442 rc = rc ? rc : -EAGAIN;
444 fprintf(stderr, "%s: external attempt to access file '%s' "
445 "blocked until migration ends.\n", progname, path);
448 *lease_broken = true;
452 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
453 bool group_locked, const char *fname)
462 bool lease_broken = false;
464 /* Use a page-aligned buffer for direct I/O */
465 rc = posix_memalign(&buf, getpagesize(), buf_size);
470 /* read new data only if we have written all
471 * previously read data */
474 rc = check_lease(fd_src, &lease_broken,
475 group_locked, fname);
479 rsize = read(fd_src, buf, buf_size);
482 fprintf(stderr, "%s: %s: read failed: %s\n",
483 progname, fname, strerror(-rc));
493 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
497 "%s: %s: write failed on volatile: %s\n",
498 progname, fname, strerror(-rc));
508 fprintf(stderr, "%s: %s: fsync failed: %s\n",
509 progname, fname, strerror(-rc));
517 static int migrate_copy_timestamps(int fdv, const struct stat *st)
519 struct timeval tv[2] = {
520 {.tv_sec = st->st_atime},
521 {.tv_sec = st->st_mtime}
524 return futimes(fdv, tv);
527 static int migrate_block(int fd, int fdv, const struct stat *st,
528 size_t buf_size, const char *name)
535 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
537 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
538 progname, name, strerror(-rc));
546 /* The grouplock blocks all concurrent accesses to the file.
547 * It has to be taken after llapi_get_data_version as it would
549 rc = llapi_group_lock(fd, gid);
551 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
552 progname, name, strerror(-rc));
556 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
558 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
562 /* Make sure we keep original atime/mtime values */
563 rc = migrate_copy_timestamps(fdv, st);
565 fprintf(stderr, "%s: %s: timestamp copy failed\n",
571 * for a migration we need to check data version on file did
574 * Pass in gid=0 since we already own grouplock. */
575 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
576 SWAP_LAYOUTS_CHECK_DV1);
578 fprintf(stderr, "%s: %s: dataversion changed during copy, "
579 "migration aborted\n", progname, name);
582 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
583 name, strerror(-rc));
588 rc2 = llapi_group_unlock(fd, gid);
589 if (rc2 < 0 && rc == 0) {
590 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
591 progname, name, strerror(-rc2));
598 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
599 size_t buf_size, const char *name)
605 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
607 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
608 progname, name, strerror(-rc));
612 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
614 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
618 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
620 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
621 progname, name, strerror(-rc));
627 fprintf(stderr, "%s: %s: data version changed during "
633 /* Make sure we keep original atime/mtime values */
634 rc = migrate_copy_timestamps(fdv, st);
636 fprintf(stderr, "%s: %s: timestamp copy failed\n",
641 /* Atomically put lease, swap layouts and close.
642 * for a migration we need to check data version on file did
644 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
646 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
647 progname, name, strerror(-rc));
654 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
659 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
663 if (flags != 0 && comp_id != 0)
666 /* LCME_FL_INIT is the only supported flag in PFL */
668 if (flags & ~LCME_KNOWN_FLAGS) {
669 fprintf(stderr, "Invalid component flags %#x\n", flags);
672 comp_id = LCME_ID_NONE | flags;
673 } else if (comp_id > LCME_ID_MAX) {
674 fprintf(stderr, "Invalid component id %u\n", comp_id);
678 rc = llapi_layout_file_comp_del(fname, comp_id);
680 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
681 comp_id, fname, strerror(errno));
685 static int lfs_component_add(char *fname, struct llapi_layout *layout)
692 rc = llapi_layout_file_comp_add(fname, layout);
694 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
695 fname, strerror(errno));
699 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
700 struct llapi_layout *layout)
708 fd = lstat(fname, &st);
709 if (fd == 0 && S_ISDIR(st.st_mode)) {
710 open_flags = O_DIRECTORY | O_RDONLY;
711 fd = llapi_layout_file_open(fname, open_flags, open_mode,
714 fd = llapi_layout_file_create(fname, open_flags, open_mode,
719 fprintf(stderr, "%s %s failed. %s\n",
720 S_ISDIR(st.st_mode) ?
721 "Set default composite layout to " :
722 "Create composite file",
723 fname, strerror(errno));
727 static int lfs_migrate(char *name, __u64 migration_flags,
728 struct llapi_stripe_param *param,
729 struct llapi_layout *layout)
733 char parent[PATH_MAX];
736 char volatile_file[sizeof(parent) +
737 LUSTRE_VOLATILE_HDR_LEN +
738 2 * sizeof(mdt_index) +
739 2 * sizeof(random_value) + 4];
742 struct lov_user_md *lum = NULL;
744 int buf_size = 1024 * 1024 * 4;
745 bool have_lease_rdlck = false;
749 /* find the right size for the IO and allocate the buffer */
750 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
751 lum = malloc(lum_size);
757 rc = llapi_file_get_stripe(name, lum);
758 /* failure can happen for many reasons and some may be not real errors
760 * in case of a real error, a later call will fail with better
761 * error management */
763 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
764 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
765 lum->lmm_stripe_size != 0)
766 buf_size = lum->lmm_stripe_size;
769 /* open file, direct io */
770 /* even if the file is only read, WR mode is nedeed to allow
771 * layout swap on fd */
772 fd = open(name, O_RDWR | O_DIRECT);
775 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
780 if (file_lease_supported) {
781 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
782 if (rc == -EOPNOTSUPP) {
783 /* Older servers do not support file lease.
784 * Disable related checks. This opens race conditions
785 * as explained in LU-4840 */
786 file_lease_supported = false;
788 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
789 progname, name, strerror(-rc));
792 have_lease_rdlck = true;
796 /* search for file directory pathname */
797 if (strlen(name) > sizeof(parent)-1) {
801 strncpy(parent, name, sizeof(parent));
802 ptr = strrchr(parent, '/');
804 if (getcwd(parent, sizeof(parent)) == NULL) {
815 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
817 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
818 progname, name, strerror(-rc));
823 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
824 mode_t open_mode = S_IRUSR | S_IWUSR;
826 random_value = random();
827 rc = snprintf(volatile_file, sizeof(volatile_file),
828 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
829 mdt_index, random_value);
830 if (rc >= sizeof(volatile_file)) {
835 /* create, open a volatile file, use caching (ie no directio) */
837 fdv = llapi_file_open_param(volatile_file, open_flags,
839 else if (layout != NULL)
840 fdv = lfs_component_create(volatile_file, open_flags,
844 } while (fdv == -EEXIST);
848 fprintf(stderr, "%s: %s: cannot create volatile file in"
850 progname, parent, strerror(-rc));
854 /* In case the MDT does not support creation of volatile files
855 * we should try to unlink it. */
856 (void)unlink(volatile_file);
858 /* Not-owner (root?) special case.
859 * Need to set owner/group of volatile file like original.
860 * This will allow to pass related check during layout_swap.
865 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
869 rc = fstat(fdv, &stv);
872 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
873 volatile_file, strerror(errno));
876 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
877 rc = fchown(fdv, st.st_uid, st.st_gid);
880 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
881 name, strerror(errno));
886 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
887 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
889 have_lease_rdlck = false;
890 fdv = -1; /* The volatile file is closed as we put the
891 * lease in non-blocking mode. */
894 /* Blocking mode (forced if servers do not support file lease).
895 * It is also the default mode, since we cannot distinguish
896 * between a broken lease and a server that does not support
897 * atomic swap/close (LU-6785) */
898 rc = migrate_block(fd, fdv, &st, buf_size, name);
902 if (have_lease_rdlck)
919 * Parse a string containing an OST index list into an array of integers.
921 * The input string contains a comma delimited list of individual
922 * indices and ranges, for example "1,2-4,7". Add the indices into the
923 * \a osts array and remove duplicates.
925 * \param[out] osts array to store indices in
926 * \param[in] size size of \a osts array
927 * \param[in] offset starting index in \a osts
928 * \param[in] arg string containing OST index list
930 * \retval positive number of indices in \a osts
931 * \retval -EINVAL unable to parse \a arg
933 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
937 int slots = size - offset;
945 while (!end_of_loop) {
953 ptr = strchrnul(arg, ',');
955 end_of_loop = *ptr == '\0';
958 start_index = strtol(arg, &endptr, 0);
959 if (endptr == arg) /* no data at all */
961 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
966 end_index = start_index;
967 if (*endptr == '-') {
968 end_index = strtol(endptr + 1, &endptr, 0);
971 if (end_index < start_index)
975 for (i = start_index; i <= end_index && slots > 0; i++) {
978 /* remove duplicate */
979 for (j = 0; j < offset; j++) {
983 if (j == offset) { /* no duplicate */
988 if (slots == 0 && i < end_index)
996 if (!end_of_loop && ptr != NULL)
999 return rc < 0 ? rc : nr;
1002 static int verify_pool_name(char *prog_name, char *pool_name)
1007 if (pool_name == NULL)
1010 ptr = strchr(pool_name, '.');
1014 if (ptr == pool_name) {
1015 fprintf(stderr, "error: %s: fsname is empty "
1016 "in pool name '%s'\n",
1017 prog_name, pool_name);
1023 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1025 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1026 prog_name, pool_name);
1028 } else if (rc == -2) {
1029 fprintf(stderr, "error: %s: pool name '%s' is too long "
1030 "(max is %d characters)\n",
1031 prog_name, pool_name, LOV_MAXPOOLNAME);
1033 } else if (rc > 0) {
1034 fprintf(stderr, "error: %s: char '%c' not allowed in "
1036 prog_name, rc, pool_name);
1042 struct lfs_setstripe_args {
1044 unsigned long long lsa_stripe_size;
1045 int lsa_stripe_count;
1047 __u32 lsa_comp_flags;
1050 char *lsa_pool_name;
1053 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1055 memset(lsa, 0, sizeof(*lsa));
1056 lsa->lsa_stripe_off = -1;
1059 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1061 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1062 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1063 lsa->lsa_comp_end != 0);
1066 static int comp_args_to_layout(struct llapi_layout **composite,
1067 struct lfs_setstripe_args *lsa)
1069 struct llapi_layout *layout = *composite;
1070 uint64_t prev_end = 0;
1073 if (layout == NULL) {
1074 layout = llapi_layout_alloc();
1075 if (layout == NULL) {
1076 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1080 *composite = layout;
1084 /* Get current component extent, current component
1085 * must be the tail component. */
1086 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1088 fprintf(stderr, "Get comp extent failed. %s\n",
1093 rc = llapi_layout_comp_add(layout);
1095 fprintf(stderr, "Add component failed. %s\n",
1101 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1103 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1104 prev_end, lsa->lsa_comp_end, strerror(errno));
1108 if (lsa->lsa_stripe_size != 0) {
1109 rc = llapi_layout_stripe_size_set(layout,
1110 lsa->lsa_stripe_size);
1112 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1113 lsa->lsa_stripe_size, strerror(errno));
1118 if (lsa->lsa_stripe_count != 0) {
1119 rc = llapi_layout_stripe_count_set(layout,
1120 lsa->lsa_stripe_count == -1 ?
1122 lsa->lsa_stripe_count);
1124 fprintf(stderr, "Set stripe count %d failed. %s\n",
1125 lsa->lsa_stripe_count, strerror(errno));
1130 if (lsa->lsa_pool_name != NULL) {
1131 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1133 fprintf(stderr, "Set pool name: %s failed. %s\n",
1134 lsa->lsa_pool_name, strerror(errno));
1139 if (lsa->lsa_nr_osts > 0) {
1140 if (lsa->lsa_stripe_count > 0 &&
1141 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1142 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1143 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1146 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1147 rc = llapi_layout_ost_index_set(layout, i,
1152 } else if (lsa->lsa_stripe_off != -1) {
1153 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1156 fprintf(stderr, "Set ost index %d failed. %s\n",
1157 i, strerror(errno));
1164 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1165 * end of the last component in the existing file, and adjust the
1166 * first extent start of the components to be added accordingly. */
1167 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1169 struct llapi_layout *head;
1170 uint64_t start, end, stripe_size, prev_end = 0;
1176 head = llapi_layout_get_by_path(fname, 0);
1178 fprintf(stderr, "Read layout from %s failed. %s\n",
1179 fname, strerror(errno));
1183 /* Current component of 'head' should be tail of component list. */
1184 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1186 fprintf(stderr, "Get prev extent failed. %s\n",
1188 llapi_layout_free(head);
1192 llapi_layout_free(head);
1194 /* Make sure we use the first component of the layout to be added. */
1195 rc = llapi_layout_comp_move(layout, LLAPI_LAYOUT_COMP_POS_FIRST);
1197 fprintf(stderr, "Move component cursor failed. %s\n",
1202 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1204 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1208 if (start > prev_end || end <= prev_end) {
1209 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1210 "adjacent with the existing file extent end: %lu\n",
1211 start, end, prev_end);
1215 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1217 fprintf(stderr, "Get stripe size failed. %s\n",
1222 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1223 (prev_end & (stripe_size - 1))) {
1224 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1225 stripe_size, prev_end);
1229 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1231 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1232 prev_end, end, strerror(errno));
1239 static int comp_name2flags(__u32 *flags, char *name)
1247 for (ptr = name; ; ptr = NULL) {
1248 char *flg = strtok(ptr, ",");
1251 if (strcmp(flg, "init") == 0)
1252 *flags |= LCME_FL_INIT;
1256 return (*flags == 0) ? -EINVAL : 0;
1270 static int lfs_setstripe(int argc, char **argv)
1272 struct lfs_setstripe_args lsa;
1273 struct llapi_stripe_param *param = NULL;
1274 struct find_param migrate_mdt_param = {
1284 char *mdt_idx_arg = NULL;
1285 unsigned long long size_units = 1;
1286 bool migrate_mode = false;
1287 bool migration_block = false;
1288 __u64 migration_flags = 0;
1289 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1290 int comp_del = 0, comp_set = 0;
1293 struct llapi_layout *layout = NULL;
1295 struct option long_opts[] = {
1296 /* --block is only valid in migrate mode */
1297 {"block", no_argument, 0, 'b'},
1298 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1299 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1300 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1301 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1302 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1303 /* This formerly implied "stripe-count", but was explicitly
1304 * made "stripe-count" for consistency with other options,
1305 * and to separate it from "mdt-count" when DNE arrives. */
1306 {"count", required_argument, 0, 'c'},
1308 {"stripe-count", required_argument, 0, 'c'},
1309 {"stripe_count", required_argument, 0, 'c'},
1310 {"delete", no_argument, 0, 'd'},
1311 {"component-end", required_argument, 0, 'E'},
1312 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1313 /* This formerly implied "stripe-index", but was explicitly
1314 * made "stripe-index" for consistency with other options,
1315 * and to separate it from "mdt-index" when DNE arrives. */
1316 {"index", required_argument, 0, 'i'},
1318 {"stripe-index", required_argument, 0, 'i'},
1319 {"stripe_index", required_argument, 0, 'i'},
1320 {"component-id", required_argument, 0, 'I'},
1321 {"mdt", required_argument, 0, 'm'},
1322 {"mdt-index", required_argument, 0, 'm'},
1323 {"mdt_index", required_argument, 0, 'm'},
1324 /* --non-block is only valid in migrate mode */
1325 {"non-block", no_argument, 0, 'n'},
1326 {"ost", required_argument, 0, 'o'},
1327 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1328 {"ost-list", required_argument, 0, 'o'},
1329 {"ost_list", required_argument, 0, 'o'},
1331 {"pool", required_argument, 0, 'p'},
1332 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1333 /* This formerly implied "--stripe-size", but was confusing
1334 * with "lfs find --size|-s", which means "file size", so use
1335 * the consistent "--stripe-size|-S" for all commands. */
1336 {"size", required_argument, 0, 's'},
1338 {"stripe-size", required_argument, 0, 'S'},
1339 {"stripe_size", required_argument, 0, 'S'},
1340 /* --verbose is only valid in migrate mode */
1341 {"verbose", no_argument, 0, 'v'},
1345 setstripe_args_init(&lsa);
1347 if (strcmp(argv[0], "migrate") == 0)
1348 migrate_mode = true;
1350 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1351 long_opts, NULL)) >= 0) {
1356 case LFS_COMP_ADD_OPT:
1359 case LFS_COMP_DEL_OPT:
1362 case LFS_COMP_FLAGS_OPT:
1363 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1365 fprintf(stderr, "error: %s: bad comp flags "
1366 "'%s'\n", argv[0], optarg);
1370 case LFS_COMP_SET_OPT:
1374 if (!migrate_mode) {
1375 fprintf(stderr, "--block is valid only for"
1379 migration_block = true;
1382 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1383 if (strcmp(argv[optind - 1], "--count") == 0)
1384 fprintf(stderr, "warning: '--count' deprecated"
1385 ", use '--stripe-count' instead\n");
1387 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1389 fprintf(stderr, "error: %s: bad stripe count "
1390 "'%s'\n", argv[0], optarg);
1395 /* delete the default striping pattern */
1399 if (lsa.lsa_comp_end != 0) {
1400 result = comp_args_to_layout(&layout, &lsa);
1404 setstripe_args_init(&lsa);
1407 if (!strncmp(optarg, "-1", strlen("-1")) ||
1408 !strncmp(optarg, "EOF", strlen("EOF")) ||
1409 !strncmp(optarg, "eof", strlen("eof"))) {
1410 lsa.lsa_comp_end = LUSTRE_EOF;
1412 result = llapi_parse_size(optarg,
1416 fprintf(stderr, "error: %s: "
1417 "bad component end '%s'\n",
1424 if (strcmp(argv[optind - 1], "--index") == 0)
1425 fprintf(stderr, "warning: '--index' deprecated"
1426 ", use '--stripe-index' instead\n");
1427 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1429 fprintf(stderr, "error: %s: bad stripe offset "
1430 "'%s'\n", argv[0], optarg);
1435 comp_id = strtoul(optarg, &end, 0);
1436 if (*end != '\0' || comp_id == 0) {
1437 fprintf(stderr, "error: %s: bad comp ID "
1438 "'%s'\n", argv[0], optarg);
1443 if (!migrate_mode) {
1444 fprintf(stderr, "--mdt-index is valid only for"
1448 mdt_idx_arg = optarg;
1451 if (!migrate_mode) {
1452 fprintf(stderr, "--non-block is valid only for"
1456 migration_flags |= MIGRATION_NONBLOCK;
1459 lsa.lsa_nr_osts = parse_targets(osts,
1460 sizeof(osts) / sizeof(__u32),
1461 lsa.lsa_nr_osts, optarg);
1462 if (lsa.lsa_nr_osts < 0) {
1464 "error: %s: bad OST indices '%s'\n",
1469 lsa.lsa_osts = osts;
1470 if (lsa.lsa_stripe_off == -1)
1471 lsa.lsa_stripe_off = osts[0];
1474 result = verify_pool_name(argv[0], optarg);
1477 lsa.lsa_pool_name = optarg;
1479 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1481 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1482 fprintf(stderr, "warning: '--size|-s' deprecated, "
1483 "use '--stripe-size|-S' instead\n");
1485 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1487 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1490 fprintf(stderr, "error: %s: bad stripe size "
1491 "'%s'\n", argv[0], optarg);
1496 if (!migrate_mode) {
1497 fprintf(stderr, "--verbose is valid only for"
1501 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1508 fname = argv[optind];
1510 if (lsa.lsa_comp_end != 0) {
1511 result = comp_args_to_layout(&layout, &lsa);
1516 if (optind == argc) {
1517 fprintf(stderr, "error: %s: missing filename|dirname\n",
1522 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1523 * altered by user space tool, so we don't need to support the
1524 * --component-set for this moment. */
1525 if (comp_set != 0) {
1526 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1531 if ((delete + comp_set + comp_del + comp_add) > 1) {
1532 fprintf(stderr, "error: %s: can't specify --component-set, "
1533 "--component-del, --component-add or -d together\n",
1538 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1539 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1540 fprintf(stderr, "error: %s: can't specify -d with "
1541 "-s, -c, -o, -p, -I, -F or -E options\n",
1546 if ((comp_set || comp_del) &&
1547 (setstripe_args_specified(&lsa) || layout != NULL)) {
1548 fprintf(stderr, "error: %s: can't specify --component-del or "
1549 "--component-set with -s, -c, -o, -p or -E options.\n",
1554 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1555 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1556 "--component-del option.\n", argv[0]);
1561 if (layout == NULL) {
1562 fprintf(stderr, "error: %s: -E option must be present"
1563 "in --component-add mode.\n", argv[0]);
1566 result = adjust_first_extent(fname, layout);
1571 if (mdt_idx_arg != NULL && optind > 3) {
1572 fprintf(stderr, "error: %s: cannot specify -m with other "
1573 "options\n", argv[0]);
1577 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1579 "error: %s: cannot specify --non-block and --block\n",
1584 /* support --component-id option for migrate later. */
1585 if (migrate_mode && comp_id != 0) {
1586 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1591 if (mdt_idx_arg != NULL) {
1592 /* initialize migrate mdt parameters */
1593 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1595 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1596 argv[0], mdt_idx_arg);
1599 migrate_mdt_param.fp_migrate = 1;
1600 } else if (layout == NULL) {
1601 /* initialize stripe parameters */
1602 param = calloc(1, offsetof(typeof(*param),
1603 lsp_osts[lsa.lsa_nr_osts]));
1604 if (param == NULL) {
1605 fprintf(stderr, "error: %s: %s\n", argv[0],
1610 param->lsp_stripe_size = lsa.lsa_stripe_size;
1611 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1612 param->lsp_stripe_count = lsa.lsa_stripe_count;
1613 param->lsp_stripe_pattern = 0;
1614 param->lsp_pool = lsa.lsa_pool_name;
1615 param->lsp_is_specific = false;
1616 if (lsa.lsa_nr_osts > 0) {
1617 if (lsa.lsa_stripe_count > 0 &&
1618 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1619 fprintf(stderr, "error: %s: stripe count '%d' "
1620 "doesn't match the number of OSTs: %d\n"
1621 , argv[0], lsa.lsa_stripe_count,
1627 param->lsp_is_specific = true;
1628 param->lsp_stripe_count = lsa.lsa_nr_osts;
1629 memcpy(param->lsp_osts, osts,
1630 sizeof(*osts) * lsa.lsa_nr_osts);
1634 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1636 if (mdt_idx_arg != NULL) {
1637 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1638 op = "migrate mdt objects of";
1639 } else if (migrate_mode) {
1640 result = lfs_migrate(fname, migration_flags, param,
1642 op = "migrate ost objects of";
1643 } else if (comp_set != 0) {
1644 result = lfs_component_set(fname, comp_id,
1645 lsa.lsa_comp_flags);
1646 op = "modify component flags of";
1647 } else if (comp_del != 0) {
1648 result = lfs_component_del(fname, comp_id,
1649 lsa.lsa_comp_flags);
1650 op = "delete component of";
1651 } else if (comp_add != 0) {
1652 result = lfs_component_add(fname, layout);
1653 op = "add component to";
1654 } else if (layout != NULL) {
1655 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1661 op = "create composite";
1663 result = llapi_file_open_param(fname,
1670 op = "create striped";
1673 /* Save the first error encountered. */
1676 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1678 lsa.lsa_pool_name != NULL && result == EINVAL ?
1679 "OST not in pool?" : strerror(errno));
1685 llapi_layout_free(layout);
1688 llapi_layout_free(layout);
1692 static int lfs_poollist(int argc, char **argv)
1697 return llapi_poollist(argv[1]);
1700 static int set_time(time_t *time, time_t *set, char *str)
1707 else if (str[0] == '-')
1713 t = strtol(str, NULL, 0);
1714 if (*time < t * 24 * 60 * 60) {
1717 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1721 *set = *time - t * 24 * 60 * 60;
1728 static int name2id(unsigned int *id, char *name, int type)
1731 struct passwd *entry;
1733 if (!(entry = getpwnam(name))) {
1739 *id = entry->pw_uid;
1741 struct group *entry;
1743 if (!(entry = getgrnam(name))) {
1749 *id = entry->gr_gid;
1755 static int id2name(char **name, unsigned int id, int type)
1758 struct passwd *entry;
1760 if (!(entry = getpwuid(id))) {
1766 *name = entry->pw_name;
1768 struct group *entry;
1770 if (!(entry = getgrgid(id))) {
1776 *name = entry->gr_name;
1782 static int name2layout(__u32 *layout, char *name)
1787 for (ptr = name; ; ptr = NULL) {
1788 lyt = strtok(ptr, ",");
1791 if (strcmp(lyt, "released") == 0)
1792 *layout |= LOV_PATTERN_F_RELEASED;
1793 else if (strcmp(lyt, "raid0") == 0)
1794 *layout |= LOV_PATTERN_RAID0;
1801 static int lfs_find(int argc, char **argv)
1806 struct find_param param = {
1810 struct option long_opts[] = {
1811 {"atime", required_argument, 0, 'A'},
1812 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1813 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1814 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1815 {"stripe-count", required_argument, 0, 'c'},
1816 {"stripe_count", required_argument, 0, 'c'},
1817 {"ctime", required_argument, 0, 'C'},
1818 {"maxdepth", required_argument, 0, 'D'},
1819 {"component-end", required_argument, 0, 'E'},
1820 {"gid", required_argument, 0, 'g'},
1821 {"group", required_argument, 0, 'G'},
1822 {"stripe-index", required_argument, 0, 'i'},
1823 {"stripe_index", required_argument, 0, 'i'},
1824 /*{"component-id", required_argument, 0, 'I'},*/
1825 {"layout", required_argument, 0, 'L'},
1826 {"mdt", required_argument, 0, 'm'},
1827 {"mdt-index", required_argument, 0, 'm'},
1828 {"mdt_index", required_argument, 0, 'm'},
1829 {"mtime", required_argument, 0, 'M'},
1830 {"name", required_argument, 0, 'n'},
1831 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1832 {"obd", required_argument, 0, 'O'},
1833 {"ost", required_argument, 0, 'O'},
1834 /* no short option for pool, p/P already used */
1835 {"pool", required_argument, 0, LFS_POOL_OPT},
1836 {"print0", no_argument, 0, 'p'},
1837 {"print", no_argument, 0, 'P'},
1838 {"size", required_argument, 0, 's'},
1839 {"stripe-size", required_argument, 0, 'S'},
1840 {"stripe_size", required_argument, 0, 'S'},
1841 {"type", required_argument, 0, 't'},
1842 {"uid", required_argument, 0, 'u'},
1843 {"user", required_argument, 0, 'U'},
1856 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1857 while ((c = getopt_long_only(argc, argv,
1858 "-A:c:C:D:E:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1859 long_opts, NULL)) >= 0) {
1864 /* '!' is part of option */
1865 /* when getopt_long_only() finds a string which is not
1866 * an option nor a known option argument it returns 1
1867 * in that case if we already have found pathstart and pathend
1868 * (i.e. we have the list of pathnames),
1869 * the only supported value is "!"
1871 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1872 if (!isoption && pathend != -1) {
1873 fprintf(stderr, "err: %s: filename|dirname must either "
1874 "precede options or follow options\n",
1879 if (!isoption && pathstart == -1)
1880 pathstart = optind - 1;
1881 if (isoption && pathstart != -1 && pathend == -1)
1882 pathend = optind - 2;
1888 /* unknown; opt is "!" or path component,
1889 * checking done above.
1891 if (strcmp(optarg, "!") == 0)
1895 xtime = ¶m.fp_atime;
1896 xsign = ¶m.fp_asign;
1897 param.fp_exclude_atime = !!neg_opt;
1898 /* no break, this falls through to 'C' for ctime */
1901 xtime = ¶m.fp_ctime;
1902 xsign = ¶m.fp_csign;
1903 param.fp_exclude_ctime = !!neg_opt;
1905 /* no break, this falls through to 'M' for mtime */
1908 xtime = ¶m.fp_mtime;
1909 xsign = ¶m.fp_msign;
1910 param.fp_exclude_mtime = !!neg_opt;
1912 rc = set_time(&t, xtime, optarg);
1913 if (rc == INT_MAX) {
1920 case LFS_COMP_COUNT_OPT:
1921 if (optarg[0] == '+') {
1922 param.fp_comp_count_sign = -1;
1924 } else if (optarg[0] == '-') {
1925 param.fp_comp_count_sign = 1;
1929 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1930 if (*endptr != '\0') {
1931 fprintf(stderr, "error: bad component count "
1935 param.fp_check_comp_count = 1;
1936 param.fp_exclude_comp_count = !!neg_opt;
1938 case LFS_COMP_FLAGS_OPT:
1939 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1941 fprintf(stderr, "error: bad component flags "
1945 param.fp_check_comp_flags = 1;
1946 param.fp_exclude_comp_flags = !!neg_opt;
1948 case LFS_COMP_START_OPT:
1949 if (optarg[0] == '+') {
1950 param.fp_comp_start_sign = -1;
1952 } else if (optarg[0] == '-') {
1953 param.fp_comp_start_sign = 1;
1957 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1958 ¶m.fp_comp_start_units, 0);
1960 fprintf(stderr, "error: bad component start "
1964 param.fp_check_comp_start = 1;
1965 param.fp_exclude_comp_start = !!neg_opt;
1968 if (optarg[0] == '+') {
1969 param.fp_stripe_count_sign = -1;
1971 } else if (optarg[0] == '-') {
1972 param.fp_stripe_count_sign = 1;
1976 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1977 if (*endptr != '\0') {
1978 fprintf(stderr,"error: bad stripe_count '%s'\n",
1983 param.fp_check_stripe_count = 1;
1984 param.fp_exclude_stripe_count = !!neg_opt;
1987 param.fp_max_depth = strtol(optarg, 0, 0);
1990 if (optarg[0] == '+') {
1991 param.fp_comp_end_sign = -1;
1993 } else if (optarg[0] == '-') {
1994 param.fp_comp_end_sign = 1;
1998 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
1999 ¶m.fp_comp_end_units, 0);
2001 fprintf(stderr, "error: bad component end "
2005 param.fp_check_comp_end = 1;
2006 param.fp_exclude_comp_end = !!neg_opt;
2010 rc = name2id(¶m.fp_gid, optarg, GROUP);
2012 param.fp_gid = strtoul(optarg, &endptr, 10);
2013 if (*endptr != '\0') {
2014 fprintf(stderr, "Group/GID: %s cannot "
2015 "be found.\n", optarg);
2020 param.fp_exclude_gid = !!neg_opt;
2021 param.fp_check_gid = 1;
2024 ret = name2layout(¶m.fp_layout, optarg);
2027 param.fp_exclude_layout = !!neg_opt;
2028 param.fp_check_layout = 1;
2032 rc = name2id(¶m.fp_uid, optarg, USER);
2034 param.fp_uid = strtoul(optarg, &endptr, 10);
2035 if (*endptr != '\0') {
2036 fprintf(stderr, "User/UID: %s cannot "
2037 "be found.\n", optarg);
2042 param.fp_exclude_uid = !!neg_opt;
2043 param.fp_check_uid = 1;
2046 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2048 "Pool name %s is too long"
2049 " (max is %d)\n", optarg,
2054 /* we do check for empty pool because empty pool
2055 * is used to find V1 lov attributes */
2056 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2057 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2058 param.fp_exclude_pool = !!neg_opt;
2059 param.fp_check_pool = 1;
2062 param.fp_pattern = (char *)optarg;
2063 param.fp_exclude_pattern = !!neg_opt;
2068 char *buf, *token, *next, *p;
2072 buf = strdup(optarg);
2078 param.fp_exclude_obd = !!neg_opt;
2081 while (token && *token) {
2082 token = strchr(token, ',');
2089 param.fp_exclude_mdt = !!neg_opt;
2090 param.fp_num_alloc_mdts += len;
2091 tmp = realloc(param.fp_mdt_uuid,
2092 param.fp_num_alloc_mdts *
2093 sizeof(*param.fp_mdt_uuid));
2099 param.fp_mdt_uuid = tmp;
2101 param.fp_exclude_obd = !!neg_opt;
2102 param.fp_num_alloc_obds += len;
2103 tmp = realloc(param.fp_obd_uuid,
2104 param.fp_num_alloc_obds *
2105 sizeof(*param.fp_obd_uuid));
2111 param.fp_obd_uuid = tmp;
2113 for (token = buf; token && *token; token = next) {
2114 struct obd_uuid *puuid;
2117 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2120 ¶m.fp_obd_uuid[param.fp_num_obds++];
2122 p = strchr(token, ',');
2129 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2134 strncpy(puuid->uuid, token,
2135 sizeof(puuid->uuid));
2143 param.fp_zero_end = 1;
2148 if (optarg[0] == '+') {
2149 param.fp_size_sign = -1;
2151 } else if (optarg[0] == '-') {
2152 param.fp_size_sign = 1;
2156 ret = llapi_parse_size(optarg, ¶m.fp_size,
2157 ¶m.fp_size_units, 0);
2159 fprintf(stderr, "error: bad file size '%s'\n",
2163 param.fp_check_size = 1;
2164 param.fp_exclude_size = !!neg_opt;
2167 if (optarg[0] == '+') {
2168 param.fp_stripe_size_sign = -1;
2170 } else if (optarg[0] == '-') {
2171 param.fp_stripe_size_sign = 1;
2175 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2176 ¶m.fp_stripe_size_units, 0);
2178 fprintf(stderr, "error: bad stripe_size '%s'\n",
2182 param.fp_check_stripe_size = 1;
2183 param.fp_exclude_stripe_size = !!neg_opt;
2186 param.fp_exclude_type = !!neg_opt;
2187 switch (optarg[0]) {
2189 param.fp_type = S_IFBLK;
2192 param.fp_type = S_IFCHR;
2195 param.fp_type = S_IFDIR;
2198 param.fp_type = S_IFREG;
2201 param.fp_type = S_IFLNK;
2204 param.fp_type = S_IFIFO;
2207 param.fp_type = S_IFSOCK;
2210 fprintf(stderr, "error: %s: bad type '%s'\n",
2222 if (pathstart == -1) {
2223 fprintf(stderr, "error: %s: no filename|pathname\n",
2227 } else if (pathend == -1) {
2233 rc = llapi_find(argv[pathstart], ¶m);
2234 if (rc != 0 && ret == 0)
2236 } while (++pathstart < pathend);
2239 fprintf(stderr, "error: %s failed for %s.\n",
2240 argv[0], argv[optind - 1]);
2242 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2243 free(param.fp_obd_uuid);
2245 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2246 free(param.fp_mdt_uuid);
2251 static int lfs_getstripe_internal(int argc, char **argv,
2252 struct find_param *param)
2254 struct option long_opts[] = {
2255 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2256 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2257 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2258 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2259 /* This formerly implied "stripe-count", but was explicitly
2260 * made "stripe-count" for consistency with other options,
2261 * and to separate it from "mdt-count" when DNE arrives. */
2262 {"count", no_argument, 0, 'c'},
2264 {"stripe-count", no_argument, 0, 'c'},
2265 {"stripe_count", no_argument, 0, 'c'},
2266 {"directory", no_argument, 0, 'd'},
2267 {"default", no_argument, 0, 'D'},
2268 {"component-end", required_argument, 0, 'E'},
2269 {"fid", no_argument, 0, 'F'},
2270 {"generation", no_argument, 0, 'g'},
2271 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2272 /* This formerly implied "stripe-index", but was explicitly
2273 * made "stripe-index" for consistency with other options,
2274 * and to separate it from "mdt-index" when DNE arrives. */
2275 {"index", no_argument, 0, 'i'},
2277 {"stripe-index", no_argument, 0, 'i'},
2278 {"stripe_index", no_argument, 0, 'i'},
2279 {"component-id", required_argument, 0, 'I'},
2280 {"layout", no_argument, 0, 'L'},
2281 {"mdt", no_argument, 0, 'm'},
2282 {"mdt-index", no_argument, 0, 'm'},
2283 {"mdt_index", no_argument, 0, 'm'},
2284 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2285 {"mdt-index", no_argument, 0, 'M'},
2286 {"mdt_index", no_argument, 0, 'M'},
2288 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2289 /* This formerly implied "stripe-index", but was confusing
2290 * with "file offset" (which will eventually be needed for
2291 * with different layouts by offset), so deprecate it. */
2292 {"offset", no_argument, 0, 'o'},
2294 {"obd", required_argument, 0, 'O'},
2295 {"ost", required_argument, 0, 'O'},
2296 {"pool", no_argument, 0, 'p'},
2297 {"quiet", no_argument, 0, 'q'},
2298 {"recursive", no_argument, 0, 'r'},
2299 {"raw", no_argument, 0, 'R'},
2300 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2301 /* This formerly implied "--stripe-size", but was confusing
2302 * with "lfs find --size|-s", which means "file size", so use
2303 * the consistent "--stripe-size|-S" for all commands. */
2304 {"size", no_argument, 0, 's'},
2306 {"stripe-size", no_argument, 0, 'S'},
2307 {"stripe_size", no_argument, 0, 'S'},
2308 {"verbose", no_argument, 0, 'v'},
2314 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2315 long_opts, NULL)) != -1) {
2318 if (param->fp_obd_uuid) {
2320 "error: %s: only one obduuid allowed",
2324 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2329 case LFS_COMP_COUNT_OPT:
2330 param->fp_verbose |= VERBOSE_COMP_COUNT;
2331 param->fp_max_depth = 0;
2333 case LFS_COMP_FLAGS_OPT:
2334 if (optarg != NULL) {
2335 rc = comp_name2flags(¶m->fp_comp_flags,
2338 param->fp_verbose |=
2340 param->fp_max_depth = 0;
2343 param->fp_check_comp_flags = 1;
2346 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2347 param->fp_max_depth = 0;
2350 case LFS_COMP_START_OPT:
2351 if (optarg != NULL) {
2353 if (tmp[0] == '+') {
2354 param->fp_comp_start_sign = 1;
2356 } else if (tmp[0] == '-') {
2357 param->fp_comp_start_sign = -1;
2360 rc = llapi_parse_size(tmp,
2361 ¶m->fp_comp_start,
2362 ¶m->fp_comp_start_units, 0);
2364 param->fp_verbose |= VERBOSE_COMP_START;
2365 param->fp_max_depth = 0;
2368 param->fp_check_comp_start = 1;
2371 param->fp_verbose |= VERBOSE_COMP_START;
2372 param->fp_max_depth = 0;
2376 param->fp_max_depth = 0;
2379 param->fp_get_default_lmv = 1;
2382 if (optarg != NULL) {
2384 if (tmp[0] == '+') {
2385 param->fp_comp_end_sign = 1;
2387 } else if (tmp[0] == '-') {
2388 param->fp_comp_end_sign = -1;
2391 rc = llapi_parse_size(tmp,
2392 ¶m->fp_comp_end,
2393 ¶m->fp_comp_end_units, 0);
2395 param->fp_verbose |= VERBOSE_COMP_END;
2396 param->fp_max_depth = 0;
2399 param->fp_check_comp_end = 1;
2402 param->fp_verbose |= VERBOSE_COMP_END;
2403 param->fp_max_depth = 0;
2407 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2408 param->fp_verbose |= VERBOSE_DFID;
2409 param->fp_max_depth = 0;
2413 param->fp_recursive = 1;
2416 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2419 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2420 if (strcmp(argv[optind - 1], "--count") == 0)
2421 fprintf(stderr, "warning: '--count' deprecated,"
2422 " use '--stripe-count' instead\n");
2424 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2425 param->fp_verbose |= VERBOSE_COUNT;
2426 param->fp_max_depth = 0;
2429 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2431 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2432 fprintf(stderr, "warning: '--size|-s' deprecated, "
2433 "use '--stripe-size|-S' instead\n");
2435 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2437 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2438 param->fp_verbose |= VERBOSE_SIZE;
2439 param->fp_max_depth = 0;
2442 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2444 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2445 "use '--stripe-index|-i' instead\n");
2448 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2449 if (strcmp(argv[optind - 1], "--index") == 0)
2450 fprintf(stderr, "warning: '--index' deprecated"
2451 ", use '--stripe-index' instead\n");
2453 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2454 param->fp_verbose |= VERBOSE_OFFSET;
2455 param->fp_max_depth = 0;
2459 if (optarg != NULL) {
2460 param->fp_comp_id = strtoul(optarg, &end, 0);
2462 param->fp_verbose |= VERBOSE_COMP_ID;
2463 param->fp_max_depth = 0;
2466 param->fp_check_comp_id = 1;
2469 param->fp_max_depth = 0;
2470 param->fp_verbose |= VERBOSE_COMP_ID;
2474 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2475 param->fp_verbose |= VERBOSE_POOL;
2476 param->fp_max_depth = 0;
2480 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2481 param->fp_verbose |= VERBOSE_GENERATION;
2482 param->fp_max_depth = 0;
2486 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2487 param->fp_verbose |= VERBOSE_LAYOUT;
2488 param->fp_max_depth = 0;
2491 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2493 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2494 fprintf(stderr, "warning: '-M' deprecated"
2495 ", use '-m' instead\n");
2499 if (!(param->fp_verbose & VERBOSE_DETAIL))
2500 param->fp_max_depth = 0;
2501 param->fp_verbose |= VERBOSE_MDTINDEX;
2514 if (param->fp_recursive)
2515 param->fp_max_depth = -1;
2516 else if (param->fp_verbose & VERBOSE_DETAIL)
2517 param->fp_max_depth = 1;
2519 if (!param->fp_verbose)
2520 param->fp_verbose = VERBOSE_DEFAULT;
2521 if (param->fp_quiet)
2522 param->fp_verbose = VERBOSE_OBJID;
2525 rc = llapi_getstripe(argv[optind], param);
2526 } while (++optind < argc && !rc);
2529 fprintf(stderr, "error: %s failed for %s.\n",
2530 argv[0], argv[optind - 1]);
2534 static int lfs_tgts(int argc, char **argv)
2536 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2537 struct find_param param;
2538 int index = 0, rc=0;
2543 if (argc == 2 && !realpath(argv[1], path)) {
2545 fprintf(stderr, "error: invalid path '%s': %s\n",
2546 argv[1], strerror(-rc));
2550 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2551 /* Check if we have a mount point */
2552 if (mntdir[0] == '\0')
2555 memset(¶m, 0, sizeof(param));
2556 if (!strcmp(argv[0], "mdts"))
2557 param.fp_get_lmv = 1;
2559 rc = llapi_ostlist(mntdir, ¶m);
2561 fprintf(stderr, "error: %s: failed on %s\n",
2564 if (path[0] != '\0')
2566 memset(mntdir, 0, PATH_MAX);
2572 static int lfs_getstripe(int argc, char **argv)
2574 struct find_param param = { 0 };
2576 param.fp_max_depth = 1;
2577 return lfs_getstripe_internal(argc, argv, ¶m);
2581 static int lfs_getdirstripe(int argc, char **argv)
2583 struct find_param param = { 0 };
2584 struct option long_opts[] = {
2585 {"mdt-count", no_argument, 0, 'c'},
2586 {"mdt-index", no_argument, 0, 'i'},
2587 {"recursive", no_argument, 0, 'r'},
2588 {"mdt-hash", no_argument, 0, 't'},
2589 {"default", no_argument, 0, 'D'},
2590 {"obd", required_argument, 0, 'O'},
2595 param.fp_get_lmv = 1;
2597 while ((c = getopt_long(argc, argv, "cirtDO:", long_opts, NULL)) != -1)
2601 if (param.fp_obd_uuid) {
2603 "error: %s: only one obduuid allowed",
2607 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2610 param.fp_verbose |= VERBOSE_COUNT;
2613 param.fp_verbose |= VERBOSE_OFFSET;
2616 param.fp_verbose |= VERBOSE_HASH_TYPE;
2619 param.fp_get_default_lmv = 1;
2622 param.fp_recursive = 1;
2632 if (param.fp_recursive)
2633 param.fp_max_depth = -1;
2635 if (!param.fp_verbose)
2636 param.fp_verbose = VERBOSE_DEFAULT;
2639 rc = llapi_getstripe(argv[optind], ¶m);
2640 } while (++optind < argc && !rc);
2643 fprintf(stderr, "error: %s failed for %s.\n",
2644 argv[0], argv[optind - 1]);
2649 static int lfs_setdirstripe(int argc, char **argv)
2653 unsigned int stripe_offset = -1;
2654 unsigned int stripe_count = 1;
2655 enum lmv_hash_type hash_type;
2658 char *stripe_offset_opt = NULL;
2659 char *stripe_count_opt = NULL;
2660 char *stripe_hash_opt = NULL;
2661 char *mode_opt = NULL;
2662 bool default_stripe = false;
2663 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2664 mode_t previous_mode = 0;
2665 bool delete = false;
2667 struct option long_opts[] = {
2668 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2669 {"count", required_argument, 0, 'c'},
2671 {"mdt-count", required_argument, 0, 'c'},
2672 {"delete", no_argument, 0, 'd'},
2673 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2674 {"index", required_argument, 0, 'i'},
2676 {"mdt-index", required_argument, 0, 'i'},
2677 {"mode", required_argument, 0, 'm'},
2678 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2679 {"hash-type", required_argument, 0, 't'},
2681 {"mdt-hash", required_argument, 0, 't'},
2682 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2683 {"default_stripe", no_argument, 0, 'D'},
2685 {"default", no_argument, 0, 'D'},
2689 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2696 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2697 if (strcmp(argv[optind - 1], "--count") == 0)
2698 fprintf(stderr, "warning: '--count' deprecated"
2699 ", use '--mdt-count' instead\n");
2701 stripe_count_opt = optarg;
2705 default_stripe = true;
2708 default_stripe = true;
2711 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2712 if (strcmp(argv[optind - 1], "--index") == 0)
2713 fprintf(stderr, "warning: '--index' deprecated"
2714 ", use '--mdt-index' instead\n");
2716 stripe_offset_opt = optarg;
2722 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2723 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2724 fprintf(stderr, "warning: '--hash-type' "
2725 "deprecated, use '--mdt-hash' "
2728 stripe_hash_opt = optarg;
2731 fprintf(stderr, "error: %s: option '%s' "
2733 argv[0], argv[optind - 1]);
2738 if (optind == argc) {
2739 fprintf(stderr, "error: %s: missing dirname\n",
2744 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2745 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2750 if (stripe_offset_opt != NULL) {
2751 /* get the stripe offset */
2752 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2754 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2755 argv[0], stripe_offset_opt);
2761 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2762 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2763 " or -i options.\n", argv[0]);
2771 if (mode_opt != NULL) {
2772 mode = strtoul(mode_opt, &end, 8);
2774 fprintf(stderr, "error: %s: bad mode '%s'\n",
2778 previous_mode = umask(0);
2781 if (stripe_hash_opt == NULL) {
2782 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2786 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
2787 if (strcmp(stripe_hash_opt, mdt_hash_name[i]) == 0)
2790 if (i == LMV_HASH_TYPE_MAX) {
2792 "error: %s: bad stripe hash type '%s'\n",
2793 argv[0], stripe_hash_opt);
2800 /* get the stripe count */
2801 if (stripe_count_opt != NULL) {
2802 stripe_count = strtoul(stripe_count_opt, &end, 0);
2804 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2805 argv[0], stripe_count_opt);
2810 dname = argv[optind];
2812 if (default_stripe) {
2813 result = llapi_dir_set_default_lmv_stripe(dname,
2814 stripe_offset, stripe_count,
2817 result = llapi_dir_create_pool(dname, mode,
2819 stripe_count, hash_type,
2824 fprintf(stderr, "error: %s: create stripe dir '%s' "
2825 "failed\n", argv[0], dname);
2828 dname = argv[++optind];
2829 } while (dname != NULL);
2831 if (mode_opt != NULL)
2832 umask(previous_mode);
2838 static int lfs_rmentry(int argc, char **argv)
2845 fprintf(stderr, "error: %s: missing dirname\n",
2851 dname = argv[index];
2852 while (dname != NULL) {
2853 result = llapi_direntry_remove(dname);
2855 fprintf(stderr, "error: %s: remove dir entry '%s' "
2856 "failed\n", argv[0], dname);
2859 dname = argv[++index];
2864 static int lfs_mv(int argc, char **argv)
2866 struct find_param param = {
2873 struct option long_opts[] = {
2874 {"mdt-index", required_argument, 0, 'M'},
2875 {"verbose", no_argument, 0, 'v'},
2879 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2882 param.fp_mdt_index = strtoul(optarg, &end, 0);
2884 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2891 param.fp_verbose = VERBOSE_DETAIL;
2895 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2896 argv[0], argv[optind - 1]);
2901 if (param.fp_mdt_index == -1) {
2902 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2906 if (optind >= argc) {
2907 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2911 param.fp_migrate = 1;
2912 rc = llapi_migrate_mdt(argv[optind], ¶m);
2914 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2915 argv[0], argv[optind], param.fp_mdt_index,
2920 static int lfs_osts(int argc, char **argv)
2922 return lfs_tgts(argc, argv);
2925 static int lfs_mdts(int argc, char **argv)
2927 return lfs_tgts(argc, argv);
2930 #define COOK(value) \
2933 while (value > 1024) { \
2941 #define CDF "%11llu"
2942 #define HDF "%8.1f%c"
2947 MNTDF_INODES = 0x0001,
2948 MNTDF_COOKED = 0x0002,
2949 MNTDF_LAZY = 0x0004,
2950 MNTDF_VERBOSE = 0x0008,
2953 static int showdf(char *mntdir, struct obd_statfs *stat,
2954 char *uuid, enum mntdf_flags flags,
2955 char *type, int index, int rc)
2957 long long avail, used, total;
2959 char *suffix = "KMGTPEZY";
2960 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2961 char tbuf[3 * sizeof(__u64)];
2962 char ubuf[3 * sizeof(__u64)];
2963 char abuf[3 * sizeof(__u64)];
2964 char rbuf[3 * sizeof(__u64)];
2971 if (flags & MNTDF_INODES) {
2972 avail = stat->os_ffree;
2973 used = stat->os_files - stat->os_ffree;
2974 total = stat->os_files;
2976 int shift = flags & MNTDF_COOKED ? 0 : 10;
2978 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2979 used = ((stat->os_blocks - stat->os_bfree) *
2980 stat->os_bsize) >> shift;
2981 total = (stat->os_blocks * stat->os_bsize) >> shift;
2984 if ((used + avail) > 0)
2985 ratio = (double)used / (double)(used + avail);
2987 if (flags & MNTDF_COOKED) {
2991 cook_val = (double)total;
2994 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2997 snprintf(tbuf, sizeof(tbuf), CDF, total);
2999 cook_val = (double)used;
3002 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3005 snprintf(ubuf, sizeof(ubuf), CDF, used);
3007 cook_val = (double)avail;
3010 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3013 snprintf(abuf, sizeof(abuf), CDF, avail);
3015 snprintf(tbuf, sizeof(tbuf), CDF, total);
3016 snprintf(ubuf, sizeof(tbuf), CDF, used);
3017 snprintf(abuf, sizeof(tbuf), CDF, avail);
3020 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3021 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3022 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3024 printf("[%s:%d]", type, index);
3026 if (stat->os_state) {
3028 * Each character represents the matching
3031 const char state_names[] = "DRSI";
3036 for (i = 0, state = stat->os_state;
3037 state && i < sizeof(state_names); i++) {
3038 if (!(state & (1 << i)))
3040 printf("%c", state_names[i]);
3048 printf(UUF": inactive device\n", uuid);
3051 printf(UUF": %s\n", uuid, strerror(-rc));
3058 struct ll_stat_type {
3063 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3065 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3066 struct obd_uuid uuid_buf;
3067 char *poolname = NULL;
3068 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3069 { LL_STATFS_LOV, "OST" },
3071 struct ll_stat_type *tp;
3072 __u64 ost_ffree = 0;
3080 poolname = strchr(pool, '.');
3081 if (poolname != NULL) {
3082 if (strncmp(fsname, pool, strlen(fsname))) {
3083 fprintf(stderr, "filesystem name incorrect\n");
3091 fd = open(mntdir, O_RDONLY);
3094 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3099 if (flags & MNTDF_INODES)
3100 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3101 "UUID", "Inodes", "IUsed", "IFree",
3102 "IUse%", "Mounted on");
3104 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3105 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3106 "Used", "Available", "Use%", "Mounted on");
3108 for (tp = types; tp->st_name != NULL; tp++) {
3109 for (index = 0; ; index++) {
3110 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3111 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3112 type = flags & MNTDF_LAZY ?
3113 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3114 rc2 = llapi_obd_fstatfs(fd, type, index,
3115 &stat_buf, &uuid_buf);
3120 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3121 if (!(flags & MNTDF_VERBOSE))
3123 } else if (rc2 < 0 && rc == 0) {
3127 if (poolname && tp->st_op == LL_STATFS_LOV &&
3128 llapi_search_ost(fsname, poolname,
3129 obd_uuid2str(&uuid_buf)) != 1)
3132 /* the llapi_obd_statfs() call may have returned with
3133 * an error, but if it filled in uuid_buf we will at
3134 * lease use that to print out a message for that OBD.
3135 * If we didn't get anything in the uuid_buf, then fill
3136 * it in so that we can print an error message. */
3137 if (uuid_buf.uuid[0] == '\0')
3138 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3139 "%s%04x", tp->st_name, index);
3140 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3141 flags, tp->st_name, index, rc2);
3144 if (tp->st_op == LL_STATFS_LMV) {
3145 sum.os_ffree += stat_buf.os_ffree;
3146 sum.os_files += stat_buf.os_files;
3147 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3148 sum.os_blocks += stat_buf.os_blocks *
3150 sum.os_bfree += stat_buf.os_bfree *
3152 sum.os_bavail += stat_buf.os_bavail *
3154 ost_ffree += stat_buf.os_ffree;
3162 /* If we don't have as many objects free on the OST as inodes
3163 * on the MDS, we reduce the total number of inodes to
3164 * compensate, so that the "inodes in use" number is correct.
3165 * Matches ll_statfs_internal() so the results are consistent. */
3166 if (ost_ffree < sum.os_ffree) {
3167 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3168 sum.os_ffree = ost_ffree;
3171 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3177 static int lfs_df(int argc, char **argv)
3179 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3180 enum mntdf_flags flags = 0;
3181 int c, rc = 0, index = 0;
3182 char fsname[PATH_MAX] = "", *pool_name = NULL;
3183 struct option long_opts[] = {
3184 {"human-readable", 0, 0, 'h'},
3185 {"inodes", 0, 0, 'i'},
3186 {"lazy", 0, 0, 'l'},
3187 {"pool", required_argument, 0, 'p'},
3188 {"verbose", 0, 0, 'v'},
3192 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3195 flags |= MNTDF_COOKED;
3198 flags |= MNTDF_INODES;
3201 flags |= MNTDF_LAZY;
3207 flags |= MNTDF_VERBOSE;
3213 if (optind < argc && !realpath(argv[optind], path)) {
3215 fprintf(stderr, "error: invalid path '%s': %s\n",
3216 argv[optind], strerror(-rc));
3220 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3221 /* Check if we have a mount point */
3222 if (mntdir[0] == '\0')
3225 rc = mntdf(mntdir, fsname, pool_name, flags);
3226 if (rc || path[0] != '\0')
3228 fsname[0] = '\0'; /* avoid matching in next loop */
3229 mntdir[0] = '\0'; /* avoid matching in next loop */
3235 static int lfs_getname(int argc, char **argv)
3237 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3238 int rc = 0, index = 0, c;
3239 char buf[sizeof(struct obd_uuid)];
3241 while ((c = getopt(argc, argv, "h")) != -1)
3244 if (optind == argc) { /* no paths specified, get all paths. */
3245 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3246 rc = llapi_getname(mntdir, buf, sizeof(buf));
3249 "cannot get name for `%s': %s\n",
3250 mntdir, strerror(-rc));
3254 printf("%s %s\n", buf, mntdir);
3256 path[0] = fsname[0] = mntdir[0] = 0;
3258 } else { /* paths specified, only attempt to search these. */
3259 for (; optind < argc; optind++) {
3260 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3263 "cannot get name for `%s': %s\n",
3264 argv[optind], strerror(-rc));
3268 printf("%s %s\n", buf, argv[optind]);
3274 static int lfs_check(int argc, char **argv)
3277 char mntdir[PATH_MAX] = {'\0'};
3286 obd_types[0] = obd_type1;
3287 obd_types[1] = obd_type2;
3289 if (strcmp(argv[1], "osts") == 0) {
3290 strcpy(obd_types[0], "osc");
3291 } else if (strcmp(argv[1], "mds") == 0) {
3292 strcpy(obd_types[0], "mdc");
3293 } else if (strcmp(argv[1], "servers") == 0) {
3295 strcpy(obd_types[0], "osc");
3296 strcpy(obd_types[1], "mdc");
3298 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3303 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3304 if (rc < 0 || mntdir[0] == '\0') {
3305 fprintf(stderr, "No suitable Lustre mount found\n");
3309 rc = llapi_target_check(num_types, obd_types, mntdir);
3311 fprintf(stderr, "error: %s: %s status failed\n",
3318 #ifdef HAVE_SYS_QUOTA_H
3319 #define ARG2INT(nr, str, msg) \
3322 nr = strtol(str, &endp, 0); \
3324 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3329 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3331 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3332 * returns the value or ULONG_MAX on integer overflow or incorrect format
3334 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3335 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3336 * 3. empty integer value is interpreted as 0
3338 static unsigned long str2sec(const char* timestr)
3340 const char spec[] = "smhdw";
3341 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3342 unsigned long val = 0;
3345 if (strpbrk(timestr, spec) == NULL) {
3346 /* no specifiers inside the time string,
3347 should treat it as an integer value */
3348 val = strtoul(timestr, &tail, 10);
3349 return *tail ? ULONG_MAX : val;
3352 /* format string is XXwXXdXXhXXmXXs */
3358 v = strtoul(timestr, &tail, 10);
3359 if (v == ULONG_MAX || *tail == '\0')
3360 /* value too large (ULONG_MAX or more)
3361 or missing specifier */
3364 ptr = strchr(spec, *tail);
3366 /* unknown specifier */
3371 /* check if product will overflow the type */
3372 if (!(v < ULONG_MAX / mult[ind]))
3375 ADD_OVERFLOW(val, mult[ind] * v);
3376 if (val == ULONG_MAX)
3388 #define ARG2ULL(nr, str, def_units) \
3390 unsigned long long limit, units = def_units; \
3393 rc = llapi_parse_size(str, &limit, &units, 1); \
3395 fprintf(stderr, "error: bad limit value %s\n", str); \
3401 static inline int has_times_option(int argc, char **argv)
3405 for (i = 1; i < argc; i++)
3406 if (!strcmp(argv[i], "-t"))
3412 int lfs_setquota_times(int argc, char **argv)
3415 struct if_quotactl qctl;
3416 char *mnt, *obd_type = (char *)qctl.obd_type;
3417 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3418 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3419 struct option long_opts[] = {
3420 {"block-grace", required_argument, 0, 'b'},
3421 {"group", no_argument, 0, 'g'},
3422 {"inode-grace", required_argument, 0, 'i'},
3423 {"times", no_argument, 0, 't'},
3424 {"user", no_argument, 0, 'u'},
3428 memset(&qctl, 0, sizeof(qctl));
3429 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3430 qctl.qc_type = UGQUOTA;
3432 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
3436 if (qctl.qc_type != UGQUOTA) {
3437 fprintf(stderr, "error: -u and -g can't be used "
3438 "more than once\n");
3441 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
3444 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3445 fprintf(stderr, "error: bad block-grace: %s\n",
3449 dqb->dqb_valid |= QIF_BTIME;
3452 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3453 fprintf(stderr, "error: bad inode-grace: %s\n",
3457 dqb->dqb_valid |= QIF_ITIME;
3459 case 't': /* Yes, of course! */
3461 default: /* getopt prints error message for us when opterr != 0 */
3466 if (qctl.qc_type == UGQUOTA) {
3467 fprintf(stderr, "error: neither -u nor -g specified\n");
3471 if (optind != argc - 1) {
3472 fprintf(stderr, "error: unexpected parameters encountered\n");
3477 rc = llapi_quotactl(mnt, &qctl);
3480 fprintf(stderr, "%s %s ", obd_type,
3481 obd_uuid2str(&qctl.obd_uuid));
3482 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3489 #define BSLIMIT (1 << 0)
3490 #define BHLIMIT (1 << 1)
3491 #define ISLIMIT (1 << 2)
3492 #define IHLIMIT (1 << 3)
3494 int lfs_setquota(int argc, char **argv)
3497 struct if_quotactl qctl;
3498 char *mnt, *obd_type = (char *)qctl.obd_type;
3499 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3500 struct option long_opts[] = {
3501 {"block-softlimit", required_argument, 0, 'b'},
3502 {"block-hardlimit", required_argument, 0, 'B'},
3503 {"group", required_argument, 0, 'g'},
3504 {"inode-softlimit", required_argument, 0, 'i'},
3505 {"inode-hardlimit", required_argument, 0, 'I'},
3506 {"user", required_argument, 0, 'u'},
3509 unsigned limit_mask = 0;
3512 if (has_times_option(argc, argv))
3513 return lfs_setquota_times(argc, argv);
3515 memset(&qctl, 0, sizeof(qctl));
3516 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3517 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
3518 * so it can be used as a marker that qc_type
3519 * isn't reinitialized from command line */
3521 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
3525 if (qctl.qc_type != UGQUOTA) {
3526 fprintf(stderr, "error: -u and -g can't be used"
3527 " more than once\n");
3530 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
3531 rc = name2id(&qctl.qc_id, optarg,
3532 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3534 qctl.qc_id = strtoul(optarg, &endptr, 10);
3535 if (*endptr != '\0') {
3536 fprintf(stderr, "error: can't find id "
3537 "for name %s\n", optarg);
3543 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3544 dqb->dqb_bsoftlimit >>= 10;
3545 limit_mask |= BSLIMIT;
3546 if (dqb->dqb_bsoftlimit &&
3547 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3548 fprintf(stderr, "warning: block softlimit is "
3549 "smaller than the miminal qunit size, "
3550 "please see the help of setquota or "
3551 "Lustre manual for details.\n");
3554 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3555 dqb->dqb_bhardlimit >>= 10;
3556 limit_mask |= BHLIMIT;
3557 if (dqb->dqb_bhardlimit &&
3558 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3559 fprintf(stderr, "warning: block hardlimit is "
3560 "smaller than the miminal qunit size, "
3561 "please see the help of setquota or "
3562 "Lustre manual for details.\n");
3565 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3566 limit_mask |= ISLIMIT;
3567 if (dqb->dqb_isoftlimit &&
3568 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3569 fprintf(stderr, "warning: inode softlimit is "
3570 "smaller than the miminal qunit size, "
3571 "please see the help of setquota or "
3572 "Lustre manual for details.\n");
3575 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3576 limit_mask |= IHLIMIT;
3577 if (dqb->dqb_ihardlimit &&
3578 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3579 fprintf(stderr, "warning: inode hardlimit is "
3580 "smaller than the miminal qunit size, "
3581 "please see the help of setquota or "
3582 "Lustre manual for details.\n");
3584 default: /* getopt prints error message for us when opterr != 0 */
3589 if (qctl.qc_type == UGQUOTA) {
3590 fprintf(stderr, "error: neither -u nor -g was specified\n");
3594 if (limit_mask == 0) {
3595 fprintf(stderr, "error: at least one limit must be specified\n");
3599 if (optind != argc - 1) {
3600 fprintf(stderr, "error: unexpected parameters encountered\n");
3606 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3607 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3608 /* sigh, we can't just set blimits/ilimits */
3609 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3610 .qc_type = qctl.qc_type,
3611 .qc_id = qctl.qc_id};
3613 rc = llapi_quotactl(mnt, &tmp_qctl);
3615 fprintf(stderr, "error: setquota failed while retrieving"
3616 " current quota settings (%s)\n",
3621 if (!(limit_mask & BHLIMIT))
3622 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3623 if (!(limit_mask & BSLIMIT))
3624 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3625 if (!(limit_mask & IHLIMIT))
3626 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3627 if (!(limit_mask & ISLIMIT))
3628 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3630 /* Keep grace times if we have got no softlimit arguments */
3631 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3632 dqb->dqb_valid |= QIF_BTIME;
3633 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3636 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3637 dqb->dqb_valid |= QIF_ITIME;
3638 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3642 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3643 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3645 rc = llapi_quotactl(mnt, &qctl);
3648 fprintf(stderr, "%s %s ", obd_type,
3649 obd_uuid2str(&qctl.obd_uuid));
3650 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3657 static inline char *type2name(int check_type)
3659 if (check_type == USRQUOTA)
3661 else if (check_type == GRPQUOTA)
3667 /* Converts seconds value into format string
3668 * result is returned in buf
3670 * 1. result is in descenting order: 1w2d3h4m5s
3671 * 2. zero fields are not filled (except for p. 3): 5d1s
3672 * 3. zero seconds value is presented as "0s"
3674 static char * __sec2str(time_t seconds, char *buf)
3676 const char spec[] = "smhdw";
3677 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3682 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3683 c = seconds / mult[i];
3685 if (c > 0 || (i == 0 && buf == tail))
3686 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3694 static void sec2str(time_t seconds, char *buf, int rc)
3701 tail = __sec2str(seconds, tail);
3703 if (rc && tail - buf < 39) {
3709 static void diff2str(time_t seconds, char *buf, time_t now)
3715 if (seconds <= now) {
3716 strcpy(buf, "none");
3719 __sec2str(seconds - now, buf);
3722 static void print_quota_title(char *name, struct if_quotactl *qctl,
3723 bool human_readable)
3725 printf("Disk quotas for %s %s (%cid %u):\n",
3726 type2name(qctl->qc_type), name,
3727 *type2name(qctl->qc_type), qctl->qc_id);
3728 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3729 "Filesystem", human_readable ? "used" : "kbytes",
3730 "quota", "limit", "grace",
3731 "files", "quota", "limit", "grace");
3734 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3737 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3740 snprintf(buf, buflen, "%5.4gP",
3741 (double)num / ((__u64)1 << 40));
3743 snprintf(buf, buflen, "%5.4gT",
3744 (double)num / (1 << 30));
3746 snprintf(buf, buflen, "%5.4gG",
3747 (double)num / (1 << 20));
3749 snprintf(buf, buflen, "%5.4gM",
3750 (double)num / (1 << 10));
3752 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3756 #define STRBUF_LEN 32
3757 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3764 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3765 int bover = 0, iover = 0;
3766 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3767 char numbuf[3][STRBUF_LEN];
3769 char strbuf[STRBUF_LEN];
3771 if (dqb->dqb_bhardlimit &&
3772 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3774 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3775 if (dqb->dqb_btime > now) {
3782 if (dqb->dqb_ihardlimit &&
3783 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3785 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3786 if (dqb->dqb_itime > now) {
3794 if (strlen(mnt) > 15)
3795 printf("%s\n%15s", mnt, "");
3797 printf("%15s", mnt);
3800 diff2str(dqb->dqb_btime, timebuf, now);
3802 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3803 strbuf, sizeof(strbuf), h);
3804 if (rc == -EREMOTEIO)
3805 sprintf(numbuf[0], "%s*", strbuf);
3807 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3808 "%s" : "[%s]", strbuf);
3810 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3811 if (type == QC_GENERAL)
3812 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3813 "%s" : "[%s]", strbuf);
3815 sprintf(numbuf[1], "%s", "-");
3817 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3818 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3819 "%s" : "[%s]", strbuf);
3821 printf(" %7s%c %6s %7s %7s",
3822 numbuf[0], bover ? '*' : ' ', numbuf[1],
3823 numbuf[2], bover > 1 ? timebuf : "-");
3826 diff2str(dqb->dqb_itime, timebuf, now);
3828 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3829 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3831 if (type == QC_GENERAL)
3832 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3834 (uintmax_t)dqb->dqb_isoftlimit);
3836 sprintf(numbuf[1], "%s", "-");
3838 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3839 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3841 if (type != QC_OSTIDX)
3842 printf(" %7s%c %6s %7s %7s",
3843 numbuf[0], iover ? '*' : ' ', numbuf[1],
3844 numbuf[2], iover > 1 ? timebuf : "-");
3846 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3849 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3850 qctl->qc_cmd == Q_GETOINFO) {
3854 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3855 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3856 printf("Block grace time: %s; Inode grace time: %s\n",
3857 bgtimebuf, igtimebuf);
3861 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3862 bool h, __u64 *total)
3864 int rc = 0, rc1 = 0, count = 0;
3865 __u32 valid = qctl->qc_valid;
3867 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3869 fprintf(stderr, "can not get %s count: %s\n",
3870 is_mdt ? "mdt": "ost", strerror(-rc));
3874 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3875 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3876 rc = llapi_quotactl(mnt, qctl);
3878 /* It is remote client case. */
3879 if (-rc == EOPNOTSUPP) {
3886 fprintf(stderr, "quotactl %s%d failed.\n",
3887 is_mdt ? "mdt": "ost", qctl->qc_idx);
3891 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3892 qctl->qc_valid, 0, h);
3893 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3894 qctl->qc_dqblk.dqb_bhardlimit;
3897 qctl->qc_valid = valid;
3901 static int lfs_quota(int argc, char **argv)
3904 char *mnt, *name = NULL;
3905 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3906 .qc_type = UGQUOTA };
3907 char *obd_type = (char *)qctl.obd_type;
3908 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3909 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3910 verbose = 0, pass = 0, quiet = 0, inacc;
3912 __u32 valid = QC_GENERAL, idx = 0;
3913 __u64 total_ialloc = 0, total_balloc = 0;
3914 bool human_readable = false;
3916 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3919 if (qctl.qc_type != UGQUOTA) {
3920 fprintf(stderr, "error: use either -u or -g\n");
3923 qctl.qc_type = USRQUOTA;
3926 if (qctl.qc_type != UGQUOTA) {
3927 fprintf(stderr, "error: use either -u or -g\n");
3930 qctl.qc_type = GRPQUOTA;
3933 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3936 valid = qctl.qc_valid = QC_UUID;
3937 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3940 valid = qctl.qc_valid = QC_MDTIDX;
3941 idx = qctl.qc_idx = atoi(optarg);
3944 valid = qctl.qc_valid = QC_OSTIDX;
3945 idx = qctl.qc_idx = atoi(optarg);
3954 human_readable = true;
3957 fprintf(stderr, "error: %s: option '-%c' "
3958 "unrecognized\n", argv[0], c);
3963 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3964 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3965 optind == argc - 1) {
3967 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3968 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3969 qctl.qc_valid = valid;
3972 qctl.qc_type = USRQUOTA;
3973 qctl.qc_id = geteuid();
3975 qctl.qc_type = GRPQUOTA;
3976 qctl.qc_id = getegid();
3978 rc = id2name(&name, qctl.qc_id,
3979 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3982 /* lfs quota -u username /path/to/lustre/mount */
3983 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3984 /* options should be followed by u/g-name and mntpoint */
3985 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3986 fprintf(stderr, "error: missing quota argument(s)\n");
3990 name = argv[optind++];
3991 rc = name2id(&qctl.qc_id, name,
3992 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3994 qctl.qc_id = strtoul(name, &endptr, 10);
3995 if (*endptr != '\0') {
3996 fprintf(stderr, "error: can't find id for name "
4001 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
4002 fprintf(stderr, "error: missing quota info argument(s)\n");
4008 rc1 = llapi_quotactl(mnt, &qctl);
4012 fprintf(stderr, "%s quotas are not enabled.\n",
4013 qctl.qc_type == USRQUOTA ? "user" : "group");
4016 fprintf(stderr, "Permission denied.\n");
4019 /* We already got error message. */
4022 fprintf(stderr, "Unexpected quotactl error: %s\n",
4027 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4028 print_quota_title(name, &qctl, human_readable);
4030 if (rc1 && *obd_type)
4031 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4033 if (qctl.qc_valid != QC_GENERAL)
4036 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4037 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4038 (QIF_LIMITS|QIF_USAGE));
4040 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4042 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4044 char strbuf[STRBUF_LEN];
4046 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4048 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4050 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4052 printf("Total allocated inode limit: %ju, total "
4053 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4057 if (rc1 || rc2 || rc3 || inacc)
4058 printf("Some errors happened when getting quota info. "
4059 "Some devices may be not working or deactivated. "
4060 "The data in \"[]\" is inaccurate.\n");
4068 #endif /* HAVE_SYS_QUOTA_H! */
4070 static int flushctx_ioctl(char *mp)
4074 fd = open(mp, O_RDONLY);
4076 fprintf(stderr, "flushctx: error open %s: %s\n",
4077 mp, strerror(errno));
4081 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4083 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4084 mp, strerror(errno));
4090 static int lfs_flushctx(int argc, char **argv)
4092 int kdestroy = 0, c;
4093 char mntdir[PATH_MAX] = {'\0'};
4097 while ((c = getopt(argc, argv, "k")) != -1) {
4103 fprintf(stderr, "error: %s: option '-%c' "
4104 "unrecognized\n", argv[0], c);
4110 if ((rc = system("kdestroy > /dev/null")) != 0) {
4111 rc = WEXITSTATUS(rc);
4112 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4116 if (optind >= argc) {
4117 /* flush for all mounted lustre fs. */
4118 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4119 /* Check if we have a mount point */
4120 if (mntdir[0] == '\0')
4123 if (flushctx_ioctl(mntdir))
4126 mntdir[0] = '\0'; /* avoid matching in next loop */
4129 /* flush fs as specified */
4130 while (optind < argc) {
4131 if (flushctx_ioctl(argv[optind++]))
4138 static int lfs_cp(int argc, char **argv)
4140 fprintf(stderr, "remote client copy file(s).\n"
4141 "obsolete, does not support it anymore.\n");
4145 static int lfs_ls(int argc, char **argv)
4147 fprintf(stderr, "remote client lists directory contents.\n"
4148 "obsolete, does not support it anymore.\n");
4152 static int lfs_changelog(int argc, char **argv)
4154 void *changelog_priv;
4155 struct changelog_rec *rec;
4156 long long startrec = 0, endrec = 0;
4158 struct option long_opts[] = {
4159 {"follow", no_argument, 0, 'f'},
4162 char short_opts[] = "f";
4165 while ((rc = getopt_long(argc, argv, short_opts,
4166 long_opts, NULL)) != -1) {
4174 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4175 argv[0], argv[optind - 1]);
4182 mdd = argv[optind++];
4184 startrec = strtoll(argv[optind++], NULL, 10);
4186 endrec = strtoll(argv[optind++], NULL, 10);
4188 rc = llapi_changelog_start(&changelog_priv,
4189 CHANGELOG_FLAG_BLOCK |
4190 CHANGELOG_FLAG_JOBID |
4191 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4194 fprintf(stderr, "Can't start changelog: %s\n",
4195 strerror(errno = -rc));
4199 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4203 if (endrec && rec->cr_index > endrec) {
4204 llapi_changelog_free(&rec);
4207 if (rec->cr_index < startrec) {
4208 llapi_changelog_free(&rec);
4212 secs = rec->cr_time >> 30;
4213 gmtime_r(&secs, &ts);
4214 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4215 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4216 changelog_type2str(rec->cr_type),
4217 ts.tm_hour, ts.tm_min, ts.tm_sec,
4218 (int)(rec->cr_time & ((1<<30) - 1)),
4219 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4220 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4222 if (rec->cr_flags & CLF_JOBID) {
4223 struct changelog_ext_jobid *jid =
4224 changelog_rec_jobid(rec);
4226 if (jid->cr_jobid[0] != '\0')
4227 printf(" j=%s", jid->cr_jobid);
4230 if (rec->cr_namelen)
4231 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4232 rec->cr_namelen, changelog_rec_name(rec));
4234 if (rec->cr_flags & CLF_RENAME) {
4235 struct changelog_ext_rename *rnm =
4236 changelog_rec_rename(rec);
4238 if (!fid_is_zero(&rnm->cr_sfid))
4239 printf(" s="DFID" sp="DFID" %.*s",
4240 PFID(&rnm->cr_sfid),
4241 PFID(&rnm->cr_spfid),
4242 (int)changelog_rec_snamelen(rec),
4243 changelog_rec_sname(rec));
4247 llapi_changelog_free(&rec);
4250 llapi_changelog_fini(&changelog_priv);
4253 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4255 return (rc == 1 ? 0 : rc);
4258 static int lfs_changelog_clear(int argc, char **argv)
4266 endrec = strtoll(argv[3], NULL, 10);
4268 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4271 fprintf(stderr, "%s: record out of range: %llu\n",
4273 else if (rc == -ENOENT)
4274 fprintf(stderr, "%s: no changelog user: %s\n",
4277 fprintf(stderr, "%s error: %s\n", argv[0],
4286 static int lfs_fid2path(int argc, char **argv)
4288 struct option long_opts[] = {
4289 {"cur", no_argument, 0, 'c'},
4290 {"link", required_argument, 0, 'l'},
4291 {"rec", required_argument, 0, 'r'},
4294 char short_opts[] = "cl:r:";
4295 char *device, *fid, *path;
4296 long long recno = -1;
4302 while ((rc = getopt_long(argc, argv, short_opts,
4303 long_opts, NULL)) != -1) {
4309 linkno = strtol(optarg, NULL, 10);
4312 recno = strtoll(optarg, NULL, 10);
4317 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4318 argv[0], argv[optind - 1]);
4326 device = argv[optind++];
4327 path = calloc(1, PATH_MAX);
4329 fprintf(stderr, "error: Not enough memory\n");
4334 while (optind < argc) {
4335 fid = argv[optind++];
4337 lnktmp = (linkno >= 0) ? linkno : 0;
4339 int oldtmp = lnktmp;
4340 long long rectmp = recno;
4342 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4345 fprintf(stderr, "%s: error on FID %s: %s\n",
4346 argv[0], fid, strerror(errno = -rc2));
4353 fprintf(stdout, "%lld ", rectmp);
4354 if (device[0] == '/') {
4355 fprintf(stdout, "%s", device);
4356 if (device[strlen(device) - 1] != '/')
4357 fprintf(stdout, "/");
4358 } else if (path[0] == '\0') {
4359 fprintf(stdout, "/");
4361 fprintf(stdout, "%s\n", path);
4364 /* specified linkno */
4366 if (oldtmp == lnktmp)
4376 static int lfs_path2fid(int argc, char **argv)
4378 struct option long_opts[] = {
4379 {"parents", no_argument, 0, 'p'},
4383 const char short_opts[] = "p";
4384 const char *sep = "";
4387 bool show_parents = false;
4389 while ((rc = getopt_long(argc, argv, short_opts,
4390 long_opts, NULL)) != -1) {
4393 show_parents = true;
4396 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4397 argv[0], argv[optind - 1]);
4402 if (optind > argc - 1)
4404 else if (optind < argc - 1)
4408 for (path = argv + optind; *path != NULL; path++) {
4410 if (!show_parents) {
4411 err = llapi_path2fid(*path, &fid);
4413 printf("%s%s"DFID"\n",
4414 *sep != '\0' ? *path : "", sep,
4417 char name[NAME_MAX + 1];
4418 unsigned int linkno = 0;
4420 while ((err = llapi_path2parent(*path, linkno, &fid,
4421 name, sizeof(name))) == 0) {
4422 if (*sep != '\0' && linkno == 0)
4423 printf("%s%s", *path, sep);
4425 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4430 /* err == -ENODATA is end-of-loop */
4431 if (linkno > 0 && err == -ENODATA) {
4438 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4439 argv[0], show_parents ? "parent " : "", *path,
4451 static int lfs_data_version(int argc, char **argv)
4458 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4463 while ((c = getopt(argc, argv, "nrw")) != -1) {
4466 data_version_flags = 0;
4469 data_version_flags |= LL_DV_RD_FLUSH;
4472 data_version_flags |= LL_DV_WR_FLUSH;
4481 path = argv[optind];
4482 fd = open(path, O_RDONLY);
4484 err(errno, "cannot open file %s", path);
4486 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4488 err(errno, "cannot get version for %s", path);
4490 printf("%ju" "\n", (uintmax_t)data_version);
4496 static int lfs_hsm_state(int argc, char **argv)
4501 struct hsm_user_state hus;
4509 rc = llapi_hsm_state_get(path, &hus);
4511 fprintf(stderr, "can't get hsm state for %s: %s\n",
4512 path, strerror(errno = -rc));
4516 /* Display path name and status flags */
4517 printf("%s: (0x%08x)", path, hus.hus_states);
4519 if (hus.hus_states & HS_RELEASED)
4520 printf(" released");
4521 if (hus.hus_states & HS_EXISTS)
4523 if (hus.hus_states & HS_DIRTY)
4525 if (hus.hus_states & HS_ARCHIVED)
4526 printf(" archived");
4527 /* Display user-settable flags */
4528 if (hus.hus_states & HS_NORELEASE)
4529 printf(" never_release");
4530 if (hus.hus_states & HS_NOARCHIVE)
4531 printf(" never_archive");
4532 if (hus.hus_states & HS_LOST)
4533 printf(" lost_from_hsm");
4535 if (hus.hus_archive_id != 0)
4536 printf(", archive_id:%d", hus.hus_archive_id);
4539 } while (++i < argc);
4544 #define LFS_HSM_SET 0
4545 #define LFS_HSM_CLEAR 1
4548 * Generic function to set or clear HSM flags.
4549 * Used by hsm_set and hsm_clear.
4551 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4553 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4555 struct option long_opts[] = {
4556 {"lost", 0, 0, 'l'},
4557 {"norelease", 0, 0, 'r'},
4558 {"noarchive", 0, 0, 'a'},
4559 {"archived", 0, 0, 'A'},
4560 {"dirty", 0, 0, 'd'},
4561 {"exists", 0, 0, 'e'},
4564 char short_opts[] = "lraAde";
4572 while ((c = getopt_long(argc, argv, short_opts,
4573 long_opts, NULL)) != -1) {
4579 mask |= HS_NOARCHIVE;
4582 mask |= HS_ARCHIVED;
4585 mask |= HS_NORELEASE;
4596 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4597 argv[0], argv[optind - 1]);
4602 /* User should have specified a flag */
4606 while (optind < argc) {
4608 path = argv[optind];
4610 /* If mode == 0, this means we apply the mask. */
4611 if (mode == LFS_HSM_SET)
4612 rc = llapi_hsm_state_set(path, mask, 0, 0);
4614 rc = llapi_hsm_state_set(path, 0, mask, 0);
4617 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4618 path, strerror(errno = -rc));
4627 static int lfs_hsm_action(int argc, char **argv)
4632 struct hsm_current_action hca;
4633 struct hsm_extent he;
4634 enum hsm_user_action hua;
4635 enum hsm_progress_states hps;
4643 rc = llapi_hsm_current_action(path, &hca);
4645 fprintf(stderr, "can't get hsm action for %s: %s\n",
4646 path, strerror(errno = -rc));
4649 he = hca.hca_location;
4650 hua = hca.hca_action;
4651 hps = hca.hca_state;
4653 printf("%s: %s", path, hsm_user_action2name(hua));
4655 /* Skip file without action */
4656 if (hca.hca_action == HUA_NONE) {
4661 printf(" %s ", hsm_progress_state2name(hps));
4663 if ((hps == HPS_RUNNING) &&
4664 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4665 printf("(%llu bytes moved)\n",
4666 (unsigned long long)he.length);
4667 else if ((he.offset + he.length) == LUSTRE_EOF)
4668 printf("(from %llu to EOF)\n",
4669 (unsigned long long)he.offset);
4671 printf("(from %llu to %llu)\n",
4672 (unsigned long long)he.offset,
4673 (unsigned long long)(he.offset + he.length));
4675 } while (++i < argc);
4680 static int lfs_hsm_set(int argc, char **argv)
4682 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4685 static int lfs_hsm_clear(int argc, char **argv)
4687 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4691 * Check file state and return its fid, to be used by lfs_hsm_request().
4693 * \param[in] file Path to file to check
4694 * \param[in,out] fid Pointer to allocated lu_fid struct.
4695 * \param[in,out] last_dev Pointer to last device id used.
4697 * \return 0 on success.
4699 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4705 rc = lstat(file, &st);
4707 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4710 /* Checking for regular file as archiving as posix copytool
4711 * rejects archiving files other than regular files
4713 if (!S_ISREG(st.st_mode)) {
4714 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4717 /* A request should be ... */
4718 if (*last_dev != st.st_dev && *last_dev != 0) {
4719 fprintf(stderr, "All files should be "
4720 "on the same filesystem: %s\n", file);
4723 *last_dev = st.st_dev;
4725 rc = llapi_path2fid(file, fid);
4727 fprintf(stderr, "Cannot read FID of %s: %s\n",
4728 file, strerror(-rc));
4734 /* Fill an HSM HUR item with a given file name.
4736 * If mntpath is set, then the filename is actually a FID, and no
4737 * lookup on the filesystem will be performed.
4739 * \param[in] hur the user request to fill
4740 * \param[in] idx index of the item inside the HUR to fill
4741 * \param[in] mntpath mountpoint of Lustre
4742 * \param[in] fname filename (if mtnpath is NULL)
4743 * or FID (if mntpath is set)
4744 * \param[in] last_dev pointer to last device id used
4746 * \retval 0 on success
4747 * \retval CMD_HELP or a negative errno on error
4749 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4750 const char *mntpath, const char *fname,
4753 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4756 hui->hui_extent.length = -1;
4758 if (mntpath != NULL) {
4761 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4765 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4770 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4774 hur->hur_request.hr_itemcount++;
4779 static int lfs_hsm_request(int argc, char **argv, int action)
4781 struct option long_opts[] = {
4782 {"filelist", 1, 0, 'l'},
4783 {"data", 1, 0, 'D'},
4784 {"archive", 1, 0, 'a'},
4785 {"mntpath", 1, 0, 'm'},
4789 char short_opts[] = "l:D:a:m:";
4790 struct hsm_user_request *hur, *oldhur;
4795 char *filelist = NULL;
4796 char fullpath[PATH_MAX];
4797 char *opaque = NULL;
4801 int nbfile_alloc = 0;
4802 char *some_file = NULL;
4803 char *mntpath = NULL;
4809 while ((c = getopt_long(argc, argv, short_opts,
4810 long_opts, NULL)) != -1) {
4819 if (action != HUA_ARCHIVE &&
4820 action != HUA_REMOVE) {
4822 "error: -a is supported only "
4823 "when archiving or removing\n");
4826 archive_id = atoi(optarg);
4829 if (some_file == NULL) {
4831 some_file = strdup(optarg);
4837 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4838 argv[0], argv[optind - 1]);
4843 /* All remaining args are files, so we have at least nbfile */
4844 nbfile = argc - optind;
4846 if ((nbfile == 0) && (filelist == NULL))
4850 opaque_len = strlen(opaque);
4852 /* Alloc the request structure with enough place to store all files
4853 * from command line. */
4854 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4856 fprintf(stderr, "Cannot create the request: %s\n",
4860 nbfile_alloc = nbfile;
4862 hur->hur_request.hr_action = action;
4863 hur->hur_request.hr_archive_id = archive_id;
4864 hur->hur_request.hr_flags = 0;
4866 /* All remaining args are files, add them */
4867 if (nbfile != 0 && some_file == NULL)
4868 some_file = strdup(argv[optind]);
4870 for (i = 0; i < nbfile; i++) {
4871 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4877 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4879 /* If a filelist was specified, read the filelist from it. */
4880 if (filelist != NULL) {
4881 fp = fopen(filelist, "r");
4883 fprintf(stderr, "Cannot read the file list %s: %s\n",
4884 filelist, strerror(errno));
4889 while ((rc = getline(&line, &len, fp)) != -1) {
4890 /* If allocated buffer was too small, get something
4892 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4895 nbfile_alloc = nbfile_alloc * 2 + 1;
4897 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4900 fprintf(stderr, "hsm: cannot allocate "
4901 "the request: %s\n",
4908 size = hur_len(oldhur);
4910 fprintf(stderr, "hsm: cannot allocate "
4911 "%u files + %u bytes data\n",
4912 oldhur->hur_request.hr_itemcount,
4913 oldhur->hur_request.hr_data_len);
4920 memcpy(hur, oldhur, size);
4925 if (line[strlen(line) - 1] == '\n')
4926 line[strlen(line) - 1] = '\0';
4928 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4929 mntpath, line, &last_dev);
4935 if (some_file == NULL) {
4945 /* If a --data was used, add it to the request */
4946 hur->hur_request.hr_data_len = opaque_len;
4948 memcpy(hur_data(hur), opaque, opaque_len);
4950 /* Send the HSM request */
4951 if (realpath(some_file, fullpath) == NULL) {
4952 fprintf(stderr, "Could not find path '%s': %s\n",
4953 some_file, strerror(errno));
4955 rc = llapi_hsm_request(fullpath, hur);
4957 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4958 some_file, strerror(-rc));
4968 static int lfs_hsm_archive(int argc, char **argv)
4970 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4973 static int lfs_hsm_restore(int argc, char **argv)
4975 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4978 static int lfs_hsm_release(int argc, char **argv)
4980 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4983 static int lfs_hsm_remove(int argc, char **argv)
4985 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4988 static int lfs_hsm_cancel(int argc, char **argv)
4990 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4993 static int lfs_swap_layouts(int argc, char **argv)
4998 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4999 SWAP_LAYOUTS_KEEP_MTIME |
5000 SWAP_LAYOUTS_KEEP_ATIME);
5003 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5005 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5007 enum lu_ladvise_type advice;
5010 advice < ARRAY_SIZE(ladvise_names); advice++) {
5011 if (ladvise_names[advice] == NULL)
5013 if (strcmp(string, ladvise_names[advice]) == 0)
5017 return LU_LADVISE_INVALID;
5020 static int lfs_ladvise(int argc, char **argv)
5022 struct option long_opts[] = {
5023 {"advice", required_argument, 0, 'a'},
5024 {"background", no_argument, 0, 'b'},
5025 {"end", required_argument, 0, 'e'},
5026 {"start", required_argument, 0, 's'},
5027 {"length", required_argument, 0, 'l'},
5030 char short_opts[] = "a:be:l:s:";
5035 struct llapi_lu_ladvise advice;
5036 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5037 unsigned long long start = 0;
5038 unsigned long long end = LUSTRE_EOF;
5039 unsigned long long length = 0;
5040 unsigned long long size_units;
5041 unsigned long long flags = 0;
5044 while ((c = getopt_long(argc, argv, short_opts,
5045 long_opts, NULL)) != -1) {
5048 advice_type = lfs_get_ladvice(optarg);
5049 if (advice_type == LU_LADVISE_INVALID) {
5050 fprintf(stderr, "%s: invalid advice type "
5051 "'%s'\n", argv[0], optarg);
5052 fprintf(stderr, "Valid types:");
5054 for (advice_type = 0;
5055 advice_type < ARRAY_SIZE(ladvise_names);
5057 if (ladvise_names[advice_type] == NULL)
5059 fprintf(stderr, " %s",
5060 ladvise_names[advice_type]);
5062 fprintf(stderr, "\n");
5072 rc = llapi_parse_size(optarg, &end,
5075 fprintf(stderr, "%s: bad end offset '%s'\n",
5082 rc = llapi_parse_size(optarg, &start,
5085 fprintf(stderr, "%s: bad start offset "
5086 "'%s'\n", argv[0], optarg);
5092 rc = llapi_parse_size(optarg, &length,
5095 fprintf(stderr, "%s: bad length '%s'\n",
5103 fprintf(stderr, "%s: option '%s' unrecognized\n",
5104 argv[0], argv[optind - 1]);
5109 if (advice_type == LU_LADVISE_INVALID) {
5110 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5111 fprintf(stderr, "Valid types:");
5112 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5114 if (ladvise_names[advice_type] == NULL)
5116 fprintf(stderr, " %s", ladvise_names[advice_type]);
5118 fprintf(stderr, "\n");
5122 if (argc <= optind) {
5123 fprintf(stderr, "%s: please give one or more file names\n",
5128 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5129 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5134 if (end == LUSTRE_EOF && length != 0)
5135 end = start + length;
5138 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5139 argv[0], start, end);
5143 while (optind < argc) {
5146 path = argv[optind++];
5148 fd = open(path, O_RDONLY);
5150 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5151 argv[0], path, strerror(errno));
5156 advice.lla_start = start;
5157 advice.lla_end = end;
5158 advice.lla_advice = advice_type;
5159 advice.lla_value1 = 0;
5160 advice.lla_value2 = 0;
5161 advice.lla_value3 = 0;
5162 advice.lla_value4 = 0;
5163 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5166 fprintf(stderr, "%s: cannot give advice '%s' to file "
5167 "'%s': %s\n", argv[0],
5168 ladvise_names[advice_type],
5169 path, strerror(errno));
5172 if (rc == 0 && rc2 < 0)
5178 static int lfs_list_commands(int argc, char **argv)
5180 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5182 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5187 int main(int argc, char **argv)
5191 /* Ensure that liblustreapi constructor has run */
5192 if (!liblustreapi_initialized)
5193 fprintf(stderr, "liblustreapi was not properly initialized\n");
5197 Parser_init("lfs > ", cmdlist);
5199 progname = argv[0]; /* Used in error messages */
5201 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5203 rc = Parser_commands();
5206 return rc < 0 ? -rc : rc;
5209 #ifdef _LUSTRE_IDL_H_
5210 /* Everything we need here should be included by lustreapi.h. */
5211 # error "lfs should not depend on lustre_idl.h"
5212 #endif /* _LUSTRE_IDL_H_ */