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|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
275 " -b <block-softlimit> -B <block-hardlimit>\n"
276 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
277 " setquota <-u|--user|-g|--group|-p|--project> <uname>|<uid>|<gname>|<gid>|<projid>\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|-p|--project>\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|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
300 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <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 inline int name2projid(unsigned int *id, const char *name)
1750 static int uid2name(char **name, unsigned int id)
1752 struct passwd *passwd;
1754 passwd = getpwuid(id);
1757 *name = passwd->pw_name;
1762 static inline int gid2name(char **name, unsigned int id)
1764 struct group *group;
1766 group = getgrgid(id);
1769 *name = group->gr_name;
1774 static int name2layout(__u32 *layout, char *name)
1779 for (ptr = name; ; ptr = NULL) {
1780 lyt = strtok(ptr, ",");
1783 if (strcmp(lyt, "released") == 0)
1784 *layout |= LOV_PATTERN_F_RELEASED;
1785 else if (strcmp(lyt, "raid0") == 0)
1786 *layout |= LOV_PATTERN_RAID0;
1793 static int lfs_find(int argc, char **argv)
1798 struct find_param param = {
1802 struct option long_opts[] = {
1803 {"atime", required_argument, 0, 'A'},
1804 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1805 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1806 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1807 {"stripe-count", required_argument, 0, 'c'},
1808 {"stripe_count", required_argument, 0, 'c'},
1809 {"ctime", required_argument, 0, 'C'},
1810 {"maxdepth", required_argument, 0, 'D'},
1811 {"component-end", required_argument, 0, 'E'},
1812 {"gid", required_argument, 0, 'g'},
1813 {"group", required_argument, 0, 'G'},
1814 {"stripe-index", required_argument, 0, 'i'},
1815 {"stripe_index", required_argument, 0, 'i'},
1816 /*{"component-id", required_argument, 0, 'I'},*/
1817 {"layout", required_argument, 0, 'L'},
1818 {"mdt", required_argument, 0, 'm'},
1819 {"mdt-index", required_argument, 0, 'm'},
1820 {"mdt_index", required_argument, 0, 'm'},
1821 {"mtime", required_argument, 0, 'M'},
1822 {"name", required_argument, 0, 'n'},
1823 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1824 {"obd", required_argument, 0, 'O'},
1825 {"ost", required_argument, 0, 'O'},
1826 /* no short option for pool, p/P already used */
1827 {"pool", required_argument, 0, LFS_POOL_OPT},
1828 {"print0", no_argument, 0, 'p'},
1829 {"print", no_argument, 0, 'P'},
1830 {"size", required_argument, 0, 's'},
1831 {"stripe-size", required_argument, 0, 'S'},
1832 {"stripe_size", required_argument, 0, 'S'},
1833 {"type", required_argument, 0, 't'},
1834 {"uid", required_argument, 0, 'u'},
1835 {"user", required_argument, 0, 'U'},
1848 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1849 while ((c = getopt_long_only(argc, argv,
1850 "-A:c:C:D:E:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1851 long_opts, NULL)) >= 0) {
1856 /* '!' is part of option */
1857 /* when getopt_long_only() finds a string which is not
1858 * an option nor a known option argument it returns 1
1859 * in that case if we already have found pathstart and pathend
1860 * (i.e. we have the list of pathnames),
1861 * the only supported value is "!"
1863 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1864 if (!isoption && pathend != -1) {
1865 fprintf(stderr, "err: %s: filename|dirname must either "
1866 "precede options or follow options\n",
1871 if (!isoption && pathstart == -1)
1872 pathstart = optind - 1;
1873 if (isoption && pathstart != -1 && pathend == -1)
1874 pathend = optind - 2;
1880 /* unknown; opt is "!" or path component,
1881 * checking done above.
1883 if (strcmp(optarg, "!") == 0)
1887 xtime = ¶m.fp_atime;
1888 xsign = ¶m.fp_asign;
1889 param.fp_exclude_atime = !!neg_opt;
1890 /* no break, this falls through to 'C' for ctime */
1893 xtime = ¶m.fp_ctime;
1894 xsign = ¶m.fp_csign;
1895 param.fp_exclude_ctime = !!neg_opt;
1897 /* no break, this falls through to 'M' for mtime */
1900 xtime = ¶m.fp_mtime;
1901 xsign = ¶m.fp_msign;
1902 param.fp_exclude_mtime = !!neg_opt;
1904 rc = set_time(&t, xtime, optarg);
1905 if (rc == INT_MAX) {
1912 case LFS_COMP_COUNT_OPT:
1913 if (optarg[0] == '+') {
1914 param.fp_comp_count_sign = -1;
1916 } else if (optarg[0] == '-') {
1917 param.fp_comp_count_sign = 1;
1921 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1922 if (*endptr != '\0') {
1923 fprintf(stderr, "error: bad component count "
1927 param.fp_check_comp_count = 1;
1928 param.fp_exclude_comp_count = !!neg_opt;
1930 case LFS_COMP_FLAGS_OPT:
1931 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1933 fprintf(stderr, "error: bad component flags "
1937 param.fp_check_comp_flags = 1;
1938 param.fp_exclude_comp_flags = !!neg_opt;
1940 case LFS_COMP_START_OPT:
1941 if (optarg[0] == '+') {
1942 param.fp_comp_start_sign = -1;
1944 } else if (optarg[0] == '-') {
1945 param.fp_comp_start_sign = 1;
1949 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1950 ¶m.fp_comp_start_units, 0);
1952 fprintf(stderr, "error: bad component start "
1956 param.fp_check_comp_start = 1;
1957 param.fp_exclude_comp_start = !!neg_opt;
1960 if (optarg[0] == '+') {
1961 param.fp_stripe_count_sign = -1;
1963 } else if (optarg[0] == '-') {
1964 param.fp_stripe_count_sign = 1;
1968 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1969 if (*endptr != '\0') {
1970 fprintf(stderr,"error: bad stripe_count '%s'\n",
1975 param.fp_check_stripe_count = 1;
1976 param.fp_exclude_stripe_count = !!neg_opt;
1979 param.fp_max_depth = strtol(optarg, 0, 0);
1982 if (optarg[0] == '+') {
1983 param.fp_comp_end_sign = -1;
1985 } else if (optarg[0] == '-') {
1986 param.fp_comp_end_sign = 1;
1990 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
1991 ¶m.fp_comp_end_units, 0);
1993 fprintf(stderr, "error: bad component end "
1997 param.fp_check_comp_end = 1;
1998 param.fp_exclude_comp_end = !!neg_opt;
2002 rc = name2gid(¶m.fp_gid, optarg);
2004 param.fp_gid = strtoul(optarg, &endptr, 10);
2005 if (*endptr != '\0') {
2006 fprintf(stderr, "Group/GID: %s cannot "
2007 "be found.\n", optarg);
2012 param.fp_exclude_gid = !!neg_opt;
2013 param.fp_check_gid = 1;
2016 ret = name2layout(¶m.fp_layout, optarg);
2019 param.fp_exclude_layout = !!neg_opt;
2020 param.fp_check_layout = 1;
2024 rc = name2uid(¶m.fp_uid, optarg);
2026 param.fp_uid = strtoul(optarg, &endptr, 10);
2027 if (*endptr != '\0') {
2028 fprintf(stderr, "User/UID: %s cannot "
2029 "be found.\n", optarg);
2034 param.fp_exclude_uid = !!neg_opt;
2035 param.fp_check_uid = 1;
2038 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2040 "Pool name %s is too long"
2041 " (max is %d)\n", optarg,
2046 /* we do check for empty pool because empty pool
2047 * is used to find V1 lov attributes */
2048 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2049 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2050 param.fp_exclude_pool = !!neg_opt;
2051 param.fp_check_pool = 1;
2054 param.fp_pattern = (char *)optarg;
2055 param.fp_exclude_pattern = !!neg_opt;
2060 char *buf, *token, *next, *p;
2064 buf = strdup(optarg);
2070 param.fp_exclude_obd = !!neg_opt;
2073 while (token && *token) {
2074 token = strchr(token, ',');
2081 param.fp_exclude_mdt = !!neg_opt;
2082 param.fp_num_alloc_mdts += len;
2083 tmp = realloc(param.fp_mdt_uuid,
2084 param.fp_num_alloc_mdts *
2085 sizeof(*param.fp_mdt_uuid));
2091 param.fp_mdt_uuid = tmp;
2093 param.fp_exclude_obd = !!neg_opt;
2094 param.fp_num_alloc_obds += len;
2095 tmp = realloc(param.fp_obd_uuid,
2096 param.fp_num_alloc_obds *
2097 sizeof(*param.fp_obd_uuid));
2103 param.fp_obd_uuid = tmp;
2105 for (token = buf; token && *token; token = next) {
2106 struct obd_uuid *puuid;
2109 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2112 ¶m.fp_obd_uuid[param.fp_num_obds++];
2114 p = strchr(token, ',');
2121 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2126 strncpy(puuid->uuid, token,
2127 sizeof(puuid->uuid));
2135 param.fp_zero_end = 1;
2140 if (optarg[0] == '+') {
2141 param.fp_size_sign = -1;
2143 } else if (optarg[0] == '-') {
2144 param.fp_size_sign = 1;
2148 ret = llapi_parse_size(optarg, ¶m.fp_size,
2149 ¶m.fp_size_units, 0);
2151 fprintf(stderr, "error: bad file size '%s'\n",
2155 param.fp_check_size = 1;
2156 param.fp_exclude_size = !!neg_opt;
2159 if (optarg[0] == '+') {
2160 param.fp_stripe_size_sign = -1;
2162 } else if (optarg[0] == '-') {
2163 param.fp_stripe_size_sign = 1;
2167 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2168 ¶m.fp_stripe_size_units, 0);
2170 fprintf(stderr, "error: bad stripe_size '%s'\n",
2174 param.fp_check_stripe_size = 1;
2175 param.fp_exclude_stripe_size = !!neg_opt;
2178 param.fp_exclude_type = !!neg_opt;
2179 switch (optarg[0]) {
2181 param.fp_type = S_IFBLK;
2184 param.fp_type = S_IFCHR;
2187 param.fp_type = S_IFDIR;
2190 param.fp_type = S_IFREG;
2193 param.fp_type = S_IFLNK;
2196 param.fp_type = S_IFIFO;
2199 param.fp_type = S_IFSOCK;
2202 fprintf(stderr, "error: %s: bad type '%s'\n",
2214 if (pathstart == -1) {
2215 fprintf(stderr, "error: %s: no filename|pathname\n",
2219 } else if (pathend == -1) {
2225 rc = llapi_find(argv[pathstart], ¶m);
2226 if (rc != 0 && ret == 0)
2228 } while (++pathstart < pathend);
2231 fprintf(stderr, "error: %s failed for %s.\n",
2232 argv[0], argv[optind - 1]);
2234 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2235 free(param.fp_obd_uuid);
2237 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2238 free(param.fp_mdt_uuid);
2243 static int lfs_getstripe_internal(int argc, char **argv,
2244 struct find_param *param)
2246 struct option long_opts[] = {
2247 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2248 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2249 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2250 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2251 /* This formerly implied "stripe-count", but was explicitly
2252 * made "stripe-count" for consistency with other options,
2253 * and to separate it from "mdt-count" when DNE arrives. */
2254 {"count", no_argument, 0, 'c'},
2256 {"stripe-count", no_argument, 0, 'c'},
2257 {"stripe_count", no_argument, 0, 'c'},
2258 {"directory", no_argument, 0, 'd'},
2259 {"default", no_argument, 0, 'D'},
2260 {"component-end", required_argument, 0, 'E'},
2261 {"fid", no_argument, 0, 'F'},
2262 {"generation", no_argument, 0, 'g'},
2263 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2264 /* This formerly implied "stripe-index", but was explicitly
2265 * made "stripe-index" for consistency with other options,
2266 * and to separate it from "mdt-index" when DNE arrives. */
2267 {"index", no_argument, 0, 'i'},
2269 {"stripe-index", no_argument, 0, 'i'},
2270 {"stripe_index", no_argument, 0, 'i'},
2271 {"component-id", required_argument, 0, 'I'},
2272 {"layout", no_argument, 0, 'L'},
2273 {"mdt", no_argument, 0, 'm'},
2274 {"mdt-index", no_argument, 0, 'm'},
2275 {"mdt_index", no_argument, 0, 'm'},
2276 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2277 {"mdt-index", no_argument, 0, 'M'},
2278 {"mdt_index", no_argument, 0, 'M'},
2280 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2281 /* This formerly implied "stripe-index", but was confusing
2282 * with "file offset" (which will eventually be needed for
2283 * with different layouts by offset), so deprecate it. */
2284 {"offset", no_argument, 0, 'o'},
2286 {"obd", required_argument, 0, 'O'},
2287 {"ost", required_argument, 0, 'O'},
2288 {"pool", no_argument, 0, 'p'},
2289 {"quiet", no_argument, 0, 'q'},
2290 {"recursive", no_argument, 0, 'r'},
2291 {"raw", no_argument, 0, 'R'},
2292 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2293 /* This formerly implied "--stripe-size", but was confusing
2294 * with "lfs find --size|-s", which means "file size", so use
2295 * the consistent "--stripe-size|-S" for all commands. */
2296 {"size", no_argument, 0, 's'},
2298 {"stripe-size", no_argument, 0, 'S'},
2299 {"stripe_size", no_argument, 0, 'S'},
2300 {"verbose", no_argument, 0, 'v'},
2306 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2307 long_opts, NULL)) != -1) {
2310 if (param->fp_obd_uuid) {
2312 "error: %s: only one obduuid allowed",
2316 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2321 case LFS_COMP_COUNT_OPT:
2322 param->fp_verbose |= VERBOSE_COMP_COUNT;
2323 param->fp_max_depth = 0;
2325 case LFS_COMP_FLAGS_OPT:
2326 if (optarg != NULL) {
2327 rc = comp_name2flags(¶m->fp_comp_flags,
2330 param->fp_verbose |=
2332 param->fp_max_depth = 0;
2335 param->fp_check_comp_flags = 1;
2338 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2339 param->fp_max_depth = 0;
2342 case LFS_COMP_START_OPT:
2343 if (optarg != NULL) {
2345 if (tmp[0] == '+') {
2346 param->fp_comp_start_sign = 1;
2348 } else if (tmp[0] == '-') {
2349 param->fp_comp_start_sign = -1;
2352 rc = llapi_parse_size(tmp,
2353 ¶m->fp_comp_start,
2354 ¶m->fp_comp_start_units, 0);
2356 param->fp_verbose |= VERBOSE_COMP_START;
2357 param->fp_max_depth = 0;
2360 param->fp_check_comp_start = 1;
2363 param->fp_verbose |= VERBOSE_COMP_START;
2364 param->fp_max_depth = 0;
2368 param->fp_max_depth = 0;
2371 param->fp_get_default_lmv = 1;
2374 if (optarg != NULL) {
2376 if (tmp[0] == '+') {
2377 param->fp_comp_end_sign = 1;
2379 } else if (tmp[0] == '-') {
2380 param->fp_comp_end_sign = -1;
2383 rc = llapi_parse_size(tmp,
2384 ¶m->fp_comp_end,
2385 ¶m->fp_comp_end_units, 0);
2387 param->fp_verbose |= VERBOSE_COMP_END;
2388 param->fp_max_depth = 0;
2391 param->fp_check_comp_end = 1;
2394 param->fp_verbose |= VERBOSE_COMP_END;
2395 param->fp_max_depth = 0;
2399 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2400 param->fp_verbose |= VERBOSE_DFID;
2401 param->fp_max_depth = 0;
2405 param->fp_recursive = 1;
2408 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2411 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2412 if (strcmp(argv[optind - 1], "--count") == 0)
2413 fprintf(stderr, "warning: '--count' deprecated,"
2414 " use '--stripe-count' instead\n");
2416 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2417 param->fp_verbose |= VERBOSE_COUNT;
2418 param->fp_max_depth = 0;
2421 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2423 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2424 fprintf(stderr, "warning: '--size|-s' deprecated, "
2425 "use '--stripe-size|-S' instead\n");
2427 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2429 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2430 param->fp_verbose |= VERBOSE_SIZE;
2431 param->fp_max_depth = 0;
2434 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2436 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2437 "use '--stripe-index|-i' instead\n");
2440 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2441 if (strcmp(argv[optind - 1], "--index") == 0)
2442 fprintf(stderr, "warning: '--index' deprecated"
2443 ", use '--stripe-index' instead\n");
2445 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2446 param->fp_verbose |= VERBOSE_OFFSET;
2447 param->fp_max_depth = 0;
2451 if (optarg != NULL) {
2452 param->fp_comp_id = strtoul(optarg, &end, 0);
2454 param->fp_verbose |= VERBOSE_COMP_ID;
2455 param->fp_max_depth = 0;
2458 param->fp_check_comp_id = 1;
2461 param->fp_max_depth = 0;
2462 param->fp_verbose |= VERBOSE_COMP_ID;
2466 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2467 param->fp_verbose |= VERBOSE_POOL;
2468 param->fp_max_depth = 0;
2472 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2473 param->fp_verbose |= VERBOSE_GENERATION;
2474 param->fp_max_depth = 0;
2478 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2479 param->fp_verbose |= VERBOSE_LAYOUT;
2480 param->fp_max_depth = 0;
2483 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2485 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2486 fprintf(stderr, "warning: '-M' deprecated"
2487 ", use '-m' instead\n");
2491 if (!(param->fp_verbose & VERBOSE_DETAIL))
2492 param->fp_max_depth = 0;
2493 param->fp_verbose |= VERBOSE_MDTINDEX;
2506 if (param->fp_recursive)
2507 param->fp_max_depth = -1;
2508 else if (param->fp_verbose & VERBOSE_DETAIL)
2509 param->fp_max_depth = 1;
2511 if (!param->fp_verbose)
2512 param->fp_verbose = VERBOSE_DEFAULT;
2513 if (param->fp_quiet)
2514 param->fp_verbose = VERBOSE_OBJID;
2517 rc = llapi_getstripe(argv[optind], param);
2518 } while (++optind < argc && !rc);
2521 fprintf(stderr, "error: %s failed for %s.\n",
2522 argv[0], argv[optind - 1]);
2526 static int lfs_tgts(int argc, char **argv)
2528 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2529 struct find_param param;
2530 int index = 0, rc=0;
2535 if (argc == 2 && !realpath(argv[1], path)) {
2537 fprintf(stderr, "error: invalid path '%s': %s\n",
2538 argv[1], strerror(-rc));
2542 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2543 /* Check if we have a mount point */
2544 if (mntdir[0] == '\0')
2547 memset(¶m, 0, sizeof(param));
2548 if (!strcmp(argv[0], "mdts"))
2549 param.fp_get_lmv = 1;
2551 rc = llapi_ostlist(mntdir, ¶m);
2553 fprintf(stderr, "error: %s: failed on %s\n",
2556 if (path[0] != '\0')
2558 memset(mntdir, 0, PATH_MAX);
2564 static int lfs_getstripe(int argc, char **argv)
2566 struct find_param param = { 0 };
2568 param.fp_max_depth = 1;
2569 return lfs_getstripe_internal(argc, argv, ¶m);
2573 static int lfs_getdirstripe(int argc, char **argv)
2575 struct find_param param = { 0 };
2576 struct option long_opts[] = {
2577 {"mdt-count", no_argument, 0, 'c'},
2578 {"mdt-index", no_argument, 0, 'i'},
2579 {"recursive", no_argument, 0, 'r'},
2580 {"mdt-hash", no_argument, 0, 't'},
2581 {"default", no_argument, 0, 'D'},
2582 {"obd", required_argument, 0, 'O'},
2587 param.fp_get_lmv = 1;
2589 while ((c = getopt_long(argc, argv, "cirtDO:", long_opts, NULL)) != -1)
2593 if (param.fp_obd_uuid) {
2595 "error: %s: only one obduuid allowed",
2599 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2602 param.fp_verbose |= VERBOSE_COUNT;
2605 param.fp_verbose |= VERBOSE_OFFSET;
2608 param.fp_verbose |= VERBOSE_HASH_TYPE;
2611 param.fp_get_default_lmv = 1;
2614 param.fp_recursive = 1;
2624 if (param.fp_recursive)
2625 param.fp_max_depth = -1;
2627 if (!param.fp_verbose)
2628 param.fp_verbose = VERBOSE_DEFAULT;
2631 rc = llapi_getstripe(argv[optind], ¶m);
2632 } while (++optind < argc && !rc);
2635 fprintf(stderr, "error: %s failed for %s.\n",
2636 argv[0], argv[optind - 1]);
2641 static int lfs_setdirstripe(int argc, char **argv)
2645 unsigned int stripe_offset = -1;
2646 unsigned int stripe_count = 1;
2647 enum lmv_hash_type hash_type;
2650 char *stripe_offset_opt = NULL;
2651 char *stripe_count_opt = NULL;
2652 char *stripe_hash_opt = NULL;
2653 char *mode_opt = NULL;
2654 bool default_stripe = false;
2655 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2656 mode_t previous_mode = 0;
2657 bool delete = false;
2659 struct option long_opts[] = {
2660 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2661 {"count", required_argument, 0, 'c'},
2663 {"mdt-count", required_argument, 0, 'c'},
2664 {"delete", no_argument, 0, 'd'},
2665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2666 {"index", required_argument, 0, 'i'},
2668 {"mdt-index", required_argument, 0, 'i'},
2669 {"mode", required_argument, 0, 'm'},
2670 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2671 {"hash-type", required_argument, 0, 't'},
2673 {"mdt-hash", required_argument, 0, 't'},
2674 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2675 {"default_stripe", no_argument, 0, 'D'},
2677 {"default", no_argument, 0, 'D'},
2681 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2688 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2689 if (strcmp(argv[optind - 1], "--count") == 0)
2690 fprintf(stderr, "warning: '--count' deprecated"
2691 ", use '--mdt-count' instead\n");
2693 stripe_count_opt = optarg;
2697 default_stripe = true;
2700 default_stripe = true;
2703 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2704 if (strcmp(argv[optind - 1], "--index") == 0)
2705 fprintf(stderr, "warning: '--index' deprecated"
2706 ", use '--mdt-index' instead\n");
2708 stripe_offset_opt = optarg;
2714 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2715 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2716 fprintf(stderr, "warning: '--hash-type' "
2717 "deprecated, use '--mdt-hash' "
2720 stripe_hash_opt = optarg;
2723 fprintf(stderr, "error: %s: option '%s' "
2725 argv[0], argv[optind - 1]);
2730 if (optind == argc) {
2731 fprintf(stderr, "error: %s: missing dirname\n",
2736 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2737 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2742 if (stripe_offset_opt != NULL) {
2743 /* get the stripe offset */
2744 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2746 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2747 argv[0], stripe_offset_opt);
2753 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2754 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2755 " or -i options.\n", argv[0]);
2763 if (mode_opt != NULL) {
2764 mode = strtoul(mode_opt, &end, 8);
2766 fprintf(stderr, "error: %s: bad mode '%s'\n",
2770 previous_mode = umask(0);
2773 if (stripe_hash_opt == NULL) {
2774 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2778 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
2779 if (strcmp(stripe_hash_opt, mdt_hash_name[i]) == 0)
2782 if (i == LMV_HASH_TYPE_MAX) {
2784 "error: %s: bad stripe hash type '%s'\n",
2785 argv[0], stripe_hash_opt);
2792 /* get the stripe count */
2793 if (stripe_count_opt != NULL) {
2794 stripe_count = strtoul(stripe_count_opt, &end, 0);
2796 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2797 argv[0], stripe_count_opt);
2802 dname = argv[optind];
2804 if (default_stripe) {
2805 result = llapi_dir_set_default_lmv_stripe(dname,
2806 stripe_offset, stripe_count,
2809 result = llapi_dir_create_pool(dname, mode,
2811 stripe_count, hash_type,
2816 fprintf(stderr, "error: %s: create stripe dir '%s' "
2817 "failed\n", argv[0], dname);
2820 dname = argv[++optind];
2821 } while (dname != NULL);
2823 if (mode_opt != NULL)
2824 umask(previous_mode);
2830 static int lfs_rmentry(int argc, char **argv)
2837 fprintf(stderr, "error: %s: missing dirname\n",
2843 dname = argv[index];
2844 while (dname != NULL) {
2845 result = llapi_direntry_remove(dname);
2847 fprintf(stderr, "error: %s: remove dir entry '%s' "
2848 "failed\n", argv[0], dname);
2851 dname = argv[++index];
2856 static int lfs_mv(int argc, char **argv)
2858 struct find_param param = {
2865 struct option long_opts[] = {
2866 {"mdt-index", required_argument, 0, 'M'},
2867 {"verbose", no_argument, 0, 'v'},
2871 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2874 param.fp_mdt_index = strtoul(optarg, &end, 0);
2876 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2883 param.fp_verbose = VERBOSE_DETAIL;
2887 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2888 argv[0], argv[optind - 1]);
2893 if (param.fp_mdt_index == -1) {
2894 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2898 if (optind >= argc) {
2899 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2903 param.fp_migrate = 1;
2904 rc = llapi_migrate_mdt(argv[optind], ¶m);
2906 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2907 argv[0], argv[optind], param.fp_mdt_index,
2912 static int lfs_osts(int argc, char **argv)
2914 return lfs_tgts(argc, argv);
2917 static int lfs_mdts(int argc, char **argv)
2919 return lfs_tgts(argc, argv);
2922 #define COOK(value) \
2925 while (value > 1024) { \
2933 #define CDF "%11llu"
2934 #define HDF "%8.1f%c"
2939 MNTDF_INODES = 0x0001,
2940 MNTDF_COOKED = 0x0002,
2941 MNTDF_LAZY = 0x0004,
2942 MNTDF_VERBOSE = 0x0008,
2945 static int showdf(char *mntdir, struct obd_statfs *stat,
2946 char *uuid, enum mntdf_flags flags,
2947 char *type, int index, int rc)
2949 long long avail, used, total;
2951 char *suffix = "KMGTPEZY";
2952 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2953 char tbuf[3 * sizeof(__u64)];
2954 char ubuf[3 * sizeof(__u64)];
2955 char abuf[3 * sizeof(__u64)];
2956 char rbuf[3 * sizeof(__u64)];
2963 if (flags & MNTDF_INODES) {
2964 avail = stat->os_ffree;
2965 used = stat->os_files - stat->os_ffree;
2966 total = stat->os_files;
2968 int shift = flags & MNTDF_COOKED ? 0 : 10;
2970 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2971 used = ((stat->os_blocks - stat->os_bfree) *
2972 stat->os_bsize) >> shift;
2973 total = (stat->os_blocks * stat->os_bsize) >> shift;
2976 if ((used + avail) > 0)
2977 ratio = (double)used / (double)(used + avail);
2979 if (flags & MNTDF_COOKED) {
2983 cook_val = (double)total;
2986 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2989 snprintf(tbuf, sizeof(tbuf), CDF, total);
2991 cook_val = (double)used;
2994 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
2997 snprintf(ubuf, sizeof(ubuf), CDF, used);
2999 cook_val = (double)avail;
3002 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3005 snprintf(abuf, sizeof(abuf), CDF, avail);
3007 snprintf(tbuf, sizeof(tbuf), CDF, total);
3008 snprintf(ubuf, sizeof(tbuf), CDF, used);
3009 snprintf(abuf, sizeof(tbuf), CDF, avail);
3012 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3013 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3014 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3016 printf("[%s:%d]", type, index);
3018 if (stat->os_state) {
3020 * Each character represents the matching
3023 const char state_names[] = "DRSI";
3028 for (i = 0, state = stat->os_state;
3029 state && i < sizeof(state_names); i++) {
3030 if (!(state & (1 << i)))
3032 printf("%c", state_names[i]);
3040 printf(UUF": inactive device\n", uuid);
3043 printf(UUF": %s\n", uuid, strerror(-rc));
3050 struct ll_stat_type {
3055 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3057 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3058 struct obd_uuid uuid_buf;
3059 char *poolname = NULL;
3060 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3061 { LL_STATFS_LOV, "OST" },
3063 struct ll_stat_type *tp;
3064 __u64 ost_ffree = 0;
3072 poolname = strchr(pool, '.');
3073 if (poolname != NULL) {
3074 if (strncmp(fsname, pool, strlen(fsname))) {
3075 fprintf(stderr, "filesystem name incorrect\n");
3083 fd = open(mntdir, O_RDONLY);
3086 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3091 if (flags & MNTDF_INODES)
3092 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3093 "UUID", "Inodes", "IUsed", "IFree",
3094 "IUse%", "Mounted on");
3096 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3097 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3098 "Used", "Available", "Use%", "Mounted on");
3100 for (tp = types; tp->st_name != NULL; tp++) {
3101 for (index = 0; ; index++) {
3102 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3103 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3104 type = flags & MNTDF_LAZY ?
3105 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3106 rc2 = llapi_obd_fstatfs(fd, type, index,
3107 &stat_buf, &uuid_buf);
3112 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3113 if (!(flags & MNTDF_VERBOSE))
3115 } else if (rc2 < 0 && rc == 0) {
3119 if (poolname && tp->st_op == LL_STATFS_LOV &&
3120 llapi_search_ost(fsname, poolname,
3121 obd_uuid2str(&uuid_buf)) != 1)
3124 /* the llapi_obd_statfs() call may have returned with
3125 * an error, but if it filled in uuid_buf we will at
3126 * lease use that to print out a message for that OBD.
3127 * If we didn't get anything in the uuid_buf, then fill
3128 * it in so that we can print an error message. */
3129 if (uuid_buf.uuid[0] == '\0')
3130 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3131 "%s%04x", tp->st_name, index);
3132 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3133 flags, tp->st_name, index, rc2);
3136 if (tp->st_op == LL_STATFS_LMV) {
3137 sum.os_ffree += stat_buf.os_ffree;
3138 sum.os_files += stat_buf.os_files;
3139 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3140 sum.os_blocks += stat_buf.os_blocks *
3142 sum.os_bfree += stat_buf.os_bfree *
3144 sum.os_bavail += stat_buf.os_bavail *
3146 ost_ffree += stat_buf.os_ffree;
3154 /* If we don't have as many objects free on the OST as inodes
3155 * on the MDS, we reduce the total number of inodes to
3156 * compensate, so that the "inodes in use" number is correct.
3157 * Matches ll_statfs_internal() so the results are consistent. */
3158 if (ost_ffree < sum.os_ffree) {
3159 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3160 sum.os_ffree = ost_ffree;
3163 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3169 static int lfs_df(int argc, char **argv)
3171 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3172 enum mntdf_flags flags = 0;
3173 int c, rc = 0, index = 0;
3174 char fsname[PATH_MAX] = "", *pool_name = NULL;
3175 struct option long_opts[] = {
3176 {"human-readable", 0, 0, 'h'},
3177 {"inodes", 0, 0, 'i'},
3178 {"lazy", 0, 0, 'l'},
3179 {"pool", required_argument, 0, 'p'},
3180 {"verbose", 0, 0, 'v'},
3184 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3187 flags |= MNTDF_COOKED;
3190 flags |= MNTDF_INODES;
3193 flags |= MNTDF_LAZY;
3199 flags |= MNTDF_VERBOSE;
3205 if (optind < argc && !realpath(argv[optind], path)) {
3207 fprintf(stderr, "error: invalid path '%s': %s\n",
3208 argv[optind], strerror(-rc));
3212 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3213 /* Check if we have a mount point */
3214 if (mntdir[0] == '\0')
3217 rc = mntdf(mntdir, fsname, pool_name, flags);
3218 if (rc || path[0] != '\0')
3220 fsname[0] = '\0'; /* avoid matching in next loop */
3221 mntdir[0] = '\0'; /* avoid matching in next loop */
3227 static int lfs_getname(int argc, char **argv)
3229 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3230 int rc = 0, index = 0, c;
3231 char buf[sizeof(struct obd_uuid)];
3233 while ((c = getopt(argc, argv, "h")) != -1)
3236 if (optind == argc) { /* no paths specified, get all paths. */
3237 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3238 rc = llapi_getname(mntdir, buf, sizeof(buf));
3241 "cannot get name for `%s': %s\n",
3242 mntdir, strerror(-rc));
3246 printf("%s %s\n", buf, mntdir);
3248 path[0] = fsname[0] = mntdir[0] = 0;
3250 } else { /* paths specified, only attempt to search these. */
3251 for (; optind < argc; optind++) {
3252 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3255 "cannot get name for `%s': %s\n",
3256 argv[optind], strerror(-rc));
3260 printf("%s %s\n", buf, argv[optind]);
3266 static int lfs_check(int argc, char **argv)
3269 char mntdir[PATH_MAX] = {'\0'};
3278 obd_types[0] = obd_type1;
3279 obd_types[1] = obd_type2;
3281 if (strcmp(argv[1], "osts") == 0) {
3282 strcpy(obd_types[0], "osc");
3283 } else if (strcmp(argv[1], "mds") == 0) {
3284 strcpy(obd_types[0], "mdc");
3285 } else if (strcmp(argv[1], "servers") == 0) {
3287 strcpy(obd_types[0], "osc");
3288 strcpy(obd_types[1], "mdc");
3290 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3295 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3296 if (rc < 0 || mntdir[0] == '\0') {
3297 fprintf(stderr, "No suitable Lustre mount found\n");
3301 rc = llapi_target_check(num_types, obd_types, mntdir);
3303 fprintf(stderr, "error: %s: %s status failed\n",
3310 #ifdef HAVE_SYS_QUOTA_H
3311 #define ARG2INT(nr, str, msg) \
3314 nr = strtol(str, &endp, 0); \
3316 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3321 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3323 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3324 * returns the value or ULONG_MAX on integer overflow or incorrect format
3326 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3327 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3328 * 3. empty integer value is interpreted as 0
3330 static unsigned long str2sec(const char* timestr)
3332 const char spec[] = "smhdw";
3333 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3334 unsigned long val = 0;
3337 if (strpbrk(timestr, spec) == NULL) {
3338 /* no specifiers inside the time string,
3339 should treat it as an integer value */
3340 val = strtoul(timestr, &tail, 10);
3341 return *tail ? ULONG_MAX : val;
3344 /* format string is XXwXXdXXhXXmXXs */
3350 v = strtoul(timestr, &tail, 10);
3351 if (v == ULONG_MAX || *tail == '\0')
3352 /* value too large (ULONG_MAX or more)
3353 or missing specifier */
3356 ptr = strchr(spec, *tail);
3358 /* unknown specifier */
3363 /* check if product will overflow the type */
3364 if (!(v < ULONG_MAX / mult[ind]))
3367 ADD_OVERFLOW(val, mult[ind] * v);
3368 if (val == ULONG_MAX)
3380 #define ARG2ULL(nr, str, def_units) \
3382 unsigned long long limit, units = def_units; \
3385 rc = llapi_parse_size(str, &limit, &units, 1); \
3387 fprintf(stderr, "error: bad limit value %s\n", str); \
3393 static inline int has_times_option(int argc, char **argv)
3397 for (i = 1; i < argc; i++)
3398 if (!strcmp(argv[i], "-t"))
3404 int lfs_setquota_times(int argc, char **argv)
3407 struct if_quotactl qctl;
3408 char *mnt, *obd_type = (char *)qctl.obd_type;
3409 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3410 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3411 struct option long_opts[] = {
3412 {"block-grace", required_argument, 0, 'b'},
3413 {"group", no_argument, 0, 'g'},
3414 {"inode-grace", required_argument, 0, 'i'},
3415 {"project", no_argument, 0, 'p'},
3416 {"times", no_argument, 0, 't'},
3417 {"user", no_argument, 0, 'u'},
3422 memset(&qctl, 0, sizeof(qctl));
3423 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3424 qctl.qc_type = ALLQUOTA;
3426 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3427 long_opts, NULL)) != -1) {
3438 if (qctl.qc_type != ALLQUOTA) {
3439 fprintf(stderr, "error: -u/g/p can't be used "
3440 "more than once\n");
3443 qctl.qc_type = qtype;
3446 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3447 fprintf(stderr, "error: bad block-grace: %s\n",
3451 dqb->dqb_valid |= QIF_BTIME;
3454 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3455 fprintf(stderr, "error: bad inode-grace: %s\n",
3459 dqb->dqb_valid |= QIF_ITIME;
3461 case 't': /* Yes, of course! */
3463 default: /* getopt prints error message for us when opterr != 0 */
3468 if (qctl.qc_type == ALLQUOTA) {
3469 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3473 if (optind != argc - 1) {
3474 fprintf(stderr, "error: unexpected parameters encountered\n");
3479 rc = llapi_quotactl(mnt, &qctl);
3482 fprintf(stderr, "%s %s ", obd_type,
3483 obd_uuid2str(&qctl.obd_uuid));
3484 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3491 #define BSLIMIT (1 << 0)
3492 #define BHLIMIT (1 << 1)
3493 #define ISLIMIT (1 << 2)
3494 #define IHLIMIT (1 << 3)
3496 int lfs_setquota(int argc, char **argv)
3499 struct if_quotactl qctl;
3500 char *mnt, *obd_type = (char *)qctl.obd_type;
3501 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3502 struct option long_opts[] = {
3503 {"block-softlimit", required_argument, 0, 'b'},
3504 {"block-hardlimit", required_argument, 0, 'B'},
3505 {"group", required_argument, 0, 'g'},
3506 {"inode-softlimit", required_argument, 0, 'i'},
3507 {"inode-hardlimit", required_argument, 0, 'I'},
3508 {"user", required_argument, 0, 'u'},
3509 {"project", required_argument, 0, 'p'},
3512 unsigned limit_mask = 0;
3516 if (has_times_option(argc, argv))
3517 return lfs_setquota_times(argc, argv);
3519 memset(&qctl, 0, sizeof(qctl));
3520 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3521 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3522 * so it can be used as a marker that qc_type
3523 * isn't reinitialized from command line */
3525 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3526 long_opts, NULL)) != -1) {
3530 rc = name2uid(&qctl.qc_id, optarg);
3534 rc = name2gid(&qctl.qc_id, optarg);
3538 rc = name2projid(&qctl.qc_id, optarg);
3540 if (qctl.qc_type != ALLQUOTA) {
3541 fprintf(stderr, "error: -u and -g can't be used"
3542 " more than once\n");
3545 qctl.qc_type = qtype;
3547 qctl.qc_id = strtoul(optarg, &endptr, 10);
3548 if (*endptr != '\0') {
3549 fprintf(stderr, "error: can't find id "
3550 "for name %s\n", optarg);
3556 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3557 dqb->dqb_bsoftlimit >>= 10;
3558 limit_mask |= BSLIMIT;
3559 if (dqb->dqb_bsoftlimit &&
3560 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3561 fprintf(stderr, "warning: block softlimit is "
3562 "smaller than the miminal qunit size, "
3563 "please see the help of setquota or "
3564 "Lustre manual for details.\n");
3567 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3568 dqb->dqb_bhardlimit >>= 10;
3569 limit_mask |= BHLIMIT;
3570 if (dqb->dqb_bhardlimit &&
3571 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3572 fprintf(stderr, "warning: block hardlimit is "
3573 "smaller than the miminal qunit size, "
3574 "please see the help of setquota or "
3575 "Lustre manual for details.\n");
3578 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3579 limit_mask |= ISLIMIT;
3580 if (dqb->dqb_isoftlimit &&
3581 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3582 fprintf(stderr, "warning: inode softlimit is "
3583 "smaller than the miminal qunit size, "
3584 "please see the help of setquota or "
3585 "Lustre manual for details.\n");
3588 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3589 limit_mask |= IHLIMIT;
3590 if (dqb->dqb_ihardlimit &&
3591 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3592 fprintf(stderr, "warning: inode hardlimit is "
3593 "smaller than the miminal qunit size, "
3594 "please see the help of setquota or "
3595 "Lustre manual for details.\n");
3597 default: /* getopt prints error message for us when opterr != 0 */
3602 if (qctl.qc_type == ALLQUOTA) {
3603 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3607 if (limit_mask == 0) {
3608 fprintf(stderr, "error: at least one limit must be specified\n");
3612 if (optind != argc - 1) {
3613 fprintf(stderr, "error: unexpected parameters encountered\n");
3619 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3620 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3621 /* sigh, we can't just set blimits/ilimits */
3622 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3623 .qc_type = qctl.qc_type,
3624 .qc_id = qctl.qc_id};
3626 rc = llapi_quotactl(mnt, &tmp_qctl);
3628 fprintf(stderr, "error: setquota failed while retrieving"
3629 " current quota settings (%s)\n",
3634 if (!(limit_mask & BHLIMIT))
3635 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3636 if (!(limit_mask & BSLIMIT))
3637 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3638 if (!(limit_mask & IHLIMIT))
3639 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3640 if (!(limit_mask & ISLIMIT))
3641 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3643 /* Keep grace times if we have got no softlimit arguments */
3644 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3645 dqb->dqb_valid |= QIF_BTIME;
3646 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3649 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3650 dqb->dqb_valid |= QIF_ITIME;
3651 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3655 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3656 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3658 rc = llapi_quotactl(mnt, &qctl);
3661 fprintf(stderr, "%s %s ", obd_type,
3662 obd_uuid2str(&qctl.obd_uuid));
3663 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3670 /* Converts seconds value into format string
3671 * result is returned in buf
3673 * 1. result is in descenting order: 1w2d3h4m5s
3674 * 2. zero fields are not filled (except for p. 3): 5d1s
3675 * 3. zero seconds value is presented as "0s"
3677 static char * __sec2str(time_t seconds, char *buf)
3679 const char spec[] = "smhdw";
3680 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3685 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3686 c = seconds / mult[i];
3688 if (c > 0 || (i == 0 && buf == tail))
3689 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3697 static void sec2str(time_t seconds, char *buf, int rc)
3704 tail = __sec2str(seconds, tail);
3706 if (rc && tail - buf < 39) {
3712 static void diff2str(time_t seconds, char *buf, time_t now)
3718 if (seconds <= now) {
3719 strcpy(buf, "none");
3722 __sec2str(seconds - now, buf);
3725 static void print_quota_title(char *name, struct if_quotactl *qctl,
3726 bool human_readable)
3728 printf("Disk quotas for %s %s (%cid %u):\n",
3729 qtype_name(qctl->qc_type), name,
3730 *qtype_name(qctl->qc_type), qctl->qc_id);
3731 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3732 "Filesystem", human_readable ? "used" : "kbytes",
3733 "quota", "limit", "grace",
3734 "files", "quota", "limit", "grace");
3737 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3740 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3743 snprintf(buf, buflen, "%5.4gP",
3744 (double)num / ((__u64)1 << 40));
3746 snprintf(buf, buflen, "%5.4gT",
3747 (double)num / (1 << 30));
3749 snprintf(buf, buflen, "%5.4gG",
3750 (double)num / (1 << 20));
3752 snprintf(buf, buflen, "%5.4gM",
3753 (double)num / (1 << 10));
3755 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3759 #define STRBUF_LEN 32
3760 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3767 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3768 int bover = 0, iover = 0;
3769 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3770 char numbuf[3][STRBUF_LEN];
3772 char strbuf[STRBUF_LEN];
3774 if (dqb->dqb_bhardlimit &&
3775 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3777 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3778 if (dqb->dqb_btime > now) {
3785 if (dqb->dqb_ihardlimit &&
3786 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3788 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3789 if (dqb->dqb_itime > now) {
3797 if (strlen(mnt) > 15)
3798 printf("%s\n%15s", mnt, "");
3800 printf("%15s", mnt);
3803 diff2str(dqb->dqb_btime, timebuf, now);
3805 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3806 strbuf, sizeof(strbuf), h);
3807 if (rc == -EREMOTEIO)
3808 sprintf(numbuf[0], "%s*", strbuf);
3810 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3811 "%s" : "[%s]", strbuf);
3813 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3814 if (type == QC_GENERAL)
3815 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3816 "%s" : "[%s]", strbuf);
3818 sprintf(numbuf[1], "%s", "-");
3820 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3821 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3822 "%s" : "[%s]", strbuf);
3824 printf(" %7s%c %6s %7s %7s",
3825 numbuf[0], bover ? '*' : ' ', numbuf[1],
3826 numbuf[2], bover > 1 ? timebuf : "-");
3829 diff2str(dqb->dqb_itime, timebuf, now);
3831 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3832 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3834 if (type == QC_GENERAL)
3835 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3837 (uintmax_t)dqb->dqb_isoftlimit);
3839 sprintf(numbuf[1], "%s", "-");
3841 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3842 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3844 if (type != QC_OSTIDX)
3845 printf(" %7s%c %6s %7s %7s",
3846 numbuf[0], iover ? '*' : ' ', numbuf[1],
3847 numbuf[2], iover > 1 ? timebuf : "-");
3849 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3852 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3853 qctl->qc_cmd == Q_GETOINFO) {
3857 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3858 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3859 printf("Block grace time: %s; Inode grace time: %s\n",
3860 bgtimebuf, igtimebuf);
3864 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3865 bool h, __u64 *total)
3867 int rc = 0, rc1 = 0, count = 0;
3868 __u32 valid = qctl->qc_valid;
3870 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3872 fprintf(stderr, "can not get %s count: %s\n",
3873 is_mdt ? "mdt": "ost", strerror(-rc));
3877 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3878 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3879 rc = llapi_quotactl(mnt, qctl);
3881 /* It is remote client case. */
3882 if (rc == -EOPNOTSUPP) {
3889 fprintf(stderr, "quotactl %s%d failed.\n",
3890 is_mdt ? "mdt": "ost", qctl->qc_idx);
3894 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3895 qctl->qc_valid, 0, h);
3896 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3897 qctl->qc_dqblk.dqb_bhardlimit;
3900 qctl->qc_valid = valid;
3904 static int lfs_quota(int argc, char **argv)
3907 char *mnt, *name = NULL;
3908 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3909 .qc_type = ALLQUOTA };
3910 char *obd_type = (char *)qctl.obd_type;
3911 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3912 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
3913 verbose = 0, pass = 0, quiet = 0, inacc;
3915 __u32 valid = QC_GENERAL, idx = 0;
3916 __u64 total_ialloc = 0, total_balloc = 0;
3917 bool human_readable = false;
3920 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
3931 if (qctl.qc_type != ALLQUOTA) {
3932 fprintf(stderr, "error: use either -u or -g\n");
3935 qctl.qc_type = qtype;
3938 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3941 valid = qctl.qc_valid = QC_UUID;
3942 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3945 valid = qctl.qc_valid = QC_MDTIDX;
3946 idx = qctl.qc_idx = atoi(optarg);
3949 valid = qctl.qc_valid = QC_OSTIDX;
3950 idx = qctl.qc_idx = atoi(optarg);
3959 human_readable = true;
3962 fprintf(stderr, "error: %s: option '-%c' "
3963 "unrecognized\n", argv[0], c);
3968 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3969 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
3970 optind == argc - 1) {
3972 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3973 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3974 qctl.qc_valid = valid;
3976 qctl.qc_type = pass;
3977 switch (qctl.qc_type) {
3979 qctl.qc_id = geteuid();
3980 rc = uid2name(&name, qctl.qc_id);
3983 qctl.qc_id = getegid();
3984 rc = gid2name(&name, qctl.qc_id);
3993 /* lfs quota -u username /path/to/lustre/mount */
3994 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3995 /* options should be followed by u/g-name and mntpoint */
3996 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
3997 fprintf(stderr, "error: missing quota argument(s)\n");
4001 name = argv[optind++];
4002 switch (qctl.qc_type) {
4004 rc = name2uid(&qctl.qc_id, name);
4007 rc = name2gid(&qctl.qc_id, name);
4010 rc = name2projid(&qctl.qc_id, name);
4017 qctl.qc_id = strtoul(name, &endptr, 10);
4018 if (*endptr != '\0') {
4019 fprintf(stderr, "error: can't find id for name "
4024 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4025 fprintf(stderr, "error: missing quota info argument(s)\n");
4031 rc1 = llapi_quotactl(mnt, &qctl);
4035 fprintf(stderr, "%s quotas are not enabled.\n",
4036 qtype_name(qctl.qc_type));
4039 fprintf(stderr, "Permission denied.\n");
4042 /* We already got error message. */
4045 fprintf(stderr, "Unexpected quotactl error: %s\n",
4050 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4051 print_quota_title(name, &qctl, human_readable);
4053 if (rc1 && *obd_type)
4054 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4056 if (qctl.qc_valid != QC_GENERAL)
4059 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4060 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4061 (QIF_LIMITS|QIF_USAGE));
4063 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4065 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4067 char strbuf[STRBUF_LEN];
4069 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4071 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4073 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4075 printf("Total allocated inode limit: %ju, total "
4076 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4080 if (rc1 || rc2 || rc3 || inacc)
4081 printf("Some errors happened when getting quota info. "
4082 "Some devices may be not working or deactivated. "
4083 "The data in \"[]\" is inaccurate.\n");
4086 if (pass > 0 && pass < LL_MAXQUOTAS)
4091 #endif /* HAVE_SYS_QUOTA_H! */
4093 static int flushctx_ioctl(char *mp)
4097 fd = open(mp, O_RDONLY);
4099 fprintf(stderr, "flushctx: error open %s: %s\n",
4100 mp, strerror(errno));
4104 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4106 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4107 mp, strerror(errno));
4113 static int lfs_flushctx(int argc, char **argv)
4115 int kdestroy = 0, c;
4116 char mntdir[PATH_MAX] = {'\0'};
4120 while ((c = getopt(argc, argv, "k")) != -1) {
4126 fprintf(stderr, "error: %s: option '-%c' "
4127 "unrecognized\n", argv[0], c);
4133 if ((rc = system("kdestroy > /dev/null")) != 0) {
4134 rc = WEXITSTATUS(rc);
4135 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4139 if (optind >= argc) {
4140 /* flush for all mounted lustre fs. */
4141 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4142 /* Check if we have a mount point */
4143 if (mntdir[0] == '\0')
4146 if (flushctx_ioctl(mntdir))
4149 mntdir[0] = '\0'; /* avoid matching in next loop */
4152 /* flush fs as specified */
4153 while (optind < argc) {
4154 if (flushctx_ioctl(argv[optind++]))
4161 static int lfs_cp(int argc, char **argv)
4163 fprintf(stderr, "remote client copy file(s).\n"
4164 "obsolete, does not support it anymore.\n");
4168 static int lfs_ls(int argc, char **argv)
4170 fprintf(stderr, "remote client lists directory contents.\n"
4171 "obsolete, does not support it anymore.\n");
4175 static int lfs_changelog(int argc, char **argv)
4177 void *changelog_priv;
4178 struct changelog_rec *rec;
4179 long long startrec = 0, endrec = 0;
4181 struct option long_opts[] = {
4182 {"follow", no_argument, 0, 'f'},
4185 char short_opts[] = "f";
4188 while ((rc = getopt_long(argc, argv, short_opts,
4189 long_opts, NULL)) != -1) {
4197 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4198 argv[0], argv[optind - 1]);
4205 mdd = argv[optind++];
4207 startrec = strtoll(argv[optind++], NULL, 10);
4209 endrec = strtoll(argv[optind++], NULL, 10);
4211 rc = llapi_changelog_start(&changelog_priv,
4212 CHANGELOG_FLAG_BLOCK |
4213 CHANGELOG_FLAG_JOBID |
4214 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4217 fprintf(stderr, "Can't start changelog: %s\n",
4218 strerror(errno = -rc));
4222 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4226 if (endrec && rec->cr_index > endrec) {
4227 llapi_changelog_free(&rec);
4230 if (rec->cr_index < startrec) {
4231 llapi_changelog_free(&rec);
4235 secs = rec->cr_time >> 30;
4236 gmtime_r(&secs, &ts);
4237 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4238 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4239 changelog_type2str(rec->cr_type),
4240 ts.tm_hour, ts.tm_min, ts.tm_sec,
4241 (int)(rec->cr_time & ((1<<30) - 1)),
4242 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4243 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4245 if (rec->cr_flags & CLF_JOBID) {
4246 struct changelog_ext_jobid *jid =
4247 changelog_rec_jobid(rec);
4249 if (jid->cr_jobid[0] != '\0')
4250 printf(" j=%s", jid->cr_jobid);
4253 if (rec->cr_namelen)
4254 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4255 rec->cr_namelen, changelog_rec_name(rec));
4257 if (rec->cr_flags & CLF_RENAME) {
4258 struct changelog_ext_rename *rnm =
4259 changelog_rec_rename(rec);
4261 if (!fid_is_zero(&rnm->cr_sfid))
4262 printf(" s="DFID" sp="DFID" %.*s",
4263 PFID(&rnm->cr_sfid),
4264 PFID(&rnm->cr_spfid),
4265 (int)changelog_rec_snamelen(rec),
4266 changelog_rec_sname(rec));
4270 llapi_changelog_free(&rec);
4273 llapi_changelog_fini(&changelog_priv);
4276 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4278 return (rc == 1 ? 0 : rc);
4281 static int lfs_changelog_clear(int argc, char **argv)
4289 endrec = strtoll(argv[3], NULL, 10);
4291 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4294 fprintf(stderr, "%s: record out of range: %llu\n",
4296 else if (rc == -ENOENT)
4297 fprintf(stderr, "%s: no changelog user: %s\n",
4300 fprintf(stderr, "%s error: %s\n", argv[0],
4309 static int lfs_fid2path(int argc, char **argv)
4311 struct option long_opts[] = {
4312 {"cur", no_argument, 0, 'c'},
4313 {"link", required_argument, 0, 'l'},
4314 {"rec", required_argument, 0, 'r'},
4317 char short_opts[] = "cl:r:";
4318 char *device, *fid, *path;
4319 long long recno = -1;
4325 while ((rc = getopt_long(argc, argv, short_opts,
4326 long_opts, NULL)) != -1) {
4332 linkno = strtol(optarg, NULL, 10);
4335 recno = strtoll(optarg, NULL, 10);
4340 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4341 argv[0], argv[optind - 1]);
4349 device = argv[optind++];
4350 path = calloc(1, PATH_MAX);
4352 fprintf(stderr, "error: Not enough memory\n");
4357 while (optind < argc) {
4358 fid = argv[optind++];
4360 lnktmp = (linkno >= 0) ? linkno : 0;
4362 int oldtmp = lnktmp;
4363 long long rectmp = recno;
4365 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4368 fprintf(stderr, "%s: error on FID %s: %s\n",
4369 argv[0], fid, strerror(errno = -rc2));
4376 fprintf(stdout, "%lld ", rectmp);
4377 if (device[0] == '/') {
4378 fprintf(stdout, "%s", device);
4379 if (device[strlen(device) - 1] != '/')
4380 fprintf(stdout, "/");
4381 } else if (path[0] == '\0') {
4382 fprintf(stdout, "/");
4384 fprintf(stdout, "%s\n", path);
4387 /* specified linkno */
4389 if (oldtmp == lnktmp)
4399 static int lfs_path2fid(int argc, char **argv)
4401 struct option long_opts[] = {
4402 {"parents", no_argument, 0, 'p'},
4406 const char short_opts[] = "p";
4407 const char *sep = "";
4410 bool show_parents = false;
4412 while ((rc = getopt_long(argc, argv, short_opts,
4413 long_opts, NULL)) != -1) {
4416 show_parents = true;
4419 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4420 argv[0], argv[optind - 1]);
4425 if (optind > argc - 1)
4427 else if (optind < argc - 1)
4431 for (path = argv + optind; *path != NULL; path++) {
4433 if (!show_parents) {
4434 err = llapi_path2fid(*path, &fid);
4436 printf("%s%s"DFID"\n",
4437 *sep != '\0' ? *path : "", sep,
4440 char name[NAME_MAX + 1];
4441 unsigned int linkno = 0;
4443 while ((err = llapi_path2parent(*path, linkno, &fid,
4444 name, sizeof(name))) == 0) {
4445 if (*sep != '\0' && linkno == 0)
4446 printf("%s%s", *path, sep);
4448 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4453 /* err == -ENODATA is end-of-loop */
4454 if (linkno > 0 && err == -ENODATA) {
4461 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4462 argv[0], show_parents ? "parent " : "", *path,
4474 static int lfs_data_version(int argc, char **argv)
4481 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4486 while ((c = getopt(argc, argv, "nrw")) != -1) {
4489 data_version_flags = 0;
4492 data_version_flags |= LL_DV_RD_FLUSH;
4495 data_version_flags |= LL_DV_WR_FLUSH;
4504 path = argv[optind];
4505 fd = open(path, O_RDONLY);
4507 err(errno, "cannot open file %s", path);
4509 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4511 err(errno, "cannot get version for %s", path);
4513 printf("%ju" "\n", (uintmax_t)data_version);
4519 static int lfs_hsm_state(int argc, char **argv)
4524 struct hsm_user_state hus;
4532 rc = llapi_hsm_state_get(path, &hus);
4534 fprintf(stderr, "can't get hsm state for %s: %s\n",
4535 path, strerror(errno = -rc));
4539 /* Display path name and status flags */
4540 printf("%s: (0x%08x)", path, hus.hus_states);
4542 if (hus.hus_states & HS_RELEASED)
4543 printf(" released");
4544 if (hus.hus_states & HS_EXISTS)
4546 if (hus.hus_states & HS_DIRTY)
4548 if (hus.hus_states & HS_ARCHIVED)
4549 printf(" archived");
4550 /* Display user-settable flags */
4551 if (hus.hus_states & HS_NORELEASE)
4552 printf(" never_release");
4553 if (hus.hus_states & HS_NOARCHIVE)
4554 printf(" never_archive");
4555 if (hus.hus_states & HS_LOST)
4556 printf(" lost_from_hsm");
4558 if (hus.hus_archive_id != 0)
4559 printf(", archive_id:%d", hus.hus_archive_id);
4562 } while (++i < argc);
4567 #define LFS_HSM_SET 0
4568 #define LFS_HSM_CLEAR 1
4571 * Generic function to set or clear HSM flags.
4572 * Used by hsm_set and hsm_clear.
4574 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4576 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4578 struct option long_opts[] = {
4579 {"lost", 0, 0, 'l'},
4580 {"norelease", 0, 0, 'r'},
4581 {"noarchive", 0, 0, 'a'},
4582 {"archived", 0, 0, 'A'},
4583 {"dirty", 0, 0, 'd'},
4584 {"exists", 0, 0, 'e'},
4587 char short_opts[] = "lraAde";
4595 while ((c = getopt_long(argc, argv, short_opts,
4596 long_opts, NULL)) != -1) {
4602 mask |= HS_NOARCHIVE;
4605 mask |= HS_ARCHIVED;
4608 mask |= HS_NORELEASE;
4619 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4620 argv[0], argv[optind - 1]);
4625 /* User should have specified a flag */
4629 while (optind < argc) {
4631 path = argv[optind];
4633 /* If mode == 0, this means we apply the mask. */
4634 if (mode == LFS_HSM_SET)
4635 rc = llapi_hsm_state_set(path, mask, 0, 0);
4637 rc = llapi_hsm_state_set(path, 0, mask, 0);
4640 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4641 path, strerror(errno = -rc));
4650 static int lfs_hsm_action(int argc, char **argv)
4655 struct hsm_current_action hca;
4656 struct hsm_extent he;
4657 enum hsm_user_action hua;
4658 enum hsm_progress_states hps;
4666 rc = llapi_hsm_current_action(path, &hca);
4668 fprintf(stderr, "can't get hsm action for %s: %s\n",
4669 path, strerror(errno = -rc));
4672 he = hca.hca_location;
4673 hua = hca.hca_action;
4674 hps = hca.hca_state;
4676 printf("%s: %s", path, hsm_user_action2name(hua));
4678 /* Skip file without action */
4679 if (hca.hca_action == HUA_NONE) {
4684 printf(" %s ", hsm_progress_state2name(hps));
4686 if ((hps == HPS_RUNNING) &&
4687 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4688 printf("(%llu bytes moved)\n",
4689 (unsigned long long)he.length);
4690 else if ((he.offset + he.length) == LUSTRE_EOF)
4691 printf("(from %llu to EOF)\n",
4692 (unsigned long long)he.offset);
4694 printf("(from %llu to %llu)\n",
4695 (unsigned long long)he.offset,
4696 (unsigned long long)(he.offset + he.length));
4698 } while (++i < argc);
4703 static int lfs_hsm_set(int argc, char **argv)
4705 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4708 static int lfs_hsm_clear(int argc, char **argv)
4710 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4714 * Check file state and return its fid, to be used by lfs_hsm_request().
4716 * \param[in] file Path to file to check
4717 * \param[in,out] fid Pointer to allocated lu_fid struct.
4718 * \param[in,out] last_dev Pointer to last device id used.
4720 * \return 0 on success.
4722 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4728 rc = lstat(file, &st);
4730 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4733 /* Checking for regular file as archiving as posix copytool
4734 * rejects archiving files other than regular files
4736 if (!S_ISREG(st.st_mode)) {
4737 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4740 /* A request should be ... */
4741 if (*last_dev != st.st_dev && *last_dev != 0) {
4742 fprintf(stderr, "All files should be "
4743 "on the same filesystem: %s\n", file);
4746 *last_dev = st.st_dev;
4748 rc = llapi_path2fid(file, fid);
4750 fprintf(stderr, "Cannot read FID of %s: %s\n",
4751 file, strerror(-rc));
4757 /* Fill an HSM HUR item with a given file name.
4759 * If mntpath is set, then the filename is actually a FID, and no
4760 * lookup on the filesystem will be performed.
4762 * \param[in] hur the user request to fill
4763 * \param[in] idx index of the item inside the HUR to fill
4764 * \param[in] mntpath mountpoint of Lustre
4765 * \param[in] fname filename (if mtnpath is NULL)
4766 * or FID (if mntpath is set)
4767 * \param[in] last_dev pointer to last device id used
4769 * \retval 0 on success
4770 * \retval CMD_HELP or a negative errno on error
4772 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4773 const char *mntpath, const char *fname,
4776 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4779 hui->hui_extent.length = -1;
4781 if (mntpath != NULL) {
4784 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4788 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4793 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4797 hur->hur_request.hr_itemcount++;
4802 static int lfs_hsm_request(int argc, char **argv, int action)
4804 struct option long_opts[] = {
4805 {"filelist", 1, 0, 'l'},
4806 {"data", 1, 0, 'D'},
4807 {"archive", 1, 0, 'a'},
4808 {"mntpath", 1, 0, 'm'},
4812 char short_opts[] = "l:D:a:m:";
4813 struct hsm_user_request *hur, *oldhur;
4818 char *filelist = NULL;
4819 char fullpath[PATH_MAX];
4820 char *opaque = NULL;
4824 int nbfile_alloc = 0;
4825 char *some_file = NULL;
4826 char *mntpath = NULL;
4832 while ((c = getopt_long(argc, argv, short_opts,
4833 long_opts, NULL)) != -1) {
4842 if (action != HUA_ARCHIVE &&
4843 action != HUA_REMOVE) {
4845 "error: -a is supported only "
4846 "when archiving or removing\n");
4849 archive_id = atoi(optarg);
4852 if (some_file == NULL) {
4854 some_file = strdup(optarg);
4860 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4861 argv[0], argv[optind - 1]);
4866 /* All remaining args are files, so we have at least nbfile */
4867 nbfile = argc - optind;
4869 if ((nbfile == 0) && (filelist == NULL))
4873 opaque_len = strlen(opaque);
4875 /* Alloc the request structure with enough place to store all files
4876 * from command line. */
4877 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4879 fprintf(stderr, "Cannot create the request: %s\n",
4883 nbfile_alloc = nbfile;
4885 hur->hur_request.hr_action = action;
4886 hur->hur_request.hr_archive_id = archive_id;
4887 hur->hur_request.hr_flags = 0;
4889 /* All remaining args are files, add them */
4890 if (nbfile != 0 && some_file == NULL)
4891 some_file = strdup(argv[optind]);
4893 for (i = 0; i < nbfile; i++) {
4894 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4900 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4902 /* If a filelist was specified, read the filelist from it. */
4903 if (filelist != NULL) {
4904 fp = fopen(filelist, "r");
4906 fprintf(stderr, "Cannot read the file list %s: %s\n",
4907 filelist, strerror(errno));
4912 while ((rc = getline(&line, &len, fp)) != -1) {
4913 /* If allocated buffer was too small, get something
4915 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4918 nbfile_alloc = nbfile_alloc * 2 + 1;
4920 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4923 fprintf(stderr, "hsm: cannot allocate "
4924 "the request: %s\n",
4931 size = hur_len(oldhur);
4933 fprintf(stderr, "hsm: cannot allocate "
4934 "%u files + %u bytes data\n",
4935 oldhur->hur_request.hr_itemcount,
4936 oldhur->hur_request.hr_data_len);
4943 memcpy(hur, oldhur, size);
4948 if (line[strlen(line) - 1] == '\n')
4949 line[strlen(line) - 1] = '\0';
4951 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4952 mntpath, line, &last_dev);
4958 if (some_file == NULL) {
4968 /* If a --data was used, add it to the request */
4969 hur->hur_request.hr_data_len = opaque_len;
4971 memcpy(hur_data(hur), opaque, opaque_len);
4973 /* Send the HSM request */
4974 if (realpath(some_file, fullpath) == NULL) {
4975 fprintf(stderr, "Could not find path '%s': %s\n",
4976 some_file, strerror(errno));
4978 rc = llapi_hsm_request(fullpath, hur);
4980 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4981 some_file, strerror(-rc));
4991 static int lfs_hsm_archive(int argc, char **argv)
4993 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4996 static int lfs_hsm_restore(int argc, char **argv)
4998 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5001 static int lfs_hsm_release(int argc, char **argv)
5003 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5006 static int lfs_hsm_remove(int argc, char **argv)
5008 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5011 static int lfs_hsm_cancel(int argc, char **argv)
5013 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5016 static int lfs_swap_layouts(int argc, char **argv)
5021 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5022 SWAP_LAYOUTS_KEEP_MTIME |
5023 SWAP_LAYOUTS_KEEP_ATIME);
5026 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5028 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5030 enum lu_ladvise_type advice;
5033 advice < ARRAY_SIZE(ladvise_names); advice++) {
5034 if (ladvise_names[advice] == NULL)
5036 if (strcmp(string, ladvise_names[advice]) == 0)
5040 return LU_LADVISE_INVALID;
5043 static int lfs_ladvise(int argc, char **argv)
5045 struct option long_opts[] = {
5046 {"advice", required_argument, 0, 'a'},
5047 {"background", no_argument, 0, 'b'},
5048 {"end", required_argument, 0, 'e'},
5049 {"start", required_argument, 0, 's'},
5050 {"length", required_argument, 0, 'l'},
5053 char short_opts[] = "a:be:l:s:";
5058 struct llapi_lu_ladvise advice;
5059 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5060 unsigned long long start = 0;
5061 unsigned long long end = LUSTRE_EOF;
5062 unsigned long long length = 0;
5063 unsigned long long size_units;
5064 unsigned long long flags = 0;
5067 while ((c = getopt_long(argc, argv, short_opts,
5068 long_opts, NULL)) != -1) {
5071 advice_type = lfs_get_ladvice(optarg);
5072 if (advice_type == LU_LADVISE_INVALID) {
5073 fprintf(stderr, "%s: invalid advice type "
5074 "'%s'\n", argv[0], optarg);
5075 fprintf(stderr, "Valid types:");
5077 for (advice_type = 0;
5078 advice_type < ARRAY_SIZE(ladvise_names);
5080 if (ladvise_names[advice_type] == NULL)
5082 fprintf(stderr, " %s",
5083 ladvise_names[advice_type]);
5085 fprintf(stderr, "\n");
5095 rc = llapi_parse_size(optarg, &end,
5098 fprintf(stderr, "%s: bad end offset '%s'\n",
5105 rc = llapi_parse_size(optarg, &start,
5108 fprintf(stderr, "%s: bad start offset "
5109 "'%s'\n", argv[0], optarg);
5115 rc = llapi_parse_size(optarg, &length,
5118 fprintf(stderr, "%s: bad length '%s'\n",
5126 fprintf(stderr, "%s: option '%s' unrecognized\n",
5127 argv[0], argv[optind - 1]);
5132 if (advice_type == LU_LADVISE_INVALID) {
5133 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5134 fprintf(stderr, "Valid types:");
5135 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5137 if (ladvise_names[advice_type] == NULL)
5139 fprintf(stderr, " %s", ladvise_names[advice_type]);
5141 fprintf(stderr, "\n");
5145 if (argc <= optind) {
5146 fprintf(stderr, "%s: please give one or more file names\n",
5151 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5152 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5157 if (end == LUSTRE_EOF && length != 0)
5158 end = start + length;
5161 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5162 argv[0], start, end);
5166 while (optind < argc) {
5169 path = argv[optind++];
5171 fd = open(path, O_RDONLY);
5173 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5174 argv[0], path, strerror(errno));
5179 advice.lla_start = start;
5180 advice.lla_end = end;
5181 advice.lla_advice = advice_type;
5182 advice.lla_value1 = 0;
5183 advice.lla_value2 = 0;
5184 advice.lla_value3 = 0;
5185 advice.lla_value4 = 0;
5186 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5189 fprintf(stderr, "%s: cannot give advice '%s' to file "
5190 "'%s': %s\n", argv[0],
5191 ladvise_names[advice_type],
5192 path, strerror(errno));
5195 if (rc == 0 && rc2 < 0)
5201 static int lfs_list_commands(int argc, char **argv)
5203 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5205 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5210 int main(int argc, char **argv)
5214 /* Ensure that liblustreapi constructor has run */
5215 if (!liblustreapi_initialized)
5216 fprintf(stderr, "liblustreapi was not properly initialized\n");
5220 Parser_init("lfs > ", cmdlist);
5222 progname = argv[0]; /* Used in error messages */
5224 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5226 rc = Parser_commands();
5229 return rc < 0 ? -rc : rc;
5232 #ifdef _LUSTRE_IDL_H_
5233 /* Everything we need here should be included by lustreapi.h. */
5234 # error "lfs should not depend on lustre_idl.h"
5235 #endif /* _LUSTRE_IDL_H_ */