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, "migrate file from one OST layout to "
356 "another.\n" MIGRATE_USAGE},
358 "To move directories between MDTs.\n"
359 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
361 {"help", Parser_help, 0, "help"},
362 {"exit", Parser_quit, 0, "quit"},
363 {"quit", Parser_quit, 0, "quit"},
364 {"--version", Parser_version, 0,
365 "output build version of the utility and exit"},
370 #define MIGRATION_BLOCKS 1
373 * Internal helper for migrate_copy_data(). Check lease and report error if
376 * \param[in] fd File descriptor on which to check the lease.
377 * \param[out] lease_broken Set to true if the lease was broken.
378 * \param[in] group_locked Whether a group lock was taken or not.
379 * \param[in] path Name of the file being processed, for error
382 * \retval 0 Migration can keep on going.
383 * \retval -errno Error occurred, abort migration.
385 static int check_lease(int fd, bool *lease_broken, bool group_locked,
390 if (!file_lease_supported)
393 rc = llapi_lease_check(fd);
395 return 0; /* llapi_check_lease returns > 0 on success. */
398 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
400 rc = rc ? rc : -EAGAIN;
402 fprintf(stderr, "%s: external attempt to access file '%s' "
403 "blocked until migration ends.\n", progname, path);
406 *lease_broken = true;
410 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
411 bool group_locked, const char *fname)
420 bool lease_broken = false;
422 /* Use a page-aligned buffer for direct I/O */
423 rc = posix_memalign(&buf, getpagesize(), buf_size);
428 /* read new data only if we have written all
429 * previously read data */
432 rc = check_lease(fd_src, &lease_broken,
433 group_locked, fname);
437 rsize = read(fd_src, buf, buf_size);
440 fprintf(stderr, "%s: %s: read failed: %s\n",
441 progname, fname, strerror(-rc));
451 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
455 "%s: %s: write failed on volatile: %s\n",
456 progname, fname, strerror(-rc));
466 fprintf(stderr, "%s: %s: fsync failed: %s\n",
467 progname, fname, strerror(-rc));
475 static int migrate_copy_timestamps(int fdv, const struct stat *st)
477 struct timeval tv[2] = {
478 {.tv_sec = st->st_atime},
479 {.tv_sec = st->st_mtime}
482 return futimes(fdv, tv);
485 static int migrate_block(int fd, int fdv, const struct stat *st,
486 size_t buf_size, const char *name)
493 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
495 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
496 progname, name, strerror(-rc));
504 /* The grouplock blocks all concurrent accesses to the file.
505 * It has to be taken after llapi_get_data_version as it would
507 rc = llapi_group_lock(fd, gid);
509 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
510 progname, name, strerror(-rc));
514 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
516 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
520 /* Make sure we keep original atime/mtime values */
521 rc = migrate_copy_timestamps(fdv, st);
523 fprintf(stderr, "%s: %s: timestamp copy failed\n",
529 * for a migration we need to check data version on file did
532 * Pass in gid=0 since we already own grouplock. */
533 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
534 SWAP_LAYOUTS_CHECK_DV1);
536 fprintf(stderr, "%s: %s: dataversion changed during copy, "
537 "migration aborted\n", progname, name);
540 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
541 name, strerror(-rc));
546 rc2 = llapi_group_unlock(fd, gid);
547 if (rc2 < 0 && rc == 0) {
548 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
549 progname, name, strerror(-rc2));
556 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
557 size_t buf_size, const char *name)
563 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
565 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
566 progname, name, strerror(-rc));
570 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
572 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
576 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
578 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
579 progname, name, strerror(-rc));
585 fprintf(stderr, "%s: %s: data version changed during "
591 /* Make sure we keep original atime/mtime values */
592 rc = migrate_copy_timestamps(fdv, st);
594 fprintf(stderr, "%s: %s: timestamp copy failed\n",
599 /* Atomically put lease, swap layouts and close.
600 * for a migration we need to check data version on file did
602 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
604 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
605 progname, name, strerror(-rc));
612 static int lfs_migrate(char *name, __u64 migration_flags,
613 struct llapi_stripe_param *param)
617 char volatile_file[PATH_MAX +
618 LUSTRE_VOLATILE_HDR_LEN + 4];
619 char parent[PATH_MAX];
622 struct lov_user_md *lum = NULL;
625 bool have_lease_rdlck = false;
629 /* find the right size for the IO and allocate the buffer */
630 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
631 lum = malloc(lum_size);
637 rc = llapi_file_get_stripe(name, lum);
638 /* failure can happen for many reasons and some may be not real errors
640 * in case of a real error, a later call will fail with better
641 * error management */
643 buf_size = 1024 * 1024;
645 buf_size = lum->lmm_stripe_size;
647 /* open file, direct io */
648 /* even if the file is only read, WR mode is nedeed to allow
649 * layout swap on fd */
650 fd = open(name, O_RDWR | O_DIRECT);
653 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
658 if (file_lease_supported) {
659 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
660 if (rc == -EOPNOTSUPP) {
661 /* Older servers do not support file lease.
662 * Disable related checks. This opens race conditions
663 * as explained in LU-4840 */
664 file_lease_supported = false;
666 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
667 progname, name, strerror(-rc));
670 have_lease_rdlck = true;
674 /* search for file directory pathname */
675 if (strlen(name) > sizeof(parent)-1) {
679 strncpy(parent, name, sizeof(parent));
680 ptr = strrchr(parent, '/');
682 if (getcwd(parent, sizeof(parent)) == NULL) {
693 rc = snprintf(volatile_file, sizeof(volatile_file), "%s/%s::", parent,
694 LUSTRE_VOLATILE_HDR);
695 if (rc >= sizeof(volatile_file)) {
700 /* create, open a volatile file, use caching (ie no directio) */
701 /* exclusive create is not needed because volatile files cannot
702 * conflict on name by construction */
703 fdv = llapi_file_open_param(volatile_file, O_CREAT | O_WRONLY, 0644,
707 fprintf(stderr, "%s: %s: cannot create volatile file in"
709 progname, parent, strerror(-rc));
713 /* Not-owner (root?) special case.
714 * Need to set owner/group of volatile file like original.
715 * This will allow to pass related check during layout_swap.
720 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
724 rc = fstat(fdv, &stv);
727 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
728 volatile_file, strerror(errno));
731 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
732 rc = fchown(fdv, st.st_uid, st.st_gid);
735 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
736 name, strerror(errno));
741 if (migration_flags & MIGRATION_BLOCKS || !file_lease_supported) {
742 /* Blocking mode, forced if servers do not support file lease */
743 rc = migrate_block(fd, fdv, &st, buf_size, name);
745 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
747 have_lease_rdlck = false;
748 fdv = -1; /* The volatile file is closed as we put the
749 * lease in non-blocking mode. */
754 if (have_lease_rdlck)
771 * Parse a string containing an OST index list into an array of integers.
773 * The input string contains a comma delimited list of individual
774 * indices and ranges, for example "1,2-4,7". Add the indices into the
775 * \a osts array and remove duplicates.
777 * \param[out] osts array to store indices in
778 * \param[in] size size of \a osts array
779 * \param[in] offset starting index in \a osts
780 * \param[in] arg string containing OST index list
782 * \retval positive number of indices in \a osts
783 * \retval -EINVAL unable to parse \a arg
785 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
789 int slots = size - offset;
797 while (!end_of_loop) {
805 ptr = strchrnul(arg, ',');
807 end_of_loop = *ptr == '\0';
810 start_index = strtol(arg, &endptr, 0);
811 if (endptr == arg) /* no data at all */
813 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
818 end_index = start_index;
819 if (*endptr == '-') {
820 end_index = strtol(endptr + 1, &endptr, 0);
823 if (end_index < start_index)
827 for (i = start_index; i <= end_index && slots > 0; i++) {
830 /* remove duplicate */
831 for (j = 0; j < offset; j++) {
835 if (j == offset) { /* no duplicate */
840 if (slots == 0 && i < end_index)
848 if (!end_of_loop && ptr != NULL)
851 return rc < 0 ? rc : nr;
855 static int lfs_setstripe(int argc, char **argv)
857 struct llapi_stripe_param *param;
861 unsigned long long st_size;
862 int st_offset, st_count;
866 char *stripe_size_arg = NULL;
867 char *stripe_off_arg = NULL;
868 char *stripe_count_arg = NULL;
869 char *pool_name_arg = NULL;
870 unsigned long long size_units = 1;
871 bool migrate_mode = false;
872 __u64 migration_flags = 0;
873 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
876 struct option long_opts[] = {
877 /* valid only in migrate mode */
878 {"block", no_argument, 0, 'b'},
879 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
880 /* This formerly implied "stripe-count", but was explicitly
881 * made "stripe-count" for consistency with other options,
882 * and to separate it from "mdt-count" when DNE arrives. */
883 {"count", required_argument, 0, 'c'},
885 {"stripe-count", required_argument, 0, 'c'},
886 {"stripe_count", required_argument, 0, 'c'},
887 {"delete", no_argument, 0, 'd'},
888 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
889 /* This formerly implied "stripe-index", but was explicitly
890 * made "stripe-index" for consistency with other options,
891 * and to separate it from "mdt-index" when DNE arrives. */
892 {"index", required_argument, 0, 'i'},
894 {"stripe-index", required_argument, 0, 'i'},
895 {"stripe_index", required_argument, 0, 'i'},
896 {"ost-list", required_argument, 0, 'o'},
897 {"ost_list", required_argument, 0, 'o'},
898 {"pool", required_argument, 0, 'p'},
899 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
900 /* This formerly implied "--stripe-size", but was confusing
901 * with "lfs find --size|-s", which means "file size", so use
902 * the consistent "--stripe-size|-S" for all commands. */
903 {"size", required_argument, 0, 's'},
905 {"stripe-size", required_argument, 0, 'S'},
906 {"stripe_size", required_argument, 0, 'S'},
914 if (strcmp(argv[0], "migrate") == 0)
917 while ((c = getopt_long(argc, argv, "bc:di:o:p:s:S:",
918 long_opts, NULL)) >= 0) {
925 fprintf(stderr, "--block is valid only for"
929 migration_flags |= MIGRATION_BLOCKS;
932 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
933 if (strcmp(argv[optind - 1], "--count") == 0)
934 fprintf(stderr, "warning: '--count' deprecated"
935 ", use '--stripe-count' instead\n");
937 stripe_count_arg = optarg;
940 /* delete the default striping pattern */
944 nr_osts = parse_targets(osts,
945 sizeof(osts) / sizeof(__u32),
949 "error: %s: bad OST indices '%s'\n",
954 if (st_offset == -1) /* first in the command line */
958 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
959 if (strcmp(argv[optind - 1], "--index") == 0)
960 fprintf(stderr, "warning: '--index' deprecated"
961 ", use '--stripe-index' instead\n");
963 stripe_off_arg = optarg;
965 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
967 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
968 fprintf(stderr, "warning: '--size|-s' deprecated, "
969 "use '--stripe-size|-S' instead\n");
971 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
973 stripe_size_arg = optarg;
976 pool_name_arg = optarg;
983 fname = argv[optind];
986 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
987 stripe_count_arg != NULL || pool_name_arg != NULL)) {
988 fprintf(stderr, "error: %s: cannot specify -d with "
989 "-s, -c, -o, or -p options\n",
994 if (optind == argc) {
995 fprintf(stderr, "error: %s: missing filename|dirname\n",
1000 if (pool_name_arg && strlen(pool_name_arg) > LOV_MAXPOOLNAME) {
1002 "error: %s: pool name '%s' is too long (max is %d characters)\n",
1003 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1007 /* get the stripe size */
1008 if (stripe_size_arg != NULL) {
1009 result = llapi_parse_size(stripe_size_arg, &st_size,
1012 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1013 argv[0], stripe_size_arg);
1017 /* get the stripe offset */
1018 if (stripe_off_arg != NULL) {
1019 st_offset = strtol(stripe_off_arg, &end, 0);
1021 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1022 argv[0], stripe_off_arg);
1026 /* get the stripe count */
1027 if (stripe_count_arg != NULL) {
1028 st_count = strtoul(stripe_count_arg, &end, 0);
1030 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1031 argv[0], stripe_count_arg);
1036 /* initialize stripe parameters */
1037 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1038 if (param == NULL) {
1039 fprintf(stderr, "error: %s: run out of memory\n", argv[0]);
1043 param->lsp_stripe_size = st_size;
1044 param->lsp_stripe_offset = st_offset;
1045 param->lsp_stripe_count = st_count;
1046 param->lsp_stripe_pattern = 0;
1047 param->lsp_pool = pool_name_arg;
1048 param->lsp_is_specific = false;
1050 if (st_count > 0 && nr_osts != st_count) {
1051 fprintf(stderr, "error: %s: stripe count '%d' doesn't "
1052 "match the number of OSTs: %d\n",
1053 argv[0], st_count, nr_osts);
1058 param->lsp_is_specific = true;
1059 param->lsp_stripe_count = nr_osts;
1060 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1063 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1065 result = lfs_migrate(fname, migration_flags, param);
1067 result = llapi_file_open_param(fname,
1076 /* Save the first error encountered. */
1080 "error: %s: %s stripe file '%s' failed\n",
1081 argv[0], migrate_mode ? "migrate" : "create",
1091 static int lfs_poollist(int argc, char **argv)
1096 return llapi_poollist(argv[1]);
1099 static int set_time(time_t *time, time_t *set, char *str)
1106 else if (str[0] == '-')
1112 t = strtol(str, NULL, 0);
1113 if (*time < t * 24 * 60 * 60) {
1116 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1120 *set = *time - t * 24 * 60 * 60;
1127 static int name2id(unsigned int *id, char *name, int type)
1130 struct passwd *entry;
1132 if (!(entry = getpwnam(name))) {
1138 *id = entry->pw_uid;
1140 struct group *entry;
1142 if (!(entry = getgrnam(name))) {
1148 *id = entry->gr_gid;
1154 static int id2name(char **name, unsigned int id, int type)
1157 struct passwd *entry;
1159 if (!(entry = getpwuid(id))) {
1165 *name = entry->pw_name;
1167 struct group *entry;
1169 if (!(entry = getgrgid(id))) {
1175 *name = entry->gr_name;
1181 static int name2layout(__u32 *layout, char *name)
1186 for (ptr = name; ; ptr = NULL) {
1187 lyt = strtok(ptr, ",");
1190 if (strcmp(lyt, "released") == 0)
1191 *layout |= LOV_PATTERN_F_RELEASED;
1192 else if (strcmp(lyt, "raid0") == 0)
1193 *layout |= LOV_PATTERN_RAID0;
1200 #define FIND_POOL_OPT 3
1201 static int lfs_find(int argc, char **argv)
1206 struct find_param param = {
1210 struct option long_opts[] = {
1211 {"atime", required_argument, 0, 'A'},
1212 {"stripe-count", required_argument, 0, 'c'},
1213 {"stripe_count", required_argument, 0, 'c'},
1214 {"ctime", required_argument, 0, 'C'},
1215 {"maxdepth", required_argument, 0, 'D'},
1216 {"gid", required_argument, 0, 'g'},
1217 {"group", required_argument, 0, 'G'},
1218 {"stripe-index", required_argument, 0, 'i'},
1219 {"stripe_index", required_argument, 0, 'i'},
1220 {"layout", required_argument, 0, 'L'},
1221 {"mdt", required_argument, 0, 'm'},
1222 {"mtime", required_argument, 0, 'M'},
1223 {"name", required_argument, 0, 'n'},
1224 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1225 {"obd", required_argument, 0, 'O'},
1226 {"ost", required_argument, 0, 'O'},
1227 /* no short option for pool, p/P already used */
1228 {"pool", required_argument, 0, FIND_POOL_OPT},
1229 {"print0", no_argument, 0, 'p'},
1230 {"print", no_argument, 0, 'P'},
1231 {"size", required_argument, 0, 's'},
1232 {"stripe-size", required_argument, 0, 'S'},
1233 {"stripe_size", required_argument, 0, 'S'},
1234 {"type", required_argument, 0, 't'},
1235 {"uid", required_argument, 0, 'u'},
1236 {"user", required_argument, 0, 'U'},
1249 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1250 while ((c = getopt_long_only(argc, argv,
1251 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1252 long_opts, NULL)) >= 0) {
1257 /* '!' is part of option */
1258 /* when getopt_long_only() finds a string which is not
1259 * an option nor a known option argument it returns 1
1260 * in that case if we already have found pathstart and pathend
1261 * (i.e. we have the list of pathnames),
1262 * the only supported value is "!"
1264 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1265 if (!isoption && pathend != -1) {
1266 fprintf(stderr, "err: %s: filename|dirname must either "
1267 "precede options or follow options\n",
1272 if (!isoption && pathstart == -1)
1273 pathstart = optind - 1;
1274 if (isoption && pathstart != -1 && pathend == -1)
1275 pathend = optind - 2;
1281 /* unknown; opt is "!" or path component,
1282 * checking done above.
1284 if (strcmp(optarg, "!") == 0)
1288 xtime = ¶m.fp_atime;
1289 xsign = ¶m.fp_asign;
1290 param.fp_exclude_atime = !!neg_opt;
1291 /* no break, this falls through to 'C' for ctime */
1294 xtime = ¶m.fp_ctime;
1295 xsign = ¶m.fp_csign;
1296 param.fp_exclude_ctime = !!neg_opt;
1298 /* no break, this falls through to 'M' for mtime */
1301 xtime = ¶m.fp_mtime;
1302 xsign = ¶m.fp_msign;
1303 param.fp_exclude_mtime = !!neg_opt;
1305 rc = set_time(&t, xtime, optarg);
1306 if (rc == INT_MAX) {
1314 if (optarg[0] == '+') {
1315 param.fp_stripe_count_sign = -1;
1317 } else if (optarg[0] == '-') {
1318 param.fp_stripe_count_sign = 1;
1322 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1323 if (*endptr != '\0') {
1324 fprintf(stderr,"error: bad stripe_count '%s'\n",
1329 param.fp_check_stripe_count = 1;
1330 param.fp_exclude_stripe_count = !!neg_opt;
1333 param.fp_max_depth = strtol(optarg, 0, 0);
1337 rc = name2id(¶m.fp_gid, optarg, GROUP);
1339 param.fp_gid = strtoul(optarg, &endptr, 10);
1340 if (*endptr != '\0') {
1341 fprintf(stderr, "Group/GID: %s cannot "
1342 "be found.\n", optarg);
1347 param.fp_exclude_gid = !!neg_opt;
1348 param.fp_check_gid = 1;
1351 ret = name2layout(¶m.fp_layout, optarg);
1354 param.fp_exclude_layout = !!neg_opt;
1355 param.fp_check_layout = 1;
1359 rc = name2id(¶m.fp_uid, optarg, USER);
1361 param.fp_uid = strtoul(optarg, &endptr, 10);
1362 if (*endptr != '\0') {
1363 fprintf(stderr, "User/UID: %s cannot "
1364 "be found.\n", optarg);
1369 param.fp_exclude_uid = !!neg_opt;
1370 param.fp_check_uid = 1;
1373 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1375 "Pool name %s is too long"
1376 " (max is %d)\n", optarg,
1381 /* we do check for empty pool because empty pool
1382 * is used to find V1 lov attributes */
1383 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1384 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1385 param.fp_exclude_pool = !!neg_opt;
1386 param.fp_check_pool = 1;
1389 param.fp_pattern = (char *)optarg;
1390 param.fp_exclude_pattern = !!neg_opt;
1395 char *buf, *token, *next, *p;
1399 buf = strdup(optarg);
1405 param.fp_exclude_obd = !!neg_opt;
1408 while (token && *token) {
1409 token = strchr(token, ',');
1416 param.fp_exclude_mdt = !!neg_opt;
1417 param.fp_num_alloc_mdts += len;
1418 tmp = realloc(param.fp_mdt_uuid,
1419 param.fp_num_alloc_mdts *
1420 sizeof(*param.fp_mdt_uuid));
1426 param.fp_mdt_uuid = tmp;
1428 param.fp_exclude_obd = !!neg_opt;
1429 param.fp_num_alloc_obds += len;
1430 tmp = realloc(param.fp_obd_uuid,
1431 param.fp_num_alloc_obds *
1432 sizeof(*param.fp_obd_uuid));
1438 param.fp_obd_uuid = tmp;
1440 for (token = buf; token && *token; token = next) {
1441 struct obd_uuid *puuid;
1444 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1447 ¶m.fp_obd_uuid[param.fp_num_obds++];
1449 p = strchr(token, ',');
1456 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1461 strncpy(puuid->uuid, token,
1462 sizeof(puuid->uuid));
1470 param.fp_zero_end = 1;
1475 if (optarg[0] == '+') {
1476 param.fp_size_sign = -1;
1478 } else if (optarg[0] == '-') {
1479 param.fp_size_sign = 1;
1483 ret = llapi_parse_size(optarg, ¶m.fp_size,
1484 ¶m.fp_size_units, 0);
1486 fprintf(stderr, "error: bad file size '%s'\n",
1490 param.fp_check_size = 1;
1491 param.fp_exclude_size = !!neg_opt;
1494 if (optarg[0] == '+') {
1495 param.fp_stripe_size_sign = -1;
1497 } else if (optarg[0] == '-') {
1498 param.fp_stripe_size_sign = 1;
1502 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1503 ¶m.fp_stripe_size_units, 0);
1505 fprintf(stderr, "error: bad stripe_size '%s'\n",
1509 param.fp_check_stripe_size = 1;
1510 param.fp_exclude_stripe_size = !!neg_opt;
1513 param.fp_exclude_type = !!neg_opt;
1514 switch (optarg[0]) {
1516 param.fp_type = S_IFBLK;
1519 param.fp_type = S_IFCHR;
1522 param.fp_type = S_IFDIR;
1525 param.fp_type = S_IFREG;
1528 param.fp_type = S_IFLNK;
1531 param.fp_type = S_IFIFO;
1534 param.fp_type = S_IFSOCK;
1537 fprintf(stderr, "error: %s: bad type '%s'\n",
1549 if (pathstart == -1) {
1550 fprintf(stderr, "error: %s: no filename|pathname\n",
1554 } else if (pathend == -1) {
1560 rc = llapi_find(argv[pathstart], ¶m);
1561 if (rc != 0 && ret == 0)
1563 } while (++pathstart < pathend);
1566 fprintf(stderr, "error: %s failed for %s.\n",
1567 argv[0], argv[optind - 1]);
1569 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1570 free(param.fp_obd_uuid);
1572 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1573 free(param.fp_mdt_uuid);
1578 static int lfs_getstripe_internal(int argc, char **argv,
1579 struct find_param *param)
1581 struct option long_opts[] = {
1582 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1583 /* This formerly implied "stripe-count", but was explicitly
1584 * made "stripe-count" for consistency with other options,
1585 * and to separate it from "mdt-count" when DNE arrives. */
1586 {"count", no_argument, 0, 'c'},
1588 {"stripe-count", no_argument, 0, 'c'},
1589 {"stripe_count", no_argument, 0, 'c'},
1590 {"directory", no_argument, 0, 'd'},
1591 {"default", no_argument, 0, 'D'},
1592 {"generation", no_argument, 0, 'g'},
1593 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1594 /* This formerly implied "stripe-index", but was explicitly
1595 * made "stripe-index" for consistency with other options,
1596 * and to separate it from "mdt-index" when DNE arrives. */
1597 {"index", no_argument, 0, 'i'},
1599 {"stripe-index", no_argument, 0, 'i'},
1600 {"stripe_index", no_argument, 0, 'i'},
1601 {"layout", no_argument, 0, 'L'},
1602 {"mdt-index", no_argument, 0, 'M'},
1603 {"mdt_index", no_argument, 0, 'M'},
1604 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1605 /* This formerly implied "stripe-index", but was confusing
1606 * with "file offset" (which will eventually be needed for
1607 * with different layouts by offset), so deprecate it. */
1608 {"offset", no_argument, 0, 'o'},
1610 {"obd", required_argument, 0, 'O'},
1611 {"ost", required_argument, 0, 'O'},
1612 {"pool", no_argument, 0, 'p'},
1613 {"quiet", no_argument, 0, 'q'},
1614 {"recursive", no_argument, 0, 'r'},
1615 {"raw", no_argument, 0, 'R'},
1616 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1617 /* This formerly implied "--stripe-size", but was confusing
1618 * with "lfs find --size|-s", which means "file size", so use
1619 * the consistent "--stripe-size|-S" for all commands. */
1620 {"size", no_argument, 0, 's'},
1622 {"stripe-size", no_argument, 0, 'S'},
1623 {"stripe_size", no_argument, 0, 'S'},
1624 {"verbose", no_argument, 0, 'v'},
1629 param->fp_max_depth = 1;
1630 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1631 long_opts, NULL)) != -1) {
1634 if (param->fp_obd_uuid) {
1636 "error: %s: only one obduuid allowed",
1640 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1646 param->fp_max_depth = 0;
1649 param->fp_get_default_lmv = 1;
1652 param->fp_recursive = 1;
1655 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1658 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1659 if (strcmp(argv[optind - 1], "--count") == 0)
1660 fprintf(stderr, "warning: '--count' deprecated,"
1661 " use '--stripe-count' instead\n");
1663 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1664 param->fp_verbose |= VERBOSE_COUNT;
1665 param->fp_max_depth = 0;
1668 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1670 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1671 fprintf(stderr, "warning: '--size|-s' deprecated, "
1672 "use '--stripe-size|-S' instead\n");
1674 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1676 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1677 param->fp_verbose |= VERBOSE_SIZE;
1678 param->fp_max_depth = 0;
1681 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1683 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1684 "use '--stripe-index|-i' instead\n");
1687 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1688 if (strcmp(argv[optind - 1], "--index") == 0)
1689 fprintf(stderr, "warning: '--index' deprecated"
1690 ", use '--stripe-index' instead\n");
1692 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1693 param->fp_verbose |= VERBOSE_OFFSET;
1694 param->fp_max_depth = 0;
1698 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1699 param->fp_verbose |= VERBOSE_POOL;
1700 param->fp_max_depth = 0;
1704 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1705 param->fp_verbose |= VERBOSE_GENERATION;
1706 param->fp_max_depth = 0;
1710 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1711 param->fp_verbose |= VERBOSE_LAYOUT;
1712 param->fp_max_depth = 0;
1716 if (!(param->fp_verbose & VERBOSE_DETAIL))
1717 param->fp_max_depth = 0;
1718 param->fp_verbose |= VERBOSE_MDTINDEX;
1731 if (param->fp_recursive)
1732 param->fp_max_depth = -1;
1734 if (!param->fp_verbose)
1735 param->fp_verbose = VERBOSE_ALL;
1736 if (param->fp_quiet)
1737 param->fp_verbose = VERBOSE_OBJID;
1740 rc = llapi_getstripe(argv[optind], param);
1741 } while (++optind < argc && !rc);
1744 fprintf(stderr, "error: %s failed for %s.\n",
1745 argv[0], argv[optind - 1]);
1749 static int lfs_tgts(int argc, char **argv)
1751 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1752 struct find_param param;
1753 int index = 0, rc=0;
1758 if (argc == 2 && !realpath(argv[1], path)) {
1760 fprintf(stderr, "error: invalid path '%s': %s\n",
1761 argv[1], strerror(-rc));
1765 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1766 /* Check if we have a mount point */
1767 if (mntdir[0] == '\0')
1770 memset(¶m, 0, sizeof(param));
1771 if (!strcmp(argv[0], "mdts"))
1772 param.fp_get_lmv = 1;
1774 rc = llapi_ostlist(mntdir, ¶m);
1776 fprintf(stderr, "error: %s: failed on %s\n",
1779 if (path[0] != '\0')
1781 memset(mntdir, 0, PATH_MAX);
1787 static int lfs_getstripe(int argc, char **argv)
1789 struct find_param param = { 0 };
1790 return lfs_getstripe_internal(argc, argv, ¶m);
1794 static int lfs_getdirstripe(int argc, char **argv)
1796 struct find_param param = { 0 };
1798 param.fp_get_lmv = 1;
1799 return lfs_getstripe_internal(argc, argv, ¶m);
1803 static int lfs_setdirstripe(int argc, char **argv)
1807 unsigned int stripe_offset = -1;
1808 unsigned int stripe_count = 1;
1809 enum lmv_hash_type hash_type;
1812 char *stripe_offset_opt = NULL;
1813 char *stripe_count_opt = NULL;
1814 char *stripe_hash_opt = NULL;
1815 char *mode_opt = NULL;
1816 bool default_stripe = false;
1817 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1818 mode_t previous_mode = 0;
1819 bool delete = false;
1821 struct option long_opts[] = {
1822 {"count", required_argument, 0, 'c'},
1823 {"delete", no_argument, 0, 'd'},
1824 {"index", required_argument, 0, 'i'},
1825 {"mode", required_argument, 0, 'm'},
1826 {"hash-type", required_argument, 0, 't'},
1827 {"default_stripe", no_argument, 0, 'D'},
1831 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1838 stripe_count_opt = optarg;
1842 default_stripe = true;
1845 default_stripe = true;
1848 stripe_offset_opt = optarg;
1854 stripe_hash_opt = optarg;
1857 fprintf(stderr, "error: %s: option '%s' "
1859 argv[0], argv[optind - 1]);
1864 if (optind == argc) {
1865 fprintf(stderr, "error: %s: missing dirname\n",
1870 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1871 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1876 if (stripe_offset_opt != NULL) {
1877 /* get the stripe offset */
1878 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1880 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1881 argv[0], stripe_offset_opt);
1887 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1888 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1889 " or -i options.\n", argv[0]);
1897 if (mode_opt != NULL) {
1898 mode = strtoul(mode_opt, &end, 8);
1900 fprintf(stderr, "error: %s: bad mode '%s'\n",
1904 previous_mode = umask(0);
1907 if (stripe_hash_opt == NULL ||
1908 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1909 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1910 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1911 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1913 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1914 argv[0], stripe_hash_opt);
1918 /* get the stripe count */
1919 if (stripe_count_opt != NULL) {
1920 stripe_count = strtoul(stripe_count_opt, &end, 0);
1922 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1923 argv[0], stripe_count_opt);
1928 dname = argv[optind];
1930 if (default_stripe) {
1931 result = llapi_dir_set_default_lmv_stripe(dname,
1932 stripe_offset, stripe_count,
1935 result = llapi_dir_create_pool(dname, mode,
1937 stripe_count, hash_type,
1942 fprintf(stderr, "error: %s: create stripe dir '%s' "
1943 "failed\n", argv[0], dname);
1946 dname = argv[++optind];
1947 } while (dname != NULL);
1949 if (mode_opt != NULL)
1950 umask(previous_mode);
1956 static int lfs_rmentry(int argc, char **argv)
1963 fprintf(stderr, "error: %s: missing dirname\n",
1969 dname = argv[index];
1970 while (dname != NULL) {
1971 result = llapi_direntry_remove(dname);
1973 fprintf(stderr, "error: %s: remove dir entry '%s' "
1974 "failed\n", argv[0], dname);
1977 dname = argv[++index];
1982 static int lfs_mv(int argc, char **argv)
1984 struct find_param param = {
1991 struct option long_opts[] = {
1992 {"mdt-index", required_argument, 0, 'M'},
1993 {"verbose", no_argument, 0, 'v'},
1997 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2000 param.fp_mdt_index = strtoul(optarg, &end, 0);
2002 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2009 param.fp_verbose = VERBOSE_DETAIL;
2013 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2014 argv[0], argv[optind - 1]);
2019 if (param.fp_mdt_index == -1) {
2020 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2024 if (optind >= argc) {
2025 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2029 param.fp_migrate = 1;
2030 rc = llapi_mv(argv[optind], ¶m);
2032 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2033 argv[0], argv[optind], param.fp_mdt_index,
2038 static int lfs_osts(int argc, char **argv)
2040 return lfs_tgts(argc, argv);
2043 static int lfs_mdts(int argc, char **argv)
2045 return lfs_tgts(argc, argv);
2048 #define COOK(value) \
2051 while (value > 1024) { \
2059 #define CDF "%11llu"
2060 #define HDF "%8.1f%c"
2064 static int showdf(char *mntdir, struct obd_statfs *stat,
2065 char *uuid, int ishow, int cooked,
2066 char *type, int index, int rc)
2068 long long avail, used, total;
2070 char *suffix = "KMGTPEZY";
2071 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2072 char tbuf[3 * sizeof(__u64)];
2073 char ubuf[3 * sizeof(__u64)];
2074 char abuf[3 * sizeof(__u64)];
2075 char rbuf[3 * sizeof(__u64)];
2083 avail = stat->os_ffree;
2084 used = stat->os_files - stat->os_ffree;
2085 total = stat->os_files;
2087 int shift = cooked ? 0 : 10;
2089 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2090 used = ((stat->os_blocks - stat->os_bfree) *
2091 stat->os_bsize) >> shift;
2092 total = (stat->os_blocks * stat->os_bsize) >> shift;
2095 if ((used + avail) > 0)
2096 ratio = (double)used / (double)(used + avail);
2102 cook_val = (double)total;
2105 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2107 sprintf(tbuf, CDF, total);
2109 cook_val = (double)used;
2112 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2114 sprintf(ubuf, CDF, used);
2116 cook_val = (double)avail;
2119 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2121 sprintf(abuf, CDF, avail);
2123 sprintf(tbuf, CDF, total);
2124 sprintf(ubuf, CDF, used);
2125 sprintf(abuf, CDF, avail);
2128 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2129 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2130 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2132 printf("[%s:%d]\n", type, index);
2138 printf(UUF": inactive device\n", uuid);
2141 printf(UUF": %s\n", uuid, strerror(-rc));
2148 struct ll_stat_type {
2153 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2154 int cooked, int lazy)
2156 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2157 struct obd_uuid uuid_buf;
2158 char *poolname = NULL;
2159 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2160 { LL_STATFS_LOV, "OST" },
2162 struct ll_stat_type *tp;
2163 __u64 ost_ffree = 0;
2169 poolname = strchr(pool, '.');
2170 if (poolname != NULL) {
2171 if (strncmp(fsname, pool, strlen(fsname))) {
2172 fprintf(stderr, "filesystem name incorrect\n");
2181 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2182 "UUID", "Inodes", "IUsed", "IFree",
2183 "IUse%", "Mounted on");
2185 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2186 "UUID", cooked ? "bytes" : "1K-blocks",
2187 "Used", "Available", "Use%", "Mounted on");
2189 for (tp = types; tp->st_name != NULL; tp++) {
2190 for (index = 0; ; index++) {
2191 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2192 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2193 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2194 rc = llapi_obd_statfs(mntdir, type, index,
2195 &stat_buf, &uuid_buf);
2202 if (poolname && tp->st_op == LL_STATFS_LOV &&
2203 llapi_search_ost(fsname, poolname,
2204 obd_uuid2str(&uuid_buf)) != 1)
2207 /* the llapi_obd_statfs() call may have returned with
2208 * an error, but if it filled in uuid_buf we will at
2209 * lease use that to print out a message for that OBD.
2210 * If we didn't get anything in the uuid_buf, then fill
2211 * it in so that we can print an error message. */
2212 if (uuid_buf.uuid[0] == '\0')
2213 sprintf(uuid_buf.uuid, "%s%04x",
2214 tp->st_name, index);
2215 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2216 ishow, cooked, tp->st_name, index, rc);
2219 if (tp->st_op == LL_STATFS_LMV) {
2220 sum.os_ffree += stat_buf.os_ffree;
2221 sum.os_files += stat_buf.os_files;
2222 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2223 sum.os_blocks += stat_buf.os_blocks *
2225 sum.os_bfree += stat_buf.os_bfree *
2227 sum.os_bavail += stat_buf.os_bavail *
2229 ost_ffree += stat_buf.os_ffree;
2231 } else if (rc == -EINVAL || rc == -EFAULT) {
2237 /* If we don't have as many objects free on the OST as inodes
2238 * on the MDS, we reduce the total number of inodes to
2239 * compensate, so that the "inodes in use" number is correct.
2240 * Matches ll_statfs_internal() so the results are consistent. */
2241 if (ost_ffree < sum.os_ffree) {
2242 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2243 sum.os_ffree = ost_ffree;
2246 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2251 static int lfs_df(int argc, char **argv)
2253 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2254 int ishow = 0, cooked = 0;
2256 int c, rc = 0, index = 0;
2257 char fsname[PATH_MAX] = "", *pool_name = NULL;
2258 struct option long_opts[] = {
2259 {"pool", required_argument, 0, 'p'},
2260 {"lazy", 0, 0, 'l'},
2264 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2282 if (optind < argc && !realpath(argv[optind], path)) {
2284 fprintf(stderr, "error: invalid path '%s': %s\n",
2285 argv[optind], strerror(-rc));
2289 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2290 /* Check if we have a mount point */
2291 if (mntdir[0] == '\0')
2294 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2295 if (rc || path[0] != '\0')
2297 fsname[0] = '\0'; /* avoid matching in next loop */
2298 mntdir[0] = '\0'; /* avoid matching in next loop */
2304 static int lfs_getname(int argc, char **argv)
2306 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2307 int rc = 0, index = 0, c;
2308 char buf[sizeof(struct obd_uuid)];
2310 while ((c = getopt(argc, argv, "h")) != -1)
2313 if (optind == argc) { /* no paths specified, get all paths. */
2314 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2315 rc = llapi_getname(mntdir, buf, sizeof(buf));
2318 "cannot get name for `%s': %s\n",
2319 mntdir, strerror(-rc));
2323 printf("%s %s\n", buf, mntdir);
2325 path[0] = fsname[0] = mntdir[0] = 0;
2327 } else { /* paths specified, only attempt to search these. */
2328 for (; optind < argc; optind++) {
2329 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2332 "cannot get name for `%s': %s\n",
2333 argv[optind], strerror(-rc));
2337 printf("%s %s\n", buf, argv[optind]);
2343 static int lfs_check(int argc, char **argv)
2346 char mntdir[PATH_MAX] = {'\0'};
2355 obd_types[0] = obd_type1;
2356 obd_types[1] = obd_type2;
2358 if (strcmp(argv[1], "osts") == 0) {
2359 strcpy(obd_types[0], "osc");
2360 } else if (strcmp(argv[1], "mds") == 0) {
2361 strcpy(obd_types[0], "mdc");
2362 } else if (strcmp(argv[1], "servers") == 0) {
2364 strcpy(obd_types[0], "osc");
2365 strcpy(obd_types[1], "mdc");
2367 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2372 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2373 if (rc < 0 || mntdir[0] == '\0') {
2374 fprintf(stderr, "No suitable Lustre mount found\n");
2378 rc = llapi_target_check(num_types, obd_types, mntdir);
2380 fprintf(stderr, "error: %s: %s status failed\n",
2387 static int lfs_join(int argc, char **argv)
2389 fprintf(stderr, "join two lustre files into one.\n"
2390 "obsolete, HEAD does not support it anymore.\n");
2394 #ifdef HAVE_SYS_QUOTA_H
2395 #define ARG2INT(nr, str, msg) \
2398 nr = strtol(str, &endp, 0); \
2400 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2405 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2407 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2408 * returns the value or ULONG_MAX on integer overflow or incorrect format
2410 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2411 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2412 * 3. empty integer value is interpreted as 0
2414 static unsigned long str2sec(const char* timestr)
2416 const char spec[] = "smhdw";
2417 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2418 unsigned long val = 0;
2421 if (strpbrk(timestr, spec) == NULL) {
2422 /* no specifiers inside the time string,
2423 should treat it as an integer value */
2424 val = strtoul(timestr, &tail, 10);
2425 return *tail ? ULONG_MAX : val;
2428 /* format string is XXwXXdXXhXXmXXs */
2434 v = strtoul(timestr, &tail, 10);
2435 if (v == ULONG_MAX || *tail == '\0')
2436 /* value too large (ULONG_MAX or more)
2437 or missing specifier */
2440 ptr = strchr(spec, *tail);
2442 /* unknown specifier */
2447 /* check if product will overflow the type */
2448 if (!(v < ULONG_MAX / mult[ind]))
2451 ADD_OVERFLOW(val, mult[ind] * v);
2452 if (val == ULONG_MAX)
2464 #define ARG2ULL(nr, str, def_units) \
2466 unsigned long long limit, units = def_units; \
2469 rc = llapi_parse_size(str, &limit, &units, 1); \
2471 fprintf(stderr, "error: bad limit value %s\n", str); \
2477 static inline int has_times_option(int argc, char **argv)
2481 for (i = 1; i < argc; i++)
2482 if (!strcmp(argv[i], "-t"))
2488 int lfs_setquota_times(int argc, char **argv)
2491 struct if_quotactl qctl;
2492 char *mnt, *obd_type = (char *)qctl.obd_type;
2493 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2494 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2495 struct option long_opts[] = {
2496 {"block-grace", required_argument, 0, 'b'},
2497 {"group", no_argument, 0, 'g'},
2498 {"inode-grace", required_argument, 0, 'i'},
2499 {"times", no_argument, 0, 't'},
2500 {"user", no_argument, 0, 'u'},
2504 memset(&qctl, 0, sizeof(qctl));
2505 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2506 qctl.qc_type = UGQUOTA;
2508 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2512 if (qctl.qc_type != UGQUOTA) {
2513 fprintf(stderr, "error: -u and -g can't be used "
2514 "more than once\n");
2517 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2520 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2521 fprintf(stderr, "error: bad block-grace: %s\n",
2525 dqb->dqb_valid |= QIF_BTIME;
2528 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2529 fprintf(stderr, "error: bad inode-grace: %s\n",
2533 dqb->dqb_valid |= QIF_ITIME;
2535 case 't': /* Yes, of course! */
2537 default: /* getopt prints error message for us when opterr != 0 */
2542 if (qctl.qc_type == UGQUOTA) {
2543 fprintf(stderr, "error: neither -u nor -g specified\n");
2547 if (optind != argc - 1) {
2548 fprintf(stderr, "error: unexpected parameters encountered\n");
2553 rc = llapi_quotactl(mnt, &qctl);
2556 fprintf(stderr, "%s %s ", obd_type,
2557 obd_uuid2str(&qctl.obd_uuid));
2558 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2565 #define BSLIMIT (1 << 0)
2566 #define BHLIMIT (1 << 1)
2567 #define ISLIMIT (1 << 2)
2568 #define IHLIMIT (1 << 3)
2570 int lfs_setquota(int argc, char **argv)
2573 struct if_quotactl qctl;
2574 char *mnt, *obd_type = (char *)qctl.obd_type;
2575 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2576 struct option long_opts[] = {
2577 {"block-softlimit", required_argument, 0, 'b'},
2578 {"block-hardlimit", required_argument, 0, 'B'},
2579 {"group", required_argument, 0, 'g'},
2580 {"inode-softlimit", required_argument, 0, 'i'},
2581 {"inode-hardlimit", required_argument, 0, 'I'},
2582 {"user", required_argument, 0, 'u'},
2585 unsigned limit_mask = 0;
2588 if (has_times_option(argc, argv))
2589 return lfs_setquota_times(argc, argv);
2591 memset(&qctl, 0, sizeof(qctl));
2592 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2593 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2594 * so it can be used as a marker that qc_type
2595 * isn't reinitialized from command line */
2597 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2601 if (qctl.qc_type != UGQUOTA) {
2602 fprintf(stderr, "error: -u and -g can't be used"
2603 " more than once\n");
2606 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2607 rc = name2id(&qctl.qc_id, optarg,
2608 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2610 qctl.qc_id = strtoul(optarg, &endptr, 10);
2611 if (*endptr != '\0') {
2612 fprintf(stderr, "error: can't find id "
2613 "for name %s\n", optarg);
2619 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2620 dqb->dqb_bsoftlimit >>= 10;
2621 limit_mask |= BSLIMIT;
2622 if (dqb->dqb_bsoftlimit &&
2623 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2624 fprintf(stderr, "warning: block softlimit is "
2625 "smaller than the miminal qunit size, "
2626 "please see the help of setquota or "
2627 "Lustre manual for details.\n");
2630 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2631 dqb->dqb_bhardlimit >>= 10;
2632 limit_mask |= BHLIMIT;
2633 if (dqb->dqb_bhardlimit &&
2634 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2635 fprintf(stderr, "warning: block hardlimit is "
2636 "smaller than the miminal qunit size, "
2637 "please see the help of setquota or "
2638 "Lustre manual for details.\n");
2641 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2642 limit_mask |= ISLIMIT;
2643 if (dqb->dqb_isoftlimit &&
2644 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2645 fprintf(stderr, "warning: inode softlimit is "
2646 "smaller than the miminal qunit size, "
2647 "please see the help of setquota or "
2648 "Lustre manual for details.\n");
2651 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2652 limit_mask |= IHLIMIT;
2653 if (dqb->dqb_ihardlimit &&
2654 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2655 fprintf(stderr, "warning: inode hardlimit is "
2656 "smaller than the miminal qunit size, "
2657 "please see the help of setquota or "
2658 "Lustre manual for details.\n");
2660 default: /* getopt prints error message for us when opterr != 0 */
2665 if (qctl.qc_type == UGQUOTA) {
2666 fprintf(stderr, "error: neither -u nor -g was specified\n");
2670 if (limit_mask == 0) {
2671 fprintf(stderr, "error: at least one limit must be specified\n");
2675 if (optind != argc - 1) {
2676 fprintf(stderr, "error: unexpected parameters encountered\n");
2682 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2683 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2684 /* sigh, we can't just set blimits/ilimits */
2685 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2686 .qc_type = qctl.qc_type,
2687 .qc_id = qctl.qc_id};
2689 rc = llapi_quotactl(mnt, &tmp_qctl);
2691 fprintf(stderr, "error: setquota failed while retrieving"
2692 " current quota settings (%s)\n",
2697 if (!(limit_mask & BHLIMIT))
2698 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2699 if (!(limit_mask & BSLIMIT))
2700 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2701 if (!(limit_mask & IHLIMIT))
2702 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2703 if (!(limit_mask & ISLIMIT))
2704 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2706 /* Keep grace times if we have got no softlimit arguments */
2707 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2708 dqb->dqb_valid |= QIF_BTIME;
2709 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2712 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2713 dqb->dqb_valid |= QIF_ITIME;
2714 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2718 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2719 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2721 rc = llapi_quotactl(mnt, &qctl);
2724 fprintf(stderr, "%s %s ", obd_type,
2725 obd_uuid2str(&qctl.obd_uuid));
2726 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2733 static inline char *type2name(int check_type)
2735 if (check_type == USRQUOTA)
2737 else if (check_type == GRPQUOTA)
2743 /* Converts seconds value into format string
2744 * result is returned in buf
2746 * 1. result is in descenting order: 1w2d3h4m5s
2747 * 2. zero fields are not filled (except for p. 3): 5d1s
2748 * 3. zero seconds value is presented as "0s"
2750 static char * __sec2str(time_t seconds, char *buf)
2752 const char spec[] = "smhdw";
2753 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2758 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2759 c = seconds / mult[i];
2761 if (c > 0 || (i == 0 && buf == tail))
2762 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2770 static void sec2str(time_t seconds, char *buf, int rc)
2777 tail = __sec2str(seconds, tail);
2779 if (rc && tail - buf < 39) {
2785 static void diff2str(time_t seconds, char *buf, time_t now)
2791 if (seconds <= now) {
2792 strcpy(buf, "none");
2795 __sec2str(seconds - now, buf);
2798 static void print_quota_title(char *name, struct if_quotactl *qctl,
2799 bool human_readable)
2801 printf("Disk quotas for %s %s (%cid %u):\n",
2802 type2name(qctl->qc_type), name,
2803 *type2name(qctl->qc_type), qctl->qc_id);
2804 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2805 "Filesystem", human_readable ? "used" : "kbytes",
2806 "quota", "limit", "grace",
2807 "files", "quota", "limit", "grace");
2810 static void kbytes2str(__u64 num, char *buf, bool h)
2813 sprintf(buf, LPU64, num);
2816 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2818 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2820 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2822 sprintf(buf, LPU64"%s", num, "k");
2826 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2833 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2834 int bover = 0, iover = 0;
2835 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2840 if (dqb->dqb_bhardlimit &&
2841 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2843 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2844 if (dqb->dqb_btime > now) {
2851 if (dqb->dqb_ihardlimit &&
2852 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2854 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2855 if (dqb->dqb_itime > now) {
2863 if (strlen(mnt) > 15)
2864 printf("%s\n%15s", mnt, "");
2866 printf("%15s", mnt);
2869 diff2str(dqb->dqb_btime, timebuf, now);
2871 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2872 if (rc == -EREMOTEIO)
2873 sprintf(numbuf[0], "%s*", strbuf);
2875 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2876 "%s" : "[%s]", strbuf);
2878 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2879 if (type == QC_GENERAL)
2880 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2881 "%s" : "[%s]", strbuf);
2883 sprintf(numbuf[1], "%s", "-");
2885 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2886 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2887 "%s" : "[%s]", strbuf);
2889 printf(" %7s%c %6s %7s %7s",
2890 numbuf[0], bover ? '*' : ' ', numbuf[1],
2891 numbuf[2], bover > 1 ? timebuf : "-");
2894 diff2str(dqb->dqb_itime, timebuf, now);
2896 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2897 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2899 if (type == QC_GENERAL)
2900 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2901 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2903 sprintf(numbuf[1], "%s", "-");
2905 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2906 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2908 if (type != QC_OSTIDX)
2909 printf(" %7s%c %6s %7s %7s",
2910 numbuf[0], iover ? '*' : ' ', numbuf[1],
2911 numbuf[2], iover > 1 ? timebuf : "-");
2913 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2916 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2917 qctl->qc_cmd == Q_GETOINFO) {
2921 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2922 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2923 printf("Block grace time: %s; Inode grace time: %s\n",
2924 bgtimebuf, igtimebuf);
2928 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2929 bool h, __u64 *total)
2931 int rc = 0, rc1 = 0, count = 0;
2932 __u32 valid = qctl->qc_valid;
2934 rc = llapi_get_obd_count(mnt, &count, is_mdt);
2936 fprintf(stderr, "can not get %s count: %s\n",
2937 is_mdt ? "mdt": "ost", strerror(-rc));
2941 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2942 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2943 rc = llapi_quotactl(mnt, qctl);
2945 /* It is remote client case. */
2946 if (-rc == EOPNOTSUPP) {
2953 fprintf(stderr, "quotactl %s%d failed.\n",
2954 is_mdt ? "mdt": "ost", qctl->qc_idx);
2958 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
2959 qctl->qc_valid, 0, h);
2960 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
2961 qctl->qc_dqblk.dqb_bhardlimit;
2964 qctl->qc_valid = valid;
2968 static int lfs_quota(int argc, char **argv)
2971 char *mnt, *name = NULL;
2972 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2973 .qc_type = UGQUOTA };
2974 char *obd_type = (char *)qctl.obd_type;
2975 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2976 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2977 verbose = 0, pass = 0, quiet = 0, inacc;
2979 __u32 valid = QC_GENERAL, idx = 0;
2980 __u64 total_ialloc = 0, total_balloc = 0;
2981 bool human_readable = false;
2983 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
2986 if (qctl.qc_type != UGQUOTA) {
2987 fprintf(stderr, "error: use either -u or -g\n");
2990 qctl.qc_type = USRQUOTA;
2993 if (qctl.qc_type != UGQUOTA) {
2994 fprintf(stderr, "error: use either -u or -g\n");
2997 qctl.qc_type = GRPQUOTA;
3000 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3003 valid = qctl.qc_valid = QC_UUID;
3004 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3007 valid = qctl.qc_valid = QC_MDTIDX;
3008 idx = qctl.qc_idx = atoi(optarg);
3011 valid = qctl.qc_valid = QC_OSTIDX;
3012 idx = qctl.qc_idx = atoi(optarg);
3021 human_readable = true;
3024 fprintf(stderr, "error: %s: option '-%c' "
3025 "unrecognized\n", argv[0], c);
3030 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3031 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3032 optind == argc - 1) {
3034 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3035 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3036 qctl.qc_valid = valid;
3039 qctl.qc_type = USRQUOTA;
3040 qctl.qc_id = geteuid();
3042 qctl.qc_type = GRPQUOTA;
3043 qctl.qc_id = getegid();
3045 rc = id2name(&name, qctl.qc_id,
3046 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3049 /* lfs quota -u username /path/to/lustre/mount */
3050 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3051 /* options should be followed by u/g-name and mntpoint */
3052 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3053 fprintf(stderr, "error: missing quota argument(s)\n");
3057 name = argv[optind++];
3058 rc = name2id(&qctl.qc_id, name,
3059 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3061 qctl.qc_id = strtoul(name, &endptr, 10);
3062 if (*endptr != '\0') {
3063 fprintf(stderr, "error: can't find id for name "
3068 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3069 fprintf(stderr, "error: missing quota info argument(s)\n");
3075 rc1 = llapi_quotactl(mnt, &qctl);
3079 fprintf(stderr, "%s quotas are not enabled.\n",
3080 qctl.qc_type == USRQUOTA ? "user" : "group");
3083 fprintf(stderr, "Permission denied.\n");
3085 /* We already got a "No such file..." message. */
3088 fprintf(stderr, "Unexpected quotactl error: %s\n",
3093 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3094 print_quota_title(name, &qctl, human_readable);
3096 if (rc1 && *obd_type)
3097 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3099 if (qctl.qc_valid != QC_GENERAL)
3102 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3103 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3104 (QIF_LIMITS|QIF_USAGE));
3106 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3108 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3112 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3114 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3116 kbytes2str(total_balloc, strbuf, human_readable);
3117 printf("Total allocated inode limit: "LPU64", total "
3118 "allocated block limit: %s\n", total_ialloc, strbuf);
3121 if (rc1 || rc2 || rc3 || inacc)
3122 printf("Some errors happened when getting quota info. "
3123 "Some devices may be not working or deactivated. "
3124 "The data in \"[]\" is inaccurate.\n");
3132 #endif /* HAVE_SYS_QUOTA_H! */
3134 static int flushctx_ioctl(char *mp)
3138 fd = open(mp, O_RDONLY);
3140 fprintf(stderr, "flushctx: error open %s: %s\n",
3141 mp, strerror(errno));
3145 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3147 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3148 mp, strerror(errno));
3154 static int lfs_flushctx(int argc, char **argv)
3156 int kdestroy = 0, c;
3157 char mntdir[PATH_MAX] = {'\0'};
3161 while ((c = getopt(argc, argv, "k")) != -1) {
3167 fprintf(stderr, "error: %s: option '-%c' "
3168 "unrecognized\n", argv[0], c);
3174 if ((rc = system("kdestroy > /dev/null")) != 0) {
3175 rc = WEXITSTATUS(rc);
3176 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3180 if (optind >= argc) {
3181 /* flush for all mounted lustre fs. */
3182 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3183 /* Check if we have a mount point */
3184 if (mntdir[0] == '\0')
3187 if (flushctx_ioctl(mntdir))
3190 mntdir[0] = '\0'; /* avoid matching in next loop */
3193 /* flush fs as specified */
3194 while (optind < argc) {
3195 if (flushctx_ioctl(argv[optind++]))
3202 static int lfs_lsetfacl(int argc, char **argv)
3205 return(llapi_lsetfacl(argc, argv));
3208 static int lfs_lgetfacl(int argc, char **argv)
3211 return(llapi_lgetfacl(argc, argv));
3214 static int lfs_rsetfacl(int argc, char **argv)
3217 return(llapi_rsetfacl(argc, argv));
3220 static int lfs_rgetfacl(int argc, char **argv)
3223 return(llapi_rgetfacl(argc, argv));
3226 static int lfs_cp(int argc, char **argv)
3228 return(llapi_cp(argc, argv));
3231 static int lfs_ls(int argc, char **argv)
3233 return(llapi_ls(argc, argv));
3236 static int lfs_changelog(int argc, char **argv)
3238 void *changelog_priv;
3239 struct changelog_rec *rec;
3240 long long startrec = 0, endrec = 0;
3242 struct option long_opts[] = {
3243 {"follow", no_argument, 0, 'f'},
3246 char short_opts[] = "f";
3249 while ((rc = getopt_long(argc, argv, short_opts,
3250 long_opts, NULL)) != -1) {
3258 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3259 argv[0], argv[optind - 1]);
3266 mdd = argv[optind++];
3268 startrec = strtoll(argv[optind++], NULL, 10);
3270 endrec = strtoll(argv[optind++], NULL, 10);
3272 rc = llapi_changelog_start(&changelog_priv,
3273 CHANGELOG_FLAG_BLOCK |
3274 CHANGELOG_FLAG_JOBID |
3275 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3278 fprintf(stderr, "Can't start changelog: %s\n",
3279 strerror(errno = -rc));
3283 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3287 if (endrec && rec->cr_index > endrec) {
3288 llapi_changelog_free(&rec);
3291 if (rec->cr_index < startrec) {
3292 llapi_changelog_free(&rec);
3296 secs = rec->cr_time >> 30;
3297 gmtime_r(&secs, &ts);
3298 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3299 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3300 changelog_type2str(rec->cr_type),
3301 ts.tm_hour, ts.tm_min, ts.tm_sec,
3302 (int)(rec->cr_time & ((1<<30) - 1)),
3303 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3304 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3306 if (rec->cr_flags & CLF_JOBID) {
3307 struct changelog_ext_jobid *jid =
3308 changelog_rec_jobid(rec);
3310 if (jid->cr_jobid[0] != '\0')
3311 printf(" j=%s", jid->cr_jobid);
3314 if (rec->cr_namelen)
3315 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3316 rec->cr_namelen, changelog_rec_name(rec));
3318 if (rec->cr_flags & CLF_RENAME) {
3319 struct changelog_ext_rename *rnm =
3320 changelog_rec_rename(rec);
3322 if (!fid_is_zero(&rnm->cr_sfid))
3323 printf(" s="DFID" sp="DFID" %.*s",
3324 PFID(&rnm->cr_sfid),
3325 PFID(&rnm->cr_spfid),
3326 (int)changelog_rec_snamelen(rec),
3327 changelog_rec_sname(rec));
3331 llapi_changelog_free(&rec);
3334 llapi_changelog_fini(&changelog_priv);
3337 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3339 return (rc == 1 ? 0 : rc);
3342 static int lfs_changelog_clear(int argc, char **argv)
3350 endrec = strtoll(argv[3], NULL, 10);
3352 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3354 fprintf(stderr, "%s error: %s\n", argv[0],
3355 strerror(errno = -rc));
3359 static int lfs_fid2path(int argc, char **argv)
3361 struct option long_opts[] = {
3362 {"cur", no_argument, 0, 'c'},
3363 {"link", required_argument, 0, 'l'},
3364 {"rec", required_argument, 0, 'r'},
3367 char short_opts[] = "cl:r:";
3368 char *device, *fid, *path;
3369 long long recno = -1;
3375 while ((rc = getopt_long(argc, argv, short_opts,
3376 long_opts, NULL)) != -1) {
3382 linkno = strtol(optarg, NULL, 10);
3385 recno = strtoll(optarg, NULL, 10);
3390 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3391 argv[0], argv[optind - 1]);
3399 device = argv[optind++];
3400 path = calloc(1, PATH_MAX);
3402 fprintf(stderr, "error: Not enough memory\n");
3407 while (optind < argc) {
3408 fid = argv[optind++];
3410 lnktmp = (linkno >= 0) ? linkno : 0;
3412 int oldtmp = lnktmp;
3413 long long rectmp = recno;
3415 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3418 fprintf(stderr, "%s: error on FID %s: %s\n",
3419 argv[0], fid, strerror(errno = -rc2));
3426 fprintf(stdout, "%lld ", rectmp);
3427 if (device[0] == '/') {
3428 fprintf(stdout, "%s", device);
3429 if (device[strlen(device) - 1] != '/')
3430 fprintf(stdout, "/");
3431 } else if (path[0] == '\0') {
3432 fprintf(stdout, "/");
3434 fprintf(stdout, "%s\n", path);
3437 /* specified linkno */
3439 if (oldtmp == lnktmp)
3449 static int lfs_path2fid(int argc, char **argv)
3451 struct option long_opts[] = {
3452 {"parents", no_argument, 0, 'p'},
3456 const char short_opts[] = "p";
3457 const char *sep = "";
3460 bool show_parents = false;
3462 while ((rc = getopt_long(argc, argv, short_opts,
3463 long_opts, NULL)) != -1) {
3466 show_parents = true;
3469 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3470 argv[0], argv[optind - 1]);
3475 if (optind > argc - 1)
3477 else if (optind < argc - 1)
3481 for (path = argv + optind; *path != NULL; path++) {
3483 if (!show_parents) {
3484 err = llapi_path2fid(*path, &fid);
3486 printf("%s%s"DFID"\n",
3487 *sep != '\0' ? *path : "", sep,
3490 char name[NAME_MAX + 1];
3491 unsigned int linkno = 0;
3493 while ((err = llapi_path2parent(*path, linkno, &fid,
3494 name, sizeof(name))) == 0) {
3495 if (*sep != '\0' && linkno == 0)
3496 printf("%s%s", *path, sep);
3498 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3503 /* err == -ENODATA is end-of-loop */
3504 if (linkno > 0 && err == -ENODATA) {
3511 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3512 argv[0], show_parents ? "parent " : "", *path,
3524 static int lfs_data_version(int argc, char **argv)
3531 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3536 while ((c = getopt(argc, argv, "nrw")) != -1) {
3539 data_version_flags = 0;
3542 data_version_flags |= LL_DV_RD_FLUSH;
3545 data_version_flags |= LL_DV_WR_FLUSH;
3554 path = argv[optind];
3555 fd = open(path, O_RDONLY);
3557 err(errno, "cannot open file %s", path);
3559 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3561 err(errno, "cannot get version for %s", path);
3563 printf(LPU64 "\n", data_version);
3569 static int lfs_hsm_state(int argc, char **argv)
3574 struct hsm_user_state hus;
3582 rc = llapi_hsm_state_get(path, &hus);
3584 fprintf(stderr, "can't get hsm state for %s: %s\n",
3585 path, strerror(errno = -rc));
3589 /* Display path name and status flags */
3590 printf("%s: (0x%08x)", path, hus.hus_states);
3592 if (hus.hus_states & HS_RELEASED)
3593 printf(" released");
3594 if (hus.hus_states & HS_EXISTS)
3596 if (hus.hus_states & HS_DIRTY)
3598 if (hus.hus_states & HS_ARCHIVED)
3599 printf(" archived");
3600 /* Display user-settable flags */
3601 if (hus.hus_states & HS_NORELEASE)
3602 printf(" never_release");
3603 if (hus.hus_states & HS_NOARCHIVE)
3604 printf(" never_archive");
3605 if (hus.hus_states & HS_LOST)
3606 printf(" lost_from_hsm");
3608 if (hus.hus_archive_id != 0)
3609 printf(", archive_id:%d", hus.hus_archive_id);
3612 } while (++i < argc);
3617 #define LFS_HSM_SET 0
3618 #define LFS_HSM_CLEAR 1
3621 * Generic function to set or clear HSM flags.
3622 * Used by hsm_set and hsm_clear.
3624 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3626 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3628 struct option long_opts[] = {
3629 {"lost", 0, 0, 'l'},
3630 {"norelease", 0, 0, 'r'},
3631 {"noarchive", 0, 0, 'a'},
3632 {"archived", 0, 0, 'A'},
3633 {"dirty", 0, 0, 'd'},
3634 {"exists", 0, 0, 'e'},
3637 char short_opts[] = "lraAde";
3645 while ((c = getopt_long(argc, argv, short_opts,
3646 long_opts, NULL)) != -1) {
3652 mask |= HS_NOARCHIVE;
3655 mask |= HS_ARCHIVED;
3658 mask |= HS_NORELEASE;
3669 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3670 argv[0], argv[optind - 1]);
3675 /* User should have specified a flag */
3679 while (optind < argc) {
3681 path = argv[optind];
3683 /* If mode == 0, this means we apply the mask. */
3684 if (mode == LFS_HSM_SET)
3685 rc = llapi_hsm_state_set(path, mask, 0, 0);
3687 rc = llapi_hsm_state_set(path, 0, mask, 0);
3690 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3691 path, strerror(errno = -rc));
3700 static int lfs_hsm_action(int argc, char **argv)
3705 struct hsm_current_action hca;
3706 struct hsm_extent he;
3707 enum hsm_user_action hua;
3708 enum hsm_progress_states hps;
3716 rc = llapi_hsm_current_action(path, &hca);
3718 fprintf(stderr, "can't get hsm action for %s: %s\n",
3719 path, strerror(errno = -rc));
3722 he = hca.hca_location;
3723 hua = hca.hca_action;
3724 hps = hca.hca_state;
3726 printf("%s: %s", path, hsm_user_action2name(hua));
3728 /* Skip file without action */
3729 if (hca.hca_action == HUA_NONE) {
3734 printf(" %s ", hsm_progress_state2name(hps));
3736 if ((hps == HPS_RUNNING) &&
3737 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3738 printf("(%llu bytes moved)\n",
3739 (unsigned long long)he.length);
3740 else if ((he.offset + he.length) == LUSTRE_EOF)
3741 printf("(from %llu to EOF)\n",
3742 (unsigned long long)he.offset);
3744 printf("(from %llu to %llu)\n",
3745 (unsigned long long)he.offset,
3746 (unsigned long long)(he.offset + he.length));
3748 } while (++i < argc);
3753 static int lfs_hsm_set(int argc, char **argv)
3755 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3758 static int lfs_hsm_clear(int argc, char **argv)
3760 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3764 * Check file state and return its fid, to be used by lfs_hsm_request().
3766 * \param[in] file Path to file to check
3767 * \param[in,out] fid Pointer to allocated lu_fid struct.
3768 * \param[in,out] last_dev Pointer to last device id used.
3770 * \return 0 on success.
3772 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3778 rc = lstat(file, &st);
3780 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3783 /* Checking for regular file as archiving as posix copytool
3784 * rejects archiving files other than regular files
3786 if (!S_ISREG(st.st_mode)) {
3787 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3790 /* A request should be ... */
3791 if (*last_dev != st.st_dev && *last_dev != 0) {
3792 fprintf(stderr, "All files should be "
3793 "on the same filesystem: %s\n", file);
3796 *last_dev = st.st_dev;
3798 rc = llapi_path2fid(file, fid);
3800 fprintf(stderr, "Cannot read FID of %s: %s\n",
3801 file, strerror(-rc));
3807 /* Fill an HSM HUR item with a given file name.
3809 * If mntpath is set, then the filename is actually a FID, and no
3810 * lookup on the filesystem will be performed.
3812 * \param[in] hur the user request to fill
3813 * \param[in] idx index of the item inside the HUR to fill
3814 * \param[in] mntpath mountpoint of Lustre
3815 * \param[in] fname filename (if mtnpath is NULL)
3816 * or FID (if mntpath is set)
3817 * \param[in] last_dev pointer to last device id used
3819 * \retval 0 on success
3820 * \retval CMD_HELP or a negative errno on error
3822 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3823 const char *mntpath, const char *fname,
3826 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3829 hui->hui_extent.length = -1;
3831 if (mntpath != NULL) {
3834 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3838 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3843 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3847 hur->hur_request.hr_itemcount++;
3852 static int lfs_hsm_request(int argc, char **argv, int action)
3854 struct option long_opts[] = {
3855 {"filelist", 1, 0, 'l'},
3856 {"data", 1, 0, 'D'},
3857 {"archive", 1, 0, 'a'},
3858 {"mntpath", 1, 0, 'm'},
3862 char short_opts[] = "l:D:a:m:";
3863 struct hsm_user_request *hur, *oldhur;
3868 char *filelist = NULL;
3869 char fullpath[PATH_MAX];
3870 char *opaque = NULL;
3874 int nbfile_alloc = 0;
3875 char *some_file = NULL;
3876 char *mntpath = NULL;
3882 while ((c = getopt_long(argc, argv, short_opts,
3883 long_opts, NULL)) != -1) {
3892 if (action != HUA_ARCHIVE &&
3893 action != HUA_REMOVE) {
3895 "error: -a is supported only "
3896 "when archiving or removing\n");
3899 archive_id = atoi(optarg);
3902 if (some_file == NULL) {
3904 some_file = strdup(optarg);
3910 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3911 argv[0], argv[optind - 1]);
3916 /* All remaining args are files, so we have at least nbfile */
3917 nbfile = argc - optind;
3919 if ((nbfile == 0) && (filelist == NULL))
3923 opaque_len = strlen(opaque);
3925 /* Alloc the request structure with enough place to store all files
3926 * from command line. */
3927 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3929 fprintf(stderr, "Cannot create the request: %s\n",
3933 nbfile_alloc = nbfile;
3935 hur->hur_request.hr_action = action;
3936 hur->hur_request.hr_archive_id = archive_id;
3937 hur->hur_request.hr_flags = 0;
3939 /* All remaining args are files, add them */
3940 if (nbfile != 0 && some_file == NULL)
3941 some_file = strdup(argv[optind]);
3943 for (i = 0; i < nbfile; i++) {
3944 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
3950 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3952 /* If a filelist was specified, read the filelist from it. */
3953 if (filelist != NULL) {
3954 fp = fopen(filelist, "r");
3956 fprintf(stderr, "Cannot read the file list %s: %s\n",
3957 filelist, strerror(errno));
3962 while ((rc = getline(&line, &len, fp)) != -1) {
3963 /* If allocated buffer was too small, get something
3965 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3968 nbfile_alloc = nbfile_alloc * 2 + 1;
3970 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3973 fprintf(stderr, "hsm: cannot allocate "
3974 "the request: %s\n",
3981 size = hur_len(oldhur);
3983 fprintf(stderr, "hsm: cannot allocate "
3984 "%u files + %u bytes data\n",
3985 oldhur->hur_request.hr_itemcount,
3986 oldhur->hur_request.hr_data_len);
3993 memcpy(hur, oldhur, size);
3998 if (line[strlen(line) - 1] == '\n')
3999 line[strlen(line) - 1] = '\0';
4001 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4002 mntpath, line, &last_dev);
4008 if (some_file == NULL) {
4018 /* If a --data was used, add it to the request */
4019 hur->hur_request.hr_data_len = opaque_len;
4021 memcpy(hur_data(hur), opaque, opaque_len);
4023 /* Send the HSM request */
4024 if (realpath(some_file, fullpath) == NULL) {
4025 fprintf(stderr, "Could not find path '%s': %s\n",
4026 some_file, strerror(errno));
4028 rc = llapi_hsm_request(fullpath, hur);
4030 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4031 some_file, strerror(-rc));
4041 static int lfs_hsm_archive(int argc, char **argv)
4043 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4046 static int lfs_hsm_restore(int argc, char **argv)
4048 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4051 static int lfs_hsm_release(int argc, char **argv)
4053 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4056 static int lfs_hsm_remove(int argc, char **argv)
4058 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4061 static int lfs_hsm_cancel(int argc, char **argv)
4063 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4066 static int lfs_swap_layouts(int argc, char **argv)
4071 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4072 SWAP_LAYOUTS_KEEP_MTIME |
4073 SWAP_LAYOUTS_KEEP_ATIME);
4076 int main(int argc, char **argv)
4080 /* Ensure that liblustreapi constructor has run */
4081 if (!liblustreapi_initialized)
4082 fprintf(stderr, "liblustreapi was not properly initialized\n");
4086 Parser_init("lfs > ", cmdlist);
4088 progname = argv[0]; /* Used in error messages */
4090 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4092 rc = Parser_commands();
4095 return rc < 0 ? -rc : rc;
4098 #ifdef _LUSTRE_IDL_H_
4099 /* Everything we need here should be included by lustreapi.h. */
4100 # error "lfs should not depend on lustre_idl.h"
4101 #endif /* _LUSTRE_IDL_H_ */