4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-t mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t-I and -F can't be specified at the same time\n"
192 "To add component(s) to an existing composite file:\n"
193 SSM_CMD_COMMON("setstripe --component-add")
195 "To create a file with specified striping/composite layout:\n"
197 {"getstripe", lfs_getstripe, 0,
198 "To list the striping info for a given file or files in a\n"
199 "directory or recursively for all files in a directory tree.\n"
200 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201 " [--stripe-count|-c] [--stripe-index|-i]\n"
202 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
203 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
204 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
205 " [--component-id|-I [comp_id]]\n"
206 " [--component-flags [comp_flags]]\n"
207 " [--component-count [comp_count]]\n"
208 " [--component-start [comp_start]]\n"
209 " [--component-end|-E [comp_end]]\n"
210 " <directory|filename> ..."},
211 {"setdirstripe", lfs_setdirstripe, 0,
212 "To create a striped directory on a specified MDT. This can only\n"
213 "be done on MDT0 with the right of administrator.\n"
214 "usage: setdirstripe [OPTION] <directory>\n"
216 {"getdirstripe", lfs_getdirstripe, 0,
217 "To list the striping info for a given directory\n"
218 "or recursively for all directories in a directory tree.\n"
219 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
220 " [--mdt-index|-i] [--mdt-hash|-t]\n"
221 " [--recursive|-r] [--default|-D] <dir> ..."},
222 {"mkdir", lfs_setdirstripe, 0,
223 "To create a striped directory on a specified MDT. This can only\n"
224 "be done on MDT0 with the right of administrator.\n"
225 "usage: mkdir [OPTION] <directory>\n"
227 {"rm_entry", lfs_rmentry, 0,
228 "To remove the name entry of the remote directory. Note: This\n"
229 "command will only delete the name entry, i.e. the remote directory\n"
230 "will become inaccessable after this command. This can only be done\n"
231 "by the administrator\n"
232 "usage: rm_entry <dir>\n"},
233 {"pool_list", lfs_poollist, 0,
234 "List pools or pool OSTs\n"
235 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
236 {"find", lfs_find, 0,
237 "find files matching given attributes recursively in directory tree.\n"
238 "usage: find <directory|filename> ...\n"
239 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
240 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
241 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
242 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
243 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
244 " [[!] --stripe-count|-c [+-]<stripes>]\n"
245 " [[!] --stripe-index|-i <index,...>]\n"
246 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
247 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
248 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
249 " [[!] --layout|-L released,raid0]\n"
250 " [[!] --component-count [+-]<comp_cnt>]\n"
251 " [[!] --component-start [+-]N[kMGTPE]]\n"
252 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
253 " [[!] --component-flags <comp_flags>]\n"
254 "\t !: used before an option indicates 'NOT' requested attribute\n"
255 "\t -: used before a value indicates 'AT MOST' requested value\n"
256 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
257 {"check", lfs_check, 0,
258 "Display the status of MDS or OSTs (as specified in the command)\n"
259 "or all the servers (MDS and OSTs).\n"
260 "usage: check <osts|mds|servers>"},
261 {"osts", lfs_osts, 0, "list OSTs connected to client "
262 "[for specified path only]\n" "usage: osts [path]"},
263 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
264 "[for specified path only]\n" "usage: mdts [path]"},
266 "report filesystem disk space usage or inodes usage"
267 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
268 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
269 {"getname", lfs_getname, 0, "list instances and specified mount points "
270 "[for specified path only]\n"
271 "Usage: getname [-h]|[path ...] "},
272 #ifdef HAVE_SYS_QUOTA_H
273 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
274 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
275 " -b <block-softlimit> -B <block-hardlimit>\n"
276 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
277 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
278 " [--block-softlimit <block-softlimit>]\n"
279 " [--block-hardlimit <block-hardlimit>]\n"
280 " [--inode-softlimit <inode-softlimit>]\n"
281 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
282 " setquota [-t] <-u|--user|-g|--group>\n"
283 " [--block-grace <block-grace>]\n"
284 " [--inode-grace <inode-grace>] <filesystem>\n"
285 " -b can be used instead of --block-softlimit/--block-grace\n"
286 " -B can be used instead of --block-hardlimit\n"
287 " -i can be used instead of --inode-softlimit/--inode-grace\n"
288 " -I can be used instead of --inode-hardlimit\n\n"
289 "Note: The total quota space will be split into many qunits and\n"
290 " balanced over all server targets, the minimal qunit size is\n"
291 " 1M bytes for block space and 1K inodes for inode space.\n\n"
292 " Quota space rebalancing process will stop when this mininum\n"
293 " value is reached. As a result, quota exceeded can be returned\n"
294 " while many targets still have 1MB or 1K inodes of spare\n"
296 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
297 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
299 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
300 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
302 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
303 "usage: flushctx [-k] [mountpoint...]"},
305 "Remote user copy files and directories.\n"
306 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
308 "Remote user list directory contents.\n"
309 "usage: ls [OPTION]... [FILE]..."},
310 {"changelog", lfs_changelog, 0,
311 "Show the metadata changes on an MDT."
312 "\nusage: changelog <mdtname> [startrec [endrec]]"},
313 {"changelog_clear", lfs_changelog_clear, 0,
314 "Indicate that old changelog records up to <endrec> are no longer of "
315 "interest to consumer <id>, allowing the system to free up space.\n"
316 "An <endrec> of 0 means all records.\n"
317 "usage: changelog_clear <mdtname> <id> <endrec>"},
318 {"fid2path", lfs_fid2path, 0,
319 "Resolve the full path(s) for given FID(s). For a specific hardlink "
320 "specify link number <linkno>.\n"
321 /* "For a historical link name, specify changelog record <recno>.\n" */
322 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
323 /* [ --rec <recno> ] */ },
324 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
325 "usage: path2fid [--parents] <path> ..."},
326 {"data_version", lfs_data_version, 0, "Display file data version for "
327 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
328 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
329 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
330 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
331 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
332 "[--archived] [--lost] <file> ..."},
333 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
335 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
336 "[--archived] [--lost] <file> ..."},
337 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
338 "given files.\n" "usage: hsm_action <file> ..."},
339 {"hsm_archive", lfs_hsm_archive, 0,
340 "Archive file to external storage.\n"
341 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
343 {"hsm_restore", lfs_hsm_restore, 0,
344 "Restore file from external storage.\n"
345 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
346 {"hsm_release", lfs_hsm_release, 0,
347 "Release files from Lustre.\n"
348 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
349 {"hsm_remove", lfs_hsm_remove, 0,
350 "Remove file copy from external storage.\n"
351 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
352 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
354 "Note: To remove files from the archive that have been deleted on\n"
355 "Lustre, set mntpath and optionally archive. In that case, all the\n"
356 "positional arguments and entries in the file list must be FIDs."
358 {"hsm_cancel", lfs_hsm_cancel, 0,
359 "Cancel requests related to specified files.\n"
360 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
361 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
362 "usage: swap_layouts <path1> <path2>"},
363 {"migrate", lfs_setstripe, 0,
364 "migrate a directory between MDTs.\n"
365 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
367 "\tmdt_idx: index of the destination MDT\n"
369 "migrate file objects from one OST "
370 "layout\nto another (may be not safe with concurent writes).\n"
372 "[--stripe-count|-c] <stripe_count>\n"
373 " [--stripe-index|-i] <start_ost_index>\n"
374 " [--stripe-size|-S] <stripe_size>\n"
375 " [--pool|-p] <pool_name>\n"
376 " [--ost-list|-o] <ost_indices>\n"
378 " [--non-block|-n]\n"
379 " <file|directory>\n"
380 "\tstripe_count: number of OSTs to stripe a file over\n"
381 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
382 "\tstripe_size: number of bytes to store before moving to the next OST\n"
383 "\tpool_name: name of the predefined pool of OSTs\n"
384 "\tost_indices: OSTs to stripe over, in order\n"
385 "\tblock: wait for the operation to return before continuing\n"
386 "\tnon-block: do not wait for the operation to return.\n"},
388 "To move directories between MDTs. This command is deprecated, "
389 "use \"migrate\" instead.\n"
390 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
392 {"ladvise", lfs_ladvise, 0,
393 "Provide servers with advice about access patterns for a file.\n"
394 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
395 " [--background|-b]\n"
396 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
398 {"help", Parser_help, 0, "help"},
399 {"exit", Parser_quit, 0, "quit"},
400 {"quit", Parser_quit, 0, "quit"},
401 {"--version", Parser_version, 0,
402 "output build version of the utility and exit"},
403 {"--list-commands", lfs_list_commands, 0,
404 "list commands supported by the utility and exit"},
409 #define MIGRATION_NONBLOCK 1
412 * Internal helper for migrate_copy_data(). Check lease and report error if
415 * \param[in] fd File descriptor on which to check the lease.
416 * \param[out] lease_broken Set to true if the lease was broken.
417 * \param[in] group_locked Whether a group lock was taken or not.
418 * \param[in] path Name of the file being processed, for error
421 * \retval 0 Migration can keep on going.
422 * \retval -errno Error occurred, abort migration.
424 static int check_lease(int fd, bool *lease_broken, bool group_locked,
429 if (!file_lease_supported)
432 rc = llapi_lease_check(fd);
434 return 0; /* llapi_check_lease returns > 0 on success. */
437 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
439 rc = rc ? rc : -EAGAIN;
441 fprintf(stderr, "%s: external attempt to access file '%s' "
442 "blocked until migration ends.\n", progname, path);
445 *lease_broken = true;
449 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
450 bool group_locked, const char *fname)
459 bool lease_broken = false;
461 /* Use a page-aligned buffer for direct I/O */
462 rc = posix_memalign(&buf, getpagesize(), buf_size);
467 /* read new data only if we have written all
468 * previously read data */
471 rc = check_lease(fd_src, &lease_broken,
472 group_locked, fname);
476 rsize = read(fd_src, buf, buf_size);
479 fprintf(stderr, "%s: %s: read failed: %s\n",
480 progname, fname, strerror(-rc));
490 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
494 "%s: %s: write failed on volatile: %s\n",
495 progname, fname, strerror(-rc));
505 fprintf(stderr, "%s: %s: fsync failed: %s\n",
506 progname, fname, strerror(-rc));
514 static int migrate_copy_timestamps(int fdv, const struct stat *st)
516 struct timeval tv[2] = {
517 {.tv_sec = st->st_atime},
518 {.tv_sec = st->st_mtime}
521 return futimes(fdv, tv);
524 static int migrate_block(int fd, int fdv, const struct stat *st,
525 size_t buf_size, const char *name)
532 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
534 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
535 progname, name, strerror(-rc));
543 /* The grouplock blocks all concurrent accesses to the file.
544 * It has to be taken after llapi_get_data_version as it would
546 rc = llapi_group_lock(fd, gid);
548 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
549 progname, name, strerror(-rc));
553 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
555 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
559 /* Make sure we keep original atime/mtime values */
560 rc = migrate_copy_timestamps(fdv, st);
562 fprintf(stderr, "%s: %s: timestamp copy failed\n",
568 * for a migration we need to check data version on file did
571 * Pass in gid=0 since we already own grouplock. */
572 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
573 SWAP_LAYOUTS_CHECK_DV1);
575 fprintf(stderr, "%s: %s: dataversion changed during copy, "
576 "migration aborted\n", progname, name);
579 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
580 name, strerror(-rc));
585 rc2 = llapi_group_unlock(fd, gid);
586 if (rc2 < 0 && rc == 0) {
587 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
588 progname, name, strerror(-rc2));
595 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
596 size_t buf_size, const char *name)
602 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
604 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
605 progname, name, strerror(-rc));
609 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
611 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
615 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
617 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
618 progname, name, strerror(-rc));
624 fprintf(stderr, "%s: %s: data version changed during "
630 /* Make sure we keep original atime/mtime values */
631 rc = migrate_copy_timestamps(fdv, st);
633 fprintf(stderr, "%s: %s: timestamp copy failed\n",
638 /* Atomically put lease, swap layouts and close.
639 * for a migration we need to check data version on file did
641 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
643 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
644 progname, name, strerror(-rc));
651 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
656 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
660 if (flags != 0 && comp_id != 0)
663 /* LCME_FL_INIT is the only supported flag in PFL */
665 if (flags & ~LCME_KNOWN_FLAGS) {
666 fprintf(stderr, "Invalid component flags %#x\n", flags);
669 comp_id = LCME_ID_NONE | flags;
670 } else if (comp_id > LCME_ID_MAX) {
671 fprintf(stderr, "Invalid component id %u\n", comp_id);
675 rc = llapi_layout_file_comp_del(fname, comp_id);
677 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
678 comp_id, fname, strerror(errno));
682 static int lfs_component_add(char *fname, struct llapi_layout *layout)
689 rc = llapi_layout_file_comp_add(fname, layout);
691 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
692 fname, strerror(errno));
696 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
697 struct llapi_layout *layout)
705 fd = lstat(fname, &st);
706 if (fd == 0 && S_ISDIR(st.st_mode)) {
707 open_flags = O_DIRECTORY | O_RDONLY;
708 fd = llapi_layout_file_open(fname, open_flags, open_mode,
711 fd = llapi_layout_file_create(fname, open_flags, open_mode,
716 fprintf(stderr, "%s %s failed. %s\n",
717 S_ISDIR(st.st_mode) ?
718 "Set default composite layout to " :
719 "Create composite file",
720 fname, strerror(errno));
724 static int lfs_migrate(char *name, __u64 migration_flags,
725 struct llapi_stripe_param *param,
726 struct llapi_layout *layout)
730 char parent[PATH_MAX];
733 char volatile_file[sizeof(parent) +
734 LUSTRE_VOLATILE_HDR_LEN +
735 2 * sizeof(mdt_index) +
736 2 * sizeof(random_value) + 4];
739 struct lov_user_md *lum = NULL;
741 int buf_size = 1024 * 1024 * 4;
742 bool have_lease_rdlck = false;
746 /* find the right size for the IO and allocate the buffer */
747 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
748 lum = malloc(lum_size);
754 rc = llapi_file_get_stripe(name, lum);
755 /* failure can happen for many reasons and some may be not real errors
757 * in case of a real error, a later call will fail with better
758 * error management */
760 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
761 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
762 lum->lmm_stripe_size != 0)
763 buf_size = lum->lmm_stripe_size;
766 /* open file, direct io */
767 /* even if the file is only read, WR mode is nedeed to allow
768 * layout swap on fd */
769 fd = open(name, O_RDWR | O_DIRECT);
772 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
777 if (file_lease_supported) {
778 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
779 if (rc == -EOPNOTSUPP) {
780 /* Older servers do not support file lease.
781 * Disable related checks. This opens race conditions
782 * as explained in LU-4840 */
783 file_lease_supported = false;
785 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
786 progname, name, strerror(-rc));
789 have_lease_rdlck = true;
793 /* search for file directory pathname */
794 if (strlen(name) > sizeof(parent)-1) {
798 strncpy(parent, name, sizeof(parent));
799 ptr = strrchr(parent, '/');
801 if (getcwd(parent, sizeof(parent)) == NULL) {
812 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
814 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
815 progname, name, strerror(-rc));
820 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
821 mode_t open_mode = S_IRUSR | S_IWUSR;
823 random_value = random();
824 rc = snprintf(volatile_file, sizeof(volatile_file),
825 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
826 mdt_index, random_value);
827 if (rc >= sizeof(volatile_file)) {
832 /* create, open a volatile file, use caching (ie no directio) */
834 fdv = llapi_file_open_param(volatile_file, open_flags,
836 else if (layout != NULL)
837 fdv = lfs_component_create(volatile_file, open_flags,
841 } while (fdv == -EEXIST);
845 fprintf(stderr, "%s: %s: cannot create volatile file in"
847 progname, parent, strerror(-rc));
851 /* In case the MDT does not support creation of volatile files
852 * we should try to unlink it. */
853 (void)unlink(volatile_file);
855 /* Not-owner (root?) special case.
856 * Need to set owner/group of volatile file like original.
857 * This will allow to pass related check during layout_swap.
862 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
866 rc = fstat(fdv, &stv);
869 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
870 volatile_file, strerror(errno));
873 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
874 rc = fchown(fdv, st.st_uid, st.st_gid);
877 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
878 name, strerror(errno));
883 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
884 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
886 have_lease_rdlck = false;
887 fdv = -1; /* The volatile file is closed as we put the
888 * lease in non-blocking mode. */
891 /* Blocking mode (forced if servers do not support file lease).
892 * It is also the default mode, since we cannot distinguish
893 * between a broken lease and a server that does not support
894 * atomic swap/close (LU-6785) */
895 rc = migrate_block(fd, fdv, &st, buf_size, name);
899 if (have_lease_rdlck)
916 * Parse a string containing an OST index list into an array of integers.
918 * The input string contains a comma delimited list of individual
919 * indices and ranges, for example "1,2-4,7". Add the indices into the
920 * \a osts array and remove duplicates.
922 * \param[out] osts array to store indices in
923 * \param[in] size size of \a osts array
924 * \param[in] offset starting index in \a osts
925 * \param[in] arg string containing OST index list
927 * \retval positive number of indices in \a osts
928 * \retval -EINVAL unable to parse \a arg
930 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
934 int slots = size - offset;
942 while (!end_of_loop) {
950 ptr = strchrnul(arg, ',');
952 end_of_loop = *ptr == '\0';
955 start_index = strtol(arg, &endptr, 0);
956 if (endptr == arg) /* no data at all */
958 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
963 end_index = start_index;
964 if (*endptr == '-') {
965 end_index = strtol(endptr + 1, &endptr, 0);
968 if (end_index < start_index)
972 for (i = start_index; i <= end_index && slots > 0; i++) {
975 /* remove duplicate */
976 for (j = 0; j < offset; j++) {
980 if (j == offset) { /* no duplicate */
985 if (slots == 0 && i < end_index)
993 if (!end_of_loop && ptr != NULL)
996 return rc < 0 ? rc : nr;
999 static int verify_pool_name(char *prog_name, char *pool_name)
1004 if (pool_name == NULL)
1007 ptr = strchr(pool_name, '.');
1011 if (ptr == pool_name) {
1012 fprintf(stderr, "error: %s: fsname is empty "
1013 "in pool name '%s'\n",
1014 prog_name, pool_name);
1020 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1022 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1023 prog_name, pool_name);
1025 } else if (rc == -2) {
1026 fprintf(stderr, "error: %s: pool name '%s' is too long "
1027 "(max is %d characters)\n",
1028 prog_name, pool_name, LOV_MAXPOOLNAME);
1030 } else if (rc > 0) {
1031 fprintf(stderr, "error: %s: char '%c' not allowed in "
1033 prog_name, rc, pool_name);
1039 struct lfs_setstripe_args {
1041 unsigned long long lsa_stripe_size;
1042 int lsa_stripe_count;
1044 __u32 lsa_comp_flags;
1047 char *lsa_pool_name;
1050 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1052 memset(lsa, 0, sizeof(*lsa));
1053 lsa->lsa_stripe_off = -1;
1056 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1058 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1059 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1060 lsa->lsa_comp_end != 0);
1063 static int comp_args_to_layout(struct llapi_layout **composite,
1064 struct lfs_setstripe_args *lsa)
1066 struct llapi_layout *layout = *composite;
1067 uint64_t prev_end = 0;
1070 if (layout == NULL) {
1071 layout = llapi_layout_alloc();
1072 if (layout == NULL) {
1073 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1077 *composite = layout;
1081 /* Get current component extent, current component
1082 * must be the tail component. */
1083 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1085 fprintf(stderr, "Get comp extent failed. %s\n",
1090 rc = llapi_layout_comp_add(layout);
1092 fprintf(stderr, "Add component failed. %s\n",
1098 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1100 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1101 prev_end, lsa->lsa_comp_end, strerror(errno));
1105 if (lsa->lsa_stripe_size != 0) {
1106 rc = llapi_layout_stripe_size_set(layout,
1107 lsa->lsa_stripe_size);
1109 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1110 lsa->lsa_stripe_size, strerror(errno));
1115 if (lsa->lsa_stripe_count != 0) {
1116 rc = llapi_layout_stripe_count_set(layout,
1117 lsa->lsa_stripe_count == -1 ?
1119 lsa->lsa_stripe_count);
1121 fprintf(stderr, "Set stripe count %d failed. %s\n",
1122 lsa->lsa_stripe_count, strerror(errno));
1127 if (lsa->lsa_pool_name != NULL) {
1128 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1130 fprintf(stderr, "Set pool name: %s failed. %s\n",
1131 lsa->lsa_pool_name, strerror(errno));
1136 if (lsa->lsa_nr_osts > 0) {
1137 if (lsa->lsa_stripe_count > 0 &&
1138 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1139 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1140 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1143 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1144 rc = llapi_layout_ost_index_set(layout, i,
1149 } else if (lsa->lsa_stripe_off != -1) {
1150 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1153 fprintf(stderr, "Set ost index %d failed. %s\n",
1154 i, strerror(errno));
1161 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1162 * end of the last component in the existing file, and adjust the
1163 * first extent start of the components to be added accordingly. */
1164 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1166 struct llapi_layout *head;
1167 uint64_t start, end, stripe_size, prev_end = 0;
1173 head = llapi_layout_get_by_path(fname, 0);
1175 fprintf(stderr, "Read layout from %s failed. %s\n",
1176 fname, strerror(errno));
1180 /* Current component of 'head' should be tail of component list. */
1181 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1183 fprintf(stderr, "Get prev extent failed. %s\n",
1185 llapi_layout_free(head);
1189 llapi_layout_free(head);
1191 /* Make sure we use the first component of the layout to be added. */
1192 rc = llapi_layout_comp_move(layout, LLAPI_LAYOUT_COMP_POS_FIRST);
1194 fprintf(stderr, "Move component cursor failed. %s\n",
1199 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1201 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1205 if (start > prev_end || end <= prev_end) {
1206 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1207 "adjacent with the existing file extent end: %lu\n",
1208 start, end, prev_end);
1212 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1214 fprintf(stderr, "Get stripe size failed. %s\n",
1219 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1220 (prev_end & (stripe_size - 1))) {
1221 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1222 stripe_size, prev_end);
1226 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1228 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1229 prev_end, end, strerror(errno));
1236 static int comp_name2flags(__u32 *flags, char *name)
1244 for (ptr = name; ; ptr = NULL) {
1245 char *flg = strtok(ptr, ",");
1248 if (strcmp(flg, "init") == 0)
1249 *flags |= LCME_FL_INIT;
1253 return (*flags == 0) ? -EINVAL : 0;
1267 static int lfs_setstripe(int argc, char **argv)
1269 struct lfs_setstripe_args lsa;
1270 struct llapi_stripe_param *param = NULL;
1271 struct find_param migrate_mdt_param = {
1281 char *mdt_idx_arg = NULL;
1282 unsigned long long size_units = 1;
1283 bool migrate_mode = false;
1284 bool migration_block = false;
1285 __u64 migration_flags = 0;
1286 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1287 int comp_del = 0, comp_set = 0;
1290 struct llapi_layout *layout = NULL;
1292 struct option long_opts[] = {
1293 /* --block is only valid in migrate mode */
1294 {"block", no_argument, 0, 'b'},
1295 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1296 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1297 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1298 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1299 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1300 /* This formerly implied "stripe-count", but was explicitly
1301 * made "stripe-count" for consistency with other options,
1302 * and to separate it from "mdt-count" when DNE arrives. */
1303 {"count", required_argument, 0, 'c'},
1305 {"stripe-count", required_argument, 0, 'c'},
1306 {"stripe_count", required_argument, 0, 'c'},
1307 {"delete", no_argument, 0, 'd'},
1308 {"component-end", required_argument, 0, 'E'},
1309 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1310 /* This formerly implied "stripe-index", but was explicitly
1311 * made "stripe-index" for consistency with other options,
1312 * and to separate it from "mdt-index" when DNE arrives. */
1313 {"index", required_argument, 0, 'i'},
1315 {"stripe-index", required_argument, 0, 'i'},
1316 {"stripe_index", required_argument, 0, 'i'},
1317 {"component-id", required_argument, 0, 'I'},
1318 {"mdt", required_argument, 0, 'm'},
1319 {"mdt-index", required_argument, 0, 'm'},
1320 {"mdt_index", required_argument, 0, 'm'},
1321 /* --non-block is only valid in migrate mode */
1322 {"non-block", no_argument, 0, 'n'},
1323 {"ost", required_argument, 0, 'o'},
1324 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1325 {"ost-list", required_argument, 0, 'o'},
1326 {"ost_list", required_argument, 0, 'o'},
1328 {"pool", required_argument, 0, 'p'},
1329 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1330 /* This formerly implied "--stripe-size", but was confusing
1331 * with "lfs find --size|-s", which means "file size", so use
1332 * the consistent "--stripe-size|-S" for all commands. */
1333 {"size", required_argument, 0, 's'},
1335 {"stripe-size", required_argument, 0, 'S'},
1336 {"stripe_size", required_argument, 0, 'S'},
1337 /* --verbose is only valid in migrate mode */
1338 {"verbose", no_argument, 0, 'v'},
1342 setstripe_args_init(&lsa);
1344 if (strcmp(argv[0], "migrate") == 0)
1345 migrate_mode = true;
1347 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1348 long_opts, NULL)) >= 0) {
1353 case LFS_COMP_ADD_OPT:
1356 case LFS_COMP_DEL_OPT:
1359 case LFS_COMP_FLAGS_OPT:
1360 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1362 fprintf(stderr, "error: %s: bad comp flags "
1363 "'%s'\n", argv[0], optarg);
1367 case LFS_COMP_SET_OPT:
1371 if (!migrate_mode) {
1372 fprintf(stderr, "--block is valid only for"
1376 migration_block = true;
1379 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1380 if (strcmp(argv[optind - 1], "--count") == 0)
1381 fprintf(stderr, "warning: '--count' deprecated"
1382 ", use '--stripe-count' instead\n");
1384 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1386 fprintf(stderr, "error: %s: bad stripe count "
1387 "'%s'\n", argv[0], optarg);
1392 /* delete the default striping pattern */
1396 if (lsa.lsa_comp_end != 0) {
1397 result = comp_args_to_layout(&layout, &lsa);
1401 setstripe_args_init(&lsa);
1404 if (!strncmp(optarg, "-1", strlen("-1")) ||
1405 !strncmp(optarg, "EOF", strlen("EOF")) ||
1406 !strncmp(optarg, "eof", strlen("eof"))) {
1407 lsa.lsa_comp_end = LUSTRE_EOF;
1409 result = llapi_parse_size(optarg,
1413 fprintf(stderr, "error: %s: "
1414 "bad component end '%s'\n",
1421 if (strcmp(argv[optind - 1], "--index") == 0)
1422 fprintf(stderr, "warning: '--index' deprecated"
1423 ", use '--stripe-index' instead\n");
1424 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1426 fprintf(stderr, "error: %s: bad stripe offset "
1427 "'%s'\n", argv[0], optarg);
1432 comp_id = strtoul(optarg, &end, 0);
1433 if (*end != '\0' || comp_id == 0) {
1434 fprintf(stderr, "error: %s: bad comp ID "
1435 "'%s'\n", argv[0], optarg);
1440 if (!migrate_mode) {
1441 fprintf(stderr, "--mdt-index is valid only for"
1445 mdt_idx_arg = optarg;
1448 if (!migrate_mode) {
1449 fprintf(stderr, "--non-block is valid only for"
1453 migration_flags |= MIGRATION_NONBLOCK;
1456 lsa.lsa_nr_osts = parse_targets(osts,
1457 sizeof(osts) / sizeof(__u32),
1458 lsa.lsa_nr_osts, optarg);
1459 if (lsa.lsa_nr_osts < 0) {
1461 "error: %s: bad OST indices '%s'\n",
1466 lsa.lsa_osts = osts;
1467 if (lsa.lsa_stripe_off == -1)
1468 lsa.lsa_stripe_off = osts[0];
1471 result = verify_pool_name(argv[0], optarg);
1474 lsa.lsa_pool_name = optarg;
1476 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1478 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1479 fprintf(stderr, "warning: '--size|-s' deprecated, "
1480 "use '--stripe-size|-S' instead\n");
1482 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1484 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1487 fprintf(stderr, "error: %s: bad stripe size "
1488 "'%s'\n", argv[0], optarg);
1493 if (!migrate_mode) {
1494 fprintf(stderr, "--verbose is valid only for"
1498 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1505 fname = argv[optind];
1507 if (lsa.lsa_comp_end != 0) {
1508 result = comp_args_to_layout(&layout, &lsa);
1513 if (optind == argc) {
1514 fprintf(stderr, "error: %s: missing filename|dirname\n",
1519 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1520 * altered by user space tool, so we don't need to support the
1521 * --component-set for this moment. */
1522 if (comp_set != 0) {
1523 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1528 if ((delete + comp_set + comp_del + comp_add) > 1) {
1529 fprintf(stderr, "error: %s: can't specify --component-set, "
1530 "--component-del, --component-add or -d together\n",
1535 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1536 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1537 fprintf(stderr, "error: %s: can't specify -d with "
1538 "-s, -c, -o, -p, -I, -F or -E options\n",
1543 if ((comp_set || comp_del) &&
1544 (setstripe_args_specified(&lsa) || layout != NULL)) {
1545 fprintf(stderr, "error: %s: can't specify --component-del or "
1546 "--component-set with -s, -c, -o, -p or -E options.\n",
1551 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1552 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1553 "--component-del option.\n", argv[0]);
1558 if (layout == NULL) {
1559 fprintf(stderr, "error: %s: -E option must be present"
1560 "in --component-add mode.\n", argv[0]);
1563 result = adjust_first_extent(fname, layout);
1568 if (mdt_idx_arg != NULL && optind > 3) {
1569 fprintf(stderr, "error: %s: cannot specify -m with other "
1570 "options\n", argv[0]);
1574 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1576 "error: %s: cannot specify --non-block and --block\n",
1581 /* support --component-id option for migrate later. */
1582 if (migrate_mode && comp_id != 0) {
1583 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1588 if (mdt_idx_arg != NULL) {
1589 /* initialize migrate mdt parameters */
1590 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1592 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1593 argv[0], mdt_idx_arg);
1596 migrate_mdt_param.fp_migrate = 1;
1597 } else if (layout == NULL) {
1598 /* initialize stripe parameters */
1599 param = calloc(1, offsetof(typeof(*param),
1600 lsp_osts[lsa.lsa_nr_osts]));
1601 if (param == NULL) {
1602 fprintf(stderr, "error: %s: %s\n", argv[0],
1607 param->lsp_stripe_size = lsa.lsa_stripe_size;
1608 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1609 param->lsp_stripe_count = lsa.lsa_stripe_count;
1610 param->lsp_stripe_pattern = 0;
1611 param->lsp_pool = lsa.lsa_pool_name;
1612 param->lsp_is_specific = false;
1613 if (lsa.lsa_nr_osts > 0) {
1614 if (lsa.lsa_stripe_count > 0 &&
1615 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1616 fprintf(stderr, "error: %s: stripe count '%d' "
1617 "doesn't match the number of OSTs: %d\n"
1618 , argv[0], lsa.lsa_stripe_count,
1624 param->lsp_is_specific = true;
1625 param->lsp_stripe_count = lsa.lsa_nr_osts;
1626 memcpy(param->lsp_osts, osts,
1627 sizeof(*osts) * lsa.lsa_nr_osts);
1631 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1633 if (mdt_idx_arg != NULL) {
1634 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1635 op = "migrate mdt objects of";
1636 } else if (migrate_mode) {
1637 result = lfs_migrate(fname, migration_flags, param,
1639 op = "migrate ost objects of";
1640 } else if (comp_set != 0) {
1641 result = lfs_component_set(fname, comp_id,
1642 lsa.lsa_comp_flags);
1643 op = "modify component flags of";
1644 } else if (comp_del != 0) {
1645 result = lfs_component_del(fname, comp_id,
1646 lsa.lsa_comp_flags);
1647 op = "delete component of";
1648 } else if (comp_add != 0) {
1649 result = lfs_component_add(fname, layout);
1650 op = "add component to";
1651 } else if (layout != NULL) {
1652 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1658 op = "create composite";
1660 result = llapi_file_open_param(fname,
1667 op = "create striped";
1670 /* Save the first error encountered. */
1673 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1675 lsa.lsa_pool_name != NULL && result == EINVAL ?
1676 "OST not in pool?" : strerror(errno));
1682 llapi_layout_free(layout);
1685 llapi_layout_free(layout);
1689 static int lfs_poollist(int argc, char **argv)
1694 return llapi_poollist(argv[1]);
1697 static int set_time(time_t *time, time_t *set, char *str)
1704 else if (str[0] == '-')
1710 t = strtol(str, NULL, 0);
1711 if (*time < t * 24 * 60 * 60) {
1714 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1718 *set = *time - t * 24 * 60 * 60;
1721 static int name2uid(unsigned int *id, const char *name)
1723 struct passwd *passwd;
1725 passwd = getpwnam(name);
1728 *id = passwd->pw_uid;
1733 static int name2gid(unsigned int *id, const char *name)
1735 struct group *group;
1737 group = getgrnam(name);
1740 *id = group->gr_gid;
1745 static int uid2name(char **name, unsigned int id)
1747 struct passwd *passwd;
1749 passwd = getpwuid(id);
1752 *name = passwd->pw_name;
1757 static inline int gid2name(char **name, unsigned int id)
1759 struct group *group;
1761 group = getgrgid(id);
1764 *name = group->gr_name;
1769 static int name2layout(__u32 *layout, char *name)
1774 for (ptr = name; ; ptr = NULL) {
1775 lyt = strtok(ptr, ",");
1778 if (strcmp(lyt, "released") == 0)
1779 *layout |= LOV_PATTERN_F_RELEASED;
1780 else if (strcmp(lyt, "raid0") == 0)
1781 *layout |= LOV_PATTERN_RAID0;
1788 static int lfs_find(int argc, char **argv)
1793 struct find_param param = {
1797 struct option long_opts[] = {
1798 {"atime", required_argument, 0, 'A'},
1799 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1800 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1801 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1802 {"stripe-count", required_argument, 0, 'c'},
1803 {"stripe_count", required_argument, 0, 'c'},
1804 {"ctime", required_argument, 0, 'C'},
1805 {"maxdepth", required_argument, 0, 'D'},
1806 {"component-end", required_argument, 0, 'E'},
1807 {"gid", required_argument, 0, 'g'},
1808 {"group", required_argument, 0, 'G'},
1809 {"stripe-index", required_argument, 0, 'i'},
1810 {"stripe_index", required_argument, 0, 'i'},
1811 /*{"component-id", required_argument, 0, 'I'},*/
1812 {"layout", required_argument, 0, 'L'},
1813 {"mdt", required_argument, 0, 'm'},
1814 {"mdt-index", required_argument, 0, 'm'},
1815 {"mdt_index", required_argument, 0, 'm'},
1816 {"mtime", required_argument, 0, 'M'},
1817 {"name", required_argument, 0, 'n'},
1818 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1819 {"obd", required_argument, 0, 'O'},
1820 {"ost", required_argument, 0, 'O'},
1821 /* no short option for pool, p/P already used */
1822 {"pool", required_argument, 0, LFS_POOL_OPT},
1823 {"print0", no_argument, 0, 'p'},
1824 {"print", no_argument, 0, 'P'},
1825 {"size", required_argument, 0, 's'},
1826 {"stripe-size", required_argument, 0, 'S'},
1827 {"stripe_size", required_argument, 0, 'S'},
1828 {"type", required_argument, 0, 't'},
1829 {"uid", required_argument, 0, 'u'},
1830 {"user", required_argument, 0, 'U'},
1843 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1844 while ((c = getopt_long_only(argc, argv,
1845 "-A:c:C:D:E:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1846 long_opts, NULL)) >= 0) {
1851 /* '!' is part of option */
1852 /* when getopt_long_only() finds a string which is not
1853 * an option nor a known option argument it returns 1
1854 * in that case if we already have found pathstart and pathend
1855 * (i.e. we have the list of pathnames),
1856 * the only supported value is "!"
1858 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1859 if (!isoption && pathend != -1) {
1860 fprintf(stderr, "err: %s: filename|dirname must either "
1861 "precede options or follow options\n",
1866 if (!isoption && pathstart == -1)
1867 pathstart = optind - 1;
1868 if (isoption && pathstart != -1 && pathend == -1)
1869 pathend = optind - 2;
1875 /* unknown; opt is "!" or path component,
1876 * checking done above.
1878 if (strcmp(optarg, "!") == 0)
1882 xtime = ¶m.fp_atime;
1883 xsign = ¶m.fp_asign;
1884 param.fp_exclude_atime = !!neg_opt;
1885 /* no break, this falls through to 'C' for ctime */
1888 xtime = ¶m.fp_ctime;
1889 xsign = ¶m.fp_csign;
1890 param.fp_exclude_ctime = !!neg_opt;
1892 /* no break, this falls through to 'M' for mtime */
1895 xtime = ¶m.fp_mtime;
1896 xsign = ¶m.fp_msign;
1897 param.fp_exclude_mtime = !!neg_opt;
1899 rc = set_time(&t, xtime, optarg);
1900 if (rc == INT_MAX) {
1907 case LFS_COMP_COUNT_OPT:
1908 if (optarg[0] == '+') {
1909 param.fp_comp_count_sign = -1;
1911 } else if (optarg[0] == '-') {
1912 param.fp_comp_count_sign = 1;
1916 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1917 if (*endptr != '\0') {
1918 fprintf(stderr, "error: bad component count "
1922 param.fp_check_comp_count = 1;
1923 param.fp_exclude_comp_count = !!neg_opt;
1925 case LFS_COMP_FLAGS_OPT:
1926 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1928 fprintf(stderr, "error: bad component flags "
1932 param.fp_check_comp_flags = 1;
1933 param.fp_exclude_comp_flags = !!neg_opt;
1935 case LFS_COMP_START_OPT:
1936 if (optarg[0] == '+') {
1937 param.fp_comp_start_sign = -1;
1939 } else if (optarg[0] == '-') {
1940 param.fp_comp_start_sign = 1;
1944 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1945 ¶m.fp_comp_start_units, 0);
1947 fprintf(stderr, "error: bad component start "
1951 param.fp_check_comp_start = 1;
1952 param.fp_exclude_comp_start = !!neg_opt;
1955 if (optarg[0] == '+') {
1956 param.fp_stripe_count_sign = -1;
1958 } else if (optarg[0] == '-') {
1959 param.fp_stripe_count_sign = 1;
1963 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1964 if (*endptr != '\0') {
1965 fprintf(stderr,"error: bad stripe_count '%s'\n",
1970 param.fp_check_stripe_count = 1;
1971 param.fp_exclude_stripe_count = !!neg_opt;
1974 param.fp_max_depth = strtol(optarg, 0, 0);
1977 if (optarg[0] == '+') {
1978 param.fp_comp_end_sign = -1;
1980 } else if (optarg[0] == '-') {
1981 param.fp_comp_end_sign = 1;
1985 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
1986 ¶m.fp_comp_end_units, 0);
1988 fprintf(stderr, "error: bad component end "
1992 param.fp_check_comp_end = 1;
1993 param.fp_exclude_comp_end = !!neg_opt;
1997 rc = name2gid(¶m.fp_gid, optarg);
1999 param.fp_gid = strtoul(optarg, &endptr, 10);
2000 if (*endptr != '\0') {
2001 fprintf(stderr, "Group/GID: %s cannot "
2002 "be found.\n", optarg);
2007 param.fp_exclude_gid = !!neg_opt;
2008 param.fp_check_gid = 1;
2011 ret = name2layout(¶m.fp_layout, optarg);
2014 param.fp_exclude_layout = !!neg_opt;
2015 param.fp_check_layout = 1;
2019 rc = name2uid(¶m.fp_uid, optarg);
2021 param.fp_uid = strtoul(optarg, &endptr, 10);
2022 if (*endptr != '\0') {
2023 fprintf(stderr, "User/UID: %s cannot "
2024 "be found.\n", optarg);
2029 param.fp_exclude_uid = !!neg_opt;
2030 param.fp_check_uid = 1;
2033 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2035 "Pool name %s is too long"
2036 " (max is %d)\n", optarg,
2041 /* we do check for empty pool because empty pool
2042 * is used to find V1 lov attributes */
2043 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2044 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2045 param.fp_exclude_pool = !!neg_opt;
2046 param.fp_check_pool = 1;
2049 param.fp_pattern = (char *)optarg;
2050 param.fp_exclude_pattern = !!neg_opt;
2055 char *buf, *token, *next, *p;
2059 buf = strdup(optarg);
2065 param.fp_exclude_obd = !!neg_opt;
2068 while (token && *token) {
2069 token = strchr(token, ',');
2076 param.fp_exclude_mdt = !!neg_opt;
2077 param.fp_num_alloc_mdts += len;
2078 tmp = realloc(param.fp_mdt_uuid,
2079 param.fp_num_alloc_mdts *
2080 sizeof(*param.fp_mdt_uuid));
2086 param.fp_mdt_uuid = tmp;
2088 param.fp_exclude_obd = !!neg_opt;
2089 param.fp_num_alloc_obds += len;
2090 tmp = realloc(param.fp_obd_uuid,
2091 param.fp_num_alloc_obds *
2092 sizeof(*param.fp_obd_uuid));
2098 param.fp_obd_uuid = tmp;
2100 for (token = buf; token && *token; token = next) {
2101 struct obd_uuid *puuid;
2104 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2107 ¶m.fp_obd_uuid[param.fp_num_obds++];
2109 p = strchr(token, ',');
2116 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2121 strncpy(puuid->uuid, token,
2122 sizeof(puuid->uuid));
2130 param.fp_zero_end = 1;
2135 if (optarg[0] == '+') {
2136 param.fp_size_sign = -1;
2138 } else if (optarg[0] == '-') {
2139 param.fp_size_sign = 1;
2143 ret = llapi_parse_size(optarg, ¶m.fp_size,
2144 ¶m.fp_size_units, 0);
2146 fprintf(stderr, "error: bad file size '%s'\n",
2150 param.fp_check_size = 1;
2151 param.fp_exclude_size = !!neg_opt;
2154 if (optarg[0] == '+') {
2155 param.fp_stripe_size_sign = -1;
2157 } else if (optarg[0] == '-') {
2158 param.fp_stripe_size_sign = 1;
2162 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2163 ¶m.fp_stripe_size_units, 0);
2165 fprintf(stderr, "error: bad stripe_size '%s'\n",
2169 param.fp_check_stripe_size = 1;
2170 param.fp_exclude_stripe_size = !!neg_opt;
2173 param.fp_exclude_type = !!neg_opt;
2174 switch (optarg[0]) {
2176 param.fp_type = S_IFBLK;
2179 param.fp_type = S_IFCHR;
2182 param.fp_type = S_IFDIR;
2185 param.fp_type = S_IFREG;
2188 param.fp_type = S_IFLNK;
2191 param.fp_type = S_IFIFO;
2194 param.fp_type = S_IFSOCK;
2197 fprintf(stderr, "error: %s: bad type '%s'\n",
2209 if (pathstart == -1) {
2210 fprintf(stderr, "error: %s: no filename|pathname\n",
2214 } else if (pathend == -1) {
2220 rc = llapi_find(argv[pathstart], ¶m);
2221 if (rc != 0 && ret == 0)
2223 } while (++pathstart < pathend);
2226 fprintf(stderr, "error: %s failed for %s.\n",
2227 argv[0], argv[optind - 1]);
2229 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2230 free(param.fp_obd_uuid);
2232 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2233 free(param.fp_mdt_uuid);
2238 static int lfs_getstripe_internal(int argc, char **argv,
2239 struct find_param *param)
2241 struct option long_opts[] = {
2242 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2243 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2244 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2245 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2246 /* This formerly implied "stripe-count", but was explicitly
2247 * made "stripe-count" for consistency with other options,
2248 * and to separate it from "mdt-count" when DNE arrives. */
2249 {"count", no_argument, 0, 'c'},
2251 {"stripe-count", no_argument, 0, 'c'},
2252 {"stripe_count", no_argument, 0, 'c'},
2253 {"directory", no_argument, 0, 'd'},
2254 {"default", no_argument, 0, 'D'},
2255 {"component-end", required_argument, 0, 'E'},
2256 {"fid", no_argument, 0, 'F'},
2257 {"generation", no_argument, 0, 'g'},
2258 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2259 /* This formerly implied "stripe-index", but was explicitly
2260 * made "stripe-index" for consistency with other options,
2261 * and to separate it from "mdt-index" when DNE arrives. */
2262 {"index", no_argument, 0, 'i'},
2264 {"stripe-index", no_argument, 0, 'i'},
2265 {"stripe_index", no_argument, 0, 'i'},
2266 {"component-id", required_argument, 0, 'I'},
2267 {"layout", no_argument, 0, 'L'},
2268 {"mdt", no_argument, 0, 'm'},
2269 {"mdt-index", no_argument, 0, 'm'},
2270 {"mdt_index", no_argument, 0, 'm'},
2271 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2272 {"mdt-index", no_argument, 0, 'M'},
2273 {"mdt_index", no_argument, 0, 'M'},
2275 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2276 /* This formerly implied "stripe-index", but was confusing
2277 * with "file offset" (which will eventually be needed for
2278 * with different layouts by offset), so deprecate it. */
2279 {"offset", no_argument, 0, 'o'},
2281 {"obd", required_argument, 0, 'O'},
2282 {"ost", required_argument, 0, 'O'},
2283 {"pool", no_argument, 0, 'p'},
2284 {"quiet", no_argument, 0, 'q'},
2285 {"recursive", no_argument, 0, 'r'},
2286 {"raw", no_argument, 0, 'R'},
2287 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2288 /* This formerly implied "--stripe-size", but was confusing
2289 * with "lfs find --size|-s", which means "file size", so use
2290 * the consistent "--stripe-size|-S" for all commands. */
2291 {"size", no_argument, 0, 's'},
2293 {"stripe-size", no_argument, 0, 'S'},
2294 {"stripe_size", no_argument, 0, 'S'},
2295 {"verbose", no_argument, 0, 'v'},
2301 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2302 long_opts, NULL)) != -1) {
2305 if (param->fp_obd_uuid) {
2307 "error: %s: only one obduuid allowed",
2311 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2316 case LFS_COMP_COUNT_OPT:
2317 param->fp_verbose |= VERBOSE_COMP_COUNT;
2318 param->fp_max_depth = 0;
2320 case LFS_COMP_FLAGS_OPT:
2321 if (optarg != NULL) {
2322 rc = comp_name2flags(¶m->fp_comp_flags,
2325 param->fp_verbose |=
2327 param->fp_max_depth = 0;
2330 param->fp_check_comp_flags = 1;
2333 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2334 param->fp_max_depth = 0;
2337 case LFS_COMP_START_OPT:
2338 if (optarg != NULL) {
2340 if (tmp[0] == '+') {
2341 param->fp_comp_start_sign = 1;
2343 } else if (tmp[0] == '-') {
2344 param->fp_comp_start_sign = -1;
2347 rc = llapi_parse_size(tmp,
2348 ¶m->fp_comp_start,
2349 ¶m->fp_comp_start_units, 0);
2351 param->fp_verbose |= VERBOSE_COMP_START;
2352 param->fp_max_depth = 0;
2355 param->fp_check_comp_start = 1;
2358 param->fp_verbose |= VERBOSE_COMP_START;
2359 param->fp_max_depth = 0;
2363 param->fp_max_depth = 0;
2366 param->fp_get_default_lmv = 1;
2369 if (optarg != NULL) {
2371 if (tmp[0] == '+') {
2372 param->fp_comp_end_sign = 1;
2374 } else if (tmp[0] == '-') {
2375 param->fp_comp_end_sign = -1;
2378 rc = llapi_parse_size(tmp,
2379 ¶m->fp_comp_end,
2380 ¶m->fp_comp_end_units, 0);
2382 param->fp_verbose |= VERBOSE_COMP_END;
2383 param->fp_max_depth = 0;
2386 param->fp_check_comp_end = 1;
2389 param->fp_verbose |= VERBOSE_COMP_END;
2390 param->fp_max_depth = 0;
2394 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2395 param->fp_verbose |= VERBOSE_DFID;
2396 param->fp_max_depth = 0;
2400 param->fp_recursive = 1;
2403 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2406 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2407 if (strcmp(argv[optind - 1], "--count") == 0)
2408 fprintf(stderr, "warning: '--count' deprecated,"
2409 " use '--stripe-count' instead\n");
2411 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2412 param->fp_verbose |= VERBOSE_COUNT;
2413 param->fp_max_depth = 0;
2416 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2418 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2419 fprintf(stderr, "warning: '--size|-s' deprecated, "
2420 "use '--stripe-size|-S' instead\n");
2422 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2424 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2425 param->fp_verbose |= VERBOSE_SIZE;
2426 param->fp_max_depth = 0;
2429 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2431 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2432 "use '--stripe-index|-i' instead\n");
2435 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2436 if (strcmp(argv[optind - 1], "--index") == 0)
2437 fprintf(stderr, "warning: '--index' deprecated"
2438 ", use '--stripe-index' instead\n");
2440 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2441 param->fp_verbose |= VERBOSE_OFFSET;
2442 param->fp_max_depth = 0;
2446 if (optarg != NULL) {
2447 param->fp_comp_id = strtoul(optarg, &end, 0);
2449 param->fp_verbose |= VERBOSE_COMP_ID;
2450 param->fp_max_depth = 0;
2453 param->fp_check_comp_id = 1;
2456 param->fp_max_depth = 0;
2457 param->fp_verbose |= VERBOSE_COMP_ID;
2461 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2462 param->fp_verbose |= VERBOSE_POOL;
2463 param->fp_max_depth = 0;
2467 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2468 param->fp_verbose |= VERBOSE_GENERATION;
2469 param->fp_max_depth = 0;
2473 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2474 param->fp_verbose |= VERBOSE_LAYOUT;
2475 param->fp_max_depth = 0;
2478 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2480 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2481 fprintf(stderr, "warning: '-M' deprecated"
2482 ", use '-m' instead\n");
2486 if (!(param->fp_verbose & VERBOSE_DETAIL))
2487 param->fp_max_depth = 0;
2488 param->fp_verbose |= VERBOSE_MDTINDEX;
2501 if (param->fp_recursive)
2502 param->fp_max_depth = -1;
2503 else if (param->fp_verbose & VERBOSE_DETAIL)
2504 param->fp_max_depth = 1;
2506 if (!param->fp_verbose)
2507 param->fp_verbose = VERBOSE_DEFAULT;
2508 if (param->fp_quiet)
2509 param->fp_verbose = VERBOSE_OBJID;
2512 rc = llapi_getstripe(argv[optind], param);
2513 } while (++optind < argc && !rc);
2516 fprintf(stderr, "error: %s failed for %s.\n",
2517 argv[0], argv[optind - 1]);
2521 static int lfs_tgts(int argc, char **argv)
2523 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2524 struct find_param param;
2525 int index = 0, rc=0;
2530 if (argc == 2 && !realpath(argv[1], path)) {
2532 fprintf(stderr, "error: invalid path '%s': %s\n",
2533 argv[1], strerror(-rc));
2537 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2538 /* Check if we have a mount point */
2539 if (mntdir[0] == '\0')
2542 memset(¶m, 0, sizeof(param));
2543 if (!strcmp(argv[0], "mdts"))
2544 param.fp_get_lmv = 1;
2546 rc = llapi_ostlist(mntdir, ¶m);
2548 fprintf(stderr, "error: %s: failed on %s\n",
2551 if (path[0] != '\0')
2553 memset(mntdir, 0, PATH_MAX);
2559 static int lfs_getstripe(int argc, char **argv)
2561 struct find_param param = { 0 };
2563 param.fp_max_depth = 1;
2564 return lfs_getstripe_internal(argc, argv, ¶m);
2568 static int lfs_getdirstripe(int argc, char **argv)
2570 struct find_param param = { 0 };
2571 struct option long_opts[] = {
2572 {"mdt-count", no_argument, 0, 'c'},
2573 {"mdt-index", no_argument, 0, 'i'},
2574 {"recursive", no_argument, 0, 'r'},
2575 {"mdt-hash", no_argument, 0, 't'},
2576 {"default", no_argument, 0, 'D'},
2577 {"obd", required_argument, 0, 'O'},
2582 param.fp_get_lmv = 1;
2584 while ((c = getopt_long(argc, argv, "cirtDO:", long_opts, NULL)) != -1)
2588 if (param.fp_obd_uuid) {
2590 "error: %s: only one obduuid allowed",
2594 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2597 param.fp_verbose |= VERBOSE_COUNT;
2600 param.fp_verbose |= VERBOSE_OFFSET;
2603 param.fp_verbose |= VERBOSE_HASH_TYPE;
2606 param.fp_get_default_lmv = 1;
2609 param.fp_recursive = 1;
2619 if (param.fp_recursive)
2620 param.fp_max_depth = -1;
2622 if (!param.fp_verbose)
2623 param.fp_verbose = VERBOSE_DEFAULT;
2626 rc = llapi_getstripe(argv[optind], ¶m);
2627 } while (++optind < argc && !rc);
2630 fprintf(stderr, "error: %s failed for %s.\n",
2631 argv[0], argv[optind - 1]);
2636 static int lfs_setdirstripe(int argc, char **argv)
2640 unsigned int stripe_offset = -1;
2641 unsigned int stripe_count = 1;
2642 enum lmv_hash_type hash_type;
2645 char *stripe_offset_opt = NULL;
2646 char *stripe_count_opt = NULL;
2647 char *stripe_hash_opt = NULL;
2648 char *mode_opt = NULL;
2649 bool default_stripe = false;
2650 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2651 mode_t previous_mode = 0;
2652 bool delete = false;
2654 struct option long_opts[] = {
2655 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2656 {"count", required_argument, 0, 'c'},
2658 {"mdt-count", required_argument, 0, 'c'},
2659 {"delete", no_argument, 0, 'd'},
2660 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2661 {"index", required_argument, 0, 'i'},
2663 {"mdt-index", required_argument, 0, 'i'},
2664 {"mode", required_argument, 0, 'm'},
2665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2666 {"hash-type", required_argument, 0, 't'},
2668 {"mdt-hash", required_argument, 0, 't'},
2669 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2670 {"default_stripe", no_argument, 0, 'D'},
2672 {"default", no_argument, 0, 'D'},
2676 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2683 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2684 if (strcmp(argv[optind - 1], "--count") == 0)
2685 fprintf(stderr, "warning: '--count' deprecated"
2686 ", use '--mdt-count' instead\n");
2688 stripe_count_opt = optarg;
2692 default_stripe = true;
2695 default_stripe = true;
2698 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2699 if (strcmp(argv[optind - 1], "--index") == 0)
2700 fprintf(stderr, "warning: '--index' deprecated"
2701 ", use '--mdt-index' instead\n");
2703 stripe_offset_opt = optarg;
2709 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2710 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2711 fprintf(stderr, "warning: '--hash-type' "
2712 "deprecated, use '--mdt-hash' "
2715 stripe_hash_opt = optarg;
2718 fprintf(stderr, "error: %s: option '%s' "
2720 argv[0], argv[optind - 1]);
2725 if (optind == argc) {
2726 fprintf(stderr, "error: %s: missing dirname\n",
2731 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2732 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2737 if (stripe_offset_opt != NULL) {
2738 /* get the stripe offset */
2739 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2741 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2742 argv[0], stripe_offset_opt);
2748 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2749 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2750 " or -i options.\n", argv[0]);
2758 if (mode_opt != NULL) {
2759 mode = strtoul(mode_opt, &end, 8);
2761 fprintf(stderr, "error: %s: bad mode '%s'\n",
2765 previous_mode = umask(0);
2768 if (stripe_hash_opt == NULL) {
2769 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2773 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
2774 if (strcmp(stripe_hash_opt, mdt_hash_name[i]) == 0)
2777 if (i == LMV_HASH_TYPE_MAX) {
2779 "error: %s: bad stripe hash type '%s'\n",
2780 argv[0], stripe_hash_opt);
2787 /* get the stripe count */
2788 if (stripe_count_opt != NULL) {
2789 stripe_count = strtoul(stripe_count_opt, &end, 0);
2791 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2792 argv[0], stripe_count_opt);
2797 dname = argv[optind];
2799 if (default_stripe) {
2800 result = llapi_dir_set_default_lmv_stripe(dname,
2801 stripe_offset, stripe_count,
2804 result = llapi_dir_create_pool(dname, mode,
2806 stripe_count, hash_type,
2811 fprintf(stderr, "error: %s: create stripe dir '%s' "
2812 "failed\n", argv[0], dname);
2815 dname = argv[++optind];
2816 } while (dname != NULL);
2818 if (mode_opt != NULL)
2819 umask(previous_mode);
2825 static int lfs_rmentry(int argc, char **argv)
2832 fprintf(stderr, "error: %s: missing dirname\n",
2838 dname = argv[index];
2839 while (dname != NULL) {
2840 result = llapi_direntry_remove(dname);
2842 fprintf(stderr, "error: %s: remove dir entry '%s' "
2843 "failed\n", argv[0], dname);
2846 dname = argv[++index];
2851 static int lfs_mv(int argc, char **argv)
2853 struct find_param param = {
2860 struct option long_opts[] = {
2861 {"mdt-index", required_argument, 0, 'M'},
2862 {"verbose", no_argument, 0, 'v'},
2866 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2869 param.fp_mdt_index = strtoul(optarg, &end, 0);
2871 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2878 param.fp_verbose = VERBOSE_DETAIL;
2882 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2883 argv[0], argv[optind - 1]);
2888 if (param.fp_mdt_index == -1) {
2889 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2893 if (optind >= argc) {
2894 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2898 param.fp_migrate = 1;
2899 rc = llapi_migrate_mdt(argv[optind], ¶m);
2901 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2902 argv[0], argv[optind], param.fp_mdt_index,
2907 static int lfs_osts(int argc, char **argv)
2909 return lfs_tgts(argc, argv);
2912 static int lfs_mdts(int argc, char **argv)
2914 return lfs_tgts(argc, argv);
2917 #define COOK(value) \
2920 while (value > 1024) { \
2928 #define CDF "%11llu"
2929 #define HDF "%8.1f%c"
2934 MNTDF_INODES = 0x0001,
2935 MNTDF_COOKED = 0x0002,
2936 MNTDF_LAZY = 0x0004,
2937 MNTDF_VERBOSE = 0x0008,
2940 static int showdf(char *mntdir, struct obd_statfs *stat,
2941 char *uuid, enum mntdf_flags flags,
2942 char *type, int index, int rc)
2944 long long avail, used, total;
2946 char *suffix = "KMGTPEZY";
2947 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2948 char tbuf[3 * sizeof(__u64)];
2949 char ubuf[3 * sizeof(__u64)];
2950 char abuf[3 * sizeof(__u64)];
2951 char rbuf[3 * sizeof(__u64)];
2958 if (flags & MNTDF_INODES) {
2959 avail = stat->os_ffree;
2960 used = stat->os_files - stat->os_ffree;
2961 total = stat->os_files;
2963 int shift = flags & MNTDF_COOKED ? 0 : 10;
2965 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2966 used = ((stat->os_blocks - stat->os_bfree) *
2967 stat->os_bsize) >> shift;
2968 total = (stat->os_blocks * stat->os_bsize) >> shift;
2971 if ((used + avail) > 0)
2972 ratio = (double)used / (double)(used + avail);
2974 if (flags & MNTDF_COOKED) {
2978 cook_val = (double)total;
2981 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2984 snprintf(tbuf, sizeof(tbuf), CDF, total);
2986 cook_val = (double)used;
2989 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
2992 snprintf(ubuf, sizeof(ubuf), CDF, used);
2994 cook_val = (double)avail;
2997 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3000 snprintf(abuf, sizeof(abuf), CDF, avail);
3002 snprintf(tbuf, sizeof(tbuf), CDF, total);
3003 snprintf(ubuf, sizeof(tbuf), CDF, used);
3004 snprintf(abuf, sizeof(tbuf), CDF, avail);
3007 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3008 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3009 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3011 printf("[%s:%d]", type, index);
3013 if (stat->os_state) {
3015 * Each character represents the matching
3018 const char state_names[] = "DRSI";
3023 for (i = 0, state = stat->os_state;
3024 state && i < sizeof(state_names); i++) {
3025 if (!(state & (1 << i)))
3027 printf("%c", state_names[i]);
3035 printf(UUF": inactive device\n", uuid);
3038 printf(UUF": %s\n", uuid, strerror(-rc));
3045 struct ll_stat_type {
3050 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3052 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3053 struct obd_uuid uuid_buf;
3054 char *poolname = NULL;
3055 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3056 { LL_STATFS_LOV, "OST" },
3058 struct ll_stat_type *tp;
3059 __u64 ost_ffree = 0;
3067 poolname = strchr(pool, '.');
3068 if (poolname != NULL) {
3069 if (strncmp(fsname, pool, strlen(fsname))) {
3070 fprintf(stderr, "filesystem name incorrect\n");
3078 fd = open(mntdir, O_RDONLY);
3081 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3086 if (flags & MNTDF_INODES)
3087 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3088 "UUID", "Inodes", "IUsed", "IFree",
3089 "IUse%", "Mounted on");
3091 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3092 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3093 "Used", "Available", "Use%", "Mounted on");
3095 for (tp = types; tp->st_name != NULL; tp++) {
3096 for (index = 0; ; index++) {
3097 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3098 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3099 type = flags & MNTDF_LAZY ?
3100 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3101 rc2 = llapi_obd_fstatfs(fd, type, index,
3102 &stat_buf, &uuid_buf);
3107 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3108 if (!(flags & MNTDF_VERBOSE))
3110 } else if (rc2 < 0 && rc == 0) {
3114 if (poolname && tp->st_op == LL_STATFS_LOV &&
3115 llapi_search_ost(fsname, poolname,
3116 obd_uuid2str(&uuid_buf)) != 1)
3119 /* the llapi_obd_statfs() call may have returned with
3120 * an error, but if it filled in uuid_buf we will at
3121 * lease use that to print out a message for that OBD.
3122 * If we didn't get anything in the uuid_buf, then fill
3123 * it in so that we can print an error message. */
3124 if (uuid_buf.uuid[0] == '\0')
3125 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3126 "%s%04x", tp->st_name, index);
3127 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3128 flags, tp->st_name, index, rc2);
3131 if (tp->st_op == LL_STATFS_LMV) {
3132 sum.os_ffree += stat_buf.os_ffree;
3133 sum.os_files += stat_buf.os_files;
3134 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3135 sum.os_blocks += stat_buf.os_blocks *
3137 sum.os_bfree += stat_buf.os_bfree *
3139 sum.os_bavail += stat_buf.os_bavail *
3141 ost_ffree += stat_buf.os_ffree;
3149 /* If we don't have as many objects free on the OST as inodes
3150 * on the MDS, we reduce the total number of inodes to
3151 * compensate, so that the "inodes in use" number is correct.
3152 * Matches ll_statfs_internal() so the results are consistent. */
3153 if (ost_ffree < sum.os_ffree) {
3154 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3155 sum.os_ffree = ost_ffree;
3158 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3164 static int lfs_df(int argc, char **argv)
3166 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3167 enum mntdf_flags flags = 0;
3168 int c, rc = 0, index = 0;
3169 char fsname[PATH_MAX] = "", *pool_name = NULL;
3170 struct option long_opts[] = {
3171 {"human-readable", 0, 0, 'h'},
3172 {"inodes", 0, 0, 'i'},
3173 {"lazy", 0, 0, 'l'},
3174 {"pool", required_argument, 0, 'p'},
3175 {"verbose", 0, 0, 'v'},
3179 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3182 flags |= MNTDF_COOKED;
3185 flags |= MNTDF_INODES;
3188 flags |= MNTDF_LAZY;
3194 flags |= MNTDF_VERBOSE;
3200 if (optind < argc && !realpath(argv[optind], path)) {
3202 fprintf(stderr, "error: invalid path '%s': %s\n",
3203 argv[optind], strerror(-rc));
3207 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3208 /* Check if we have a mount point */
3209 if (mntdir[0] == '\0')
3212 rc = mntdf(mntdir, fsname, pool_name, flags);
3213 if (rc || path[0] != '\0')
3215 fsname[0] = '\0'; /* avoid matching in next loop */
3216 mntdir[0] = '\0'; /* avoid matching in next loop */
3222 static int lfs_getname(int argc, char **argv)
3224 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3225 int rc = 0, index = 0, c;
3226 char buf[sizeof(struct obd_uuid)];
3228 while ((c = getopt(argc, argv, "h")) != -1)
3231 if (optind == argc) { /* no paths specified, get all paths. */
3232 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3233 rc = llapi_getname(mntdir, buf, sizeof(buf));
3236 "cannot get name for `%s': %s\n",
3237 mntdir, strerror(-rc));
3241 printf("%s %s\n", buf, mntdir);
3243 path[0] = fsname[0] = mntdir[0] = 0;
3245 } else { /* paths specified, only attempt to search these. */
3246 for (; optind < argc; optind++) {
3247 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3250 "cannot get name for `%s': %s\n",
3251 argv[optind], strerror(-rc));
3255 printf("%s %s\n", buf, argv[optind]);
3261 static int lfs_check(int argc, char **argv)
3264 char mntdir[PATH_MAX] = {'\0'};
3273 obd_types[0] = obd_type1;
3274 obd_types[1] = obd_type2;
3276 if (strcmp(argv[1], "osts") == 0) {
3277 strcpy(obd_types[0], "osc");
3278 } else if (strcmp(argv[1], "mds") == 0) {
3279 strcpy(obd_types[0], "mdc");
3280 } else if (strcmp(argv[1], "servers") == 0) {
3282 strcpy(obd_types[0], "osc");
3283 strcpy(obd_types[1], "mdc");
3285 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3290 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3291 if (rc < 0 || mntdir[0] == '\0') {
3292 fprintf(stderr, "No suitable Lustre mount found\n");
3296 rc = llapi_target_check(num_types, obd_types, mntdir);
3298 fprintf(stderr, "error: %s: %s status failed\n",
3305 #ifdef HAVE_SYS_QUOTA_H
3306 #define ARG2INT(nr, str, msg) \
3309 nr = strtol(str, &endp, 0); \
3311 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3316 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3318 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3319 * returns the value or ULONG_MAX on integer overflow or incorrect format
3321 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3322 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3323 * 3. empty integer value is interpreted as 0
3325 static unsigned long str2sec(const char* timestr)
3327 const char spec[] = "smhdw";
3328 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3329 unsigned long val = 0;
3332 if (strpbrk(timestr, spec) == NULL) {
3333 /* no specifiers inside the time string,
3334 should treat it as an integer value */
3335 val = strtoul(timestr, &tail, 10);
3336 return *tail ? ULONG_MAX : val;
3339 /* format string is XXwXXdXXhXXmXXs */
3345 v = strtoul(timestr, &tail, 10);
3346 if (v == ULONG_MAX || *tail == '\0')
3347 /* value too large (ULONG_MAX or more)
3348 or missing specifier */
3351 ptr = strchr(spec, *tail);
3353 /* unknown specifier */
3358 /* check if product will overflow the type */
3359 if (!(v < ULONG_MAX / mult[ind]))
3362 ADD_OVERFLOW(val, mult[ind] * v);
3363 if (val == ULONG_MAX)
3375 #define ARG2ULL(nr, str, def_units) \
3377 unsigned long long limit, units = def_units; \
3380 rc = llapi_parse_size(str, &limit, &units, 1); \
3382 fprintf(stderr, "error: bad limit value %s\n", str); \
3388 static inline int has_times_option(int argc, char **argv)
3392 for (i = 1; i < argc; i++)
3393 if (!strcmp(argv[i], "-t"))
3399 int lfs_setquota_times(int argc, char **argv)
3402 struct if_quotactl qctl;
3403 char *mnt, *obd_type = (char *)qctl.obd_type;
3404 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3405 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3406 struct option long_opts[] = {
3407 {"block-grace", required_argument, 0, 'b'},
3408 {"group", no_argument, 0, 'g'},
3409 {"inode-grace", required_argument, 0, 'i'},
3410 {"times", no_argument, 0, 't'},
3411 {"user", no_argument, 0, 'u'},
3416 memset(&qctl, 0, sizeof(qctl));
3417 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3418 qctl.qc_type = ALLQUOTA;
3420 while ((c = getopt_long(argc, argv, "b:gi:tu",
3421 long_opts, NULL)) != -1) {
3429 if (qctl.qc_type != ALLQUOTA) {
3430 fprintf(stderr, "error: -u and -g can't be used "
3431 "more than once\n");
3434 qctl.qc_type = qtype;
3437 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3438 fprintf(stderr, "error: bad block-grace: %s\n",
3442 dqb->dqb_valid |= QIF_BTIME;
3445 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3446 fprintf(stderr, "error: bad inode-grace: %s\n",
3450 dqb->dqb_valid |= QIF_ITIME;
3452 case 't': /* Yes, of course! */
3454 default: /* getopt prints error message for us when opterr != 0 */
3459 if (qctl.qc_type == ALLQUOTA) {
3460 fprintf(stderr, "error: neither -u nor -g specified\n");
3464 if (optind != argc - 1) {
3465 fprintf(stderr, "error: unexpected parameters encountered\n");
3470 rc = llapi_quotactl(mnt, &qctl);
3473 fprintf(stderr, "%s %s ", obd_type,
3474 obd_uuid2str(&qctl.obd_uuid));
3475 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3482 #define BSLIMIT (1 << 0)
3483 #define BHLIMIT (1 << 1)
3484 #define ISLIMIT (1 << 2)
3485 #define IHLIMIT (1 << 3)
3487 int lfs_setquota(int argc, char **argv)
3490 struct if_quotactl qctl;
3491 char *mnt, *obd_type = (char *)qctl.obd_type;
3492 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3493 struct option long_opts[] = {
3494 {"block-softlimit", required_argument, 0, 'b'},
3495 {"block-hardlimit", required_argument, 0, 'B'},
3496 {"group", required_argument, 0, 'g'},
3497 {"inode-softlimit", required_argument, 0, 'i'},
3498 {"inode-hardlimit", required_argument, 0, 'I'},
3499 {"user", required_argument, 0, 'u'},
3502 unsigned limit_mask = 0;
3506 if (has_times_option(argc, argv))
3507 return lfs_setquota_times(argc, argv);
3509 memset(&qctl, 0, sizeof(qctl));
3510 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3511 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3512 * so it can be used as a marker that qc_type
3513 * isn't reinitialized from command line */
3515 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
3519 rc = name2uid(&qctl.qc_id, optarg);
3524 rc = name2gid(&qctl.qc_id, optarg);
3526 if (qctl.qc_type != ALLQUOTA) {
3527 fprintf(stderr, "error: -u and -g can't be used"
3528 " more than once\n");
3531 qctl.qc_type = qtype;
3533 qctl.qc_id = strtoul(optarg, &endptr, 10);
3534 if (*endptr != '\0') {
3535 fprintf(stderr, "error: can't find id "
3536 "for name %s\n", optarg);
3542 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3543 dqb->dqb_bsoftlimit >>= 10;
3544 limit_mask |= BSLIMIT;
3545 if (dqb->dqb_bsoftlimit &&
3546 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3547 fprintf(stderr, "warning: block softlimit is "
3548 "smaller than the miminal qunit size, "
3549 "please see the help of setquota or "
3550 "Lustre manual for details.\n");
3553 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3554 dqb->dqb_bhardlimit >>= 10;
3555 limit_mask |= BHLIMIT;
3556 if (dqb->dqb_bhardlimit &&
3557 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3558 fprintf(stderr, "warning: block hardlimit is "
3559 "smaller than the miminal qunit size, "
3560 "please see the help of setquota or "
3561 "Lustre manual for details.\n");
3564 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3565 limit_mask |= ISLIMIT;
3566 if (dqb->dqb_isoftlimit &&
3567 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3568 fprintf(stderr, "warning: inode softlimit is "
3569 "smaller than the miminal qunit size, "
3570 "please see the help of setquota or "
3571 "Lustre manual for details.\n");
3574 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3575 limit_mask |= IHLIMIT;
3576 if (dqb->dqb_ihardlimit &&
3577 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3578 fprintf(stderr, "warning: inode hardlimit is "
3579 "smaller than the miminal qunit size, "
3580 "please see the help of setquota or "
3581 "Lustre manual for details.\n");
3583 default: /* getopt prints error message for us when opterr != 0 */
3588 if (qctl.qc_type == ALLQUOTA) {
3589 fprintf(stderr, "error: neither -u nor -g was specified\n");
3593 if (limit_mask == 0) {
3594 fprintf(stderr, "error: at least one limit must be specified\n");
3598 if (optind != argc - 1) {
3599 fprintf(stderr, "error: unexpected parameters encountered\n");
3605 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3606 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3607 /* sigh, we can't just set blimits/ilimits */
3608 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3609 .qc_type = qctl.qc_type,
3610 .qc_id = qctl.qc_id};
3612 rc = llapi_quotactl(mnt, &tmp_qctl);
3614 fprintf(stderr, "error: setquota failed while retrieving"
3615 " current quota settings (%s)\n",
3620 if (!(limit_mask & BHLIMIT))
3621 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3622 if (!(limit_mask & BSLIMIT))
3623 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3624 if (!(limit_mask & IHLIMIT))
3625 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3626 if (!(limit_mask & ISLIMIT))
3627 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3629 /* Keep grace times if we have got no softlimit arguments */
3630 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3631 dqb->dqb_valid |= QIF_BTIME;
3632 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3635 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3636 dqb->dqb_valid |= QIF_ITIME;
3637 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3641 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3642 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3644 rc = llapi_quotactl(mnt, &qctl);
3647 fprintf(stderr, "%s %s ", obd_type,
3648 obd_uuid2str(&qctl.obd_uuid));
3649 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3656 /* Converts seconds value into format string
3657 * result is returned in buf
3659 * 1. result is in descenting order: 1w2d3h4m5s
3660 * 2. zero fields are not filled (except for p. 3): 5d1s
3661 * 3. zero seconds value is presented as "0s"
3663 static char * __sec2str(time_t seconds, char *buf)
3665 const char spec[] = "smhdw";
3666 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3671 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3672 c = seconds / mult[i];
3674 if (c > 0 || (i == 0 && buf == tail))
3675 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3683 static void sec2str(time_t seconds, char *buf, int rc)
3690 tail = __sec2str(seconds, tail);
3692 if (rc && tail - buf < 39) {
3698 static void diff2str(time_t seconds, char *buf, time_t now)
3704 if (seconds <= now) {
3705 strcpy(buf, "none");
3708 __sec2str(seconds - now, buf);
3711 static void print_quota_title(char *name, struct if_quotactl *qctl,
3712 bool human_readable)
3714 printf("Disk quotas for %s %s (%cid %u):\n",
3715 qtype_name(qctl->qc_type), name,
3716 *qtype_name(qctl->qc_type), qctl->qc_id);
3717 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3718 "Filesystem", human_readable ? "used" : "kbytes",
3719 "quota", "limit", "grace",
3720 "files", "quota", "limit", "grace");
3723 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3726 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3729 snprintf(buf, buflen, "%5.4gP",
3730 (double)num / ((__u64)1 << 40));
3732 snprintf(buf, buflen, "%5.4gT",
3733 (double)num / (1 << 30));
3735 snprintf(buf, buflen, "%5.4gG",
3736 (double)num / (1 << 20));
3738 snprintf(buf, buflen, "%5.4gM",
3739 (double)num / (1 << 10));
3741 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3745 #define STRBUF_LEN 32
3746 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3753 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3754 int bover = 0, iover = 0;
3755 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3756 char numbuf[3][STRBUF_LEN];
3758 char strbuf[STRBUF_LEN];
3760 if (dqb->dqb_bhardlimit &&
3761 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3763 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3764 if (dqb->dqb_btime > now) {
3771 if (dqb->dqb_ihardlimit &&
3772 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3774 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3775 if (dqb->dqb_itime > now) {
3783 if (strlen(mnt) > 15)
3784 printf("%s\n%15s", mnt, "");
3786 printf("%15s", mnt);
3789 diff2str(dqb->dqb_btime, timebuf, now);
3791 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3792 strbuf, sizeof(strbuf), h);
3793 if (rc == -EREMOTEIO)
3794 sprintf(numbuf[0], "%s*", strbuf);
3796 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3797 "%s" : "[%s]", strbuf);
3799 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3800 if (type == QC_GENERAL)
3801 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3802 "%s" : "[%s]", strbuf);
3804 sprintf(numbuf[1], "%s", "-");
3806 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3807 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3808 "%s" : "[%s]", strbuf);
3810 printf(" %7s%c %6s %7s %7s",
3811 numbuf[0], bover ? '*' : ' ', numbuf[1],
3812 numbuf[2], bover > 1 ? timebuf : "-");
3815 diff2str(dqb->dqb_itime, timebuf, now);
3817 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3818 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3820 if (type == QC_GENERAL)
3821 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3823 (uintmax_t)dqb->dqb_isoftlimit);
3825 sprintf(numbuf[1], "%s", "-");
3827 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3828 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3830 if (type != QC_OSTIDX)
3831 printf(" %7s%c %6s %7s %7s",
3832 numbuf[0], iover ? '*' : ' ', numbuf[1],
3833 numbuf[2], iover > 1 ? timebuf : "-");
3835 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3838 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3839 qctl->qc_cmd == Q_GETOINFO) {
3843 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3844 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3845 printf("Block grace time: %s; Inode grace time: %s\n",
3846 bgtimebuf, igtimebuf);
3850 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3851 bool h, __u64 *total)
3853 int rc = 0, rc1 = 0, count = 0;
3854 __u32 valid = qctl->qc_valid;
3856 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3858 fprintf(stderr, "can not get %s count: %s\n",
3859 is_mdt ? "mdt": "ost", strerror(-rc));
3863 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3864 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3865 rc = llapi_quotactl(mnt, qctl);
3867 /* It is remote client case. */
3868 if (rc == -EOPNOTSUPP) {
3875 fprintf(stderr, "quotactl %s%d failed.\n",
3876 is_mdt ? "mdt": "ost", qctl->qc_idx);
3880 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3881 qctl->qc_valid, 0, h);
3882 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3883 qctl->qc_dqblk.dqb_bhardlimit;
3886 qctl->qc_valid = valid;
3890 static int lfs_quota(int argc, char **argv)
3893 char *mnt, *name = NULL;
3894 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3895 .qc_type = ALLQUOTA };
3896 char *obd_type = (char *)qctl.obd_type;
3897 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3898 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
3899 verbose = 0, pass = 0, quiet = 0, inacc;
3901 __u32 valid = QC_GENERAL, idx = 0;
3902 __u64 total_ialloc = 0, total_balloc = 0;
3903 bool human_readable = false;
3906 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3915 if (qctl.qc_type != ALLQUOTA) {
3916 fprintf(stderr, "error: use either -u or -g\n");
3919 qctl.qc_type = qtype;
3922 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3925 valid = qctl.qc_valid = QC_UUID;
3926 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3929 valid = qctl.qc_valid = QC_MDTIDX;
3930 idx = qctl.qc_idx = atoi(optarg);
3933 valid = qctl.qc_valid = QC_OSTIDX;
3934 idx = qctl.qc_idx = atoi(optarg);
3943 human_readable = true;
3946 fprintf(stderr, "error: %s: option '-%c' "
3947 "unrecognized\n", argv[0], c);
3952 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3953 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
3954 optind == argc - 1) {
3956 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3957 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3958 qctl.qc_valid = valid;
3960 qctl.qc_type = pass;
3961 switch (qctl.qc_type) {
3963 qctl.qc_id = geteuid();
3964 rc = uid2name(&name, qctl.qc_id);
3967 qctl.qc_id = getegid();
3968 rc = gid2name(&name, qctl.qc_id);
3977 /* lfs quota -u username /path/to/lustre/mount */
3978 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3979 /* options should be followed by u/g-name and mntpoint */
3980 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
3981 fprintf(stderr, "error: missing quota argument(s)\n");
3985 name = argv[optind++];
3986 switch (qctl.qc_type) {
3988 rc = name2uid(&qctl.qc_id, name);
3991 rc = name2gid(&qctl.qc_id, name);
3998 qctl.qc_id = strtoul(name, &endptr, 10);
3999 if (*endptr != '\0') {
4000 fprintf(stderr, "error: can't find id for name "
4005 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4006 fprintf(stderr, "error: missing quota info argument(s)\n");
4012 rc1 = llapi_quotactl(mnt, &qctl);
4016 fprintf(stderr, "%s quotas are not enabled.\n",
4017 qtype_name(qctl.qc_type));
4020 fprintf(stderr, "Permission denied.\n");
4023 /* We already got error message. */
4026 fprintf(stderr, "Unexpected quotactl error: %s\n",
4031 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4032 print_quota_title(name, &qctl, human_readable);
4034 if (rc1 && *obd_type)
4035 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4037 if (qctl.qc_valid != QC_GENERAL)
4040 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4041 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4042 (QIF_LIMITS|QIF_USAGE));
4044 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4046 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4048 char strbuf[STRBUF_LEN];
4050 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4052 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4054 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4056 printf("Total allocated inode limit: %ju, total "
4057 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4061 if (rc1 || rc2 || rc3 || inacc)
4062 printf("Some errors happened when getting quota info. "
4063 "Some devices may be not working or deactivated. "
4064 "The data in \"[]\" is inaccurate.\n");
4067 if (pass > 0 && pass < LL_MAXQUOTAS)
4072 #endif /* HAVE_SYS_QUOTA_H! */
4074 static int flushctx_ioctl(char *mp)
4078 fd = open(mp, O_RDONLY);
4080 fprintf(stderr, "flushctx: error open %s: %s\n",
4081 mp, strerror(errno));
4085 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4087 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4088 mp, strerror(errno));
4094 static int lfs_flushctx(int argc, char **argv)
4096 int kdestroy = 0, c;
4097 char mntdir[PATH_MAX] = {'\0'};
4101 while ((c = getopt(argc, argv, "k")) != -1) {
4107 fprintf(stderr, "error: %s: option '-%c' "
4108 "unrecognized\n", argv[0], c);
4114 if ((rc = system("kdestroy > /dev/null")) != 0) {
4115 rc = WEXITSTATUS(rc);
4116 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4120 if (optind >= argc) {
4121 /* flush for all mounted lustre fs. */
4122 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4123 /* Check if we have a mount point */
4124 if (mntdir[0] == '\0')
4127 if (flushctx_ioctl(mntdir))
4130 mntdir[0] = '\0'; /* avoid matching in next loop */
4133 /* flush fs as specified */
4134 while (optind < argc) {
4135 if (flushctx_ioctl(argv[optind++]))
4142 static int lfs_cp(int argc, char **argv)
4144 fprintf(stderr, "remote client copy file(s).\n"
4145 "obsolete, does not support it anymore.\n");
4149 static int lfs_ls(int argc, char **argv)
4151 fprintf(stderr, "remote client lists directory contents.\n"
4152 "obsolete, does not support it anymore.\n");
4156 static int lfs_changelog(int argc, char **argv)
4158 void *changelog_priv;
4159 struct changelog_rec *rec;
4160 long long startrec = 0, endrec = 0;
4162 struct option long_opts[] = {
4163 {"follow", no_argument, 0, 'f'},
4166 char short_opts[] = "f";
4169 while ((rc = getopt_long(argc, argv, short_opts,
4170 long_opts, NULL)) != -1) {
4178 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4179 argv[0], argv[optind - 1]);
4186 mdd = argv[optind++];
4188 startrec = strtoll(argv[optind++], NULL, 10);
4190 endrec = strtoll(argv[optind++], NULL, 10);
4192 rc = llapi_changelog_start(&changelog_priv,
4193 CHANGELOG_FLAG_BLOCK |
4194 CHANGELOG_FLAG_JOBID |
4195 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4198 fprintf(stderr, "Can't start changelog: %s\n",
4199 strerror(errno = -rc));
4203 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4207 if (endrec && rec->cr_index > endrec) {
4208 llapi_changelog_free(&rec);
4211 if (rec->cr_index < startrec) {
4212 llapi_changelog_free(&rec);
4216 secs = rec->cr_time >> 30;
4217 gmtime_r(&secs, &ts);
4218 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4219 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4220 changelog_type2str(rec->cr_type),
4221 ts.tm_hour, ts.tm_min, ts.tm_sec,
4222 (int)(rec->cr_time & ((1<<30) - 1)),
4223 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4224 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4226 if (rec->cr_flags & CLF_JOBID) {
4227 struct changelog_ext_jobid *jid =
4228 changelog_rec_jobid(rec);
4230 if (jid->cr_jobid[0] != '\0')
4231 printf(" j=%s", jid->cr_jobid);
4234 if (rec->cr_namelen)
4235 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4236 rec->cr_namelen, changelog_rec_name(rec));
4238 if (rec->cr_flags & CLF_RENAME) {
4239 struct changelog_ext_rename *rnm =
4240 changelog_rec_rename(rec);
4242 if (!fid_is_zero(&rnm->cr_sfid))
4243 printf(" s="DFID" sp="DFID" %.*s",
4244 PFID(&rnm->cr_sfid),
4245 PFID(&rnm->cr_spfid),
4246 (int)changelog_rec_snamelen(rec),
4247 changelog_rec_sname(rec));
4251 llapi_changelog_free(&rec);
4254 llapi_changelog_fini(&changelog_priv);
4257 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4259 return (rc == 1 ? 0 : rc);
4262 static int lfs_changelog_clear(int argc, char **argv)
4270 endrec = strtoll(argv[3], NULL, 10);
4272 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4275 fprintf(stderr, "%s: record out of range: %llu\n",
4277 else if (rc == -ENOENT)
4278 fprintf(stderr, "%s: no changelog user: %s\n",
4281 fprintf(stderr, "%s error: %s\n", argv[0],
4290 static int lfs_fid2path(int argc, char **argv)
4292 struct option long_opts[] = {
4293 {"cur", no_argument, 0, 'c'},
4294 {"link", required_argument, 0, 'l'},
4295 {"rec", required_argument, 0, 'r'},
4298 char short_opts[] = "cl:r:";
4299 char *device, *fid, *path;
4300 long long recno = -1;
4306 while ((rc = getopt_long(argc, argv, short_opts,
4307 long_opts, NULL)) != -1) {
4313 linkno = strtol(optarg, NULL, 10);
4316 recno = strtoll(optarg, NULL, 10);
4321 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4322 argv[0], argv[optind - 1]);
4330 device = argv[optind++];
4331 path = calloc(1, PATH_MAX);
4333 fprintf(stderr, "error: Not enough memory\n");
4338 while (optind < argc) {
4339 fid = argv[optind++];
4341 lnktmp = (linkno >= 0) ? linkno : 0;
4343 int oldtmp = lnktmp;
4344 long long rectmp = recno;
4346 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4349 fprintf(stderr, "%s: error on FID %s: %s\n",
4350 argv[0], fid, strerror(errno = -rc2));
4357 fprintf(stdout, "%lld ", rectmp);
4358 if (device[0] == '/') {
4359 fprintf(stdout, "%s", device);
4360 if (device[strlen(device) - 1] != '/')
4361 fprintf(stdout, "/");
4362 } else if (path[0] == '\0') {
4363 fprintf(stdout, "/");
4365 fprintf(stdout, "%s\n", path);
4368 /* specified linkno */
4370 if (oldtmp == lnktmp)
4380 static int lfs_path2fid(int argc, char **argv)
4382 struct option long_opts[] = {
4383 {"parents", no_argument, 0, 'p'},
4387 const char short_opts[] = "p";
4388 const char *sep = "";
4391 bool show_parents = false;
4393 while ((rc = getopt_long(argc, argv, short_opts,
4394 long_opts, NULL)) != -1) {
4397 show_parents = true;
4400 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4401 argv[0], argv[optind - 1]);
4406 if (optind > argc - 1)
4408 else if (optind < argc - 1)
4412 for (path = argv + optind; *path != NULL; path++) {
4414 if (!show_parents) {
4415 err = llapi_path2fid(*path, &fid);
4417 printf("%s%s"DFID"\n",
4418 *sep != '\0' ? *path : "", sep,
4421 char name[NAME_MAX + 1];
4422 unsigned int linkno = 0;
4424 while ((err = llapi_path2parent(*path, linkno, &fid,
4425 name, sizeof(name))) == 0) {
4426 if (*sep != '\0' && linkno == 0)
4427 printf("%s%s", *path, sep);
4429 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4434 /* err == -ENODATA is end-of-loop */
4435 if (linkno > 0 && err == -ENODATA) {
4442 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4443 argv[0], show_parents ? "parent " : "", *path,
4455 static int lfs_data_version(int argc, char **argv)
4462 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4467 while ((c = getopt(argc, argv, "nrw")) != -1) {
4470 data_version_flags = 0;
4473 data_version_flags |= LL_DV_RD_FLUSH;
4476 data_version_flags |= LL_DV_WR_FLUSH;
4485 path = argv[optind];
4486 fd = open(path, O_RDONLY);
4488 err(errno, "cannot open file %s", path);
4490 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4492 err(errno, "cannot get version for %s", path);
4494 printf("%ju" "\n", (uintmax_t)data_version);
4500 static int lfs_hsm_state(int argc, char **argv)
4505 struct hsm_user_state hus;
4513 rc = llapi_hsm_state_get(path, &hus);
4515 fprintf(stderr, "can't get hsm state for %s: %s\n",
4516 path, strerror(errno = -rc));
4520 /* Display path name and status flags */
4521 printf("%s: (0x%08x)", path, hus.hus_states);
4523 if (hus.hus_states & HS_RELEASED)
4524 printf(" released");
4525 if (hus.hus_states & HS_EXISTS)
4527 if (hus.hus_states & HS_DIRTY)
4529 if (hus.hus_states & HS_ARCHIVED)
4530 printf(" archived");
4531 /* Display user-settable flags */
4532 if (hus.hus_states & HS_NORELEASE)
4533 printf(" never_release");
4534 if (hus.hus_states & HS_NOARCHIVE)
4535 printf(" never_archive");
4536 if (hus.hus_states & HS_LOST)
4537 printf(" lost_from_hsm");
4539 if (hus.hus_archive_id != 0)
4540 printf(", archive_id:%d", hus.hus_archive_id);
4543 } while (++i < argc);
4548 #define LFS_HSM_SET 0
4549 #define LFS_HSM_CLEAR 1
4552 * Generic function to set or clear HSM flags.
4553 * Used by hsm_set and hsm_clear.
4555 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4557 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4559 struct option long_opts[] = {
4560 {"lost", 0, 0, 'l'},
4561 {"norelease", 0, 0, 'r'},
4562 {"noarchive", 0, 0, 'a'},
4563 {"archived", 0, 0, 'A'},
4564 {"dirty", 0, 0, 'd'},
4565 {"exists", 0, 0, 'e'},
4568 char short_opts[] = "lraAde";
4576 while ((c = getopt_long(argc, argv, short_opts,
4577 long_opts, NULL)) != -1) {
4583 mask |= HS_NOARCHIVE;
4586 mask |= HS_ARCHIVED;
4589 mask |= HS_NORELEASE;
4600 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4601 argv[0], argv[optind - 1]);
4606 /* User should have specified a flag */
4610 while (optind < argc) {
4612 path = argv[optind];
4614 /* If mode == 0, this means we apply the mask. */
4615 if (mode == LFS_HSM_SET)
4616 rc = llapi_hsm_state_set(path, mask, 0, 0);
4618 rc = llapi_hsm_state_set(path, 0, mask, 0);
4621 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4622 path, strerror(errno = -rc));
4631 static int lfs_hsm_action(int argc, char **argv)
4636 struct hsm_current_action hca;
4637 struct hsm_extent he;
4638 enum hsm_user_action hua;
4639 enum hsm_progress_states hps;
4647 rc = llapi_hsm_current_action(path, &hca);
4649 fprintf(stderr, "can't get hsm action for %s: %s\n",
4650 path, strerror(errno = -rc));
4653 he = hca.hca_location;
4654 hua = hca.hca_action;
4655 hps = hca.hca_state;
4657 printf("%s: %s", path, hsm_user_action2name(hua));
4659 /* Skip file without action */
4660 if (hca.hca_action == HUA_NONE) {
4665 printf(" %s ", hsm_progress_state2name(hps));
4667 if ((hps == HPS_RUNNING) &&
4668 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4669 printf("(%llu bytes moved)\n",
4670 (unsigned long long)he.length);
4671 else if ((he.offset + he.length) == LUSTRE_EOF)
4672 printf("(from %llu to EOF)\n",
4673 (unsigned long long)he.offset);
4675 printf("(from %llu to %llu)\n",
4676 (unsigned long long)he.offset,
4677 (unsigned long long)(he.offset + he.length));
4679 } while (++i < argc);
4684 static int lfs_hsm_set(int argc, char **argv)
4686 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4689 static int lfs_hsm_clear(int argc, char **argv)
4691 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4695 * Check file state and return its fid, to be used by lfs_hsm_request().
4697 * \param[in] file Path to file to check
4698 * \param[in,out] fid Pointer to allocated lu_fid struct.
4699 * \param[in,out] last_dev Pointer to last device id used.
4701 * \return 0 on success.
4703 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4709 rc = lstat(file, &st);
4711 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4714 /* Checking for regular file as archiving as posix copytool
4715 * rejects archiving files other than regular files
4717 if (!S_ISREG(st.st_mode)) {
4718 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4721 /* A request should be ... */
4722 if (*last_dev != st.st_dev && *last_dev != 0) {
4723 fprintf(stderr, "All files should be "
4724 "on the same filesystem: %s\n", file);
4727 *last_dev = st.st_dev;
4729 rc = llapi_path2fid(file, fid);
4731 fprintf(stderr, "Cannot read FID of %s: %s\n",
4732 file, strerror(-rc));
4738 /* Fill an HSM HUR item with a given file name.
4740 * If mntpath is set, then the filename is actually a FID, and no
4741 * lookup on the filesystem will be performed.
4743 * \param[in] hur the user request to fill
4744 * \param[in] idx index of the item inside the HUR to fill
4745 * \param[in] mntpath mountpoint of Lustre
4746 * \param[in] fname filename (if mtnpath is NULL)
4747 * or FID (if mntpath is set)
4748 * \param[in] last_dev pointer to last device id used
4750 * \retval 0 on success
4751 * \retval CMD_HELP or a negative errno on error
4753 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4754 const char *mntpath, const char *fname,
4757 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4760 hui->hui_extent.length = -1;
4762 if (mntpath != NULL) {
4765 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4769 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4774 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4778 hur->hur_request.hr_itemcount++;
4783 static int lfs_hsm_request(int argc, char **argv, int action)
4785 struct option long_opts[] = {
4786 {"filelist", 1, 0, 'l'},
4787 {"data", 1, 0, 'D'},
4788 {"archive", 1, 0, 'a'},
4789 {"mntpath", 1, 0, 'm'},
4793 char short_opts[] = "l:D:a:m:";
4794 struct hsm_user_request *hur, *oldhur;
4799 char *filelist = NULL;
4800 char fullpath[PATH_MAX];
4801 char *opaque = NULL;
4805 int nbfile_alloc = 0;
4806 char *some_file = NULL;
4807 char *mntpath = NULL;
4813 while ((c = getopt_long(argc, argv, short_opts,
4814 long_opts, NULL)) != -1) {
4823 if (action != HUA_ARCHIVE &&
4824 action != HUA_REMOVE) {
4826 "error: -a is supported only "
4827 "when archiving or removing\n");
4830 archive_id = atoi(optarg);
4833 if (some_file == NULL) {
4835 some_file = strdup(optarg);
4841 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4842 argv[0], argv[optind - 1]);
4847 /* All remaining args are files, so we have at least nbfile */
4848 nbfile = argc - optind;
4850 if ((nbfile == 0) && (filelist == NULL))
4854 opaque_len = strlen(opaque);
4856 /* Alloc the request structure with enough place to store all files
4857 * from command line. */
4858 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4860 fprintf(stderr, "Cannot create the request: %s\n",
4864 nbfile_alloc = nbfile;
4866 hur->hur_request.hr_action = action;
4867 hur->hur_request.hr_archive_id = archive_id;
4868 hur->hur_request.hr_flags = 0;
4870 /* All remaining args are files, add them */
4871 if (nbfile != 0 && some_file == NULL)
4872 some_file = strdup(argv[optind]);
4874 for (i = 0; i < nbfile; i++) {
4875 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4881 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4883 /* If a filelist was specified, read the filelist from it. */
4884 if (filelist != NULL) {
4885 fp = fopen(filelist, "r");
4887 fprintf(stderr, "Cannot read the file list %s: %s\n",
4888 filelist, strerror(errno));
4893 while ((rc = getline(&line, &len, fp)) != -1) {
4894 /* If allocated buffer was too small, get something
4896 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4899 nbfile_alloc = nbfile_alloc * 2 + 1;
4901 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4904 fprintf(stderr, "hsm: cannot allocate "
4905 "the request: %s\n",
4912 size = hur_len(oldhur);
4914 fprintf(stderr, "hsm: cannot allocate "
4915 "%u files + %u bytes data\n",
4916 oldhur->hur_request.hr_itemcount,
4917 oldhur->hur_request.hr_data_len);
4924 memcpy(hur, oldhur, size);
4929 if (line[strlen(line) - 1] == '\n')
4930 line[strlen(line) - 1] = '\0';
4932 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4933 mntpath, line, &last_dev);
4939 if (some_file == NULL) {
4949 /* If a --data was used, add it to the request */
4950 hur->hur_request.hr_data_len = opaque_len;
4952 memcpy(hur_data(hur), opaque, opaque_len);
4954 /* Send the HSM request */
4955 if (realpath(some_file, fullpath) == NULL) {
4956 fprintf(stderr, "Could not find path '%s': %s\n",
4957 some_file, strerror(errno));
4959 rc = llapi_hsm_request(fullpath, hur);
4961 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4962 some_file, strerror(-rc));
4972 static int lfs_hsm_archive(int argc, char **argv)
4974 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4977 static int lfs_hsm_restore(int argc, char **argv)
4979 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4982 static int lfs_hsm_release(int argc, char **argv)
4984 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4987 static int lfs_hsm_remove(int argc, char **argv)
4989 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4992 static int lfs_hsm_cancel(int argc, char **argv)
4994 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4997 static int lfs_swap_layouts(int argc, char **argv)
5002 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5003 SWAP_LAYOUTS_KEEP_MTIME |
5004 SWAP_LAYOUTS_KEEP_ATIME);
5007 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5009 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5011 enum lu_ladvise_type advice;
5014 advice < ARRAY_SIZE(ladvise_names); advice++) {
5015 if (ladvise_names[advice] == NULL)
5017 if (strcmp(string, ladvise_names[advice]) == 0)
5021 return LU_LADVISE_INVALID;
5024 static int lfs_ladvise(int argc, char **argv)
5026 struct option long_opts[] = {
5027 {"advice", required_argument, 0, 'a'},
5028 {"background", no_argument, 0, 'b'},
5029 {"end", required_argument, 0, 'e'},
5030 {"start", required_argument, 0, 's'},
5031 {"length", required_argument, 0, 'l'},
5034 char short_opts[] = "a:be:l:s:";
5039 struct llapi_lu_ladvise advice;
5040 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5041 unsigned long long start = 0;
5042 unsigned long long end = LUSTRE_EOF;
5043 unsigned long long length = 0;
5044 unsigned long long size_units;
5045 unsigned long long flags = 0;
5048 while ((c = getopt_long(argc, argv, short_opts,
5049 long_opts, NULL)) != -1) {
5052 advice_type = lfs_get_ladvice(optarg);
5053 if (advice_type == LU_LADVISE_INVALID) {
5054 fprintf(stderr, "%s: invalid advice type "
5055 "'%s'\n", argv[0], optarg);
5056 fprintf(stderr, "Valid types:");
5058 for (advice_type = 0;
5059 advice_type < ARRAY_SIZE(ladvise_names);
5061 if (ladvise_names[advice_type] == NULL)
5063 fprintf(stderr, " %s",
5064 ladvise_names[advice_type]);
5066 fprintf(stderr, "\n");
5076 rc = llapi_parse_size(optarg, &end,
5079 fprintf(stderr, "%s: bad end offset '%s'\n",
5086 rc = llapi_parse_size(optarg, &start,
5089 fprintf(stderr, "%s: bad start offset "
5090 "'%s'\n", argv[0], optarg);
5096 rc = llapi_parse_size(optarg, &length,
5099 fprintf(stderr, "%s: bad length '%s'\n",
5107 fprintf(stderr, "%s: option '%s' unrecognized\n",
5108 argv[0], argv[optind - 1]);
5113 if (advice_type == LU_LADVISE_INVALID) {
5114 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5115 fprintf(stderr, "Valid types:");
5116 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5118 if (ladvise_names[advice_type] == NULL)
5120 fprintf(stderr, " %s", ladvise_names[advice_type]);
5122 fprintf(stderr, "\n");
5126 if (argc <= optind) {
5127 fprintf(stderr, "%s: please give one or more file names\n",
5132 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5133 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5138 if (end == LUSTRE_EOF && length != 0)
5139 end = start + length;
5142 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5143 argv[0], start, end);
5147 while (optind < argc) {
5150 path = argv[optind++];
5152 fd = open(path, O_RDONLY);
5154 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5155 argv[0], path, strerror(errno));
5160 advice.lla_start = start;
5161 advice.lla_end = end;
5162 advice.lla_advice = advice_type;
5163 advice.lla_value1 = 0;
5164 advice.lla_value2 = 0;
5165 advice.lla_value3 = 0;
5166 advice.lla_value4 = 0;
5167 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5170 fprintf(stderr, "%s: cannot give advice '%s' to file "
5171 "'%s': %s\n", argv[0],
5172 ladvise_names[advice_type],
5173 path, strerror(errno));
5176 if (rc == 0 && rc2 < 0)
5182 static int lfs_list_commands(int argc, char **argv)
5184 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5186 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5191 int main(int argc, char **argv)
5195 /* Ensure that liblustreapi constructor has run */
5196 if (!liblustreapi_initialized)
5197 fprintf(stderr, "liblustreapi was not properly initialized\n");
5201 Parser_init("lfs > ", cmdlist);
5203 progname = argv[0]; /* Used in error messages */
5205 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5207 rc = Parser_commands();
5210 return rc < 0 ? -rc : rc;
5213 #ifdef _LUSTRE_IDL_H_
5214 /* Everything we need here should be included by lustreapi.h. */
5215 # error "lfs should not depend on lustre_idl.h"
5216 #endif /* _LUSTRE_IDL_H_ */