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;
1724 static int name2uid(unsigned int *id, const char *name)
1726 struct passwd *passwd;
1728 passwd = getpwnam(name);
1731 *id = passwd->pw_uid;
1736 static int name2gid(unsigned int *id, const char *name)
1738 struct group *group;
1740 group = getgrnam(name);
1743 *id = group->gr_gid;
1748 static int uid2name(char **name, unsigned int id)
1750 struct passwd *passwd;
1752 passwd = getpwuid(id);
1755 *name = passwd->pw_name;
1760 static inline int gid2name(char **name, unsigned int id)
1762 struct group *group;
1764 group = getgrgid(id);
1767 *name = group->gr_name;
1772 static int name2layout(__u32 *layout, char *name)
1777 for (ptr = name; ; ptr = NULL) {
1778 lyt = strtok(ptr, ",");
1781 if (strcmp(lyt, "released") == 0)
1782 *layout |= LOV_PATTERN_F_RELEASED;
1783 else if (strcmp(lyt, "raid0") == 0)
1784 *layout |= LOV_PATTERN_RAID0;
1791 static int lfs_find(int argc, char **argv)
1796 struct find_param param = {
1800 struct option long_opts[] = {
1801 {"atime", required_argument, 0, 'A'},
1802 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1803 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1804 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1805 {"stripe-count", required_argument, 0, 'c'},
1806 {"stripe_count", required_argument, 0, 'c'},
1807 {"ctime", required_argument, 0, 'C'},
1808 {"maxdepth", required_argument, 0, 'D'},
1809 {"component-end", required_argument, 0, 'E'},
1810 {"gid", required_argument, 0, 'g'},
1811 {"group", required_argument, 0, 'G'},
1812 {"stripe-index", required_argument, 0, 'i'},
1813 {"stripe_index", required_argument, 0, 'i'},
1814 /*{"component-id", required_argument, 0, 'I'},*/
1815 {"layout", required_argument, 0, 'L'},
1816 {"mdt", required_argument, 0, 'm'},
1817 {"mdt-index", required_argument, 0, 'm'},
1818 {"mdt_index", required_argument, 0, 'm'},
1819 {"mtime", required_argument, 0, 'M'},
1820 {"name", required_argument, 0, 'n'},
1821 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1822 {"obd", required_argument, 0, 'O'},
1823 {"ost", required_argument, 0, 'O'},
1824 /* no short option for pool, p/P already used */
1825 {"pool", required_argument, 0, LFS_POOL_OPT},
1826 {"print0", no_argument, 0, 'p'},
1827 {"print", no_argument, 0, 'P'},
1828 {"size", required_argument, 0, 's'},
1829 {"stripe-size", required_argument, 0, 'S'},
1830 {"stripe_size", required_argument, 0, 'S'},
1831 {"type", required_argument, 0, 't'},
1832 {"uid", required_argument, 0, 'u'},
1833 {"user", required_argument, 0, 'U'},
1846 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1847 while ((c = getopt_long_only(argc, argv,
1848 "-A:c:C:D:E:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1849 long_opts, NULL)) >= 0) {
1854 /* '!' is part of option */
1855 /* when getopt_long_only() finds a string which is not
1856 * an option nor a known option argument it returns 1
1857 * in that case if we already have found pathstart and pathend
1858 * (i.e. we have the list of pathnames),
1859 * the only supported value is "!"
1861 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1862 if (!isoption && pathend != -1) {
1863 fprintf(stderr, "err: %s: filename|dirname must either "
1864 "precede options or follow options\n",
1869 if (!isoption && pathstart == -1)
1870 pathstart = optind - 1;
1871 if (isoption && pathstart != -1 && pathend == -1)
1872 pathend = optind - 2;
1878 /* unknown; opt is "!" or path component,
1879 * checking done above.
1881 if (strcmp(optarg, "!") == 0)
1885 xtime = ¶m.fp_atime;
1886 xsign = ¶m.fp_asign;
1887 param.fp_exclude_atime = !!neg_opt;
1888 /* no break, this falls through to 'C' for ctime */
1891 xtime = ¶m.fp_ctime;
1892 xsign = ¶m.fp_csign;
1893 param.fp_exclude_ctime = !!neg_opt;
1895 /* no break, this falls through to 'M' for mtime */
1898 xtime = ¶m.fp_mtime;
1899 xsign = ¶m.fp_msign;
1900 param.fp_exclude_mtime = !!neg_opt;
1902 rc = set_time(&t, xtime, optarg);
1903 if (rc == INT_MAX) {
1910 case LFS_COMP_COUNT_OPT:
1911 if (optarg[0] == '+') {
1912 param.fp_comp_count_sign = -1;
1914 } else if (optarg[0] == '-') {
1915 param.fp_comp_count_sign = 1;
1919 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1920 if (*endptr != '\0') {
1921 fprintf(stderr, "error: bad component count "
1925 param.fp_check_comp_count = 1;
1926 param.fp_exclude_comp_count = !!neg_opt;
1928 case LFS_COMP_FLAGS_OPT:
1929 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1931 fprintf(stderr, "error: bad component flags "
1935 param.fp_check_comp_flags = 1;
1936 param.fp_exclude_comp_flags = !!neg_opt;
1938 case LFS_COMP_START_OPT:
1939 if (optarg[0] == '+') {
1940 param.fp_comp_start_sign = -1;
1942 } else if (optarg[0] == '-') {
1943 param.fp_comp_start_sign = 1;
1947 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1948 ¶m.fp_comp_start_units, 0);
1950 fprintf(stderr, "error: bad component start "
1954 param.fp_check_comp_start = 1;
1955 param.fp_exclude_comp_start = !!neg_opt;
1958 if (optarg[0] == '+') {
1959 param.fp_stripe_count_sign = -1;
1961 } else if (optarg[0] == '-') {
1962 param.fp_stripe_count_sign = 1;
1966 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1967 if (*endptr != '\0') {
1968 fprintf(stderr,"error: bad stripe_count '%s'\n",
1973 param.fp_check_stripe_count = 1;
1974 param.fp_exclude_stripe_count = !!neg_opt;
1977 param.fp_max_depth = strtol(optarg, 0, 0);
1980 if (optarg[0] == '+') {
1981 param.fp_comp_end_sign = -1;
1983 } else if (optarg[0] == '-') {
1984 param.fp_comp_end_sign = 1;
1988 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
1989 ¶m.fp_comp_end_units, 0);
1991 fprintf(stderr, "error: bad component end "
1995 param.fp_check_comp_end = 1;
1996 param.fp_exclude_comp_end = !!neg_opt;
2000 rc = name2gid(¶m.fp_gid, optarg);
2002 param.fp_gid = strtoul(optarg, &endptr, 10);
2003 if (*endptr != '\0') {
2004 fprintf(stderr, "Group/GID: %s cannot "
2005 "be found.\n", optarg);
2010 param.fp_exclude_gid = !!neg_opt;
2011 param.fp_check_gid = 1;
2014 ret = name2layout(¶m.fp_layout, optarg);
2017 param.fp_exclude_layout = !!neg_opt;
2018 param.fp_check_layout = 1;
2022 rc = name2uid(¶m.fp_uid, optarg);
2024 param.fp_uid = strtoul(optarg, &endptr, 10);
2025 if (*endptr != '\0') {
2026 fprintf(stderr, "User/UID: %s cannot "
2027 "be found.\n", optarg);
2032 param.fp_exclude_uid = !!neg_opt;
2033 param.fp_check_uid = 1;
2036 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2038 "Pool name %s is too long"
2039 " (max is %d)\n", optarg,
2044 /* we do check for empty pool because empty pool
2045 * is used to find V1 lov attributes */
2046 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2047 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2048 param.fp_exclude_pool = !!neg_opt;
2049 param.fp_check_pool = 1;
2052 param.fp_pattern = (char *)optarg;
2053 param.fp_exclude_pattern = !!neg_opt;
2058 char *buf, *token, *next, *p;
2062 buf = strdup(optarg);
2068 param.fp_exclude_obd = !!neg_opt;
2071 while (token && *token) {
2072 token = strchr(token, ',');
2079 param.fp_exclude_mdt = !!neg_opt;
2080 param.fp_num_alloc_mdts += len;
2081 tmp = realloc(param.fp_mdt_uuid,
2082 param.fp_num_alloc_mdts *
2083 sizeof(*param.fp_mdt_uuid));
2089 param.fp_mdt_uuid = tmp;
2091 param.fp_exclude_obd = !!neg_opt;
2092 param.fp_num_alloc_obds += len;
2093 tmp = realloc(param.fp_obd_uuid,
2094 param.fp_num_alloc_obds *
2095 sizeof(*param.fp_obd_uuid));
2101 param.fp_obd_uuid = tmp;
2103 for (token = buf; token && *token; token = next) {
2104 struct obd_uuid *puuid;
2107 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2110 ¶m.fp_obd_uuid[param.fp_num_obds++];
2112 p = strchr(token, ',');
2119 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2124 strncpy(puuid->uuid, token,
2125 sizeof(puuid->uuid));
2133 param.fp_zero_end = 1;
2138 if (optarg[0] == '+') {
2139 param.fp_size_sign = -1;
2141 } else if (optarg[0] == '-') {
2142 param.fp_size_sign = 1;
2146 ret = llapi_parse_size(optarg, ¶m.fp_size,
2147 ¶m.fp_size_units, 0);
2149 fprintf(stderr, "error: bad file size '%s'\n",
2153 param.fp_check_size = 1;
2154 param.fp_exclude_size = !!neg_opt;
2157 if (optarg[0] == '+') {
2158 param.fp_stripe_size_sign = -1;
2160 } else if (optarg[0] == '-') {
2161 param.fp_stripe_size_sign = 1;
2165 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2166 ¶m.fp_stripe_size_units, 0);
2168 fprintf(stderr, "error: bad stripe_size '%s'\n",
2172 param.fp_check_stripe_size = 1;
2173 param.fp_exclude_stripe_size = !!neg_opt;
2176 param.fp_exclude_type = !!neg_opt;
2177 switch (optarg[0]) {
2179 param.fp_type = S_IFBLK;
2182 param.fp_type = S_IFCHR;
2185 param.fp_type = S_IFDIR;
2188 param.fp_type = S_IFREG;
2191 param.fp_type = S_IFLNK;
2194 param.fp_type = S_IFIFO;
2197 param.fp_type = S_IFSOCK;
2200 fprintf(stderr, "error: %s: bad type '%s'\n",
2212 if (pathstart == -1) {
2213 fprintf(stderr, "error: %s: no filename|pathname\n",
2217 } else if (pathend == -1) {
2223 rc = llapi_find(argv[pathstart], ¶m);
2224 if (rc != 0 && ret == 0)
2226 } while (++pathstart < pathend);
2229 fprintf(stderr, "error: %s failed for %s.\n",
2230 argv[0], argv[optind - 1]);
2232 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2233 free(param.fp_obd_uuid);
2235 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2236 free(param.fp_mdt_uuid);
2241 static int lfs_getstripe_internal(int argc, char **argv,
2242 struct find_param *param)
2244 struct option long_opts[] = {
2245 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2246 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2247 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2248 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2249 /* This formerly implied "stripe-count", but was explicitly
2250 * made "stripe-count" for consistency with other options,
2251 * and to separate it from "mdt-count" when DNE arrives. */
2252 {"count", no_argument, 0, 'c'},
2254 {"stripe-count", no_argument, 0, 'c'},
2255 {"stripe_count", no_argument, 0, 'c'},
2256 {"directory", no_argument, 0, 'd'},
2257 {"default", no_argument, 0, 'D'},
2258 {"component-end", required_argument, 0, 'E'},
2259 {"fid", no_argument, 0, 'F'},
2260 {"generation", no_argument, 0, 'g'},
2261 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2262 /* This formerly implied "stripe-index", but was explicitly
2263 * made "stripe-index" for consistency with other options,
2264 * and to separate it from "mdt-index" when DNE arrives. */
2265 {"index", no_argument, 0, 'i'},
2267 {"stripe-index", no_argument, 0, 'i'},
2268 {"stripe_index", no_argument, 0, 'i'},
2269 {"component-id", required_argument, 0, 'I'},
2270 {"layout", no_argument, 0, 'L'},
2271 {"mdt", no_argument, 0, 'm'},
2272 {"mdt-index", no_argument, 0, 'm'},
2273 {"mdt_index", no_argument, 0, 'm'},
2274 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2275 {"mdt-index", no_argument, 0, 'M'},
2276 {"mdt_index", no_argument, 0, 'M'},
2278 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2279 /* This formerly implied "stripe-index", but was confusing
2280 * with "file offset" (which will eventually be needed for
2281 * with different layouts by offset), so deprecate it. */
2282 {"offset", no_argument, 0, 'o'},
2284 {"obd", required_argument, 0, 'O'},
2285 {"ost", required_argument, 0, 'O'},
2286 {"pool", no_argument, 0, 'p'},
2287 {"quiet", no_argument, 0, 'q'},
2288 {"recursive", no_argument, 0, 'r'},
2289 {"raw", no_argument, 0, 'R'},
2290 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2291 /* This formerly implied "--stripe-size", but was confusing
2292 * with "lfs find --size|-s", which means "file size", so use
2293 * the consistent "--stripe-size|-S" for all commands. */
2294 {"size", no_argument, 0, 's'},
2296 {"stripe-size", no_argument, 0, 'S'},
2297 {"stripe_size", no_argument, 0, 'S'},
2298 {"verbose", no_argument, 0, 'v'},
2304 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2305 long_opts, NULL)) != -1) {
2308 if (param->fp_obd_uuid) {
2310 "error: %s: only one obduuid allowed",
2314 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2319 case LFS_COMP_COUNT_OPT:
2320 param->fp_verbose |= VERBOSE_COMP_COUNT;
2321 param->fp_max_depth = 0;
2323 case LFS_COMP_FLAGS_OPT:
2324 if (optarg != NULL) {
2325 rc = comp_name2flags(¶m->fp_comp_flags,
2328 param->fp_verbose |=
2330 param->fp_max_depth = 0;
2333 param->fp_check_comp_flags = 1;
2336 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2337 param->fp_max_depth = 0;
2340 case LFS_COMP_START_OPT:
2341 if (optarg != NULL) {
2343 if (tmp[0] == '+') {
2344 param->fp_comp_start_sign = 1;
2346 } else if (tmp[0] == '-') {
2347 param->fp_comp_start_sign = -1;
2350 rc = llapi_parse_size(tmp,
2351 ¶m->fp_comp_start,
2352 ¶m->fp_comp_start_units, 0);
2354 param->fp_verbose |= VERBOSE_COMP_START;
2355 param->fp_max_depth = 0;
2358 param->fp_check_comp_start = 1;
2361 param->fp_verbose |= VERBOSE_COMP_START;
2362 param->fp_max_depth = 0;
2366 param->fp_max_depth = 0;
2369 param->fp_get_default_lmv = 1;
2372 if (optarg != NULL) {
2374 if (tmp[0] == '+') {
2375 param->fp_comp_end_sign = 1;
2377 } else if (tmp[0] == '-') {
2378 param->fp_comp_end_sign = -1;
2381 rc = llapi_parse_size(tmp,
2382 ¶m->fp_comp_end,
2383 ¶m->fp_comp_end_units, 0);
2385 param->fp_verbose |= VERBOSE_COMP_END;
2386 param->fp_max_depth = 0;
2389 param->fp_check_comp_end = 1;
2392 param->fp_verbose |= VERBOSE_COMP_END;
2393 param->fp_max_depth = 0;
2397 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2398 param->fp_verbose |= VERBOSE_DFID;
2399 param->fp_max_depth = 0;
2403 param->fp_recursive = 1;
2406 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2409 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2410 if (strcmp(argv[optind - 1], "--count") == 0)
2411 fprintf(stderr, "warning: '--count' deprecated,"
2412 " use '--stripe-count' instead\n");
2414 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2415 param->fp_verbose |= VERBOSE_COUNT;
2416 param->fp_max_depth = 0;
2419 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2421 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2422 fprintf(stderr, "warning: '--size|-s' deprecated, "
2423 "use '--stripe-size|-S' instead\n");
2425 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2427 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2428 param->fp_verbose |= VERBOSE_SIZE;
2429 param->fp_max_depth = 0;
2432 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2434 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2435 "use '--stripe-index|-i' instead\n");
2438 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2439 if (strcmp(argv[optind - 1], "--index") == 0)
2440 fprintf(stderr, "warning: '--index' deprecated"
2441 ", use '--stripe-index' instead\n");
2443 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2444 param->fp_verbose |= VERBOSE_OFFSET;
2445 param->fp_max_depth = 0;
2449 if (optarg != NULL) {
2450 param->fp_comp_id = strtoul(optarg, &end, 0);
2452 param->fp_verbose |= VERBOSE_COMP_ID;
2453 param->fp_max_depth = 0;
2456 param->fp_check_comp_id = 1;
2459 param->fp_max_depth = 0;
2460 param->fp_verbose |= VERBOSE_COMP_ID;
2464 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2465 param->fp_verbose |= VERBOSE_POOL;
2466 param->fp_max_depth = 0;
2470 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2471 param->fp_verbose |= VERBOSE_GENERATION;
2472 param->fp_max_depth = 0;
2476 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2477 param->fp_verbose |= VERBOSE_LAYOUT;
2478 param->fp_max_depth = 0;
2481 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2483 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2484 fprintf(stderr, "warning: '-M' deprecated"
2485 ", use '-m' instead\n");
2489 if (!(param->fp_verbose & VERBOSE_DETAIL))
2490 param->fp_max_depth = 0;
2491 param->fp_verbose |= VERBOSE_MDTINDEX;
2504 if (param->fp_recursive)
2505 param->fp_max_depth = -1;
2506 else if (param->fp_verbose & VERBOSE_DETAIL)
2507 param->fp_max_depth = 1;
2509 if (!param->fp_verbose)
2510 param->fp_verbose = VERBOSE_DEFAULT;
2511 if (param->fp_quiet)
2512 param->fp_verbose = VERBOSE_OBJID;
2515 rc = llapi_getstripe(argv[optind], param);
2516 } while (++optind < argc && !rc);
2519 fprintf(stderr, "error: %s failed for %s.\n",
2520 argv[0], argv[optind - 1]);
2524 static int lfs_tgts(int argc, char **argv)
2526 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2527 struct find_param param;
2528 int index = 0, rc=0;
2533 if (argc == 2 && !realpath(argv[1], path)) {
2535 fprintf(stderr, "error: invalid path '%s': %s\n",
2536 argv[1], strerror(-rc));
2540 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2541 /* Check if we have a mount point */
2542 if (mntdir[0] == '\0')
2545 memset(¶m, 0, sizeof(param));
2546 if (!strcmp(argv[0], "mdts"))
2547 param.fp_get_lmv = 1;
2549 rc = llapi_ostlist(mntdir, ¶m);
2551 fprintf(stderr, "error: %s: failed on %s\n",
2554 if (path[0] != '\0')
2556 memset(mntdir, 0, PATH_MAX);
2562 static int lfs_getstripe(int argc, char **argv)
2564 struct find_param param = { 0 };
2566 param.fp_max_depth = 1;
2567 return lfs_getstripe_internal(argc, argv, ¶m);
2571 static int lfs_getdirstripe(int argc, char **argv)
2573 struct find_param param = { 0 };
2574 struct option long_opts[] = {
2575 {"mdt-count", no_argument, 0, 'c'},
2576 {"mdt-index", no_argument, 0, 'i'},
2577 {"recursive", no_argument, 0, 'r'},
2578 {"mdt-hash", no_argument, 0, 't'},
2579 {"default", no_argument, 0, 'D'},
2580 {"obd", required_argument, 0, 'O'},
2585 param.fp_get_lmv = 1;
2587 while ((c = getopt_long(argc, argv, "cirtDO:", long_opts, NULL)) != -1)
2591 if (param.fp_obd_uuid) {
2593 "error: %s: only one obduuid allowed",
2597 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2600 param.fp_verbose |= VERBOSE_COUNT;
2603 param.fp_verbose |= VERBOSE_OFFSET;
2606 param.fp_verbose |= VERBOSE_HASH_TYPE;
2609 param.fp_get_default_lmv = 1;
2612 param.fp_recursive = 1;
2622 if (param.fp_recursive)
2623 param.fp_max_depth = -1;
2625 if (!param.fp_verbose)
2626 param.fp_verbose = VERBOSE_DEFAULT;
2629 rc = llapi_getstripe(argv[optind], ¶m);
2630 } while (++optind < argc && !rc);
2633 fprintf(stderr, "error: %s failed for %s.\n",
2634 argv[0], argv[optind - 1]);
2639 static int lfs_setdirstripe(int argc, char **argv)
2643 unsigned int stripe_offset = -1;
2644 unsigned int stripe_count = 1;
2645 enum lmv_hash_type hash_type;
2648 char *stripe_offset_opt = NULL;
2649 char *stripe_count_opt = NULL;
2650 char *stripe_hash_opt = NULL;
2651 char *mode_opt = NULL;
2652 bool default_stripe = false;
2653 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2654 mode_t previous_mode = 0;
2655 bool delete = false;
2657 struct option long_opts[] = {
2658 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2659 {"count", required_argument, 0, 'c'},
2661 {"mdt-count", required_argument, 0, 'c'},
2662 {"delete", no_argument, 0, 'd'},
2663 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2664 {"index", required_argument, 0, 'i'},
2666 {"mdt-index", required_argument, 0, 'i'},
2667 {"mode", required_argument, 0, 'm'},
2668 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2669 {"hash-type", required_argument, 0, 't'},
2671 {"mdt-hash", required_argument, 0, 't'},
2672 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2673 {"default_stripe", no_argument, 0, 'D'},
2675 {"default", no_argument, 0, 'D'},
2679 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2686 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2687 if (strcmp(argv[optind - 1], "--count") == 0)
2688 fprintf(stderr, "warning: '--count' deprecated"
2689 ", use '--mdt-count' instead\n");
2691 stripe_count_opt = optarg;
2695 default_stripe = true;
2698 default_stripe = true;
2701 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2702 if (strcmp(argv[optind - 1], "--index") == 0)
2703 fprintf(stderr, "warning: '--index' deprecated"
2704 ", use '--mdt-index' instead\n");
2706 stripe_offset_opt = optarg;
2712 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2713 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2714 fprintf(stderr, "warning: '--hash-type' "
2715 "deprecated, use '--mdt-hash' "
2718 stripe_hash_opt = optarg;
2721 fprintf(stderr, "error: %s: option '%s' "
2723 argv[0], argv[optind - 1]);
2728 if (optind == argc) {
2729 fprintf(stderr, "error: %s: missing dirname\n",
2734 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2735 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2740 if (stripe_offset_opt != NULL) {
2741 /* get the stripe offset */
2742 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2744 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2745 argv[0], stripe_offset_opt);
2751 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2752 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2753 " or -i options.\n", argv[0]);
2761 if (mode_opt != NULL) {
2762 mode = strtoul(mode_opt, &end, 8);
2764 fprintf(stderr, "error: %s: bad mode '%s'\n",
2768 previous_mode = umask(0);
2771 if (stripe_hash_opt == NULL) {
2772 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2776 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
2777 if (strcmp(stripe_hash_opt, mdt_hash_name[i]) == 0)
2780 if (i == LMV_HASH_TYPE_MAX) {
2782 "error: %s: bad stripe hash type '%s'\n",
2783 argv[0], stripe_hash_opt);
2790 /* get the stripe count */
2791 if (stripe_count_opt != NULL) {
2792 stripe_count = strtoul(stripe_count_opt, &end, 0);
2794 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2795 argv[0], stripe_count_opt);
2800 dname = argv[optind];
2802 if (default_stripe) {
2803 result = llapi_dir_set_default_lmv_stripe(dname,
2804 stripe_offset, stripe_count,
2807 result = llapi_dir_create_pool(dname, mode,
2809 stripe_count, hash_type,
2814 fprintf(stderr, "error: %s: create stripe dir '%s' "
2815 "failed\n", argv[0], dname);
2818 dname = argv[++optind];
2819 } while (dname != NULL);
2821 if (mode_opt != NULL)
2822 umask(previous_mode);
2828 static int lfs_rmentry(int argc, char **argv)
2835 fprintf(stderr, "error: %s: missing dirname\n",
2841 dname = argv[index];
2842 while (dname != NULL) {
2843 result = llapi_direntry_remove(dname);
2845 fprintf(stderr, "error: %s: remove dir entry '%s' "
2846 "failed\n", argv[0], dname);
2849 dname = argv[++index];
2854 static int lfs_mv(int argc, char **argv)
2856 struct find_param param = {
2863 struct option long_opts[] = {
2864 {"mdt-index", required_argument, 0, 'M'},
2865 {"verbose", no_argument, 0, 'v'},
2869 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2872 param.fp_mdt_index = strtoul(optarg, &end, 0);
2874 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2881 param.fp_verbose = VERBOSE_DETAIL;
2885 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2886 argv[0], argv[optind - 1]);
2891 if (param.fp_mdt_index == -1) {
2892 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2896 if (optind >= argc) {
2897 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2901 param.fp_migrate = 1;
2902 rc = llapi_migrate_mdt(argv[optind], ¶m);
2904 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2905 argv[0], argv[optind], param.fp_mdt_index,
2910 static int lfs_osts(int argc, char **argv)
2912 return lfs_tgts(argc, argv);
2915 static int lfs_mdts(int argc, char **argv)
2917 return lfs_tgts(argc, argv);
2920 #define COOK(value) \
2923 while (value > 1024) { \
2931 #define CDF "%11llu"
2932 #define HDF "%8.1f%c"
2937 MNTDF_INODES = 0x0001,
2938 MNTDF_COOKED = 0x0002,
2939 MNTDF_LAZY = 0x0004,
2940 MNTDF_VERBOSE = 0x0008,
2943 static int showdf(char *mntdir, struct obd_statfs *stat,
2944 char *uuid, enum mntdf_flags flags,
2945 char *type, int index, int rc)
2947 long long avail, used, total;
2949 char *suffix = "KMGTPEZY";
2950 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2951 char tbuf[3 * sizeof(__u64)];
2952 char ubuf[3 * sizeof(__u64)];
2953 char abuf[3 * sizeof(__u64)];
2954 char rbuf[3 * sizeof(__u64)];
2961 if (flags & MNTDF_INODES) {
2962 avail = stat->os_ffree;
2963 used = stat->os_files - stat->os_ffree;
2964 total = stat->os_files;
2966 int shift = flags & MNTDF_COOKED ? 0 : 10;
2968 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2969 used = ((stat->os_blocks - stat->os_bfree) *
2970 stat->os_bsize) >> shift;
2971 total = (stat->os_blocks * stat->os_bsize) >> shift;
2974 if ((used + avail) > 0)
2975 ratio = (double)used / (double)(used + avail);
2977 if (flags & MNTDF_COOKED) {
2981 cook_val = (double)total;
2984 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2987 snprintf(tbuf, sizeof(tbuf), CDF, total);
2989 cook_val = (double)used;
2992 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
2995 snprintf(ubuf, sizeof(ubuf), CDF, used);
2997 cook_val = (double)avail;
3000 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3003 snprintf(abuf, sizeof(abuf), CDF, avail);
3005 snprintf(tbuf, sizeof(tbuf), CDF, total);
3006 snprintf(ubuf, sizeof(tbuf), CDF, used);
3007 snprintf(abuf, sizeof(tbuf), CDF, avail);
3010 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3011 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3012 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3014 printf("[%s:%d]", type, index);
3016 if (stat->os_state) {
3018 * Each character represents the matching
3021 const char state_names[] = "DRSI";
3026 for (i = 0, state = stat->os_state;
3027 state && i < sizeof(state_names); i++) {
3028 if (!(state & (1 << i)))
3030 printf("%c", state_names[i]);
3038 printf(UUF": inactive device\n", uuid);
3041 printf(UUF": %s\n", uuid, strerror(-rc));
3048 struct ll_stat_type {
3053 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3055 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3056 struct obd_uuid uuid_buf;
3057 char *poolname = NULL;
3058 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3059 { LL_STATFS_LOV, "OST" },
3061 struct ll_stat_type *tp;
3062 __u64 ost_ffree = 0;
3070 poolname = strchr(pool, '.');
3071 if (poolname != NULL) {
3072 if (strncmp(fsname, pool, strlen(fsname))) {
3073 fprintf(stderr, "filesystem name incorrect\n");
3081 fd = open(mntdir, O_RDONLY);
3084 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3089 if (flags & MNTDF_INODES)
3090 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3091 "UUID", "Inodes", "IUsed", "IFree",
3092 "IUse%", "Mounted on");
3094 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3095 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3096 "Used", "Available", "Use%", "Mounted on");
3098 for (tp = types; tp->st_name != NULL; tp++) {
3099 for (index = 0; ; index++) {
3100 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3101 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3102 type = flags & MNTDF_LAZY ?
3103 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3104 rc2 = llapi_obd_fstatfs(fd, type, index,
3105 &stat_buf, &uuid_buf);
3110 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3111 if (!(flags & MNTDF_VERBOSE))
3113 } else if (rc2 < 0 && rc == 0) {
3117 if (poolname && tp->st_op == LL_STATFS_LOV &&
3118 llapi_search_ost(fsname, poolname,
3119 obd_uuid2str(&uuid_buf)) != 1)
3122 /* the llapi_obd_statfs() call may have returned with
3123 * an error, but if it filled in uuid_buf we will at
3124 * lease use that to print out a message for that OBD.
3125 * If we didn't get anything in the uuid_buf, then fill
3126 * it in so that we can print an error message. */
3127 if (uuid_buf.uuid[0] == '\0')
3128 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3129 "%s%04x", tp->st_name, index);
3130 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3131 flags, tp->st_name, index, rc2);
3134 if (tp->st_op == LL_STATFS_LMV) {
3135 sum.os_ffree += stat_buf.os_ffree;
3136 sum.os_files += stat_buf.os_files;
3137 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3138 sum.os_blocks += stat_buf.os_blocks *
3140 sum.os_bfree += stat_buf.os_bfree *
3142 sum.os_bavail += stat_buf.os_bavail *
3144 ost_ffree += stat_buf.os_ffree;
3152 /* If we don't have as many objects free on the OST as inodes
3153 * on the MDS, we reduce the total number of inodes to
3154 * compensate, so that the "inodes in use" number is correct.
3155 * Matches ll_statfs_internal() so the results are consistent. */
3156 if (ost_ffree < sum.os_ffree) {
3157 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3158 sum.os_ffree = ost_ffree;
3161 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3167 static int lfs_df(int argc, char **argv)
3169 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3170 enum mntdf_flags flags = 0;
3171 int c, rc = 0, index = 0;
3172 char fsname[PATH_MAX] = "", *pool_name = NULL;
3173 struct option long_opts[] = {
3174 {"human-readable", 0, 0, 'h'},
3175 {"inodes", 0, 0, 'i'},
3176 {"lazy", 0, 0, 'l'},
3177 {"pool", required_argument, 0, 'p'},
3178 {"verbose", 0, 0, 'v'},
3182 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3185 flags |= MNTDF_COOKED;
3188 flags |= MNTDF_INODES;
3191 flags |= MNTDF_LAZY;
3197 flags |= MNTDF_VERBOSE;
3203 if (optind < argc && !realpath(argv[optind], path)) {
3205 fprintf(stderr, "error: invalid path '%s': %s\n",
3206 argv[optind], strerror(-rc));
3210 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3211 /* Check if we have a mount point */
3212 if (mntdir[0] == '\0')
3215 rc = mntdf(mntdir, fsname, pool_name, flags);
3216 if (rc || path[0] != '\0')
3218 fsname[0] = '\0'; /* avoid matching in next loop */
3219 mntdir[0] = '\0'; /* avoid matching in next loop */
3225 static int lfs_getname(int argc, char **argv)
3227 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3228 int rc = 0, index = 0, c;
3229 char buf[sizeof(struct obd_uuid)];
3231 while ((c = getopt(argc, argv, "h")) != -1)
3234 if (optind == argc) { /* no paths specified, get all paths. */
3235 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3236 rc = llapi_getname(mntdir, buf, sizeof(buf));
3239 "cannot get name for `%s': %s\n",
3240 mntdir, strerror(-rc));
3244 printf("%s %s\n", buf, mntdir);
3246 path[0] = fsname[0] = mntdir[0] = 0;
3248 } else { /* paths specified, only attempt to search these. */
3249 for (; optind < argc; optind++) {
3250 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3253 "cannot get name for `%s': %s\n",
3254 argv[optind], strerror(-rc));
3258 printf("%s %s\n", buf, argv[optind]);
3264 static int lfs_check(int argc, char **argv)
3267 char mntdir[PATH_MAX] = {'\0'};
3276 obd_types[0] = obd_type1;
3277 obd_types[1] = obd_type2;
3279 if (strcmp(argv[1], "osts") == 0) {
3280 strcpy(obd_types[0], "osc");
3281 } else if (strcmp(argv[1], "mds") == 0) {
3282 strcpy(obd_types[0], "mdc");
3283 } else if (strcmp(argv[1], "servers") == 0) {
3285 strcpy(obd_types[0], "osc");
3286 strcpy(obd_types[1], "mdc");
3288 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3293 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3294 if (rc < 0 || mntdir[0] == '\0') {
3295 fprintf(stderr, "No suitable Lustre mount found\n");
3299 rc = llapi_target_check(num_types, obd_types, mntdir);
3301 fprintf(stderr, "error: %s: %s status failed\n",
3308 #ifdef HAVE_SYS_QUOTA_H
3309 #define ARG2INT(nr, str, msg) \
3312 nr = strtol(str, &endp, 0); \
3314 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3319 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3321 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3322 * returns the value or ULONG_MAX on integer overflow or incorrect format
3324 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3325 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3326 * 3. empty integer value is interpreted as 0
3328 static unsigned long str2sec(const char* timestr)
3330 const char spec[] = "smhdw";
3331 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3332 unsigned long val = 0;
3335 if (strpbrk(timestr, spec) == NULL) {
3336 /* no specifiers inside the time string,
3337 should treat it as an integer value */
3338 val = strtoul(timestr, &tail, 10);
3339 return *tail ? ULONG_MAX : val;
3342 /* format string is XXwXXdXXhXXmXXs */
3348 v = strtoul(timestr, &tail, 10);
3349 if (v == ULONG_MAX || *tail == '\0')
3350 /* value too large (ULONG_MAX or more)
3351 or missing specifier */
3354 ptr = strchr(spec, *tail);
3356 /* unknown specifier */
3361 /* check if product will overflow the type */
3362 if (!(v < ULONG_MAX / mult[ind]))
3365 ADD_OVERFLOW(val, mult[ind] * v);
3366 if (val == ULONG_MAX)
3378 #define ARG2ULL(nr, str, def_units) \
3380 unsigned long long limit, units = def_units; \
3383 rc = llapi_parse_size(str, &limit, &units, 1); \
3385 fprintf(stderr, "error: bad limit value %s\n", str); \
3391 static inline int has_times_option(int argc, char **argv)
3395 for (i = 1; i < argc; i++)
3396 if (!strcmp(argv[i], "-t"))
3402 int lfs_setquota_times(int argc, char **argv)
3405 struct if_quotactl qctl;
3406 char *mnt, *obd_type = (char *)qctl.obd_type;
3407 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3408 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3409 struct option long_opts[] = {
3410 {"block-grace", required_argument, 0, 'b'},
3411 {"group", no_argument, 0, 'g'},
3412 {"inode-grace", required_argument, 0, 'i'},
3413 {"times", no_argument, 0, 't'},
3414 {"user", no_argument, 0, 'u'},
3419 memset(&qctl, 0, sizeof(qctl));
3420 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3421 qctl.qc_type = ALLQUOTA;
3423 while ((c = getopt_long(argc, argv, "b:gi:tu",
3424 long_opts, NULL)) != -1) {
3432 if (qctl.qc_type != ALLQUOTA) {
3433 fprintf(stderr, "error: -u and -g can't be used "
3434 "more than once\n");
3437 qctl.qc_type = qtype;
3440 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3441 fprintf(stderr, "error: bad block-grace: %s\n",
3445 dqb->dqb_valid |= QIF_BTIME;
3448 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3449 fprintf(stderr, "error: bad inode-grace: %s\n",
3453 dqb->dqb_valid |= QIF_ITIME;
3455 case 't': /* Yes, of course! */
3457 default: /* getopt prints error message for us when opterr != 0 */
3462 if (qctl.qc_type == ALLQUOTA) {
3463 fprintf(stderr, "error: neither -u nor -g specified\n");
3467 if (optind != argc - 1) {
3468 fprintf(stderr, "error: unexpected parameters encountered\n");
3473 rc = llapi_quotactl(mnt, &qctl);
3476 fprintf(stderr, "%s %s ", obd_type,
3477 obd_uuid2str(&qctl.obd_uuid));
3478 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3485 #define BSLIMIT (1 << 0)
3486 #define BHLIMIT (1 << 1)
3487 #define ISLIMIT (1 << 2)
3488 #define IHLIMIT (1 << 3)
3490 int lfs_setquota(int argc, char **argv)
3493 struct if_quotactl qctl;
3494 char *mnt, *obd_type = (char *)qctl.obd_type;
3495 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3496 struct option long_opts[] = {
3497 {"block-softlimit", required_argument, 0, 'b'},
3498 {"block-hardlimit", required_argument, 0, 'B'},
3499 {"group", required_argument, 0, 'g'},
3500 {"inode-softlimit", required_argument, 0, 'i'},
3501 {"inode-hardlimit", required_argument, 0, 'I'},
3502 {"user", required_argument, 0, 'u'},
3505 unsigned limit_mask = 0;
3509 if (has_times_option(argc, argv))
3510 return lfs_setquota_times(argc, argv);
3512 memset(&qctl, 0, sizeof(qctl));
3513 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3514 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3515 * so it can be used as a marker that qc_type
3516 * isn't reinitialized from command line */
3518 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
3522 rc = name2uid(&qctl.qc_id, optarg);
3527 rc = name2gid(&qctl.qc_id, optarg);
3529 if (qctl.qc_type != ALLQUOTA) {
3530 fprintf(stderr, "error: -u and -g can't be used"
3531 " more than once\n");
3534 qctl.qc_type = qtype;
3536 qctl.qc_id = strtoul(optarg, &endptr, 10);
3537 if (*endptr != '\0') {
3538 fprintf(stderr, "error: can't find id "
3539 "for name %s\n", optarg);
3545 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3546 dqb->dqb_bsoftlimit >>= 10;
3547 limit_mask |= BSLIMIT;
3548 if (dqb->dqb_bsoftlimit &&
3549 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3550 fprintf(stderr, "warning: block softlimit is "
3551 "smaller than the miminal qunit size, "
3552 "please see the help of setquota or "
3553 "Lustre manual for details.\n");
3556 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3557 dqb->dqb_bhardlimit >>= 10;
3558 limit_mask |= BHLIMIT;
3559 if (dqb->dqb_bhardlimit &&
3560 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3561 fprintf(stderr, "warning: block hardlimit is "
3562 "smaller than the miminal qunit size, "
3563 "please see the help of setquota or "
3564 "Lustre manual for details.\n");
3567 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3568 limit_mask |= ISLIMIT;
3569 if (dqb->dqb_isoftlimit &&
3570 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3571 fprintf(stderr, "warning: inode softlimit is "
3572 "smaller than the miminal qunit size, "
3573 "please see the help of setquota or "
3574 "Lustre manual for details.\n");
3577 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3578 limit_mask |= IHLIMIT;
3579 if (dqb->dqb_ihardlimit &&
3580 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3581 fprintf(stderr, "warning: inode hardlimit is "
3582 "smaller than the miminal qunit size, "
3583 "please see the help of setquota or "
3584 "Lustre manual for details.\n");
3586 default: /* getopt prints error message for us when opterr != 0 */
3591 if (qctl.qc_type == ALLQUOTA) {
3592 fprintf(stderr, "error: neither -u nor -g was specified\n");
3596 if (limit_mask == 0) {
3597 fprintf(stderr, "error: at least one limit must be specified\n");
3601 if (optind != argc - 1) {
3602 fprintf(stderr, "error: unexpected parameters encountered\n");
3608 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3609 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3610 /* sigh, we can't just set blimits/ilimits */
3611 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3612 .qc_type = qctl.qc_type,
3613 .qc_id = qctl.qc_id};
3615 rc = llapi_quotactl(mnt, &tmp_qctl);
3617 fprintf(stderr, "error: setquota failed while retrieving"
3618 " current quota settings (%s)\n",
3623 if (!(limit_mask & BHLIMIT))
3624 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3625 if (!(limit_mask & BSLIMIT))
3626 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3627 if (!(limit_mask & IHLIMIT))
3628 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3629 if (!(limit_mask & ISLIMIT))
3630 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3632 /* Keep grace times if we have got no softlimit arguments */
3633 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3634 dqb->dqb_valid |= QIF_BTIME;
3635 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3638 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3639 dqb->dqb_valid |= QIF_ITIME;
3640 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3644 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3645 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3647 rc = llapi_quotactl(mnt, &qctl);
3650 fprintf(stderr, "%s %s ", obd_type,
3651 obd_uuid2str(&qctl.obd_uuid));
3652 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3659 /* Converts seconds value into format string
3660 * result is returned in buf
3662 * 1. result is in descenting order: 1w2d3h4m5s
3663 * 2. zero fields are not filled (except for p. 3): 5d1s
3664 * 3. zero seconds value is presented as "0s"
3666 static char * __sec2str(time_t seconds, char *buf)
3668 const char spec[] = "smhdw";
3669 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3674 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3675 c = seconds / mult[i];
3677 if (c > 0 || (i == 0 && buf == tail))
3678 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3686 static void sec2str(time_t seconds, char *buf, int rc)
3693 tail = __sec2str(seconds, tail);
3695 if (rc && tail - buf < 39) {
3701 static void diff2str(time_t seconds, char *buf, time_t now)
3707 if (seconds <= now) {
3708 strcpy(buf, "none");
3711 __sec2str(seconds - now, buf);
3714 static void print_quota_title(char *name, struct if_quotactl *qctl,
3715 bool human_readable)
3717 printf("Disk quotas for %s %s (%cid %u):\n",
3718 qtype_name(qctl->qc_type), name,
3719 *qtype_name(qctl->qc_type), qctl->qc_id);
3720 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3721 "Filesystem", human_readable ? "used" : "kbytes",
3722 "quota", "limit", "grace",
3723 "files", "quota", "limit", "grace");
3726 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3729 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3732 snprintf(buf, buflen, "%5.4gP",
3733 (double)num / ((__u64)1 << 40));
3735 snprintf(buf, buflen, "%5.4gT",
3736 (double)num / (1 << 30));
3738 snprintf(buf, buflen, "%5.4gG",
3739 (double)num / (1 << 20));
3741 snprintf(buf, buflen, "%5.4gM",
3742 (double)num / (1 << 10));
3744 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3748 #define STRBUF_LEN 32
3749 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3756 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3757 int bover = 0, iover = 0;
3758 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3759 char numbuf[3][STRBUF_LEN];
3761 char strbuf[STRBUF_LEN];
3763 if (dqb->dqb_bhardlimit &&
3764 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3766 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3767 if (dqb->dqb_btime > now) {
3774 if (dqb->dqb_ihardlimit &&
3775 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3777 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3778 if (dqb->dqb_itime > now) {
3786 if (strlen(mnt) > 15)
3787 printf("%s\n%15s", mnt, "");
3789 printf("%15s", mnt);
3792 diff2str(dqb->dqb_btime, timebuf, now);
3794 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3795 strbuf, sizeof(strbuf), h);
3796 if (rc == -EREMOTEIO)
3797 sprintf(numbuf[0], "%s*", strbuf);
3799 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3800 "%s" : "[%s]", strbuf);
3802 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3803 if (type == QC_GENERAL)
3804 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3805 "%s" : "[%s]", strbuf);
3807 sprintf(numbuf[1], "%s", "-");
3809 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3810 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3811 "%s" : "[%s]", strbuf);
3813 printf(" %7s%c %6s %7s %7s",
3814 numbuf[0], bover ? '*' : ' ', numbuf[1],
3815 numbuf[2], bover > 1 ? timebuf : "-");
3818 diff2str(dqb->dqb_itime, timebuf, now);
3820 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3821 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3823 if (type == QC_GENERAL)
3824 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3826 (uintmax_t)dqb->dqb_isoftlimit);
3828 sprintf(numbuf[1], "%s", "-");
3830 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3831 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3833 if (type != QC_OSTIDX)
3834 printf(" %7s%c %6s %7s %7s",
3835 numbuf[0], iover ? '*' : ' ', numbuf[1],
3836 numbuf[2], iover > 1 ? timebuf : "-");
3838 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3841 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3842 qctl->qc_cmd == Q_GETOINFO) {
3846 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3847 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3848 printf("Block grace time: %s; Inode grace time: %s\n",
3849 bgtimebuf, igtimebuf);
3853 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3854 bool h, __u64 *total)
3856 int rc = 0, rc1 = 0, count = 0;
3857 __u32 valid = qctl->qc_valid;
3859 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3861 fprintf(stderr, "can not get %s count: %s\n",
3862 is_mdt ? "mdt": "ost", strerror(-rc));
3866 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3867 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3868 rc = llapi_quotactl(mnt, qctl);
3870 /* It is remote client case. */
3871 if (rc == -EOPNOTSUPP) {
3878 fprintf(stderr, "quotactl %s%d failed.\n",
3879 is_mdt ? "mdt": "ost", qctl->qc_idx);
3883 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3884 qctl->qc_valid, 0, h);
3885 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3886 qctl->qc_dqblk.dqb_bhardlimit;
3889 qctl->qc_valid = valid;
3893 static int lfs_quota(int argc, char **argv)
3896 char *mnt, *name = NULL;
3897 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3898 .qc_type = ALLQUOTA };
3899 char *obd_type = (char *)qctl.obd_type;
3900 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3901 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
3902 verbose = 0, pass = 0, quiet = 0, inacc;
3904 __u32 valid = QC_GENERAL, idx = 0;
3905 __u64 total_ialloc = 0, total_balloc = 0;
3906 bool human_readable = false;
3909 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3918 if (qctl.qc_type != ALLQUOTA) {
3919 fprintf(stderr, "error: use either -u or -g\n");
3922 qctl.qc_type = qtype;
3925 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3928 valid = qctl.qc_valid = QC_UUID;
3929 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3932 valid = qctl.qc_valid = QC_MDTIDX;
3933 idx = qctl.qc_idx = atoi(optarg);
3936 valid = qctl.qc_valid = QC_OSTIDX;
3937 idx = qctl.qc_idx = atoi(optarg);
3946 human_readable = true;
3949 fprintf(stderr, "error: %s: option '-%c' "
3950 "unrecognized\n", argv[0], c);
3955 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3956 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
3957 optind == argc - 1) {
3959 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3960 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3961 qctl.qc_valid = valid;
3963 qctl.qc_type = pass;
3964 switch (qctl.qc_type) {
3966 qctl.qc_id = geteuid();
3967 rc = uid2name(&name, qctl.qc_id);
3970 qctl.qc_id = getegid();
3971 rc = gid2name(&name, qctl.qc_id);
3980 /* lfs quota -u username /path/to/lustre/mount */
3981 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3982 /* options should be followed by u/g-name and mntpoint */
3983 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
3984 fprintf(stderr, "error: missing quota argument(s)\n");
3988 name = argv[optind++];
3989 switch (qctl.qc_type) {
3991 rc = name2uid(&qctl.qc_id, name);
3994 rc = name2gid(&qctl.qc_id, name);
4001 qctl.qc_id = strtoul(name, &endptr, 10);
4002 if (*endptr != '\0') {
4003 fprintf(stderr, "error: can't find id for name "
4008 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4009 fprintf(stderr, "error: missing quota info argument(s)\n");
4015 rc1 = llapi_quotactl(mnt, &qctl);
4019 fprintf(stderr, "%s quotas are not enabled.\n",
4020 qtype_name(qctl.qc_type));
4023 fprintf(stderr, "Permission denied.\n");
4026 /* We already got error message. */
4029 fprintf(stderr, "Unexpected quotactl error: %s\n",
4034 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4035 print_quota_title(name, &qctl, human_readable);
4037 if (rc1 && *obd_type)
4038 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4040 if (qctl.qc_valid != QC_GENERAL)
4043 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4044 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4045 (QIF_LIMITS|QIF_USAGE));
4047 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4049 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4051 char strbuf[STRBUF_LEN];
4053 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4055 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4057 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4059 printf("Total allocated inode limit: %ju, total "
4060 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4064 if (rc1 || rc2 || rc3 || inacc)
4065 printf("Some errors happened when getting quota info. "
4066 "Some devices may be not working or deactivated. "
4067 "The data in \"[]\" is inaccurate.\n");
4070 if (pass > 0 && pass < LL_MAXQUOTAS)
4075 #endif /* HAVE_SYS_QUOTA_H! */
4077 static int flushctx_ioctl(char *mp)
4081 fd = open(mp, O_RDONLY);
4083 fprintf(stderr, "flushctx: error open %s: %s\n",
4084 mp, strerror(errno));
4088 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4090 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4091 mp, strerror(errno));
4097 static int lfs_flushctx(int argc, char **argv)
4099 int kdestroy = 0, c;
4100 char mntdir[PATH_MAX] = {'\0'};
4104 while ((c = getopt(argc, argv, "k")) != -1) {
4110 fprintf(stderr, "error: %s: option '-%c' "
4111 "unrecognized\n", argv[0], c);
4117 if ((rc = system("kdestroy > /dev/null")) != 0) {
4118 rc = WEXITSTATUS(rc);
4119 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4123 if (optind >= argc) {
4124 /* flush for all mounted lustre fs. */
4125 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4126 /* Check if we have a mount point */
4127 if (mntdir[0] == '\0')
4130 if (flushctx_ioctl(mntdir))
4133 mntdir[0] = '\0'; /* avoid matching in next loop */
4136 /* flush fs as specified */
4137 while (optind < argc) {
4138 if (flushctx_ioctl(argv[optind++]))
4145 static int lfs_cp(int argc, char **argv)
4147 fprintf(stderr, "remote client copy file(s).\n"
4148 "obsolete, does not support it anymore.\n");
4152 static int lfs_ls(int argc, char **argv)
4154 fprintf(stderr, "remote client lists directory contents.\n"
4155 "obsolete, does not support it anymore.\n");
4159 static int lfs_changelog(int argc, char **argv)
4161 void *changelog_priv;
4162 struct changelog_rec *rec;
4163 long long startrec = 0, endrec = 0;
4165 struct option long_opts[] = {
4166 {"follow", no_argument, 0, 'f'},
4169 char short_opts[] = "f";
4172 while ((rc = getopt_long(argc, argv, short_opts,
4173 long_opts, NULL)) != -1) {
4181 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4182 argv[0], argv[optind - 1]);
4189 mdd = argv[optind++];
4191 startrec = strtoll(argv[optind++], NULL, 10);
4193 endrec = strtoll(argv[optind++], NULL, 10);
4195 rc = llapi_changelog_start(&changelog_priv,
4196 CHANGELOG_FLAG_BLOCK |
4197 CHANGELOG_FLAG_JOBID |
4198 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4201 fprintf(stderr, "Can't start changelog: %s\n",
4202 strerror(errno = -rc));
4206 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4210 if (endrec && rec->cr_index > endrec) {
4211 llapi_changelog_free(&rec);
4214 if (rec->cr_index < startrec) {
4215 llapi_changelog_free(&rec);
4219 secs = rec->cr_time >> 30;
4220 gmtime_r(&secs, &ts);
4221 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4222 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4223 changelog_type2str(rec->cr_type),
4224 ts.tm_hour, ts.tm_min, ts.tm_sec,
4225 (int)(rec->cr_time & ((1<<30) - 1)),
4226 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4227 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4229 if (rec->cr_flags & CLF_JOBID) {
4230 struct changelog_ext_jobid *jid =
4231 changelog_rec_jobid(rec);
4233 if (jid->cr_jobid[0] != '\0')
4234 printf(" j=%s", jid->cr_jobid);
4237 if (rec->cr_namelen)
4238 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4239 rec->cr_namelen, changelog_rec_name(rec));
4241 if (rec->cr_flags & CLF_RENAME) {
4242 struct changelog_ext_rename *rnm =
4243 changelog_rec_rename(rec);
4245 if (!fid_is_zero(&rnm->cr_sfid))
4246 printf(" s="DFID" sp="DFID" %.*s",
4247 PFID(&rnm->cr_sfid),
4248 PFID(&rnm->cr_spfid),
4249 (int)changelog_rec_snamelen(rec),
4250 changelog_rec_sname(rec));
4254 llapi_changelog_free(&rec);
4257 llapi_changelog_fini(&changelog_priv);
4260 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4262 return (rc == 1 ? 0 : rc);
4265 static int lfs_changelog_clear(int argc, char **argv)
4273 endrec = strtoll(argv[3], NULL, 10);
4275 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4278 fprintf(stderr, "%s: record out of range: %llu\n",
4280 else if (rc == -ENOENT)
4281 fprintf(stderr, "%s: no changelog user: %s\n",
4284 fprintf(stderr, "%s error: %s\n", argv[0],
4293 static int lfs_fid2path(int argc, char **argv)
4295 struct option long_opts[] = {
4296 {"cur", no_argument, 0, 'c'},
4297 {"link", required_argument, 0, 'l'},
4298 {"rec", required_argument, 0, 'r'},
4301 char short_opts[] = "cl:r:";
4302 char *device, *fid, *path;
4303 long long recno = -1;
4309 while ((rc = getopt_long(argc, argv, short_opts,
4310 long_opts, NULL)) != -1) {
4316 linkno = strtol(optarg, NULL, 10);
4319 recno = strtoll(optarg, NULL, 10);
4324 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4325 argv[0], argv[optind - 1]);
4333 device = argv[optind++];
4334 path = calloc(1, PATH_MAX);
4336 fprintf(stderr, "error: Not enough memory\n");
4341 while (optind < argc) {
4342 fid = argv[optind++];
4344 lnktmp = (linkno >= 0) ? linkno : 0;
4346 int oldtmp = lnktmp;
4347 long long rectmp = recno;
4349 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4352 fprintf(stderr, "%s: error on FID %s: %s\n",
4353 argv[0], fid, strerror(errno = -rc2));
4360 fprintf(stdout, "%lld ", rectmp);
4361 if (device[0] == '/') {
4362 fprintf(stdout, "%s", device);
4363 if (device[strlen(device) - 1] != '/')
4364 fprintf(stdout, "/");
4365 } else if (path[0] == '\0') {
4366 fprintf(stdout, "/");
4368 fprintf(stdout, "%s\n", path);
4371 /* specified linkno */
4373 if (oldtmp == lnktmp)
4383 static int lfs_path2fid(int argc, char **argv)
4385 struct option long_opts[] = {
4386 {"parents", no_argument, 0, 'p'},
4390 const char short_opts[] = "p";
4391 const char *sep = "";
4394 bool show_parents = false;
4396 while ((rc = getopt_long(argc, argv, short_opts,
4397 long_opts, NULL)) != -1) {
4400 show_parents = true;
4403 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4404 argv[0], argv[optind - 1]);
4409 if (optind > argc - 1)
4411 else if (optind < argc - 1)
4415 for (path = argv + optind; *path != NULL; path++) {
4417 if (!show_parents) {
4418 err = llapi_path2fid(*path, &fid);
4420 printf("%s%s"DFID"\n",
4421 *sep != '\0' ? *path : "", sep,
4424 char name[NAME_MAX + 1];
4425 unsigned int linkno = 0;
4427 while ((err = llapi_path2parent(*path, linkno, &fid,
4428 name, sizeof(name))) == 0) {
4429 if (*sep != '\0' && linkno == 0)
4430 printf("%s%s", *path, sep);
4432 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4437 /* err == -ENODATA is end-of-loop */
4438 if (linkno > 0 && err == -ENODATA) {
4445 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4446 argv[0], show_parents ? "parent " : "", *path,
4458 static int lfs_data_version(int argc, char **argv)
4465 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4470 while ((c = getopt(argc, argv, "nrw")) != -1) {
4473 data_version_flags = 0;
4476 data_version_flags |= LL_DV_RD_FLUSH;
4479 data_version_flags |= LL_DV_WR_FLUSH;
4488 path = argv[optind];
4489 fd = open(path, O_RDONLY);
4491 err(errno, "cannot open file %s", path);
4493 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4495 err(errno, "cannot get version for %s", path);
4497 printf("%ju" "\n", (uintmax_t)data_version);
4503 static int lfs_hsm_state(int argc, char **argv)
4508 struct hsm_user_state hus;
4516 rc = llapi_hsm_state_get(path, &hus);
4518 fprintf(stderr, "can't get hsm state for %s: %s\n",
4519 path, strerror(errno = -rc));
4523 /* Display path name and status flags */
4524 printf("%s: (0x%08x)", path, hus.hus_states);
4526 if (hus.hus_states & HS_RELEASED)
4527 printf(" released");
4528 if (hus.hus_states & HS_EXISTS)
4530 if (hus.hus_states & HS_DIRTY)
4532 if (hus.hus_states & HS_ARCHIVED)
4533 printf(" archived");
4534 /* Display user-settable flags */
4535 if (hus.hus_states & HS_NORELEASE)
4536 printf(" never_release");
4537 if (hus.hus_states & HS_NOARCHIVE)
4538 printf(" never_archive");
4539 if (hus.hus_states & HS_LOST)
4540 printf(" lost_from_hsm");
4542 if (hus.hus_archive_id != 0)
4543 printf(", archive_id:%d", hus.hus_archive_id);
4546 } while (++i < argc);
4551 #define LFS_HSM_SET 0
4552 #define LFS_HSM_CLEAR 1
4555 * Generic function to set or clear HSM flags.
4556 * Used by hsm_set and hsm_clear.
4558 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4560 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4562 struct option long_opts[] = {
4563 {"lost", 0, 0, 'l'},
4564 {"norelease", 0, 0, 'r'},
4565 {"noarchive", 0, 0, 'a'},
4566 {"archived", 0, 0, 'A'},
4567 {"dirty", 0, 0, 'd'},
4568 {"exists", 0, 0, 'e'},
4571 char short_opts[] = "lraAde";
4579 while ((c = getopt_long(argc, argv, short_opts,
4580 long_opts, NULL)) != -1) {
4586 mask |= HS_NOARCHIVE;
4589 mask |= HS_ARCHIVED;
4592 mask |= HS_NORELEASE;
4603 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4604 argv[0], argv[optind - 1]);
4609 /* User should have specified a flag */
4613 while (optind < argc) {
4615 path = argv[optind];
4617 /* If mode == 0, this means we apply the mask. */
4618 if (mode == LFS_HSM_SET)
4619 rc = llapi_hsm_state_set(path, mask, 0, 0);
4621 rc = llapi_hsm_state_set(path, 0, mask, 0);
4624 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4625 path, strerror(errno = -rc));
4634 static int lfs_hsm_action(int argc, char **argv)
4639 struct hsm_current_action hca;
4640 struct hsm_extent he;
4641 enum hsm_user_action hua;
4642 enum hsm_progress_states hps;
4650 rc = llapi_hsm_current_action(path, &hca);
4652 fprintf(stderr, "can't get hsm action for %s: %s\n",
4653 path, strerror(errno = -rc));
4656 he = hca.hca_location;
4657 hua = hca.hca_action;
4658 hps = hca.hca_state;
4660 printf("%s: %s", path, hsm_user_action2name(hua));
4662 /* Skip file without action */
4663 if (hca.hca_action == HUA_NONE) {
4668 printf(" %s ", hsm_progress_state2name(hps));
4670 if ((hps == HPS_RUNNING) &&
4671 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4672 printf("(%llu bytes moved)\n",
4673 (unsigned long long)he.length);
4674 else if ((he.offset + he.length) == LUSTRE_EOF)
4675 printf("(from %llu to EOF)\n",
4676 (unsigned long long)he.offset);
4678 printf("(from %llu to %llu)\n",
4679 (unsigned long long)he.offset,
4680 (unsigned long long)(he.offset + he.length));
4682 } while (++i < argc);
4687 static int lfs_hsm_set(int argc, char **argv)
4689 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4692 static int lfs_hsm_clear(int argc, char **argv)
4694 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4698 * Check file state and return its fid, to be used by lfs_hsm_request().
4700 * \param[in] file Path to file to check
4701 * \param[in,out] fid Pointer to allocated lu_fid struct.
4702 * \param[in,out] last_dev Pointer to last device id used.
4704 * \return 0 on success.
4706 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4712 rc = lstat(file, &st);
4714 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4717 /* Checking for regular file as archiving as posix copytool
4718 * rejects archiving files other than regular files
4720 if (!S_ISREG(st.st_mode)) {
4721 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4724 /* A request should be ... */
4725 if (*last_dev != st.st_dev && *last_dev != 0) {
4726 fprintf(stderr, "All files should be "
4727 "on the same filesystem: %s\n", file);
4730 *last_dev = st.st_dev;
4732 rc = llapi_path2fid(file, fid);
4734 fprintf(stderr, "Cannot read FID of %s: %s\n",
4735 file, strerror(-rc));
4741 /* Fill an HSM HUR item with a given file name.
4743 * If mntpath is set, then the filename is actually a FID, and no
4744 * lookup on the filesystem will be performed.
4746 * \param[in] hur the user request to fill
4747 * \param[in] idx index of the item inside the HUR to fill
4748 * \param[in] mntpath mountpoint of Lustre
4749 * \param[in] fname filename (if mtnpath is NULL)
4750 * or FID (if mntpath is set)
4751 * \param[in] last_dev pointer to last device id used
4753 * \retval 0 on success
4754 * \retval CMD_HELP or a negative errno on error
4756 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4757 const char *mntpath, const char *fname,
4760 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4763 hui->hui_extent.length = -1;
4765 if (mntpath != NULL) {
4768 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4772 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4777 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4781 hur->hur_request.hr_itemcount++;
4786 static int lfs_hsm_request(int argc, char **argv, int action)
4788 struct option long_opts[] = {
4789 {"filelist", 1, 0, 'l'},
4790 {"data", 1, 0, 'D'},
4791 {"archive", 1, 0, 'a'},
4792 {"mntpath", 1, 0, 'm'},
4796 char short_opts[] = "l:D:a:m:";
4797 struct hsm_user_request *hur, *oldhur;
4802 char *filelist = NULL;
4803 char fullpath[PATH_MAX];
4804 char *opaque = NULL;
4808 int nbfile_alloc = 0;
4809 char *some_file = NULL;
4810 char *mntpath = NULL;
4816 while ((c = getopt_long(argc, argv, short_opts,
4817 long_opts, NULL)) != -1) {
4826 if (action != HUA_ARCHIVE &&
4827 action != HUA_REMOVE) {
4829 "error: -a is supported only "
4830 "when archiving or removing\n");
4833 archive_id = atoi(optarg);
4836 if (some_file == NULL) {
4838 some_file = strdup(optarg);
4844 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4845 argv[0], argv[optind - 1]);
4850 /* All remaining args are files, so we have at least nbfile */
4851 nbfile = argc - optind;
4853 if ((nbfile == 0) && (filelist == NULL))
4857 opaque_len = strlen(opaque);
4859 /* Alloc the request structure with enough place to store all files
4860 * from command line. */
4861 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4863 fprintf(stderr, "Cannot create the request: %s\n",
4867 nbfile_alloc = nbfile;
4869 hur->hur_request.hr_action = action;
4870 hur->hur_request.hr_archive_id = archive_id;
4871 hur->hur_request.hr_flags = 0;
4873 /* All remaining args are files, add them */
4874 if (nbfile != 0 && some_file == NULL)
4875 some_file = strdup(argv[optind]);
4877 for (i = 0; i < nbfile; i++) {
4878 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4884 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4886 /* If a filelist was specified, read the filelist from it. */
4887 if (filelist != NULL) {
4888 fp = fopen(filelist, "r");
4890 fprintf(stderr, "Cannot read the file list %s: %s\n",
4891 filelist, strerror(errno));
4896 while ((rc = getline(&line, &len, fp)) != -1) {
4897 /* If allocated buffer was too small, get something
4899 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4902 nbfile_alloc = nbfile_alloc * 2 + 1;
4904 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4907 fprintf(stderr, "hsm: cannot allocate "
4908 "the request: %s\n",
4915 size = hur_len(oldhur);
4917 fprintf(stderr, "hsm: cannot allocate "
4918 "%u files + %u bytes data\n",
4919 oldhur->hur_request.hr_itemcount,
4920 oldhur->hur_request.hr_data_len);
4927 memcpy(hur, oldhur, size);
4932 if (line[strlen(line) - 1] == '\n')
4933 line[strlen(line) - 1] = '\0';
4935 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4936 mntpath, line, &last_dev);
4942 if (some_file == NULL) {
4952 /* If a --data was used, add it to the request */
4953 hur->hur_request.hr_data_len = opaque_len;
4955 memcpy(hur_data(hur), opaque, opaque_len);
4957 /* Send the HSM request */
4958 if (realpath(some_file, fullpath) == NULL) {
4959 fprintf(stderr, "Could not find path '%s': %s\n",
4960 some_file, strerror(errno));
4962 rc = llapi_hsm_request(fullpath, hur);
4964 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4965 some_file, strerror(-rc));
4975 static int lfs_hsm_archive(int argc, char **argv)
4977 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4980 static int lfs_hsm_restore(int argc, char **argv)
4982 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4985 static int lfs_hsm_release(int argc, char **argv)
4987 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4990 static int lfs_hsm_remove(int argc, char **argv)
4992 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4995 static int lfs_hsm_cancel(int argc, char **argv)
4997 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5000 static int lfs_swap_layouts(int argc, char **argv)
5005 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5006 SWAP_LAYOUTS_KEEP_MTIME |
5007 SWAP_LAYOUTS_KEEP_ATIME);
5010 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5012 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5014 enum lu_ladvise_type advice;
5017 advice < ARRAY_SIZE(ladvise_names); advice++) {
5018 if (ladvise_names[advice] == NULL)
5020 if (strcmp(string, ladvise_names[advice]) == 0)
5024 return LU_LADVISE_INVALID;
5027 static int lfs_ladvise(int argc, char **argv)
5029 struct option long_opts[] = {
5030 {"advice", required_argument, 0, 'a'},
5031 {"background", no_argument, 0, 'b'},
5032 {"end", required_argument, 0, 'e'},
5033 {"start", required_argument, 0, 's'},
5034 {"length", required_argument, 0, 'l'},
5037 char short_opts[] = "a:be:l:s:";
5042 struct llapi_lu_ladvise advice;
5043 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5044 unsigned long long start = 0;
5045 unsigned long long end = LUSTRE_EOF;
5046 unsigned long long length = 0;
5047 unsigned long long size_units;
5048 unsigned long long flags = 0;
5051 while ((c = getopt_long(argc, argv, short_opts,
5052 long_opts, NULL)) != -1) {
5055 advice_type = lfs_get_ladvice(optarg);
5056 if (advice_type == LU_LADVISE_INVALID) {
5057 fprintf(stderr, "%s: invalid advice type "
5058 "'%s'\n", argv[0], optarg);
5059 fprintf(stderr, "Valid types:");
5061 for (advice_type = 0;
5062 advice_type < ARRAY_SIZE(ladvise_names);
5064 if (ladvise_names[advice_type] == NULL)
5066 fprintf(stderr, " %s",
5067 ladvise_names[advice_type]);
5069 fprintf(stderr, "\n");
5079 rc = llapi_parse_size(optarg, &end,
5082 fprintf(stderr, "%s: bad end offset '%s'\n",
5089 rc = llapi_parse_size(optarg, &start,
5092 fprintf(stderr, "%s: bad start offset "
5093 "'%s'\n", argv[0], optarg);
5099 rc = llapi_parse_size(optarg, &length,
5102 fprintf(stderr, "%s: bad length '%s'\n",
5110 fprintf(stderr, "%s: option '%s' unrecognized\n",
5111 argv[0], argv[optind - 1]);
5116 if (advice_type == LU_LADVISE_INVALID) {
5117 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5118 fprintf(stderr, "Valid types:");
5119 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5121 if (ladvise_names[advice_type] == NULL)
5123 fprintf(stderr, " %s", ladvise_names[advice_type]);
5125 fprintf(stderr, "\n");
5129 if (argc <= optind) {
5130 fprintf(stderr, "%s: please give one or more file names\n",
5135 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5136 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5141 if (end == LUSTRE_EOF && length != 0)
5142 end = start + length;
5145 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5146 argv[0], start, end);
5150 while (optind < argc) {
5153 path = argv[optind++];
5155 fd = open(path, O_RDONLY);
5157 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5158 argv[0], path, strerror(errno));
5163 advice.lla_start = start;
5164 advice.lla_end = end;
5165 advice.lla_advice = advice_type;
5166 advice.lla_value1 = 0;
5167 advice.lla_value2 = 0;
5168 advice.lla_value3 = 0;
5169 advice.lla_value4 = 0;
5170 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5173 fprintf(stderr, "%s: cannot give advice '%s' to file "
5174 "'%s': %s\n", argv[0],
5175 ladvise_names[advice_type],
5176 path, strerror(errno));
5179 if (rc == 0 && rc2 < 0)
5185 static int lfs_list_commands(int argc, char **argv)
5187 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5189 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5194 int main(int argc, char **argv)
5198 /* Ensure that liblustreapi constructor has run */
5199 if (!liblustreapi_initialized)
5200 fprintf(stderr, "liblustreapi was not properly initialized\n");
5204 Parser_init("lfs > ", cmdlist);
5206 progname = argv[0]; /* Used in error messages */
5208 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5210 rc = Parser_commands();
5213 return rc < 0 ? -rc : rc;
5216 #ifdef _LUSTRE_IDL_H_
5217 /* Everything we need here should be included by lustreapi.h. */
5218 # error "lfs should not depend on lustre_idl.h"
5219 #endif /* _LUSTRE_IDL_H_ */