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, 2014, 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>] <directory|filename>]\n"
362 "\tmdt_idx: MDT index to migrate to\n"
366 "To move directories between MDTs. This command is deprecated, "
367 "use \"migrate\" instead.\n"
368 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
370 {"help", Parser_help, 0, "help"},
371 {"exit", Parser_quit, 0, "quit"},
372 {"quit", Parser_quit, 0, "quit"},
373 {"--version", Parser_version, 0,
374 "output build version of the utility and exit"},
379 #define MIGRATION_NONBLOCK 1
382 * Internal helper for migrate_copy_data(). Check lease and report error if
385 * \param[in] fd File descriptor on which to check the lease.
386 * \param[out] lease_broken Set to true if the lease was broken.
387 * \param[in] group_locked Whether a group lock was taken or not.
388 * \param[in] path Name of the file being processed, for error
391 * \retval 0 Migration can keep on going.
392 * \retval -errno Error occurred, abort migration.
394 static int check_lease(int fd, bool *lease_broken, bool group_locked,
399 if (!file_lease_supported)
402 rc = llapi_lease_check(fd);
404 return 0; /* llapi_check_lease returns > 0 on success. */
407 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
409 rc = rc ? rc : -EAGAIN;
411 fprintf(stderr, "%s: external attempt to access file '%s' "
412 "blocked until migration ends.\n", progname, path);
415 *lease_broken = true;
419 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
420 bool group_locked, const char *fname)
429 bool lease_broken = false;
431 /* Use a page-aligned buffer for direct I/O */
432 rc = posix_memalign(&buf, getpagesize(), buf_size);
437 /* read new data only if we have written all
438 * previously read data */
441 rc = check_lease(fd_src, &lease_broken,
442 group_locked, fname);
446 rsize = read(fd_src, buf, buf_size);
449 fprintf(stderr, "%s: %s: read failed: %s\n",
450 progname, fname, strerror(-rc));
460 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
464 "%s: %s: write failed on volatile: %s\n",
465 progname, fname, strerror(-rc));
475 fprintf(stderr, "%s: %s: fsync failed: %s\n",
476 progname, fname, strerror(-rc));
484 static int migrate_copy_timestamps(int fdv, const struct stat *st)
486 struct timeval tv[2] = {
487 {.tv_sec = st->st_atime},
488 {.tv_sec = st->st_mtime}
491 return futimes(fdv, tv);
494 static int migrate_block(int fd, int fdv, const struct stat *st,
495 size_t buf_size, const char *name)
502 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
504 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
505 progname, name, strerror(-rc));
513 /* The grouplock blocks all concurrent accesses to the file.
514 * It has to be taken after llapi_get_data_version as it would
516 rc = llapi_group_lock(fd, gid);
518 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
519 progname, name, strerror(-rc));
523 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
525 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
529 /* Make sure we keep original atime/mtime values */
530 rc = migrate_copy_timestamps(fdv, st);
532 fprintf(stderr, "%s: %s: timestamp copy failed\n",
538 * for a migration we need to check data version on file did
541 * Pass in gid=0 since we already own grouplock. */
542 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
543 SWAP_LAYOUTS_CHECK_DV1);
545 fprintf(stderr, "%s: %s: dataversion changed during copy, "
546 "migration aborted\n", progname, name);
549 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
550 name, strerror(-rc));
555 rc2 = llapi_group_unlock(fd, gid);
556 if (rc2 < 0 && rc == 0) {
557 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
558 progname, name, strerror(-rc2));
565 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
566 size_t buf_size, const char *name)
572 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
574 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
575 progname, name, strerror(-rc));
579 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
581 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
585 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
587 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
588 progname, name, strerror(-rc));
594 fprintf(stderr, "%s: %s: data version changed during "
600 /* Make sure we keep original atime/mtime values */
601 rc = migrate_copy_timestamps(fdv, st);
603 fprintf(stderr, "%s: %s: timestamp copy failed\n",
608 /* Atomically put lease, swap layouts and close.
609 * for a migration we need to check data version on file did
611 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
613 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
614 progname, name, strerror(-rc));
621 static int lfs_migrate(char *name, __u64 migration_flags,
622 struct llapi_stripe_param *param)
626 char volatile_file[PATH_MAX +
627 LUSTRE_VOLATILE_HDR_LEN + 4];
628 char parent[PATH_MAX];
631 struct lov_user_md *lum = NULL;
634 bool have_lease_rdlck = false;
638 /* find the right size for the IO and allocate the buffer */
639 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
640 lum = malloc(lum_size);
646 rc = llapi_file_get_stripe(name, lum);
647 /* failure can happen for many reasons and some may be not real errors
649 * in case of a real error, a later call will fail with better
650 * error management */
652 buf_size = 1024 * 1024;
654 buf_size = lum->lmm_stripe_size;
656 /* open file, direct io */
657 /* even if the file is only read, WR mode is nedeed to allow
658 * layout swap on fd */
659 fd = open(name, O_RDWR | O_DIRECT);
662 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
667 if (file_lease_supported) {
668 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
669 if (rc == -EOPNOTSUPP) {
670 /* Older servers do not support file lease.
671 * Disable related checks. This opens race conditions
672 * as explained in LU-4840 */
673 file_lease_supported = false;
675 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
676 progname, name, strerror(-rc));
679 have_lease_rdlck = true;
683 /* search for file directory pathname */
684 if (strlen(name) > sizeof(parent)-1) {
688 strncpy(parent, name, sizeof(parent));
689 ptr = strrchr(parent, '/');
691 if (getcwd(parent, sizeof(parent)) == NULL) {
702 rc = snprintf(volatile_file, sizeof(volatile_file), "%s/%s::", parent,
703 LUSTRE_VOLATILE_HDR);
704 if (rc >= sizeof(volatile_file)) {
709 /* create, open a volatile file, use caching (ie no directio) */
710 /* exclusive create is not needed because volatile files cannot
711 * conflict on name by construction */
712 fdv = llapi_file_open_param(volatile_file, O_CREAT | O_WRONLY, 0644,
716 fprintf(stderr, "%s: %s: cannot create volatile file in"
718 progname, parent, strerror(-rc));
722 /* Not-owner (root?) special case.
723 * Need to set owner/group of volatile file like original.
724 * This will allow to pass related check during layout_swap.
729 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
733 rc = fstat(fdv, &stv);
736 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
737 volatile_file, strerror(errno));
740 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
741 rc = fchown(fdv, st.st_uid, st.st_gid);
744 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
745 name, strerror(errno));
750 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
751 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
753 have_lease_rdlck = false;
754 fdv = -1; /* The volatile file is closed as we put the
755 * lease in non-blocking mode. */
758 /* Blocking mode (forced if servers do not support file lease).
759 * It is also the default mode, since we cannot distinguish
760 * between a broken lease and a server that does not support
761 * atomic swap/close (LU-6785) */
762 rc = migrate_block(fd, fdv, &st, buf_size, name);
766 if (have_lease_rdlck)
783 * Parse a string containing an OST index list into an array of integers.
785 * The input string contains a comma delimited list of individual
786 * indices and ranges, for example "1,2-4,7". Add the indices into the
787 * \a osts array and remove duplicates.
789 * \param[out] osts array to store indices in
790 * \param[in] size size of \a osts array
791 * \param[in] offset starting index in \a osts
792 * \param[in] arg string containing OST index list
794 * \retval positive number of indices in \a osts
795 * \retval -EINVAL unable to parse \a arg
797 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
801 int slots = size - offset;
809 while (!end_of_loop) {
817 ptr = strchrnul(arg, ',');
819 end_of_loop = *ptr == '\0';
822 start_index = strtol(arg, &endptr, 0);
823 if (endptr == arg) /* no data at all */
825 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
830 end_index = start_index;
831 if (*endptr == '-') {
832 end_index = strtol(endptr + 1, &endptr, 0);
835 if (end_index < start_index)
839 for (i = start_index; i <= end_index && slots > 0; i++) {
842 /* remove duplicate */
843 for (j = 0; j < offset; j++) {
847 if (j == offset) { /* no duplicate */
852 if (slots == 0 && i < end_index)
860 if (!end_of_loop && ptr != NULL)
863 return rc < 0 ? rc : nr;
867 static int lfs_setstripe(int argc, char **argv)
869 struct llapi_stripe_param *param = NULL;
870 struct find_param migrate_mdt_param = {
877 unsigned long long st_size;
878 int st_offset, st_count;
882 char *stripe_size_arg = NULL;
883 char *stripe_off_arg = NULL;
884 char *stripe_count_arg = NULL;
885 char *pool_name_arg = NULL;
886 char *mdt_idx_arg = NULL;
887 unsigned long long size_units = 1;
888 bool migrate_mode = false;
889 bool migration_block = false;
890 __u64 migration_flags = 0;
891 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
894 struct option long_opts[] = {
895 /* --block is only valid in migrate mode */
896 {"block", no_argument, 0, 'b'},
897 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
898 /* This formerly implied "stripe-count", but was explicitly
899 * made "stripe-count" for consistency with other options,
900 * and to separate it from "mdt-count" when DNE arrives. */
901 {"count", required_argument, 0, 'c'},
903 {"stripe-count", required_argument, 0, 'c'},
904 {"stripe_count", required_argument, 0, 'c'},
905 {"delete", no_argument, 0, 'd'},
906 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
907 /* This formerly implied "stripe-index", but was explicitly
908 * made "stripe-index" for consistency with other options,
909 * and to separate it from "mdt-index" when DNE arrives. */
910 {"index", required_argument, 0, 'i'},
912 {"stripe-index", required_argument, 0, 'i'},
913 {"stripe_index", required_argument, 0, 'i'},
914 {"mdt-index", required_argument, 0, 'm'},
915 {"mdt_index", required_argument, 0, 'm'},
916 /* --non-block is only valid in migrate mode */
917 {"non-block", no_argument, 0, 'n'},
918 {"ost-list", required_argument, 0, 'o'},
919 {"ost_list", required_argument, 0, 'o'},
920 {"pool", required_argument, 0, 'p'},
921 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
922 /* This formerly implied "--stripe-size", but was confusing
923 * with "lfs find --size|-s", which means "file size", so use
924 * the consistent "--stripe-size|-S" for all commands. */
925 {"size", required_argument, 0, 's'},
927 {"stripe-size", required_argument, 0, 'S'},
928 {"stripe_size", required_argument, 0, 'S'},
936 if (strcmp(argv[0], "migrate") == 0)
939 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:",
940 long_opts, NULL)) >= 0) {
947 fprintf(stderr, "--block is valid only for"
951 migration_block = true;
954 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
955 if (strcmp(argv[optind - 1], "--count") == 0)
956 fprintf(stderr, "warning: '--count' deprecated"
957 ", use '--stripe-count' instead\n");
959 stripe_count_arg = optarg;
962 /* delete the default striping pattern */
966 nr_osts = parse_targets(osts,
967 sizeof(osts) / sizeof(__u32),
971 "error: %s: bad OST indices '%s'\n",
976 if (st_offset == -1) /* first in the command line */
980 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
981 if (strcmp(argv[optind - 1], "--index") == 0)
982 fprintf(stderr, "warning: '--index' deprecated"
983 ", use '--stripe-index' instead\n");
985 stripe_off_arg = optarg;
989 fprintf(stderr, "--mdt-index is valid only for"
993 mdt_idx_arg = optarg;
997 fprintf(stderr, "--non-block is valid only for"
1001 migration_flags |= MIGRATION_NONBLOCK;
1003 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1005 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1006 fprintf(stderr, "warning: '--size|-s' deprecated, "
1007 "use '--stripe-size|-S' instead\n");
1009 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1011 stripe_size_arg = optarg;
1014 pool_name_arg = optarg;
1021 fname = argv[optind];
1024 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1025 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1026 fprintf(stderr, "error: %s: cannot specify -d with "
1027 "-s, -c, -o, or -p options\n",
1032 if (optind == argc) {
1033 fprintf(stderr, "error: %s: missing filename|dirname\n",
1038 if (mdt_idx_arg != NULL && optind > 3) {
1039 fprintf(stderr, "error: %s: cannot specify -m with other "
1040 "options\n", argv[0]);
1044 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1046 "error: %s: cannot specify --non-block and --block\n",
1051 if (pool_name_arg != NULL) {
1055 ptr = strchr(pool_name_arg, '.');
1057 ptr = pool_name_arg;
1059 if ((ptr - pool_name_arg) == 0) {
1060 fprintf(stderr, "error: %s: fsname is empty "
1061 "in pool name '%s'\n",
1062 argv[0], pool_name_arg);
1069 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1071 fprintf(stderr, "error: %s: poolname '%s' is "
1073 argv[0], pool_name_arg);
1075 } else if (rc == -2) {
1076 fprintf(stderr, "error: %s: pool name '%s' is too long "
1077 "(max is %d characters)\n",
1078 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1080 } else if (rc > 0) {
1081 fprintf(stderr, "error: %s: char '%c' not allowed in "
1083 argv[0], rc, pool_name_arg);
1088 /* get the stripe size */
1089 if (stripe_size_arg != NULL) {
1090 result = llapi_parse_size(stripe_size_arg, &st_size,
1093 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1094 argv[0], stripe_size_arg);
1098 /* get the stripe offset */
1099 if (stripe_off_arg != NULL) {
1100 st_offset = strtol(stripe_off_arg, &end, 0);
1102 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1103 argv[0], stripe_off_arg);
1107 /* get the stripe count */
1108 if (stripe_count_arg != NULL) {
1109 st_count = strtoul(stripe_count_arg, &end, 0);
1111 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1112 argv[0], stripe_count_arg);
1117 if (mdt_idx_arg != NULL) {
1118 /* initialize migrate mdt parameters */
1119 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1121 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1122 argv[0], mdt_idx_arg);
1125 migrate_mdt_param.fp_migrate = 1;
1127 /* initialize stripe parameters */
1128 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1129 if (param == NULL) {
1130 fprintf(stderr, "error: %s: run out of memory\n",
1135 param->lsp_stripe_size = st_size;
1136 param->lsp_stripe_offset = st_offset;
1137 param->lsp_stripe_count = st_count;
1138 param->lsp_stripe_pattern = 0;
1139 param->lsp_pool = pool_name_arg;
1140 param->lsp_is_specific = false;
1142 if (st_count > 0 && nr_osts != st_count) {
1143 fprintf(stderr, "error: %s: stripe count '%d' "
1144 "doesn't match the number of OSTs: %d\n"
1145 , argv[0], st_count, nr_osts);
1150 param->lsp_is_specific = true;
1151 param->lsp_stripe_count = nr_osts;
1152 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1156 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1157 if (!migrate_mode) {
1158 result = llapi_file_open_param(fname,
1165 } else if (mdt_idx_arg != NULL) {
1166 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1168 result = lfs_migrate(fname, migration_flags, param);
1171 /* Save the first error encountered. */
1175 "error: %s: %s file '%s' failed\n",
1176 argv[0], migrate_mode ? "migrate" : "create",
1186 static int lfs_poollist(int argc, char **argv)
1191 return llapi_poollist(argv[1]);
1194 static int set_time(time_t *time, time_t *set, char *str)
1201 else if (str[0] == '-')
1207 t = strtol(str, NULL, 0);
1208 if (*time < t * 24 * 60 * 60) {
1211 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1215 *set = *time - t * 24 * 60 * 60;
1222 static int name2id(unsigned int *id, char *name, int type)
1225 struct passwd *entry;
1227 if (!(entry = getpwnam(name))) {
1233 *id = entry->pw_uid;
1235 struct group *entry;
1237 if (!(entry = getgrnam(name))) {
1243 *id = entry->gr_gid;
1249 static int id2name(char **name, unsigned int id, int type)
1252 struct passwd *entry;
1254 if (!(entry = getpwuid(id))) {
1260 *name = entry->pw_name;
1262 struct group *entry;
1264 if (!(entry = getgrgid(id))) {
1270 *name = entry->gr_name;
1276 static int name2layout(__u32 *layout, char *name)
1281 for (ptr = name; ; ptr = NULL) {
1282 lyt = strtok(ptr, ",");
1285 if (strcmp(lyt, "released") == 0)
1286 *layout |= LOV_PATTERN_F_RELEASED;
1287 else if (strcmp(lyt, "raid0") == 0)
1288 *layout |= LOV_PATTERN_RAID0;
1295 #define FIND_POOL_OPT 3
1296 static int lfs_find(int argc, char **argv)
1301 struct find_param param = {
1305 struct option long_opts[] = {
1306 {"atime", required_argument, 0, 'A'},
1307 {"stripe-count", required_argument, 0, 'c'},
1308 {"stripe_count", required_argument, 0, 'c'},
1309 {"ctime", required_argument, 0, 'C'},
1310 {"maxdepth", required_argument, 0, 'D'},
1311 {"gid", required_argument, 0, 'g'},
1312 {"group", required_argument, 0, 'G'},
1313 {"stripe-index", required_argument, 0, 'i'},
1314 {"stripe_index", required_argument, 0, 'i'},
1315 {"layout", required_argument, 0, 'L'},
1316 {"mdt", required_argument, 0, 'm'},
1317 {"mtime", required_argument, 0, 'M'},
1318 {"name", required_argument, 0, 'n'},
1319 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1320 {"obd", required_argument, 0, 'O'},
1321 {"ost", required_argument, 0, 'O'},
1322 /* no short option for pool, p/P already used */
1323 {"pool", required_argument, 0, FIND_POOL_OPT},
1324 {"print0", no_argument, 0, 'p'},
1325 {"print", no_argument, 0, 'P'},
1326 {"size", required_argument, 0, 's'},
1327 {"stripe-size", required_argument, 0, 'S'},
1328 {"stripe_size", required_argument, 0, 'S'},
1329 {"type", required_argument, 0, 't'},
1330 {"uid", required_argument, 0, 'u'},
1331 {"user", required_argument, 0, 'U'},
1344 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1345 while ((c = getopt_long_only(argc, argv,
1346 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1347 long_opts, NULL)) >= 0) {
1352 /* '!' is part of option */
1353 /* when getopt_long_only() finds a string which is not
1354 * an option nor a known option argument it returns 1
1355 * in that case if we already have found pathstart and pathend
1356 * (i.e. we have the list of pathnames),
1357 * the only supported value is "!"
1359 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1360 if (!isoption && pathend != -1) {
1361 fprintf(stderr, "err: %s: filename|dirname must either "
1362 "precede options or follow options\n",
1367 if (!isoption && pathstart == -1)
1368 pathstart = optind - 1;
1369 if (isoption && pathstart != -1 && pathend == -1)
1370 pathend = optind - 2;
1376 /* unknown; opt is "!" or path component,
1377 * checking done above.
1379 if (strcmp(optarg, "!") == 0)
1383 xtime = ¶m.fp_atime;
1384 xsign = ¶m.fp_asign;
1385 param.fp_exclude_atime = !!neg_opt;
1386 /* no break, this falls through to 'C' for ctime */
1389 xtime = ¶m.fp_ctime;
1390 xsign = ¶m.fp_csign;
1391 param.fp_exclude_ctime = !!neg_opt;
1393 /* no break, this falls through to 'M' for mtime */
1396 xtime = ¶m.fp_mtime;
1397 xsign = ¶m.fp_msign;
1398 param.fp_exclude_mtime = !!neg_opt;
1400 rc = set_time(&t, xtime, optarg);
1401 if (rc == INT_MAX) {
1409 if (optarg[0] == '+') {
1410 param.fp_stripe_count_sign = -1;
1412 } else if (optarg[0] == '-') {
1413 param.fp_stripe_count_sign = 1;
1417 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1418 if (*endptr != '\0') {
1419 fprintf(stderr,"error: bad stripe_count '%s'\n",
1424 param.fp_check_stripe_count = 1;
1425 param.fp_exclude_stripe_count = !!neg_opt;
1428 param.fp_max_depth = strtol(optarg, 0, 0);
1432 rc = name2id(¶m.fp_gid, optarg, GROUP);
1434 param.fp_gid = strtoul(optarg, &endptr, 10);
1435 if (*endptr != '\0') {
1436 fprintf(stderr, "Group/GID: %s cannot "
1437 "be found.\n", optarg);
1442 param.fp_exclude_gid = !!neg_opt;
1443 param.fp_check_gid = 1;
1446 ret = name2layout(¶m.fp_layout, optarg);
1449 param.fp_exclude_layout = !!neg_opt;
1450 param.fp_check_layout = 1;
1454 rc = name2id(¶m.fp_uid, optarg, USER);
1456 param.fp_uid = strtoul(optarg, &endptr, 10);
1457 if (*endptr != '\0') {
1458 fprintf(stderr, "User/UID: %s cannot "
1459 "be found.\n", optarg);
1464 param.fp_exclude_uid = !!neg_opt;
1465 param.fp_check_uid = 1;
1468 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1470 "Pool name %s is too long"
1471 " (max is %d)\n", optarg,
1476 /* we do check for empty pool because empty pool
1477 * is used to find V1 lov attributes */
1478 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1479 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1480 param.fp_exclude_pool = !!neg_opt;
1481 param.fp_check_pool = 1;
1484 param.fp_pattern = (char *)optarg;
1485 param.fp_exclude_pattern = !!neg_opt;
1490 char *buf, *token, *next, *p;
1494 buf = strdup(optarg);
1500 param.fp_exclude_obd = !!neg_opt;
1503 while (token && *token) {
1504 token = strchr(token, ',');
1511 param.fp_exclude_mdt = !!neg_opt;
1512 param.fp_num_alloc_mdts += len;
1513 tmp = realloc(param.fp_mdt_uuid,
1514 param.fp_num_alloc_mdts *
1515 sizeof(*param.fp_mdt_uuid));
1521 param.fp_mdt_uuid = tmp;
1523 param.fp_exclude_obd = !!neg_opt;
1524 param.fp_num_alloc_obds += len;
1525 tmp = realloc(param.fp_obd_uuid,
1526 param.fp_num_alloc_obds *
1527 sizeof(*param.fp_obd_uuid));
1533 param.fp_obd_uuid = tmp;
1535 for (token = buf; token && *token; token = next) {
1536 struct obd_uuid *puuid;
1539 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1542 ¶m.fp_obd_uuid[param.fp_num_obds++];
1544 p = strchr(token, ',');
1551 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1556 strncpy(puuid->uuid, token,
1557 sizeof(puuid->uuid));
1565 param.fp_zero_end = 1;
1570 if (optarg[0] == '+') {
1571 param.fp_size_sign = -1;
1573 } else if (optarg[0] == '-') {
1574 param.fp_size_sign = 1;
1578 ret = llapi_parse_size(optarg, ¶m.fp_size,
1579 ¶m.fp_size_units, 0);
1581 fprintf(stderr, "error: bad file size '%s'\n",
1585 param.fp_check_size = 1;
1586 param.fp_exclude_size = !!neg_opt;
1589 if (optarg[0] == '+') {
1590 param.fp_stripe_size_sign = -1;
1592 } else if (optarg[0] == '-') {
1593 param.fp_stripe_size_sign = 1;
1597 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1598 ¶m.fp_stripe_size_units, 0);
1600 fprintf(stderr, "error: bad stripe_size '%s'\n",
1604 param.fp_check_stripe_size = 1;
1605 param.fp_exclude_stripe_size = !!neg_opt;
1608 param.fp_exclude_type = !!neg_opt;
1609 switch (optarg[0]) {
1611 param.fp_type = S_IFBLK;
1614 param.fp_type = S_IFCHR;
1617 param.fp_type = S_IFDIR;
1620 param.fp_type = S_IFREG;
1623 param.fp_type = S_IFLNK;
1626 param.fp_type = S_IFIFO;
1629 param.fp_type = S_IFSOCK;
1632 fprintf(stderr, "error: %s: bad type '%s'\n",
1644 if (pathstart == -1) {
1645 fprintf(stderr, "error: %s: no filename|pathname\n",
1649 } else if (pathend == -1) {
1655 rc = llapi_find(argv[pathstart], ¶m);
1656 if (rc != 0 && ret == 0)
1658 } while (++pathstart < pathend);
1661 fprintf(stderr, "error: %s failed for %s.\n",
1662 argv[0], argv[optind - 1]);
1664 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1665 free(param.fp_obd_uuid);
1667 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1668 free(param.fp_mdt_uuid);
1673 static int lfs_getstripe_internal(int argc, char **argv,
1674 struct find_param *param)
1676 struct option long_opts[] = {
1677 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1678 /* This formerly implied "stripe-count", but was explicitly
1679 * made "stripe-count" for consistency with other options,
1680 * and to separate it from "mdt-count" when DNE arrives. */
1681 {"count", no_argument, 0, 'c'},
1683 {"stripe-count", no_argument, 0, 'c'},
1684 {"stripe_count", no_argument, 0, 'c'},
1685 {"directory", no_argument, 0, 'd'},
1686 {"default", no_argument, 0, 'D'},
1687 {"generation", no_argument, 0, 'g'},
1688 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1689 /* This formerly implied "stripe-index", but was explicitly
1690 * made "stripe-index" for consistency with other options,
1691 * and to separate it from "mdt-index" when DNE arrives. */
1692 {"index", no_argument, 0, 'i'},
1694 {"stripe-index", no_argument, 0, 'i'},
1695 {"stripe_index", no_argument, 0, 'i'},
1696 {"layout", no_argument, 0, 'L'},
1697 {"mdt-index", no_argument, 0, 'M'},
1698 {"mdt_index", no_argument, 0, 'M'},
1699 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1700 /* This formerly implied "stripe-index", but was confusing
1701 * with "file offset" (which will eventually be needed for
1702 * with different layouts by offset), so deprecate it. */
1703 {"offset", no_argument, 0, 'o'},
1705 {"obd", required_argument, 0, 'O'},
1706 {"ost", required_argument, 0, 'O'},
1707 {"pool", no_argument, 0, 'p'},
1708 {"quiet", no_argument, 0, 'q'},
1709 {"recursive", no_argument, 0, 'r'},
1710 {"raw", no_argument, 0, 'R'},
1711 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1712 /* This formerly implied "--stripe-size", but was confusing
1713 * with "lfs find --size|-s", which means "file size", so use
1714 * the consistent "--stripe-size|-S" for all commands. */
1715 {"size", no_argument, 0, 's'},
1717 {"stripe-size", no_argument, 0, 'S'},
1718 {"stripe_size", no_argument, 0, 'S'},
1719 {"verbose", no_argument, 0, 'v'},
1724 param->fp_max_depth = 1;
1725 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1726 long_opts, NULL)) != -1) {
1729 if (param->fp_obd_uuid) {
1731 "error: %s: only one obduuid allowed",
1735 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1741 param->fp_max_depth = 0;
1744 param->fp_get_default_lmv = 1;
1747 param->fp_recursive = 1;
1750 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1753 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1754 if (strcmp(argv[optind - 1], "--count") == 0)
1755 fprintf(stderr, "warning: '--count' deprecated,"
1756 " use '--stripe-count' instead\n");
1758 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1759 param->fp_verbose |= VERBOSE_COUNT;
1760 param->fp_max_depth = 0;
1763 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1765 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1766 fprintf(stderr, "warning: '--size|-s' deprecated, "
1767 "use '--stripe-size|-S' instead\n");
1769 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1771 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1772 param->fp_verbose |= VERBOSE_SIZE;
1773 param->fp_max_depth = 0;
1776 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1778 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1779 "use '--stripe-index|-i' instead\n");
1782 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1783 if (strcmp(argv[optind - 1], "--index") == 0)
1784 fprintf(stderr, "warning: '--index' deprecated"
1785 ", use '--stripe-index' instead\n");
1787 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1788 param->fp_verbose |= VERBOSE_OFFSET;
1789 param->fp_max_depth = 0;
1793 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1794 param->fp_verbose |= VERBOSE_POOL;
1795 param->fp_max_depth = 0;
1799 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1800 param->fp_verbose |= VERBOSE_GENERATION;
1801 param->fp_max_depth = 0;
1805 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1806 param->fp_verbose |= VERBOSE_LAYOUT;
1807 param->fp_max_depth = 0;
1811 if (!(param->fp_verbose & VERBOSE_DETAIL))
1812 param->fp_max_depth = 0;
1813 param->fp_verbose |= VERBOSE_MDTINDEX;
1826 if (param->fp_recursive)
1827 param->fp_max_depth = -1;
1829 if (!param->fp_verbose)
1830 param->fp_verbose = VERBOSE_ALL;
1831 if (param->fp_quiet)
1832 param->fp_verbose = VERBOSE_OBJID;
1835 rc = llapi_getstripe(argv[optind], param);
1836 } while (++optind < argc && !rc);
1839 fprintf(stderr, "error: %s failed for %s.\n",
1840 argv[0], argv[optind - 1]);
1844 static int lfs_tgts(int argc, char **argv)
1846 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1847 struct find_param param;
1848 int index = 0, rc=0;
1853 if (argc == 2 && !realpath(argv[1], path)) {
1855 fprintf(stderr, "error: invalid path '%s': %s\n",
1856 argv[1], strerror(-rc));
1860 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1861 /* Check if we have a mount point */
1862 if (mntdir[0] == '\0')
1865 memset(¶m, 0, sizeof(param));
1866 if (!strcmp(argv[0], "mdts"))
1867 param.fp_get_lmv = 1;
1869 rc = llapi_ostlist(mntdir, ¶m);
1871 fprintf(stderr, "error: %s: failed on %s\n",
1874 if (path[0] != '\0')
1876 memset(mntdir, 0, PATH_MAX);
1882 static int lfs_getstripe(int argc, char **argv)
1884 struct find_param param = { 0 };
1885 return lfs_getstripe_internal(argc, argv, ¶m);
1889 static int lfs_getdirstripe(int argc, char **argv)
1891 struct find_param param = { 0 };
1893 param.fp_get_lmv = 1;
1894 return lfs_getstripe_internal(argc, argv, ¶m);
1898 static int lfs_setdirstripe(int argc, char **argv)
1902 unsigned int stripe_offset = -1;
1903 unsigned int stripe_count = 1;
1904 enum lmv_hash_type hash_type;
1907 char *stripe_offset_opt = NULL;
1908 char *stripe_count_opt = NULL;
1909 char *stripe_hash_opt = NULL;
1910 char *mode_opt = NULL;
1911 bool default_stripe = false;
1912 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1913 mode_t previous_mode = 0;
1914 bool delete = false;
1916 struct option long_opts[] = {
1917 {"count", required_argument, 0, 'c'},
1918 {"delete", no_argument, 0, 'd'},
1919 {"index", required_argument, 0, 'i'},
1920 {"mode", required_argument, 0, 'm'},
1921 {"hash-type", required_argument, 0, 't'},
1922 {"default_stripe", no_argument, 0, 'D'},
1926 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1933 stripe_count_opt = optarg;
1937 default_stripe = true;
1940 default_stripe = true;
1943 stripe_offset_opt = optarg;
1949 stripe_hash_opt = optarg;
1952 fprintf(stderr, "error: %s: option '%s' "
1954 argv[0], argv[optind - 1]);
1959 if (optind == argc) {
1960 fprintf(stderr, "error: %s: missing dirname\n",
1965 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1966 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1971 if (stripe_offset_opt != NULL) {
1972 /* get the stripe offset */
1973 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1975 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1976 argv[0], stripe_offset_opt);
1982 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1983 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1984 " or -i options.\n", argv[0]);
1992 if (mode_opt != NULL) {
1993 mode = strtoul(mode_opt, &end, 8);
1995 fprintf(stderr, "error: %s: bad mode '%s'\n",
1999 previous_mode = umask(0);
2002 if (stripe_hash_opt == NULL ||
2003 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2004 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2005 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2006 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2008 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2009 argv[0], stripe_hash_opt);
2013 /* get the stripe count */
2014 if (stripe_count_opt != NULL) {
2015 stripe_count = strtoul(stripe_count_opt, &end, 0);
2017 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2018 argv[0], stripe_count_opt);
2023 dname = argv[optind];
2025 if (default_stripe) {
2026 result = llapi_dir_set_default_lmv_stripe(dname,
2027 stripe_offset, stripe_count,
2030 result = llapi_dir_create_pool(dname, mode,
2032 stripe_count, hash_type,
2037 fprintf(stderr, "error: %s: create stripe dir '%s' "
2038 "failed\n", argv[0], dname);
2041 dname = argv[++optind];
2042 } while (dname != NULL);
2044 if (mode_opt != NULL)
2045 umask(previous_mode);
2051 static int lfs_rmentry(int argc, char **argv)
2058 fprintf(stderr, "error: %s: missing dirname\n",
2064 dname = argv[index];
2065 while (dname != NULL) {
2066 result = llapi_direntry_remove(dname);
2068 fprintf(stderr, "error: %s: remove dir entry '%s' "
2069 "failed\n", argv[0], dname);
2072 dname = argv[++index];
2077 static int lfs_mv(int argc, char **argv)
2079 struct find_param param = {
2086 struct option long_opts[] = {
2087 {"mdt-index", required_argument, 0, 'M'},
2088 {"verbose", no_argument, 0, 'v'},
2092 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2095 param.fp_mdt_index = strtoul(optarg, &end, 0);
2097 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2104 param.fp_verbose = VERBOSE_DETAIL;
2108 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2109 argv[0], argv[optind - 1]);
2114 if (param.fp_mdt_index == -1) {
2115 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2119 if (optind >= argc) {
2120 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2124 param.fp_migrate = 1;
2125 rc = llapi_migrate_mdt(argv[optind], ¶m);
2127 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2128 argv[0], argv[optind], param.fp_mdt_index,
2133 static int lfs_osts(int argc, char **argv)
2135 return lfs_tgts(argc, argv);
2138 static int lfs_mdts(int argc, char **argv)
2140 return lfs_tgts(argc, argv);
2143 #define COOK(value) \
2146 while (value > 1024) { \
2154 #define CDF "%11llu"
2155 #define HDF "%8.1f%c"
2159 static int showdf(char *mntdir, struct obd_statfs *stat,
2160 char *uuid, int ishow, int cooked,
2161 char *type, int index, int rc)
2163 long long avail, used, total;
2165 char *suffix = "KMGTPEZY";
2166 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2167 char tbuf[3 * sizeof(__u64)];
2168 char ubuf[3 * sizeof(__u64)];
2169 char abuf[3 * sizeof(__u64)];
2170 char rbuf[3 * sizeof(__u64)];
2178 avail = stat->os_ffree;
2179 used = stat->os_files - stat->os_ffree;
2180 total = stat->os_files;
2182 int shift = cooked ? 0 : 10;
2184 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2185 used = ((stat->os_blocks - stat->os_bfree) *
2186 stat->os_bsize) >> shift;
2187 total = (stat->os_blocks * stat->os_bsize) >> shift;
2190 if ((used + avail) > 0)
2191 ratio = (double)used / (double)(used + avail);
2197 cook_val = (double)total;
2200 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2202 sprintf(tbuf, CDF, total);
2204 cook_val = (double)used;
2207 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2209 sprintf(ubuf, CDF, used);
2211 cook_val = (double)avail;
2214 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2216 sprintf(abuf, CDF, avail);
2218 sprintf(tbuf, CDF, total);
2219 sprintf(ubuf, CDF, used);
2220 sprintf(abuf, CDF, avail);
2223 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2224 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2225 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2227 printf("[%s:%d]\n", type, index);
2233 printf(UUF": inactive device\n", uuid);
2236 printf(UUF": %s\n", uuid, strerror(-rc));
2243 struct ll_stat_type {
2248 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2249 int cooked, int lazy)
2251 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2252 struct obd_uuid uuid_buf;
2253 char *poolname = NULL;
2254 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2255 { LL_STATFS_LOV, "OST" },
2257 struct ll_stat_type *tp;
2258 __u64 ost_ffree = 0;
2264 poolname = strchr(pool, '.');
2265 if (poolname != NULL) {
2266 if (strncmp(fsname, pool, strlen(fsname))) {
2267 fprintf(stderr, "filesystem name incorrect\n");
2276 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2277 "UUID", "Inodes", "IUsed", "IFree",
2278 "IUse%", "Mounted on");
2280 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2281 "UUID", cooked ? "bytes" : "1K-blocks",
2282 "Used", "Available", "Use%", "Mounted on");
2284 for (tp = types; tp->st_name != NULL; tp++) {
2285 for (index = 0; ; index++) {
2286 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2287 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2288 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2289 rc = llapi_obd_statfs(mntdir, type, index,
2290 &stat_buf, &uuid_buf);
2297 if (poolname && tp->st_op == LL_STATFS_LOV &&
2298 llapi_search_ost(fsname, poolname,
2299 obd_uuid2str(&uuid_buf)) != 1)
2302 /* the llapi_obd_statfs() call may have returned with
2303 * an error, but if it filled in uuid_buf we will at
2304 * lease use that to print out a message for that OBD.
2305 * If we didn't get anything in the uuid_buf, then fill
2306 * it in so that we can print an error message. */
2307 if (uuid_buf.uuid[0] == '\0')
2308 sprintf(uuid_buf.uuid, "%s%04x",
2309 tp->st_name, index);
2310 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2311 ishow, cooked, tp->st_name, index, rc);
2314 if (tp->st_op == LL_STATFS_LMV) {
2315 sum.os_ffree += stat_buf.os_ffree;
2316 sum.os_files += stat_buf.os_files;
2317 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2318 sum.os_blocks += stat_buf.os_blocks *
2320 sum.os_bfree += stat_buf.os_bfree *
2322 sum.os_bavail += stat_buf.os_bavail *
2324 ost_ffree += stat_buf.os_ffree;
2326 } else if (rc == -EINVAL || rc == -EFAULT) {
2332 /* If we don't have as many objects free on the OST as inodes
2333 * on the MDS, we reduce the total number of inodes to
2334 * compensate, so that the "inodes in use" number is correct.
2335 * Matches ll_statfs_internal() so the results are consistent. */
2336 if (ost_ffree < sum.os_ffree) {
2337 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2338 sum.os_ffree = ost_ffree;
2341 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2346 static int lfs_df(int argc, char **argv)
2348 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2349 int ishow = 0, cooked = 0;
2351 int c, rc = 0, index = 0;
2352 char fsname[PATH_MAX] = "", *pool_name = NULL;
2353 struct option long_opts[] = {
2354 {"pool", required_argument, 0, 'p'},
2355 {"lazy", 0, 0, 'l'},
2359 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2377 if (optind < argc && !realpath(argv[optind], path)) {
2379 fprintf(stderr, "error: invalid path '%s': %s\n",
2380 argv[optind], strerror(-rc));
2384 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2385 /* Check if we have a mount point */
2386 if (mntdir[0] == '\0')
2389 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2390 if (rc || path[0] != '\0')
2392 fsname[0] = '\0'; /* avoid matching in next loop */
2393 mntdir[0] = '\0'; /* avoid matching in next loop */
2399 static int lfs_getname(int argc, char **argv)
2401 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2402 int rc = 0, index = 0, c;
2403 char buf[sizeof(struct obd_uuid)];
2405 while ((c = getopt(argc, argv, "h")) != -1)
2408 if (optind == argc) { /* no paths specified, get all paths. */
2409 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2410 rc = llapi_getname(mntdir, buf, sizeof(buf));
2413 "cannot get name for `%s': %s\n",
2414 mntdir, strerror(-rc));
2418 printf("%s %s\n", buf, mntdir);
2420 path[0] = fsname[0] = mntdir[0] = 0;
2422 } else { /* paths specified, only attempt to search these. */
2423 for (; optind < argc; optind++) {
2424 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2427 "cannot get name for `%s': %s\n",
2428 argv[optind], strerror(-rc));
2432 printf("%s %s\n", buf, argv[optind]);
2438 static int lfs_check(int argc, char **argv)
2441 char mntdir[PATH_MAX] = {'\0'};
2450 obd_types[0] = obd_type1;
2451 obd_types[1] = obd_type2;
2453 if (strcmp(argv[1], "osts") == 0) {
2454 strcpy(obd_types[0], "osc");
2455 } else if (strcmp(argv[1], "mds") == 0) {
2456 strcpy(obd_types[0], "mdc");
2457 } else if (strcmp(argv[1], "servers") == 0) {
2459 strcpy(obd_types[0], "osc");
2460 strcpy(obd_types[1], "mdc");
2462 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2467 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2468 if (rc < 0 || mntdir[0] == '\0') {
2469 fprintf(stderr, "No suitable Lustre mount found\n");
2473 rc = llapi_target_check(num_types, obd_types, mntdir);
2475 fprintf(stderr, "error: %s: %s status failed\n",
2482 static int lfs_join(int argc, char **argv)
2484 fprintf(stderr, "join two lustre files into one.\n"
2485 "obsolete, HEAD does not support it anymore.\n");
2489 #ifdef HAVE_SYS_QUOTA_H
2490 #define ARG2INT(nr, str, msg) \
2493 nr = strtol(str, &endp, 0); \
2495 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2500 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2502 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2503 * returns the value or ULONG_MAX on integer overflow or incorrect format
2505 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2506 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2507 * 3. empty integer value is interpreted as 0
2509 static unsigned long str2sec(const char* timestr)
2511 const char spec[] = "smhdw";
2512 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2513 unsigned long val = 0;
2516 if (strpbrk(timestr, spec) == NULL) {
2517 /* no specifiers inside the time string,
2518 should treat it as an integer value */
2519 val = strtoul(timestr, &tail, 10);
2520 return *tail ? ULONG_MAX : val;
2523 /* format string is XXwXXdXXhXXmXXs */
2529 v = strtoul(timestr, &tail, 10);
2530 if (v == ULONG_MAX || *tail == '\0')
2531 /* value too large (ULONG_MAX or more)
2532 or missing specifier */
2535 ptr = strchr(spec, *tail);
2537 /* unknown specifier */
2542 /* check if product will overflow the type */
2543 if (!(v < ULONG_MAX / mult[ind]))
2546 ADD_OVERFLOW(val, mult[ind] * v);
2547 if (val == ULONG_MAX)
2559 #define ARG2ULL(nr, str, def_units) \
2561 unsigned long long limit, units = def_units; \
2564 rc = llapi_parse_size(str, &limit, &units, 1); \
2566 fprintf(stderr, "error: bad limit value %s\n", str); \
2572 static inline int has_times_option(int argc, char **argv)
2576 for (i = 1; i < argc; i++)
2577 if (!strcmp(argv[i], "-t"))
2583 int lfs_setquota_times(int argc, char **argv)
2586 struct if_quotactl qctl;
2587 char *mnt, *obd_type = (char *)qctl.obd_type;
2588 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2589 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2590 struct option long_opts[] = {
2591 {"block-grace", required_argument, 0, 'b'},
2592 {"group", no_argument, 0, 'g'},
2593 {"inode-grace", required_argument, 0, 'i'},
2594 {"times", no_argument, 0, 't'},
2595 {"user", no_argument, 0, 'u'},
2599 memset(&qctl, 0, sizeof(qctl));
2600 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2601 qctl.qc_type = UGQUOTA;
2603 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2607 if (qctl.qc_type != UGQUOTA) {
2608 fprintf(stderr, "error: -u and -g can't be used "
2609 "more than once\n");
2612 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2615 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2616 fprintf(stderr, "error: bad block-grace: %s\n",
2620 dqb->dqb_valid |= QIF_BTIME;
2623 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2624 fprintf(stderr, "error: bad inode-grace: %s\n",
2628 dqb->dqb_valid |= QIF_ITIME;
2630 case 't': /* Yes, of course! */
2632 default: /* getopt prints error message for us when opterr != 0 */
2637 if (qctl.qc_type == UGQUOTA) {
2638 fprintf(stderr, "error: neither -u nor -g specified\n");
2642 if (optind != argc - 1) {
2643 fprintf(stderr, "error: unexpected parameters encountered\n");
2648 rc = llapi_quotactl(mnt, &qctl);
2651 fprintf(stderr, "%s %s ", obd_type,
2652 obd_uuid2str(&qctl.obd_uuid));
2653 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2660 #define BSLIMIT (1 << 0)
2661 #define BHLIMIT (1 << 1)
2662 #define ISLIMIT (1 << 2)
2663 #define IHLIMIT (1 << 3)
2665 int lfs_setquota(int argc, char **argv)
2668 struct if_quotactl qctl;
2669 char *mnt, *obd_type = (char *)qctl.obd_type;
2670 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2671 struct option long_opts[] = {
2672 {"block-softlimit", required_argument, 0, 'b'},
2673 {"block-hardlimit", required_argument, 0, 'B'},
2674 {"group", required_argument, 0, 'g'},
2675 {"inode-softlimit", required_argument, 0, 'i'},
2676 {"inode-hardlimit", required_argument, 0, 'I'},
2677 {"user", required_argument, 0, 'u'},
2680 unsigned limit_mask = 0;
2683 if (has_times_option(argc, argv))
2684 return lfs_setquota_times(argc, argv);
2686 memset(&qctl, 0, sizeof(qctl));
2687 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2688 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2689 * so it can be used as a marker that qc_type
2690 * isn't reinitialized from command line */
2692 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2696 if (qctl.qc_type != UGQUOTA) {
2697 fprintf(stderr, "error: -u and -g can't be used"
2698 " more than once\n");
2701 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2702 rc = name2id(&qctl.qc_id, optarg,
2703 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2705 qctl.qc_id = strtoul(optarg, &endptr, 10);
2706 if (*endptr != '\0') {
2707 fprintf(stderr, "error: can't find id "
2708 "for name %s\n", optarg);
2714 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2715 dqb->dqb_bsoftlimit >>= 10;
2716 limit_mask |= BSLIMIT;
2717 if (dqb->dqb_bsoftlimit &&
2718 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2719 fprintf(stderr, "warning: block softlimit is "
2720 "smaller than the miminal qunit size, "
2721 "please see the help of setquota or "
2722 "Lustre manual for details.\n");
2725 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2726 dqb->dqb_bhardlimit >>= 10;
2727 limit_mask |= BHLIMIT;
2728 if (dqb->dqb_bhardlimit &&
2729 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2730 fprintf(stderr, "warning: block hardlimit is "
2731 "smaller than the miminal qunit size, "
2732 "please see the help of setquota or "
2733 "Lustre manual for details.\n");
2736 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2737 limit_mask |= ISLIMIT;
2738 if (dqb->dqb_isoftlimit &&
2739 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2740 fprintf(stderr, "warning: inode softlimit is "
2741 "smaller than the miminal qunit size, "
2742 "please see the help of setquota or "
2743 "Lustre manual for details.\n");
2746 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2747 limit_mask |= IHLIMIT;
2748 if (dqb->dqb_ihardlimit &&
2749 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2750 fprintf(stderr, "warning: inode hardlimit is "
2751 "smaller than the miminal qunit size, "
2752 "please see the help of setquota or "
2753 "Lustre manual for details.\n");
2755 default: /* getopt prints error message for us when opterr != 0 */
2760 if (qctl.qc_type == UGQUOTA) {
2761 fprintf(stderr, "error: neither -u nor -g was specified\n");
2765 if (limit_mask == 0) {
2766 fprintf(stderr, "error: at least one limit must be specified\n");
2770 if (optind != argc - 1) {
2771 fprintf(stderr, "error: unexpected parameters encountered\n");
2777 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2778 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2779 /* sigh, we can't just set blimits/ilimits */
2780 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2781 .qc_type = qctl.qc_type,
2782 .qc_id = qctl.qc_id};
2784 rc = llapi_quotactl(mnt, &tmp_qctl);
2786 fprintf(stderr, "error: setquota failed while retrieving"
2787 " current quota settings (%s)\n",
2792 if (!(limit_mask & BHLIMIT))
2793 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2794 if (!(limit_mask & BSLIMIT))
2795 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2796 if (!(limit_mask & IHLIMIT))
2797 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2798 if (!(limit_mask & ISLIMIT))
2799 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2801 /* Keep grace times if we have got no softlimit arguments */
2802 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2803 dqb->dqb_valid |= QIF_BTIME;
2804 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2807 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2808 dqb->dqb_valid |= QIF_ITIME;
2809 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2813 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2814 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2816 rc = llapi_quotactl(mnt, &qctl);
2819 fprintf(stderr, "%s %s ", obd_type,
2820 obd_uuid2str(&qctl.obd_uuid));
2821 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2828 static inline char *type2name(int check_type)
2830 if (check_type == USRQUOTA)
2832 else if (check_type == GRPQUOTA)
2838 /* Converts seconds value into format string
2839 * result is returned in buf
2841 * 1. result is in descenting order: 1w2d3h4m5s
2842 * 2. zero fields are not filled (except for p. 3): 5d1s
2843 * 3. zero seconds value is presented as "0s"
2845 static char * __sec2str(time_t seconds, char *buf)
2847 const char spec[] = "smhdw";
2848 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2853 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2854 c = seconds / mult[i];
2856 if (c > 0 || (i == 0 && buf == tail))
2857 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2865 static void sec2str(time_t seconds, char *buf, int rc)
2872 tail = __sec2str(seconds, tail);
2874 if (rc && tail - buf < 39) {
2880 static void diff2str(time_t seconds, char *buf, time_t now)
2886 if (seconds <= now) {
2887 strcpy(buf, "none");
2890 __sec2str(seconds - now, buf);
2893 static void print_quota_title(char *name, struct if_quotactl *qctl,
2894 bool human_readable)
2896 printf("Disk quotas for %s %s (%cid %u):\n",
2897 type2name(qctl->qc_type), name,
2898 *type2name(qctl->qc_type), qctl->qc_id);
2899 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2900 "Filesystem", human_readable ? "used" : "kbytes",
2901 "quota", "limit", "grace",
2902 "files", "quota", "limit", "grace");
2905 static void kbytes2str(__u64 num, char *buf, bool h)
2908 sprintf(buf, LPU64, num);
2911 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2913 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2915 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2917 sprintf(buf, LPU64"%s", num, "k");
2921 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2928 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2929 int bover = 0, iover = 0;
2930 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2935 if (dqb->dqb_bhardlimit &&
2936 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2938 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2939 if (dqb->dqb_btime > now) {
2946 if (dqb->dqb_ihardlimit &&
2947 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2949 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2950 if (dqb->dqb_itime > now) {
2958 if (strlen(mnt) > 15)
2959 printf("%s\n%15s", mnt, "");
2961 printf("%15s", mnt);
2964 diff2str(dqb->dqb_btime, timebuf, now);
2966 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2967 if (rc == -EREMOTEIO)
2968 sprintf(numbuf[0], "%s*", strbuf);
2970 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2971 "%s" : "[%s]", strbuf);
2973 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2974 if (type == QC_GENERAL)
2975 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2976 "%s" : "[%s]", strbuf);
2978 sprintf(numbuf[1], "%s", "-");
2980 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2981 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2982 "%s" : "[%s]", strbuf);
2984 printf(" %7s%c %6s %7s %7s",
2985 numbuf[0], bover ? '*' : ' ', numbuf[1],
2986 numbuf[2], bover > 1 ? timebuf : "-");
2989 diff2str(dqb->dqb_itime, timebuf, now);
2991 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2992 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2994 if (type == QC_GENERAL)
2995 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2996 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2998 sprintf(numbuf[1], "%s", "-");
3000 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3001 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
3003 if (type != QC_OSTIDX)
3004 printf(" %7s%c %6s %7s %7s",
3005 numbuf[0], iover ? '*' : ' ', numbuf[1],
3006 numbuf[2], iover > 1 ? timebuf : "-");
3008 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3011 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3012 qctl->qc_cmd == Q_GETOINFO) {
3016 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3017 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3018 printf("Block grace time: %s; Inode grace time: %s\n",
3019 bgtimebuf, igtimebuf);
3023 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3024 bool h, __u64 *total)
3026 int rc = 0, rc1 = 0, count = 0;
3027 __u32 valid = qctl->qc_valid;
3029 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3031 fprintf(stderr, "can not get %s count: %s\n",
3032 is_mdt ? "mdt": "ost", strerror(-rc));
3036 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3037 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3038 rc = llapi_quotactl(mnt, qctl);
3040 /* It is remote client case. */
3041 if (-rc == EOPNOTSUPP) {
3048 fprintf(stderr, "quotactl %s%d failed.\n",
3049 is_mdt ? "mdt": "ost", qctl->qc_idx);
3053 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3054 qctl->qc_valid, 0, h);
3055 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3056 qctl->qc_dqblk.dqb_bhardlimit;
3059 qctl->qc_valid = valid;
3063 static int lfs_quota(int argc, char **argv)
3066 char *mnt, *name = NULL;
3067 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3068 .qc_type = UGQUOTA };
3069 char *obd_type = (char *)qctl.obd_type;
3070 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3071 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3072 verbose = 0, pass = 0, quiet = 0, inacc;
3074 __u32 valid = QC_GENERAL, idx = 0;
3075 __u64 total_ialloc = 0, total_balloc = 0;
3076 bool human_readable = false;
3078 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3081 if (qctl.qc_type != UGQUOTA) {
3082 fprintf(stderr, "error: use either -u or -g\n");
3085 qctl.qc_type = USRQUOTA;
3088 if (qctl.qc_type != UGQUOTA) {
3089 fprintf(stderr, "error: use either -u or -g\n");
3092 qctl.qc_type = GRPQUOTA;
3095 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3098 valid = qctl.qc_valid = QC_UUID;
3099 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3102 valid = qctl.qc_valid = QC_MDTIDX;
3103 idx = qctl.qc_idx = atoi(optarg);
3106 valid = qctl.qc_valid = QC_OSTIDX;
3107 idx = qctl.qc_idx = atoi(optarg);
3116 human_readable = true;
3119 fprintf(stderr, "error: %s: option '-%c' "
3120 "unrecognized\n", argv[0], c);
3125 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3126 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3127 optind == argc - 1) {
3129 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3130 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3131 qctl.qc_valid = valid;
3134 qctl.qc_type = USRQUOTA;
3135 qctl.qc_id = geteuid();
3137 qctl.qc_type = GRPQUOTA;
3138 qctl.qc_id = getegid();
3140 rc = id2name(&name, qctl.qc_id,
3141 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3144 /* lfs quota -u username /path/to/lustre/mount */
3145 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3146 /* options should be followed by u/g-name and mntpoint */
3147 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3148 fprintf(stderr, "error: missing quota argument(s)\n");
3152 name = argv[optind++];
3153 rc = name2id(&qctl.qc_id, name,
3154 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3156 qctl.qc_id = strtoul(name, &endptr, 10);
3157 if (*endptr != '\0') {
3158 fprintf(stderr, "error: can't find id for name "
3163 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3164 fprintf(stderr, "error: missing quota info argument(s)\n");
3170 rc1 = llapi_quotactl(mnt, &qctl);
3174 fprintf(stderr, "%s quotas are not enabled.\n",
3175 qctl.qc_type == USRQUOTA ? "user" : "group");
3178 fprintf(stderr, "Permission denied.\n");
3180 /* We already got a "No such file..." message. */
3183 fprintf(stderr, "Unexpected quotactl error: %s\n",
3188 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3189 print_quota_title(name, &qctl, human_readable);
3191 if (rc1 && *obd_type)
3192 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3194 if (qctl.qc_valid != QC_GENERAL)
3197 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3198 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3199 (QIF_LIMITS|QIF_USAGE));
3201 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3203 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3207 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3209 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3211 kbytes2str(total_balloc, strbuf, human_readable);
3212 printf("Total allocated inode limit: "LPU64", total "
3213 "allocated block limit: %s\n", total_ialloc, strbuf);
3216 if (rc1 || rc2 || rc3 || inacc)
3217 printf("Some errors happened when getting quota info. "
3218 "Some devices may be not working or deactivated. "
3219 "The data in \"[]\" is inaccurate.\n");
3227 #endif /* HAVE_SYS_QUOTA_H! */
3229 static int flushctx_ioctl(char *mp)
3233 fd = open(mp, O_RDONLY);
3235 fprintf(stderr, "flushctx: error open %s: %s\n",
3236 mp, strerror(errno));
3240 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3242 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3243 mp, strerror(errno));
3249 static int lfs_flushctx(int argc, char **argv)
3251 int kdestroy = 0, c;
3252 char mntdir[PATH_MAX] = {'\0'};
3256 while ((c = getopt(argc, argv, "k")) != -1) {
3262 fprintf(stderr, "error: %s: option '-%c' "
3263 "unrecognized\n", argv[0], c);
3269 if ((rc = system("kdestroy > /dev/null")) != 0) {
3270 rc = WEXITSTATUS(rc);
3271 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3275 if (optind >= argc) {
3276 /* flush for all mounted lustre fs. */
3277 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3278 /* Check if we have a mount point */
3279 if (mntdir[0] == '\0')
3282 if (flushctx_ioctl(mntdir))
3285 mntdir[0] = '\0'; /* avoid matching in next loop */
3288 /* flush fs as specified */
3289 while (optind < argc) {
3290 if (flushctx_ioctl(argv[optind++]))
3297 static int lfs_lsetfacl(int argc, char **argv)
3300 return(llapi_lsetfacl(argc, argv));
3303 static int lfs_lgetfacl(int argc, char **argv)
3306 return(llapi_lgetfacl(argc, argv));
3309 static int lfs_rsetfacl(int argc, char **argv)
3312 return(llapi_rsetfacl(argc, argv));
3315 static int lfs_rgetfacl(int argc, char **argv)
3318 return(llapi_rgetfacl(argc, argv));
3321 static int lfs_cp(int argc, char **argv)
3323 return(llapi_cp(argc, argv));
3326 static int lfs_ls(int argc, char **argv)
3328 return(llapi_ls(argc, argv));
3331 static int lfs_changelog(int argc, char **argv)
3333 void *changelog_priv;
3334 struct changelog_rec *rec;
3335 long long startrec = 0, endrec = 0;
3337 struct option long_opts[] = {
3338 {"follow", no_argument, 0, 'f'},
3341 char short_opts[] = "f";
3344 while ((rc = getopt_long(argc, argv, short_opts,
3345 long_opts, NULL)) != -1) {
3353 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3354 argv[0], argv[optind - 1]);
3361 mdd = argv[optind++];
3363 startrec = strtoll(argv[optind++], NULL, 10);
3365 endrec = strtoll(argv[optind++], NULL, 10);
3367 rc = llapi_changelog_start(&changelog_priv,
3368 CHANGELOG_FLAG_BLOCK |
3369 CHANGELOG_FLAG_JOBID |
3370 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3373 fprintf(stderr, "Can't start changelog: %s\n",
3374 strerror(errno = -rc));
3378 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3382 if (endrec && rec->cr_index > endrec) {
3383 llapi_changelog_free(&rec);
3386 if (rec->cr_index < startrec) {
3387 llapi_changelog_free(&rec);
3391 secs = rec->cr_time >> 30;
3392 gmtime_r(&secs, &ts);
3393 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3394 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3395 changelog_type2str(rec->cr_type),
3396 ts.tm_hour, ts.tm_min, ts.tm_sec,
3397 (int)(rec->cr_time & ((1<<30) - 1)),
3398 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3399 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3401 if (rec->cr_flags & CLF_JOBID) {
3402 struct changelog_ext_jobid *jid =
3403 changelog_rec_jobid(rec);
3405 if (jid->cr_jobid[0] != '\0')
3406 printf(" j=%s", jid->cr_jobid);
3409 if (rec->cr_namelen)
3410 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3411 rec->cr_namelen, changelog_rec_name(rec));
3413 if (rec->cr_flags & CLF_RENAME) {
3414 struct changelog_ext_rename *rnm =
3415 changelog_rec_rename(rec);
3417 if (!fid_is_zero(&rnm->cr_sfid))
3418 printf(" s="DFID" sp="DFID" %.*s",
3419 PFID(&rnm->cr_sfid),
3420 PFID(&rnm->cr_spfid),
3421 (int)changelog_rec_snamelen(rec),
3422 changelog_rec_sname(rec));
3426 llapi_changelog_free(&rec);
3429 llapi_changelog_fini(&changelog_priv);
3432 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3434 return (rc == 1 ? 0 : rc);
3437 static int lfs_changelog_clear(int argc, char **argv)
3445 endrec = strtoll(argv[3], NULL, 10);
3447 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3449 fprintf(stderr, "%s error: %s\n", argv[0],
3450 strerror(errno = -rc));
3454 static int lfs_fid2path(int argc, char **argv)
3456 struct option long_opts[] = {
3457 {"cur", no_argument, 0, 'c'},
3458 {"link", required_argument, 0, 'l'},
3459 {"rec", required_argument, 0, 'r'},
3462 char short_opts[] = "cl:r:";
3463 char *device, *fid, *path;
3464 long long recno = -1;
3470 while ((rc = getopt_long(argc, argv, short_opts,
3471 long_opts, NULL)) != -1) {
3477 linkno = strtol(optarg, NULL, 10);
3480 recno = strtoll(optarg, NULL, 10);
3485 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3486 argv[0], argv[optind - 1]);
3494 device = argv[optind++];
3495 path = calloc(1, PATH_MAX);
3497 fprintf(stderr, "error: Not enough memory\n");
3502 while (optind < argc) {
3503 fid = argv[optind++];
3505 lnktmp = (linkno >= 0) ? linkno : 0;
3507 int oldtmp = lnktmp;
3508 long long rectmp = recno;
3510 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3513 fprintf(stderr, "%s: error on FID %s: %s\n",
3514 argv[0], fid, strerror(errno = -rc2));
3521 fprintf(stdout, "%lld ", rectmp);
3522 if (device[0] == '/') {
3523 fprintf(stdout, "%s", device);
3524 if (device[strlen(device) - 1] != '/')
3525 fprintf(stdout, "/");
3526 } else if (path[0] == '\0') {
3527 fprintf(stdout, "/");
3529 fprintf(stdout, "%s\n", path);
3532 /* specified linkno */
3534 if (oldtmp == lnktmp)
3544 static int lfs_path2fid(int argc, char **argv)
3546 struct option long_opts[] = {
3547 {"parents", no_argument, 0, 'p'},
3551 const char short_opts[] = "p";
3552 const char *sep = "";
3555 bool show_parents = false;
3557 while ((rc = getopt_long(argc, argv, short_opts,
3558 long_opts, NULL)) != -1) {
3561 show_parents = true;
3564 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3565 argv[0], argv[optind - 1]);
3570 if (optind > argc - 1)
3572 else if (optind < argc - 1)
3576 for (path = argv + optind; *path != NULL; path++) {
3578 if (!show_parents) {
3579 err = llapi_path2fid(*path, &fid);
3581 printf("%s%s"DFID"\n",
3582 *sep != '\0' ? *path : "", sep,
3585 char name[NAME_MAX + 1];
3586 unsigned int linkno = 0;
3588 while ((err = llapi_path2parent(*path, linkno, &fid,
3589 name, sizeof(name))) == 0) {
3590 if (*sep != '\0' && linkno == 0)
3591 printf("%s%s", *path, sep);
3593 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3598 /* err == -ENODATA is end-of-loop */
3599 if (linkno > 0 && err == -ENODATA) {
3606 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3607 argv[0], show_parents ? "parent " : "", *path,
3619 static int lfs_data_version(int argc, char **argv)
3626 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3631 while ((c = getopt(argc, argv, "nrw")) != -1) {
3634 data_version_flags = 0;
3637 data_version_flags |= LL_DV_RD_FLUSH;
3640 data_version_flags |= LL_DV_WR_FLUSH;
3649 path = argv[optind];
3650 fd = open(path, O_RDONLY);
3652 err(errno, "cannot open file %s", path);
3654 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3656 err(errno, "cannot get version for %s", path);
3658 printf(LPU64 "\n", data_version);
3664 static int lfs_hsm_state(int argc, char **argv)
3669 struct hsm_user_state hus;
3677 rc = llapi_hsm_state_get(path, &hus);
3679 fprintf(stderr, "can't get hsm state for %s: %s\n",
3680 path, strerror(errno = -rc));
3684 /* Display path name and status flags */
3685 printf("%s: (0x%08x)", path, hus.hus_states);
3687 if (hus.hus_states & HS_RELEASED)
3688 printf(" released");
3689 if (hus.hus_states & HS_EXISTS)
3691 if (hus.hus_states & HS_DIRTY)
3693 if (hus.hus_states & HS_ARCHIVED)
3694 printf(" archived");
3695 /* Display user-settable flags */
3696 if (hus.hus_states & HS_NORELEASE)
3697 printf(" never_release");
3698 if (hus.hus_states & HS_NOARCHIVE)
3699 printf(" never_archive");
3700 if (hus.hus_states & HS_LOST)
3701 printf(" lost_from_hsm");
3703 if (hus.hus_archive_id != 0)
3704 printf(", archive_id:%d", hus.hus_archive_id);
3707 } while (++i < argc);
3712 #define LFS_HSM_SET 0
3713 #define LFS_HSM_CLEAR 1
3716 * Generic function to set or clear HSM flags.
3717 * Used by hsm_set and hsm_clear.
3719 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3721 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3723 struct option long_opts[] = {
3724 {"lost", 0, 0, 'l'},
3725 {"norelease", 0, 0, 'r'},
3726 {"noarchive", 0, 0, 'a'},
3727 {"archived", 0, 0, 'A'},
3728 {"dirty", 0, 0, 'd'},
3729 {"exists", 0, 0, 'e'},
3732 char short_opts[] = "lraAde";
3740 while ((c = getopt_long(argc, argv, short_opts,
3741 long_opts, NULL)) != -1) {
3747 mask |= HS_NOARCHIVE;
3750 mask |= HS_ARCHIVED;
3753 mask |= HS_NORELEASE;
3764 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3765 argv[0], argv[optind - 1]);
3770 /* User should have specified a flag */
3774 while (optind < argc) {
3776 path = argv[optind];
3778 /* If mode == 0, this means we apply the mask. */
3779 if (mode == LFS_HSM_SET)
3780 rc = llapi_hsm_state_set(path, mask, 0, 0);
3782 rc = llapi_hsm_state_set(path, 0, mask, 0);
3785 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3786 path, strerror(errno = -rc));
3795 static int lfs_hsm_action(int argc, char **argv)
3800 struct hsm_current_action hca;
3801 struct hsm_extent he;
3802 enum hsm_user_action hua;
3803 enum hsm_progress_states hps;
3811 rc = llapi_hsm_current_action(path, &hca);
3813 fprintf(stderr, "can't get hsm action for %s: %s\n",
3814 path, strerror(errno = -rc));
3817 he = hca.hca_location;
3818 hua = hca.hca_action;
3819 hps = hca.hca_state;
3821 printf("%s: %s", path, hsm_user_action2name(hua));
3823 /* Skip file without action */
3824 if (hca.hca_action == HUA_NONE) {
3829 printf(" %s ", hsm_progress_state2name(hps));
3831 if ((hps == HPS_RUNNING) &&
3832 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3833 printf("(%llu bytes moved)\n",
3834 (unsigned long long)he.length);
3835 else if ((he.offset + he.length) == LUSTRE_EOF)
3836 printf("(from %llu to EOF)\n",
3837 (unsigned long long)he.offset);
3839 printf("(from %llu to %llu)\n",
3840 (unsigned long long)he.offset,
3841 (unsigned long long)(he.offset + he.length));
3843 } while (++i < argc);
3848 static int lfs_hsm_set(int argc, char **argv)
3850 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3853 static int lfs_hsm_clear(int argc, char **argv)
3855 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3859 * Check file state and return its fid, to be used by lfs_hsm_request().
3861 * \param[in] file Path to file to check
3862 * \param[in,out] fid Pointer to allocated lu_fid struct.
3863 * \param[in,out] last_dev Pointer to last device id used.
3865 * \return 0 on success.
3867 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3873 rc = lstat(file, &st);
3875 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3878 /* Checking for regular file as archiving as posix copytool
3879 * rejects archiving files other than regular files
3881 if (!S_ISREG(st.st_mode)) {
3882 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3885 /* A request should be ... */
3886 if (*last_dev != st.st_dev && *last_dev != 0) {
3887 fprintf(stderr, "All files should be "
3888 "on the same filesystem: %s\n", file);
3891 *last_dev = st.st_dev;
3893 rc = llapi_path2fid(file, fid);
3895 fprintf(stderr, "Cannot read FID of %s: %s\n",
3896 file, strerror(-rc));
3902 /* Fill an HSM HUR item with a given file name.
3904 * If mntpath is set, then the filename is actually a FID, and no
3905 * lookup on the filesystem will be performed.
3907 * \param[in] hur the user request to fill
3908 * \param[in] idx index of the item inside the HUR to fill
3909 * \param[in] mntpath mountpoint of Lustre
3910 * \param[in] fname filename (if mtnpath is NULL)
3911 * or FID (if mntpath is set)
3912 * \param[in] last_dev pointer to last device id used
3914 * \retval 0 on success
3915 * \retval CMD_HELP or a negative errno on error
3917 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3918 const char *mntpath, const char *fname,
3921 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3924 hui->hui_extent.length = -1;
3926 if (mntpath != NULL) {
3929 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3933 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3938 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3942 hur->hur_request.hr_itemcount++;
3947 static int lfs_hsm_request(int argc, char **argv, int action)
3949 struct option long_opts[] = {
3950 {"filelist", 1, 0, 'l'},
3951 {"data", 1, 0, 'D'},
3952 {"archive", 1, 0, 'a'},
3953 {"mntpath", 1, 0, 'm'},
3957 char short_opts[] = "l:D:a:m:";
3958 struct hsm_user_request *hur, *oldhur;
3963 char *filelist = NULL;
3964 char fullpath[PATH_MAX];
3965 char *opaque = NULL;
3969 int nbfile_alloc = 0;
3970 char *some_file = NULL;
3971 char *mntpath = NULL;
3977 while ((c = getopt_long(argc, argv, short_opts,
3978 long_opts, NULL)) != -1) {
3987 if (action != HUA_ARCHIVE &&
3988 action != HUA_REMOVE) {
3990 "error: -a is supported only "
3991 "when archiving or removing\n");
3994 archive_id = atoi(optarg);
3997 if (some_file == NULL) {
3999 some_file = strdup(optarg);
4005 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4006 argv[0], argv[optind - 1]);
4011 /* All remaining args are files, so we have at least nbfile */
4012 nbfile = argc - optind;
4014 if ((nbfile == 0) && (filelist == NULL))
4018 opaque_len = strlen(opaque);
4020 /* Alloc the request structure with enough place to store all files
4021 * from command line. */
4022 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4024 fprintf(stderr, "Cannot create the request: %s\n",
4028 nbfile_alloc = nbfile;
4030 hur->hur_request.hr_action = action;
4031 hur->hur_request.hr_archive_id = archive_id;
4032 hur->hur_request.hr_flags = 0;
4034 /* All remaining args are files, add them */
4035 if (nbfile != 0 && some_file == NULL)
4036 some_file = strdup(argv[optind]);
4038 for (i = 0; i < nbfile; i++) {
4039 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4045 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4047 /* If a filelist was specified, read the filelist from it. */
4048 if (filelist != NULL) {
4049 fp = fopen(filelist, "r");
4051 fprintf(stderr, "Cannot read the file list %s: %s\n",
4052 filelist, strerror(errno));
4057 while ((rc = getline(&line, &len, fp)) != -1) {
4058 /* If allocated buffer was too small, get something
4060 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4063 nbfile_alloc = nbfile_alloc * 2 + 1;
4065 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4068 fprintf(stderr, "hsm: cannot allocate "
4069 "the request: %s\n",
4076 size = hur_len(oldhur);
4078 fprintf(stderr, "hsm: cannot allocate "
4079 "%u files + %u bytes data\n",
4080 oldhur->hur_request.hr_itemcount,
4081 oldhur->hur_request.hr_data_len);
4088 memcpy(hur, oldhur, size);
4093 if (line[strlen(line) - 1] == '\n')
4094 line[strlen(line) - 1] = '\0';
4096 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4097 mntpath, line, &last_dev);
4103 if (some_file == NULL) {
4113 /* If a --data was used, add it to the request */
4114 hur->hur_request.hr_data_len = opaque_len;
4116 memcpy(hur_data(hur), opaque, opaque_len);
4118 /* Send the HSM request */
4119 if (realpath(some_file, fullpath) == NULL) {
4120 fprintf(stderr, "Could not find path '%s': %s\n",
4121 some_file, strerror(errno));
4123 rc = llapi_hsm_request(fullpath, hur);
4125 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4126 some_file, strerror(-rc));
4136 static int lfs_hsm_archive(int argc, char **argv)
4138 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4141 static int lfs_hsm_restore(int argc, char **argv)
4143 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4146 static int lfs_hsm_release(int argc, char **argv)
4148 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4151 static int lfs_hsm_remove(int argc, char **argv)
4153 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4156 static int lfs_hsm_cancel(int argc, char **argv)
4158 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4161 static int lfs_swap_layouts(int argc, char **argv)
4166 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4167 SWAP_LAYOUTS_KEEP_MTIME |
4168 SWAP_LAYOUTS_KEEP_ATIME);
4171 int main(int argc, char **argv)
4175 /* Ensure that liblustreapi constructor has run */
4176 if (!liblustreapi_initialized)
4177 fprintf(stderr, "liblustreapi was not properly initialized\n");
4181 Parser_init("lfs > ", cmdlist);
4183 progname = argv[0]; /* Used in error messages */
4185 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4187 rc = Parser_commands();
4190 return rc < 0 ? -rc : rc;
4193 #ifdef _LUSTRE_IDL_H_
4194 /* Everything we need here should be included by lustreapi.h. */
4195 # error "lfs should not depend on lustre_idl.h"
4196 #endif /* _LUSTRE_IDL_H_ */