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>
78 static int lfs_setstripe(int argc, char **argv);
79 static int lfs_find(int argc, char **argv);
80 static int lfs_getstripe(int argc, char **argv);
81 static int lfs_getdirstripe(int argc, char **argv);
82 static int lfs_setdirstripe(int argc, char **argv);
83 static int lfs_rmentry(int argc, char **argv);
84 static int lfs_osts(int argc, char **argv);
85 static int lfs_mdts(int argc, char **argv);
86 static int lfs_df(int argc, char **argv);
87 static int lfs_getname(int argc, char **argv);
88 static int lfs_check(int argc, char **argv);
89 #ifdef HAVE_SYS_QUOTA_H
90 static int lfs_setquota(int argc, char **argv);
91 static int lfs_quota(int argc, char **argv);
93 static int lfs_flushctx(int argc, char **argv);
94 static int lfs_join(int argc, char **argv);
95 static int lfs_lsetfacl(int argc, char **argv);
96 static int lfs_lgetfacl(int argc, char **argv);
97 static int lfs_rsetfacl(int argc, char **argv);
98 static int lfs_rgetfacl(int argc, char **argv);
99 static int lfs_cp(int argc, char **argv);
100 static int lfs_ls(int argc, char **argv);
101 static int lfs_poollist(int argc, char **argv);
102 static int lfs_changelog(int argc, char **argv);
103 static int lfs_changelog_clear(int argc, char **argv);
104 static int lfs_fid2path(int argc, char **argv);
105 static int lfs_path2fid(int argc, char **argv);
106 static int lfs_data_version(int argc, char **argv);
107 static int lfs_hsm_state(int argc, char **argv);
108 static int lfs_hsm_set(int argc, char **argv);
109 static int lfs_hsm_clear(int argc, char **argv);
110 static int lfs_hsm_action(int argc, char **argv);
111 static int lfs_hsm_archive(int argc, char **argv);
112 static int lfs_hsm_restore(int argc, char **argv);
113 static int lfs_hsm_release(int argc, char **argv);
114 static int lfs_hsm_remove(int argc, char **argv);
115 static int lfs_hsm_cancel(int argc, char **argv);
116 static int lfs_swap_layouts(int argc, char **argv);
117 static int lfs_mv(int argc, char **argv);
119 /* Setstripe and migrate share mostly the same parameters */
120 #define SSM_CMD_COMMON(cmd) \
121 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
122 " [--stripe-index|-i <start_ost_idx>]\n" \
123 " [--stripe-size|-S <stripe_size>]\n" \
124 " [--pool|-p <pool_name>]\n" \
125 " [--ost-list|-o <ost_indices>]\n"
127 #define SSM_HELP_COMMON \
128 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
129 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
130 "\t respectively)\n" \
131 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
132 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
133 "\tpool_name: Name of OST pool to use (default none)\n" \
134 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
135 "\t Indices be specified in a format of:\n" \
136 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
138 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
139 "\t If --pool is set with --ost-list, then the OSTs\n" \
140 "\t must be the members of the pool."
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
153 "\tblock: Block file access during data migration\n" \
155 static const char *progname;
156 static bool file_lease_supported = true;
158 /* all available commands */
159 command_t cmdlist[] = {
160 {"setstripe", lfs_setstripe, 0,
161 "Create a new file with a specific striping pattern or\n"
162 "set the default striping pattern on an existing directory or\n"
163 "delete the default striping pattern from an existing directory\n"
164 "usage: setstripe -d <directory> (to delete default striping)\n"\
167 {"getstripe", lfs_getstripe, 0,
168 "To list the striping info for a given file or files in a\n"
169 "directory or recursively for all files in a directory tree.\n"
170 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
171 " [--stripe-count|-c] [--stripe-index|-i]\n"
172 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
173 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
175 " <directory|filename> ..."},
176 {"setdirstripe", lfs_setdirstripe, 0,
177 "To create a striped directory on a specified MDT. This can only\n"
178 "be done on MDT0 with the right of administrator.\n"
179 "usage: setdirstripe <--count|-c stripe_count>\n"
180 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
181 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
182 "\tstripe_count: stripe count of the striped directory\n"
183 "\tmdt_index: MDT index of first stripe\n"
184 "\thash_type: hash type of the striped directory. Hash types:\n"
185 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
186 " all_char sum of characters % MDT_COUNT (not recommended)\n"
187 "\tdefault_stripe: set default dirstripe of the directory\n"
188 "\tmode: the mode of the directory\n"},
189 {"getdirstripe", lfs_getdirstripe, 0,
190 "To list the striping info for a given directory\n"
191 "or recursively for all directories in a directory tree.\n"
192 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
193 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
194 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
195 {"mkdir", lfs_setdirstripe, 0,
196 "To create a striped directory on a specified MDT. This can only\n"
197 "be done on MDT0 with the right of administrator.\n"
198 "usage: mkdir <--count|-c stripe_count>\n"
199 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
200 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
201 "\tstripe_count: stripe count of the striped directory\n"
202 "\tmdt_index: MDT index of first stripe\n"
203 "\thash_type: hash type of the striped directory. Hash types:\n"
204 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
205 " all_char sum of characters % MDT_COUNT (not recommended)\n"
206 "\tdefault_stripe: set default dirstripe of the directory\n"
207 "\tmode: the mode of the directory\n"},
208 {"rm_entry", lfs_rmentry, 0,
209 "To remove the name entry of the remote directory. Note: This\n"
210 "command will only delete the name entry, i.e. the remote directory\n"
211 "will become inaccessable after this command. This can only be done\n"
212 "by the administrator\n"
213 "usage: rm_entry <dir>\n"},
214 {"pool_list", lfs_poollist, 0,
215 "List pools or pool OSTs\n"
216 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
217 {"find", lfs_find, 0,
218 "find files matching given attributes recursively in directory tree.\n"
219 "usage: find <directory|filename> ...\n"
220 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
221 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
222 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
223 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
224 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
225 " [[!] --stripe-count|-c [+-]<stripes>]\n"
226 " [[!] --stripe-index|-i <index,...>]\n"
227 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
228 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
229 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
230 " [[!] --layout|-L released,raid0]\n"
231 "\t !: used before an option indicates 'NOT' requested attribute\n"
232 "\t -: used before a value indicates 'AT MOST' requested value\n"
233 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
234 {"check", lfs_check, 0,
235 "Display the status of MDS or OSTs (as specified in the command)\n"
236 "or all the servers (MDS and OSTs).\n"
237 "usage: check <osts|mds|servers>"},
238 {"join", lfs_join, 0,
239 "join two lustre files into one.\n"
240 "obsolete, HEAD does not support it anymore.\n"},
241 {"osts", lfs_osts, 0, "list OSTs connected to client "
242 "[for specified path only]\n" "usage: osts [path]"},
243 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
244 "[for specified path only]\n" "usage: mdts [path]"},
246 "report filesystem disk space usage or inodes usage"
247 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
248 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
249 {"getname", lfs_getname, 0, "list instances and specified mount points "
250 "[for specified path only]\n"
251 "Usage: getname [-h]|[path ...] "},
252 #ifdef HAVE_SYS_QUOTA_H
253 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
254 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
255 " -b <block-softlimit> -B <block-hardlimit>\n"
256 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
257 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
258 " [--block-softlimit <block-softlimit>]\n"
259 " [--block-hardlimit <block-hardlimit>]\n"
260 " [--inode-softlimit <inode-softlimit>]\n"
261 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
262 " setquota [-t] <-u|--user|-g|--group>\n"
263 " [--block-grace <block-grace>]\n"
264 " [--inode-grace <inode-grace>] <filesystem>\n"
265 " -b can be used instead of --block-softlimit/--block-grace\n"
266 " -B can be used instead of --block-hardlimit\n"
267 " -i can be used instead of --inode-softlimit/--inode-grace\n"
268 " -I can be used instead of --inode-hardlimit\n\n"
269 "Note: The total quota space will be split into many qunits and\n"
270 " balanced over all server targets, the minimal qunit size is\n"
271 " 1M bytes for block space and 1K inodes for inode space.\n\n"
272 " Quota space rebalancing process will stop when this mininum\n"
273 " value is reached. As a result, quota exceeded can be returned\n"
274 " while many targets still have 1MB or 1K inodes of spare\n"
276 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
277 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
279 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
280 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
282 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
283 "usage: flushctx [-k] [mountpoint...]"},
284 {"lsetfacl", lfs_lsetfacl, 0,
285 "Remote user setfacl for user/group on the same remote client.\n"
286 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
287 {"lgetfacl", lfs_lgetfacl, 0,
288 "Remote user getfacl for user/group on the same remote client.\n"
289 "usage: lgetfacl [-dRLPvh] file ..."},
290 {"rsetfacl", lfs_rsetfacl, 0,
291 "Remote user setfacl for user/group on other clients.\n"
292 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
293 {"rgetfacl", lfs_rgetfacl, 0,
294 "Remote user getfacl for user/group on other clients.\n"
295 "usage: rgetfacl [-dRLPvh] file ..."},
297 "Remote user copy files and directories.\n"
298 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
300 "Remote user list directory contents.\n"
301 "usage: ls [OPTION]... [FILE]..."},
302 {"changelog", lfs_changelog, 0,
303 "Show the metadata changes on an MDT."
304 "\nusage: changelog <mdtname> [startrec [endrec]]"},
305 {"changelog_clear", lfs_changelog_clear, 0,
306 "Indicate that old changelog records up to <endrec> are no longer of "
307 "interest to consumer <id>, allowing the system to free up space.\n"
308 "An <endrec> of 0 means all records.\n"
309 "usage: changelog_clear <mdtname> <id> <endrec>"},
310 {"fid2path", lfs_fid2path, 0,
311 "Resolve the full path(s) for given FID(s). For a specific hardlink "
312 "specify link number <linkno>.\n"
313 /* "For a historical link name, specify changelog record <recno>.\n" */
314 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
315 /* [ --rec <recno> ] */ },
316 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
317 "usage: path2fid [--parents] <path> ..."},
318 {"data_version", lfs_data_version, 0, "Display file data version for "
319 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
320 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
321 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
322 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
323 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
324 "[--archived] [--lost] <file> ..."},
325 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
327 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
328 "[--archived] [--lost] <file> ..."},
329 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
330 "given files.\n" "usage: hsm_action <file> ..."},
331 {"hsm_archive", lfs_hsm_archive, 0,
332 "Archive file to external storage.\n"
333 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
335 {"hsm_restore", lfs_hsm_restore, 0,
336 "Restore file from external storage.\n"
337 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
338 {"hsm_release", lfs_hsm_release, 0,
339 "Release files from Lustre.\n"
340 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
341 {"hsm_remove", lfs_hsm_remove, 0,
342 "Remove file copy from external storage.\n"
343 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
344 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
346 "Note: To remove files from the archive that have been deleted on\n"
347 "Lustre, set mntpath and optionally archive. In that case, all the\n"
348 "positional arguments and entries in the file list must be FIDs."
350 {"hsm_cancel", lfs_hsm_cancel, 0,
351 "Cancel requests related to specified files.\n"
352 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
353 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
354 "usage: swap_layouts <path1> <path2>"},
355 {"migrate", lfs_setstripe, 0,
356 "migrate file/directory between MDTs, or migrate file from one OST "
357 "layout\nto another (may be not safe with concurent writes).\n"
358 "usage: migrate [--mdt-index|-m <mdt_idx>] <directory|filename>]\n"
359 "\tmdt_idx: MDT index to migrate to\n"
363 "To move directories between MDTs. This command is deprecated, "
364 "use \"migrate\" instead.\n"
365 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
367 {"help", Parser_help, 0, "help"},
368 {"exit", Parser_quit, 0, "quit"},
369 {"quit", Parser_quit, 0, "quit"},
370 {"--version", Parser_version, 0,
371 "output build version of the utility and exit"},
376 #define MIGRATION_BLOCKS 1
379 * Internal helper for migrate_copy_data(). Check lease and report error if
382 * \param[in] fd File descriptor on which to check the lease.
383 * \param[out] lease_broken Set to true if the lease was broken.
384 * \param[in] group_locked Whether a group lock was taken or not.
385 * \param[in] path Name of the file being processed, for error
388 * \retval 0 Migration can keep on going.
389 * \retval -errno Error occurred, abort migration.
391 static int check_lease(int fd, bool *lease_broken, bool group_locked,
396 if (!file_lease_supported)
399 rc = llapi_lease_check(fd);
401 return 0; /* llapi_check_lease returns > 0 on success. */
404 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
406 rc = rc ? rc : -EAGAIN;
408 fprintf(stderr, "%s: external attempt to access file '%s' "
409 "blocked until migration ends.\n", progname, path);
412 *lease_broken = true;
416 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
417 bool group_locked, const char *fname)
426 bool lease_broken = false;
428 /* Use a page-aligned buffer for direct I/O */
429 rc = posix_memalign(&buf, getpagesize(), buf_size);
434 /* read new data only if we have written all
435 * previously read data */
438 rc = check_lease(fd_src, &lease_broken,
439 group_locked, fname);
443 rsize = read(fd_src, buf, buf_size);
446 fprintf(stderr, "%s: %s: read failed: %s\n",
447 progname, fname, strerror(-rc));
457 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
461 "%s: %s: write failed on volatile: %s\n",
462 progname, fname, strerror(-rc));
472 fprintf(stderr, "%s: %s: fsync failed: %s\n",
473 progname, fname, strerror(-rc));
481 static int migrate_copy_timestamps(int fdv, const struct stat *st)
483 struct timeval tv[2] = {
484 {.tv_sec = st->st_atime},
485 {.tv_sec = st->st_mtime}
488 return futimes(fdv, tv);
491 static int migrate_block(int fd, int fdv, const struct stat *st,
492 size_t buf_size, const char *name)
499 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
501 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
502 progname, name, strerror(-rc));
510 /* The grouplock blocks all concurrent accesses to the file.
511 * It has to be taken after llapi_get_data_version as it would
513 rc = llapi_group_lock(fd, gid);
515 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
516 progname, name, strerror(-rc));
520 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
522 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
526 /* Make sure we keep original atime/mtime values */
527 rc = migrate_copy_timestamps(fdv, st);
529 fprintf(stderr, "%s: %s: timestamp copy failed\n",
535 * for a migration we need to check data version on file did
538 * Pass in gid=0 since we already own grouplock. */
539 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
540 SWAP_LAYOUTS_CHECK_DV1);
542 fprintf(stderr, "%s: %s: dataversion changed during copy, "
543 "migration aborted\n", progname, name);
546 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
547 name, strerror(-rc));
552 rc2 = llapi_group_unlock(fd, gid);
553 if (rc2 < 0 && rc == 0) {
554 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
555 progname, name, strerror(-rc2));
562 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
563 size_t buf_size, const char *name)
569 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
571 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
572 progname, name, strerror(-rc));
576 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
578 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
582 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
584 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
585 progname, name, strerror(-rc));
591 fprintf(stderr, "%s: %s: data version changed during "
597 /* Make sure we keep original atime/mtime values */
598 rc = migrate_copy_timestamps(fdv, st);
600 fprintf(stderr, "%s: %s: timestamp copy failed\n",
605 /* Atomically put lease, swap layouts and close.
606 * for a migration we need to check data version on file did
608 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
610 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
611 progname, name, strerror(-rc));
618 static int lfs_migrate(char *name, __u64 migration_flags,
619 struct llapi_stripe_param *param)
623 char volatile_file[PATH_MAX +
624 LUSTRE_VOLATILE_HDR_LEN + 4];
625 char parent[PATH_MAX];
628 struct lov_user_md *lum = NULL;
631 bool have_lease_rdlck = false;
635 /* find the right size for the IO and allocate the buffer */
636 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
637 lum = malloc(lum_size);
643 rc = llapi_file_get_stripe(name, lum);
644 /* failure can happen for many reasons and some may be not real errors
646 * in case of a real error, a later call will fail with better
647 * error management */
649 buf_size = 1024 * 1024;
651 buf_size = lum->lmm_stripe_size;
653 /* open file, direct io */
654 /* even if the file is only read, WR mode is nedeed to allow
655 * layout swap on fd */
656 fd = open(name, O_RDWR | O_DIRECT);
659 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
664 if (file_lease_supported) {
665 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
666 if (rc == -EOPNOTSUPP) {
667 /* Older servers do not support file lease.
668 * Disable related checks. This opens race conditions
669 * as explained in LU-4840 */
670 file_lease_supported = false;
672 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
673 progname, name, strerror(-rc));
676 have_lease_rdlck = true;
680 /* search for file directory pathname */
681 if (strlen(name) > sizeof(parent)-1) {
685 strncpy(parent, name, sizeof(parent));
686 ptr = strrchr(parent, '/');
688 if (getcwd(parent, sizeof(parent)) == NULL) {
699 rc = snprintf(volatile_file, sizeof(volatile_file), "%s/%s::", parent,
700 LUSTRE_VOLATILE_HDR);
701 if (rc >= sizeof(volatile_file)) {
706 /* create, open a volatile file, use caching (ie no directio) */
707 /* exclusive create is not needed because volatile files cannot
708 * conflict on name by construction */
709 fdv = llapi_file_open_param(volatile_file, O_CREAT | O_WRONLY, 0644,
713 fprintf(stderr, "%s: %s: cannot create volatile file in"
715 progname, parent, strerror(-rc));
719 /* Not-owner (root?) special case.
720 * Need to set owner/group of volatile file like original.
721 * This will allow to pass related check during layout_swap.
726 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
730 rc = fstat(fdv, &stv);
733 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
734 volatile_file, strerror(errno));
737 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
738 rc = fchown(fdv, st.st_uid, st.st_gid);
741 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
742 name, strerror(errno));
747 if (migration_flags & MIGRATION_BLOCKS || !file_lease_supported) {
748 /* Blocking mode, forced if servers do not support file lease */
749 rc = migrate_block(fd, fdv, &st, buf_size, name);
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. */
760 if (have_lease_rdlck)
777 * Parse a string containing an OST index list into an array of integers.
779 * The input string contains a comma delimited list of individual
780 * indices and ranges, for example "1,2-4,7". Add the indices into the
781 * \a osts array and remove duplicates.
783 * \param[out] osts array to store indices in
784 * \param[in] size size of \a osts array
785 * \param[in] offset starting index in \a osts
786 * \param[in] arg string containing OST index list
788 * \retval positive number of indices in \a osts
789 * \retval -EINVAL unable to parse \a arg
791 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
795 int slots = size - offset;
803 while (!end_of_loop) {
811 ptr = strchrnul(arg, ',');
813 end_of_loop = *ptr == '\0';
816 start_index = strtol(arg, &endptr, 0);
817 if (endptr == arg) /* no data at all */
819 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
824 end_index = start_index;
825 if (*endptr == '-') {
826 end_index = strtol(endptr + 1, &endptr, 0);
829 if (end_index < start_index)
833 for (i = start_index; i <= end_index && slots > 0; i++) {
836 /* remove duplicate */
837 for (j = 0; j < offset; j++) {
841 if (j == offset) { /* no duplicate */
846 if (slots == 0 && i < end_index)
854 if (!end_of_loop && ptr != NULL)
857 return rc < 0 ? rc : nr;
861 static int lfs_setstripe(int argc, char **argv)
863 struct llapi_stripe_param *param = NULL;
864 struct find_param migrate_mdt_param = {
871 unsigned long long st_size;
872 int st_offset, st_count;
876 char *stripe_size_arg = NULL;
877 char *stripe_off_arg = NULL;
878 char *stripe_count_arg = NULL;
879 char *pool_name_arg = NULL;
880 char *mdt_idx_arg = NULL;
881 unsigned long long size_units = 1;
882 bool migrate_mode = false;
883 __u64 migration_flags = 0;
884 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
887 struct option long_opts[] = {
888 /* valid only in migrate mode */
889 {"block", no_argument, 0, 'b'},
890 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
891 /* This formerly implied "stripe-count", but was explicitly
892 * made "stripe-count" for consistency with other options,
893 * and to separate it from "mdt-count" when DNE arrives. */
894 {"count", required_argument, 0, 'c'},
896 {"stripe-count", required_argument, 0, 'c'},
897 {"stripe_count", required_argument, 0, 'c'},
898 {"delete", no_argument, 0, 'd'},
899 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
900 /* This formerly implied "stripe-index", but was explicitly
901 * made "stripe-index" for consistency with other options,
902 * and to separate it from "mdt-index" when DNE arrives. */
903 {"index", required_argument, 0, 'i'},
905 {"stripe-index", required_argument, 0, 'i'},
906 {"stripe_index", required_argument, 0, 'i'},
907 {"mdt-index", required_argument, 0, 'm'},
908 {"mdt_index", required_argument, 0, 'm'},
909 {"ost-list", required_argument, 0, 'o'},
910 {"ost_list", required_argument, 0, 'o'},
911 {"pool", required_argument, 0, 'p'},
912 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
913 /* This formerly implied "--stripe-size", but was confusing
914 * with "lfs find --size|-s", which means "file size", so use
915 * the consistent "--stripe-size|-S" for all commands. */
916 {"size", required_argument, 0, 's'},
918 {"stripe-size", required_argument, 0, 'S'},
919 {"stripe_size", required_argument, 0, 'S'},
927 if (strcmp(argv[0], "migrate") == 0)
930 while ((c = getopt_long(argc, argv, "bc:di:m:o:p:s:S:",
931 long_opts, NULL)) >= 0) {
938 fprintf(stderr, "--block is valid only for"
942 migration_flags |= MIGRATION_BLOCKS;
945 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
946 if (strcmp(argv[optind - 1], "--count") == 0)
947 fprintf(stderr, "warning: '--count' deprecated"
948 ", use '--stripe-count' instead\n");
950 stripe_count_arg = optarg;
953 /* delete the default striping pattern */
957 nr_osts = parse_targets(osts,
958 sizeof(osts) / sizeof(__u32),
962 "error: %s: bad OST indices '%s'\n",
967 if (st_offset == -1) /* first in the command line */
971 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
972 if (strcmp(argv[optind - 1], "--index") == 0)
973 fprintf(stderr, "warning: '--index' deprecated"
974 ", use '--stripe-index' instead\n");
976 stripe_off_arg = optarg;
980 fprintf(stderr, "--mdt-index is valid only for"
984 mdt_idx_arg = optarg;
986 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
988 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
989 fprintf(stderr, "warning: '--size|-s' deprecated, "
990 "use '--stripe-size|-S' instead\n");
992 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
994 stripe_size_arg = optarg;
997 pool_name_arg = optarg;
1004 fname = argv[optind];
1007 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1008 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1009 fprintf(stderr, "error: %s: cannot specify -d with "
1010 "-s, -c, -o, or -p options\n",
1015 if (optind == argc) {
1016 fprintf(stderr, "error: %s: missing filename|dirname\n",
1021 if (mdt_idx_arg != NULL && optind > 3) {
1022 fprintf(stderr, "error: %s: cannot specify -m with other "
1023 "options\n", argv[0]);
1027 if (pool_name_arg && strlen(pool_name_arg) > LOV_MAXPOOLNAME) {
1029 "error: %s: pool name '%s' is too long (max is %d characters)\n",
1030 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1034 /* get the stripe size */
1035 if (stripe_size_arg != NULL) {
1036 result = llapi_parse_size(stripe_size_arg, &st_size,
1039 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1040 argv[0], stripe_size_arg);
1044 /* get the stripe offset */
1045 if (stripe_off_arg != NULL) {
1046 st_offset = strtol(stripe_off_arg, &end, 0);
1048 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1049 argv[0], stripe_off_arg);
1053 /* get the stripe count */
1054 if (stripe_count_arg != NULL) {
1055 st_count = strtoul(stripe_count_arg, &end, 0);
1057 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1058 argv[0], stripe_count_arg);
1063 if (mdt_idx_arg != NULL) {
1064 /* initialize migrate mdt parameters */
1065 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1067 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1068 argv[0], mdt_idx_arg);
1071 migrate_mdt_param.fp_migrate = 1;
1073 /* initialize stripe parameters */
1074 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1075 if (param == NULL) {
1076 fprintf(stderr, "error: %s: run out of memory\n",
1081 param->lsp_stripe_size = st_size;
1082 param->lsp_stripe_offset = st_offset;
1083 param->lsp_stripe_count = st_count;
1084 param->lsp_stripe_pattern = 0;
1085 param->lsp_pool = pool_name_arg;
1086 param->lsp_is_specific = false;
1088 if (st_count > 0 && nr_osts != st_count) {
1089 fprintf(stderr, "error: %s: stripe count '%d' "
1090 "doesn't match the number of OSTs: %d\n"
1091 , argv[0], st_count, nr_osts);
1096 param->lsp_is_specific = true;
1097 param->lsp_stripe_count = nr_osts;
1098 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1102 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1103 if (!migrate_mode) {
1104 result = llapi_file_open_param(fname,
1111 } else if (mdt_idx_arg != NULL) {
1112 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1114 result = lfs_migrate(fname, migration_flags, param);
1117 /* Save the first error encountered. */
1121 "error: %s: %s file '%s' failed\n",
1122 argv[0], migrate_mode ? "migrate" : "create",
1132 static int lfs_poollist(int argc, char **argv)
1137 return llapi_poollist(argv[1]);
1140 static int set_time(time_t *time, time_t *set, char *str)
1147 else if (str[0] == '-')
1153 t = strtol(str, NULL, 0);
1154 if (*time < t * 24 * 60 * 60) {
1157 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1161 *set = *time - t * 24 * 60 * 60;
1168 static int name2id(unsigned int *id, char *name, int type)
1171 struct passwd *entry;
1173 if (!(entry = getpwnam(name))) {
1179 *id = entry->pw_uid;
1181 struct group *entry;
1183 if (!(entry = getgrnam(name))) {
1189 *id = entry->gr_gid;
1195 static int id2name(char **name, unsigned int id, int type)
1198 struct passwd *entry;
1200 if (!(entry = getpwuid(id))) {
1206 *name = entry->pw_name;
1208 struct group *entry;
1210 if (!(entry = getgrgid(id))) {
1216 *name = entry->gr_name;
1222 static int name2layout(__u32 *layout, char *name)
1227 for (ptr = name; ; ptr = NULL) {
1228 lyt = strtok(ptr, ",");
1231 if (strcmp(lyt, "released") == 0)
1232 *layout |= LOV_PATTERN_F_RELEASED;
1233 else if (strcmp(lyt, "raid0") == 0)
1234 *layout |= LOV_PATTERN_RAID0;
1241 #define FIND_POOL_OPT 3
1242 static int lfs_find(int argc, char **argv)
1247 struct find_param param = {
1251 struct option long_opts[] = {
1252 {"atime", required_argument, 0, 'A'},
1253 {"stripe-count", required_argument, 0, 'c'},
1254 {"stripe_count", required_argument, 0, 'c'},
1255 {"ctime", required_argument, 0, 'C'},
1256 {"maxdepth", required_argument, 0, 'D'},
1257 {"gid", required_argument, 0, 'g'},
1258 {"group", required_argument, 0, 'G'},
1259 {"stripe-index", required_argument, 0, 'i'},
1260 {"stripe_index", required_argument, 0, 'i'},
1261 {"layout", required_argument, 0, 'L'},
1262 {"mdt", required_argument, 0, 'm'},
1263 {"mtime", required_argument, 0, 'M'},
1264 {"name", required_argument, 0, 'n'},
1265 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1266 {"obd", required_argument, 0, 'O'},
1267 {"ost", required_argument, 0, 'O'},
1268 /* no short option for pool, p/P already used */
1269 {"pool", required_argument, 0, FIND_POOL_OPT},
1270 {"print0", no_argument, 0, 'p'},
1271 {"print", no_argument, 0, 'P'},
1272 {"size", required_argument, 0, 's'},
1273 {"stripe-size", required_argument, 0, 'S'},
1274 {"stripe_size", required_argument, 0, 'S'},
1275 {"type", required_argument, 0, 't'},
1276 {"uid", required_argument, 0, 'u'},
1277 {"user", required_argument, 0, 'U'},
1290 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1291 while ((c = getopt_long_only(argc, argv,
1292 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1293 long_opts, NULL)) >= 0) {
1298 /* '!' is part of option */
1299 /* when getopt_long_only() finds a string which is not
1300 * an option nor a known option argument it returns 1
1301 * in that case if we already have found pathstart and pathend
1302 * (i.e. we have the list of pathnames),
1303 * the only supported value is "!"
1305 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1306 if (!isoption && pathend != -1) {
1307 fprintf(stderr, "err: %s: filename|dirname must either "
1308 "precede options or follow options\n",
1313 if (!isoption && pathstart == -1)
1314 pathstart = optind - 1;
1315 if (isoption && pathstart != -1 && pathend == -1)
1316 pathend = optind - 2;
1322 /* unknown; opt is "!" or path component,
1323 * checking done above.
1325 if (strcmp(optarg, "!") == 0)
1329 xtime = ¶m.fp_atime;
1330 xsign = ¶m.fp_asign;
1331 param.fp_exclude_atime = !!neg_opt;
1332 /* no break, this falls through to 'C' for ctime */
1335 xtime = ¶m.fp_ctime;
1336 xsign = ¶m.fp_csign;
1337 param.fp_exclude_ctime = !!neg_opt;
1339 /* no break, this falls through to 'M' for mtime */
1342 xtime = ¶m.fp_mtime;
1343 xsign = ¶m.fp_msign;
1344 param.fp_exclude_mtime = !!neg_opt;
1346 rc = set_time(&t, xtime, optarg);
1347 if (rc == INT_MAX) {
1355 if (optarg[0] == '+') {
1356 param.fp_stripe_count_sign = -1;
1358 } else if (optarg[0] == '-') {
1359 param.fp_stripe_count_sign = 1;
1363 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1364 if (*endptr != '\0') {
1365 fprintf(stderr,"error: bad stripe_count '%s'\n",
1370 param.fp_check_stripe_count = 1;
1371 param.fp_exclude_stripe_count = !!neg_opt;
1374 param.fp_max_depth = strtol(optarg, 0, 0);
1378 rc = name2id(¶m.fp_gid, optarg, GROUP);
1380 param.fp_gid = strtoul(optarg, &endptr, 10);
1381 if (*endptr != '\0') {
1382 fprintf(stderr, "Group/GID: %s cannot "
1383 "be found.\n", optarg);
1388 param.fp_exclude_gid = !!neg_opt;
1389 param.fp_check_gid = 1;
1392 ret = name2layout(¶m.fp_layout, optarg);
1395 param.fp_exclude_layout = !!neg_opt;
1396 param.fp_check_layout = 1;
1400 rc = name2id(¶m.fp_uid, optarg, USER);
1402 param.fp_uid = strtoul(optarg, &endptr, 10);
1403 if (*endptr != '\0') {
1404 fprintf(stderr, "User/UID: %s cannot "
1405 "be found.\n", optarg);
1410 param.fp_exclude_uid = !!neg_opt;
1411 param.fp_check_uid = 1;
1414 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1416 "Pool name %s is too long"
1417 " (max is %d)\n", optarg,
1422 /* we do check for empty pool because empty pool
1423 * is used to find V1 lov attributes */
1424 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1425 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1426 param.fp_exclude_pool = !!neg_opt;
1427 param.fp_check_pool = 1;
1430 param.fp_pattern = (char *)optarg;
1431 param.fp_exclude_pattern = !!neg_opt;
1436 char *buf, *token, *next, *p;
1440 buf = strdup(optarg);
1446 param.fp_exclude_obd = !!neg_opt;
1449 while (token && *token) {
1450 token = strchr(token, ',');
1457 param.fp_exclude_mdt = !!neg_opt;
1458 param.fp_num_alloc_mdts += len;
1459 tmp = realloc(param.fp_mdt_uuid,
1460 param.fp_num_alloc_mdts *
1461 sizeof(*param.fp_mdt_uuid));
1467 param.fp_mdt_uuid = tmp;
1469 param.fp_exclude_obd = !!neg_opt;
1470 param.fp_num_alloc_obds += len;
1471 tmp = realloc(param.fp_obd_uuid,
1472 param.fp_num_alloc_obds *
1473 sizeof(*param.fp_obd_uuid));
1479 param.fp_obd_uuid = tmp;
1481 for (token = buf; token && *token; token = next) {
1482 struct obd_uuid *puuid;
1485 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1488 ¶m.fp_obd_uuid[param.fp_num_obds++];
1490 p = strchr(token, ',');
1497 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1502 strncpy(puuid->uuid, token,
1503 sizeof(puuid->uuid));
1511 param.fp_zero_end = 1;
1516 if (optarg[0] == '+') {
1517 param.fp_size_sign = -1;
1519 } else if (optarg[0] == '-') {
1520 param.fp_size_sign = 1;
1524 ret = llapi_parse_size(optarg, ¶m.fp_size,
1525 ¶m.fp_size_units, 0);
1527 fprintf(stderr, "error: bad file size '%s'\n",
1531 param.fp_check_size = 1;
1532 param.fp_exclude_size = !!neg_opt;
1535 if (optarg[0] == '+') {
1536 param.fp_stripe_size_sign = -1;
1538 } else if (optarg[0] == '-') {
1539 param.fp_stripe_size_sign = 1;
1543 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1544 ¶m.fp_stripe_size_units, 0);
1546 fprintf(stderr, "error: bad stripe_size '%s'\n",
1550 param.fp_check_stripe_size = 1;
1551 param.fp_exclude_stripe_size = !!neg_opt;
1554 param.fp_exclude_type = !!neg_opt;
1555 switch (optarg[0]) {
1557 param.fp_type = S_IFBLK;
1560 param.fp_type = S_IFCHR;
1563 param.fp_type = S_IFDIR;
1566 param.fp_type = S_IFREG;
1569 param.fp_type = S_IFLNK;
1572 param.fp_type = S_IFIFO;
1575 param.fp_type = S_IFSOCK;
1578 fprintf(stderr, "error: %s: bad type '%s'\n",
1590 if (pathstart == -1) {
1591 fprintf(stderr, "error: %s: no filename|pathname\n",
1595 } else if (pathend == -1) {
1601 rc = llapi_find(argv[pathstart], ¶m);
1602 if (rc != 0 && ret == 0)
1604 } while (++pathstart < pathend);
1607 fprintf(stderr, "error: %s failed for %s.\n",
1608 argv[0], argv[optind - 1]);
1610 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1611 free(param.fp_obd_uuid);
1613 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1614 free(param.fp_mdt_uuid);
1619 static int lfs_getstripe_internal(int argc, char **argv,
1620 struct find_param *param)
1622 struct option long_opts[] = {
1623 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1624 /* This formerly implied "stripe-count", but was explicitly
1625 * made "stripe-count" for consistency with other options,
1626 * and to separate it from "mdt-count" when DNE arrives. */
1627 {"count", no_argument, 0, 'c'},
1629 {"stripe-count", no_argument, 0, 'c'},
1630 {"stripe_count", no_argument, 0, 'c'},
1631 {"directory", no_argument, 0, 'd'},
1632 {"default", no_argument, 0, 'D'},
1633 {"generation", no_argument, 0, 'g'},
1634 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1635 /* This formerly implied "stripe-index", but was explicitly
1636 * made "stripe-index" for consistency with other options,
1637 * and to separate it from "mdt-index" when DNE arrives. */
1638 {"index", no_argument, 0, 'i'},
1640 {"stripe-index", no_argument, 0, 'i'},
1641 {"stripe_index", no_argument, 0, 'i'},
1642 {"layout", no_argument, 0, 'L'},
1643 {"mdt-index", no_argument, 0, 'M'},
1644 {"mdt_index", no_argument, 0, 'M'},
1645 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1646 /* This formerly implied "stripe-index", but was confusing
1647 * with "file offset" (which will eventually be needed for
1648 * with different layouts by offset), so deprecate it. */
1649 {"offset", no_argument, 0, 'o'},
1651 {"obd", required_argument, 0, 'O'},
1652 {"ost", required_argument, 0, 'O'},
1653 {"pool", no_argument, 0, 'p'},
1654 {"quiet", no_argument, 0, 'q'},
1655 {"recursive", no_argument, 0, 'r'},
1656 {"raw", no_argument, 0, 'R'},
1657 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1658 /* This formerly implied "--stripe-size", but was confusing
1659 * with "lfs find --size|-s", which means "file size", so use
1660 * the consistent "--stripe-size|-S" for all commands. */
1661 {"size", no_argument, 0, 's'},
1663 {"stripe-size", no_argument, 0, 'S'},
1664 {"stripe_size", no_argument, 0, 'S'},
1665 {"verbose", no_argument, 0, 'v'},
1670 param->fp_max_depth = 1;
1671 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1672 long_opts, NULL)) != -1) {
1675 if (param->fp_obd_uuid) {
1677 "error: %s: only one obduuid allowed",
1681 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1687 param->fp_max_depth = 0;
1690 param->fp_get_default_lmv = 1;
1693 param->fp_recursive = 1;
1696 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1699 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1700 if (strcmp(argv[optind - 1], "--count") == 0)
1701 fprintf(stderr, "warning: '--count' deprecated,"
1702 " use '--stripe-count' instead\n");
1704 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1705 param->fp_verbose |= VERBOSE_COUNT;
1706 param->fp_max_depth = 0;
1709 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1711 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1712 fprintf(stderr, "warning: '--size|-s' deprecated, "
1713 "use '--stripe-size|-S' instead\n");
1715 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1717 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1718 param->fp_verbose |= VERBOSE_SIZE;
1719 param->fp_max_depth = 0;
1722 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1724 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1725 "use '--stripe-index|-i' instead\n");
1728 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1729 if (strcmp(argv[optind - 1], "--index") == 0)
1730 fprintf(stderr, "warning: '--index' deprecated"
1731 ", use '--stripe-index' instead\n");
1733 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1734 param->fp_verbose |= VERBOSE_OFFSET;
1735 param->fp_max_depth = 0;
1739 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1740 param->fp_verbose |= VERBOSE_POOL;
1741 param->fp_max_depth = 0;
1745 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1746 param->fp_verbose |= VERBOSE_GENERATION;
1747 param->fp_max_depth = 0;
1751 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1752 param->fp_verbose |= VERBOSE_LAYOUT;
1753 param->fp_max_depth = 0;
1757 if (!(param->fp_verbose & VERBOSE_DETAIL))
1758 param->fp_max_depth = 0;
1759 param->fp_verbose |= VERBOSE_MDTINDEX;
1772 if (param->fp_recursive)
1773 param->fp_max_depth = -1;
1775 if (!param->fp_verbose)
1776 param->fp_verbose = VERBOSE_ALL;
1777 if (param->fp_quiet)
1778 param->fp_verbose = VERBOSE_OBJID;
1781 rc = llapi_getstripe(argv[optind], param);
1782 } while (++optind < argc && !rc);
1785 fprintf(stderr, "error: %s failed for %s.\n",
1786 argv[0], argv[optind - 1]);
1790 static int lfs_tgts(int argc, char **argv)
1792 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1793 struct find_param param;
1794 int index = 0, rc=0;
1799 if (argc == 2 && !realpath(argv[1], path)) {
1801 fprintf(stderr, "error: invalid path '%s': %s\n",
1802 argv[1], strerror(-rc));
1806 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1807 /* Check if we have a mount point */
1808 if (mntdir[0] == '\0')
1811 memset(¶m, 0, sizeof(param));
1812 if (!strcmp(argv[0], "mdts"))
1813 param.fp_get_lmv = 1;
1815 rc = llapi_ostlist(mntdir, ¶m);
1817 fprintf(stderr, "error: %s: failed on %s\n",
1820 if (path[0] != '\0')
1822 memset(mntdir, 0, PATH_MAX);
1828 static int lfs_getstripe(int argc, char **argv)
1830 struct find_param param = { 0 };
1831 return lfs_getstripe_internal(argc, argv, ¶m);
1835 static int lfs_getdirstripe(int argc, char **argv)
1837 struct find_param param = { 0 };
1839 param.fp_get_lmv = 1;
1840 return lfs_getstripe_internal(argc, argv, ¶m);
1844 static int lfs_setdirstripe(int argc, char **argv)
1848 unsigned int stripe_offset = -1;
1849 unsigned int stripe_count = 1;
1850 enum lmv_hash_type hash_type;
1853 char *stripe_offset_opt = NULL;
1854 char *stripe_count_opt = NULL;
1855 char *stripe_hash_opt = NULL;
1856 char *mode_opt = NULL;
1857 bool default_stripe = false;
1858 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1859 mode_t previous_mode = 0;
1860 bool delete = false;
1862 struct option long_opts[] = {
1863 {"count", required_argument, 0, 'c'},
1864 {"delete", no_argument, 0, 'd'},
1865 {"index", required_argument, 0, 'i'},
1866 {"mode", required_argument, 0, 'm'},
1867 {"hash-type", required_argument, 0, 't'},
1868 {"default_stripe", no_argument, 0, 'D'},
1872 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1879 stripe_count_opt = optarg;
1883 default_stripe = true;
1886 default_stripe = true;
1889 stripe_offset_opt = optarg;
1895 stripe_hash_opt = optarg;
1898 fprintf(stderr, "error: %s: option '%s' "
1900 argv[0], argv[optind - 1]);
1905 if (optind == argc) {
1906 fprintf(stderr, "error: %s: missing dirname\n",
1911 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1912 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1917 if (stripe_offset_opt != NULL) {
1918 /* get the stripe offset */
1919 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1921 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1922 argv[0], stripe_offset_opt);
1928 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1929 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1930 " or -i options.\n", argv[0]);
1938 if (mode_opt != NULL) {
1939 mode = strtoul(mode_opt, &end, 8);
1941 fprintf(stderr, "error: %s: bad mode '%s'\n",
1945 previous_mode = umask(0);
1948 if (stripe_hash_opt == NULL ||
1949 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1950 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1951 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1952 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1954 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1955 argv[0], stripe_hash_opt);
1959 /* get the stripe count */
1960 if (stripe_count_opt != NULL) {
1961 stripe_count = strtoul(stripe_count_opt, &end, 0);
1963 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1964 argv[0], stripe_count_opt);
1969 dname = argv[optind];
1971 if (default_stripe) {
1972 result = llapi_dir_set_default_lmv_stripe(dname,
1973 stripe_offset, stripe_count,
1976 result = llapi_dir_create_pool(dname, mode,
1978 stripe_count, hash_type,
1983 fprintf(stderr, "error: %s: create stripe dir '%s' "
1984 "failed\n", argv[0], dname);
1987 dname = argv[++optind];
1988 } while (dname != NULL);
1990 if (mode_opt != NULL)
1991 umask(previous_mode);
1997 static int lfs_rmentry(int argc, char **argv)
2004 fprintf(stderr, "error: %s: missing dirname\n",
2010 dname = argv[index];
2011 while (dname != NULL) {
2012 result = llapi_direntry_remove(dname);
2014 fprintf(stderr, "error: %s: remove dir entry '%s' "
2015 "failed\n", argv[0], dname);
2018 dname = argv[++index];
2023 static int lfs_mv(int argc, char **argv)
2025 struct find_param param = {
2032 struct option long_opts[] = {
2033 {"mdt-index", required_argument, 0, 'M'},
2034 {"verbose", no_argument, 0, 'v'},
2038 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2041 param.fp_mdt_index = strtoul(optarg, &end, 0);
2043 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2050 param.fp_verbose = VERBOSE_DETAIL;
2054 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2055 argv[0], argv[optind - 1]);
2060 if (param.fp_mdt_index == -1) {
2061 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2065 if (optind >= argc) {
2066 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2070 param.fp_migrate = 1;
2071 rc = llapi_migrate_mdt(argv[optind], ¶m);
2073 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2074 argv[0], argv[optind], param.fp_mdt_index,
2079 static int lfs_osts(int argc, char **argv)
2081 return lfs_tgts(argc, argv);
2084 static int lfs_mdts(int argc, char **argv)
2086 return lfs_tgts(argc, argv);
2089 #define COOK(value) \
2092 while (value > 1024) { \
2100 #define CDF "%11llu"
2101 #define HDF "%8.1f%c"
2105 static int showdf(char *mntdir, struct obd_statfs *stat,
2106 char *uuid, int ishow, int cooked,
2107 char *type, int index, int rc)
2109 long long avail, used, total;
2111 char *suffix = "KMGTPEZY";
2112 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2113 char tbuf[3 * sizeof(__u64)];
2114 char ubuf[3 * sizeof(__u64)];
2115 char abuf[3 * sizeof(__u64)];
2116 char rbuf[3 * sizeof(__u64)];
2124 avail = stat->os_ffree;
2125 used = stat->os_files - stat->os_ffree;
2126 total = stat->os_files;
2128 int shift = cooked ? 0 : 10;
2130 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2131 used = ((stat->os_blocks - stat->os_bfree) *
2132 stat->os_bsize) >> shift;
2133 total = (stat->os_blocks * stat->os_bsize) >> shift;
2136 if ((used + avail) > 0)
2137 ratio = (double)used / (double)(used + avail);
2143 cook_val = (double)total;
2146 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2148 sprintf(tbuf, CDF, total);
2150 cook_val = (double)used;
2153 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2155 sprintf(ubuf, CDF, used);
2157 cook_val = (double)avail;
2160 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2162 sprintf(abuf, CDF, avail);
2164 sprintf(tbuf, CDF, total);
2165 sprintf(ubuf, CDF, used);
2166 sprintf(abuf, CDF, avail);
2169 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2170 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2171 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2173 printf("[%s:%d]\n", type, index);
2179 printf(UUF": inactive device\n", uuid);
2182 printf(UUF": %s\n", uuid, strerror(-rc));
2189 struct ll_stat_type {
2194 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2195 int cooked, int lazy)
2197 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2198 struct obd_uuid uuid_buf;
2199 char *poolname = NULL;
2200 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2201 { LL_STATFS_LOV, "OST" },
2203 struct ll_stat_type *tp;
2204 __u64 ost_ffree = 0;
2210 poolname = strchr(pool, '.');
2211 if (poolname != NULL) {
2212 if (strncmp(fsname, pool, strlen(fsname))) {
2213 fprintf(stderr, "filesystem name incorrect\n");
2222 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2223 "UUID", "Inodes", "IUsed", "IFree",
2224 "IUse%", "Mounted on");
2226 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2227 "UUID", cooked ? "bytes" : "1K-blocks",
2228 "Used", "Available", "Use%", "Mounted on");
2230 for (tp = types; tp->st_name != NULL; tp++) {
2231 for (index = 0; ; index++) {
2232 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2233 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2234 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2235 rc = llapi_obd_statfs(mntdir, type, index,
2236 &stat_buf, &uuid_buf);
2243 if (poolname && tp->st_op == LL_STATFS_LOV &&
2244 llapi_search_ost(fsname, poolname,
2245 obd_uuid2str(&uuid_buf)) != 1)
2248 /* the llapi_obd_statfs() call may have returned with
2249 * an error, but if it filled in uuid_buf we will at
2250 * lease use that to print out a message for that OBD.
2251 * If we didn't get anything in the uuid_buf, then fill
2252 * it in so that we can print an error message. */
2253 if (uuid_buf.uuid[0] == '\0')
2254 sprintf(uuid_buf.uuid, "%s%04x",
2255 tp->st_name, index);
2256 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2257 ishow, cooked, tp->st_name, index, rc);
2260 if (tp->st_op == LL_STATFS_LMV) {
2261 sum.os_ffree += stat_buf.os_ffree;
2262 sum.os_files += stat_buf.os_files;
2263 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2264 sum.os_blocks += stat_buf.os_blocks *
2266 sum.os_bfree += stat_buf.os_bfree *
2268 sum.os_bavail += stat_buf.os_bavail *
2270 ost_ffree += stat_buf.os_ffree;
2272 } else if (rc == -EINVAL || rc == -EFAULT) {
2278 /* If we don't have as many objects free on the OST as inodes
2279 * on the MDS, we reduce the total number of inodes to
2280 * compensate, so that the "inodes in use" number is correct.
2281 * Matches ll_statfs_internal() so the results are consistent. */
2282 if (ost_ffree < sum.os_ffree) {
2283 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2284 sum.os_ffree = ost_ffree;
2287 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2292 static int lfs_df(int argc, char **argv)
2294 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2295 int ishow = 0, cooked = 0;
2297 int c, rc = 0, index = 0;
2298 char fsname[PATH_MAX] = "", *pool_name = NULL;
2299 struct option long_opts[] = {
2300 {"pool", required_argument, 0, 'p'},
2301 {"lazy", 0, 0, 'l'},
2305 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2323 if (optind < argc && !realpath(argv[optind], path)) {
2325 fprintf(stderr, "error: invalid path '%s': %s\n",
2326 argv[optind], strerror(-rc));
2330 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2331 /* Check if we have a mount point */
2332 if (mntdir[0] == '\0')
2335 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2336 if (rc || path[0] != '\0')
2338 fsname[0] = '\0'; /* avoid matching in next loop */
2339 mntdir[0] = '\0'; /* avoid matching in next loop */
2345 static int lfs_getname(int argc, char **argv)
2347 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2348 int rc = 0, index = 0, c;
2349 char buf[sizeof(struct obd_uuid)];
2351 while ((c = getopt(argc, argv, "h")) != -1)
2354 if (optind == argc) { /* no paths specified, get all paths. */
2355 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2356 rc = llapi_getname(mntdir, buf, sizeof(buf));
2359 "cannot get name for `%s': %s\n",
2360 mntdir, strerror(-rc));
2364 printf("%s %s\n", buf, mntdir);
2366 path[0] = fsname[0] = mntdir[0] = 0;
2368 } else { /* paths specified, only attempt to search these. */
2369 for (; optind < argc; optind++) {
2370 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2373 "cannot get name for `%s': %s\n",
2374 argv[optind], strerror(-rc));
2378 printf("%s %s\n", buf, argv[optind]);
2384 static int lfs_check(int argc, char **argv)
2387 char mntdir[PATH_MAX] = {'\0'};
2396 obd_types[0] = obd_type1;
2397 obd_types[1] = obd_type2;
2399 if (strcmp(argv[1], "osts") == 0) {
2400 strcpy(obd_types[0], "osc");
2401 } else if (strcmp(argv[1], "mds") == 0) {
2402 strcpy(obd_types[0], "mdc");
2403 } else if (strcmp(argv[1], "servers") == 0) {
2405 strcpy(obd_types[0], "osc");
2406 strcpy(obd_types[1], "mdc");
2408 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2413 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2414 if (rc < 0 || mntdir[0] == '\0') {
2415 fprintf(stderr, "No suitable Lustre mount found\n");
2419 rc = llapi_target_check(num_types, obd_types, mntdir);
2421 fprintf(stderr, "error: %s: %s status failed\n",
2428 static int lfs_join(int argc, char **argv)
2430 fprintf(stderr, "join two lustre files into one.\n"
2431 "obsolete, HEAD does not support it anymore.\n");
2435 #ifdef HAVE_SYS_QUOTA_H
2436 #define ARG2INT(nr, str, msg) \
2439 nr = strtol(str, &endp, 0); \
2441 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2446 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2448 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2449 * returns the value or ULONG_MAX on integer overflow or incorrect format
2451 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2452 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2453 * 3. empty integer value is interpreted as 0
2455 static unsigned long str2sec(const char* timestr)
2457 const char spec[] = "smhdw";
2458 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2459 unsigned long val = 0;
2462 if (strpbrk(timestr, spec) == NULL) {
2463 /* no specifiers inside the time string,
2464 should treat it as an integer value */
2465 val = strtoul(timestr, &tail, 10);
2466 return *tail ? ULONG_MAX : val;
2469 /* format string is XXwXXdXXhXXmXXs */
2475 v = strtoul(timestr, &tail, 10);
2476 if (v == ULONG_MAX || *tail == '\0')
2477 /* value too large (ULONG_MAX or more)
2478 or missing specifier */
2481 ptr = strchr(spec, *tail);
2483 /* unknown specifier */
2488 /* check if product will overflow the type */
2489 if (!(v < ULONG_MAX / mult[ind]))
2492 ADD_OVERFLOW(val, mult[ind] * v);
2493 if (val == ULONG_MAX)
2505 #define ARG2ULL(nr, str, def_units) \
2507 unsigned long long limit, units = def_units; \
2510 rc = llapi_parse_size(str, &limit, &units, 1); \
2512 fprintf(stderr, "error: bad limit value %s\n", str); \
2518 static inline int has_times_option(int argc, char **argv)
2522 for (i = 1; i < argc; i++)
2523 if (!strcmp(argv[i], "-t"))
2529 int lfs_setquota_times(int argc, char **argv)
2532 struct if_quotactl qctl;
2533 char *mnt, *obd_type = (char *)qctl.obd_type;
2534 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2535 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2536 struct option long_opts[] = {
2537 {"block-grace", required_argument, 0, 'b'},
2538 {"group", no_argument, 0, 'g'},
2539 {"inode-grace", required_argument, 0, 'i'},
2540 {"times", no_argument, 0, 't'},
2541 {"user", no_argument, 0, 'u'},
2545 memset(&qctl, 0, sizeof(qctl));
2546 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2547 qctl.qc_type = UGQUOTA;
2549 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2553 if (qctl.qc_type != UGQUOTA) {
2554 fprintf(stderr, "error: -u and -g can't be used "
2555 "more than once\n");
2558 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2561 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2562 fprintf(stderr, "error: bad block-grace: %s\n",
2566 dqb->dqb_valid |= QIF_BTIME;
2569 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2570 fprintf(stderr, "error: bad inode-grace: %s\n",
2574 dqb->dqb_valid |= QIF_ITIME;
2576 case 't': /* Yes, of course! */
2578 default: /* getopt prints error message for us when opterr != 0 */
2583 if (qctl.qc_type == UGQUOTA) {
2584 fprintf(stderr, "error: neither -u nor -g specified\n");
2588 if (optind != argc - 1) {
2589 fprintf(stderr, "error: unexpected parameters encountered\n");
2594 rc = llapi_quotactl(mnt, &qctl);
2597 fprintf(stderr, "%s %s ", obd_type,
2598 obd_uuid2str(&qctl.obd_uuid));
2599 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2606 #define BSLIMIT (1 << 0)
2607 #define BHLIMIT (1 << 1)
2608 #define ISLIMIT (1 << 2)
2609 #define IHLIMIT (1 << 3)
2611 int lfs_setquota(int argc, char **argv)
2614 struct if_quotactl qctl;
2615 char *mnt, *obd_type = (char *)qctl.obd_type;
2616 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2617 struct option long_opts[] = {
2618 {"block-softlimit", required_argument, 0, 'b'},
2619 {"block-hardlimit", required_argument, 0, 'B'},
2620 {"group", required_argument, 0, 'g'},
2621 {"inode-softlimit", required_argument, 0, 'i'},
2622 {"inode-hardlimit", required_argument, 0, 'I'},
2623 {"user", required_argument, 0, 'u'},
2626 unsigned limit_mask = 0;
2629 if (has_times_option(argc, argv))
2630 return lfs_setquota_times(argc, argv);
2632 memset(&qctl, 0, sizeof(qctl));
2633 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2634 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2635 * so it can be used as a marker that qc_type
2636 * isn't reinitialized from command line */
2638 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2642 if (qctl.qc_type != UGQUOTA) {
2643 fprintf(stderr, "error: -u and -g can't be used"
2644 " more than once\n");
2647 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2648 rc = name2id(&qctl.qc_id, optarg,
2649 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2651 qctl.qc_id = strtoul(optarg, &endptr, 10);
2652 if (*endptr != '\0') {
2653 fprintf(stderr, "error: can't find id "
2654 "for name %s\n", optarg);
2660 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2661 dqb->dqb_bsoftlimit >>= 10;
2662 limit_mask |= BSLIMIT;
2663 if (dqb->dqb_bsoftlimit &&
2664 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2665 fprintf(stderr, "warning: block softlimit is "
2666 "smaller than the miminal qunit size, "
2667 "please see the help of setquota or "
2668 "Lustre manual for details.\n");
2671 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2672 dqb->dqb_bhardlimit >>= 10;
2673 limit_mask |= BHLIMIT;
2674 if (dqb->dqb_bhardlimit &&
2675 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2676 fprintf(stderr, "warning: block hardlimit is "
2677 "smaller than the miminal qunit size, "
2678 "please see the help of setquota or "
2679 "Lustre manual for details.\n");
2682 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2683 limit_mask |= ISLIMIT;
2684 if (dqb->dqb_isoftlimit &&
2685 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2686 fprintf(stderr, "warning: inode softlimit is "
2687 "smaller than the miminal qunit size, "
2688 "please see the help of setquota or "
2689 "Lustre manual for details.\n");
2692 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2693 limit_mask |= IHLIMIT;
2694 if (dqb->dqb_ihardlimit &&
2695 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2696 fprintf(stderr, "warning: inode hardlimit is "
2697 "smaller than the miminal qunit size, "
2698 "please see the help of setquota or "
2699 "Lustre manual for details.\n");
2701 default: /* getopt prints error message for us when opterr != 0 */
2706 if (qctl.qc_type == UGQUOTA) {
2707 fprintf(stderr, "error: neither -u nor -g was specified\n");
2711 if (limit_mask == 0) {
2712 fprintf(stderr, "error: at least one limit must be specified\n");
2716 if (optind != argc - 1) {
2717 fprintf(stderr, "error: unexpected parameters encountered\n");
2723 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2724 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2725 /* sigh, we can't just set blimits/ilimits */
2726 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2727 .qc_type = qctl.qc_type,
2728 .qc_id = qctl.qc_id};
2730 rc = llapi_quotactl(mnt, &tmp_qctl);
2732 fprintf(stderr, "error: setquota failed while retrieving"
2733 " current quota settings (%s)\n",
2738 if (!(limit_mask & BHLIMIT))
2739 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2740 if (!(limit_mask & BSLIMIT))
2741 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2742 if (!(limit_mask & IHLIMIT))
2743 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2744 if (!(limit_mask & ISLIMIT))
2745 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2747 /* Keep grace times if we have got no softlimit arguments */
2748 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2749 dqb->dqb_valid |= QIF_BTIME;
2750 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2753 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2754 dqb->dqb_valid |= QIF_ITIME;
2755 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2759 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2760 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2762 rc = llapi_quotactl(mnt, &qctl);
2765 fprintf(stderr, "%s %s ", obd_type,
2766 obd_uuid2str(&qctl.obd_uuid));
2767 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2774 static inline char *type2name(int check_type)
2776 if (check_type == USRQUOTA)
2778 else if (check_type == GRPQUOTA)
2784 /* Converts seconds value into format string
2785 * result is returned in buf
2787 * 1. result is in descenting order: 1w2d3h4m5s
2788 * 2. zero fields are not filled (except for p. 3): 5d1s
2789 * 3. zero seconds value is presented as "0s"
2791 static char * __sec2str(time_t seconds, char *buf)
2793 const char spec[] = "smhdw";
2794 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2799 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2800 c = seconds / mult[i];
2802 if (c > 0 || (i == 0 && buf == tail))
2803 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2811 static void sec2str(time_t seconds, char *buf, int rc)
2818 tail = __sec2str(seconds, tail);
2820 if (rc && tail - buf < 39) {
2826 static void diff2str(time_t seconds, char *buf, time_t now)
2832 if (seconds <= now) {
2833 strcpy(buf, "none");
2836 __sec2str(seconds - now, buf);
2839 static void print_quota_title(char *name, struct if_quotactl *qctl,
2840 bool human_readable)
2842 printf("Disk quotas for %s %s (%cid %u):\n",
2843 type2name(qctl->qc_type), name,
2844 *type2name(qctl->qc_type), qctl->qc_id);
2845 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2846 "Filesystem", human_readable ? "used" : "kbytes",
2847 "quota", "limit", "grace",
2848 "files", "quota", "limit", "grace");
2851 static void kbytes2str(__u64 num, char *buf, bool h)
2854 sprintf(buf, LPU64, num);
2857 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2859 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2861 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2863 sprintf(buf, LPU64"%s", num, "k");
2867 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2874 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2875 int bover = 0, iover = 0;
2876 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2881 if (dqb->dqb_bhardlimit &&
2882 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2884 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2885 if (dqb->dqb_btime > now) {
2892 if (dqb->dqb_ihardlimit &&
2893 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2895 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2896 if (dqb->dqb_itime > now) {
2904 if (strlen(mnt) > 15)
2905 printf("%s\n%15s", mnt, "");
2907 printf("%15s", mnt);
2910 diff2str(dqb->dqb_btime, timebuf, now);
2912 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2913 if (rc == -EREMOTEIO)
2914 sprintf(numbuf[0], "%s*", strbuf);
2916 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2917 "%s" : "[%s]", strbuf);
2919 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2920 if (type == QC_GENERAL)
2921 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2922 "%s" : "[%s]", strbuf);
2924 sprintf(numbuf[1], "%s", "-");
2926 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2927 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2928 "%s" : "[%s]", strbuf);
2930 printf(" %7s%c %6s %7s %7s",
2931 numbuf[0], bover ? '*' : ' ', numbuf[1],
2932 numbuf[2], bover > 1 ? timebuf : "-");
2935 diff2str(dqb->dqb_itime, timebuf, now);
2937 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2938 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2940 if (type == QC_GENERAL)
2941 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2942 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2944 sprintf(numbuf[1], "%s", "-");
2946 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2947 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2949 if (type != QC_OSTIDX)
2950 printf(" %7s%c %6s %7s %7s",
2951 numbuf[0], iover ? '*' : ' ', numbuf[1],
2952 numbuf[2], iover > 1 ? timebuf : "-");
2954 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2957 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2958 qctl->qc_cmd == Q_GETOINFO) {
2962 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2963 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2964 printf("Block grace time: %s; Inode grace time: %s\n",
2965 bgtimebuf, igtimebuf);
2969 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2970 bool h, __u64 *total)
2972 int rc = 0, rc1 = 0, count = 0;
2973 __u32 valid = qctl->qc_valid;
2975 rc = llapi_get_obd_count(mnt, &count, is_mdt);
2977 fprintf(stderr, "can not get %s count: %s\n",
2978 is_mdt ? "mdt": "ost", strerror(-rc));
2982 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2983 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2984 rc = llapi_quotactl(mnt, qctl);
2986 /* It is remote client case. */
2987 if (-rc == EOPNOTSUPP) {
2994 fprintf(stderr, "quotactl %s%d failed.\n",
2995 is_mdt ? "mdt": "ost", qctl->qc_idx);
2999 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3000 qctl->qc_valid, 0, h);
3001 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3002 qctl->qc_dqblk.dqb_bhardlimit;
3005 qctl->qc_valid = valid;
3009 static int lfs_quota(int argc, char **argv)
3012 char *mnt, *name = NULL;
3013 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3014 .qc_type = UGQUOTA };
3015 char *obd_type = (char *)qctl.obd_type;
3016 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3017 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3018 verbose = 0, pass = 0, quiet = 0, inacc;
3020 __u32 valid = QC_GENERAL, idx = 0;
3021 __u64 total_ialloc = 0, total_balloc = 0;
3022 bool human_readable = false;
3024 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3027 if (qctl.qc_type != UGQUOTA) {
3028 fprintf(stderr, "error: use either -u or -g\n");
3031 qctl.qc_type = USRQUOTA;
3034 if (qctl.qc_type != UGQUOTA) {
3035 fprintf(stderr, "error: use either -u or -g\n");
3038 qctl.qc_type = GRPQUOTA;
3041 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3044 valid = qctl.qc_valid = QC_UUID;
3045 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3048 valid = qctl.qc_valid = QC_MDTIDX;
3049 idx = qctl.qc_idx = atoi(optarg);
3052 valid = qctl.qc_valid = QC_OSTIDX;
3053 idx = qctl.qc_idx = atoi(optarg);
3062 human_readable = true;
3065 fprintf(stderr, "error: %s: option '-%c' "
3066 "unrecognized\n", argv[0], c);
3071 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3072 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3073 optind == argc - 1) {
3075 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3076 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3077 qctl.qc_valid = valid;
3080 qctl.qc_type = USRQUOTA;
3081 qctl.qc_id = geteuid();
3083 qctl.qc_type = GRPQUOTA;
3084 qctl.qc_id = getegid();
3086 rc = id2name(&name, qctl.qc_id,
3087 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3090 /* lfs quota -u username /path/to/lustre/mount */
3091 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3092 /* options should be followed by u/g-name and mntpoint */
3093 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3094 fprintf(stderr, "error: missing quota argument(s)\n");
3098 name = argv[optind++];
3099 rc = name2id(&qctl.qc_id, name,
3100 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3102 qctl.qc_id = strtoul(name, &endptr, 10);
3103 if (*endptr != '\0') {
3104 fprintf(stderr, "error: can't find id for name "
3109 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3110 fprintf(stderr, "error: missing quota info argument(s)\n");
3116 rc1 = llapi_quotactl(mnt, &qctl);
3120 fprintf(stderr, "%s quotas are not enabled.\n",
3121 qctl.qc_type == USRQUOTA ? "user" : "group");
3124 fprintf(stderr, "Permission denied.\n");
3126 /* We already got a "No such file..." message. */
3129 fprintf(stderr, "Unexpected quotactl error: %s\n",
3134 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3135 print_quota_title(name, &qctl, human_readable);
3137 if (rc1 && *obd_type)
3138 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3140 if (qctl.qc_valid != QC_GENERAL)
3143 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3144 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3145 (QIF_LIMITS|QIF_USAGE));
3147 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3149 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3153 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3155 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3157 kbytes2str(total_balloc, strbuf, human_readable);
3158 printf("Total allocated inode limit: "LPU64", total "
3159 "allocated block limit: %s\n", total_ialloc, strbuf);
3162 if (rc1 || rc2 || rc3 || inacc)
3163 printf("Some errors happened when getting quota info. "
3164 "Some devices may be not working or deactivated. "
3165 "The data in \"[]\" is inaccurate.\n");
3173 #endif /* HAVE_SYS_QUOTA_H! */
3175 static int flushctx_ioctl(char *mp)
3179 fd = open(mp, O_RDONLY);
3181 fprintf(stderr, "flushctx: error open %s: %s\n",
3182 mp, strerror(errno));
3186 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3188 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3189 mp, strerror(errno));
3195 static int lfs_flushctx(int argc, char **argv)
3197 int kdestroy = 0, c;
3198 char mntdir[PATH_MAX] = {'\0'};
3202 while ((c = getopt(argc, argv, "k")) != -1) {
3208 fprintf(stderr, "error: %s: option '-%c' "
3209 "unrecognized\n", argv[0], c);
3215 if ((rc = system("kdestroy > /dev/null")) != 0) {
3216 rc = WEXITSTATUS(rc);
3217 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3221 if (optind >= argc) {
3222 /* flush for all mounted lustre fs. */
3223 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3224 /* Check if we have a mount point */
3225 if (mntdir[0] == '\0')
3228 if (flushctx_ioctl(mntdir))
3231 mntdir[0] = '\0'; /* avoid matching in next loop */
3234 /* flush fs as specified */
3235 while (optind < argc) {
3236 if (flushctx_ioctl(argv[optind++]))
3243 static int lfs_lsetfacl(int argc, char **argv)
3246 return(llapi_lsetfacl(argc, argv));
3249 static int lfs_lgetfacl(int argc, char **argv)
3252 return(llapi_lgetfacl(argc, argv));
3255 static int lfs_rsetfacl(int argc, char **argv)
3258 return(llapi_rsetfacl(argc, argv));
3261 static int lfs_rgetfacl(int argc, char **argv)
3264 return(llapi_rgetfacl(argc, argv));
3267 static int lfs_cp(int argc, char **argv)
3269 return(llapi_cp(argc, argv));
3272 static int lfs_ls(int argc, char **argv)
3274 return(llapi_ls(argc, argv));
3277 static int lfs_changelog(int argc, char **argv)
3279 void *changelog_priv;
3280 struct changelog_rec *rec;
3281 long long startrec = 0, endrec = 0;
3283 struct option long_opts[] = {
3284 {"follow", no_argument, 0, 'f'},
3287 char short_opts[] = "f";
3290 while ((rc = getopt_long(argc, argv, short_opts,
3291 long_opts, NULL)) != -1) {
3299 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3300 argv[0], argv[optind - 1]);
3307 mdd = argv[optind++];
3309 startrec = strtoll(argv[optind++], NULL, 10);
3311 endrec = strtoll(argv[optind++], NULL, 10);
3313 rc = llapi_changelog_start(&changelog_priv,
3314 CHANGELOG_FLAG_BLOCK |
3315 CHANGELOG_FLAG_JOBID |
3316 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3319 fprintf(stderr, "Can't start changelog: %s\n",
3320 strerror(errno = -rc));
3324 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3328 if (endrec && rec->cr_index > endrec) {
3329 llapi_changelog_free(&rec);
3332 if (rec->cr_index < startrec) {
3333 llapi_changelog_free(&rec);
3337 secs = rec->cr_time >> 30;
3338 gmtime_r(&secs, &ts);
3339 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3340 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3341 changelog_type2str(rec->cr_type),
3342 ts.tm_hour, ts.tm_min, ts.tm_sec,
3343 (int)(rec->cr_time & ((1<<30) - 1)),
3344 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3345 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3347 if (rec->cr_flags & CLF_JOBID) {
3348 struct changelog_ext_jobid *jid =
3349 changelog_rec_jobid(rec);
3351 if (jid->cr_jobid[0] != '\0')
3352 printf(" j=%s", jid->cr_jobid);
3355 if (rec->cr_namelen)
3356 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3357 rec->cr_namelen, changelog_rec_name(rec));
3359 if (rec->cr_flags & CLF_RENAME) {
3360 struct changelog_ext_rename *rnm =
3361 changelog_rec_rename(rec);
3363 if (!fid_is_zero(&rnm->cr_sfid))
3364 printf(" s="DFID" sp="DFID" %.*s",
3365 PFID(&rnm->cr_sfid),
3366 PFID(&rnm->cr_spfid),
3367 (int)changelog_rec_snamelen(rec),
3368 changelog_rec_sname(rec));
3372 llapi_changelog_free(&rec);
3375 llapi_changelog_fini(&changelog_priv);
3378 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3380 return (rc == 1 ? 0 : rc);
3383 static int lfs_changelog_clear(int argc, char **argv)
3391 endrec = strtoll(argv[3], NULL, 10);
3393 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3395 fprintf(stderr, "%s error: %s\n", argv[0],
3396 strerror(errno = -rc));
3400 static int lfs_fid2path(int argc, char **argv)
3402 struct option long_opts[] = {
3403 {"cur", no_argument, 0, 'c'},
3404 {"link", required_argument, 0, 'l'},
3405 {"rec", required_argument, 0, 'r'},
3408 char short_opts[] = "cl:r:";
3409 char *device, *fid, *path;
3410 long long recno = -1;
3416 while ((rc = getopt_long(argc, argv, short_opts,
3417 long_opts, NULL)) != -1) {
3423 linkno = strtol(optarg, NULL, 10);
3426 recno = strtoll(optarg, NULL, 10);
3431 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3432 argv[0], argv[optind - 1]);
3440 device = argv[optind++];
3441 path = calloc(1, PATH_MAX);
3443 fprintf(stderr, "error: Not enough memory\n");
3448 while (optind < argc) {
3449 fid = argv[optind++];
3451 lnktmp = (linkno >= 0) ? linkno : 0;
3453 int oldtmp = lnktmp;
3454 long long rectmp = recno;
3456 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3459 fprintf(stderr, "%s: error on FID %s: %s\n",
3460 argv[0], fid, strerror(errno = -rc2));
3467 fprintf(stdout, "%lld ", rectmp);
3468 if (device[0] == '/') {
3469 fprintf(stdout, "%s", device);
3470 if (device[strlen(device) - 1] != '/')
3471 fprintf(stdout, "/");
3472 } else if (path[0] == '\0') {
3473 fprintf(stdout, "/");
3475 fprintf(stdout, "%s\n", path);
3478 /* specified linkno */
3480 if (oldtmp == lnktmp)
3490 static int lfs_path2fid(int argc, char **argv)
3492 struct option long_opts[] = {
3493 {"parents", no_argument, 0, 'p'},
3497 const char short_opts[] = "p";
3498 const char *sep = "";
3501 bool show_parents = false;
3503 while ((rc = getopt_long(argc, argv, short_opts,
3504 long_opts, NULL)) != -1) {
3507 show_parents = true;
3510 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3511 argv[0], argv[optind - 1]);
3516 if (optind > argc - 1)
3518 else if (optind < argc - 1)
3522 for (path = argv + optind; *path != NULL; path++) {
3524 if (!show_parents) {
3525 err = llapi_path2fid(*path, &fid);
3527 printf("%s%s"DFID"\n",
3528 *sep != '\0' ? *path : "", sep,
3531 char name[NAME_MAX + 1];
3532 unsigned int linkno = 0;
3534 while ((err = llapi_path2parent(*path, linkno, &fid,
3535 name, sizeof(name))) == 0) {
3536 if (*sep != '\0' && linkno == 0)
3537 printf("%s%s", *path, sep);
3539 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3544 /* err == -ENODATA is end-of-loop */
3545 if (linkno > 0 && err == -ENODATA) {
3552 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3553 argv[0], show_parents ? "parent " : "", *path,
3565 static int lfs_data_version(int argc, char **argv)
3572 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3577 while ((c = getopt(argc, argv, "nrw")) != -1) {
3580 data_version_flags = 0;
3583 data_version_flags |= LL_DV_RD_FLUSH;
3586 data_version_flags |= LL_DV_WR_FLUSH;
3595 path = argv[optind];
3596 fd = open(path, O_RDONLY);
3598 err(errno, "cannot open file %s", path);
3600 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3602 err(errno, "cannot get version for %s", path);
3604 printf(LPU64 "\n", data_version);
3610 static int lfs_hsm_state(int argc, char **argv)
3615 struct hsm_user_state hus;
3623 rc = llapi_hsm_state_get(path, &hus);
3625 fprintf(stderr, "can't get hsm state for %s: %s\n",
3626 path, strerror(errno = -rc));
3630 /* Display path name and status flags */
3631 printf("%s: (0x%08x)", path, hus.hus_states);
3633 if (hus.hus_states & HS_RELEASED)
3634 printf(" released");
3635 if (hus.hus_states & HS_EXISTS)
3637 if (hus.hus_states & HS_DIRTY)
3639 if (hus.hus_states & HS_ARCHIVED)
3640 printf(" archived");
3641 /* Display user-settable flags */
3642 if (hus.hus_states & HS_NORELEASE)
3643 printf(" never_release");
3644 if (hus.hus_states & HS_NOARCHIVE)
3645 printf(" never_archive");
3646 if (hus.hus_states & HS_LOST)
3647 printf(" lost_from_hsm");
3649 if (hus.hus_archive_id != 0)
3650 printf(", archive_id:%d", hus.hus_archive_id);
3653 } while (++i < argc);
3658 #define LFS_HSM_SET 0
3659 #define LFS_HSM_CLEAR 1
3662 * Generic function to set or clear HSM flags.
3663 * Used by hsm_set and hsm_clear.
3665 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3667 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3669 struct option long_opts[] = {
3670 {"lost", 0, 0, 'l'},
3671 {"norelease", 0, 0, 'r'},
3672 {"noarchive", 0, 0, 'a'},
3673 {"archived", 0, 0, 'A'},
3674 {"dirty", 0, 0, 'd'},
3675 {"exists", 0, 0, 'e'},
3678 char short_opts[] = "lraAde";
3686 while ((c = getopt_long(argc, argv, short_opts,
3687 long_opts, NULL)) != -1) {
3693 mask |= HS_NOARCHIVE;
3696 mask |= HS_ARCHIVED;
3699 mask |= HS_NORELEASE;
3710 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3711 argv[0], argv[optind - 1]);
3716 /* User should have specified a flag */
3720 while (optind < argc) {
3722 path = argv[optind];
3724 /* If mode == 0, this means we apply the mask. */
3725 if (mode == LFS_HSM_SET)
3726 rc = llapi_hsm_state_set(path, mask, 0, 0);
3728 rc = llapi_hsm_state_set(path, 0, mask, 0);
3731 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3732 path, strerror(errno = -rc));
3741 static int lfs_hsm_action(int argc, char **argv)
3746 struct hsm_current_action hca;
3747 struct hsm_extent he;
3748 enum hsm_user_action hua;
3749 enum hsm_progress_states hps;
3757 rc = llapi_hsm_current_action(path, &hca);
3759 fprintf(stderr, "can't get hsm action for %s: %s\n",
3760 path, strerror(errno = -rc));
3763 he = hca.hca_location;
3764 hua = hca.hca_action;
3765 hps = hca.hca_state;
3767 printf("%s: %s", path, hsm_user_action2name(hua));
3769 /* Skip file without action */
3770 if (hca.hca_action == HUA_NONE) {
3775 printf(" %s ", hsm_progress_state2name(hps));
3777 if ((hps == HPS_RUNNING) &&
3778 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3779 printf("(%llu bytes moved)\n",
3780 (unsigned long long)he.length);
3781 else if ((he.offset + he.length) == LUSTRE_EOF)
3782 printf("(from %llu to EOF)\n",
3783 (unsigned long long)he.offset);
3785 printf("(from %llu to %llu)\n",
3786 (unsigned long long)he.offset,
3787 (unsigned long long)(he.offset + he.length));
3789 } while (++i < argc);
3794 static int lfs_hsm_set(int argc, char **argv)
3796 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3799 static int lfs_hsm_clear(int argc, char **argv)
3801 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3805 * Check file state and return its fid, to be used by lfs_hsm_request().
3807 * \param[in] file Path to file to check
3808 * \param[in,out] fid Pointer to allocated lu_fid struct.
3809 * \param[in,out] last_dev Pointer to last device id used.
3811 * \return 0 on success.
3813 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3819 rc = lstat(file, &st);
3821 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3824 /* Checking for regular file as archiving as posix copytool
3825 * rejects archiving files other than regular files
3827 if (!S_ISREG(st.st_mode)) {
3828 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3831 /* A request should be ... */
3832 if (*last_dev != st.st_dev && *last_dev != 0) {
3833 fprintf(stderr, "All files should be "
3834 "on the same filesystem: %s\n", file);
3837 *last_dev = st.st_dev;
3839 rc = llapi_path2fid(file, fid);
3841 fprintf(stderr, "Cannot read FID of %s: %s\n",
3842 file, strerror(-rc));
3848 /* Fill an HSM HUR item with a given file name.
3850 * If mntpath is set, then the filename is actually a FID, and no
3851 * lookup on the filesystem will be performed.
3853 * \param[in] hur the user request to fill
3854 * \param[in] idx index of the item inside the HUR to fill
3855 * \param[in] mntpath mountpoint of Lustre
3856 * \param[in] fname filename (if mtnpath is NULL)
3857 * or FID (if mntpath is set)
3858 * \param[in] last_dev pointer to last device id used
3860 * \retval 0 on success
3861 * \retval CMD_HELP or a negative errno on error
3863 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3864 const char *mntpath, const char *fname,
3867 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3870 hui->hui_extent.length = -1;
3872 if (mntpath != NULL) {
3875 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3879 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3884 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3888 hur->hur_request.hr_itemcount++;
3893 static int lfs_hsm_request(int argc, char **argv, int action)
3895 struct option long_opts[] = {
3896 {"filelist", 1, 0, 'l'},
3897 {"data", 1, 0, 'D'},
3898 {"archive", 1, 0, 'a'},
3899 {"mntpath", 1, 0, 'm'},
3903 char short_opts[] = "l:D:a:m:";
3904 struct hsm_user_request *hur, *oldhur;
3909 char *filelist = NULL;
3910 char fullpath[PATH_MAX];
3911 char *opaque = NULL;
3915 int nbfile_alloc = 0;
3916 char *some_file = NULL;
3917 char *mntpath = NULL;
3923 while ((c = getopt_long(argc, argv, short_opts,
3924 long_opts, NULL)) != -1) {
3933 if (action != HUA_ARCHIVE &&
3934 action != HUA_REMOVE) {
3936 "error: -a is supported only "
3937 "when archiving or removing\n");
3940 archive_id = atoi(optarg);
3943 if (some_file == NULL) {
3945 some_file = strdup(optarg);
3951 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3952 argv[0], argv[optind - 1]);
3957 /* All remaining args are files, so we have at least nbfile */
3958 nbfile = argc - optind;
3960 if ((nbfile == 0) && (filelist == NULL))
3964 opaque_len = strlen(opaque);
3966 /* Alloc the request structure with enough place to store all files
3967 * from command line. */
3968 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3970 fprintf(stderr, "Cannot create the request: %s\n",
3974 nbfile_alloc = nbfile;
3976 hur->hur_request.hr_action = action;
3977 hur->hur_request.hr_archive_id = archive_id;
3978 hur->hur_request.hr_flags = 0;
3980 /* All remaining args are files, add them */
3981 if (nbfile != 0 && some_file == NULL)
3982 some_file = strdup(argv[optind]);
3984 for (i = 0; i < nbfile; i++) {
3985 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
3991 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3993 /* If a filelist was specified, read the filelist from it. */
3994 if (filelist != NULL) {
3995 fp = fopen(filelist, "r");
3997 fprintf(stderr, "Cannot read the file list %s: %s\n",
3998 filelist, strerror(errno));
4003 while ((rc = getline(&line, &len, fp)) != -1) {
4004 /* If allocated buffer was too small, get something
4006 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4009 nbfile_alloc = nbfile_alloc * 2 + 1;
4011 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4014 fprintf(stderr, "hsm: cannot allocate "
4015 "the request: %s\n",
4022 size = hur_len(oldhur);
4024 fprintf(stderr, "hsm: cannot allocate "
4025 "%u files + %u bytes data\n",
4026 oldhur->hur_request.hr_itemcount,
4027 oldhur->hur_request.hr_data_len);
4034 memcpy(hur, oldhur, size);
4039 if (line[strlen(line) - 1] == '\n')
4040 line[strlen(line) - 1] = '\0';
4042 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4043 mntpath, line, &last_dev);
4049 if (some_file == NULL) {
4059 /* If a --data was used, add it to the request */
4060 hur->hur_request.hr_data_len = opaque_len;
4062 memcpy(hur_data(hur), opaque, opaque_len);
4064 /* Send the HSM request */
4065 if (realpath(some_file, fullpath) == NULL) {
4066 fprintf(stderr, "Could not find path '%s': %s\n",
4067 some_file, strerror(errno));
4069 rc = llapi_hsm_request(fullpath, hur);
4071 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4072 some_file, strerror(-rc));
4082 static int lfs_hsm_archive(int argc, char **argv)
4084 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4087 static int lfs_hsm_restore(int argc, char **argv)
4089 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4092 static int lfs_hsm_release(int argc, char **argv)
4094 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4097 static int lfs_hsm_remove(int argc, char **argv)
4099 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4102 static int lfs_hsm_cancel(int argc, char **argv)
4104 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4107 static int lfs_swap_layouts(int argc, char **argv)
4112 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4113 SWAP_LAYOUTS_KEEP_MTIME |
4114 SWAP_LAYOUTS_KEEP_ATIME);
4117 int main(int argc, char **argv)
4121 /* Ensure that liblustreapi constructor has run */
4122 if (!liblustreapi_initialized)
4123 fprintf(stderr, "liblustreapi was not properly initialized\n");
4127 Parser_init("lfs > ", cmdlist);
4129 progname = argv[0]; /* Used in error messages */
4131 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4133 rc = Parser_commands();
4136 return rc < 0 ? -rc : rc;
4139 #ifdef _LUSTRE_IDL_H_
4140 /* Everything we need here should be included by lustreapi.h. */
4141 # error "lfs should not depend on lustre_idl.h"
4142 #endif /* _LUSTRE_IDL_H_ */