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>
60 #include <sys/types.h>
66 #ifdef HAVE_SYS_QUOTA_H
67 # include <sys/quota.h>
70 #include <libcfs/util/string.h>
71 #include <libcfs/util/ioctl.h>
72 #include <libcfs/util/parser.h>
73 #include <lustre/lustreapi.h>
74 #include <lustre_ver.h>
77 static int lfs_setstripe(int argc, char **argv);
78 static int lfs_find(int argc, char **argv);
79 static int lfs_getstripe(int argc, char **argv);
80 static int lfs_getdirstripe(int argc, char **argv);
81 static int lfs_setdirstripe(int argc, char **argv);
82 static int lfs_rmentry(int argc, char **argv);
83 static int lfs_osts(int argc, char **argv);
84 static int lfs_mdts(int argc, char **argv);
85 static int lfs_df(int argc, char **argv);
86 static int lfs_getname(int argc, char **argv);
87 static int lfs_check(int argc, char **argv);
88 #ifdef HAVE_SYS_QUOTA_H
89 static int lfs_setquota(int argc, char **argv);
90 static int lfs_quota(int argc, char **argv);
92 static int lfs_flushctx(int argc, char **argv);
93 static int lfs_join(int argc, char **argv);
94 static int lfs_lsetfacl(int argc, char **argv);
95 static int lfs_lgetfacl(int argc, char **argv);
96 static int lfs_rsetfacl(int argc, char **argv);
97 static int lfs_rgetfacl(int argc, char **argv);
98 static int lfs_cp(int argc, char **argv);
99 static int lfs_ls(int argc, char **argv);
100 static int lfs_poollist(int argc, char **argv);
101 static int lfs_changelog(int argc, char **argv);
102 static int lfs_changelog_clear(int argc, char **argv);
103 static int lfs_fid2path(int argc, char **argv);
104 static int lfs_path2fid(int argc, char **argv);
105 static int lfs_data_version(int argc, char **argv);
106 static int lfs_hsm_state(int argc, char **argv);
107 static int lfs_hsm_set(int argc, char **argv);
108 static int lfs_hsm_clear(int argc, char **argv);
109 static int lfs_hsm_action(int argc, char **argv);
110 static int lfs_hsm_archive(int argc, char **argv);
111 static int lfs_hsm_restore(int argc, char **argv);
112 static int lfs_hsm_release(int argc, char **argv);
113 static int lfs_hsm_remove(int argc, char **argv);
114 static int lfs_hsm_cancel(int argc, char **argv);
115 static int lfs_swap_layouts(int argc, char **argv);
116 static int lfs_mv(int argc, char **argv);
118 /* Setstripe and migrate share mostly the same parameters */
119 #define SSM_CMD_COMMON(cmd) \
120 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
121 " [--stripe-index|-i <start_ost_idx>]\n" \
122 " [--stripe-size|-S <stripe_size>]\n" \
123 " [--pool|-p <pool_name>]\n" \
124 " [--ost-list|-o <ost_indices>]\n"
126 #define SSM_HELP_COMMON \
127 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
128 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
129 "\t respectively)\n" \
130 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
131 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
132 "\tpool_name: Name of OST pool to use (default none)\n" \
133 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
134 "\t Indices be specified in a format of:\n" \
135 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
137 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
138 "\t If --pool is set with --ost-list, then the OSTs\n" \
139 "\t must be the members of the pool."
141 #define SETSTRIPE_USAGE \
142 SSM_CMD_COMMON("setstripe") \
143 " <directory|filename>\n" \
146 #define MIGRATE_USAGE \
147 SSM_CMD_COMMON("migrate ") \
152 "\tblock: Block file access during data migration\n" \
154 static const char *progname;
155 static bool file_lease_supported = true;
157 /* all available commands */
158 command_t cmdlist[] = {
159 {"setstripe", lfs_setstripe, 0,
160 "Create a new file with a specific striping pattern or\n"
161 "set the default striping pattern on an existing directory or\n"
162 "delete the default striping pattern from an existing directory\n"
163 "usage: setstripe -d <directory> (to delete default striping)\n"\
166 {"getstripe", lfs_getstripe, 0,
167 "To list the striping info for a given file or files in a\n"
168 "directory or recursively for all files in a directory tree.\n"
169 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
170 " [--stripe-count|-c] [--stripe-index|-i]\n"
171 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
172 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
174 " <directory|filename> ..."},
175 {"setdirstripe", lfs_setdirstripe, 0,
176 "To create a striped directory on a specified MDT. This can only\n"
177 "be done on MDT0 with the right of administrator.\n"
178 "usage: setdirstripe <--count|-c stripe_count>\n"
179 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
180 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
181 "\tstripe_count: stripe count of the striped directory\n"
182 "\tmdt_index: MDT index of first stripe\n"
183 "\thash_type: hash type of the striped directory. Hash types:\n"
184 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
185 " all_char sum of characters % MDT_COUNT (not recommended)\n"
186 "\tdefault_stripe: set default dirstripe of the directory\n"
187 "\tmode: the mode of the directory\n"},
188 {"getdirstripe", lfs_getdirstripe, 0,
189 "To list the striping info for a given directory\n"
190 "or recursively for all directories in a directory tree.\n"
191 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
192 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
193 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
194 {"mkdir", lfs_setdirstripe, 0,
195 "To create a striped directory on a specified MDT. This can only\n"
196 "be done on MDT0 with the right of administrator.\n"
197 "usage: mkdir <--count|-c stripe_count>\n"
198 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
199 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
200 "\tstripe_count: stripe count of the striped directory\n"
201 "\tmdt_index: MDT index of first stripe\n"
202 "\thash_type: hash type of the striped directory. Hash types:\n"
203 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
204 " all_char sum of characters % MDT_COUNT (not recommended)\n"
205 "\tdefault_stripe: set default dirstripe of the directory\n"
206 "\tmode: the mode of the directory\n"},
207 {"rm_entry", lfs_rmentry, 0,
208 "To remove the name entry of the remote directory. Note: This\n"
209 "command will only delete the name entry, i.e. the remote directory\n"
210 "will become inaccessable after this command. This can only be done\n"
211 "by the administrator\n"
212 "usage: rm_entry <dir>\n"},
213 {"pool_list", lfs_poollist, 0,
214 "List pools or pool OSTs\n"
215 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
216 {"find", lfs_find, 0,
217 "find files matching given attributes recursively in directory tree.\n"
218 "usage: find <directory|filename> ...\n"
219 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
220 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
221 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
222 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
223 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
224 " [[!] --stripe-count|-c [+-]<stripes>]\n"
225 " [[!] --stripe-index|-i <index,...>]\n"
226 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
227 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
228 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
229 " [[!] --layout|-L released,raid0]\n"
230 "\t !: used before an option indicates 'NOT' requested attribute\n"
231 "\t -: used before a value indicates 'AT MOST' requested value\n"
232 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
233 {"check", lfs_check, 0,
234 "Display the status of MDS or OSTs (as specified in the command)\n"
235 "or all the servers (MDS and OSTs).\n"
236 "usage: check <osts|mds|servers>"},
237 {"join", lfs_join, 0,
238 "join two lustre files into one.\n"
239 "obsolete, HEAD does not support it anymore.\n"},
240 {"osts", lfs_osts, 0, "list OSTs connected to client "
241 "[for specified path only]\n" "usage: osts [path]"},
242 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
243 "[for specified path only]\n" "usage: mdts [path]"},
245 "report filesystem disk space usage or inodes usage"
246 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
247 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
248 {"getname", lfs_getname, 0, "list instances and specified mount points "
249 "[for specified path only]\n"
250 "Usage: getname [-h]|[path ...] "},
251 #ifdef HAVE_SYS_QUOTA_H
252 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
253 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
254 " -b <block-softlimit> -B <block-hardlimit>\n"
255 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
256 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
257 " [--block-softlimit <block-softlimit>]\n"
258 " [--block-hardlimit <block-hardlimit>]\n"
259 " [--inode-softlimit <inode-softlimit>]\n"
260 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
261 " setquota [-t] <-u|--user|-g|--group>\n"
262 " [--block-grace <block-grace>]\n"
263 " [--inode-grace <inode-grace>] <filesystem>\n"
264 " -b can be used instead of --block-softlimit/--block-grace\n"
265 " -B can be used instead of --block-hardlimit\n"
266 " -i can be used instead of --inode-softlimit/--inode-grace\n"
267 " -I can be used instead of --inode-hardlimit\n\n"
268 "Note: The total quota space will be split into many qunits and\n"
269 " balanced over all server targets, the minimal qunit size is\n"
270 " 1M bytes for block space and 1K inodes for inode space.\n\n"
271 " Quota space rebalancing process will stop when this mininum\n"
272 " value is reached. As a result, quota exceeded can be returned\n"
273 " while many targets still have 1MB or 1K inodes of spare\n"
275 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
276 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
278 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
279 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
281 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
282 "usage: flushctx [-k] [mountpoint...]"},
283 {"lsetfacl", lfs_lsetfacl, 0,
284 "Remote user setfacl for user/group on the same remote client.\n"
285 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
286 {"lgetfacl", lfs_lgetfacl, 0,
287 "Remote user getfacl for user/group on the same remote client.\n"
288 "usage: lgetfacl [-dRLPvh] file ..."},
289 {"rsetfacl", lfs_rsetfacl, 0,
290 "Remote user setfacl for user/group on other clients.\n"
291 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
292 {"rgetfacl", lfs_rgetfacl, 0,
293 "Remote user getfacl for user/group on other clients.\n"
294 "usage: rgetfacl [-dRLPvh] file ..."},
296 "Remote user copy files and directories.\n"
297 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
299 "Remote user list directory contents.\n"
300 "usage: ls [OPTION]... [FILE]..."},
301 {"changelog", lfs_changelog, 0,
302 "Show the metadata changes on an MDT."
303 "\nusage: changelog <mdtname> [startrec [endrec]]"},
304 {"changelog_clear", lfs_changelog_clear, 0,
305 "Indicate that old changelog records up to <endrec> are no longer of "
306 "interest to consumer <id>, allowing the system to free up space.\n"
307 "An <endrec> of 0 means all records.\n"
308 "usage: changelog_clear <mdtname> <id> <endrec>"},
309 {"fid2path", lfs_fid2path, 0,
310 "Resolve the full path(s) for given FID(s). For a specific hardlink "
311 "specify link number <linkno>.\n"
312 /* "For a historical link name, specify changelog record <recno>.\n" */
313 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
314 /* [ --rec <recno> ] */ },
315 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
316 "usage: path2fid [--parents] <path> ..."},
317 {"data_version", lfs_data_version, 0, "Display file data version for "
318 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
319 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
320 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
321 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
322 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
323 "[--archived] [--lost] <file> ..."},
324 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
326 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
327 "[--archived] [--lost] <file> ..."},
328 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
329 "given files.\n" "usage: hsm_action <file> ..."},
330 {"hsm_archive", lfs_hsm_archive, 0,
331 "Archive file to external storage.\n"
332 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
334 {"hsm_restore", lfs_hsm_restore, 0,
335 "Restore file from external storage.\n"
336 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
337 {"hsm_release", lfs_hsm_release, 0,
338 "Release files from Lustre.\n"
339 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
340 {"hsm_remove", lfs_hsm_remove, 0,
341 "Remove file copy from external storage.\n"
342 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
343 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
345 "Note: To remove files from the archive that have been deleted on\n"
346 "Lustre, set mntpath and optionally archive. In that case, all the\n"
347 "positional arguments and entries in the file list must be FIDs."
349 {"hsm_cancel", lfs_hsm_cancel, 0,
350 "Cancel requests related to specified files.\n"
351 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
352 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
353 "usage: swap_layouts <path1> <path2>"},
354 {"migrate", lfs_setstripe, 0, "migrate file from one OST layout to "
355 "another.\n" MIGRATE_USAGE},
357 "To move directories between MDTs.\n"
358 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
360 {"help", Parser_help, 0, "help"},
361 {"exit", Parser_quit, 0, "quit"},
362 {"quit", Parser_quit, 0, "quit"},
363 {"--version", Parser_version, 0,
364 "output build version of the utility and exit"},
369 #define MIGRATION_BLOCKS 1
372 * Internal helper for migrate_copy_data(). Check lease and report error if
375 * \param[in] fd File descriptor on which to check the lease.
376 * \param[out] lease_broken Set to true if the lease was broken.
377 * \param[in] group_locked Whether a group lock was taken or not.
378 * \param[in] path Name of the file being processed, for error
381 * \retval 0 Migration can keep on going.
382 * \retval -errno Error occurred, abort migration.
384 static int check_lease(int fd, bool *lease_broken, bool group_locked,
389 if (!file_lease_supported)
392 rc = llapi_lease_check(fd);
394 return 0; /* llapi_check_lease returns > 0 on success. */
397 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
399 rc = rc ? rc : -EAGAIN;
401 fprintf(stderr, "%s: external attempt to access file '%s' "
402 "blocked until migration ends.\n", progname, path);
405 *lease_broken = true;
409 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
410 bool group_locked, const char *fname)
419 bool lease_broken = false;
421 /* Use a page-aligned buffer for direct I/O */
422 rc = posix_memalign(&buf, getpagesize(), buf_size);
427 /* read new data only if we have written all
428 * previously read data */
431 rc = check_lease(fd_src, &lease_broken,
432 group_locked, fname);
436 rsize = read(fd_src, buf, buf_size);
439 fprintf(stderr, "%s: %s: read failed: %s\n",
440 progname, fname, strerror(-rc));
450 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
454 "%s: %s: write failed on volatile: %s\n",
455 progname, fname, strerror(-rc));
465 fprintf(stderr, "%s: %s: fsync failed: %s\n",
466 progname, fname, strerror(-rc));
474 static int migrate_copy_timestamps(int fdv, const struct stat *st)
476 struct timeval tv[2] = {
477 {.tv_sec = st->st_atime},
478 {.tv_sec = st->st_mtime}
481 return futimes(fdv, tv);
484 static int migrate_block(int fd, int fdv, const struct stat *st,
485 size_t buf_size, const char *name)
492 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
494 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
495 progname, name, strerror(-rc));
503 /* The grouplock blocks all concurrent accesses to the file.
504 * It has to be taken after llapi_get_data_version as it would
506 rc = llapi_group_lock(fd, gid);
508 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
509 progname, name, strerror(-rc));
513 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
515 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
519 /* Make sure we keep original atime/mtime values */
520 rc = migrate_copy_timestamps(fdv, st);
522 fprintf(stderr, "%s: %s: timestamp copy failed\n",
528 * for a migration we need to check data version on file did
531 * Pass in gid=0 since we already own grouplock. */
532 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
533 SWAP_LAYOUTS_CHECK_DV1);
535 fprintf(stderr, "%s: %s: dataversion changed during copy, "
536 "migration aborted\n", progname, name);
539 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
540 name, strerror(-rc));
545 rc2 = llapi_group_unlock(fd, gid);
546 if (rc2 < 0 && rc == 0) {
547 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
548 progname, name, strerror(-rc2));
555 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
556 size_t buf_size, const char *name)
562 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
564 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
565 progname, name, strerror(-rc));
569 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
571 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
575 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
577 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
578 progname, name, strerror(-rc));
584 fprintf(stderr, "%s: %s: data version changed during "
590 /* Make sure we keep original atime/mtime values */
591 rc = migrate_copy_timestamps(fdv, st);
593 fprintf(stderr, "%s: %s: timestamp copy failed\n",
598 /* Atomically put lease, swap layouts and close.
599 * for a migration we need to check data version on file did
601 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
603 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
604 progname, name, strerror(-rc));
611 static int lfs_migrate(char *name, __u64 migration_flags,
612 struct llapi_stripe_param *param)
616 char volatile_file[PATH_MAX +
617 LUSTRE_VOLATILE_HDR_LEN + 4];
618 char parent[PATH_MAX];
621 struct lov_user_md *lum = NULL;
624 bool have_lease_rdlck = false;
628 /* find the right size for the IO and allocate the buffer */
629 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
630 lum = malloc(lum_size);
636 rc = llapi_file_get_stripe(name, lum);
637 /* failure can happen for many reasons and some may be not real errors
639 * in case of a real error, a later call will fail with better
640 * error management */
642 buf_size = 1024 * 1024;
644 buf_size = lum->lmm_stripe_size;
646 /* open file, direct io */
647 /* even if the file is only read, WR mode is nedeed to allow
648 * layout swap on fd */
649 fd = open(name, O_RDWR | O_DIRECT);
652 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
657 if (file_lease_supported) {
658 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
659 if (rc == -EOPNOTSUPP) {
660 /* Older servers do not support file lease.
661 * Disable related checks. This opens race conditions
662 * as explained in LU-4840 */
663 file_lease_supported = false;
665 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
666 progname, name, strerror(-rc));
669 have_lease_rdlck = true;
673 /* search for file directory pathname */
674 if (strlen(name) > sizeof(parent)-1) {
678 strncpy(parent, name, sizeof(parent));
679 ptr = strrchr(parent, '/');
681 if (getcwd(parent, sizeof(parent)) == NULL) {
692 rc = snprintf(volatile_file, sizeof(volatile_file), "%s/%s::", parent,
693 LUSTRE_VOLATILE_HDR);
694 if (rc >= sizeof(volatile_file)) {
699 /* create, open a volatile file, use caching (ie no directio) */
700 /* exclusive create is not needed because volatile files cannot
701 * conflict on name by construction */
702 fdv = llapi_file_open_param(volatile_file, O_CREAT | O_WRONLY, 0644,
706 fprintf(stderr, "%s: %s: cannot create volatile file in"
708 progname, parent, strerror(-rc));
712 /* Not-owner (root?) special case.
713 * Need to set owner/group of volatile file like original.
714 * This will allow to pass related check during layout_swap.
719 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
723 rc = fstat(fdv, &stv);
726 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
727 volatile_file, strerror(errno));
730 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
731 rc = fchown(fdv, st.st_uid, st.st_gid);
734 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
735 name, strerror(errno));
740 if (migration_flags & MIGRATION_BLOCKS || !file_lease_supported) {
741 /* Blocking mode, forced if servers do not support file lease */
742 rc = migrate_block(fd, fdv, &st, buf_size, name);
744 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
746 have_lease_rdlck = false;
747 fdv = -1; /* The volatile file is closed as we put the
748 * lease in non-blocking mode. */
753 if (have_lease_rdlck)
770 * Parse a string containing an OST index list into an array of integers.
772 * The input string contains a comma delimited list of individual
773 * indices and ranges, for example "1,2-4,7". Add the indices into the
774 * \a osts array and remove duplicates.
776 * \param[out] osts array to store indices in
777 * \param[in] size size of \a osts array
778 * \param[in] offset starting index in \a osts
779 * \param[in] arg string containing OST index list
781 * \retval positive number of indices in \a osts
782 * \retval -EINVAL unable to parse \a arg
784 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
788 int slots = size - offset;
796 while (!end_of_loop) {
804 ptr = strchrnul(arg, ',');
806 end_of_loop = *ptr == '\0';
809 start_index = strtol(arg, &endptr, 0);
810 if (endptr == arg) /* no data at all */
812 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
817 end_index = start_index;
818 if (*endptr == '-') {
819 end_index = strtol(endptr + 1, &endptr, 0);
822 if (end_index < start_index)
826 for (i = start_index; i <= end_index && slots > 0; i++) {
829 /* remove duplicate */
830 for (j = 0; j < offset; j++) {
834 if (j == offset) { /* no duplicate */
839 if (slots == 0 && i < end_index)
847 if (!end_of_loop && ptr != NULL)
850 return rc < 0 ? rc : nr;
854 static int lfs_setstripe(int argc, char **argv)
856 struct llapi_stripe_param *param;
860 unsigned long long st_size;
861 int st_offset, st_count;
865 char *stripe_size_arg = NULL;
866 char *stripe_off_arg = NULL;
867 char *stripe_count_arg = NULL;
868 char *pool_name_arg = NULL;
869 unsigned long long size_units = 1;
870 bool migrate_mode = false;
871 __u64 migration_flags = 0;
872 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
875 struct option long_opts[] = {
876 /* valid only in migrate mode */
877 {"block", no_argument, 0, 'b'},
878 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
879 /* This formerly implied "stripe-count", but was explicitly
880 * made "stripe-count" for consistency with other options,
881 * and to separate it from "mdt-count" when DNE arrives. */
882 {"count", required_argument, 0, 'c'},
884 {"stripe-count", required_argument, 0, 'c'},
885 {"stripe_count", required_argument, 0, 'c'},
886 {"delete", no_argument, 0, 'd'},
887 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
888 /* This formerly implied "stripe-index", but was explicitly
889 * made "stripe-index" for consistency with other options,
890 * and to separate it from "mdt-index" when DNE arrives. */
891 {"index", required_argument, 0, 'i'},
893 {"stripe-index", required_argument, 0, 'i'},
894 {"stripe_index", required_argument, 0, 'i'},
895 {"ost-list", required_argument, 0, 'o'},
896 {"ost_list", required_argument, 0, 'o'},
897 {"pool", required_argument, 0, 'p'},
898 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
899 /* This formerly implied "--stripe-size", but was confusing
900 * with "lfs find --size|-s", which means "file size", so use
901 * the consistent "--stripe-size|-S" for all commands. */
902 {"size", required_argument, 0, 's'},
904 {"stripe-size", required_argument, 0, 'S'},
905 {"stripe_size", required_argument, 0, 'S'},
913 if (strcmp(argv[0], "migrate") == 0)
916 while ((c = getopt_long(argc, argv, "bc:di:o:p:s:S:",
917 long_opts, NULL)) >= 0) {
924 fprintf(stderr, "--block is valid only for"
928 migration_flags |= MIGRATION_BLOCKS;
931 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
932 if (strcmp(argv[optind - 1], "--count") == 0)
933 fprintf(stderr, "warning: '--count' deprecated"
934 ", use '--stripe-count' instead\n");
936 stripe_count_arg = optarg;
939 /* delete the default striping pattern */
943 nr_osts = parse_targets(osts,
944 sizeof(osts) / sizeof(__u32),
948 "error: %s: bad OST indices '%s'\n",
953 if (st_offset == -1) /* first in the command line */
957 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
958 if (strcmp(argv[optind - 1], "--index") == 0)
959 fprintf(stderr, "warning: '--index' deprecated"
960 ", use '--stripe-index' instead\n");
962 stripe_off_arg = optarg;
964 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
966 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
967 fprintf(stderr, "warning: '--size|-s' deprecated, "
968 "use '--stripe-size|-S' instead\n");
970 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
972 stripe_size_arg = optarg;
975 pool_name_arg = optarg;
982 fname = argv[optind];
985 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
986 stripe_count_arg != NULL || pool_name_arg != NULL)) {
987 fprintf(stderr, "error: %s: cannot specify -d with "
988 "-s, -c, -o, or -p options\n",
993 if (optind == argc) {
994 fprintf(stderr, "error: %s: missing filename|dirname\n",
999 if (pool_name_arg && strlen(pool_name_arg) > LOV_MAXPOOLNAME) {
1001 "error: %s: pool name '%s' is too long (max is %d characters)\n",
1002 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1006 /* get the stripe size */
1007 if (stripe_size_arg != NULL) {
1008 result = llapi_parse_size(stripe_size_arg, &st_size,
1011 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1012 argv[0], stripe_size_arg);
1016 /* get the stripe offset */
1017 if (stripe_off_arg != NULL) {
1018 st_offset = strtol(stripe_off_arg, &end, 0);
1020 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1021 argv[0], stripe_off_arg);
1025 /* get the stripe count */
1026 if (stripe_count_arg != NULL) {
1027 st_count = strtoul(stripe_count_arg, &end, 0);
1029 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1030 argv[0], stripe_count_arg);
1035 /* initialize stripe parameters */
1036 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1037 if (param == NULL) {
1038 fprintf(stderr, "error: %s: run out of memory\n", argv[0]);
1042 param->lsp_stripe_size = st_size;
1043 param->lsp_stripe_offset = st_offset;
1044 param->lsp_stripe_count = st_count;
1045 param->lsp_stripe_pattern = 0;
1046 param->lsp_pool = pool_name_arg;
1047 param->lsp_is_specific = false;
1049 if (st_count > 0 && nr_osts != st_count) {
1050 fprintf(stderr, "error: %s: stripe count '%d' doesn't "
1051 "match the number of OSTs: %d\n",
1052 argv[0], st_count, nr_osts);
1057 param->lsp_is_specific = true;
1058 param->lsp_stripe_count = nr_osts;
1059 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1062 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1064 result = lfs_migrate(fname, migration_flags, param);
1066 result = llapi_file_open_param(fname,
1075 /* Save the first error encountered. */
1079 "error: %s: %s stripe file '%s' failed\n",
1080 argv[0], migrate_mode ? "migrate" : "create",
1090 static int lfs_poollist(int argc, char **argv)
1095 return llapi_poollist(argv[1]);
1098 static int set_time(time_t *time, time_t *set, char *str)
1105 else if (str[0] == '-')
1111 t = strtol(str, NULL, 0);
1112 if (*time < t * 24 * 60 * 60) {
1115 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1119 *set = *time - t * 24 * 60 * 60;
1126 static int name2id(unsigned int *id, char *name, int type)
1129 struct passwd *entry;
1131 if (!(entry = getpwnam(name))) {
1137 *id = entry->pw_uid;
1139 struct group *entry;
1141 if (!(entry = getgrnam(name))) {
1147 *id = entry->gr_gid;
1153 static int id2name(char **name, unsigned int id, int type)
1156 struct passwd *entry;
1158 if (!(entry = getpwuid(id))) {
1164 *name = entry->pw_name;
1166 struct group *entry;
1168 if (!(entry = getgrgid(id))) {
1174 *name = entry->gr_name;
1180 static int name2layout(__u32 *layout, char *name)
1185 for (ptr = name; ; ptr = NULL) {
1186 lyt = strtok(ptr, ",");
1189 if (strcmp(lyt, "released") == 0)
1190 *layout |= LOV_PATTERN_F_RELEASED;
1191 else if (strcmp(lyt, "raid0") == 0)
1192 *layout |= LOV_PATTERN_RAID0;
1199 #define FIND_POOL_OPT 3
1200 static int lfs_find(int argc, char **argv)
1205 struct find_param param = {
1209 struct option long_opts[] = {
1210 {"atime", required_argument, 0, 'A'},
1211 {"stripe-count", required_argument, 0, 'c'},
1212 {"stripe_count", required_argument, 0, 'c'},
1213 {"ctime", required_argument, 0, 'C'},
1214 {"maxdepth", required_argument, 0, 'D'},
1215 {"gid", required_argument, 0, 'g'},
1216 {"group", required_argument, 0, 'G'},
1217 {"stripe-index", required_argument, 0, 'i'},
1218 {"stripe_index", required_argument, 0, 'i'},
1219 {"layout", required_argument, 0, 'L'},
1220 {"mdt", required_argument, 0, 'm'},
1221 {"mtime", required_argument, 0, 'M'},
1222 {"name", required_argument, 0, 'n'},
1223 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1224 {"obd", required_argument, 0, 'O'},
1225 {"ost", required_argument, 0, 'O'},
1226 /* no short option for pool, p/P already used */
1227 {"pool", required_argument, 0, FIND_POOL_OPT},
1228 {"print0", no_argument, 0, 'p'},
1229 {"print", no_argument, 0, 'P'},
1230 {"size", required_argument, 0, 's'},
1231 {"stripe-size", required_argument, 0, 'S'},
1232 {"stripe_size", required_argument, 0, 'S'},
1233 {"type", required_argument, 0, 't'},
1234 {"uid", required_argument, 0, 'u'},
1235 {"user", required_argument, 0, 'U'},
1248 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1249 while ((c = getopt_long_only(argc, argv,
1250 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1251 long_opts, NULL)) >= 0) {
1256 /* '!' is part of option */
1257 /* when getopt_long_only() finds a string which is not
1258 * an option nor a known option argument it returns 1
1259 * in that case if we already have found pathstart and pathend
1260 * (i.e. we have the list of pathnames),
1261 * the only supported value is "!"
1263 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1264 if (!isoption && pathend != -1) {
1265 fprintf(stderr, "err: %s: filename|dirname must either "
1266 "precede options or follow options\n",
1271 if (!isoption && pathstart == -1)
1272 pathstart = optind - 1;
1273 if (isoption && pathstart != -1 && pathend == -1)
1274 pathend = optind - 2;
1280 /* unknown; opt is "!" or path component,
1281 * checking done above.
1283 if (strcmp(optarg, "!") == 0)
1287 xtime = ¶m.fp_atime;
1288 xsign = ¶m.fp_asign;
1289 param.fp_exclude_atime = !!neg_opt;
1290 /* no break, this falls through to 'C' for ctime */
1293 xtime = ¶m.fp_ctime;
1294 xsign = ¶m.fp_csign;
1295 param.fp_exclude_ctime = !!neg_opt;
1297 /* no break, this falls through to 'M' for mtime */
1300 xtime = ¶m.fp_mtime;
1301 xsign = ¶m.fp_msign;
1302 param.fp_exclude_mtime = !!neg_opt;
1304 rc = set_time(&t, xtime, optarg);
1305 if (rc == INT_MAX) {
1313 if (optarg[0] == '+') {
1314 param.fp_stripe_count_sign = -1;
1316 } else if (optarg[0] == '-') {
1317 param.fp_stripe_count_sign = 1;
1321 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1322 if (*endptr != '\0') {
1323 fprintf(stderr,"error: bad stripe_count '%s'\n",
1328 param.fp_check_stripe_count = 1;
1329 param.fp_exclude_stripe_count = !!neg_opt;
1332 param.fp_max_depth = strtol(optarg, 0, 0);
1336 rc = name2id(¶m.fp_gid, optarg, GROUP);
1338 param.fp_gid = strtoul(optarg, &endptr, 10);
1339 if (*endptr != '\0') {
1340 fprintf(stderr, "Group/GID: %s cannot "
1341 "be found.\n", optarg);
1346 param.fp_exclude_gid = !!neg_opt;
1347 param.fp_check_gid = 1;
1350 ret = name2layout(¶m.fp_layout, optarg);
1353 param.fp_exclude_layout = !!neg_opt;
1354 param.fp_check_layout = 1;
1358 rc = name2id(¶m.fp_uid, optarg, USER);
1360 param.fp_uid = strtoul(optarg, &endptr, 10);
1361 if (*endptr != '\0') {
1362 fprintf(stderr, "User/UID: %s cannot "
1363 "be found.\n", optarg);
1368 param.fp_exclude_uid = !!neg_opt;
1369 param.fp_check_uid = 1;
1372 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1374 "Pool name %s is too long"
1375 " (max is %d)\n", optarg,
1380 /* we do check for empty pool because empty pool
1381 * is used to find V1 lov attributes */
1382 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1383 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1384 param.fp_exclude_pool = !!neg_opt;
1385 param.fp_check_pool = 1;
1388 param.fp_pattern = (char *)optarg;
1389 param.fp_exclude_pattern = !!neg_opt;
1394 char *buf, *token, *next, *p;
1398 buf = strdup(optarg);
1404 param.fp_exclude_obd = !!neg_opt;
1407 while (token && *token) {
1408 token = strchr(token, ',');
1415 param.fp_exclude_mdt = !!neg_opt;
1416 param.fp_num_alloc_mdts += len;
1417 tmp = realloc(param.fp_mdt_uuid,
1418 param.fp_num_alloc_mdts *
1419 sizeof(*param.fp_mdt_uuid));
1425 param.fp_mdt_uuid = tmp;
1427 param.fp_exclude_obd = !!neg_opt;
1428 param.fp_num_alloc_obds += len;
1429 tmp = realloc(param.fp_obd_uuid,
1430 param.fp_num_alloc_obds *
1431 sizeof(*param.fp_obd_uuid));
1437 param.fp_obd_uuid = tmp;
1439 for (token = buf; token && *token; token = next) {
1440 struct obd_uuid *puuid;
1443 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1446 ¶m.fp_obd_uuid[param.fp_num_obds++];
1448 p = strchr(token, ',');
1455 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1460 strncpy(puuid->uuid, token,
1461 sizeof(puuid->uuid));
1469 param.fp_zero_end = 1;
1474 if (optarg[0] == '+') {
1475 param.fp_size_sign = -1;
1477 } else if (optarg[0] == '-') {
1478 param.fp_size_sign = 1;
1482 ret = llapi_parse_size(optarg, ¶m.fp_size,
1483 ¶m.fp_size_units, 0);
1485 fprintf(stderr, "error: bad file size '%s'\n",
1489 param.fp_check_size = 1;
1490 param.fp_exclude_size = !!neg_opt;
1493 if (optarg[0] == '+') {
1494 param.fp_stripe_size_sign = -1;
1496 } else if (optarg[0] == '-') {
1497 param.fp_stripe_size_sign = 1;
1501 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1502 ¶m.fp_stripe_size_units, 0);
1504 fprintf(stderr, "error: bad stripe_size '%s'\n",
1508 param.fp_check_stripe_size = 1;
1509 param.fp_exclude_stripe_size = !!neg_opt;
1512 param.fp_exclude_type = !!neg_opt;
1513 switch (optarg[0]) {
1515 param.fp_type = S_IFBLK;
1518 param.fp_type = S_IFCHR;
1521 param.fp_type = S_IFDIR;
1524 param.fp_type = S_IFREG;
1527 param.fp_type = S_IFLNK;
1530 param.fp_type = S_IFIFO;
1533 param.fp_type = S_IFSOCK;
1536 fprintf(stderr, "error: %s: bad type '%s'\n",
1548 if (pathstart == -1) {
1549 fprintf(stderr, "error: %s: no filename|pathname\n",
1553 } else if (pathend == -1) {
1559 rc = llapi_find(argv[pathstart], ¶m);
1560 if (rc != 0 && ret == 0)
1562 } while (++pathstart < pathend);
1565 fprintf(stderr, "error: %s failed for %s.\n",
1566 argv[0], argv[optind - 1]);
1568 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1569 free(param.fp_obd_uuid);
1571 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1572 free(param.fp_mdt_uuid);
1577 static int lfs_getstripe_internal(int argc, char **argv,
1578 struct find_param *param)
1580 struct option long_opts[] = {
1581 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1582 /* This formerly implied "stripe-count", but was explicitly
1583 * made "stripe-count" for consistency with other options,
1584 * and to separate it from "mdt-count" when DNE arrives. */
1585 {"count", no_argument, 0, 'c'},
1587 {"stripe-count", no_argument, 0, 'c'},
1588 {"stripe_count", no_argument, 0, 'c'},
1589 {"directory", no_argument, 0, 'd'},
1590 {"default", no_argument, 0, 'D'},
1591 {"generation", no_argument, 0, 'g'},
1592 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1593 /* This formerly implied "stripe-index", but was explicitly
1594 * made "stripe-index" for consistency with other options,
1595 * and to separate it from "mdt-index" when DNE arrives. */
1596 {"index", no_argument, 0, 'i'},
1598 {"stripe-index", no_argument, 0, 'i'},
1599 {"stripe_index", no_argument, 0, 'i'},
1600 {"layout", no_argument, 0, 'L'},
1601 {"mdt-index", no_argument, 0, 'M'},
1602 {"mdt_index", no_argument, 0, 'M'},
1603 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1604 /* This formerly implied "stripe-index", but was confusing
1605 * with "file offset" (which will eventually be needed for
1606 * with different layouts by offset), so deprecate it. */
1607 {"offset", no_argument, 0, 'o'},
1609 {"obd", required_argument, 0, 'O'},
1610 {"ost", required_argument, 0, 'O'},
1611 {"pool", no_argument, 0, 'p'},
1612 {"quiet", no_argument, 0, 'q'},
1613 {"recursive", no_argument, 0, 'r'},
1614 {"raw", no_argument, 0, 'R'},
1615 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1616 /* This formerly implied "--stripe-size", but was confusing
1617 * with "lfs find --size|-s", which means "file size", so use
1618 * the consistent "--stripe-size|-S" for all commands. */
1619 {"size", no_argument, 0, 's'},
1621 {"stripe-size", no_argument, 0, 'S'},
1622 {"stripe_size", no_argument, 0, 'S'},
1623 {"verbose", no_argument, 0, 'v'},
1628 param->fp_max_depth = 1;
1629 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1630 long_opts, NULL)) != -1) {
1633 if (param->fp_obd_uuid) {
1635 "error: %s: only one obduuid allowed",
1639 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1645 param->fp_max_depth = 0;
1648 param->fp_get_default_lmv = 1;
1651 param->fp_recursive = 1;
1654 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1657 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1658 if (strcmp(argv[optind - 1], "--count") == 0)
1659 fprintf(stderr, "warning: '--count' deprecated,"
1660 " use '--stripe-count' instead\n");
1662 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1663 param->fp_verbose |= VERBOSE_COUNT;
1664 param->fp_max_depth = 0;
1667 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1669 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1670 fprintf(stderr, "warning: '--size|-s' deprecated, "
1671 "use '--stripe-size|-S' instead\n");
1673 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1675 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1676 param->fp_verbose |= VERBOSE_SIZE;
1677 param->fp_max_depth = 0;
1680 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1682 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1683 "use '--stripe-index|-i' instead\n");
1686 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1687 if (strcmp(argv[optind - 1], "--index") == 0)
1688 fprintf(stderr, "warning: '--index' deprecated"
1689 ", use '--stripe-index' instead\n");
1691 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1692 param->fp_verbose |= VERBOSE_OFFSET;
1693 param->fp_max_depth = 0;
1697 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1698 param->fp_verbose |= VERBOSE_POOL;
1699 param->fp_max_depth = 0;
1703 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1704 param->fp_verbose |= VERBOSE_GENERATION;
1705 param->fp_max_depth = 0;
1709 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1710 param->fp_verbose |= VERBOSE_LAYOUT;
1711 param->fp_max_depth = 0;
1715 if (!(param->fp_verbose & VERBOSE_DETAIL))
1716 param->fp_max_depth = 0;
1717 param->fp_verbose |= VERBOSE_MDTINDEX;
1730 if (param->fp_recursive)
1731 param->fp_max_depth = -1;
1733 if (!param->fp_verbose)
1734 param->fp_verbose = VERBOSE_ALL;
1735 if (param->fp_quiet)
1736 param->fp_verbose = VERBOSE_OBJID;
1739 rc = llapi_getstripe(argv[optind], param);
1740 } while (++optind < argc && !rc);
1743 fprintf(stderr, "error: %s failed for %s.\n",
1744 argv[0], argv[optind - 1]);
1748 static int lfs_tgts(int argc, char **argv)
1750 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1751 struct find_param param;
1752 int index = 0, rc=0;
1757 if (argc == 2 && !realpath(argv[1], path)) {
1759 fprintf(stderr, "error: invalid path '%s': %s\n",
1760 argv[1], strerror(-rc));
1764 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1765 /* Check if we have a mount point */
1766 if (mntdir[0] == '\0')
1769 memset(¶m, 0, sizeof(param));
1770 if (!strcmp(argv[0], "mdts"))
1771 param.fp_get_lmv = 1;
1773 rc = llapi_ostlist(mntdir, ¶m);
1775 fprintf(stderr, "error: %s: failed on %s\n",
1778 if (path[0] != '\0')
1780 memset(mntdir, 0, PATH_MAX);
1786 static int lfs_getstripe(int argc, char **argv)
1788 struct find_param param = { 0 };
1789 return lfs_getstripe_internal(argc, argv, ¶m);
1793 static int lfs_getdirstripe(int argc, char **argv)
1795 struct find_param param = { 0 };
1797 param.fp_get_lmv = 1;
1798 return lfs_getstripe_internal(argc, argv, ¶m);
1802 static int lfs_setdirstripe(int argc, char **argv)
1806 unsigned int stripe_offset = -1;
1807 unsigned int stripe_count = 1;
1808 enum lmv_hash_type hash_type;
1811 char *stripe_offset_opt = NULL;
1812 char *stripe_count_opt = NULL;
1813 char *stripe_hash_opt = NULL;
1814 char *mode_opt = NULL;
1815 bool default_stripe = false;
1816 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1817 mode_t previous_mode = 0;
1818 bool delete = false;
1820 struct option long_opts[] = {
1821 {"count", required_argument, 0, 'c'},
1822 {"delete", no_argument, 0, 'd'},
1823 {"index", required_argument, 0, 'i'},
1824 {"mode", required_argument, 0, 'm'},
1825 {"hash-type", required_argument, 0, 't'},
1826 {"default_stripe", no_argument, 0, 'D'},
1830 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1837 stripe_count_opt = optarg;
1841 default_stripe = true;
1844 default_stripe = true;
1847 stripe_offset_opt = optarg;
1853 stripe_hash_opt = optarg;
1856 fprintf(stderr, "error: %s: option '%s' "
1858 argv[0], argv[optind - 1]);
1863 if (optind == argc) {
1864 fprintf(stderr, "error: %s: missing dirname\n",
1869 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1870 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1875 if (stripe_offset_opt != NULL) {
1876 /* get the stripe offset */
1877 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1879 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1880 argv[0], stripe_offset_opt);
1886 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1887 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1888 " or -i options.\n", argv[0]);
1896 if (mode_opt != NULL) {
1897 mode = strtoul(mode_opt, &end, 8);
1899 fprintf(stderr, "error: %s: bad mode '%s'\n",
1903 previous_mode = umask(0);
1906 if (stripe_hash_opt == NULL ||
1907 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1908 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1909 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1910 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1912 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1913 argv[0], stripe_hash_opt);
1917 /* get the stripe count */
1918 if (stripe_count_opt != NULL) {
1919 stripe_count = strtoul(stripe_count_opt, &end, 0);
1921 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1922 argv[0], stripe_count_opt);
1927 dname = argv[optind];
1929 if (default_stripe) {
1930 result = llapi_dir_set_default_lmv_stripe(dname,
1931 stripe_offset, stripe_count,
1934 result = llapi_dir_create_pool(dname, mode,
1936 stripe_count, hash_type,
1941 fprintf(stderr, "error: %s: create stripe dir '%s' "
1942 "failed\n", argv[0], dname);
1945 dname = argv[++optind];
1946 } while (dname != NULL);
1948 if (mode_opt != NULL)
1949 umask(previous_mode);
1955 static int lfs_rmentry(int argc, char **argv)
1962 fprintf(stderr, "error: %s: missing dirname\n",
1968 dname = argv[index];
1969 while (dname != NULL) {
1970 result = llapi_direntry_remove(dname);
1972 fprintf(stderr, "error: %s: remove dir entry '%s' "
1973 "failed\n", argv[0], dname);
1976 dname = argv[++index];
1981 static int lfs_mv(int argc, char **argv)
1983 struct find_param param = {
1990 struct option long_opts[] = {
1991 {"mdt-index", required_argument, 0, 'M'},
1992 {"verbose", no_argument, 0, 'v'},
1996 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
1999 param.fp_mdt_index = strtoul(optarg, &end, 0);
2001 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2008 param.fp_verbose = VERBOSE_DETAIL;
2012 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2013 argv[0], argv[optind - 1]);
2018 if (param.fp_mdt_index == -1) {
2019 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2023 if (optind >= argc) {
2024 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2028 param.fp_migrate = 1;
2029 rc = llapi_mv(argv[optind], ¶m);
2031 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2032 argv[0], argv[optind], param.fp_mdt_index,
2037 static int lfs_osts(int argc, char **argv)
2039 return lfs_tgts(argc, argv);
2042 static int lfs_mdts(int argc, char **argv)
2044 return lfs_tgts(argc, argv);
2047 #define COOK(value) \
2050 while (value > 1024) { \
2058 #define CDF "%11llu"
2059 #define HDF "%8.1f%c"
2063 static int showdf(char *mntdir, struct obd_statfs *stat,
2064 char *uuid, int ishow, int cooked,
2065 char *type, int index, int rc)
2067 long long avail, used, total;
2069 char *suffix = "KMGTPEZY";
2070 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2071 char tbuf[3 * sizeof(__u64)];
2072 char ubuf[3 * sizeof(__u64)];
2073 char abuf[3 * sizeof(__u64)];
2074 char rbuf[3 * sizeof(__u64)];
2082 avail = stat->os_ffree;
2083 used = stat->os_files - stat->os_ffree;
2084 total = stat->os_files;
2086 int shift = cooked ? 0 : 10;
2088 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2089 used = ((stat->os_blocks - stat->os_bfree) *
2090 stat->os_bsize) >> shift;
2091 total = (stat->os_blocks * stat->os_bsize) >> shift;
2094 if ((used + avail) > 0)
2095 ratio = (double)used / (double)(used + avail);
2101 cook_val = (double)total;
2104 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2106 sprintf(tbuf, CDF, total);
2108 cook_val = (double)used;
2111 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2113 sprintf(ubuf, CDF, used);
2115 cook_val = (double)avail;
2118 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2120 sprintf(abuf, CDF, avail);
2122 sprintf(tbuf, CDF, total);
2123 sprintf(ubuf, CDF, used);
2124 sprintf(abuf, CDF, avail);
2127 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2128 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2129 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2131 printf("[%s:%d]\n", type, index);
2137 printf(UUF": inactive device\n", uuid);
2140 printf(UUF": %s\n", uuid, strerror(-rc));
2147 struct ll_stat_type {
2152 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2153 int cooked, int lazy)
2155 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2156 struct obd_uuid uuid_buf;
2157 char *poolname = NULL;
2158 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2159 { LL_STATFS_LOV, "OST" },
2161 struct ll_stat_type *tp;
2162 __u64 ost_ffree = 0;
2168 poolname = strchr(pool, '.');
2169 if (poolname != NULL) {
2170 if (strncmp(fsname, pool, strlen(fsname))) {
2171 fprintf(stderr, "filesystem name incorrect\n");
2180 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2181 "UUID", "Inodes", "IUsed", "IFree",
2182 "IUse%", "Mounted on");
2184 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2185 "UUID", cooked ? "bytes" : "1K-blocks",
2186 "Used", "Available", "Use%", "Mounted on");
2188 for (tp = types; tp->st_name != NULL; tp++) {
2189 for (index = 0; ; index++) {
2190 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2191 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2192 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2193 rc = llapi_obd_statfs(mntdir, type, index,
2194 &stat_buf, &uuid_buf);
2201 if (poolname && tp->st_op == LL_STATFS_LOV &&
2202 llapi_search_ost(fsname, poolname,
2203 obd_uuid2str(&uuid_buf)) != 1)
2206 /* the llapi_obd_statfs() call may have returned with
2207 * an error, but if it filled in uuid_buf we will at
2208 * lease use that to print out a message for that OBD.
2209 * If we didn't get anything in the uuid_buf, then fill
2210 * it in so that we can print an error message. */
2211 if (uuid_buf.uuid[0] == '\0')
2212 sprintf(uuid_buf.uuid, "%s%04x",
2213 tp->st_name, index);
2214 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2215 ishow, cooked, tp->st_name, index, rc);
2218 if (tp->st_op == LL_STATFS_LMV) {
2219 sum.os_ffree += stat_buf.os_ffree;
2220 sum.os_files += stat_buf.os_files;
2221 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2222 sum.os_blocks += stat_buf.os_blocks *
2224 sum.os_bfree += stat_buf.os_bfree *
2226 sum.os_bavail += stat_buf.os_bavail *
2228 ost_ffree += stat_buf.os_ffree;
2230 } else if (rc == -EINVAL || rc == -EFAULT) {
2236 /* If we don't have as many objects free on the OST as inodes
2237 * on the MDS, we reduce the total number of inodes to
2238 * compensate, so that the "inodes in use" number is correct.
2239 * Matches ll_statfs_internal() so the results are consistent. */
2240 if (ost_ffree < sum.os_ffree) {
2241 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2242 sum.os_ffree = ost_ffree;
2245 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2250 static int lfs_df(int argc, char **argv)
2252 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2253 int ishow = 0, cooked = 0;
2255 int c, rc = 0, index = 0;
2256 char fsname[PATH_MAX] = "", *pool_name = NULL;
2257 struct option long_opts[] = {
2258 {"pool", required_argument, 0, 'p'},
2259 {"lazy", 0, 0, 'l'},
2263 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2281 if (optind < argc && !realpath(argv[optind], path)) {
2283 fprintf(stderr, "error: invalid path '%s': %s\n",
2284 argv[optind], strerror(-rc));
2288 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2289 /* Check if we have a mount point */
2290 if (mntdir[0] == '\0')
2293 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2294 if (rc || path[0] != '\0')
2296 fsname[0] = '\0'; /* avoid matching in next loop */
2297 mntdir[0] = '\0'; /* avoid matching in next loop */
2303 static int lfs_getname(int argc, char **argv)
2305 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2306 int rc = 0, index = 0, c;
2307 char buf[sizeof(struct obd_uuid)];
2309 while ((c = getopt(argc, argv, "h")) != -1)
2312 if (optind == argc) { /* no paths specified, get all paths. */
2313 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2314 rc = llapi_getname(mntdir, buf, sizeof(buf));
2317 "cannot get name for `%s': %s\n",
2318 mntdir, strerror(-rc));
2322 printf("%s %s\n", buf, mntdir);
2324 path[0] = fsname[0] = mntdir[0] = 0;
2326 } else { /* paths specified, only attempt to search these. */
2327 for (; optind < argc; optind++) {
2328 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2331 "cannot get name for `%s': %s\n",
2332 argv[optind], strerror(-rc));
2336 printf("%s %s\n", buf, argv[optind]);
2342 static int lfs_check(int argc, char **argv)
2345 char mntdir[PATH_MAX] = {'\0'};
2354 obd_types[0] = obd_type1;
2355 obd_types[1] = obd_type2;
2357 if (strcmp(argv[1], "osts") == 0) {
2358 strcpy(obd_types[0], "osc");
2359 } else if (strcmp(argv[1], "mds") == 0) {
2360 strcpy(obd_types[0], "mdc");
2361 } else if (strcmp(argv[1], "servers") == 0) {
2363 strcpy(obd_types[0], "osc");
2364 strcpy(obd_types[1], "mdc");
2366 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2371 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2372 if (rc < 0 || mntdir[0] == '\0') {
2373 fprintf(stderr, "No suitable Lustre mount found\n");
2377 rc = llapi_target_check(num_types, obd_types, mntdir);
2379 fprintf(stderr, "error: %s: %s status failed\n",
2386 static int lfs_join(int argc, char **argv)
2388 fprintf(stderr, "join two lustre files into one.\n"
2389 "obsolete, HEAD does not support it anymore.\n");
2393 #ifdef HAVE_SYS_QUOTA_H
2394 #define ARG2INT(nr, str, msg) \
2397 nr = strtol(str, &endp, 0); \
2399 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2404 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2406 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2407 * returns the value or ULONG_MAX on integer overflow or incorrect format
2409 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2410 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2411 * 3. empty integer value is interpreted as 0
2413 static unsigned long str2sec(const char* timestr)
2415 const char spec[] = "smhdw";
2416 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2417 unsigned long val = 0;
2420 if (strpbrk(timestr, spec) == NULL) {
2421 /* no specifiers inside the time string,
2422 should treat it as an integer value */
2423 val = strtoul(timestr, &tail, 10);
2424 return *tail ? ULONG_MAX : val;
2427 /* format string is XXwXXdXXhXXmXXs */
2433 v = strtoul(timestr, &tail, 10);
2434 if (v == ULONG_MAX || *tail == '\0')
2435 /* value too large (ULONG_MAX or more)
2436 or missing specifier */
2439 ptr = strchr(spec, *tail);
2441 /* unknown specifier */
2446 /* check if product will overflow the type */
2447 if (!(v < ULONG_MAX / mult[ind]))
2450 ADD_OVERFLOW(val, mult[ind] * v);
2451 if (val == ULONG_MAX)
2463 #define ARG2ULL(nr, str, def_units) \
2465 unsigned long long limit, units = def_units; \
2468 rc = llapi_parse_size(str, &limit, &units, 1); \
2470 fprintf(stderr, "error: bad limit value %s\n", str); \
2476 static inline int has_times_option(int argc, char **argv)
2480 for (i = 1; i < argc; i++)
2481 if (!strcmp(argv[i], "-t"))
2487 int lfs_setquota_times(int argc, char **argv)
2490 struct if_quotactl qctl;
2491 char *mnt, *obd_type = (char *)qctl.obd_type;
2492 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2493 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2494 struct option long_opts[] = {
2495 {"block-grace", required_argument, 0, 'b'},
2496 {"group", no_argument, 0, 'g'},
2497 {"inode-grace", required_argument, 0, 'i'},
2498 {"times", no_argument, 0, 't'},
2499 {"user", no_argument, 0, 'u'},
2503 memset(&qctl, 0, sizeof(qctl));
2504 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2505 qctl.qc_type = UGQUOTA;
2507 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2511 if (qctl.qc_type != UGQUOTA) {
2512 fprintf(stderr, "error: -u and -g can't be used "
2513 "more than once\n");
2516 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2519 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2520 fprintf(stderr, "error: bad block-grace: %s\n",
2524 dqb->dqb_valid |= QIF_BTIME;
2527 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2528 fprintf(stderr, "error: bad inode-grace: %s\n",
2532 dqb->dqb_valid |= QIF_ITIME;
2534 case 't': /* Yes, of course! */
2536 default: /* getopt prints error message for us when opterr != 0 */
2541 if (qctl.qc_type == UGQUOTA) {
2542 fprintf(stderr, "error: neither -u nor -g specified\n");
2546 if (optind != argc - 1) {
2547 fprintf(stderr, "error: unexpected parameters encountered\n");
2552 rc = llapi_quotactl(mnt, &qctl);
2555 fprintf(stderr, "%s %s ", obd_type,
2556 obd_uuid2str(&qctl.obd_uuid));
2557 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2564 #define BSLIMIT (1 << 0)
2565 #define BHLIMIT (1 << 1)
2566 #define ISLIMIT (1 << 2)
2567 #define IHLIMIT (1 << 3)
2569 int lfs_setquota(int argc, char **argv)
2572 struct if_quotactl qctl;
2573 char *mnt, *obd_type = (char *)qctl.obd_type;
2574 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2575 struct option long_opts[] = {
2576 {"block-softlimit", required_argument, 0, 'b'},
2577 {"block-hardlimit", required_argument, 0, 'B'},
2578 {"group", required_argument, 0, 'g'},
2579 {"inode-softlimit", required_argument, 0, 'i'},
2580 {"inode-hardlimit", required_argument, 0, 'I'},
2581 {"user", required_argument, 0, 'u'},
2584 unsigned limit_mask = 0;
2587 if (has_times_option(argc, argv))
2588 return lfs_setquota_times(argc, argv);
2590 memset(&qctl, 0, sizeof(qctl));
2591 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2592 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2593 * so it can be used as a marker that qc_type
2594 * isn't reinitialized from command line */
2596 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2600 if (qctl.qc_type != UGQUOTA) {
2601 fprintf(stderr, "error: -u and -g can't be used"
2602 " more than once\n");
2605 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2606 rc = name2id(&qctl.qc_id, optarg,
2607 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2609 qctl.qc_id = strtoul(optarg, &endptr, 10);
2610 if (*endptr != '\0') {
2611 fprintf(stderr, "error: can't find id "
2612 "for name %s\n", optarg);
2618 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2619 dqb->dqb_bsoftlimit >>= 10;
2620 limit_mask |= BSLIMIT;
2621 if (dqb->dqb_bsoftlimit &&
2622 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2623 fprintf(stderr, "warning: block softlimit is "
2624 "smaller than the miminal qunit size, "
2625 "please see the help of setquota or "
2626 "Lustre manual for details.\n");
2629 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2630 dqb->dqb_bhardlimit >>= 10;
2631 limit_mask |= BHLIMIT;
2632 if (dqb->dqb_bhardlimit &&
2633 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2634 fprintf(stderr, "warning: block hardlimit is "
2635 "smaller than the miminal qunit size, "
2636 "please see the help of setquota or "
2637 "Lustre manual for details.\n");
2640 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2641 limit_mask |= ISLIMIT;
2642 if (dqb->dqb_isoftlimit &&
2643 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2644 fprintf(stderr, "warning: inode softlimit is "
2645 "smaller than the miminal qunit size, "
2646 "please see the help of setquota or "
2647 "Lustre manual for details.\n");
2650 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2651 limit_mask |= IHLIMIT;
2652 if (dqb->dqb_ihardlimit &&
2653 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2654 fprintf(stderr, "warning: inode hardlimit is "
2655 "smaller than the miminal qunit size, "
2656 "please see the help of setquota or "
2657 "Lustre manual for details.\n");
2659 default: /* getopt prints error message for us when opterr != 0 */
2664 if (qctl.qc_type == UGQUOTA) {
2665 fprintf(stderr, "error: neither -u nor -g was specified\n");
2669 if (limit_mask == 0) {
2670 fprintf(stderr, "error: at least one limit must be specified\n");
2674 if (optind != argc - 1) {
2675 fprintf(stderr, "error: unexpected parameters encountered\n");
2681 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2682 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2683 /* sigh, we can't just set blimits/ilimits */
2684 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2685 .qc_type = qctl.qc_type,
2686 .qc_id = qctl.qc_id};
2688 rc = llapi_quotactl(mnt, &tmp_qctl);
2690 fprintf(stderr, "error: setquota failed while retrieving"
2691 " current quota settings (%s)\n",
2696 if (!(limit_mask & BHLIMIT))
2697 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2698 if (!(limit_mask & BSLIMIT))
2699 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2700 if (!(limit_mask & IHLIMIT))
2701 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2702 if (!(limit_mask & ISLIMIT))
2703 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2705 /* Keep grace times if we have got no softlimit arguments */
2706 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2707 dqb->dqb_valid |= QIF_BTIME;
2708 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2711 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2712 dqb->dqb_valid |= QIF_ITIME;
2713 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2717 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2718 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2720 rc = llapi_quotactl(mnt, &qctl);
2723 fprintf(stderr, "%s %s ", obd_type,
2724 obd_uuid2str(&qctl.obd_uuid));
2725 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2732 static inline char *type2name(int check_type)
2734 if (check_type == USRQUOTA)
2736 else if (check_type == GRPQUOTA)
2742 /* Converts seconds value into format string
2743 * result is returned in buf
2745 * 1. result is in descenting order: 1w2d3h4m5s
2746 * 2. zero fields are not filled (except for p. 3): 5d1s
2747 * 3. zero seconds value is presented as "0s"
2749 static char * __sec2str(time_t seconds, char *buf)
2751 const char spec[] = "smhdw";
2752 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2757 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2758 c = seconds / mult[i];
2760 if (c > 0 || (i == 0 && buf == tail))
2761 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2769 static void sec2str(time_t seconds, char *buf, int rc)
2776 tail = __sec2str(seconds, tail);
2778 if (rc && tail - buf < 39) {
2784 static void diff2str(time_t seconds, char *buf, time_t now)
2790 if (seconds <= now) {
2791 strcpy(buf, "none");
2794 __sec2str(seconds - now, buf);
2797 static void print_quota_title(char *name, struct if_quotactl *qctl,
2798 bool human_readable)
2800 printf("Disk quotas for %s %s (%cid %u):\n",
2801 type2name(qctl->qc_type), name,
2802 *type2name(qctl->qc_type), qctl->qc_id);
2803 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2804 "Filesystem", human_readable ? "used" : "kbytes",
2805 "quota", "limit", "grace",
2806 "files", "quota", "limit", "grace");
2809 static void kbytes2str(__u64 num, char *buf, bool h)
2812 sprintf(buf, LPU64, num);
2815 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2817 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2819 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2821 sprintf(buf, LPU64"%s", num, "k");
2825 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2832 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2833 int bover = 0, iover = 0;
2834 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2839 if (dqb->dqb_bhardlimit &&
2840 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2842 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2843 if (dqb->dqb_btime > now) {
2850 if (dqb->dqb_ihardlimit &&
2851 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2853 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2854 if (dqb->dqb_itime > now) {
2862 if (strlen(mnt) > 15)
2863 printf("%s\n%15s", mnt, "");
2865 printf("%15s", mnt);
2868 diff2str(dqb->dqb_btime, timebuf, now);
2870 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2871 if (rc == -EREMOTEIO)
2872 sprintf(numbuf[0], "%s*", strbuf);
2874 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2875 "%s" : "[%s]", strbuf);
2877 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2878 if (type == QC_GENERAL)
2879 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2880 "%s" : "[%s]", strbuf);
2882 sprintf(numbuf[1], "%s", "-");
2884 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2885 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2886 "%s" : "[%s]", strbuf);
2888 printf(" %7s%c %6s %7s %7s",
2889 numbuf[0], bover ? '*' : ' ', numbuf[1],
2890 numbuf[2], bover > 1 ? timebuf : "-");
2893 diff2str(dqb->dqb_itime, timebuf, now);
2895 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2896 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2898 if (type == QC_GENERAL)
2899 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2900 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2902 sprintf(numbuf[1], "%s", "-");
2904 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2905 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2907 if (type != QC_OSTIDX)
2908 printf(" %7s%c %6s %7s %7s",
2909 numbuf[0], iover ? '*' : ' ', numbuf[1],
2910 numbuf[2], iover > 1 ? timebuf : "-");
2912 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2915 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2916 qctl->qc_cmd == Q_GETOINFO) {
2920 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2921 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2922 printf("Block grace time: %s; Inode grace time: %s\n",
2923 bgtimebuf, igtimebuf);
2927 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2928 bool h, __u64 *total)
2930 int rc = 0, rc1 = 0, count = 0;
2931 __u32 valid = qctl->qc_valid;
2933 rc = llapi_get_obd_count(mnt, &count, is_mdt);
2935 fprintf(stderr, "can not get %s count: %s\n",
2936 is_mdt ? "mdt": "ost", strerror(-rc));
2940 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2941 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2942 rc = llapi_quotactl(mnt, qctl);
2944 /* It is remote client case. */
2945 if (-rc == EOPNOTSUPP) {
2952 fprintf(stderr, "quotactl %s%d failed.\n",
2953 is_mdt ? "mdt": "ost", qctl->qc_idx);
2957 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
2958 qctl->qc_valid, 0, h);
2959 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
2960 qctl->qc_dqblk.dqb_bhardlimit;
2963 qctl->qc_valid = valid;
2967 static int lfs_quota(int argc, char **argv)
2970 char *mnt, *name = NULL;
2971 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2972 .qc_type = UGQUOTA };
2973 char *obd_type = (char *)qctl.obd_type;
2974 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2975 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2976 verbose = 0, pass = 0, quiet = 0, inacc;
2978 __u32 valid = QC_GENERAL, idx = 0;
2979 __u64 total_ialloc = 0, total_balloc = 0;
2980 bool human_readable = false;
2982 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
2985 if (qctl.qc_type != UGQUOTA) {
2986 fprintf(stderr, "error: use either -u or -g\n");
2989 qctl.qc_type = USRQUOTA;
2992 if (qctl.qc_type != UGQUOTA) {
2993 fprintf(stderr, "error: use either -u or -g\n");
2996 qctl.qc_type = GRPQUOTA;
2999 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3002 valid = qctl.qc_valid = QC_UUID;
3003 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3006 valid = qctl.qc_valid = QC_MDTIDX;
3007 idx = qctl.qc_idx = atoi(optarg);
3010 valid = qctl.qc_valid = QC_OSTIDX;
3011 idx = qctl.qc_idx = atoi(optarg);
3020 human_readable = true;
3023 fprintf(stderr, "error: %s: option '-%c' "
3024 "unrecognized\n", argv[0], c);
3029 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3030 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3031 optind == argc - 1) {
3033 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3034 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3035 qctl.qc_valid = valid;
3038 qctl.qc_type = USRQUOTA;
3039 qctl.qc_id = geteuid();
3041 qctl.qc_type = GRPQUOTA;
3042 qctl.qc_id = getegid();
3044 rc = id2name(&name, qctl.qc_id,
3045 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3048 /* lfs quota -u username /path/to/lustre/mount */
3049 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3050 /* options should be followed by u/g-name and mntpoint */
3051 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3052 fprintf(stderr, "error: missing quota argument(s)\n");
3056 name = argv[optind++];
3057 rc = name2id(&qctl.qc_id, name,
3058 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3060 qctl.qc_id = strtoul(name, &endptr, 10);
3061 if (*endptr != '\0') {
3062 fprintf(stderr, "error: can't find id for name "
3067 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3068 fprintf(stderr, "error: missing quota info argument(s)\n");
3074 rc1 = llapi_quotactl(mnt, &qctl);
3078 fprintf(stderr, "%s quotas are not enabled.\n",
3079 qctl.qc_type == USRQUOTA ? "user" : "group");
3082 fprintf(stderr, "Permission denied.\n");
3084 /* We already got a "No such file..." message. */
3087 fprintf(stderr, "Unexpected quotactl error: %s\n",
3092 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3093 print_quota_title(name, &qctl, human_readable);
3095 if (rc1 && *obd_type)
3096 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3098 if (qctl.qc_valid != QC_GENERAL)
3101 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3102 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3103 (QIF_LIMITS|QIF_USAGE));
3105 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3107 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3111 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3113 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3115 kbytes2str(total_balloc, strbuf, human_readable);
3116 printf("Total allocated inode limit: "LPU64", total "
3117 "allocated block limit: %s\n", total_ialloc, strbuf);
3120 if (rc1 || rc2 || rc3 || inacc)
3121 printf("Some errors happened when getting quota info. "
3122 "Some devices may be not working or deactivated. "
3123 "The data in \"[]\" is inaccurate.\n");
3131 #endif /* HAVE_SYS_QUOTA_H! */
3133 static int flushctx_ioctl(char *mp)
3137 fd = open(mp, O_RDONLY);
3139 fprintf(stderr, "flushctx: error open %s: %s\n",
3140 mp, strerror(errno));
3144 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3146 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3147 mp, strerror(errno));
3153 static int lfs_flushctx(int argc, char **argv)
3155 int kdestroy = 0, c;
3156 char mntdir[PATH_MAX] = {'\0'};
3160 while ((c = getopt(argc, argv, "k")) != -1) {
3166 fprintf(stderr, "error: %s: option '-%c' "
3167 "unrecognized\n", argv[0], c);
3173 if ((rc = system("kdestroy > /dev/null")) != 0) {
3174 rc = WEXITSTATUS(rc);
3175 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3179 if (optind >= argc) {
3180 /* flush for all mounted lustre fs. */
3181 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3182 /* Check if we have a mount point */
3183 if (mntdir[0] == '\0')
3186 if (flushctx_ioctl(mntdir))
3189 mntdir[0] = '\0'; /* avoid matching in next loop */
3192 /* flush fs as specified */
3193 while (optind < argc) {
3194 if (flushctx_ioctl(argv[optind++]))
3201 static int lfs_lsetfacl(int argc, char **argv)
3204 return(llapi_lsetfacl(argc, argv));
3207 static int lfs_lgetfacl(int argc, char **argv)
3210 return(llapi_lgetfacl(argc, argv));
3213 static int lfs_rsetfacl(int argc, char **argv)
3216 return(llapi_rsetfacl(argc, argv));
3219 static int lfs_rgetfacl(int argc, char **argv)
3222 return(llapi_rgetfacl(argc, argv));
3225 static int lfs_cp(int argc, char **argv)
3227 return(llapi_cp(argc, argv));
3230 static int lfs_ls(int argc, char **argv)
3232 return(llapi_ls(argc, argv));
3235 static int lfs_changelog(int argc, char **argv)
3237 void *changelog_priv;
3238 struct changelog_rec *rec;
3239 long long startrec = 0, endrec = 0;
3241 struct option long_opts[] = {
3242 {"follow", no_argument, 0, 'f'},
3245 char short_opts[] = "f";
3248 while ((rc = getopt_long(argc, argv, short_opts,
3249 long_opts, NULL)) != -1) {
3257 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3258 argv[0], argv[optind - 1]);
3265 mdd = argv[optind++];
3267 startrec = strtoll(argv[optind++], NULL, 10);
3269 endrec = strtoll(argv[optind++], NULL, 10);
3271 rc = llapi_changelog_start(&changelog_priv,
3272 CHANGELOG_FLAG_BLOCK |
3273 CHANGELOG_FLAG_JOBID |
3274 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3277 fprintf(stderr, "Can't start changelog: %s\n",
3278 strerror(errno = -rc));
3282 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3286 if (endrec && rec->cr_index > endrec) {
3287 llapi_changelog_free(&rec);
3290 if (rec->cr_index < startrec) {
3291 llapi_changelog_free(&rec);
3295 secs = rec->cr_time >> 30;
3296 gmtime_r(&secs, &ts);
3297 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3298 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3299 changelog_type2str(rec->cr_type),
3300 ts.tm_hour, ts.tm_min, ts.tm_sec,
3301 (int)(rec->cr_time & ((1<<30) - 1)),
3302 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3303 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3305 if (rec->cr_flags & CLF_JOBID) {
3306 struct changelog_ext_jobid *jid =
3307 changelog_rec_jobid(rec);
3309 if (jid->cr_jobid[0] != '\0')
3310 printf(" j=%s", jid->cr_jobid);
3313 if (rec->cr_namelen)
3314 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3315 rec->cr_namelen, changelog_rec_name(rec));
3317 if (rec->cr_flags & CLF_RENAME) {
3318 struct changelog_ext_rename *rnm =
3319 changelog_rec_rename(rec);
3321 if (!fid_is_zero(&rnm->cr_sfid))
3322 printf(" s="DFID" sp="DFID" %.*s",
3323 PFID(&rnm->cr_sfid),
3324 PFID(&rnm->cr_spfid),
3325 (int)changelog_rec_snamelen(rec),
3326 changelog_rec_sname(rec));
3330 llapi_changelog_free(&rec);
3333 llapi_changelog_fini(&changelog_priv);
3336 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3338 return (rc == 1 ? 0 : rc);
3341 static int lfs_changelog_clear(int argc, char **argv)
3349 endrec = strtoll(argv[3], NULL, 10);
3351 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3353 fprintf(stderr, "%s error: %s\n", argv[0],
3354 strerror(errno = -rc));
3358 static int lfs_fid2path(int argc, char **argv)
3360 struct option long_opts[] = {
3361 {"cur", no_argument, 0, 'c'},
3362 {"link", required_argument, 0, 'l'},
3363 {"rec", required_argument, 0, 'r'},
3366 char short_opts[] = "cl:r:";
3367 char *device, *fid, *path;
3368 long long recno = -1;
3374 while ((rc = getopt_long(argc, argv, short_opts,
3375 long_opts, NULL)) != -1) {
3381 linkno = strtol(optarg, NULL, 10);
3384 recno = strtoll(optarg, NULL, 10);
3389 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3390 argv[0], argv[optind - 1]);
3398 device = argv[optind++];
3399 path = calloc(1, PATH_MAX);
3401 fprintf(stderr, "error: Not enough memory\n");
3406 while (optind < argc) {
3407 fid = argv[optind++];
3409 lnktmp = (linkno >= 0) ? linkno : 0;
3411 int oldtmp = lnktmp;
3412 long long rectmp = recno;
3414 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3417 fprintf(stderr, "%s: error on FID %s: %s\n",
3418 argv[0], fid, strerror(errno = -rc2));
3425 fprintf(stdout, "%lld ", rectmp);
3426 if (device[0] == '/') {
3427 fprintf(stdout, "%s", device);
3428 if (device[strlen(device) - 1] != '/')
3429 fprintf(stdout, "/");
3430 } else if (path[0] == '\0') {
3431 fprintf(stdout, "/");
3433 fprintf(stdout, "%s\n", path);
3436 /* specified linkno */
3438 if (oldtmp == lnktmp)
3448 static int lfs_path2fid(int argc, char **argv)
3450 struct option long_opts[] = {
3451 {"parents", no_argument, 0, 'p'},
3455 const char short_opts[] = "p";
3456 const char *sep = "";
3459 bool show_parents = false;
3461 while ((rc = getopt_long(argc, argv, short_opts,
3462 long_opts, NULL)) != -1) {
3465 show_parents = true;
3468 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3469 argv[0], argv[optind - 1]);
3474 if (optind > argc - 1)
3476 else if (optind < argc - 1)
3480 for (path = argv + optind; *path != NULL; path++) {
3482 if (!show_parents) {
3483 err = llapi_path2fid(*path, &fid);
3485 printf("%s%s"DFID"\n",
3486 *sep != '\0' ? *path : "", sep,
3489 char name[NAME_MAX + 1];
3490 unsigned int linkno = 0;
3492 while ((err = llapi_path2parent(*path, linkno, &fid,
3493 name, sizeof(name))) == 0) {
3494 if (*sep != '\0' && linkno == 0)
3495 printf("%s%s", *path, sep);
3497 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3502 /* err == -ENODATA is end-of-loop */
3503 if (linkno > 0 && err == -ENODATA) {
3510 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3511 argv[0], show_parents ? "parent " : "", *path,
3523 static int lfs_data_version(int argc, char **argv)
3530 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3535 while ((c = getopt(argc, argv, "nrw")) != -1) {
3538 data_version_flags = 0;
3541 data_version_flags |= LL_DV_RD_FLUSH;
3544 data_version_flags |= LL_DV_WR_FLUSH;
3553 path = argv[optind];
3554 fd = open(path, O_RDONLY);
3556 err(errno, "cannot open file %s", path);
3558 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3560 err(errno, "cannot get version for %s", path);
3562 printf(LPU64 "\n", data_version);
3568 static int lfs_hsm_state(int argc, char **argv)
3573 struct hsm_user_state hus;
3581 rc = llapi_hsm_state_get(path, &hus);
3583 fprintf(stderr, "can't get hsm state for %s: %s\n",
3584 path, strerror(errno = -rc));
3588 /* Display path name and status flags */
3589 printf("%s: (0x%08x)", path, hus.hus_states);
3591 if (hus.hus_states & HS_RELEASED)
3592 printf(" released");
3593 if (hus.hus_states & HS_EXISTS)
3595 if (hus.hus_states & HS_DIRTY)
3597 if (hus.hus_states & HS_ARCHIVED)
3598 printf(" archived");
3599 /* Display user-settable flags */
3600 if (hus.hus_states & HS_NORELEASE)
3601 printf(" never_release");
3602 if (hus.hus_states & HS_NOARCHIVE)
3603 printf(" never_archive");
3604 if (hus.hus_states & HS_LOST)
3605 printf(" lost_from_hsm");
3607 if (hus.hus_archive_id != 0)
3608 printf(", archive_id:%d", hus.hus_archive_id);
3611 } while (++i < argc);
3616 #define LFS_HSM_SET 0
3617 #define LFS_HSM_CLEAR 1
3620 * Generic function to set or clear HSM flags.
3621 * Used by hsm_set and hsm_clear.
3623 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3625 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3627 struct option long_opts[] = {
3628 {"lost", 0, 0, 'l'},
3629 {"norelease", 0, 0, 'r'},
3630 {"noarchive", 0, 0, 'a'},
3631 {"archived", 0, 0, 'A'},
3632 {"dirty", 0, 0, 'd'},
3633 {"exists", 0, 0, 'e'},
3636 char short_opts[] = "lraAde";
3644 while ((c = getopt_long(argc, argv, short_opts,
3645 long_opts, NULL)) != -1) {
3651 mask |= HS_NOARCHIVE;
3654 mask |= HS_ARCHIVED;
3657 mask |= HS_NORELEASE;
3668 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3669 argv[0], argv[optind - 1]);
3674 /* User should have specified a flag */
3678 while (optind < argc) {
3680 path = argv[optind];
3682 /* If mode == 0, this means we apply the mask. */
3683 if (mode == LFS_HSM_SET)
3684 rc = llapi_hsm_state_set(path, mask, 0, 0);
3686 rc = llapi_hsm_state_set(path, 0, mask, 0);
3689 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3690 path, strerror(errno = -rc));
3699 static int lfs_hsm_action(int argc, char **argv)
3704 struct hsm_current_action hca;
3705 struct hsm_extent he;
3706 enum hsm_user_action hua;
3707 enum hsm_progress_states hps;
3715 rc = llapi_hsm_current_action(path, &hca);
3717 fprintf(stderr, "can't get hsm action for %s: %s\n",
3718 path, strerror(errno = -rc));
3721 he = hca.hca_location;
3722 hua = hca.hca_action;
3723 hps = hca.hca_state;
3725 printf("%s: %s", path, hsm_user_action2name(hua));
3727 /* Skip file without action */
3728 if (hca.hca_action == HUA_NONE) {
3733 printf(" %s ", hsm_progress_state2name(hps));
3735 if ((hps == HPS_RUNNING) &&
3736 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3737 printf("(%llu bytes moved)\n",
3738 (unsigned long long)he.length);
3739 else if ((he.offset + he.length) == LUSTRE_EOF)
3740 printf("(from %llu to EOF)\n",
3741 (unsigned long long)he.offset);
3743 printf("(from %llu to %llu)\n",
3744 (unsigned long long)he.offset,
3745 (unsigned long long)(he.offset + he.length));
3747 } while (++i < argc);
3752 static int lfs_hsm_set(int argc, char **argv)
3754 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3757 static int lfs_hsm_clear(int argc, char **argv)
3759 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3763 * Check file state and return its fid, to be used by lfs_hsm_request().
3765 * \param[in] file Path to file to check
3766 * \param[in,out] fid Pointer to allocated lu_fid struct.
3767 * \param[in,out] last_dev Pointer to last device id used.
3769 * \return 0 on success.
3771 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3777 rc = lstat(file, &st);
3779 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3782 /* Checking for regular file as archiving as posix copytool
3783 * rejects archiving files other than regular files
3785 if (!S_ISREG(st.st_mode)) {
3786 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3789 /* A request should be ... */
3790 if (*last_dev != st.st_dev && *last_dev != 0) {
3791 fprintf(stderr, "All files should be "
3792 "on the same filesystem: %s\n", file);
3795 *last_dev = st.st_dev;
3797 rc = llapi_path2fid(file, fid);
3799 fprintf(stderr, "Cannot read FID of %s: %s\n",
3800 file, strerror(-rc));
3806 /* Fill an HSM HUR item with a given file name.
3808 * If mntpath is set, then the filename is actually a FID, and no
3809 * lookup on the filesystem will be performed.
3811 * \param[in] hur the user request to fill
3812 * \param[in] idx index of the item inside the HUR to fill
3813 * \param[in] mntpath mountpoint of Lustre
3814 * \param[in] fname filename (if mtnpath is NULL)
3815 * or FID (if mntpath is set)
3816 * \param[in] last_dev pointer to last device id used
3818 * \retval 0 on success
3819 * \retval CMD_HELP or a negative errno on error
3821 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3822 const char *mntpath, const char *fname,
3825 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3828 hui->hui_extent.length = -1;
3830 if (mntpath != NULL) {
3833 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3837 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3842 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3846 hur->hur_request.hr_itemcount++;
3851 static int lfs_hsm_request(int argc, char **argv, int action)
3853 struct option long_opts[] = {
3854 {"filelist", 1, 0, 'l'},
3855 {"data", 1, 0, 'D'},
3856 {"archive", 1, 0, 'a'},
3857 {"mntpath", 1, 0, 'm'},
3861 char short_opts[] = "l:D:a:m:";
3862 struct hsm_user_request *hur, *oldhur;
3867 char *filelist = NULL;
3868 char fullpath[PATH_MAX];
3869 char *opaque = NULL;
3873 int nbfile_alloc = 0;
3874 char *some_file = NULL;
3875 char *mntpath = NULL;
3881 while ((c = getopt_long(argc, argv, short_opts,
3882 long_opts, NULL)) != -1) {
3891 if (action != HUA_ARCHIVE &&
3892 action != HUA_REMOVE) {
3894 "error: -a is supported only "
3895 "when archiving or removing\n");
3898 archive_id = atoi(optarg);
3901 if (some_file == NULL) {
3903 some_file = strdup(optarg);
3909 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3910 argv[0], argv[optind - 1]);
3915 /* All remaining args are files, so we have at least nbfile */
3916 nbfile = argc - optind;
3918 if ((nbfile == 0) && (filelist == NULL))
3922 opaque_len = strlen(opaque);
3924 /* Alloc the request structure with enough place to store all files
3925 * from command line. */
3926 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3928 fprintf(stderr, "Cannot create the request: %s\n",
3932 nbfile_alloc = nbfile;
3934 hur->hur_request.hr_action = action;
3935 hur->hur_request.hr_archive_id = archive_id;
3936 hur->hur_request.hr_flags = 0;
3938 /* All remaining args are files, add them */
3939 if (nbfile != 0 && some_file == NULL)
3940 some_file = strdup(argv[optind]);
3942 for (i = 0; i < nbfile; i++) {
3943 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
3949 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3951 /* If a filelist was specified, read the filelist from it. */
3952 if (filelist != NULL) {
3953 fp = fopen(filelist, "r");
3955 fprintf(stderr, "Cannot read the file list %s: %s\n",
3956 filelist, strerror(errno));
3961 while ((rc = getline(&line, &len, fp)) != -1) {
3962 /* If allocated buffer was too small, get something
3964 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3967 nbfile_alloc = nbfile_alloc * 2 + 1;
3969 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3972 fprintf(stderr, "hsm: cannot allocate "
3973 "the request: %s\n",
3980 size = hur_len(oldhur);
3982 fprintf(stderr, "hsm: cannot allocate "
3983 "%u files + %u bytes data\n",
3984 oldhur->hur_request.hr_itemcount,
3985 oldhur->hur_request.hr_data_len);
3992 memcpy(hur, oldhur, size);
3997 if (line[strlen(line) - 1] == '\n')
3998 line[strlen(line) - 1] = '\0';
4000 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4001 mntpath, line, &last_dev);
4007 if (some_file == NULL) {
4017 /* If a --data was used, add it to the request */
4018 hur->hur_request.hr_data_len = opaque_len;
4020 memcpy(hur_data(hur), opaque, opaque_len);
4022 /* Send the HSM request */
4023 if (realpath(some_file, fullpath) == NULL) {
4024 fprintf(stderr, "Could not find path '%s': %s\n",
4025 some_file, strerror(errno));
4027 rc = llapi_hsm_request(fullpath, hur);
4029 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4030 some_file, strerror(-rc));
4040 static int lfs_hsm_archive(int argc, char **argv)
4042 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4045 static int lfs_hsm_restore(int argc, char **argv)
4047 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4050 static int lfs_hsm_release(int argc, char **argv)
4052 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4055 static int lfs_hsm_remove(int argc, char **argv)
4057 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4060 static int lfs_hsm_cancel(int argc, char **argv)
4062 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4065 static int lfs_swap_layouts(int argc, char **argv)
4070 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4071 SWAP_LAYOUTS_KEEP_MTIME |
4072 SWAP_LAYOUTS_KEEP_ATIME);
4075 int main(int argc, char **argv)
4079 /* Ensure that liblustreapi constructor has run */
4080 if (!liblustreapi_initialized)
4081 fprintf(stderr, "liblustreapi was not properly initialized\n");
4085 Parser_init("lfs > ", cmdlist);
4087 progname = argv[0]; /* Used in error messages */
4089 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4091 rc = Parser_commands();
4094 return rc < 0 ? -rc : rc;
4097 #ifdef _LUSTRE_IDL_H_
4098 /* Everything we need here should be included by lustreapi.h. */
4099 # error "lfs should not depend on lustre_idl.h"
4100 #endif /* _LUSTRE_IDL_H_ */