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);
120 /* Setstripe and migrate share mostly the same parameters */
121 #define SSM_CMD_COMMON(cmd) \
122 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
123 " [--stripe-index|-i <start_ost_idx>]\n" \
124 " [--stripe-size|-S <stripe_size>]\n" \
125 " [--pool|-p <pool_name>]\n" \
126 " [--ost-list|-o <ost_indices>]\n"
128 #define SSM_HELP_COMMON \
129 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
130 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
131 "\t respectively)\n" \
132 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
133 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
134 "\tpool_name: Name of OST pool to use (default none)\n" \
135 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
136 "\t Indices be specified in a format of:\n" \
137 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
139 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
140 "\t If --pool is set with --ost-list, then the OSTs\n" \
141 "\t must be the members of the pool."
143 #define SETSTRIPE_USAGE \
144 SSM_CMD_COMMON("setstripe") \
145 " <directory|filename>\n" \
148 #define MIGRATE_USAGE \
149 SSM_CMD_COMMON("migrate ") \
151 " [--non-block|-n]\n" \
155 "\tblock: Block file access during data migration (default)\n" \
156 "\tnon-block: Abort migrations if concurrent access is detected\n" \
158 static const char *progname;
159 static bool file_lease_supported = true;
161 /* all available commands */
162 command_t cmdlist[] = {
163 {"setstripe", lfs_setstripe, 0,
164 "Create a new file with a specific striping pattern or\n"
165 "set the default striping pattern on an existing directory or\n"
166 "delete the default striping pattern from an existing directory\n"
167 "usage: setstripe -d <directory> (to delete default striping)\n"\
170 {"getstripe", lfs_getstripe, 0,
171 "To list the striping info for a given file or files in a\n"
172 "directory or recursively for all files in a directory tree.\n"
173 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
174 " [--stripe-count|-c] [--stripe-index|-i]\n"
175 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
176 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
178 " <directory|filename> ..."},
179 {"setdirstripe", lfs_setdirstripe, 0,
180 "To create a striped directory on a specified MDT. This can only\n"
181 "be done on MDT0 with the right of administrator.\n"
182 "usage: setdirstripe <--count|-c stripe_count>\n"
183 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
184 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
185 "\tstripe_count: stripe count of the striped directory\n"
186 "\tmdt_index: MDT index of first stripe\n"
187 "\thash_type: hash type of the striped directory. Hash types:\n"
188 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
189 " all_char sum of characters % MDT_COUNT (not recommended)\n"
190 "\tdefault_stripe: set default dirstripe of the directory\n"
191 "\tmode: the mode of the directory\n"},
192 {"getdirstripe", lfs_getdirstripe, 0,
193 "To list the striping info for a given directory\n"
194 "or recursively for all directories in a directory tree.\n"
195 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
196 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
197 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
198 {"mkdir", lfs_setdirstripe, 0,
199 "To create a striped directory on a specified MDT. This can only\n"
200 "be done on MDT0 with the right of administrator.\n"
201 "usage: mkdir <--count|-c stripe_count>\n"
202 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
203 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
204 "\tstripe_count: stripe count of the striped directory\n"
205 "\tmdt_index: MDT index of first stripe\n"
206 "\thash_type: hash type of the striped directory. Hash types:\n"
207 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
208 " all_char sum of characters % MDT_COUNT (not recommended)\n"
209 "\tdefault_stripe: set default dirstripe of the directory\n"
210 "\tmode: the mode of the directory\n"},
211 {"rm_entry", lfs_rmentry, 0,
212 "To remove the name entry of the remote directory. Note: This\n"
213 "command will only delete the name entry, i.e. the remote directory\n"
214 "will become inaccessable after this command. This can only be done\n"
215 "by the administrator\n"
216 "usage: rm_entry <dir>\n"},
217 {"pool_list", lfs_poollist, 0,
218 "List pools or pool OSTs\n"
219 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
220 {"find", lfs_find, 0,
221 "find files matching given attributes recursively in directory tree.\n"
222 "usage: find <directory|filename> ...\n"
223 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
224 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
225 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
226 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
227 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
228 " [[!] --stripe-count|-c [+-]<stripes>]\n"
229 " [[!] --stripe-index|-i <index,...>]\n"
230 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
231 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
232 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
233 " [[!] --layout|-L released,raid0]\n"
234 "\t !: used before an option indicates 'NOT' requested attribute\n"
235 "\t -: used before a value indicates 'AT MOST' requested value\n"
236 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
237 {"check", lfs_check, 0,
238 "Display the status of MDS or OSTs (as specified in the command)\n"
239 "or all the servers (MDS and OSTs).\n"
240 "usage: check <osts|mds|servers>"},
241 {"join", lfs_join, 0,
242 "join two lustre files into one.\n"
243 "obsolete, HEAD does not support it anymore.\n"},
244 {"osts", lfs_osts, 0, "list OSTs connected to client "
245 "[for specified path only]\n" "usage: osts [path]"},
246 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
247 "[for specified path only]\n" "usage: mdts [path]"},
249 "report filesystem disk space usage or inodes usage"
250 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
251 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
252 {"getname", lfs_getname, 0, "list instances and specified mount points "
253 "[for specified path only]\n"
254 "Usage: getname [-h]|[path ...] "},
255 #ifdef HAVE_SYS_QUOTA_H
256 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
257 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
258 " -b <block-softlimit> -B <block-hardlimit>\n"
259 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
260 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
261 " [--block-softlimit <block-softlimit>]\n"
262 " [--block-hardlimit <block-hardlimit>]\n"
263 " [--inode-softlimit <inode-softlimit>]\n"
264 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
265 " setquota [-t] <-u|--user|-g|--group>\n"
266 " [--block-grace <block-grace>]\n"
267 " [--inode-grace <inode-grace>] <filesystem>\n"
268 " -b can be used instead of --block-softlimit/--block-grace\n"
269 " -B can be used instead of --block-hardlimit\n"
270 " -i can be used instead of --inode-softlimit/--inode-grace\n"
271 " -I can be used instead of --inode-hardlimit\n\n"
272 "Note: The total quota space will be split into many qunits and\n"
273 " balanced over all server targets, the minimal qunit size is\n"
274 " 1M bytes for block space and 1K inodes for inode space.\n\n"
275 " Quota space rebalancing process will stop when this mininum\n"
276 " value is reached. As a result, quota exceeded can be returned\n"
277 " while many targets still have 1MB or 1K inodes of spare\n"
279 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
280 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
282 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
283 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
285 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
286 "usage: flushctx [-k] [mountpoint...]"},
287 {"lsetfacl", lfs_lsetfacl, 0,
288 "Remote user setfacl for user/group on the same remote client.\n"
289 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
290 {"lgetfacl", lfs_lgetfacl, 0,
291 "Remote user getfacl for user/group on the same remote client.\n"
292 "usage: lgetfacl [-dRLPvh] file ..."},
293 {"rsetfacl", lfs_rsetfacl, 0,
294 "Remote user setfacl for user/group on other clients.\n"
295 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
296 {"rgetfacl", lfs_rgetfacl, 0,
297 "Remote user getfacl for user/group on other clients.\n"
298 "usage: rgetfacl [-dRLPvh] file ..."},
300 "Remote user copy files and directories.\n"
301 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
303 "Remote user list directory contents.\n"
304 "usage: ls [OPTION]... [FILE]..."},
305 {"changelog", lfs_changelog, 0,
306 "Show the metadata changes on an MDT."
307 "\nusage: changelog <mdtname> [startrec [endrec]]"},
308 {"changelog_clear", lfs_changelog_clear, 0,
309 "Indicate that old changelog records up to <endrec> are no longer of "
310 "interest to consumer <id>, allowing the system to free up space.\n"
311 "An <endrec> of 0 means all records.\n"
312 "usage: changelog_clear <mdtname> <id> <endrec>"},
313 {"fid2path", lfs_fid2path, 0,
314 "Resolve the full path(s) for given FID(s). For a specific hardlink "
315 "specify link number <linkno>.\n"
316 /* "For a historical link name, specify changelog record <recno>.\n" */
317 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
318 /* [ --rec <recno> ] */ },
319 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
320 "usage: path2fid [--parents] <path> ..."},
321 {"data_version", lfs_data_version, 0, "Display file data version for "
322 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
323 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
324 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
325 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
326 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
327 "[--archived] [--lost] <file> ..."},
328 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
330 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
331 "[--archived] [--lost] <file> ..."},
332 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
333 "given files.\n" "usage: hsm_action <file> ..."},
334 {"hsm_archive", lfs_hsm_archive, 0,
335 "Archive file to external storage.\n"
336 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
338 {"hsm_restore", lfs_hsm_restore, 0,
339 "Restore file from external storage.\n"
340 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
341 {"hsm_release", lfs_hsm_release, 0,
342 "Release files from Lustre.\n"
343 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
344 {"hsm_remove", lfs_hsm_remove, 0,
345 "Remove file copy from external storage.\n"
346 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
347 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
349 "Note: To remove files from the archive that have been deleted on\n"
350 "Lustre, set mntpath and optionally archive. In that case, all the\n"
351 "positional arguments and entries in the file list must be FIDs."
353 {"hsm_cancel", lfs_hsm_cancel, 0,
354 "Cancel requests related to specified files.\n"
355 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
356 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
357 "usage: swap_layouts <path1> <path2>"},
358 {"migrate", lfs_setstripe, 0,
359 "migrate file/directory between MDTs, or migrate file from one OST "
360 "layout\nto another (may be not safe with concurent writes).\n"
361 "usage: migrate [--mdt-index|-m <mdt_idx>] [--verbose|-v] "
362 "<directory|filename>\n"
363 "\tmdt_idx: MDT index to migrate to\n"
367 "To move directories between MDTs. This command is deprecated, "
368 "use \"migrate\" instead.\n"
369 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
371 {"help", Parser_help, 0, "help"},
372 {"exit", Parser_quit, 0, "quit"},
373 {"quit", Parser_quit, 0, "quit"},
374 {"--version", Parser_version, 0,
375 "output build version of the utility and exit"},
380 #define MIGRATION_NONBLOCK 1
383 * Internal helper for migrate_copy_data(). Check lease and report error if
386 * \param[in] fd File descriptor on which to check the lease.
387 * \param[out] lease_broken Set to true if the lease was broken.
388 * \param[in] group_locked Whether a group lock was taken or not.
389 * \param[in] path Name of the file being processed, for error
392 * \retval 0 Migration can keep on going.
393 * \retval -errno Error occurred, abort migration.
395 static int check_lease(int fd, bool *lease_broken, bool group_locked,
400 if (!file_lease_supported)
403 rc = llapi_lease_check(fd);
405 return 0; /* llapi_check_lease returns > 0 on success. */
408 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
410 rc = rc ? rc : -EAGAIN;
412 fprintf(stderr, "%s: external attempt to access file '%s' "
413 "blocked until migration ends.\n", progname, path);
416 *lease_broken = true;
420 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
421 bool group_locked, const char *fname)
430 bool lease_broken = false;
432 /* Use a page-aligned buffer for direct I/O */
433 rc = posix_memalign(&buf, getpagesize(), buf_size);
438 /* read new data only if we have written all
439 * previously read data */
442 rc = check_lease(fd_src, &lease_broken,
443 group_locked, fname);
447 rsize = read(fd_src, buf, buf_size);
450 fprintf(stderr, "%s: %s: read failed: %s\n",
451 progname, fname, strerror(-rc));
461 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
465 "%s: %s: write failed on volatile: %s\n",
466 progname, fname, strerror(-rc));
476 fprintf(stderr, "%s: %s: fsync failed: %s\n",
477 progname, fname, strerror(-rc));
485 static int migrate_copy_timestamps(int fdv, const struct stat *st)
487 struct timeval tv[2] = {
488 {.tv_sec = st->st_atime},
489 {.tv_sec = st->st_mtime}
492 return futimes(fdv, tv);
495 static int migrate_block(int fd, int fdv, const struct stat *st,
496 size_t buf_size, const char *name)
503 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
505 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
506 progname, name, strerror(-rc));
514 /* The grouplock blocks all concurrent accesses to the file.
515 * It has to be taken after llapi_get_data_version as it would
517 rc = llapi_group_lock(fd, gid);
519 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
520 progname, name, strerror(-rc));
524 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
526 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
530 /* Make sure we keep original atime/mtime values */
531 rc = migrate_copy_timestamps(fdv, st);
533 fprintf(stderr, "%s: %s: timestamp copy failed\n",
539 * for a migration we need to check data version on file did
542 * Pass in gid=0 since we already own grouplock. */
543 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
544 SWAP_LAYOUTS_CHECK_DV1);
546 fprintf(stderr, "%s: %s: dataversion changed during copy, "
547 "migration aborted\n", progname, name);
550 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
551 name, strerror(-rc));
556 rc2 = llapi_group_unlock(fd, gid);
557 if (rc2 < 0 && rc == 0) {
558 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
559 progname, name, strerror(-rc2));
566 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
567 size_t buf_size, const char *name)
573 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
575 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
576 progname, name, strerror(-rc));
580 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
582 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
586 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
588 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
589 progname, name, strerror(-rc));
595 fprintf(stderr, "%s: %s: data version changed during "
601 /* Make sure we keep original atime/mtime values */
602 rc = migrate_copy_timestamps(fdv, st);
604 fprintf(stderr, "%s: %s: timestamp copy failed\n",
609 /* Atomically put lease, swap layouts and close.
610 * for a migration we need to check data version on file did
612 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
614 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
615 progname, name, strerror(-rc));
622 static int lfs_migrate(char *name, __u64 migration_flags,
623 struct llapi_stripe_param *param)
627 char parent[PATH_MAX];
630 char volatile_file[sizeof(parent) +
631 LUSTRE_VOLATILE_HDR_LEN +
632 2 * sizeof(mdt_index) +
633 2 * sizeof(random_value) + 4];
636 struct lov_user_md *lum = NULL;
639 bool have_lease_rdlck = false;
643 /* find the right size for the IO and allocate the buffer */
644 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
645 lum = malloc(lum_size);
651 rc = llapi_file_get_stripe(name, lum);
652 /* failure can happen for many reasons and some may be not real errors
654 * in case of a real error, a later call will fail with better
655 * error management */
657 buf_size = 1024 * 1024;
659 buf_size = lum->lmm_stripe_size;
661 /* open file, direct io */
662 /* even if the file is only read, WR mode is nedeed to allow
663 * layout swap on fd */
664 fd = open(name, O_RDWR | O_DIRECT);
667 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
672 if (file_lease_supported) {
673 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
674 if (rc == -EOPNOTSUPP) {
675 /* Older servers do not support file lease.
676 * Disable related checks. This opens race conditions
677 * as explained in LU-4840 */
678 file_lease_supported = false;
680 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
681 progname, name, strerror(-rc));
684 have_lease_rdlck = true;
688 /* search for file directory pathname */
689 if (strlen(name) > sizeof(parent)-1) {
693 strncpy(parent, name, sizeof(parent));
694 ptr = strrchr(parent, '/');
696 if (getcwd(parent, sizeof(parent)) == NULL) {
707 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
709 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
710 progname, name, strerror(-rc));
715 random_value = random();
716 rc = snprintf(volatile_file, sizeof(volatile_file),
717 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
718 mdt_index, random_value);
719 if (rc >= sizeof(volatile_file)) {
724 /* create, open a volatile file, use caching (ie no directio) */
725 fdv = llapi_file_open_param(volatile_file,
726 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
727 S_IRUSR | S_IWUSR, param);
728 } while (fdv == -EEXIST);
732 fprintf(stderr, "%s: %s: cannot create volatile file in"
734 progname, parent, strerror(-rc));
738 /* Not-owner (root?) special case.
739 * Need to set owner/group of volatile file like original.
740 * This will allow to pass related check during layout_swap.
745 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
749 rc = fstat(fdv, &stv);
752 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
753 volatile_file, strerror(errno));
756 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
757 rc = fchown(fdv, st.st_uid, st.st_gid);
760 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
761 name, strerror(errno));
766 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
767 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
769 have_lease_rdlck = false;
770 fdv = -1; /* The volatile file is closed as we put the
771 * lease in non-blocking mode. */
774 /* Blocking mode (forced if servers do not support file lease).
775 * It is also the default mode, since we cannot distinguish
776 * between a broken lease and a server that does not support
777 * atomic swap/close (LU-6785) */
778 rc = migrate_block(fd, fdv, &st, buf_size, name);
782 if (have_lease_rdlck)
799 * Parse a string containing an OST index list into an array of integers.
801 * The input string contains a comma delimited list of individual
802 * indices and ranges, for example "1,2-4,7". Add the indices into the
803 * \a osts array and remove duplicates.
805 * \param[out] osts array to store indices in
806 * \param[in] size size of \a osts array
807 * \param[in] offset starting index in \a osts
808 * \param[in] arg string containing OST index list
810 * \retval positive number of indices in \a osts
811 * \retval -EINVAL unable to parse \a arg
813 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
817 int slots = size - offset;
825 while (!end_of_loop) {
833 ptr = strchrnul(arg, ',');
835 end_of_loop = *ptr == '\0';
838 start_index = strtol(arg, &endptr, 0);
839 if (endptr == arg) /* no data at all */
841 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
846 end_index = start_index;
847 if (*endptr == '-') {
848 end_index = strtol(endptr + 1, &endptr, 0);
851 if (end_index < start_index)
855 for (i = start_index; i <= end_index && slots > 0; i++) {
858 /* remove duplicate */
859 for (j = 0; j < offset; j++) {
863 if (j == offset) { /* no duplicate */
868 if (slots == 0 && i < end_index)
876 if (!end_of_loop && ptr != NULL)
879 return rc < 0 ? rc : nr;
883 static int lfs_setstripe(int argc, char **argv)
885 struct llapi_stripe_param *param = NULL;
886 struct find_param migrate_mdt_param = {
893 unsigned long long st_size;
894 int st_offset, st_count;
898 char *stripe_size_arg = NULL;
899 char *stripe_off_arg = NULL;
900 char *stripe_count_arg = NULL;
901 char *pool_name_arg = NULL;
902 char *mdt_idx_arg = NULL;
903 unsigned long long size_units = 1;
904 bool migrate_mode = false;
905 bool migration_block = false;
906 __u64 migration_flags = 0;
907 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
910 struct option long_opts[] = {
911 /* --block is only valid in migrate mode */
912 {"block", no_argument, 0, 'b'},
913 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
914 /* This formerly implied "stripe-count", but was explicitly
915 * made "stripe-count" for consistency with other options,
916 * and to separate it from "mdt-count" when DNE arrives. */
917 {"count", required_argument, 0, 'c'},
919 {"stripe-count", required_argument, 0, 'c'},
920 {"stripe_count", required_argument, 0, 'c'},
921 {"delete", no_argument, 0, 'd'},
922 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
923 /* This formerly implied "stripe-index", but was explicitly
924 * made "stripe-index" for consistency with other options,
925 * and to separate it from "mdt-index" when DNE arrives. */
926 {"index", required_argument, 0, 'i'},
928 {"stripe-index", required_argument, 0, 'i'},
929 {"stripe_index", required_argument, 0, 'i'},
930 {"mdt-index", required_argument, 0, 'm'},
931 {"mdt_index", required_argument, 0, 'm'},
932 /* --non-block is only valid in migrate mode */
933 {"non-block", no_argument, 0, 'n'},
934 {"ost-list", required_argument, 0, 'o'},
935 {"ost_list", required_argument, 0, 'o'},
936 {"pool", required_argument, 0, 'p'},
937 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
938 /* This formerly implied "--stripe-size", but was confusing
939 * with "lfs find --size|-s", which means "file size", so use
940 * the consistent "--stripe-size|-S" for all commands. */
941 {"size", required_argument, 0, 's'},
943 {"stripe-size", required_argument, 0, 'S'},
944 {"stripe_size", required_argument, 0, 'S'},
945 /* --verbose is only valid in migrate mode */
946 {"verbose", no_argument, 0, 'v'},
954 if (strcmp(argv[0], "migrate") == 0)
957 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
958 long_opts, NULL)) >= 0) {
965 fprintf(stderr, "--block is valid only for"
969 migration_block = true;
972 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
973 if (strcmp(argv[optind - 1], "--count") == 0)
974 fprintf(stderr, "warning: '--count' deprecated"
975 ", use '--stripe-count' instead\n");
977 stripe_count_arg = optarg;
980 /* delete the default striping pattern */
984 nr_osts = parse_targets(osts,
985 sizeof(osts) / sizeof(__u32),
989 "error: %s: bad OST indices '%s'\n",
994 if (st_offset == -1) /* first in the command line */
998 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
999 if (strcmp(argv[optind - 1], "--index") == 0)
1000 fprintf(stderr, "warning: '--index' deprecated"
1001 ", use '--stripe-index' instead\n");
1003 stripe_off_arg = optarg;
1006 if (!migrate_mode) {
1007 fprintf(stderr, "--mdt-index is valid only for"
1011 mdt_idx_arg = optarg;
1014 if (!migrate_mode) {
1015 fprintf(stderr, "--non-block is valid only for"
1019 migration_flags |= MIGRATION_NONBLOCK;
1021 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1023 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1024 fprintf(stderr, "warning: '--size|-s' deprecated, "
1025 "use '--stripe-size|-S' instead\n");
1027 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1029 stripe_size_arg = optarg;
1032 pool_name_arg = optarg;
1035 if (!migrate_mode) {
1036 fprintf(stderr, "--verbose is valid only for"
1040 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1047 fname = argv[optind];
1050 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1051 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1052 fprintf(stderr, "error: %s: cannot specify -d with "
1053 "-s, -c, -o, or -p options\n",
1058 if (optind == argc) {
1059 fprintf(stderr, "error: %s: missing filename|dirname\n",
1064 if (mdt_idx_arg != NULL && optind > 3) {
1065 fprintf(stderr, "error: %s: cannot specify -m with other "
1066 "options\n", argv[0]);
1070 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1072 "error: %s: cannot specify --non-block and --block\n",
1077 if (pool_name_arg != NULL) {
1081 ptr = strchr(pool_name_arg, '.');
1083 ptr = pool_name_arg;
1085 if ((ptr - pool_name_arg) == 0) {
1086 fprintf(stderr, "error: %s: fsname is empty "
1087 "in pool name '%s'\n",
1088 argv[0], pool_name_arg);
1095 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1097 fprintf(stderr, "error: %s: poolname '%s' is "
1099 argv[0], pool_name_arg);
1101 } else if (rc == -2) {
1102 fprintf(stderr, "error: %s: pool name '%s' is too long "
1103 "(max is %d characters)\n",
1104 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1106 } else if (rc > 0) {
1107 fprintf(stderr, "error: %s: char '%c' not allowed in "
1109 argv[0], rc, pool_name_arg);
1114 /* get the stripe size */
1115 if (stripe_size_arg != NULL) {
1116 result = llapi_parse_size(stripe_size_arg, &st_size,
1119 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1120 argv[0], stripe_size_arg);
1124 /* get the stripe offset */
1125 if (stripe_off_arg != NULL) {
1126 st_offset = strtol(stripe_off_arg, &end, 0);
1128 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1129 argv[0], stripe_off_arg);
1133 /* get the stripe count */
1134 if (stripe_count_arg != NULL) {
1135 st_count = strtoul(stripe_count_arg, &end, 0);
1137 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1138 argv[0], stripe_count_arg);
1143 if (mdt_idx_arg != NULL) {
1144 /* initialize migrate mdt parameters */
1145 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1147 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1148 argv[0], mdt_idx_arg);
1151 migrate_mdt_param.fp_migrate = 1;
1153 /* initialize stripe parameters */
1154 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1155 if (param == NULL) {
1156 fprintf(stderr, "error: %s: run out of memory\n",
1161 param->lsp_stripe_size = st_size;
1162 param->lsp_stripe_offset = st_offset;
1163 param->lsp_stripe_count = st_count;
1164 param->lsp_stripe_pattern = 0;
1165 param->lsp_pool = pool_name_arg;
1166 param->lsp_is_specific = false;
1168 if (st_count > 0 && nr_osts != st_count) {
1169 fprintf(stderr, "error: %s: stripe count '%d' "
1170 "doesn't match the number of OSTs: %d\n"
1171 , argv[0], st_count, nr_osts);
1176 param->lsp_is_specific = true;
1177 param->lsp_stripe_count = nr_osts;
1178 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1182 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1183 if (!migrate_mode) {
1184 result = llapi_file_open_param(fname,
1191 } else if (mdt_idx_arg != NULL) {
1192 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1194 result = lfs_migrate(fname, migration_flags, param);
1197 /* Save the first error encountered. */
1201 "error: %s: %s file '%s' failed\n",
1202 argv[0], migrate_mode ? "migrate" : "create",
1212 static int lfs_poollist(int argc, char **argv)
1217 return llapi_poollist(argv[1]);
1220 static int set_time(time_t *time, time_t *set, char *str)
1227 else if (str[0] == '-')
1233 t = strtol(str, NULL, 0);
1234 if (*time < t * 24 * 60 * 60) {
1237 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1241 *set = *time - t * 24 * 60 * 60;
1248 static int name2id(unsigned int *id, char *name, int type)
1251 struct passwd *entry;
1253 if (!(entry = getpwnam(name))) {
1259 *id = entry->pw_uid;
1261 struct group *entry;
1263 if (!(entry = getgrnam(name))) {
1269 *id = entry->gr_gid;
1275 static int id2name(char **name, unsigned int id, int type)
1278 struct passwd *entry;
1280 if (!(entry = getpwuid(id))) {
1286 *name = entry->pw_name;
1288 struct group *entry;
1290 if (!(entry = getgrgid(id))) {
1296 *name = entry->gr_name;
1302 static int name2layout(__u32 *layout, char *name)
1307 for (ptr = name; ; ptr = NULL) {
1308 lyt = strtok(ptr, ",");
1311 if (strcmp(lyt, "released") == 0)
1312 *layout |= LOV_PATTERN_F_RELEASED;
1313 else if (strcmp(lyt, "raid0") == 0)
1314 *layout |= LOV_PATTERN_RAID0;
1321 #define FIND_POOL_OPT 3
1322 static int lfs_find(int argc, char **argv)
1327 struct find_param param = {
1331 struct option long_opts[] = {
1332 {"atime", required_argument, 0, 'A'},
1333 {"stripe-count", required_argument, 0, 'c'},
1334 {"stripe_count", required_argument, 0, 'c'},
1335 {"ctime", required_argument, 0, 'C'},
1336 {"maxdepth", required_argument, 0, 'D'},
1337 {"gid", required_argument, 0, 'g'},
1338 {"group", required_argument, 0, 'G'},
1339 {"stripe-index", required_argument, 0, 'i'},
1340 {"stripe_index", required_argument, 0, 'i'},
1341 {"layout", required_argument, 0, 'L'},
1342 {"mdt", required_argument, 0, 'm'},
1343 {"mtime", required_argument, 0, 'M'},
1344 {"name", required_argument, 0, 'n'},
1345 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1346 {"obd", required_argument, 0, 'O'},
1347 {"ost", required_argument, 0, 'O'},
1348 /* no short option for pool, p/P already used */
1349 {"pool", required_argument, 0, FIND_POOL_OPT},
1350 {"print0", no_argument, 0, 'p'},
1351 {"print", no_argument, 0, 'P'},
1352 {"size", required_argument, 0, 's'},
1353 {"stripe-size", required_argument, 0, 'S'},
1354 {"stripe_size", required_argument, 0, 'S'},
1355 {"type", required_argument, 0, 't'},
1356 {"uid", required_argument, 0, 'u'},
1357 {"user", required_argument, 0, 'U'},
1370 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1371 while ((c = getopt_long_only(argc, argv,
1372 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1373 long_opts, NULL)) >= 0) {
1378 /* '!' is part of option */
1379 /* when getopt_long_only() finds a string which is not
1380 * an option nor a known option argument it returns 1
1381 * in that case if we already have found pathstart and pathend
1382 * (i.e. we have the list of pathnames),
1383 * the only supported value is "!"
1385 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1386 if (!isoption && pathend != -1) {
1387 fprintf(stderr, "err: %s: filename|dirname must either "
1388 "precede options or follow options\n",
1393 if (!isoption && pathstart == -1)
1394 pathstart = optind - 1;
1395 if (isoption && pathstart != -1 && pathend == -1)
1396 pathend = optind - 2;
1402 /* unknown; opt is "!" or path component,
1403 * checking done above.
1405 if (strcmp(optarg, "!") == 0)
1409 xtime = ¶m.fp_atime;
1410 xsign = ¶m.fp_asign;
1411 param.fp_exclude_atime = !!neg_opt;
1412 /* no break, this falls through to 'C' for ctime */
1415 xtime = ¶m.fp_ctime;
1416 xsign = ¶m.fp_csign;
1417 param.fp_exclude_ctime = !!neg_opt;
1419 /* no break, this falls through to 'M' for mtime */
1422 xtime = ¶m.fp_mtime;
1423 xsign = ¶m.fp_msign;
1424 param.fp_exclude_mtime = !!neg_opt;
1426 rc = set_time(&t, xtime, optarg);
1427 if (rc == INT_MAX) {
1435 if (optarg[0] == '+') {
1436 param.fp_stripe_count_sign = -1;
1438 } else if (optarg[0] == '-') {
1439 param.fp_stripe_count_sign = 1;
1443 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1444 if (*endptr != '\0') {
1445 fprintf(stderr,"error: bad stripe_count '%s'\n",
1450 param.fp_check_stripe_count = 1;
1451 param.fp_exclude_stripe_count = !!neg_opt;
1454 param.fp_max_depth = strtol(optarg, 0, 0);
1458 rc = name2id(¶m.fp_gid, optarg, GROUP);
1460 param.fp_gid = strtoul(optarg, &endptr, 10);
1461 if (*endptr != '\0') {
1462 fprintf(stderr, "Group/GID: %s cannot "
1463 "be found.\n", optarg);
1468 param.fp_exclude_gid = !!neg_opt;
1469 param.fp_check_gid = 1;
1472 ret = name2layout(¶m.fp_layout, optarg);
1475 param.fp_exclude_layout = !!neg_opt;
1476 param.fp_check_layout = 1;
1480 rc = name2id(¶m.fp_uid, optarg, USER);
1482 param.fp_uid = strtoul(optarg, &endptr, 10);
1483 if (*endptr != '\0') {
1484 fprintf(stderr, "User/UID: %s cannot "
1485 "be found.\n", optarg);
1490 param.fp_exclude_uid = !!neg_opt;
1491 param.fp_check_uid = 1;
1494 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1496 "Pool name %s is too long"
1497 " (max is %d)\n", optarg,
1502 /* we do check for empty pool because empty pool
1503 * is used to find V1 lov attributes */
1504 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1505 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1506 param.fp_exclude_pool = !!neg_opt;
1507 param.fp_check_pool = 1;
1510 param.fp_pattern = (char *)optarg;
1511 param.fp_exclude_pattern = !!neg_opt;
1516 char *buf, *token, *next, *p;
1520 buf = strdup(optarg);
1526 param.fp_exclude_obd = !!neg_opt;
1529 while (token && *token) {
1530 token = strchr(token, ',');
1537 param.fp_exclude_mdt = !!neg_opt;
1538 param.fp_num_alloc_mdts += len;
1539 tmp = realloc(param.fp_mdt_uuid,
1540 param.fp_num_alloc_mdts *
1541 sizeof(*param.fp_mdt_uuid));
1547 param.fp_mdt_uuid = tmp;
1549 param.fp_exclude_obd = !!neg_opt;
1550 param.fp_num_alloc_obds += len;
1551 tmp = realloc(param.fp_obd_uuid,
1552 param.fp_num_alloc_obds *
1553 sizeof(*param.fp_obd_uuid));
1559 param.fp_obd_uuid = tmp;
1561 for (token = buf; token && *token; token = next) {
1562 struct obd_uuid *puuid;
1565 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1568 ¶m.fp_obd_uuid[param.fp_num_obds++];
1570 p = strchr(token, ',');
1577 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1582 strncpy(puuid->uuid, token,
1583 sizeof(puuid->uuid));
1591 param.fp_zero_end = 1;
1596 if (optarg[0] == '+') {
1597 param.fp_size_sign = -1;
1599 } else if (optarg[0] == '-') {
1600 param.fp_size_sign = 1;
1604 ret = llapi_parse_size(optarg, ¶m.fp_size,
1605 ¶m.fp_size_units, 0);
1607 fprintf(stderr, "error: bad file size '%s'\n",
1611 param.fp_check_size = 1;
1612 param.fp_exclude_size = !!neg_opt;
1615 if (optarg[0] == '+') {
1616 param.fp_stripe_size_sign = -1;
1618 } else if (optarg[0] == '-') {
1619 param.fp_stripe_size_sign = 1;
1623 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1624 ¶m.fp_stripe_size_units, 0);
1626 fprintf(stderr, "error: bad stripe_size '%s'\n",
1630 param.fp_check_stripe_size = 1;
1631 param.fp_exclude_stripe_size = !!neg_opt;
1634 param.fp_exclude_type = !!neg_opt;
1635 switch (optarg[0]) {
1637 param.fp_type = S_IFBLK;
1640 param.fp_type = S_IFCHR;
1643 param.fp_type = S_IFDIR;
1646 param.fp_type = S_IFREG;
1649 param.fp_type = S_IFLNK;
1652 param.fp_type = S_IFIFO;
1655 param.fp_type = S_IFSOCK;
1658 fprintf(stderr, "error: %s: bad type '%s'\n",
1670 if (pathstart == -1) {
1671 fprintf(stderr, "error: %s: no filename|pathname\n",
1675 } else if (pathend == -1) {
1681 rc = llapi_find(argv[pathstart], ¶m);
1682 if (rc != 0 && ret == 0)
1684 } while (++pathstart < pathend);
1687 fprintf(stderr, "error: %s failed for %s.\n",
1688 argv[0], argv[optind - 1]);
1690 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1691 free(param.fp_obd_uuid);
1693 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1694 free(param.fp_mdt_uuid);
1699 static int lfs_getstripe_internal(int argc, char **argv,
1700 struct find_param *param)
1702 struct option long_opts[] = {
1703 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1704 /* This formerly implied "stripe-count", but was explicitly
1705 * made "stripe-count" for consistency with other options,
1706 * and to separate it from "mdt-count" when DNE arrives. */
1707 {"count", no_argument, 0, 'c'},
1709 {"stripe-count", no_argument, 0, 'c'},
1710 {"stripe_count", no_argument, 0, 'c'},
1711 {"directory", no_argument, 0, 'd'},
1712 {"default", no_argument, 0, 'D'},
1713 {"generation", no_argument, 0, 'g'},
1714 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1715 /* This formerly implied "stripe-index", but was explicitly
1716 * made "stripe-index" for consistency with other options,
1717 * and to separate it from "mdt-index" when DNE arrives. */
1718 {"index", no_argument, 0, 'i'},
1720 {"stripe-index", no_argument, 0, 'i'},
1721 {"stripe_index", no_argument, 0, 'i'},
1722 {"layout", no_argument, 0, 'L'},
1723 {"mdt-index", no_argument, 0, 'M'},
1724 {"mdt_index", no_argument, 0, 'M'},
1725 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1726 /* This formerly implied "stripe-index", but was confusing
1727 * with "file offset" (which will eventually be needed for
1728 * with different layouts by offset), so deprecate it. */
1729 {"offset", no_argument, 0, 'o'},
1731 {"obd", required_argument, 0, 'O'},
1732 {"ost", required_argument, 0, 'O'},
1733 {"pool", no_argument, 0, 'p'},
1734 {"quiet", no_argument, 0, 'q'},
1735 {"recursive", no_argument, 0, 'r'},
1736 {"raw", no_argument, 0, 'R'},
1737 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1738 /* This formerly implied "--stripe-size", but was confusing
1739 * with "lfs find --size|-s", which means "file size", so use
1740 * the consistent "--stripe-size|-S" for all commands. */
1741 {"size", no_argument, 0, 's'},
1743 {"stripe-size", no_argument, 0, 'S'},
1744 {"stripe_size", no_argument, 0, 'S'},
1745 {"verbose", no_argument, 0, 'v'},
1750 param->fp_max_depth = 1;
1751 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1752 long_opts, NULL)) != -1) {
1755 if (param->fp_obd_uuid) {
1757 "error: %s: only one obduuid allowed",
1761 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1767 param->fp_max_depth = 0;
1770 param->fp_get_default_lmv = 1;
1773 param->fp_recursive = 1;
1776 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1779 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1780 if (strcmp(argv[optind - 1], "--count") == 0)
1781 fprintf(stderr, "warning: '--count' deprecated,"
1782 " use '--stripe-count' instead\n");
1784 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1785 param->fp_verbose |= VERBOSE_COUNT;
1786 param->fp_max_depth = 0;
1789 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1791 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1792 fprintf(stderr, "warning: '--size|-s' deprecated, "
1793 "use '--stripe-size|-S' instead\n");
1795 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1797 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1798 param->fp_verbose |= VERBOSE_SIZE;
1799 param->fp_max_depth = 0;
1802 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1804 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1805 "use '--stripe-index|-i' instead\n");
1808 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1809 if (strcmp(argv[optind - 1], "--index") == 0)
1810 fprintf(stderr, "warning: '--index' deprecated"
1811 ", use '--stripe-index' instead\n");
1813 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1814 param->fp_verbose |= VERBOSE_OFFSET;
1815 param->fp_max_depth = 0;
1819 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1820 param->fp_verbose |= VERBOSE_POOL;
1821 param->fp_max_depth = 0;
1825 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1826 param->fp_verbose |= VERBOSE_GENERATION;
1827 param->fp_max_depth = 0;
1831 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1832 param->fp_verbose |= VERBOSE_LAYOUT;
1833 param->fp_max_depth = 0;
1837 if (!(param->fp_verbose & VERBOSE_DETAIL))
1838 param->fp_max_depth = 0;
1839 param->fp_verbose |= VERBOSE_MDTINDEX;
1852 if (param->fp_recursive)
1853 param->fp_max_depth = -1;
1855 if (!param->fp_verbose)
1856 param->fp_verbose = VERBOSE_ALL;
1857 if (param->fp_quiet)
1858 param->fp_verbose = VERBOSE_OBJID;
1861 rc = llapi_getstripe(argv[optind], param);
1862 } while (++optind < argc && !rc);
1865 fprintf(stderr, "error: %s failed for %s.\n",
1866 argv[0], argv[optind - 1]);
1870 static int lfs_tgts(int argc, char **argv)
1872 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1873 struct find_param param;
1874 int index = 0, rc=0;
1879 if (argc == 2 && !realpath(argv[1], path)) {
1881 fprintf(stderr, "error: invalid path '%s': %s\n",
1882 argv[1], strerror(-rc));
1886 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1887 /* Check if we have a mount point */
1888 if (mntdir[0] == '\0')
1891 memset(¶m, 0, sizeof(param));
1892 if (!strcmp(argv[0], "mdts"))
1893 param.fp_get_lmv = 1;
1895 rc = llapi_ostlist(mntdir, ¶m);
1897 fprintf(stderr, "error: %s: failed on %s\n",
1900 if (path[0] != '\0')
1902 memset(mntdir, 0, PATH_MAX);
1908 static int lfs_getstripe(int argc, char **argv)
1910 struct find_param param = { 0 };
1911 return lfs_getstripe_internal(argc, argv, ¶m);
1915 static int lfs_getdirstripe(int argc, char **argv)
1917 struct find_param param = { 0 };
1919 param.fp_get_lmv = 1;
1920 return lfs_getstripe_internal(argc, argv, ¶m);
1924 static int lfs_setdirstripe(int argc, char **argv)
1928 unsigned int stripe_offset = -1;
1929 unsigned int stripe_count = 1;
1930 enum lmv_hash_type hash_type;
1933 char *stripe_offset_opt = NULL;
1934 char *stripe_count_opt = NULL;
1935 char *stripe_hash_opt = NULL;
1936 char *mode_opt = NULL;
1937 bool default_stripe = false;
1938 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1939 mode_t previous_mode = 0;
1940 bool delete = false;
1942 struct option long_opts[] = {
1943 {"count", required_argument, 0, 'c'},
1944 {"delete", no_argument, 0, 'd'},
1945 {"index", required_argument, 0, 'i'},
1946 {"mode", required_argument, 0, 'm'},
1947 {"hash-type", required_argument, 0, 't'},
1948 {"default_stripe", no_argument, 0, 'D'},
1952 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1959 stripe_count_opt = optarg;
1963 default_stripe = true;
1966 default_stripe = true;
1969 stripe_offset_opt = optarg;
1975 stripe_hash_opt = optarg;
1978 fprintf(stderr, "error: %s: option '%s' "
1980 argv[0], argv[optind - 1]);
1985 if (optind == argc) {
1986 fprintf(stderr, "error: %s: missing dirname\n",
1991 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1992 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1997 if (stripe_offset_opt != NULL) {
1998 /* get the stripe offset */
1999 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2001 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2002 argv[0], stripe_offset_opt);
2008 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2009 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2010 " or -i options.\n", argv[0]);
2018 if (mode_opt != NULL) {
2019 mode = strtoul(mode_opt, &end, 8);
2021 fprintf(stderr, "error: %s: bad mode '%s'\n",
2025 previous_mode = umask(0);
2028 if (stripe_hash_opt == NULL ||
2029 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2030 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2031 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2032 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2034 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2035 argv[0], stripe_hash_opt);
2039 /* get the stripe count */
2040 if (stripe_count_opt != NULL) {
2041 stripe_count = strtoul(stripe_count_opt, &end, 0);
2043 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2044 argv[0], stripe_count_opt);
2049 dname = argv[optind];
2051 if (default_stripe) {
2052 result = llapi_dir_set_default_lmv_stripe(dname,
2053 stripe_offset, stripe_count,
2056 result = llapi_dir_create_pool(dname, mode,
2058 stripe_count, hash_type,
2063 fprintf(stderr, "error: %s: create stripe dir '%s' "
2064 "failed\n", argv[0], dname);
2067 dname = argv[++optind];
2068 } while (dname != NULL);
2070 if (mode_opt != NULL)
2071 umask(previous_mode);
2077 static int lfs_rmentry(int argc, char **argv)
2084 fprintf(stderr, "error: %s: missing dirname\n",
2090 dname = argv[index];
2091 while (dname != NULL) {
2092 result = llapi_direntry_remove(dname);
2094 fprintf(stderr, "error: %s: remove dir entry '%s' "
2095 "failed\n", argv[0], dname);
2098 dname = argv[++index];
2103 static int lfs_mv(int argc, char **argv)
2105 struct find_param param = {
2112 struct option long_opts[] = {
2113 {"mdt-index", required_argument, 0, 'M'},
2114 {"verbose", no_argument, 0, 'v'},
2118 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2121 param.fp_mdt_index = strtoul(optarg, &end, 0);
2123 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2130 param.fp_verbose = VERBOSE_DETAIL;
2134 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2135 argv[0], argv[optind - 1]);
2140 if (param.fp_mdt_index == -1) {
2141 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2145 if (optind >= argc) {
2146 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2150 param.fp_migrate = 1;
2151 rc = llapi_migrate_mdt(argv[optind], ¶m);
2153 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2154 argv[0], argv[optind], param.fp_mdt_index,
2159 static int lfs_osts(int argc, char **argv)
2161 return lfs_tgts(argc, argv);
2164 static int lfs_mdts(int argc, char **argv)
2166 return lfs_tgts(argc, argv);
2169 #define COOK(value) \
2172 while (value > 1024) { \
2180 #define CDF "%11llu"
2181 #define HDF "%8.1f%c"
2185 static int showdf(char *mntdir, struct obd_statfs *stat,
2186 char *uuid, int ishow, int cooked,
2187 char *type, int index, int rc)
2189 long long avail, used, total;
2191 char *suffix = "KMGTPEZY";
2192 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2193 char tbuf[3 * sizeof(__u64)];
2194 char ubuf[3 * sizeof(__u64)];
2195 char abuf[3 * sizeof(__u64)];
2196 char rbuf[3 * sizeof(__u64)];
2204 avail = stat->os_ffree;
2205 used = stat->os_files - stat->os_ffree;
2206 total = stat->os_files;
2208 int shift = cooked ? 0 : 10;
2210 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2211 used = ((stat->os_blocks - stat->os_bfree) *
2212 stat->os_bsize) >> shift;
2213 total = (stat->os_blocks * stat->os_bsize) >> shift;
2216 if ((used + avail) > 0)
2217 ratio = (double)used / (double)(used + avail);
2223 cook_val = (double)total;
2226 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2228 sprintf(tbuf, CDF, total);
2230 cook_val = (double)used;
2233 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2235 sprintf(ubuf, CDF, used);
2237 cook_val = (double)avail;
2240 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2242 sprintf(abuf, CDF, avail);
2244 sprintf(tbuf, CDF, total);
2245 sprintf(ubuf, CDF, used);
2246 sprintf(abuf, CDF, avail);
2249 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2250 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2251 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2253 printf("[%s:%d]\n", type, index);
2259 printf(UUF": inactive device\n", uuid);
2262 printf(UUF": %s\n", uuid, strerror(-rc));
2269 struct ll_stat_type {
2274 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2275 int cooked, int lazy)
2277 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2278 struct obd_uuid uuid_buf;
2279 char *poolname = NULL;
2280 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2281 { LL_STATFS_LOV, "OST" },
2283 struct ll_stat_type *tp;
2284 __u64 ost_ffree = 0;
2290 poolname = strchr(pool, '.');
2291 if (poolname != NULL) {
2292 if (strncmp(fsname, pool, strlen(fsname))) {
2293 fprintf(stderr, "filesystem name incorrect\n");
2302 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2303 "UUID", "Inodes", "IUsed", "IFree",
2304 "IUse%", "Mounted on");
2306 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2307 "UUID", cooked ? "bytes" : "1K-blocks",
2308 "Used", "Available", "Use%", "Mounted on");
2310 for (tp = types; tp->st_name != NULL; tp++) {
2311 for (index = 0; ; index++) {
2312 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2313 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2314 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2315 rc = llapi_obd_statfs(mntdir, type, index,
2316 &stat_buf, &uuid_buf);
2323 if (poolname && tp->st_op == LL_STATFS_LOV &&
2324 llapi_search_ost(fsname, poolname,
2325 obd_uuid2str(&uuid_buf)) != 1)
2328 /* the llapi_obd_statfs() call may have returned with
2329 * an error, but if it filled in uuid_buf we will at
2330 * lease use that to print out a message for that OBD.
2331 * If we didn't get anything in the uuid_buf, then fill
2332 * it in so that we can print an error message. */
2333 if (uuid_buf.uuid[0] == '\0')
2334 sprintf(uuid_buf.uuid, "%s%04x",
2335 tp->st_name, index);
2336 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2337 ishow, cooked, tp->st_name, index, rc);
2340 if (tp->st_op == LL_STATFS_LMV) {
2341 sum.os_ffree += stat_buf.os_ffree;
2342 sum.os_files += stat_buf.os_files;
2343 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2344 sum.os_blocks += stat_buf.os_blocks *
2346 sum.os_bfree += stat_buf.os_bfree *
2348 sum.os_bavail += stat_buf.os_bavail *
2350 ost_ffree += stat_buf.os_ffree;
2352 } else if (rc == -EINVAL || rc == -EFAULT) {
2358 /* If we don't have as many objects free on the OST as inodes
2359 * on the MDS, we reduce the total number of inodes to
2360 * compensate, so that the "inodes in use" number is correct.
2361 * Matches ll_statfs_internal() so the results are consistent. */
2362 if (ost_ffree < sum.os_ffree) {
2363 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2364 sum.os_ffree = ost_ffree;
2367 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2372 static int lfs_df(int argc, char **argv)
2374 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2375 int ishow = 0, cooked = 0;
2377 int c, rc = 0, index = 0;
2378 char fsname[PATH_MAX] = "", *pool_name = NULL;
2379 struct option long_opts[] = {
2380 {"pool", required_argument, 0, 'p'},
2381 {"lazy", 0, 0, 'l'},
2385 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2403 if (optind < argc && !realpath(argv[optind], path)) {
2405 fprintf(stderr, "error: invalid path '%s': %s\n",
2406 argv[optind], strerror(-rc));
2410 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2411 /* Check if we have a mount point */
2412 if (mntdir[0] == '\0')
2415 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2416 if (rc || path[0] != '\0')
2418 fsname[0] = '\0'; /* avoid matching in next loop */
2419 mntdir[0] = '\0'; /* avoid matching in next loop */
2425 static int lfs_getname(int argc, char **argv)
2427 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2428 int rc = 0, index = 0, c;
2429 char buf[sizeof(struct obd_uuid)];
2431 while ((c = getopt(argc, argv, "h")) != -1)
2434 if (optind == argc) { /* no paths specified, get all paths. */
2435 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2436 rc = llapi_getname(mntdir, buf, sizeof(buf));
2439 "cannot get name for `%s': %s\n",
2440 mntdir, strerror(-rc));
2444 printf("%s %s\n", buf, mntdir);
2446 path[0] = fsname[0] = mntdir[0] = 0;
2448 } else { /* paths specified, only attempt to search these. */
2449 for (; optind < argc; optind++) {
2450 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2453 "cannot get name for `%s': %s\n",
2454 argv[optind], strerror(-rc));
2458 printf("%s %s\n", buf, argv[optind]);
2464 static int lfs_check(int argc, char **argv)
2467 char mntdir[PATH_MAX] = {'\0'};
2476 obd_types[0] = obd_type1;
2477 obd_types[1] = obd_type2;
2479 if (strcmp(argv[1], "osts") == 0) {
2480 strcpy(obd_types[0], "osc");
2481 } else if (strcmp(argv[1], "mds") == 0) {
2482 strcpy(obd_types[0], "mdc");
2483 } else if (strcmp(argv[1], "servers") == 0) {
2485 strcpy(obd_types[0], "osc");
2486 strcpy(obd_types[1], "mdc");
2488 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2493 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2494 if (rc < 0 || mntdir[0] == '\0') {
2495 fprintf(stderr, "No suitable Lustre mount found\n");
2499 rc = llapi_target_check(num_types, obd_types, mntdir);
2501 fprintf(stderr, "error: %s: %s status failed\n",
2508 static int lfs_join(int argc, char **argv)
2510 fprintf(stderr, "join two lustre files into one.\n"
2511 "obsolete, HEAD does not support it anymore.\n");
2515 #ifdef HAVE_SYS_QUOTA_H
2516 #define ARG2INT(nr, str, msg) \
2519 nr = strtol(str, &endp, 0); \
2521 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2526 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2528 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2529 * returns the value or ULONG_MAX on integer overflow or incorrect format
2531 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2532 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2533 * 3. empty integer value is interpreted as 0
2535 static unsigned long str2sec(const char* timestr)
2537 const char spec[] = "smhdw";
2538 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2539 unsigned long val = 0;
2542 if (strpbrk(timestr, spec) == NULL) {
2543 /* no specifiers inside the time string,
2544 should treat it as an integer value */
2545 val = strtoul(timestr, &tail, 10);
2546 return *tail ? ULONG_MAX : val;
2549 /* format string is XXwXXdXXhXXmXXs */
2555 v = strtoul(timestr, &tail, 10);
2556 if (v == ULONG_MAX || *tail == '\0')
2557 /* value too large (ULONG_MAX or more)
2558 or missing specifier */
2561 ptr = strchr(spec, *tail);
2563 /* unknown specifier */
2568 /* check if product will overflow the type */
2569 if (!(v < ULONG_MAX / mult[ind]))
2572 ADD_OVERFLOW(val, mult[ind] * v);
2573 if (val == ULONG_MAX)
2585 #define ARG2ULL(nr, str, def_units) \
2587 unsigned long long limit, units = def_units; \
2590 rc = llapi_parse_size(str, &limit, &units, 1); \
2592 fprintf(stderr, "error: bad limit value %s\n", str); \
2598 static inline int has_times_option(int argc, char **argv)
2602 for (i = 1; i < argc; i++)
2603 if (!strcmp(argv[i], "-t"))
2609 int lfs_setquota_times(int argc, char **argv)
2612 struct if_quotactl qctl;
2613 char *mnt, *obd_type = (char *)qctl.obd_type;
2614 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2615 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2616 struct option long_opts[] = {
2617 {"block-grace", required_argument, 0, 'b'},
2618 {"group", no_argument, 0, 'g'},
2619 {"inode-grace", required_argument, 0, 'i'},
2620 {"times", no_argument, 0, 't'},
2621 {"user", no_argument, 0, 'u'},
2625 memset(&qctl, 0, sizeof(qctl));
2626 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2627 qctl.qc_type = UGQUOTA;
2629 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2633 if (qctl.qc_type != UGQUOTA) {
2634 fprintf(stderr, "error: -u and -g can't be used "
2635 "more than once\n");
2638 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2641 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2642 fprintf(stderr, "error: bad block-grace: %s\n",
2646 dqb->dqb_valid |= QIF_BTIME;
2649 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2650 fprintf(stderr, "error: bad inode-grace: %s\n",
2654 dqb->dqb_valid |= QIF_ITIME;
2656 case 't': /* Yes, of course! */
2658 default: /* getopt prints error message for us when opterr != 0 */
2663 if (qctl.qc_type == UGQUOTA) {
2664 fprintf(stderr, "error: neither -u nor -g specified\n");
2668 if (optind != argc - 1) {
2669 fprintf(stderr, "error: unexpected parameters encountered\n");
2674 rc = llapi_quotactl(mnt, &qctl);
2677 fprintf(stderr, "%s %s ", obd_type,
2678 obd_uuid2str(&qctl.obd_uuid));
2679 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2686 #define BSLIMIT (1 << 0)
2687 #define BHLIMIT (1 << 1)
2688 #define ISLIMIT (1 << 2)
2689 #define IHLIMIT (1 << 3)
2691 int lfs_setquota(int argc, char **argv)
2694 struct if_quotactl qctl;
2695 char *mnt, *obd_type = (char *)qctl.obd_type;
2696 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2697 struct option long_opts[] = {
2698 {"block-softlimit", required_argument, 0, 'b'},
2699 {"block-hardlimit", required_argument, 0, 'B'},
2700 {"group", required_argument, 0, 'g'},
2701 {"inode-softlimit", required_argument, 0, 'i'},
2702 {"inode-hardlimit", required_argument, 0, 'I'},
2703 {"user", required_argument, 0, 'u'},
2706 unsigned limit_mask = 0;
2709 if (has_times_option(argc, argv))
2710 return lfs_setquota_times(argc, argv);
2712 memset(&qctl, 0, sizeof(qctl));
2713 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2714 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2715 * so it can be used as a marker that qc_type
2716 * isn't reinitialized from command line */
2718 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2722 if (qctl.qc_type != UGQUOTA) {
2723 fprintf(stderr, "error: -u and -g can't be used"
2724 " more than once\n");
2727 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2728 rc = name2id(&qctl.qc_id, optarg,
2729 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2731 qctl.qc_id = strtoul(optarg, &endptr, 10);
2732 if (*endptr != '\0') {
2733 fprintf(stderr, "error: can't find id "
2734 "for name %s\n", optarg);
2740 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2741 dqb->dqb_bsoftlimit >>= 10;
2742 limit_mask |= BSLIMIT;
2743 if (dqb->dqb_bsoftlimit &&
2744 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2745 fprintf(stderr, "warning: block softlimit is "
2746 "smaller than the miminal qunit size, "
2747 "please see the help of setquota or "
2748 "Lustre manual for details.\n");
2751 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2752 dqb->dqb_bhardlimit >>= 10;
2753 limit_mask |= BHLIMIT;
2754 if (dqb->dqb_bhardlimit &&
2755 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2756 fprintf(stderr, "warning: block hardlimit is "
2757 "smaller than the miminal qunit size, "
2758 "please see the help of setquota or "
2759 "Lustre manual for details.\n");
2762 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2763 limit_mask |= ISLIMIT;
2764 if (dqb->dqb_isoftlimit &&
2765 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2766 fprintf(stderr, "warning: inode softlimit is "
2767 "smaller than the miminal qunit size, "
2768 "please see the help of setquota or "
2769 "Lustre manual for details.\n");
2772 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2773 limit_mask |= IHLIMIT;
2774 if (dqb->dqb_ihardlimit &&
2775 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2776 fprintf(stderr, "warning: inode hardlimit is "
2777 "smaller than the miminal qunit size, "
2778 "please see the help of setquota or "
2779 "Lustre manual for details.\n");
2781 default: /* getopt prints error message for us when opterr != 0 */
2786 if (qctl.qc_type == UGQUOTA) {
2787 fprintf(stderr, "error: neither -u nor -g was specified\n");
2791 if (limit_mask == 0) {
2792 fprintf(stderr, "error: at least one limit must be specified\n");
2796 if (optind != argc - 1) {
2797 fprintf(stderr, "error: unexpected parameters encountered\n");
2803 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2804 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2805 /* sigh, we can't just set blimits/ilimits */
2806 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2807 .qc_type = qctl.qc_type,
2808 .qc_id = qctl.qc_id};
2810 rc = llapi_quotactl(mnt, &tmp_qctl);
2812 fprintf(stderr, "error: setquota failed while retrieving"
2813 " current quota settings (%s)\n",
2818 if (!(limit_mask & BHLIMIT))
2819 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2820 if (!(limit_mask & BSLIMIT))
2821 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2822 if (!(limit_mask & IHLIMIT))
2823 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2824 if (!(limit_mask & ISLIMIT))
2825 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2827 /* Keep grace times if we have got no softlimit arguments */
2828 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2829 dqb->dqb_valid |= QIF_BTIME;
2830 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2833 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2834 dqb->dqb_valid |= QIF_ITIME;
2835 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2839 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2840 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2842 rc = llapi_quotactl(mnt, &qctl);
2845 fprintf(stderr, "%s %s ", obd_type,
2846 obd_uuid2str(&qctl.obd_uuid));
2847 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2854 static inline char *type2name(int check_type)
2856 if (check_type == USRQUOTA)
2858 else if (check_type == GRPQUOTA)
2864 /* Converts seconds value into format string
2865 * result is returned in buf
2867 * 1. result is in descenting order: 1w2d3h4m5s
2868 * 2. zero fields are not filled (except for p. 3): 5d1s
2869 * 3. zero seconds value is presented as "0s"
2871 static char * __sec2str(time_t seconds, char *buf)
2873 const char spec[] = "smhdw";
2874 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2879 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2880 c = seconds / mult[i];
2882 if (c > 0 || (i == 0 && buf == tail))
2883 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2891 static void sec2str(time_t seconds, char *buf, int rc)
2898 tail = __sec2str(seconds, tail);
2900 if (rc && tail - buf < 39) {
2906 static void diff2str(time_t seconds, char *buf, time_t now)
2912 if (seconds <= now) {
2913 strcpy(buf, "none");
2916 __sec2str(seconds - now, buf);
2919 static void print_quota_title(char *name, struct if_quotactl *qctl,
2920 bool human_readable)
2922 printf("Disk quotas for %s %s (%cid %u):\n",
2923 type2name(qctl->qc_type), name,
2924 *type2name(qctl->qc_type), qctl->qc_id);
2925 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2926 "Filesystem", human_readable ? "used" : "kbytes",
2927 "quota", "limit", "grace",
2928 "files", "quota", "limit", "grace");
2931 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
2934 snprintf(buf, buflen, LPU64, num);
2937 snprintf(buf, buflen, "%5.4gP",
2938 (double)num / ((__u64)1 << 40));
2940 snprintf(buf, buflen, "%5.4gT",
2941 (double)num / (1 << 30));
2943 snprintf(buf, buflen, "%5.4gG",
2944 (double)num / (1 << 20));
2946 snprintf(buf, buflen, "%5.4gM",
2947 (double)num / (1 << 10));
2949 snprintf(buf, buflen, LPU64"%s", num, "k");
2953 #define STRBUF_LEN 32
2954 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2961 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2962 int bover = 0, iover = 0;
2963 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2964 char numbuf[3][STRBUF_LEN];
2966 char strbuf[STRBUF_LEN];
2968 if (dqb->dqb_bhardlimit &&
2969 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2971 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2972 if (dqb->dqb_btime > now) {
2979 if (dqb->dqb_ihardlimit &&
2980 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2982 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2983 if (dqb->dqb_itime > now) {
2991 if (strlen(mnt) > 15)
2992 printf("%s\n%15s", mnt, "");
2994 printf("%15s", mnt);
2997 diff2str(dqb->dqb_btime, timebuf, now);
2999 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3000 strbuf, sizeof(strbuf), h);
3001 if (rc == -EREMOTEIO)
3002 sprintf(numbuf[0], "%s*", strbuf);
3004 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3005 "%s" : "[%s]", strbuf);
3007 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3008 if (type == QC_GENERAL)
3009 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3010 "%s" : "[%s]", strbuf);
3012 sprintf(numbuf[1], "%s", "-");
3014 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3015 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3016 "%s" : "[%s]", strbuf);
3018 printf(" %7s%c %6s %7s %7s",
3019 numbuf[0], bover ? '*' : ' ', numbuf[1],
3020 numbuf[2], bover > 1 ? timebuf : "-");
3023 diff2str(dqb->dqb_itime, timebuf, now);
3025 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3026 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
3028 if (type == QC_GENERAL)
3029 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3030 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
3032 sprintf(numbuf[1], "%s", "-");
3034 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3035 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
3037 if (type != QC_OSTIDX)
3038 printf(" %7s%c %6s %7s %7s",
3039 numbuf[0], iover ? '*' : ' ', numbuf[1],
3040 numbuf[2], iover > 1 ? timebuf : "-");
3042 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3045 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3046 qctl->qc_cmd == Q_GETOINFO) {
3050 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3051 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3052 printf("Block grace time: %s; Inode grace time: %s\n",
3053 bgtimebuf, igtimebuf);
3057 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3058 bool h, __u64 *total)
3060 int rc = 0, rc1 = 0, count = 0;
3061 __u32 valid = qctl->qc_valid;
3063 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3065 fprintf(stderr, "can not get %s count: %s\n",
3066 is_mdt ? "mdt": "ost", strerror(-rc));
3070 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3071 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3072 rc = llapi_quotactl(mnt, qctl);
3074 /* It is remote client case. */
3075 if (-rc == EOPNOTSUPP) {
3082 fprintf(stderr, "quotactl %s%d failed.\n",
3083 is_mdt ? "mdt": "ost", qctl->qc_idx);
3087 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3088 qctl->qc_valid, 0, h);
3089 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3090 qctl->qc_dqblk.dqb_bhardlimit;
3093 qctl->qc_valid = valid;
3097 static int lfs_quota(int argc, char **argv)
3100 char *mnt, *name = NULL;
3101 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3102 .qc_type = UGQUOTA };
3103 char *obd_type = (char *)qctl.obd_type;
3104 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3105 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3106 verbose = 0, pass = 0, quiet = 0, inacc;
3108 __u32 valid = QC_GENERAL, idx = 0;
3109 __u64 total_ialloc = 0, total_balloc = 0;
3110 bool human_readable = false;
3112 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3115 if (qctl.qc_type != UGQUOTA) {
3116 fprintf(stderr, "error: use either -u or -g\n");
3119 qctl.qc_type = USRQUOTA;
3122 if (qctl.qc_type != UGQUOTA) {
3123 fprintf(stderr, "error: use either -u or -g\n");
3126 qctl.qc_type = GRPQUOTA;
3129 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3132 valid = qctl.qc_valid = QC_UUID;
3133 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3136 valid = qctl.qc_valid = QC_MDTIDX;
3137 idx = qctl.qc_idx = atoi(optarg);
3140 valid = qctl.qc_valid = QC_OSTIDX;
3141 idx = qctl.qc_idx = atoi(optarg);
3150 human_readable = true;
3153 fprintf(stderr, "error: %s: option '-%c' "
3154 "unrecognized\n", argv[0], c);
3159 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3160 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3161 optind == argc - 1) {
3163 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3164 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3165 qctl.qc_valid = valid;
3168 qctl.qc_type = USRQUOTA;
3169 qctl.qc_id = geteuid();
3171 qctl.qc_type = GRPQUOTA;
3172 qctl.qc_id = getegid();
3174 rc = id2name(&name, qctl.qc_id,
3175 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3178 /* lfs quota -u username /path/to/lustre/mount */
3179 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3180 /* options should be followed by u/g-name and mntpoint */
3181 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3182 fprintf(stderr, "error: missing quota argument(s)\n");
3186 name = argv[optind++];
3187 rc = name2id(&qctl.qc_id, name,
3188 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3190 qctl.qc_id = strtoul(name, &endptr, 10);
3191 if (*endptr != '\0') {
3192 fprintf(stderr, "error: can't find id for name "
3197 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3198 fprintf(stderr, "error: missing quota info argument(s)\n");
3204 rc1 = llapi_quotactl(mnt, &qctl);
3208 fprintf(stderr, "%s quotas are not enabled.\n",
3209 qctl.qc_type == USRQUOTA ? "user" : "group");
3212 fprintf(stderr, "Permission denied.\n");
3214 /* We already got a "No such file..." message. */
3217 fprintf(stderr, "Unexpected quotactl error: %s\n",
3222 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3223 print_quota_title(name, &qctl, human_readable);
3225 if (rc1 && *obd_type)
3226 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3228 if (qctl.qc_valid != QC_GENERAL)
3231 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3232 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3233 (QIF_LIMITS|QIF_USAGE));
3235 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3237 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3239 char strbuf[STRBUF_LEN];
3241 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3243 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3245 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3247 printf("Total allocated inode limit: "LPU64", total "
3248 "allocated block limit: %s\n", total_ialloc, strbuf);
3251 if (rc1 || rc2 || rc3 || inacc)
3252 printf("Some errors happened when getting quota info. "
3253 "Some devices may be not working or deactivated. "
3254 "The data in \"[]\" is inaccurate.\n");
3262 #endif /* HAVE_SYS_QUOTA_H! */
3264 static int flushctx_ioctl(char *mp)
3268 fd = open(mp, O_RDONLY);
3270 fprintf(stderr, "flushctx: error open %s: %s\n",
3271 mp, strerror(errno));
3275 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3277 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3278 mp, strerror(errno));
3284 static int lfs_flushctx(int argc, char **argv)
3286 int kdestroy = 0, c;
3287 char mntdir[PATH_MAX] = {'\0'};
3291 while ((c = getopt(argc, argv, "k")) != -1) {
3297 fprintf(stderr, "error: %s: option '-%c' "
3298 "unrecognized\n", argv[0], c);
3304 if ((rc = system("kdestroy > /dev/null")) != 0) {
3305 rc = WEXITSTATUS(rc);
3306 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3310 if (optind >= argc) {
3311 /* flush for all mounted lustre fs. */
3312 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3313 /* Check if we have a mount point */
3314 if (mntdir[0] == '\0')
3317 if (flushctx_ioctl(mntdir))
3320 mntdir[0] = '\0'; /* avoid matching in next loop */
3323 /* flush fs as specified */
3324 while (optind < argc) {
3325 if (flushctx_ioctl(argv[optind++]))
3332 static int lfs_lsetfacl(int argc, char **argv)
3335 return(llapi_lsetfacl(argc, argv));
3338 static int lfs_lgetfacl(int argc, char **argv)
3341 return(llapi_lgetfacl(argc, argv));
3344 static int lfs_rsetfacl(int argc, char **argv)
3347 return(llapi_rsetfacl(argc, argv));
3350 static int lfs_rgetfacl(int argc, char **argv)
3353 return(llapi_rgetfacl(argc, argv));
3356 static int lfs_cp(int argc, char **argv)
3358 return(llapi_cp(argc, argv));
3361 static int lfs_ls(int argc, char **argv)
3363 return(llapi_ls(argc, argv));
3366 static int lfs_changelog(int argc, char **argv)
3368 void *changelog_priv;
3369 struct changelog_rec *rec;
3370 long long startrec = 0, endrec = 0;
3372 struct option long_opts[] = {
3373 {"follow", no_argument, 0, 'f'},
3376 char short_opts[] = "f";
3379 while ((rc = getopt_long(argc, argv, short_opts,
3380 long_opts, NULL)) != -1) {
3388 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3389 argv[0], argv[optind - 1]);
3396 mdd = argv[optind++];
3398 startrec = strtoll(argv[optind++], NULL, 10);
3400 endrec = strtoll(argv[optind++], NULL, 10);
3402 rc = llapi_changelog_start(&changelog_priv,
3403 CHANGELOG_FLAG_BLOCK |
3404 CHANGELOG_FLAG_JOBID |
3405 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3408 fprintf(stderr, "Can't start changelog: %s\n",
3409 strerror(errno = -rc));
3413 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3417 if (endrec && rec->cr_index > endrec) {
3418 llapi_changelog_free(&rec);
3421 if (rec->cr_index < startrec) {
3422 llapi_changelog_free(&rec);
3426 secs = rec->cr_time >> 30;
3427 gmtime_r(&secs, &ts);
3428 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3429 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3430 changelog_type2str(rec->cr_type),
3431 ts.tm_hour, ts.tm_min, ts.tm_sec,
3432 (int)(rec->cr_time & ((1<<30) - 1)),
3433 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3434 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3436 if (rec->cr_flags & CLF_JOBID) {
3437 struct changelog_ext_jobid *jid =
3438 changelog_rec_jobid(rec);
3440 if (jid->cr_jobid[0] != '\0')
3441 printf(" j=%s", jid->cr_jobid);
3444 if (rec->cr_namelen)
3445 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3446 rec->cr_namelen, changelog_rec_name(rec));
3448 if (rec->cr_flags & CLF_RENAME) {
3449 struct changelog_ext_rename *rnm =
3450 changelog_rec_rename(rec);
3452 if (!fid_is_zero(&rnm->cr_sfid))
3453 printf(" s="DFID" sp="DFID" %.*s",
3454 PFID(&rnm->cr_sfid),
3455 PFID(&rnm->cr_spfid),
3456 (int)changelog_rec_snamelen(rec),
3457 changelog_rec_sname(rec));
3461 llapi_changelog_free(&rec);
3464 llapi_changelog_fini(&changelog_priv);
3467 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3469 return (rc == 1 ? 0 : rc);
3472 static int lfs_changelog_clear(int argc, char **argv)
3480 endrec = strtoll(argv[3], NULL, 10);
3482 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3484 fprintf(stderr, "%s error: %s\n", argv[0],
3485 strerror(errno = -rc));
3489 static int lfs_fid2path(int argc, char **argv)
3491 struct option long_opts[] = {
3492 {"cur", no_argument, 0, 'c'},
3493 {"link", required_argument, 0, 'l'},
3494 {"rec", required_argument, 0, 'r'},
3497 char short_opts[] = "cl:r:";
3498 char *device, *fid, *path;
3499 long long recno = -1;
3505 while ((rc = getopt_long(argc, argv, short_opts,
3506 long_opts, NULL)) != -1) {
3512 linkno = strtol(optarg, NULL, 10);
3515 recno = strtoll(optarg, NULL, 10);
3520 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3521 argv[0], argv[optind - 1]);
3529 device = argv[optind++];
3530 path = calloc(1, PATH_MAX);
3532 fprintf(stderr, "error: Not enough memory\n");
3537 while (optind < argc) {
3538 fid = argv[optind++];
3540 lnktmp = (linkno >= 0) ? linkno : 0;
3542 int oldtmp = lnktmp;
3543 long long rectmp = recno;
3545 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3548 fprintf(stderr, "%s: error on FID %s: %s\n",
3549 argv[0], fid, strerror(errno = -rc2));
3556 fprintf(stdout, "%lld ", rectmp);
3557 if (device[0] == '/') {
3558 fprintf(stdout, "%s", device);
3559 if (device[strlen(device) - 1] != '/')
3560 fprintf(stdout, "/");
3561 } else if (path[0] == '\0') {
3562 fprintf(stdout, "/");
3564 fprintf(stdout, "%s\n", path);
3567 /* specified linkno */
3569 if (oldtmp == lnktmp)
3579 static int lfs_path2fid(int argc, char **argv)
3581 struct option long_opts[] = {
3582 {"parents", no_argument, 0, 'p'},
3586 const char short_opts[] = "p";
3587 const char *sep = "";
3590 bool show_parents = false;
3592 while ((rc = getopt_long(argc, argv, short_opts,
3593 long_opts, NULL)) != -1) {
3596 show_parents = true;
3599 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3600 argv[0], argv[optind - 1]);
3605 if (optind > argc - 1)
3607 else if (optind < argc - 1)
3611 for (path = argv + optind; *path != NULL; path++) {
3613 if (!show_parents) {
3614 err = llapi_path2fid(*path, &fid);
3616 printf("%s%s"DFID"\n",
3617 *sep != '\0' ? *path : "", sep,
3620 char name[NAME_MAX + 1];
3621 unsigned int linkno = 0;
3623 while ((err = llapi_path2parent(*path, linkno, &fid,
3624 name, sizeof(name))) == 0) {
3625 if (*sep != '\0' && linkno == 0)
3626 printf("%s%s", *path, sep);
3628 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3633 /* err == -ENODATA is end-of-loop */
3634 if (linkno > 0 && err == -ENODATA) {
3641 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3642 argv[0], show_parents ? "parent " : "", *path,
3654 static int lfs_data_version(int argc, char **argv)
3661 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3666 while ((c = getopt(argc, argv, "nrw")) != -1) {
3669 data_version_flags = 0;
3672 data_version_flags |= LL_DV_RD_FLUSH;
3675 data_version_flags |= LL_DV_WR_FLUSH;
3684 path = argv[optind];
3685 fd = open(path, O_RDONLY);
3687 err(errno, "cannot open file %s", path);
3689 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3691 err(errno, "cannot get version for %s", path);
3693 printf(LPU64 "\n", data_version);
3699 static int lfs_hsm_state(int argc, char **argv)
3704 struct hsm_user_state hus;
3712 rc = llapi_hsm_state_get(path, &hus);
3714 fprintf(stderr, "can't get hsm state for %s: %s\n",
3715 path, strerror(errno = -rc));
3719 /* Display path name and status flags */
3720 printf("%s: (0x%08x)", path, hus.hus_states);
3722 if (hus.hus_states & HS_RELEASED)
3723 printf(" released");
3724 if (hus.hus_states & HS_EXISTS)
3726 if (hus.hus_states & HS_DIRTY)
3728 if (hus.hus_states & HS_ARCHIVED)
3729 printf(" archived");
3730 /* Display user-settable flags */
3731 if (hus.hus_states & HS_NORELEASE)
3732 printf(" never_release");
3733 if (hus.hus_states & HS_NOARCHIVE)
3734 printf(" never_archive");
3735 if (hus.hus_states & HS_LOST)
3736 printf(" lost_from_hsm");
3738 if (hus.hus_archive_id != 0)
3739 printf(", archive_id:%d", hus.hus_archive_id);
3742 } while (++i < argc);
3747 #define LFS_HSM_SET 0
3748 #define LFS_HSM_CLEAR 1
3751 * Generic function to set or clear HSM flags.
3752 * Used by hsm_set and hsm_clear.
3754 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3756 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3758 struct option long_opts[] = {
3759 {"lost", 0, 0, 'l'},
3760 {"norelease", 0, 0, 'r'},
3761 {"noarchive", 0, 0, 'a'},
3762 {"archived", 0, 0, 'A'},
3763 {"dirty", 0, 0, 'd'},
3764 {"exists", 0, 0, 'e'},
3767 char short_opts[] = "lraAde";
3775 while ((c = getopt_long(argc, argv, short_opts,
3776 long_opts, NULL)) != -1) {
3782 mask |= HS_NOARCHIVE;
3785 mask |= HS_ARCHIVED;
3788 mask |= HS_NORELEASE;
3799 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3800 argv[0], argv[optind - 1]);
3805 /* User should have specified a flag */
3809 while (optind < argc) {
3811 path = argv[optind];
3813 /* If mode == 0, this means we apply the mask. */
3814 if (mode == LFS_HSM_SET)
3815 rc = llapi_hsm_state_set(path, mask, 0, 0);
3817 rc = llapi_hsm_state_set(path, 0, mask, 0);
3820 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3821 path, strerror(errno = -rc));
3830 static int lfs_hsm_action(int argc, char **argv)
3835 struct hsm_current_action hca;
3836 struct hsm_extent he;
3837 enum hsm_user_action hua;
3838 enum hsm_progress_states hps;
3846 rc = llapi_hsm_current_action(path, &hca);
3848 fprintf(stderr, "can't get hsm action for %s: %s\n",
3849 path, strerror(errno = -rc));
3852 he = hca.hca_location;
3853 hua = hca.hca_action;
3854 hps = hca.hca_state;
3856 printf("%s: %s", path, hsm_user_action2name(hua));
3858 /* Skip file without action */
3859 if (hca.hca_action == HUA_NONE) {
3864 printf(" %s ", hsm_progress_state2name(hps));
3866 if ((hps == HPS_RUNNING) &&
3867 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3868 printf("(%llu bytes moved)\n",
3869 (unsigned long long)he.length);
3870 else if ((he.offset + he.length) == LUSTRE_EOF)
3871 printf("(from %llu to EOF)\n",
3872 (unsigned long long)he.offset);
3874 printf("(from %llu to %llu)\n",
3875 (unsigned long long)he.offset,
3876 (unsigned long long)(he.offset + he.length));
3878 } while (++i < argc);
3883 static int lfs_hsm_set(int argc, char **argv)
3885 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3888 static int lfs_hsm_clear(int argc, char **argv)
3890 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3894 * Check file state and return its fid, to be used by lfs_hsm_request().
3896 * \param[in] file Path to file to check
3897 * \param[in,out] fid Pointer to allocated lu_fid struct.
3898 * \param[in,out] last_dev Pointer to last device id used.
3900 * \return 0 on success.
3902 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3908 rc = lstat(file, &st);
3910 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3913 /* Checking for regular file as archiving as posix copytool
3914 * rejects archiving files other than regular files
3916 if (!S_ISREG(st.st_mode)) {
3917 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3920 /* A request should be ... */
3921 if (*last_dev != st.st_dev && *last_dev != 0) {
3922 fprintf(stderr, "All files should be "
3923 "on the same filesystem: %s\n", file);
3926 *last_dev = st.st_dev;
3928 rc = llapi_path2fid(file, fid);
3930 fprintf(stderr, "Cannot read FID of %s: %s\n",
3931 file, strerror(-rc));
3937 /* Fill an HSM HUR item with a given file name.
3939 * If mntpath is set, then the filename is actually a FID, and no
3940 * lookup on the filesystem will be performed.
3942 * \param[in] hur the user request to fill
3943 * \param[in] idx index of the item inside the HUR to fill
3944 * \param[in] mntpath mountpoint of Lustre
3945 * \param[in] fname filename (if mtnpath is NULL)
3946 * or FID (if mntpath is set)
3947 * \param[in] last_dev pointer to last device id used
3949 * \retval 0 on success
3950 * \retval CMD_HELP or a negative errno on error
3952 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3953 const char *mntpath, const char *fname,
3956 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3959 hui->hui_extent.length = -1;
3961 if (mntpath != NULL) {
3964 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3968 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3973 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3977 hur->hur_request.hr_itemcount++;
3982 static int lfs_hsm_request(int argc, char **argv, int action)
3984 struct option long_opts[] = {
3985 {"filelist", 1, 0, 'l'},
3986 {"data", 1, 0, 'D'},
3987 {"archive", 1, 0, 'a'},
3988 {"mntpath", 1, 0, 'm'},
3992 char short_opts[] = "l:D:a:m:";
3993 struct hsm_user_request *hur, *oldhur;
3998 char *filelist = NULL;
3999 char fullpath[PATH_MAX];
4000 char *opaque = NULL;
4004 int nbfile_alloc = 0;
4005 char *some_file = NULL;
4006 char *mntpath = NULL;
4012 while ((c = getopt_long(argc, argv, short_opts,
4013 long_opts, NULL)) != -1) {
4022 if (action != HUA_ARCHIVE &&
4023 action != HUA_REMOVE) {
4025 "error: -a is supported only "
4026 "when archiving or removing\n");
4029 archive_id = atoi(optarg);
4032 if (some_file == NULL) {
4034 some_file = strdup(optarg);
4040 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4041 argv[0], argv[optind - 1]);
4046 /* All remaining args are files, so we have at least nbfile */
4047 nbfile = argc - optind;
4049 if ((nbfile == 0) && (filelist == NULL))
4053 opaque_len = strlen(opaque);
4055 /* Alloc the request structure with enough place to store all files
4056 * from command line. */
4057 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4059 fprintf(stderr, "Cannot create the request: %s\n",
4063 nbfile_alloc = nbfile;
4065 hur->hur_request.hr_action = action;
4066 hur->hur_request.hr_archive_id = archive_id;
4067 hur->hur_request.hr_flags = 0;
4069 /* All remaining args are files, add them */
4070 if (nbfile != 0 && some_file == NULL)
4071 some_file = strdup(argv[optind]);
4073 for (i = 0; i < nbfile; i++) {
4074 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4080 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4082 /* If a filelist was specified, read the filelist from it. */
4083 if (filelist != NULL) {
4084 fp = fopen(filelist, "r");
4086 fprintf(stderr, "Cannot read the file list %s: %s\n",
4087 filelist, strerror(errno));
4092 while ((rc = getline(&line, &len, fp)) != -1) {
4093 /* If allocated buffer was too small, get something
4095 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4098 nbfile_alloc = nbfile_alloc * 2 + 1;
4100 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4103 fprintf(stderr, "hsm: cannot allocate "
4104 "the request: %s\n",
4111 size = hur_len(oldhur);
4113 fprintf(stderr, "hsm: cannot allocate "
4114 "%u files + %u bytes data\n",
4115 oldhur->hur_request.hr_itemcount,
4116 oldhur->hur_request.hr_data_len);
4123 memcpy(hur, oldhur, size);
4128 if (line[strlen(line) - 1] == '\n')
4129 line[strlen(line) - 1] = '\0';
4131 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4132 mntpath, line, &last_dev);
4138 if (some_file == NULL) {
4148 /* If a --data was used, add it to the request */
4149 hur->hur_request.hr_data_len = opaque_len;
4151 memcpy(hur_data(hur), opaque, opaque_len);
4153 /* Send the HSM request */
4154 if (realpath(some_file, fullpath) == NULL) {
4155 fprintf(stderr, "Could not find path '%s': %s\n",
4156 some_file, strerror(errno));
4158 rc = llapi_hsm_request(fullpath, hur);
4160 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4161 some_file, strerror(-rc));
4171 static int lfs_hsm_archive(int argc, char **argv)
4173 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4176 static int lfs_hsm_restore(int argc, char **argv)
4178 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4181 static int lfs_hsm_release(int argc, char **argv)
4183 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4186 static int lfs_hsm_remove(int argc, char **argv)
4188 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4191 static int lfs_hsm_cancel(int argc, char **argv)
4193 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4196 static int lfs_swap_layouts(int argc, char **argv)
4201 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4202 SWAP_LAYOUTS_KEEP_MTIME |
4203 SWAP_LAYOUTS_KEEP_ATIME);
4206 int main(int argc, char **argv)
4210 /* Ensure that liblustreapi constructor has run */
4211 if (!liblustreapi_initialized)
4212 fprintf(stderr, "liblustreapi was not properly initialized\n");
4216 Parser_init("lfs > ", cmdlist);
4218 progname = argv[0]; /* Used in error messages */
4220 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4222 rc = Parser_commands();
4225 return rc < 0 ? -rc : rc;
4228 #ifdef _LUSTRE_IDL_H_
4229 /* Everything we need here should be included by lustreapi.h. */
4230 # error "lfs should not depend on lustre_idl.h"
4231 #endif /* _LUSTRE_IDL_H_ */