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.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2015, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
38 * Author: Peter J. Braam <braam@clusterfs.com>
39 * Author: Phil Schwan <phil@clusterfs.com>
40 * Author: Robert Read <rread@clusterfs.com>
58 #include <sys/ioctl.h>
59 #include <sys/quota.h>
61 #include <sys/types.h>
67 #ifdef HAVE_SYS_QUOTA_H
68 # include <sys/quota.h>
71 #include <libcfs/util/string.h>
72 #include <libcfs/util/ioctl.h>
73 #include <libcfs/util/parser.h>
74 #include <lustre/lustreapi.h>
75 #include <lustre_ver.h>
76 #include <lustre_param.h>
79 static int lfs_setstripe(int argc, char **argv);
80 static int lfs_find(int argc, char **argv);
81 static int lfs_getstripe(int argc, char **argv);
82 static int lfs_getdirstripe(int argc, char **argv);
83 static int lfs_setdirstripe(int argc, char **argv);
84 static int lfs_rmentry(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_mdts(int argc, char **argv);
87 static int lfs_df(int argc, char **argv);
88 static int lfs_getname(int argc, char **argv);
89 static int lfs_check(int argc, char **argv);
90 #ifdef HAVE_SYS_QUOTA_H
91 static int lfs_setquota(int argc, char **argv);
92 static int lfs_quota(int argc, char **argv);
94 static int lfs_flushctx(int argc, char **argv);
95 static int lfs_join(int argc, char **argv);
96 static int lfs_lsetfacl(int argc, char **argv);
97 static int lfs_lgetfacl(int argc, char **argv);
98 static int lfs_rsetfacl(int argc, char **argv);
99 static int lfs_rgetfacl(int argc, char **argv);
100 static int lfs_cp(int argc, char **argv);
101 static int lfs_ls(int argc, char **argv);
102 static int lfs_poollist(int argc, char **argv);
103 static int lfs_changelog(int argc, char **argv);
104 static int lfs_changelog_clear(int argc, char **argv);
105 static int lfs_fid2path(int argc, char **argv);
106 static int lfs_path2fid(int argc, char **argv);
107 static int lfs_data_version(int argc, char **argv);
108 static int lfs_hsm_state(int argc, char **argv);
109 static int lfs_hsm_set(int argc, char **argv);
110 static int lfs_hsm_clear(int argc, char **argv);
111 static int lfs_hsm_action(int argc, char **argv);
112 static int lfs_hsm_archive(int argc, char **argv);
113 static int lfs_hsm_restore(int argc, char **argv);
114 static int lfs_hsm_release(int argc, char **argv);
115 static int lfs_hsm_remove(int argc, char **argv);
116 static int lfs_hsm_cancel(int argc, char **argv);
117 static int lfs_swap_layouts(int argc, char **argv);
118 static int lfs_mv(int argc, char **argv);
119 static int lfs_ladvise(int argc, char **argv);
121 /* Setstripe and migrate share mostly the same parameters */
122 #define SSM_CMD_COMMON(cmd) \
123 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
124 " [--stripe-index|-i <start_ost_idx>]\n" \
125 " [--stripe-size|-S <stripe_size>]\n" \
126 " [--pool|-p <pool_name>]\n" \
127 " [--ost-list|-o <ost_indices>]\n"
129 #define SSM_HELP_COMMON \
130 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
131 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
132 "\t respectively)\n" \
133 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
134 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
135 "\tpool_name: Name of OST pool to use (default none)\n" \
136 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
137 "\t Indices be specified in a format of:\n" \
138 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
140 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
141 "\t If --pool is set with --ost-list, then the OSTs\n" \
142 "\t must be the members of the pool."
144 #define SETSTRIPE_USAGE \
145 SSM_CMD_COMMON("setstripe") \
146 " <directory|filename>\n" \
149 #define MIGRATE_USAGE \
150 SSM_CMD_COMMON("migrate ") \
152 " [--non-block|-n]\n" \
156 "\tblock: Block file access during data migration (default)\n" \
157 "\tnon-block: Abort migrations if concurrent access is detected\n" \
159 static const char *progname;
160 static bool file_lease_supported = true;
162 /* all available commands */
163 command_t cmdlist[] = {
164 {"setstripe", lfs_setstripe, 0,
165 "Create a new file with a specific striping pattern or\n"
166 "set the default striping pattern on an existing directory or\n"
167 "delete the default striping pattern from an existing directory\n"
168 "usage: setstripe -d <directory> (to delete default striping)\n"\
171 {"getstripe", lfs_getstripe, 0,
172 "To list the striping info for a given file or files in a\n"
173 "directory or recursively for all files in a directory tree.\n"
174 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
175 " [--stripe-count|-c] [--stripe-index|-i]\n"
176 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
177 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
179 " <directory|filename> ..."},
180 {"setdirstripe", lfs_setdirstripe, 0,
181 "To create a striped directory on a specified MDT. This can only\n"
182 "be done on MDT0 with the right of administrator.\n"
183 "usage: setdirstripe <--count|-c stripe_count>\n"
184 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
185 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
186 "\tstripe_count: stripe count of the striped directory\n"
187 "\tmdt_index: MDT index of first stripe\n"
188 "\thash_type: hash type of the striped directory. Hash types:\n"
189 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
190 " all_char sum of characters % MDT_COUNT (not recommended)\n"
191 "\tdefault_stripe: set default dirstripe of the directory\n"
192 "\tmode: the mode of the directory\n"},
193 {"getdirstripe", lfs_getdirstripe, 0,
194 "To list the striping info for a given directory\n"
195 "or recursively for all directories in a directory tree.\n"
196 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
197 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
198 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
199 {"mkdir", lfs_setdirstripe, 0,
200 "To create a striped directory on a specified MDT. This can only\n"
201 "be done on MDT0 with the right of administrator.\n"
202 "usage: mkdir <--count|-c stripe_count>\n"
203 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
204 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
205 "\tstripe_count: stripe count of the striped directory\n"
206 "\tmdt_index: MDT index of first stripe\n"
207 "\thash_type: hash type of the striped directory. Hash types:\n"
208 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
209 " all_char sum of characters % MDT_COUNT (not recommended)\n"
210 "\tdefault_stripe: set default dirstripe of the directory\n"
211 "\tmode: the mode of the directory\n"},
212 {"rm_entry", lfs_rmentry, 0,
213 "To remove the name entry of the remote directory. Note: This\n"
214 "command will only delete the name entry, i.e. the remote directory\n"
215 "will become inaccessable after this command. This can only be done\n"
216 "by the administrator\n"
217 "usage: rm_entry <dir>\n"},
218 {"pool_list", lfs_poollist, 0,
219 "List pools or pool OSTs\n"
220 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
221 {"find", lfs_find, 0,
222 "find files matching given attributes recursively in directory tree.\n"
223 "usage: find <directory|filename> ...\n"
224 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
225 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
226 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
227 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
228 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
229 " [[!] --stripe-count|-c [+-]<stripes>]\n"
230 " [[!] --stripe-index|-i <index,...>]\n"
231 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
232 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
233 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
234 " [[!] --layout|-L released,raid0]\n"
235 "\t !: used before an option indicates 'NOT' requested attribute\n"
236 "\t -: used before a value indicates 'AT MOST' requested value\n"
237 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
238 {"check", lfs_check, 0,
239 "Display the status of MDS or OSTs (as specified in the command)\n"
240 "or all the servers (MDS and OSTs).\n"
241 "usage: check <osts|mds|servers>"},
242 {"join", lfs_join, 0,
243 "join two lustre files into one.\n"
244 "obsolete, HEAD does not support it anymore.\n"},
245 {"osts", lfs_osts, 0, "list OSTs connected to client "
246 "[for specified path only]\n" "usage: osts [path]"},
247 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
248 "[for specified path only]\n" "usage: mdts [path]"},
250 "report filesystem disk space usage or inodes usage"
251 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
252 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
253 {"getname", lfs_getname, 0, "list instances and specified mount points "
254 "[for specified path only]\n"
255 "Usage: getname [-h]|[path ...] "},
256 #ifdef HAVE_SYS_QUOTA_H
257 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
258 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
259 " -b <block-softlimit> -B <block-hardlimit>\n"
260 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
261 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
262 " [--block-softlimit <block-softlimit>]\n"
263 " [--block-hardlimit <block-hardlimit>]\n"
264 " [--inode-softlimit <inode-softlimit>]\n"
265 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
266 " setquota [-t] <-u|--user|-g|--group>\n"
267 " [--block-grace <block-grace>]\n"
268 " [--inode-grace <inode-grace>] <filesystem>\n"
269 " -b can be used instead of --block-softlimit/--block-grace\n"
270 " -B can be used instead of --block-hardlimit\n"
271 " -i can be used instead of --inode-softlimit/--inode-grace\n"
272 " -I can be used instead of --inode-hardlimit\n\n"
273 "Note: The total quota space will be split into many qunits and\n"
274 " balanced over all server targets, the minimal qunit size is\n"
275 " 1M bytes for block space and 1K inodes for inode space.\n\n"
276 " Quota space rebalancing process will stop when this mininum\n"
277 " value is reached. As a result, quota exceeded can be returned\n"
278 " while many targets still have 1MB or 1K inodes of spare\n"
280 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
281 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
283 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
284 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
286 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
287 "usage: flushctx [-k] [mountpoint...]"},
288 {"lsetfacl", lfs_lsetfacl, 0,
289 "Remote user setfacl for user/group on the same remote client.\n"
290 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
291 {"lgetfacl", lfs_lgetfacl, 0,
292 "Remote user getfacl for user/group on the same remote client.\n"
293 "usage: lgetfacl [-dRLPvh] file ..."},
294 {"rsetfacl", lfs_rsetfacl, 0,
295 "Remote user setfacl for user/group on other clients.\n"
296 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
297 {"rgetfacl", lfs_rgetfacl, 0,
298 "Remote user getfacl for user/group on other clients.\n"
299 "usage: rgetfacl [-dRLPvh] file ..."},
301 "Remote user copy files and directories.\n"
302 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
304 "Remote user list directory contents.\n"
305 "usage: ls [OPTION]... [FILE]..."},
306 {"changelog", lfs_changelog, 0,
307 "Show the metadata changes on an MDT."
308 "\nusage: changelog <mdtname> [startrec [endrec]]"},
309 {"changelog_clear", lfs_changelog_clear, 0,
310 "Indicate that old changelog records up to <endrec> are no longer of "
311 "interest to consumer <id>, allowing the system to free up space.\n"
312 "An <endrec> of 0 means all records.\n"
313 "usage: changelog_clear <mdtname> <id> <endrec>"},
314 {"fid2path", lfs_fid2path, 0,
315 "Resolve the full path(s) for given FID(s). For a specific hardlink "
316 "specify link number <linkno>.\n"
317 /* "For a historical link name, specify changelog record <recno>.\n" */
318 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
319 /* [ --rec <recno> ] */ },
320 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
321 "usage: path2fid [--parents] <path> ..."},
322 {"data_version", lfs_data_version, 0, "Display file data version for "
323 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
324 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
325 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
326 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
327 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
328 "[--archived] [--lost] <file> ..."},
329 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
331 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
332 "[--archived] [--lost] <file> ..."},
333 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
334 "given files.\n" "usage: hsm_action <file> ..."},
335 {"hsm_archive", lfs_hsm_archive, 0,
336 "Archive file to external storage.\n"
337 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
339 {"hsm_restore", lfs_hsm_restore, 0,
340 "Restore file from external storage.\n"
341 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
342 {"hsm_release", lfs_hsm_release, 0,
343 "Release files from Lustre.\n"
344 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
345 {"hsm_remove", lfs_hsm_remove, 0,
346 "Remove file copy from external storage.\n"
347 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
348 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
350 "Note: To remove files from the archive that have been deleted on\n"
351 "Lustre, set mntpath and optionally archive. In that case, all the\n"
352 "positional arguments and entries in the file list must be FIDs."
354 {"hsm_cancel", lfs_hsm_cancel, 0,
355 "Cancel requests related to specified files.\n"
356 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
358 "usage: swap_layouts <path1> <path2>"},
359 {"migrate", lfs_setstripe, 0,
360 "migrate a directory between MDTs.\n"
361 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
363 "\tmdt_idx: index of the destination MDT\n"},
364 {"migrate", lfs_setstripe, 0,
365 "migrate file objects from one OST "
366 "layout\nto another (may be not safe with concurent writes).\n"
368 "[--stripe-count|-c] <stripe_count>\n"
369 "[--stripe-index|-i] <start_ost_index>\n"
370 "[--stripe-size|-S] <stripe_size>\n"
371 "[--pool|-p] <pool_name>\n"
372 "[--ost-list|-o] <ost_indices>\n"
376 "\tstripe_count: number of OSTs to stripe a file over\n"
377 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
378 "\tstripe_size: number of bytes to store before moving to the next OST\n"
379 "\tpool_name: name of the predefined pool of OSTs\n"
380 "\tost_indices: OSTs to stripe over, in order\n"
381 "\tblock: wait for the operation to return before continuing\n"
382 "\tnon-block: do not wait for the operation to return.\n"},
384 "To move directories between MDTs. This command is deprecated, "
385 "use \"migrate\" instead.\n"
386 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
388 {"ladvise", lfs_ladvise, 0,
389 "Provide servers with advice about access patterns for a file.\n"
390 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
391 " [--background|-b]\n"
392 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
394 {"help", Parser_help, 0, "help"},
395 {"exit", Parser_quit, 0, "quit"},
396 {"quit", Parser_quit, 0, "quit"},
397 {"--version", Parser_version, 0,
398 "output build version of the utility and exit"},
403 #define MIGRATION_NONBLOCK 1
406 * Internal helper for migrate_copy_data(). Check lease and report error if
409 * \param[in] fd File descriptor on which to check the lease.
410 * \param[out] lease_broken Set to true if the lease was broken.
411 * \param[in] group_locked Whether a group lock was taken or not.
412 * \param[in] path Name of the file being processed, for error
415 * \retval 0 Migration can keep on going.
416 * \retval -errno Error occurred, abort migration.
418 static int check_lease(int fd, bool *lease_broken, bool group_locked,
423 if (!file_lease_supported)
426 rc = llapi_lease_check(fd);
428 return 0; /* llapi_check_lease returns > 0 on success. */
431 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
433 rc = rc ? rc : -EAGAIN;
435 fprintf(stderr, "%s: external attempt to access file '%s' "
436 "blocked until migration ends.\n", progname, path);
439 *lease_broken = true;
443 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
444 bool group_locked, const char *fname)
453 bool lease_broken = false;
455 /* Use a page-aligned buffer for direct I/O */
456 rc = posix_memalign(&buf, getpagesize(), buf_size);
461 /* read new data only if we have written all
462 * previously read data */
465 rc = check_lease(fd_src, &lease_broken,
466 group_locked, fname);
470 rsize = read(fd_src, buf, buf_size);
473 fprintf(stderr, "%s: %s: read failed: %s\n",
474 progname, fname, strerror(-rc));
484 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
488 "%s: %s: write failed on volatile: %s\n",
489 progname, fname, strerror(-rc));
499 fprintf(stderr, "%s: %s: fsync failed: %s\n",
500 progname, fname, strerror(-rc));
508 static int migrate_copy_timestamps(int fdv, const struct stat *st)
510 struct timeval tv[2] = {
511 {.tv_sec = st->st_atime},
512 {.tv_sec = st->st_mtime}
515 return futimes(fdv, tv);
518 static int migrate_block(int fd, int fdv, const struct stat *st,
519 size_t buf_size, const char *name)
526 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
528 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
529 progname, name, strerror(-rc));
537 /* The grouplock blocks all concurrent accesses to the file.
538 * It has to be taken after llapi_get_data_version as it would
540 rc = llapi_group_lock(fd, gid);
542 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
543 progname, name, strerror(-rc));
547 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
549 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
553 /* Make sure we keep original atime/mtime values */
554 rc = migrate_copy_timestamps(fdv, st);
556 fprintf(stderr, "%s: %s: timestamp copy failed\n",
562 * for a migration we need to check data version on file did
565 * Pass in gid=0 since we already own grouplock. */
566 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
567 SWAP_LAYOUTS_CHECK_DV1);
569 fprintf(stderr, "%s: %s: dataversion changed during copy, "
570 "migration aborted\n", progname, name);
573 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
574 name, strerror(-rc));
579 rc2 = llapi_group_unlock(fd, gid);
580 if (rc2 < 0 && rc == 0) {
581 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
582 progname, name, strerror(-rc2));
589 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
590 size_t buf_size, const char *name)
596 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
598 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
599 progname, name, strerror(-rc));
603 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
605 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
609 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
611 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
612 progname, name, strerror(-rc));
618 fprintf(stderr, "%s: %s: data version changed during "
624 /* Make sure we keep original atime/mtime values */
625 rc = migrate_copy_timestamps(fdv, st);
627 fprintf(stderr, "%s: %s: timestamp copy failed\n",
632 /* Atomically put lease, swap layouts and close.
633 * for a migration we need to check data version on file did
635 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
637 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
638 progname, name, strerror(-rc));
645 static int lfs_migrate(char *name, __u64 migration_flags,
646 struct llapi_stripe_param *param)
650 char parent[PATH_MAX];
653 char volatile_file[sizeof(parent) +
654 LUSTRE_VOLATILE_HDR_LEN +
655 2 * sizeof(mdt_index) +
656 2 * sizeof(random_value) + 4];
659 struct lov_user_md *lum = NULL;
662 bool have_lease_rdlck = false;
666 /* find the right size for the IO and allocate the buffer */
667 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
668 lum = malloc(lum_size);
674 rc = llapi_file_get_stripe(name, lum);
675 /* failure can happen for many reasons and some may be not real errors
677 * in case of a real error, a later call will fail with better
678 * error management */
680 buf_size = 1024 * 1024;
682 buf_size = lum->lmm_stripe_size;
684 /* open file, direct io */
685 /* even if the file is only read, WR mode is nedeed to allow
686 * layout swap on fd */
687 fd = open(name, O_RDWR | O_DIRECT);
690 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
695 if (file_lease_supported) {
696 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
697 if (rc == -EOPNOTSUPP) {
698 /* Older servers do not support file lease.
699 * Disable related checks. This opens race conditions
700 * as explained in LU-4840 */
701 file_lease_supported = false;
703 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
704 progname, name, strerror(-rc));
707 have_lease_rdlck = true;
711 /* search for file directory pathname */
712 if (strlen(name) > sizeof(parent)-1) {
716 strncpy(parent, name, sizeof(parent));
717 ptr = strrchr(parent, '/');
719 if (getcwd(parent, sizeof(parent)) == NULL) {
730 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
732 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
733 progname, name, strerror(-rc));
738 random_value = random();
739 rc = snprintf(volatile_file, sizeof(volatile_file),
740 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
741 mdt_index, random_value);
742 if (rc >= sizeof(volatile_file)) {
747 /* create, open a volatile file, use caching (ie no directio) */
748 fdv = llapi_file_open_param(volatile_file,
749 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
750 S_IRUSR | S_IWUSR, param);
751 } while (fdv == -EEXIST);
755 fprintf(stderr, "%s: %s: cannot create volatile file in"
757 progname, parent, strerror(-rc));
761 /* Not-owner (root?) special case.
762 * Need to set owner/group of volatile file like original.
763 * This will allow to pass related check during layout_swap.
768 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
772 rc = fstat(fdv, &stv);
775 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
776 volatile_file, strerror(errno));
779 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
780 rc = fchown(fdv, st.st_uid, st.st_gid);
783 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
784 name, strerror(errno));
789 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
790 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
792 have_lease_rdlck = false;
793 fdv = -1; /* The volatile file is closed as we put the
794 * lease in non-blocking mode. */
797 /* Blocking mode (forced if servers do not support file lease).
798 * It is also the default mode, since we cannot distinguish
799 * between a broken lease and a server that does not support
800 * atomic swap/close (LU-6785) */
801 rc = migrate_block(fd, fdv, &st, buf_size, name);
805 if (have_lease_rdlck)
822 * Parse a string containing an OST index list into an array of integers.
824 * The input string contains a comma delimited list of individual
825 * indices and ranges, for example "1,2-4,7". Add the indices into the
826 * \a osts array and remove duplicates.
828 * \param[out] osts array to store indices in
829 * \param[in] size size of \a osts array
830 * \param[in] offset starting index in \a osts
831 * \param[in] arg string containing OST index list
833 * \retval positive number of indices in \a osts
834 * \retval -EINVAL unable to parse \a arg
836 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
840 int slots = size - offset;
848 while (!end_of_loop) {
856 ptr = strchrnul(arg, ',');
858 end_of_loop = *ptr == '\0';
861 start_index = strtol(arg, &endptr, 0);
862 if (endptr == arg) /* no data at all */
864 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
869 end_index = start_index;
870 if (*endptr == '-') {
871 end_index = strtol(endptr + 1, &endptr, 0);
874 if (end_index < start_index)
878 for (i = start_index; i <= end_index && slots > 0; i++) {
881 /* remove duplicate */
882 for (j = 0; j < offset; j++) {
886 if (j == offset) { /* no duplicate */
891 if (slots == 0 && i < end_index)
899 if (!end_of_loop && ptr != NULL)
902 return rc < 0 ? rc : nr;
906 static int lfs_setstripe(int argc, char **argv)
908 struct llapi_stripe_param *param = NULL;
909 struct find_param migrate_mdt_param = {
916 unsigned long long st_size;
917 int st_offset, st_count;
921 char *stripe_size_arg = NULL;
922 char *stripe_off_arg = NULL;
923 char *stripe_count_arg = NULL;
924 char *pool_name_arg = NULL;
925 char *mdt_idx_arg = NULL;
926 unsigned long long size_units = 1;
927 bool migrate_mode = false;
928 bool migration_block = false;
929 __u64 migration_flags = 0;
930 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
933 struct option long_opts[] = {
934 /* --block is only valid in migrate mode */
935 {"block", no_argument, 0, 'b'},
936 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
937 /* This formerly implied "stripe-count", but was explicitly
938 * made "stripe-count" for consistency with other options,
939 * and to separate it from "mdt-count" when DNE arrives. */
940 {"count", required_argument, 0, 'c'},
942 {"stripe-count", required_argument, 0, 'c'},
943 {"stripe_count", required_argument, 0, 'c'},
944 {"delete", no_argument, 0, 'd'},
945 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
946 /* This formerly implied "stripe-index", but was explicitly
947 * made "stripe-index" for consistency with other options,
948 * and to separate it from "mdt-index" when DNE arrives. */
949 {"index", required_argument, 0, 'i'},
951 {"stripe-index", required_argument, 0, 'i'},
952 {"stripe_index", required_argument, 0, 'i'},
953 {"mdt-index", required_argument, 0, 'm'},
954 {"mdt_index", required_argument, 0, 'm'},
955 /* --non-block is only valid in migrate mode */
956 {"non-block", no_argument, 0, 'n'},
957 {"ost-list", required_argument, 0, 'o'},
958 {"ost_list", required_argument, 0, 'o'},
959 {"pool", required_argument, 0, 'p'},
960 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
961 /* This formerly implied "--stripe-size", but was confusing
962 * with "lfs find --size|-s", which means "file size", so use
963 * the consistent "--stripe-size|-S" for all commands. */
964 {"size", required_argument, 0, 's'},
966 {"stripe-size", required_argument, 0, 'S'},
967 {"stripe_size", required_argument, 0, 'S'},
968 /* --verbose is only valid in migrate mode */
969 {"verbose", no_argument, 0, 'v'},
977 if (strcmp(argv[0], "migrate") == 0)
980 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
981 long_opts, NULL)) >= 0) {
988 fprintf(stderr, "--block is valid only for"
992 migration_block = true;
995 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
996 if (strcmp(argv[optind - 1], "--count") == 0)
997 fprintf(stderr, "warning: '--count' deprecated"
998 ", use '--stripe-count' instead\n");
1000 stripe_count_arg = optarg;
1003 /* delete the default striping pattern */
1007 nr_osts = parse_targets(osts,
1008 sizeof(osts) / sizeof(__u32),
1012 "error: %s: bad OST indices '%s'\n",
1017 if (st_offset == -1) /* first in the command line */
1018 st_offset = osts[0];
1021 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1022 if (strcmp(argv[optind - 1], "--index") == 0)
1023 fprintf(stderr, "warning: '--index' deprecated"
1024 ", use '--stripe-index' instead\n");
1026 stripe_off_arg = optarg;
1029 if (!migrate_mode) {
1030 fprintf(stderr, "--mdt-index is valid only for"
1034 mdt_idx_arg = optarg;
1037 if (!migrate_mode) {
1038 fprintf(stderr, "--non-block is valid only for"
1042 migration_flags |= MIGRATION_NONBLOCK;
1044 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1046 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1047 fprintf(stderr, "warning: '--size|-s' deprecated, "
1048 "use '--stripe-size|-S' instead\n");
1050 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1052 stripe_size_arg = optarg;
1055 pool_name_arg = optarg;
1058 if (!migrate_mode) {
1059 fprintf(stderr, "--verbose is valid only for"
1063 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1070 fname = argv[optind];
1073 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1074 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1075 fprintf(stderr, "error: %s: cannot specify -d with "
1076 "-s, -c, -o, or -p options\n",
1081 if (optind == argc) {
1082 fprintf(stderr, "error: %s: missing filename|dirname\n",
1087 if (mdt_idx_arg != NULL && optind > 3) {
1088 fprintf(stderr, "error: %s: cannot specify -m with other "
1089 "options\n", argv[0]);
1093 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1095 "error: %s: cannot specify --non-block and --block\n",
1100 if (pool_name_arg != NULL) {
1104 ptr = strchr(pool_name_arg, '.');
1106 ptr = pool_name_arg;
1108 if ((ptr - pool_name_arg) == 0) {
1109 fprintf(stderr, "error: %s: fsname is empty "
1110 "in pool name '%s'\n",
1111 argv[0], pool_name_arg);
1118 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1120 fprintf(stderr, "error: %s: poolname '%s' is "
1122 argv[0], pool_name_arg);
1124 } else if (rc == -2) {
1125 fprintf(stderr, "error: %s: pool name '%s' is too long "
1126 "(max is %d characters)\n",
1127 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1129 } else if (rc > 0) {
1130 fprintf(stderr, "error: %s: char '%c' not allowed in "
1132 argv[0], rc, pool_name_arg);
1137 /* get the stripe size */
1138 if (stripe_size_arg != NULL) {
1139 result = llapi_parse_size(stripe_size_arg, &st_size,
1142 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1143 argv[0], stripe_size_arg);
1147 /* get the stripe offset */
1148 if (stripe_off_arg != NULL) {
1149 st_offset = strtol(stripe_off_arg, &end, 0);
1151 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1152 argv[0], stripe_off_arg);
1156 /* get the stripe count */
1157 if (stripe_count_arg != NULL) {
1158 st_count = strtoul(stripe_count_arg, &end, 0);
1160 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1161 argv[0], stripe_count_arg);
1166 if (mdt_idx_arg != NULL) {
1167 /* initialize migrate mdt parameters */
1168 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1170 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1171 argv[0], mdt_idx_arg);
1174 migrate_mdt_param.fp_migrate = 1;
1176 /* initialize stripe parameters */
1177 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1178 if (param == NULL) {
1179 fprintf(stderr, "error: %s: run out of memory\n",
1184 param->lsp_stripe_size = st_size;
1185 param->lsp_stripe_offset = st_offset;
1186 param->lsp_stripe_count = st_count;
1187 param->lsp_stripe_pattern = 0;
1188 param->lsp_pool = pool_name_arg;
1189 param->lsp_is_specific = false;
1191 if (st_count > 0 && nr_osts != st_count) {
1192 fprintf(stderr, "error: %s: stripe count '%d' "
1193 "doesn't match the number of OSTs: %d\n"
1194 , argv[0], st_count, nr_osts);
1199 param->lsp_is_specific = true;
1200 param->lsp_stripe_count = nr_osts;
1201 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1205 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1206 if (!migrate_mode) {
1207 result = llapi_file_open_param(fname,
1214 } else if (mdt_idx_arg != NULL) {
1215 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1217 result = lfs_migrate(fname, migration_flags, param);
1220 /* Save the first error encountered. */
1224 "error: %s: %s file '%s' failed\n",
1225 argv[0], migrate_mode ? "migrate" : "create",
1235 static int lfs_poollist(int argc, char **argv)
1240 return llapi_poollist(argv[1]);
1243 static int set_time(time_t *time, time_t *set, char *str)
1250 else if (str[0] == '-')
1256 t = strtol(str, NULL, 0);
1257 if (*time < t * 24 * 60 * 60) {
1260 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1264 *set = *time - t * 24 * 60 * 60;
1271 static int name2id(unsigned int *id, char *name, int type)
1274 struct passwd *entry;
1276 if (!(entry = getpwnam(name))) {
1282 *id = entry->pw_uid;
1284 struct group *entry;
1286 if (!(entry = getgrnam(name))) {
1292 *id = entry->gr_gid;
1298 static int id2name(char **name, unsigned int id, int type)
1301 struct passwd *entry;
1303 if (!(entry = getpwuid(id))) {
1309 *name = entry->pw_name;
1311 struct group *entry;
1313 if (!(entry = getgrgid(id))) {
1319 *name = entry->gr_name;
1325 static int name2layout(__u32 *layout, char *name)
1330 for (ptr = name; ; ptr = NULL) {
1331 lyt = strtok(ptr, ",");
1334 if (strcmp(lyt, "released") == 0)
1335 *layout |= LOV_PATTERN_F_RELEASED;
1336 else if (strcmp(lyt, "raid0") == 0)
1337 *layout |= LOV_PATTERN_RAID0;
1344 #define FIND_POOL_OPT 3
1345 static int lfs_find(int argc, char **argv)
1350 struct find_param param = {
1354 struct option long_opts[] = {
1355 {"atime", required_argument, 0, 'A'},
1356 {"stripe-count", required_argument, 0, 'c'},
1357 {"stripe_count", required_argument, 0, 'c'},
1358 {"ctime", required_argument, 0, 'C'},
1359 {"maxdepth", required_argument, 0, 'D'},
1360 {"gid", required_argument, 0, 'g'},
1361 {"group", required_argument, 0, 'G'},
1362 {"stripe-index", required_argument, 0, 'i'},
1363 {"stripe_index", required_argument, 0, 'i'},
1364 {"layout", required_argument, 0, 'L'},
1365 {"mdt", required_argument, 0, 'm'},
1366 {"mtime", required_argument, 0, 'M'},
1367 {"name", required_argument, 0, 'n'},
1368 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1369 {"obd", required_argument, 0, 'O'},
1370 {"ost", required_argument, 0, 'O'},
1371 /* no short option for pool, p/P already used */
1372 {"pool", required_argument, 0, FIND_POOL_OPT},
1373 {"print0", no_argument, 0, 'p'},
1374 {"print", no_argument, 0, 'P'},
1375 {"size", required_argument, 0, 's'},
1376 {"stripe-size", required_argument, 0, 'S'},
1377 {"stripe_size", required_argument, 0, 'S'},
1378 {"type", required_argument, 0, 't'},
1379 {"uid", required_argument, 0, 'u'},
1380 {"user", required_argument, 0, 'U'},
1393 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1394 while ((c = getopt_long_only(argc, argv,
1395 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1396 long_opts, NULL)) >= 0) {
1401 /* '!' is part of option */
1402 /* when getopt_long_only() finds a string which is not
1403 * an option nor a known option argument it returns 1
1404 * in that case if we already have found pathstart and pathend
1405 * (i.e. we have the list of pathnames),
1406 * the only supported value is "!"
1408 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1409 if (!isoption && pathend != -1) {
1410 fprintf(stderr, "err: %s: filename|dirname must either "
1411 "precede options or follow options\n",
1416 if (!isoption && pathstart == -1)
1417 pathstart = optind - 1;
1418 if (isoption && pathstart != -1 && pathend == -1)
1419 pathend = optind - 2;
1425 /* unknown; opt is "!" or path component,
1426 * checking done above.
1428 if (strcmp(optarg, "!") == 0)
1432 xtime = ¶m.fp_atime;
1433 xsign = ¶m.fp_asign;
1434 param.fp_exclude_atime = !!neg_opt;
1435 /* no break, this falls through to 'C' for ctime */
1438 xtime = ¶m.fp_ctime;
1439 xsign = ¶m.fp_csign;
1440 param.fp_exclude_ctime = !!neg_opt;
1442 /* no break, this falls through to 'M' for mtime */
1445 xtime = ¶m.fp_mtime;
1446 xsign = ¶m.fp_msign;
1447 param.fp_exclude_mtime = !!neg_opt;
1449 rc = set_time(&t, xtime, optarg);
1450 if (rc == INT_MAX) {
1458 if (optarg[0] == '+') {
1459 param.fp_stripe_count_sign = -1;
1461 } else if (optarg[0] == '-') {
1462 param.fp_stripe_count_sign = 1;
1466 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1467 if (*endptr != '\0') {
1468 fprintf(stderr,"error: bad stripe_count '%s'\n",
1473 param.fp_check_stripe_count = 1;
1474 param.fp_exclude_stripe_count = !!neg_opt;
1477 param.fp_max_depth = strtol(optarg, 0, 0);
1481 rc = name2id(¶m.fp_gid, optarg, GROUP);
1483 param.fp_gid = strtoul(optarg, &endptr, 10);
1484 if (*endptr != '\0') {
1485 fprintf(stderr, "Group/GID: %s cannot "
1486 "be found.\n", optarg);
1491 param.fp_exclude_gid = !!neg_opt;
1492 param.fp_check_gid = 1;
1495 ret = name2layout(¶m.fp_layout, optarg);
1498 param.fp_exclude_layout = !!neg_opt;
1499 param.fp_check_layout = 1;
1503 rc = name2id(¶m.fp_uid, optarg, USER);
1505 param.fp_uid = strtoul(optarg, &endptr, 10);
1506 if (*endptr != '\0') {
1507 fprintf(stderr, "User/UID: %s cannot "
1508 "be found.\n", optarg);
1513 param.fp_exclude_uid = !!neg_opt;
1514 param.fp_check_uid = 1;
1517 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1519 "Pool name %s is too long"
1520 " (max is %d)\n", optarg,
1525 /* we do check for empty pool because empty pool
1526 * is used to find V1 lov attributes */
1527 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1528 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1529 param.fp_exclude_pool = !!neg_opt;
1530 param.fp_check_pool = 1;
1533 param.fp_pattern = (char *)optarg;
1534 param.fp_exclude_pattern = !!neg_opt;
1539 char *buf, *token, *next, *p;
1543 buf = strdup(optarg);
1549 param.fp_exclude_obd = !!neg_opt;
1552 while (token && *token) {
1553 token = strchr(token, ',');
1560 param.fp_exclude_mdt = !!neg_opt;
1561 param.fp_num_alloc_mdts += len;
1562 tmp = realloc(param.fp_mdt_uuid,
1563 param.fp_num_alloc_mdts *
1564 sizeof(*param.fp_mdt_uuid));
1570 param.fp_mdt_uuid = tmp;
1572 param.fp_exclude_obd = !!neg_opt;
1573 param.fp_num_alloc_obds += len;
1574 tmp = realloc(param.fp_obd_uuid,
1575 param.fp_num_alloc_obds *
1576 sizeof(*param.fp_obd_uuid));
1582 param.fp_obd_uuid = tmp;
1584 for (token = buf; token && *token; token = next) {
1585 struct obd_uuid *puuid;
1588 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1591 ¶m.fp_obd_uuid[param.fp_num_obds++];
1593 p = strchr(token, ',');
1600 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1605 strncpy(puuid->uuid, token,
1606 sizeof(puuid->uuid));
1614 param.fp_zero_end = 1;
1619 if (optarg[0] == '+') {
1620 param.fp_size_sign = -1;
1622 } else if (optarg[0] == '-') {
1623 param.fp_size_sign = 1;
1627 ret = llapi_parse_size(optarg, ¶m.fp_size,
1628 ¶m.fp_size_units, 0);
1630 fprintf(stderr, "error: bad file size '%s'\n",
1634 param.fp_check_size = 1;
1635 param.fp_exclude_size = !!neg_opt;
1638 if (optarg[0] == '+') {
1639 param.fp_stripe_size_sign = -1;
1641 } else if (optarg[0] == '-') {
1642 param.fp_stripe_size_sign = 1;
1646 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1647 ¶m.fp_stripe_size_units, 0);
1649 fprintf(stderr, "error: bad stripe_size '%s'\n",
1653 param.fp_check_stripe_size = 1;
1654 param.fp_exclude_stripe_size = !!neg_opt;
1657 param.fp_exclude_type = !!neg_opt;
1658 switch (optarg[0]) {
1660 param.fp_type = S_IFBLK;
1663 param.fp_type = S_IFCHR;
1666 param.fp_type = S_IFDIR;
1669 param.fp_type = S_IFREG;
1672 param.fp_type = S_IFLNK;
1675 param.fp_type = S_IFIFO;
1678 param.fp_type = S_IFSOCK;
1681 fprintf(stderr, "error: %s: bad type '%s'\n",
1693 if (pathstart == -1) {
1694 fprintf(stderr, "error: %s: no filename|pathname\n",
1698 } else if (pathend == -1) {
1704 rc = llapi_find(argv[pathstart], ¶m);
1705 if (rc != 0 && ret == 0)
1707 } while (++pathstart < pathend);
1710 fprintf(stderr, "error: %s failed for %s.\n",
1711 argv[0], argv[optind - 1]);
1713 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1714 free(param.fp_obd_uuid);
1716 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1717 free(param.fp_mdt_uuid);
1722 static int lfs_getstripe_internal(int argc, char **argv,
1723 struct find_param *param)
1725 struct option long_opts[] = {
1726 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1727 /* This formerly implied "stripe-count", but was explicitly
1728 * made "stripe-count" for consistency with other options,
1729 * and to separate it from "mdt-count" when DNE arrives. */
1730 {"count", no_argument, 0, 'c'},
1732 {"stripe-count", no_argument, 0, 'c'},
1733 {"stripe_count", no_argument, 0, 'c'},
1734 {"directory", no_argument, 0, 'd'},
1735 {"default", no_argument, 0, 'D'},
1736 {"generation", no_argument, 0, 'g'},
1737 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1738 /* This formerly implied "stripe-index", but was explicitly
1739 * made "stripe-index" for consistency with other options,
1740 * and to separate it from "mdt-index" when DNE arrives. */
1741 {"index", no_argument, 0, 'i'},
1743 {"stripe-index", no_argument, 0, 'i'},
1744 {"stripe_index", no_argument, 0, 'i'},
1745 {"layout", no_argument, 0, 'L'},
1746 {"mdt-index", no_argument, 0, 'M'},
1747 {"mdt_index", no_argument, 0, 'M'},
1748 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1749 /* This formerly implied "stripe-index", but was confusing
1750 * with "file offset" (which will eventually be needed for
1751 * with different layouts by offset), so deprecate it. */
1752 {"offset", no_argument, 0, 'o'},
1754 {"obd", required_argument, 0, 'O'},
1755 {"ost", required_argument, 0, 'O'},
1756 {"pool", no_argument, 0, 'p'},
1757 {"quiet", no_argument, 0, 'q'},
1758 {"recursive", no_argument, 0, 'r'},
1759 {"raw", no_argument, 0, 'R'},
1760 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1761 /* This formerly implied "--stripe-size", but was confusing
1762 * with "lfs find --size|-s", which means "file size", so use
1763 * the consistent "--stripe-size|-S" for all commands. */
1764 {"size", no_argument, 0, 's'},
1766 {"stripe-size", no_argument, 0, 'S'},
1767 {"stripe_size", no_argument, 0, 'S'},
1768 {"verbose", no_argument, 0, 'v'},
1773 param->fp_max_depth = 1;
1774 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1775 long_opts, NULL)) != -1) {
1778 if (param->fp_obd_uuid) {
1780 "error: %s: only one obduuid allowed",
1784 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1790 param->fp_max_depth = 0;
1793 param->fp_get_default_lmv = 1;
1796 param->fp_recursive = 1;
1799 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1802 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1803 if (strcmp(argv[optind - 1], "--count") == 0)
1804 fprintf(stderr, "warning: '--count' deprecated,"
1805 " use '--stripe-count' instead\n");
1807 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1808 param->fp_verbose |= VERBOSE_COUNT;
1809 param->fp_max_depth = 0;
1812 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1814 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1815 fprintf(stderr, "warning: '--size|-s' deprecated, "
1816 "use '--stripe-size|-S' instead\n");
1818 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1820 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1821 param->fp_verbose |= VERBOSE_SIZE;
1822 param->fp_max_depth = 0;
1825 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1827 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1828 "use '--stripe-index|-i' instead\n");
1831 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1832 if (strcmp(argv[optind - 1], "--index") == 0)
1833 fprintf(stderr, "warning: '--index' deprecated"
1834 ", use '--stripe-index' instead\n");
1836 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1837 param->fp_verbose |= VERBOSE_OFFSET;
1838 param->fp_max_depth = 0;
1842 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1843 param->fp_verbose |= VERBOSE_POOL;
1844 param->fp_max_depth = 0;
1848 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1849 param->fp_verbose |= VERBOSE_GENERATION;
1850 param->fp_max_depth = 0;
1854 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1855 param->fp_verbose |= VERBOSE_LAYOUT;
1856 param->fp_max_depth = 0;
1860 if (!(param->fp_verbose & VERBOSE_DETAIL))
1861 param->fp_max_depth = 0;
1862 param->fp_verbose |= VERBOSE_MDTINDEX;
1875 if (param->fp_recursive)
1876 param->fp_max_depth = -1;
1878 if (!param->fp_verbose)
1879 param->fp_verbose = VERBOSE_ALL;
1880 if (param->fp_quiet)
1881 param->fp_verbose = VERBOSE_OBJID;
1884 rc = llapi_getstripe(argv[optind], param);
1885 } while (++optind < argc && !rc);
1888 fprintf(stderr, "error: %s failed for %s.\n",
1889 argv[0], argv[optind - 1]);
1893 static int lfs_tgts(int argc, char **argv)
1895 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1896 struct find_param param;
1897 int index = 0, rc=0;
1902 if (argc == 2 && !realpath(argv[1], path)) {
1904 fprintf(stderr, "error: invalid path '%s': %s\n",
1905 argv[1], strerror(-rc));
1909 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1910 /* Check if we have a mount point */
1911 if (mntdir[0] == '\0')
1914 memset(¶m, 0, sizeof(param));
1915 if (!strcmp(argv[0], "mdts"))
1916 param.fp_get_lmv = 1;
1918 rc = llapi_ostlist(mntdir, ¶m);
1920 fprintf(stderr, "error: %s: failed on %s\n",
1923 if (path[0] != '\0')
1925 memset(mntdir, 0, PATH_MAX);
1931 static int lfs_getstripe(int argc, char **argv)
1933 struct find_param param = { 0 };
1934 return lfs_getstripe_internal(argc, argv, ¶m);
1938 static int lfs_getdirstripe(int argc, char **argv)
1940 struct find_param param = { 0 };
1942 param.fp_get_lmv = 1;
1943 return lfs_getstripe_internal(argc, argv, ¶m);
1947 static int lfs_setdirstripe(int argc, char **argv)
1951 unsigned int stripe_offset = -1;
1952 unsigned int stripe_count = 1;
1953 enum lmv_hash_type hash_type;
1956 char *stripe_offset_opt = NULL;
1957 char *stripe_count_opt = NULL;
1958 char *stripe_hash_opt = NULL;
1959 char *mode_opt = NULL;
1960 bool default_stripe = false;
1961 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1962 mode_t previous_mode = 0;
1963 bool delete = false;
1965 struct option long_opts[] = {
1966 {"count", required_argument, 0, 'c'},
1967 {"delete", no_argument, 0, 'd'},
1968 {"index", required_argument, 0, 'i'},
1969 {"mode", required_argument, 0, 'm'},
1970 {"hash-type", required_argument, 0, 't'},
1971 {"default_stripe", no_argument, 0, 'D'},
1975 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1982 stripe_count_opt = optarg;
1986 default_stripe = true;
1989 default_stripe = true;
1992 stripe_offset_opt = optarg;
1998 stripe_hash_opt = optarg;
2001 fprintf(stderr, "error: %s: option '%s' "
2003 argv[0], argv[optind - 1]);
2008 if (optind == argc) {
2009 fprintf(stderr, "error: %s: missing dirname\n",
2014 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2015 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2020 if (stripe_offset_opt != NULL) {
2021 /* get the stripe offset */
2022 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2024 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2025 argv[0], stripe_offset_opt);
2031 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2032 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2033 " or -i options.\n", argv[0]);
2041 if (mode_opt != NULL) {
2042 mode = strtoul(mode_opt, &end, 8);
2044 fprintf(stderr, "error: %s: bad mode '%s'\n",
2048 previous_mode = umask(0);
2051 if (stripe_hash_opt == NULL ||
2052 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2053 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2054 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2055 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2057 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2058 argv[0], stripe_hash_opt);
2062 /* get the stripe count */
2063 if (stripe_count_opt != NULL) {
2064 stripe_count = strtoul(stripe_count_opt, &end, 0);
2066 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2067 argv[0], stripe_count_opt);
2072 dname = argv[optind];
2074 if (default_stripe) {
2075 result = llapi_dir_set_default_lmv_stripe(dname,
2076 stripe_offset, stripe_count,
2079 result = llapi_dir_create_pool(dname, mode,
2081 stripe_count, hash_type,
2086 fprintf(stderr, "error: %s: create stripe dir '%s' "
2087 "failed\n", argv[0], dname);
2090 dname = argv[++optind];
2091 } while (dname != NULL);
2093 if (mode_opt != NULL)
2094 umask(previous_mode);
2100 static int lfs_rmentry(int argc, char **argv)
2107 fprintf(stderr, "error: %s: missing dirname\n",
2113 dname = argv[index];
2114 while (dname != NULL) {
2115 result = llapi_direntry_remove(dname);
2117 fprintf(stderr, "error: %s: remove dir entry '%s' "
2118 "failed\n", argv[0], dname);
2121 dname = argv[++index];
2126 static int lfs_mv(int argc, char **argv)
2128 struct find_param param = {
2135 struct option long_opts[] = {
2136 {"mdt-index", required_argument, 0, 'M'},
2137 {"verbose", no_argument, 0, 'v'},
2141 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2144 param.fp_mdt_index = strtoul(optarg, &end, 0);
2146 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2153 param.fp_verbose = VERBOSE_DETAIL;
2157 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2158 argv[0], argv[optind - 1]);
2163 if (param.fp_mdt_index == -1) {
2164 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2168 if (optind >= argc) {
2169 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2173 param.fp_migrate = 1;
2174 rc = llapi_migrate_mdt(argv[optind], ¶m);
2176 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2177 argv[0], argv[optind], param.fp_mdt_index,
2182 static int lfs_osts(int argc, char **argv)
2184 return lfs_tgts(argc, argv);
2187 static int lfs_mdts(int argc, char **argv)
2189 return lfs_tgts(argc, argv);
2192 #define COOK(value) \
2195 while (value > 1024) { \
2203 #define CDF "%11llu"
2204 #define HDF "%8.1f%c"
2208 static int showdf(char *mntdir, struct obd_statfs *stat,
2209 char *uuid, int ishow, int cooked,
2210 char *type, int index, int rc)
2212 long long avail, used, total;
2214 char *suffix = "KMGTPEZY";
2215 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2216 char tbuf[3 * sizeof(__u64)];
2217 char ubuf[3 * sizeof(__u64)];
2218 char abuf[3 * sizeof(__u64)];
2219 char rbuf[3 * sizeof(__u64)];
2227 avail = stat->os_ffree;
2228 used = stat->os_files - stat->os_ffree;
2229 total = stat->os_files;
2231 int shift = cooked ? 0 : 10;
2233 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2234 used = ((stat->os_blocks - stat->os_bfree) *
2235 stat->os_bsize) >> shift;
2236 total = (stat->os_blocks * stat->os_bsize) >> shift;
2239 if ((used + avail) > 0)
2240 ratio = (double)used / (double)(used + avail);
2246 cook_val = (double)total;
2249 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2251 sprintf(tbuf, CDF, total);
2253 cook_val = (double)used;
2256 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2258 sprintf(ubuf, CDF, used);
2260 cook_val = (double)avail;
2263 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2265 sprintf(abuf, CDF, avail);
2267 sprintf(tbuf, CDF, total);
2268 sprintf(ubuf, CDF, used);
2269 sprintf(abuf, CDF, avail);
2272 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2273 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2274 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2276 printf("[%s:%d]\n", type, index);
2282 printf(UUF": inactive device\n", uuid);
2285 printf(UUF": %s\n", uuid, strerror(-rc));
2292 struct ll_stat_type {
2297 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2298 int cooked, int lazy)
2300 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2301 struct obd_uuid uuid_buf;
2302 char *poolname = NULL;
2303 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2304 { LL_STATFS_LOV, "OST" },
2306 struct ll_stat_type *tp;
2307 __u64 ost_ffree = 0;
2313 poolname = strchr(pool, '.');
2314 if (poolname != NULL) {
2315 if (strncmp(fsname, pool, strlen(fsname))) {
2316 fprintf(stderr, "filesystem name incorrect\n");
2325 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2326 "UUID", "Inodes", "IUsed", "IFree",
2327 "IUse%", "Mounted on");
2329 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2330 "UUID", cooked ? "bytes" : "1K-blocks",
2331 "Used", "Available", "Use%", "Mounted on");
2333 for (tp = types; tp->st_name != NULL; tp++) {
2334 for (index = 0; ; index++) {
2335 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2336 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2337 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2338 rc = llapi_obd_statfs(mntdir, type, index,
2339 &stat_buf, &uuid_buf);
2346 if (poolname && tp->st_op == LL_STATFS_LOV &&
2347 llapi_search_ost(fsname, poolname,
2348 obd_uuid2str(&uuid_buf)) != 1)
2351 /* the llapi_obd_statfs() call may have returned with
2352 * an error, but if it filled in uuid_buf we will at
2353 * lease use that to print out a message for that OBD.
2354 * If we didn't get anything in the uuid_buf, then fill
2355 * it in so that we can print an error message. */
2356 if (uuid_buf.uuid[0] == '\0')
2357 sprintf(uuid_buf.uuid, "%s%04x",
2358 tp->st_name, index);
2359 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2360 ishow, cooked, tp->st_name, index, rc);
2363 if (tp->st_op == LL_STATFS_LMV) {
2364 sum.os_ffree += stat_buf.os_ffree;
2365 sum.os_files += stat_buf.os_files;
2366 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2367 sum.os_blocks += stat_buf.os_blocks *
2369 sum.os_bfree += stat_buf.os_bfree *
2371 sum.os_bavail += stat_buf.os_bavail *
2373 ost_ffree += stat_buf.os_ffree;
2375 } else if (rc == -EINVAL || rc == -EFAULT) {
2381 /* If we don't have as many objects free on the OST as inodes
2382 * on the MDS, we reduce the total number of inodes to
2383 * compensate, so that the "inodes in use" number is correct.
2384 * Matches ll_statfs_internal() so the results are consistent. */
2385 if (ost_ffree < sum.os_ffree) {
2386 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2387 sum.os_ffree = ost_ffree;
2390 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2395 static int lfs_df(int argc, char **argv)
2397 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2398 int ishow = 0, cooked = 0;
2400 int c, rc = 0, index = 0;
2401 char fsname[PATH_MAX] = "", *pool_name = NULL;
2402 struct option long_opts[] = {
2403 {"pool", required_argument, 0, 'p'},
2404 {"lazy", 0, 0, 'l'},
2408 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2426 if (optind < argc && !realpath(argv[optind], path)) {
2428 fprintf(stderr, "error: invalid path '%s': %s\n",
2429 argv[optind], strerror(-rc));
2433 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2434 /* Check if we have a mount point */
2435 if (mntdir[0] == '\0')
2438 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2439 if (rc || path[0] != '\0')
2441 fsname[0] = '\0'; /* avoid matching in next loop */
2442 mntdir[0] = '\0'; /* avoid matching in next loop */
2448 static int lfs_getname(int argc, char **argv)
2450 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2451 int rc = 0, index = 0, c;
2452 char buf[sizeof(struct obd_uuid)];
2454 while ((c = getopt(argc, argv, "h")) != -1)
2457 if (optind == argc) { /* no paths specified, get all paths. */
2458 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2459 rc = llapi_getname(mntdir, buf, sizeof(buf));
2462 "cannot get name for `%s': %s\n",
2463 mntdir, strerror(-rc));
2467 printf("%s %s\n", buf, mntdir);
2469 path[0] = fsname[0] = mntdir[0] = 0;
2471 } else { /* paths specified, only attempt to search these. */
2472 for (; optind < argc; optind++) {
2473 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2476 "cannot get name for `%s': %s\n",
2477 argv[optind], strerror(-rc));
2481 printf("%s %s\n", buf, argv[optind]);
2487 static int lfs_check(int argc, char **argv)
2490 char mntdir[PATH_MAX] = {'\0'};
2499 obd_types[0] = obd_type1;
2500 obd_types[1] = obd_type2;
2502 if (strcmp(argv[1], "osts") == 0) {
2503 strcpy(obd_types[0], "osc");
2504 } else if (strcmp(argv[1], "mds") == 0) {
2505 strcpy(obd_types[0], "mdc");
2506 } else if (strcmp(argv[1], "servers") == 0) {
2508 strcpy(obd_types[0], "osc");
2509 strcpy(obd_types[1], "mdc");
2511 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2516 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2517 if (rc < 0 || mntdir[0] == '\0') {
2518 fprintf(stderr, "No suitable Lustre mount found\n");
2522 rc = llapi_target_check(num_types, obd_types, mntdir);
2524 fprintf(stderr, "error: %s: %s status failed\n",
2531 static int lfs_join(int argc, char **argv)
2533 fprintf(stderr, "join two lustre files into one.\n"
2534 "obsolete, HEAD does not support it anymore.\n");
2538 #ifdef HAVE_SYS_QUOTA_H
2539 #define ARG2INT(nr, str, msg) \
2542 nr = strtol(str, &endp, 0); \
2544 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2549 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2551 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2552 * returns the value or ULONG_MAX on integer overflow or incorrect format
2554 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2555 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2556 * 3. empty integer value is interpreted as 0
2558 static unsigned long str2sec(const char* timestr)
2560 const char spec[] = "smhdw";
2561 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2562 unsigned long val = 0;
2565 if (strpbrk(timestr, spec) == NULL) {
2566 /* no specifiers inside the time string,
2567 should treat it as an integer value */
2568 val = strtoul(timestr, &tail, 10);
2569 return *tail ? ULONG_MAX : val;
2572 /* format string is XXwXXdXXhXXmXXs */
2578 v = strtoul(timestr, &tail, 10);
2579 if (v == ULONG_MAX || *tail == '\0')
2580 /* value too large (ULONG_MAX or more)
2581 or missing specifier */
2584 ptr = strchr(spec, *tail);
2586 /* unknown specifier */
2591 /* check if product will overflow the type */
2592 if (!(v < ULONG_MAX / mult[ind]))
2595 ADD_OVERFLOW(val, mult[ind] * v);
2596 if (val == ULONG_MAX)
2608 #define ARG2ULL(nr, str, def_units) \
2610 unsigned long long limit, units = def_units; \
2613 rc = llapi_parse_size(str, &limit, &units, 1); \
2615 fprintf(stderr, "error: bad limit value %s\n", str); \
2621 static inline int has_times_option(int argc, char **argv)
2625 for (i = 1; i < argc; i++)
2626 if (!strcmp(argv[i], "-t"))
2632 int lfs_setquota_times(int argc, char **argv)
2635 struct if_quotactl qctl;
2636 char *mnt, *obd_type = (char *)qctl.obd_type;
2637 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2638 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2639 struct option long_opts[] = {
2640 {"block-grace", required_argument, 0, 'b'},
2641 {"group", no_argument, 0, 'g'},
2642 {"inode-grace", required_argument, 0, 'i'},
2643 {"times", no_argument, 0, 't'},
2644 {"user", no_argument, 0, 'u'},
2648 memset(&qctl, 0, sizeof(qctl));
2649 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2650 qctl.qc_type = UGQUOTA;
2652 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2656 if (qctl.qc_type != UGQUOTA) {
2657 fprintf(stderr, "error: -u and -g can't be used "
2658 "more than once\n");
2661 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2664 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2665 fprintf(stderr, "error: bad block-grace: %s\n",
2669 dqb->dqb_valid |= QIF_BTIME;
2672 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2673 fprintf(stderr, "error: bad inode-grace: %s\n",
2677 dqb->dqb_valid |= QIF_ITIME;
2679 case 't': /* Yes, of course! */
2681 default: /* getopt prints error message for us when opterr != 0 */
2686 if (qctl.qc_type == UGQUOTA) {
2687 fprintf(stderr, "error: neither -u nor -g specified\n");
2691 if (optind != argc - 1) {
2692 fprintf(stderr, "error: unexpected parameters encountered\n");
2697 rc = llapi_quotactl(mnt, &qctl);
2700 fprintf(stderr, "%s %s ", obd_type,
2701 obd_uuid2str(&qctl.obd_uuid));
2702 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2709 #define BSLIMIT (1 << 0)
2710 #define BHLIMIT (1 << 1)
2711 #define ISLIMIT (1 << 2)
2712 #define IHLIMIT (1 << 3)
2714 int lfs_setquota(int argc, char **argv)
2717 struct if_quotactl qctl;
2718 char *mnt, *obd_type = (char *)qctl.obd_type;
2719 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2720 struct option long_opts[] = {
2721 {"block-softlimit", required_argument, 0, 'b'},
2722 {"block-hardlimit", required_argument, 0, 'B'},
2723 {"group", required_argument, 0, 'g'},
2724 {"inode-softlimit", required_argument, 0, 'i'},
2725 {"inode-hardlimit", required_argument, 0, 'I'},
2726 {"user", required_argument, 0, 'u'},
2729 unsigned limit_mask = 0;
2732 if (has_times_option(argc, argv))
2733 return lfs_setquota_times(argc, argv);
2735 memset(&qctl, 0, sizeof(qctl));
2736 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2737 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2738 * so it can be used as a marker that qc_type
2739 * isn't reinitialized from command line */
2741 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2745 if (qctl.qc_type != UGQUOTA) {
2746 fprintf(stderr, "error: -u and -g can't be used"
2747 " more than once\n");
2750 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2751 rc = name2id(&qctl.qc_id, optarg,
2752 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2754 qctl.qc_id = strtoul(optarg, &endptr, 10);
2755 if (*endptr != '\0') {
2756 fprintf(stderr, "error: can't find id "
2757 "for name %s\n", optarg);
2763 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2764 dqb->dqb_bsoftlimit >>= 10;
2765 limit_mask |= BSLIMIT;
2766 if (dqb->dqb_bsoftlimit &&
2767 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2768 fprintf(stderr, "warning: block softlimit is "
2769 "smaller than the miminal qunit size, "
2770 "please see the help of setquota or "
2771 "Lustre manual for details.\n");
2774 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2775 dqb->dqb_bhardlimit >>= 10;
2776 limit_mask |= BHLIMIT;
2777 if (dqb->dqb_bhardlimit &&
2778 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2779 fprintf(stderr, "warning: block hardlimit is "
2780 "smaller than the miminal qunit size, "
2781 "please see the help of setquota or "
2782 "Lustre manual for details.\n");
2785 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2786 limit_mask |= ISLIMIT;
2787 if (dqb->dqb_isoftlimit &&
2788 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2789 fprintf(stderr, "warning: inode softlimit is "
2790 "smaller than the miminal qunit size, "
2791 "please see the help of setquota or "
2792 "Lustre manual for details.\n");
2795 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2796 limit_mask |= IHLIMIT;
2797 if (dqb->dqb_ihardlimit &&
2798 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2799 fprintf(stderr, "warning: inode hardlimit is "
2800 "smaller than the miminal qunit size, "
2801 "please see the help of setquota or "
2802 "Lustre manual for details.\n");
2804 default: /* getopt prints error message for us when opterr != 0 */
2809 if (qctl.qc_type == UGQUOTA) {
2810 fprintf(stderr, "error: neither -u nor -g was specified\n");
2814 if (limit_mask == 0) {
2815 fprintf(stderr, "error: at least one limit must be specified\n");
2819 if (optind != argc - 1) {
2820 fprintf(stderr, "error: unexpected parameters encountered\n");
2826 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2827 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2828 /* sigh, we can't just set blimits/ilimits */
2829 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2830 .qc_type = qctl.qc_type,
2831 .qc_id = qctl.qc_id};
2833 rc = llapi_quotactl(mnt, &tmp_qctl);
2835 fprintf(stderr, "error: setquota failed while retrieving"
2836 " current quota settings (%s)\n",
2841 if (!(limit_mask & BHLIMIT))
2842 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2843 if (!(limit_mask & BSLIMIT))
2844 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2845 if (!(limit_mask & IHLIMIT))
2846 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2847 if (!(limit_mask & ISLIMIT))
2848 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2850 /* Keep grace times if we have got no softlimit arguments */
2851 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2852 dqb->dqb_valid |= QIF_BTIME;
2853 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2856 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2857 dqb->dqb_valid |= QIF_ITIME;
2858 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2862 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2863 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2865 rc = llapi_quotactl(mnt, &qctl);
2868 fprintf(stderr, "%s %s ", obd_type,
2869 obd_uuid2str(&qctl.obd_uuid));
2870 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2877 static inline char *type2name(int check_type)
2879 if (check_type == USRQUOTA)
2881 else if (check_type == GRPQUOTA)
2887 /* Converts seconds value into format string
2888 * result is returned in buf
2890 * 1. result is in descenting order: 1w2d3h4m5s
2891 * 2. zero fields are not filled (except for p. 3): 5d1s
2892 * 3. zero seconds value is presented as "0s"
2894 static char * __sec2str(time_t seconds, char *buf)
2896 const char spec[] = "smhdw";
2897 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2902 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2903 c = seconds / mult[i];
2905 if (c > 0 || (i == 0 && buf == tail))
2906 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2914 static void sec2str(time_t seconds, char *buf, int rc)
2921 tail = __sec2str(seconds, tail);
2923 if (rc && tail - buf < 39) {
2929 static void diff2str(time_t seconds, char *buf, time_t now)
2935 if (seconds <= now) {
2936 strcpy(buf, "none");
2939 __sec2str(seconds - now, buf);
2942 static void print_quota_title(char *name, struct if_quotactl *qctl,
2943 bool human_readable)
2945 printf("Disk quotas for %s %s (%cid %u):\n",
2946 type2name(qctl->qc_type), name,
2947 *type2name(qctl->qc_type), qctl->qc_id);
2948 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2949 "Filesystem", human_readable ? "used" : "kbytes",
2950 "quota", "limit", "grace",
2951 "files", "quota", "limit", "grace");
2954 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
2957 snprintf(buf, buflen, "%ju", (uintmax_t)num);
2960 snprintf(buf, buflen, "%5.4gP",
2961 (double)num / ((__u64)1 << 40));
2963 snprintf(buf, buflen, "%5.4gT",
2964 (double)num / (1 << 30));
2966 snprintf(buf, buflen, "%5.4gG",
2967 (double)num / (1 << 20));
2969 snprintf(buf, buflen, "%5.4gM",
2970 (double)num / (1 << 10));
2972 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
2976 #define STRBUF_LEN 32
2977 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2984 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2985 int bover = 0, iover = 0;
2986 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2987 char numbuf[3][STRBUF_LEN];
2989 char strbuf[STRBUF_LEN];
2991 if (dqb->dqb_bhardlimit &&
2992 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2994 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2995 if (dqb->dqb_btime > now) {
3002 if (dqb->dqb_ihardlimit &&
3003 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3005 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3006 if (dqb->dqb_itime > now) {
3014 if (strlen(mnt) > 15)
3015 printf("%s\n%15s", mnt, "");
3017 printf("%15s", mnt);
3020 diff2str(dqb->dqb_btime, timebuf, now);
3022 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3023 strbuf, sizeof(strbuf), h);
3024 if (rc == -EREMOTEIO)
3025 sprintf(numbuf[0], "%s*", strbuf);
3027 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3028 "%s" : "[%s]", strbuf);
3030 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3031 if (type == QC_GENERAL)
3032 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3033 "%s" : "[%s]", strbuf);
3035 sprintf(numbuf[1], "%s", "-");
3037 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3038 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3039 "%s" : "[%s]", strbuf);
3041 printf(" %7s%c %6s %7s %7s",
3042 numbuf[0], bover ? '*' : ' ', numbuf[1],
3043 numbuf[2], bover > 1 ? timebuf : "-");
3046 diff2str(dqb->dqb_itime, timebuf, now);
3048 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3049 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3051 if (type == QC_GENERAL)
3052 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3054 (uintmax_t)dqb->dqb_isoftlimit);
3056 sprintf(numbuf[1], "%s", "-");
3058 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3059 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3061 if (type != QC_OSTIDX)
3062 printf(" %7s%c %6s %7s %7s",
3063 numbuf[0], iover ? '*' : ' ', numbuf[1],
3064 numbuf[2], iover > 1 ? timebuf : "-");
3066 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3069 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3070 qctl->qc_cmd == Q_GETOINFO) {
3074 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3075 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3076 printf("Block grace time: %s; Inode grace time: %s\n",
3077 bgtimebuf, igtimebuf);
3081 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3082 bool h, __u64 *total)
3084 int rc = 0, rc1 = 0, count = 0;
3085 __u32 valid = qctl->qc_valid;
3087 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3089 fprintf(stderr, "can not get %s count: %s\n",
3090 is_mdt ? "mdt": "ost", strerror(-rc));
3094 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3095 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3096 rc = llapi_quotactl(mnt, qctl);
3098 /* It is remote client case. */
3099 if (-rc == EOPNOTSUPP) {
3106 fprintf(stderr, "quotactl %s%d failed.\n",
3107 is_mdt ? "mdt": "ost", qctl->qc_idx);
3111 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3112 qctl->qc_valid, 0, h);
3113 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3114 qctl->qc_dqblk.dqb_bhardlimit;
3117 qctl->qc_valid = valid;
3121 static int lfs_quota(int argc, char **argv)
3124 char *mnt, *name = NULL;
3125 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3126 .qc_type = UGQUOTA };
3127 char *obd_type = (char *)qctl.obd_type;
3128 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3129 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3130 verbose = 0, pass = 0, quiet = 0, inacc;
3132 __u32 valid = QC_GENERAL, idx = 0;
3133 __u64 total_ialloc = 0, total_balloc = 0;
3134 bool human_readable = false;
3136 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3139 if (qctl.qc_type != UGQUOTA) {
3140 fprintf(stderr, "error: use either -u or -g\n");
3143 qctl.qc_type = USRQUOTA;
3146 if (qctl.qc_type != UGQUOTA) {
3147 fprintf(stderr, "error: use either -u or -g\n");
3150 qctl.qc_type = GRPQUOTA;
3153 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3156 valid = qctl.qc_valid = QC_UUID;
3157 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3160 valid = qctl.qc_valid = QC_MDTIDX;
3161 idx = qctl.qc_idx = atoi(optarg);
3164 valid = qctl.qc_valid = QC_OSTIDX;
3165 idx = qctl.qc_idx = atoi(optarg);
3174 human_readable = true;
3177 fprintf(stderr, "error: %s: option '-%c' "
3178 "unrecognized\n", argv[0], c);
3183 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3184 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3185 optind == argc - 1) {
3187 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3188 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3189 qctl.qc_valid = valid;
3192 qctl.qc_type = USRQUOTA;
3193 qctl.qc_id = geteuid();
3195 qctl.qc_type = GRPQUOTA;
3196 qctl.qc_id = getegid();
3198 rc = id2name(&name, qctl.qc_id,
3199 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3202 /* lfs quota -u username /path/to/lustre/mount */
3203 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3204 /* options should be followed by u/g-name and mntpoint */
3205 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3206 fprintf(stderr, "error: missing quota argument(s)\n");
3210 name = argv[optind++];
3211 rc = name2id(&qctl.qc_id, name,
3212 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3214 qctl.qc_id = strtoul(name, &endptr, 10);
3215 if (*endptr != '\0') {
3216 fprintf(stderr, "error: can't find id for name "
3221 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3222 fprintf(stderr, "error: missing quota info argument(s)\n");
3228 rc1 = llapi_quotactl(mnt, &qctl);
3232 fprintf(stderr, "%s quotas are not enabled.\n",
3233 qctl.qc_type == USRQUOTA ? "user" : "group");
3236 fprintf(stderr, "Permission denied.\n");
3238 /* We already got a "No such file..." message. */
3241 fprintf(stderr, "Unexpected quotactl error: %s\n",
3246 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3247 print_quota_title(name, &qctl, human_readable);
3249 if (rc1 && *obd_type)
3250 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3252 if (qctl.qc_valid != QC_GENERAL)
3255 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3256 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3257 (QIF_LIMITS|QIF_USAGE));
3259 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3261 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3263 char strbuf[STRBUF_LEN];
3265 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3267 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3269 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3271 printf("Total allocated inode limit: %ju, total "
3272 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3276 if (rc1 || rc2 || rc3 || inacc)
3277 printf("Some errors happened when getting quota info. "
3278 "Some devices may be not working or deactivated. "
3279 "The data in \"[]\" is inaccurate.\n");
3287 #endif /* HAVE_SYS_QUOTA_H! */
3289 static int flushctx_ioctl(char *mp)
3293 fd = open(mp, O_RDONLY);
3295 fprintf(stderr, "flushctx: error open %s: %s\n",
3296 mp, strerror(errno));
3300 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3302 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3303 mp, strerror(errno));
3309 static int lfs_flushctx(int argc, char **argv)
3311 int kdestroy = 0, c;
3312 char mntdir[PATH_MAX] = {'\0'};
3316 while ((c = getopt(argc, argv, "k")) != -1) {
3322 fprintf(stderr, "error: %s: option '-%c' "
3323 "unrecognized\n", argv[0], c);
3329 if ((rc = system("kdestroy > /dev/null")) != 0) {
3330 rc = WEXITSTATUS(rc);
3331 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3335 if (optind >= argc) {
3336 /* flush for all mounted lustre fs. */
3337 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3338 /* Check if we have a mount point */
3339 if (mntdir[0] == '\0')
3342 if (flushctx_ioctl(mntdir))
3345 mntdir[0] = '\0'; /* avoid matching in next loop */
3348 /* flush fs as specified */
3349 while (optind < argc) {
3350 if (flushctx_ioctl(argv[optind++]))
3357 static int lfs_lsetfacl(int argc, char **argv)
3360 return(llapi_lsetfacl(argc, argv));
3363 static int lfs_lgetfacl(int argc, char **argv)
3366 return(llapi_lgetfacl(argc, argv));
3369 static int lfs_rsetfacl(int argc, char **argv)
3372 return(llapi_rsetfacl(argc, argv));
3375 static int lfs_rgetfacl(int argc, char **argv)
3378 return(llapi_rgetfacl(argc, argv));
3381 static int lfs_cp(int argc, char **argv)
3383 return(llapi_cp(argc, argv));
3386 static int lfs_ls(int argc, char **argv)
3388 return(llapi_ls(argc, argv));
3391 static int lfs_changelog(int argc, char **argv)
3393 void *changelog_priv;
3394 struct changelog_rec *rec;
3395 long long startrec = 0, endrec = 0;
3397 struct option long_opts[] = {
3398 {"follow", no_argument, 0, 'f'},
3401 char short_opts[] = "f";
3404 while ((rc = getopt_long(argc, argv, short_opts,
3405 long_opts, NULL)) != -1) {
3413 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3414 argv[0], argv[optind - 1]);
3421 mdd = argv[optind++];
3423 startrec = strtoll(argv[optind++], NULL, 10);
3425 endrec = strtoll(argv[optind++], NULL, 10);
3427 rc = llapi_changelog_start(&changelog_priv,
3428 CHANGELOG_FLAG_BLOCK |
3429 CHANGELOG_FLAG_JOBID |
3430 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3433 fprintf(stderr, "Can't start changelog: %s\n",
3434 strerror(errno = -rc));
3438 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3442 if (endrec && rec->cr_index > endrec) {
3443 llapi_changelog_free(&rec);
3446 if (rec->cr_index < startrec) {
3447 llapi_changelog_free(&rec);
3451 secs = rec->cr_time >> 30;
3452 gmtime_r(&secs, &ts);
3453 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3454 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3455 changelog_type2str(rec->cr_type),
3456 ts.tm_hour, ts.tm_min, ts.tm_sec,
3457 (int)(rec->cr_time & ((1<<30) - 1)),
3458 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3459 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3461 if (rec->cr_flags & CLF_JOBID) {
3462 struct changelog_ext_jobid *jid =
3463 changelog_rec_jobid(rec);
3465 if (jid->cr_jobid[0] != '\0')
3466 printf(" j=%s", jid->cr_jobid);
3469 if (rec->cr_namelen)
3470 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3471 rec->cr_namelen, changelog_rec_name(rec));
3473 if (rec->cr_flags & CLF_RENAME) {
3474 struct changelog_ext_rename *rnm =
3475 changelog_rec_rename(rec);
3477 if (!fid_is_zero(&rnm->cr_sfid))
3478 printf(" s="DFID" sp="DFID" %.*s",
3479 PFID(&rnm->cr_sfid),
3480 PFID(&rnm->cr_spfid),
3481 (int)changelog_rec_snamelen(rec),
3482 changelog_rec_sname(rec));
3486 llapi_changelog_free(&rec);
3489 llapi_changelog_fini(&changelog_priv);
3492 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3494 return (rc == 1 ? 0 : rc);
3497 static int lfs_changelog_clear(int argc, char **argv)
3505 endrec = strtoll(argv[3], NULL, 10);
3507 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3509 fprintf(stderr, "%s error: %s\n", argv[0],
3510 strerror(errno = -rc));
3514 static int lfs_fid2path(int argc, char **argv)
3516 struct option long_opts[] = {
3517 {"cur", no_argument, 0, 'c'},
3518 {"link", required_argument, 0, 'l'},
3519 {"rec", required_argument, 0, 'r'},
3522 char short_opts[] = "cl:r:";
3523 char *device, *fid, *path;
3524 long long recno = -1;
3530 while ((rc = getopt_long(argc, argv, short_opts,
3531 long_opts, NULL)) != -1) {
3537 linkno = strtol(optarg, NULL, 10);
3540 recno = strtoll(optarg, NULL, 10);
3545 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3546 argv[0], argv[optind - 1]);
3554 device = argv[optind++];
3555 path = calloc(1, PATH_MAX);
3557 fprintf(stderr, "error: Not enough memory\n");
3562 while (optind < argc) {
3563 fid = argv[optind++];
3565 lnktmp = (linkno >= 0) ? linkno : 0;
3567 int oldtmp = lnktmp;
3568 long long rectmp = recno;
3570 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3573 fprintf(stderr, "%s: error on FID %s: %s\n",
3574 argv[0], fid, strerror(errno = -rc2));
3581 fprintf(stdout, "%lld ", rectmp);
3582 if (device[0] == '/') {
3583 fprintf(stdout, "%s", device);
3584 if (device[strlen(device) - 1] != '/')
3585 fprintf(stdout, "/");
3586 } else if (path[0] == '\0') {
3587 fprintf(stdout, "/");
3589 fprintf(stdout, "%s\n", path);
3592 /* specified linkno */
3594 if (oldtmp == lnktmp)
3604 static int lfs_path2fid(int argc, char **argv)
3606 struct option long_opts[] = {
3607 {"parents", no_argument, 0, 'p'},
3611 const char short_opts[] = "p";
3612 const char *sep = "";
3615 bool show_parents = false;
3617 while ((rc = getopt_long(argc, argv, short_opts,
3618 long_opts, NULL)) != -1) {
3621 show_parents = true;
3624 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3625 argv[0], argv[optind - 1]);
3630 if (optind > argc - 1)
3632 else if (optind < argc - 1)
3636 for (path = argv + optind; *path != NULL; path++) {
3638 if (!show_parents) {
3639 err = llapi_path2fid(*path, &fid);
3641 printf("%s%s"DFID"\n",
3642 *sep != '\0' ? *path : "", sep,
3645 char name[NAME_MAX + 1];
3646 unsigned int linkno = 0;
3648 while ((err = llapi_path2parent(*path, linkno, &fid,
3649 name, sizeof(name))) == 0) {
3650 if (*sep != '\0' && linkno == 0)
3651 printf("%s%s", *path, sep);
3653 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3658 /* err == -ENODATA is end-of-loop */
3659 if (linkno > 0 && err == -ENODATA) {
3666 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3667 argv[0], show_parents ? "parent " : "", *path,
3679 static int lfs_data_version(int argc, char **argv)
3686 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3691 while ((c = getopt(argc, argv, "nrw")) != -1) {
3694 data_version_flags = 0;
3697 data_version_flags |= LL_DV_RD_FLUSH;
3700 data_version_flags |= LL_DV_WR_FLUSH;
3709 path = argv[optind];
3710 fd = open(path, O_RDONLY);
3712 err(errno, "cannot open file %s", path);
3714 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3716 err(errno, "cannot get version for %s", path);
3718 printf("%ju" "\n", (uintmax_t)data_version);
3724 static int lfs_hsm_state(int argc, char **argv)
3729 struct hsm_user_state hus;
3737 rc = llapi_hsm_state_get(path, &hus);
3739 fprintf(stderr, "can't get hsm state for %s: %s\n",
3740 path, strerror(errno = -rc));
3744 /* Display path name and status flags */
3745 printf("%s: (0x%08x)", path, hus.hus_states);
3747 if (hus.hus_states & HS_RELEASED)
3748 printf(" released");
3749 if (hus.hus_states & HS_EXISTS)
3751 if (hus.hus_states & HS_DIRTY)
3753 if (hus.hus_states & HS_ARCHIVED)
3754 printf(" archived");
3755 /* Display user-settable flags */
3756 if (hus.hus_states & HS_NORELEASE)
3757 printf(" never_release");
3758 if (hus.hus_states & HS_NOARCHIVE)
3759 printf(" never_archive");
3760 if (hus.hus_states & HS_LOST)
3761 printf(" lost_from_hsm");
3763 if (hus.hus_archive_id != 0)
3764 printf(", archive_id:%d", hus.hus_archive_id);
3767 } while (++i < argc);
3772 #define LFS_HSM_SET 0
3773 #define LFS_HSM_CLEAR 1
3776 * Generic function to set or clear HSM flags.
3777 * Used by hsm_set and hsm_clear.
3779 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3781 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3783 struct option long_opts[] = {
3784 {"lost", 0, 0, 'l'},
3785 {"norelease", 0, 0, 'r'},
3786 {"noarchive", 0, 0, 'a'},
3787 {"archived", 0, 0, 'A'},
3788 {"dirty", 0, 0, 'd'},
3789 {"exists", 0, 0, 'e'},
3792 char short_opts[] = "lraAde";
3800 while ((c = getopt_long(argc, argv, short_opts,
3801 long_opts, NULL)) != -1) {
3807 mask |= HS_NOARCHIVE;
3810 mask |= HS_ARCHIVED;
3813 mask |= HS_NORELEASE;
3824 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3825 argv[0], argv[optind - 1]);
3830 /* User should have specified a flag */
3834 while (optind < argc) {
3836 path = argv[optind];
3838 /* If mode == 0, this means we apply the mask. */
3839 if (mode == LFS_HSM_SET)
3840 rc = llapi_hsm_state_set(path, mask, 0, 0);
3842 rc = llapi_hsm_state_set(path, 0, mask, 0);
3845 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3846 path, strerror(errno = -rc));
3855 static int lfs_hsm_action(int argc, char **argv)
3860 struct hsm_current_action hca;
3861 struct hsm_extent he;
3862 enum hsm_user_action hua;
3863 enum hsm_progress_states hps;
3871 rc = llapi_hsm_current_action(path, &hca);
3873 fprintf(stderr, "can't get hsm action for %s: %s\n",
3874 path, strerror(errno = -rc));
3877 he = hca.hca_location;
3878 hua = hca.hca_action;
3879 hps = hca.hca_state;
3881 printf("%s: %s", path, hsm_user_action2name(hua));
3883 /* Skip file without action */
3884 if (hca.hca_action == HUA_NONE) {
3889 printf(" %s ", hsm_progress_state2name(hps));
3891 if ((hps == HPS_RUNNING) &&
3892 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3893 printf("(%llu bytes moved)\n",
3894 (unsigned long long)he.length);
3895 else if ((he.offset + he.length) == LUSTRE_EOF)
3896 printf("(from %llu to EOF)\n",
3897 (unsigned long long)he.offset);
3899 printf("(from %llu to %llu)\n",
3900 (unsigned long long)he.offset,
3901 (unsigned long long)(he.offset + he.length));
3903 } while (++i < argc);
3908 static int lfs_hsm_set(int argc, char **argv)
3910 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3913 static int lfs_hsm_clear(int argc, char **argv)
3915 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3919 * Check file state and return its fid, to be used by lfs_hsm_request().
3921 * \param[in] file Path to file to check
3922 * \param[in,out] fid Pointer to allocated lu_fid struct.
3923 * \param[in,out] last_dev Pointer to last device id used.
3925 * \return 0 on success.
3927 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3933 rc = lstat(file, &st);
3935 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3938 /* Checking for regular file as archiving as posix copytool
3939 * rejects archiving files other than regular files
3941 if (!S_ISREG(st.st_mode)) {
3942 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3945 /* A request should be ... */
3946 if (*last_dev != st.st_dev && *last_dev != 0) {
3947 fprintf(stderr, "All files should be "
3948 "on the same filesystem: %s\n", file);
3951 *last_dev = st.st_dev;
3953 rc = llapi_path2fid(file, fid);
3955 fprintf(stderr, "Cannot read FID of %s: %s\n",
3956 file, strerror(-rc));
3962 /* Fill an HSM HUR item with a given file name.
3964 * If mntpath is set, then the filename is actually a FID, and no
3965 * lookup on the filesystem will be performed.
3967 * \param[in] hur the user request to fill
3968 * \param[in] idx index of the item inside the HUR to fill
3969 * \param[in] mntpath mountpoint of Lustre
3970 * \param[in] fname filename (if mtnpath is NULL)
3971 * or FID (if mntpath is set)
3972 * \param[in] last_dev pointer to last device id used
3974 * \retval 0 on success
3975 * \retval CMD_HELP or a negative errno on error
3977 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3978 const char *mntpath, const char *fname,
3981 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3984 hui->hui_extent.length = -1;
3986 if (mntpath != NULL) {
3989 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3993 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3998 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4002 hur->hur_request.hr_itemcount++;
4007 static int lfs_hsm_request(int argc, char **argv, int action)
4009 struct option long_opts[] = {
4010 {"filelist", 1, 0, 'l'},
4011 {"data", 1, 0, 'D'},
4012 {"archive", 1, 0, 'a'},
4013 {"mntpath", 1, 0, 'm'},
4017 char short_opts[] = "l:D:a:m:";
4018 struct hsm_user_request *hur, *oldhur;
4023 char *filelist = NULL;
4024 char fullpath[PATH_MAX];
4025 char *opaque = NULL;
4029 int nbfile_alloc = 0;
4030 char *some_file = NULL;
4031 char *mntpath = NULL;
4037 while ((c = getopt_long(argc, argv, short_opts,
4038 long_opts, NULL)) != -1) {
4047 if (action != HUA_ARCHIVE &&
4048 action != HUA_REMOVE) {
4050 "error: -a is supported only "
4051 "when archiving or removing\n");
4054 archive_id = atoi(optarg);
4057 if (some_file == NULL) {
4059 some_file = strdup(optarg);
4065 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4066 argv[0], argv[optind - 1]);
4071 /* All remaining args are files, so we have at least nbfile */
4072 nbfile = argc - optind;
4074 if ((nbfile == 0) && (filelist == NULL))
4078 opaque_len = strlen(opaque);
4080 /* Alloc the request structure with enough place to store all files
4081 * from command line. */
4082 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4084 fprintf(stderr, "Cannot create the request: %s\n",
4088 nbfile_alloc = nbfile;
4090 hur->hur_request.hr_action = action;
4091 hur->hur_request.hr_archive_id = archive_id;
4092 hur->hur_request.hr_flags = 0;
4094 /* All remaining args are files, add them */
4095 if (nbfile != 0 && some_file == NULL)
4096 some_file = strdup(argv[optind]);
4098 for (i = 0; i < nbfile; i++) {
4099 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4105 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4107 /* If a filelist was specified, read the filelist from it. */
4108 if (filelist != NULL) {
4109 fp = fopen(filelist, "r");
4111 fprintf(stderr, "Cannot read the file list %s: %s\n",
4112 filelist, strerror(errno));
4117 while ((rc = getline(&line, &len, fp)) != -1) {
4118 /* If allocated buffer was too small, get something
4120 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4123 nbfile_alloc = nbfile_alloc * 2 + 1;
4125 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4128 fprintf(stderr, "hsm: cannot allocate "
4129 "the request: %s\n",
4136 size = hur_len(oldhur);
4138 fprintf(stderr, "hsm: cannot allocate "
4139 "%u files + %u bytes data\n",
4140 oldhur->hur_request.hr_itemcount,
4141 oldhur->hur_request.hr_data_len);
4148 memcpy(hur, oldhur, size);
4153 if (line[strlen(line) - 1] == '\n')
4154 line[strlen(line) - 1] = '\0';
4156 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4157 mntpath, line, &last_dev);
4163 if (some_file == NULL) {
4173 /* If a --data was used, add it to the request */
4174 hur->hur_request.hr_data_len = opaque_len;
4176 memcpy(hur_data(hur), opaque, opaque_len);
4178 /* Send the HSM request */
4179 if (realpath(some_file, fullpath) == NULL) {
4180 fprintf(stderr, "Could not find path '%s': %s\n",
4181 some_file, strerror(errno));
4183 rc = llapi_hsm_request(fullpath, hur);
4185 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4186 some_file, strerror(-rc));
4196 static int lfs_hsm_archive(int argc, char **argv)
4198 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4201 static int lfs_hsm_restore(int argc, char **argv)
4203 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4206 static int lfs_hsm_release(int argc, char **argv)
4208 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4211 static int lfs_hsm_remove(int argc, char **argv)
4213 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4216 static int lfs_hsm_cancel(int argc, char **argv)
4218 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4221 static int lfs_swap_layouts(int argc, char **argv)
4226 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4227 SWAP_LAYOUTS_KEEP_MTIME |
4228 SWAP_LAYOUTS_KEEP_ATIME);
4231 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4233 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4235 enum lu_ladvise_type advice;
4238 advice < ARRAY_SIZE(ladvise_names); advice++) {
4239 if (ladvise_names[advice] == NULL)
4241 if (strcmp(string, ladvise_names[advice]) == 0)
4245 return LU_LADVISE_INVALID;
4248 static int lfs_ladvise(int argc, char **argv)
4250 struct option long_opts[] = {
4251 {"advice", required_argument, 0, 'a'},
4252 {"background", no_argument, 0, 'b'},
4253 {"end", required_argument, 0, 'e'},
4254 {"start", required_argument, 0, 's'},
4255 {"length", required_argument, 0, 'l'},
4258 char short_opts[] = "a:be:l:s:";
4263 struct lu_ladvise advice;
4264 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4265 unsigned long long start = 0;
4266 unsigned long long end = LUSTRE_EOF;
4267 unsigned long long length = 0;
4268 unsigned long long size_units;
4269 unsigned long long flags = 0;
4272 while ((c = getopt_long(argc, argv, short_opts,
4273 long_opts, NULL)) != -1) {
4276 advice_type = lfs_get_ladvice(optarg);
4277 if (advice_type == LU_LADVISE_INVALID) {
4278 fprintf(stderr, "%s: invalid advice type "
4279 "'%s'\n", argv[0], optarg);
4280 fprintf(stderr, "Valid types:");
4282 for (advice_type = 0;
4283 advice_type < ARRAY_SIZE(ladvise_names);
4285 if (ladvise_names[advice_type] == NULL)
4287 fprintf(stderr, " %s",
4288 ladvise_names[advice_type]);
4290 fprintf(stderr, "\n");
4300 rc = llapi_parse_size(optarg, &end,
4303 fprintf(stderr, "%s: bad end offset '%s'\n",
4310 rc = llapi_parse_size(optarg, &start,
4313 fprintf(stderr, "%s: bad start offset "
4314 "'%s'\n", argv[0], optarg);
4320 rc = llapi_parse_size(optarg, &length,
4323 fprintf(stderr, "%s: bad length '%s'\n",
4331 fprintf(stderr, "%s: option '%s' unrecognized\n",
4332 argv[0], argv[optind - 1]);
4337 if (advice_type == LU_LADVISE_INVALID) {
4338 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4339 fprintf(stderr, "Valid types:");
4340 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4342 if (ladvise_names[advice_type] == NULL)
4344 fprintf(stderr, " %s", ladvise_names[advice_type]);
4346 fprintf(stderr, "\n");
4350 if (argc <= optind) {
4351 fprintf(stderr, "%s: please give one or more file names\n",
4356 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4357 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4362 if (end == LUSTRE_EOF && length != 0)
4363 end = start + length;
4366 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4367 argv[0], start, end);
4371 while (optind < argc) {
4374 path = argv[optind++];
4376 fd = open(path, O_RDONLY);
4378 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4379 argv[0], path, strerror(errno));
4384 advice.lla_start = start;
4385 advice.lla_end = end;
4386 advice.lla_advice = advice_type;
4387 advice.lla_padding = 0;
4388 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4391 fprintf(stderr, "%s: cannot give advice '%s' to file "
4392 "'%s': %s\n", argv[0],
4393 ladvise_names[advice_type],
4394 path, strerror(errno));
4397 if (rc == 0 && rc2 < 0)
4403 int main(int argc, char **argv)
4407 /* Ensure that liblustreapi constructor has run */
4408 if (!liblustreapi_initialized)
4409 fprintf(stderr, "liblustreapi was not properly initialized\n");
4413 Parser_init("lfs > ", cmdlist);
4415 progname = argv[0]; /* Used in error messages */
4417 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4419 rc = Parser_commands();
4422 return rc < 0 ? -rc : rc;
4425 #ifdef _LUSTRE_IDL_H_
4426 /* Everything we need here should be included by lustreapi.h. */
4427 # error "lfs should not depend on lustre_idl.h"
4428 #endif /* _LUSTRE_IDL_H_ */