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/quota.h>
59 #include <sys/types.h>
65 #ifdef HAVE_SYS_QUOTA_H
66 # include <sys/quota.h>
69 #include <libcfs/util/string.h>
70 #include <libcfs/libcfs.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, ARRAY_SIZE(osts), nr_osts,
947 "error: %s: bad OST indices '%s'\n",
952 if (st_offset == -1) /* first in the command line */
956 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
957 if (strcmp(argv[optind - 1], "--index") == 0)
958 fprintf(stderr, "warning: '--index' deprecated"
959 ", use '--stripe-index' instead\n");
961 stripe_off_arg = optarg;
963 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
965 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
966 fprintf(stderr, "warning: '--size|-s' deprecated, "
967 "use '--stripe-size|-S' instead\n");
969 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
971 stripe_size_arg = optarg;
974 pool_name_arg = optarg;
981 fname = argv[optind];
984 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
985 stripe_count_arg != NULL || pool_name_arg != NULL)) {
986 fprintf(stderr, "error: %s: cannot specify -d with "
987 "-s, -c, -o, or -p options\n",
992 if (optind == argc) {
993 fprintf(stderr, "error: %s: missing filename|dirname\n",
998 if (pool_name_arg && strlen(pool_name_arg) > LOV_MAXPOOLNAME) {
1000 "error: %s: pool name '%s' is too long (max is %d characters)\n",
1001 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1005 /* get the stripe size */
1006 if (stripe_size_arg != NULL) {
1007 result = llapi_parse_size(stripe_size_arg, &st_size,
1010 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1011 argv[0], stripe_size_arg);
1015 /* get the stripe offset */
1016 if (stripe_off_arg != NULL) {
1017 st_offset = strtol(stripe_off_arg, &end, 0);
1019 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1020 argv[0], stripe_off_arg);
1024 /* get the stripe count */
1025 if (stripe_count_arg != NULL) {
1026 st_count = strtoul(stripe_count_arg, &end, 0);
1028 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1029 argv[0], stripe_count_arg);
1034 /* initialize stripe parameters */
1035 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1036 if (param == NULL) {
1037 fprintf(stderr, "error: %s: run out of memory\n", argv[0]);
1041 param->lsp_stripe_size = st_size;
1042 param->lsp_stripe_offset = st_offset;
1043 param->lsp_stripe_count = st_count;
1044 param->lsp_stripe_pattern = 0;
1045 param->lsp_pool = pool_name_arg;
1046 param->lsp_is_specific = false;
1048 if (st_count > 0 && nr_osts != st_count) {
1049 fprintf(stderr, "error: %s: stripe count '%d' doesn't "
1050 "match the number of OSTs: %d\n",
1051 argv[0], st_count, nr_osts);
1055 param->lsp_is_specific = true;
1056 param->lsp_stripe_count = nr_osts;
1057 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1060 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1062 result = lfs_migrate(fname, migration_flags, param);
1064 result = llapi_file_open_param(fname,
1073 /* Save the first error encountered. */
1077 "error: %s: %s stripe file '%s' failed\n",
1078 argv[0], migrate_mode ? "migrate" : "create",
1088 static int lfs_poollist(int argc, char **argv)
1093 return llapi_poollist(argv[1]);
1096 static int set_time(time_t *time, time_t *set, char *str)
1103 else if (str[0] == '-')
1109 t = strtol(str, NULL, 0);
1110 if (*time < t * 24 * 60 * 60) {
1113 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1117 *set = *time - t * 24 * 60 * 60;
1124 static int name2id(unsigned int *id, char *name, int type)
1127 struct passwd *entry;
1129 if (!(entry = getpwnam(name))) {
1135 *id = entry->pw_uid;
1137 struct group *entry;
1139 if (!(entry = getgrnam(name))) {
1145 *id = entry->gr_gid;
1151 static int id2name(char **name, unsigned int id, int type)
1154 struct passwd *entry;
1156 if (!(entry = getpwuid(id))) {
1162 *name = entry->pw_name;
1164 struct group *entry;
1166 if (!(entry = getgrgid(id))) {
1172 *name = entry->gr_name;
1178 static int name2layout(__u32 *layout, char *name)
1183 for (ptr = name; ; ptr = NULL) {
1184 lyt = strtok(ptr, ",");
1187 if (strcmp(lyt, "released") == 0)
1188 *layout |= LOV_PATTERN_F_RELEASED;
1189 else if (strcmp(lyt, "raid0") == 0)
1190 *layout |= LOV_PATTERN_RAID0;
1197 #define FIND_POOL_OPT 3
1198 static int lfs_find(int argc, char **argv)
1203 struct find_param param = {
1207 struct option long_opts[] = {
1208 {"atime", required_argument, 0, 'A'},
1209 {"stripe-count", required_argument, 0, 'c'},
1210 {"stripe_count", required_argument, 0, 'c'},
1211 {"ctime", required_argument, 0, 'C'},
1212 {"maxdepth", required_argument, 0, 'D'},
1213 {"gid", required_argument, 0, 'g'},
1214 {"group", required_argument, 0, 'G'},
1215 {"stripe-index", required_argument, 0, 'i'},
1216 {"stripe_index", required_argument, 0, 'i'},
1217 {"layout", required_argument, 0, 'L'},
1218 {"mdt", required_argument, 0, 'm'},
1219 {"mtime", required_argument, 0, 'M'},
1220 {"name", required_argument, 0, 'n'},
1221 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1222 {"obd", required_argument, 0, 'O'},
1223 {"ost", required_argument, 0, 'O'},
1224 /* no short option for pool, p/P already used */
1225 {"pool", required_argument, 0, FIND_POOL_OPT},
1226 {"print0", no_argument, 0, 'p'},
1227 {"print", no_argument, 0, 'P'},
1228 {"size", required_argument, 0, 's'},
1229 {"stripe-size", required_argument, 0, 'S'},
1230 {"stripe_size", required_argument, 0, 'S'},
1231 {"type", required_argument, 0, 't'},
1232 {"uid", required_argument, 0, 'u'},
1233 {"user", required_argument, 0, 'U'},
1246 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1247 while ((c = getopt_long_only(argc, argv,
1248 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1249 long_opts, NULL)) >= 0) {
1254 /* '!' is part of option */
1255 /* when getopt_long_only() finds a string which is not
1256 * an option nor a known option argument it returns 1
1257 * in that case if we already have found pathstart and pathend
1258 * (i.e. we have the list of pathnames),
1259 * the only supported value is "!"
1261 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1262 if (!isoption && pathend != -1) {
1263 fprintf(stderr, "err: %s: filename|dirname must either "
1264 "precede options or follow options\n",
1269 if (!isoption && pathstart == -1)
1270 pathstart = optind - 1;
1271 if (isoption && pathstart != -1 && pathend == -1)
1272 pathend = optind - 2;
1278 /* unknown; opt is "!" or path component,
1279 * checking done above.
1281 if (strcmp(optarg, "!") == 0)
1285 xtime = ¶m.fp_atime;
1286 xsign = ¶m.fp_asign;
1287 param.fp_exclude_atime = !!neg_opt;
1288 /* no break, this falls through to 'C' for ctime */
1291 xtime = ¶m.fp_ctime;
1292 xsign = ¶m.fp_csign;
1293 param.fp_exclude_ctime = !!neg_opt;
1295 /* no break, this falls through to 'M' for mtime */
1298 xtime = ¶m.fp_mtime;
1299 xsign = ¶m.fp_msign;
1300 param.fp_exclude_mtime = !!neg_opt;
1302 rc = set_time(&t, xtime, optarg);
1303 if (rc == INT_MAX) {
1311 if (optarg[0] == '+') {
1312 param.fp_stripe_count_sign = -1;
1314 } else if (optarg[0] == '-') {
1315 param.fp_stripe_count_sign = 1;
1319 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1320 if (*endptr != '\0') {
1321 fprintf(stderr,"error: bad stripe_count '%s'\n",
1326 param.fp_check_stripe_count = 1;
1327 param.fp_exclude_stripe_count = !!neg_opt;
1330 param.fp_max_depth = strtol(optarg, 0, 0);
1334 rc = name2id(¶m.fp_gid, optarg, GROUP);
1336 param.fp_gid = strtoul(optarg, &endptr, 10);
1337 if (*endptr != '\0') {
1338 fprintf(stderr, "Group/GID: %s cannot "
1339 "be found.\n", optarg);
1344 param.fp_exclude_gid = !!neg_opt;
1345 param.fp_check_gid = 1;
1348 ret = name2layout(¶m.fp_layout, optarg);
1351 param.fp_exclude_layout = !!neg_opt;
1352 param.fp_check_layout = 1;
1356 rc = name2id(¶m.fp_uid, optarg, USER);
1358 param.fp_uid = strtoul(optarg, &endptr, 10);
1359 if (*endptr != '\0') {
1360 fprintf(stderr, "User/UID: %s cannot "
1361 "be found.\n", optarg);
1366 param.fp_exclude_uid = !!neg_opt;
1367 param.fp_check_uid = 1;
1370 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1372 "Pool name %s is too long"
1373 " (max is %d)\n", optarg,
1378 /* we do check for empty pool because empty pool
1379 * is used to find V1 lov attributes */
1380 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1381 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1382 param.fp_exclude_pool = !!neg_opt;
1383 param.fp_check_pool = 1;
1386 param.fp_pattern = (char *)optarg;
1387 param.fp_exclude_pattern = !!neg_opt;
1392 char *buf, *token, *next, *p;
1396 buf = strdup(optarg);
1402 param.fp_exclude_obd = !!neg_opt;
1405 while (token && *token) {
1406 token = strchr(token, ',');
1413 param.fp_exclude_mdt = !!neg_opt;
1414 param.fp_num_alloc_mdts += len;
1415 tmp = realloc(param.fp_mdt_uuid,
1416 param.fp_num_alloc_mdts *
1417 sizeof(*param.fp_mdt_uuid));
1423 param.fp_mdt_uuid = tmp;
1425 param.fp_exclude_obd = !!neg_opt;
1426 param.fp_num_alloc_obds += len;
1427 tmp = realloc(param.fp_obd_uuid,
1428 param.fp_num_alloc_obds *
1429 sizeof(*param.fp_obd_uuid));
1435 param.fp_obd_uuid = tmp;
1437 for (token = buf; token && *token; token = next) {
1438 struct obd_uuid *puuid;
1441 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1444 ¶m.fp_obd_uuid[param.fp_num_obds++];
1446 p = strchr(token, ',');
1453 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1458 strncpy(puuid->uuid, token,
1459 sizeof(puuid->uuid));
1467 param.fp_zero_end = 1;
1472 if (optarg[0] == '+') {
1473 param.fp_size_sign = -1;
1475 } else if (optarg[0] == '-') {
1476 param.fp_size_sign = 1;
1480 ret = llapi_parse_size(optarg, ¶m.fp_size,
1481 ¶m.fp_size_units, 0);
1483 fprintf(stderr, "error: bad file size '%s'\n",
1487 param.fp_check_size = 1;
1488 param.fp_exclude_size = !!neg_opt;
1491 if (optarg[0] == '+') {
1492 param.fp_stripe_size_sign = -1;
1494 } else if (optarg[0] == '-') {
1495 param.fp_stripe_size_sign = 1;
1499 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1500 ¶m.fp_stripe_size_units, 0);
1502 fprintf(stderr, "error: bad stripe_size '%s'\n",
1506 param.fp_check_stripe_size = 1;
1507 param.fp_exclude_stripe_size = !!neg_opt;
1510 param.fp_exclude_type = !!neg_opt;
1511 switch (optarg[0]) {
1513 param.fp_type = S_IFBLK;
1516 param.fp_type = S_IFCHR;
1519 param.fp_type = S_IFDIR;
1522 param.fp_type = S_IFREG;
1525 param.fp_type = S_IFLNK;
1528 param.fp_type = S_IFIFO;
1531 param.fp_type = S_IFSOCK;
1534 fprintf(stderr, "error: %s: bad type '%s'\n",
1546 if (pathstart == -1) {
1547 fprintf(stderr, "error: %s: no filename|pathname\n",
1551 } else if (pathend == -1) {
1557 rc = llapi_find(argv[pathstart], ¶m);
1558 if (rc != 0 && ret == 0)
1560 } while (++pathstart < pathend);
1563 fprintf(stderr, "error: %s failed for %s.\n",
1564 argv[0], argv[optind - 1]);
1566 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1567 free(param.fp_obd_uuid);
1569 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1570 free(param.fp_mdt_uuid);
1575 static int lfs_getstripe_internal(int argc, char **argv,
1576 struct find_param *param)
1578 struct option long_opts[] = {
1579 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1580 /* This formerly implied "stripe-count", but was explicitly
1581 * made "stripe-count" for consistency with other options,
1582 * and to separate it from "mdt-count" when DNE arrives. */
1583 {"count", no_argument, 0, 'c'},
1585 {"stripe-count", no_argument, 0, 'c'},
1586 {"stripe_count", no_argument, 0, 'c'},
1587 {"directory", no_argument, 0, 'd'},
1588 {"default", no_argument, 0, 'D'},
1589 {"generation", no_argument, 0, 'g'},
1590 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1591 /* This formerly implied "stripe-index", but was explicitly
1592 * made "stripe-index" for consistency with other options,
1593 * and to separate it from "mdt-index" when DNE arrives. */
1594 {"index", no_argument, 0, 'i'},
1596 {"stripe-index", no_argument, 0, 'i'},
1597 {"stripe_index", no_argument, 0, 'i'},
1598 {"layout", no_argument, 0, 'L'},
1599 {"mdt-index", no_argument, 0, 'M'},
1600 {"mdt_index", no_argument, 0, 'M'},
1601 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1602 /* This formerly implied "stripe-index", but was confusing
1603 * with "file offset" (which will eventually be needed for
1604 * with different layouts by offset), so deprecate it. */
1605 {"offset", no_argument, 0, 'o'},
1607 {"obd", required_argument, 0, 'O'},
1608 {"ost", required_argument, 0, 'O'},
1609 {"pool", no_argument, 0, 'p'},
1610 {"quiet", no_argument, 0, 'q'},
1611 {"recursive", no_argument, 0, 'r'},
1612 {"raw", no_argument, 0, 'R'},
1613 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1614 /* This formerly implied "--stripe-size", but was confusing
1615 * with "lfs find --size|-s", which means "file size", so use
1616 * the consistent "--stripe-size|-S" for all commands. */
1617 {"size", no_argument, 0, 's'},
1619 {"stripe-size", no_argument, 0, 'S'},
1620 {"stripe_size", no_argument, 0, 'S'},
1621 {"verbose", no_argument, 0, 'v'},
1626 param->fp_max_depth = 1;
1627 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1628 long_opts, NULL)) != -1) {
1631 if (param->fp_obd_uuid) {
1633 "error: %s: only one obduuid allowed",
1637 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1643 param->fp_max_depth = 0;
1646 param->fp_get_default_lmv = 1;
1649 param->fp_recursive = 1;
1652 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1655 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1656 if (strcmp(argv[optind - 1], "--count") == 0)
1657 fprintf(stderr, "warning: '--count' deprecated,"
1658 " use '--stripe-count' instead\n");
1660 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1661 param->fp_verbose |= VERBOSE_COUNT;
1662 param->fp_max_depth = 0;
1665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1667 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1668 fprintf(stderr, "warning: '--size|-s' deprecated, "
1669 "use '--stripe-size|-S' instead\n");
1671 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1673 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1674 param->fp_verbose |= VERBOSE_SIZE;
1675 param->fp_max_depth = 0;
1678 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1680 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1681 "use '--stripe-index|-i' instead\n");
1684 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1685 if (strcmp(argv[optind - 1], "--index") == 0)
1686 fprintf(stderr, "warning: '--index' deprecated"
1687 ", use '--stripe-index' instead\n");
1689 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1690 param->fp_verbose |= VERBOSE_OFFSET;
1691 param->fp_max_depth = 0;
1695 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1696 param->fp_verbose |= VERBOSE_POOL;
1697 param->fp_max_depth = 0;
1701 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1702 param->fp_verbose |= VERBOSE_GENERATION;
1703 param->fp_max_depth = 0;
1707 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1708 param->fp_verbose |= VERBOSE_LAYOUT;
1709 param->fp_max_depth = 0;
1713 if (!(param->fp_verbose & VERBOSE_DETAIL))
1714 param->fp_max_depth = 0;
1715 param->fp_verbose |= VERBOSE_MDTINDEX;
1728 if (param->fp_recursive)
1729 param->fp_max_depth = -1;
1731 if (!param->fp_verbose)
1732 param->fp_verbose = VERBOSE_ALL;
1733 if (param->fp_quiet)
1734 param->fp_verbose = VERBOSE_OBJID;
1737 rc = llapi_getstripe(argv[optind], param);
1738 } while (++optind < argc && !rc);
1741 fprintf(stderr, "error: %s failed for %s.\n",
1742 argv[0], argv[optind - 1]);
1746 static int lfs_tgts(int argc, char **argv)
1748 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1749 struct find_param param;
1750 int index = 0, rc=0;
1755 if (argc == 2 && !realpath(argv[1], path)) {
1757 fprintf(stderr, "error: invalid path '%s': %s\n",
1758 argv[1], strerror(-rc));
1762 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1763 /* Check if we have a mount point */
1764 if (mntdir[0] == '\0')
1767 memset(¶m, 0, sizeof(param));
1768 if (!strcmp(argv[0], "mdts"))
1769 param.fp_get_lmv = 1;
1771 rc = llapi_ostlist(mntdir, ¶m);
1773 fprintf(stderr, "error: %s: failed on %s\n",
1776 if (path[0] != '\0')
1778 memset(mntdir, 0, PATH_MAX);
1784 static int lfs_getstripe(int argc, char **argv)
1786 struct find_param param = { 0 };
1787 return lfs_getstripe_internal(argc, argv, ¶m);
1791 static int lfs_getdirstripe(int argc, char **argv)
1793 struct find_param param = { 0 };
1795 param.fp_get_lmv = 1;
1796 return lfs_getstripe_internal(argc, argv, ¶m);
1800 static int lfs_setdirstripe(int argc, char **argv)
1804 unsigned int stripe_offset = -1;
1805 unsigned int stripe_count = 1;
1806 enum lmv_hash_type hash_type;
1809 char *stripe_offset_opt = NULL;
1810 char *stripe_count_opt = NULL;
1811 char *stripe_hash_opt = NULL;
1812 char *mode_opt = NULL;
1813 bool default_stripe = false;
1814 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1815 mode_t previous_mode = 0;
1816 bool delete = false;
1818 struct option long_opts[] = {
1819 {"count", required_argument, 0, 'c'},
1820 {"delete", no_argument, 0, 'd'},
1821 {"index", required_argument, 0, 'i'},
1822 {"mode", required_argument, 0, 'm'},
1823 {"hash-type", required_argument, 0, 't'},
1824 {"default_stripe", no_argument, 0, 'D'},
1828 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1835 stripe_count_opt = optarg;
1839 default_stripe = true;
1842 default_stripe = true;
1845 stripe_offset_opt = optarg;
1851 stripe_hash_opt = optarg;
1854 fprintf(stderr, "error: %s: option '%s' "
1856 argv[0], argv[optind - 1]);
1861 if (optind == argc) {
1862 fprintf(stderr, "error: %s: missing dirname\n",
1867 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1868 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1873 if (stripe_offset_opt != NULL) {
1874 /* get the stripe offset */
1875 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1877 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1878 argv[0], stripe_offset_opt);
1884 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1885 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1886 " or -i options.\n", argv[0]);
1894 if (mode_opt != NULL) {
1895 mode = strtoul(mode_opt, &end, 8);
1897 fprintf(stderr, "error: %s: bad mode '%s'\n",
1901 previous_mode = umask(0);
1904 if (stripe_hash_opt == NULL ||
1905 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1906 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1907 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1908 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1910 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1911 argv[0], stripe_hash_opt);
1915 /* get the stripe count */
1916 if (stripe_count_opt != NULL) {
1917 stripe_count = strtoul(stripe_count_opt, &end, 0);
1919 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1920 argv[0], stripe_count_opt);
1925 dname = argv[optind];
1927 if (default_stripe) {
1928 result = llapi_dir_set_default_lmv_stripe(dname,
1929 stripe_offset, stripe_count,
1932 result = llapi_dir_create_pool(dname, mode,
1934 stripe_count, hash_type,
1939 fprintf(stderr, "error: %s: create stripe dir '%s' "
1940 "failed\n", argv[0], dname);
1943 dname = argv[++optind];
1944 } while (dname != NULL);
1946 if (mode_opt != NULL)
1947 umask(previous_mode);
1953 static int lfs_rmentry(int argc, char **argv)
1960 fprintf(stderr, "error: %s: missing dirname\n",
1966 dname = argv[index];
1967 while (dname != NULL) {
1968 result = llapi_direntry_remove(dname);
1970 fprintf(stderr, "error: %s: remove dir entry '%s' "
1971 "failed\n", argv[0], dname);
1974 dname = argv[++index];
1979 static int lfs_mv(int argc, char **argv)
1981 struct find_param param = {
1988 struct option long_opts[] = {
1989 {"mdt-index", required_argument, 0, 'M'},
1990 {"verbose", no_argument, 0, 'v'},
1994 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
1997 param.fp_mdt_index = strtoul(optarg, &end, 0);
1999 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2006 param.fp_verbose = VERBOSE_DETAIL;
2010 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2011 argv[0], argv[optind - 1]);
2016 if (param.fp_mdt_index == -1) {
2017 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2021 if (optind >= argc) {
2022 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2026 param.fp_migrate = 1;
2027 rc = llapi_mv(argv[optind], ¶m);
2029 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2030 argv[0], argv[optind], param.fp_mdt_index,
2035 static int lfs_osts(int argc, char **argv)
2037 return lfs_tgts(argc, argv);
2040 static int lfs_mdts(int argc, char **argv)
2042 return lfs_tgts(argc, argv);
2045 #define COOK(value) \
2048 while (value > 1024) { \
2056 #define CDF "%11llu"
2057 #define HDF "%8.1f%c"
2061 static int showdf(char *mntdir, struct obd_statfs *stat,
2062 char *uuid, int ishow, int cooked,
2063 char *type, int index, int rc)
2065 long long avail, used, total;
2067 char *suffix = "KMGTPEZY";
2068 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2069 char tbuf[3 * sizeof(__u64)];
2070 char ubuf[3 * sizeof(__u64)];
2071 char abuf[3 * sizeof(__u64)];
2072 char rbuf[3 * sizeof(__u64)];
2080 avail = stat->os_ffree;
2081 used = stat->os_files - stat->os_ffree;
2082 total = stat->os_files;
2084 int shift = cooked ? 0 : 10;
2086 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2087 used = ((stat->os_blocks - stat->os_bfree) *
2088 stat->os_bsize) >> shift;
2089 total = (stat->os_blocks * stat->os_bsize) >> shift;
2092 if ((used + avail) > 0)
2093 ratio = (double)used / (double)(used + avail);
2099 cook_val = (double)total;
2102 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2104 sprintf(tbuf, CDF, total);
2106 cook_val = (double)used;
2109 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2111 sprintf(ubuf, CDF, used);
2113 cook_val = (double)avail;
2116 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2118 sprintf(abuf, CDF, avail);
2120 sprintf(tbuf, CDF, total);
2121 sprintf(ubuf, CDF, used);
2122 sprintf(abuf, CDF, avail);
2125 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2126 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2127 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2129 printf("[%s:%d]\n", type, index);
2135 printf(UUF": inactive device\n", uuid);
2138 printf(UUF": %s\n", uuid, strerror(-rc));
2145 struct ll_stat_type {
2150 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2151 int cooked, int lazy)
2153 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2154 struct obd_uuid uuid_buf;
2155 char *poolname = NULL;
2156 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2157 { LL_STATFS_LOV, "OST" },
2159 struct ll_stat_type *tp;
2160 __u64 ost_ffree = 0;
2166 poolname = strchr(pool, '.');
2167 if (poolname != NULL) {
2168 if (strncmp(fsname, pool, strlen(fsname))) {
2169 fprintf(stderr, "filesystem name incorrect\n");
2178 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2179 "UUID", "Inodes", "IUsed", "IFree",
2180 "IUse%", "Mounted on");
2182 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2183 "UUID", cooked ? "bytes" : "1K-blocks",
2184 "Used", "Available", "Use%", "Mounted on");
2186 for (tp = types; tp->st_name != NULL; tp++) {
2187 for (index = 0; ; index++) {
2188 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2189 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2190 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2191 rc = llapi_obd_statfs(mntdir, type, index,
2192 &stat_buf, &uuid_buf);
2199 if (poolname && tp->st_op == LL_STATFS_LOV &&
2200 llapi_search_ost(fsname, poolname,
2201 obd_uuid2str(&uuid_buf)) != 1)
2204 /* the llapi_obd_statfs() call may have returned with
2205 * an error, but if it filled in uuid_buf we will at
2206 * lease use that to print out a message for that OBD.
2207 * If we didn't get anything in the uuid_buf, then fill
2208 * it in so that we can print an error message. */
2209 if (uuid_buf.uuid[0] == '\0')
2210 sprintf(uuid_buf.uuid, "%s%04x",
2211 tp->st_name, index);
2212 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2213 ishow, cooked, tp->st_name, index, rc);
2216 if (tp->st_op == LL_STATFS_LMV) {
2217 sum.os_ffree += stat_buf.os_ffree;
2218 sum.os_files += stat_buf.os_files;
2219 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2220 sum.os_blocks += stat_buf.os_blocks *
2222 sum.os_bfree += stat_buf.os_bfree *
2224 sum.os_bavail += stat_buf.os_bavail *
2226 ost_ffree += stat_buf.os_ffree;
2228 } else if (rc == -EINVAL || rc == -EFAULT) {
2234 /* If we don't have as many objects free on the OST as inodes
2235 * on the MDS, we reduce the total number of inodes to
2236 * compensate, so that the "inodes in use" number is correct.
2237 * Matches ll_statfs_internal() so the results are consistent. */
2238 if (ost_ffree < sum.os_ffree) {
2239 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2240 sum.os_ffree = ost_ffree;
2243 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2248 static int lfs_df(int argc, char **argv)
2250 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2251 int ishow = 0, cooked = 0;
2253 int c, rc = 0, index = 0;
2254 char fsname[PATH_MAX] = "", *pool_name = NULL;
2255 struct option long_opts[] = {
2256 {"pool", required_argument, 0, 'p'},
2257 {"lazy", 0, 0, 'l'},
2261 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2279 if (optind < argc && !realpath(argv[optind], path)) {
2281 fprintf(stderr, "error: invalid path '%s': %s\n",
2282 argv[optind], strerror(-rc));
2286 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2287 /* Check if we have a mount point */
2288 if (mntdir[0] == '\0')
2291 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2292 if (rc || path[0] != '\0')
2294 fsname[0] = '\0'; /* avoid matching in next loop */
2295 mntdir[0] = '\0'; /* avoid matching in next loop */
2301 static int lfs_getname(int argc, char **argv)
2303 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2304 int rc = 0, index = 0, c;
2305 char buf[sizeof(struct obd_uuid)];
2307 while ((c = getopt(argc, argv, "h")) != -1)
2310 if (optind == argc) { /* no paths specified, get all paths. */
2311 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2312 rc = llapi_getname(mntdir, buf, sizeof(buf));
2315 "cannot get name for `%s': %s\n",
2316 mntdir, strerror(-rc));
2320 printf("%s %s\n", buf, mntdir);
2322 path[0] = fsname[0] = mntdir[0] = 0;
2324 } else { /* paths specified, only attempt to search these. */
2325 for (; optind < argc; optind++) {
2326 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2329 "cannot get name for `%s': %s\n",
2330 argv[optind], strerror(-rc));
2334 printf("%s %s\n", buf, argv[optind]);
2340 static int lfs_check(int argc, char **argv)
2343 char mntdir[PATH_MAX] = {'\0'};
2352 obd_types[0] = obd_type1;
2353 obd_types[1] = obd_type2;
2355 if (strcmp(argv[1], "osts") == 0) {
2356 strcpy(obd_types[0], "osc");
2357 } else if (strcmp(argv[1], "mds") == 0) {
2358 strcpy(obd_types[0], "mdc");
2359 } else if (strcmp(argv[1], "servers") == 0) {
2361 strcpy(obd_types[0], "osc");
2362 strcpy(obd_types[1], "mdc");
2364 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2369 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2370 if (rc < 0 || mntdir[0] == '\0') {
2371 fprintf(stderr, "No suitable Lustre mount found\n");
2375 rc = llapi_target_check(num_types, obd_types, mntdir);
2377 fprintf(stderr, "error: %s: %s status failed\n",
2384 static int lfs_join(int argc, char **argv)
2386 fprintf(stderr, "join two lustre files into one.\n"
2387 "obsolete, HEAD does not support it anymore.\n");
2391 #ifdef HAVE_SYS_QUOTA_H
2392 #define ARG2INT(nr, str, msg) \
2395 nr = strtol(str, &endp, 0); \
2397 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2402 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2404 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2405 * returns the value or ULONG_MAX on integer overflow or incorrect format
2407 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2408 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2409 * 3. empty integer value is interpreted as 0
2411 static unsigned long str2sec(const char* timestr)
2413 const char spec[] = "smhdw";
2414 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2415 unsigned long val = 0;
2418 if (strpbrk(timestr, spec) == NULL) {
2419 /* no specifiers inside the time string,
2420 should treat it as an integer value */
2421 val = strtoul(timestr, &tail, 10);
2422 return *tail ? ULONG_MAX : val;
2425 /* format string is XXwXXdXXhXXmXXs */
2431 v = strtoul(timestr, &tail, 10);
2432 if (v == ULONG_MAX || *tail == '\0')
2433 /* value too large (ULONG_MAX or more)
2434 or missing specifier */
2437 ptr = strchr(spec, *tail);
2439 /* unknown specifier */
2444 /* check if product will overflow the type */
2445 if (!(v < ULONG_MAX / mult[ind]))
2448 ADD_OVERFLOW(val, mult[ind] * v);
2449 if (val == ULONG_MAX)
2461 #define ARG2ULL(nr, str, def_units) \
2463 unsigned long long limit, units = def_units; \
2466 rc = llapi_parse_size(str, &limit, &units, 1); \
2468 fprintf(stderr, "error: bad limit value %s\n", str); \
2474 static inline int has_times_option(int argc, char **argv)
2478 for (i = 1; i < argc; i++)
2479 if (!strcmp(argv[i], "-t"))
2485 int lfs_setquota_times(int argc, char **argv)
2488 struct if_quotactl qctl;
2489 char *mnt, *obd_type = (char *)qctl.obd_type;
2490 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2491 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2492 struct option long_opts[] = {
2493 {"block-grace", required_argument, 0, 'b'},
2494 {"group", no_argument, 0, 'g'},
2495 {"inode-grace", required_argument, 0, 'i'},
2496 {"times", no_argument, 0, 't'},
2497 {"user", no_argument, 0, 'u'},
2501 memset(&qctl, 0, sizeof(qctl));
2502 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2503 qctl.qc_type = UGQUOTA;
2505 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2509 if (qctl.qc_type != UGQUOTA) {
2510 fprintf(stderr, "error: -u and -g can't be used "
2511 "more than once\n");
2514 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2517 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2518 fprintf(stderr, "error: bad block-grace: %s\n",
2522 dqb->dqb_valid |= QIF_BTIME;
2525 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2526 fprintf(stderr, "error: bad inode-grace: %s\n",
2530 dqb->dqb_valid |= QIF_ITIME;
2532 case 't': /* Yes, of course! */
2534 default: /* getopt prints error message for us when opterr != 0 */
2539 if (qctl.qc_type == UGQUOTA) {
2540 fprintf(stderr, "error: neither -u nor -g specified\n");
2544 if (optind != argc - 1) {
2545 fprintf(stderr, "error: unexpected parameters encountered\n");
2550 rc = llapi_quotactl(mnt, &qctl);
2553 fprintf(stderr, "%s %s ", obd_type,
2554 obd_uuid2str(&qctl.obd_uuid));
2555 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2562 #define BSLIMIT (1 << 0)
2563 #define BHLIMIT (1 << 1)
2564 #define ISLIMIT (1 << 2)
2565 #define IHLIMIT (1 << 3)
2567 int lfs_setquota(int argc, char **argv)
2570 struct if_quotactl qctl;
2571 char *mnt, *obd_type = (char *)qctl.obd_type;
2572 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2573 struct option long_opts[] = {
2574 {"block-softlimit", required_argument, 0, 'b'},
2575 {"block-hardlimit", required_argument, 0, 'B'},
2576 {"group", required_argument, 0, 'g'},
2577 {"inode-softlimit", required_argument, 0, 'i'},
2578 {"inode-hardlimit", required_argument, 0, 'I'},
2579 {"user", required_argument, 0, 'u'},
2582 unsigned limit_mask = 0;
2585 if (has_times_option(argc, argv))
2586 return lfs_setquota_times(argc, argv);
2588 memset(&qctl, 0, sizeof(qctl));
2589 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2590 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2591 * so it can be used as a marker that qc_type
2592 * isn't reinitialized from command line */
2594 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2598 if (qctl.qc_type != UGQUOTA) {
2599 fprintf(stderr, "error: -u and -g can't be used"
2600 " more than once\n");
2603 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2604 rc = name2id(&qctl.qc_id, optarg,
2605 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2607 qctl.qc_id = strtoul(optarg, &endptr, 10);
2608 if (*endptr != '\0') {
2609 fprintf(stderr, "error: can't find id "
2610 "for name %s\n", optarg);
2616 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2617 dqb->dqb_bsoftlimit >>= 10;
2618 limit_mask |= BSLIMIT;
2619 if (dqb->dqb_bsoftlimit &&
2620 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2621 fprintf(stderr, "warning: block softlimit is "
2622 "smaller than the miminal qunit size, "
2623 "please see the help of setquota or "
2624 "Lustre manual for details.\n");
2627 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2628 dqb->dqb_bhardlimit >>= 10;
2629 limit_mask |= BHLIMIT;
2630 if (dqb->dqb_bhardlimit &&
2631 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2632 fprintf(stderr, "warning: block hardlimit is "
2633 "smaller than the miminal qunit size, "
2634 "please see the help of setquota or "
2635 "Lustre manual for details.\n");
2638 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2639 limit_mask |= ISLIMIT;
2640 if (dqb->dqb_isoftlimit &&
2641 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2642 fprintf(stderr, "warning: inode softlimit is "
2643 "smaller than the miminal qunit size, "
2644 "please see the help of setquota or "
2645 "Lustre manual for details.\n");
2648 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2649 limit_mask |= IHLIMIT;
2650 if (dqb->dqb_ihardlimit &&
2651 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2652 fprintf(stderr, "warning: inode hardlimit is "
2653 "smaller than the miminal qunit size, "
2654 "please see the help of setquota or "
2655 "Lustre manual for details.\n");
2657 default: /* getopt prints error message for us when opterr != 0 */
2662 if (qctl.qc_type == UGQUOTA) {
2663 fprintf(stderr, "error: neither -u nor -g was specified\n");
2667 if (limit_mask == 0) {
2668 fprintf(stderr, "error: at least one limit must be specified\n");
2672 if (optind != argc - 1) {
2673 fprintf(stderr, "error: unexpected parameters encountered\n");
2679 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2680 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2681 /* sigh, we can't just set blimits/ilimits */
2682 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2683 .qc_type = qctl.qc_type,
2684 .qc_id = qctl.qc_id};
2686 rc = llapi_quotactl(mnt, &tmp_qctl);
2688 fprintf(stderr, "error: setquota failed while retrieving"
2689 " current quota settings (%s)\n",
2694 if (!(limit_mask & BHLIMIT))
2695 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2696 if (!(limit_mask & BSLIMIT))
2697 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2698 if (!(limit_mask & IHLIMIT))
2699 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2700 if (!(limit_mask & ISLIMIT))
2701 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2703 /* Keep grace times if we have got no softlimit arguments */
2704 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2705 dqb->dqb_valid |= QIF_BTIME;
2706 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2709 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2710 dqb->dqb_valid |= QIF_ITIME;
2711 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2715 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2716 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2718 rc = llapi_quotactl(mnt, &qctl);
2721 fprintf(stderr, "%s %s ", obd_type,
2722 obd_uuid2str(&qctl.obd_uuid));
2723 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2730 static inline char *type2name(int check_type)
2732 if (check_type == USRQUOTA)
2734 else if (check_type == GRPQUOTA)
2740 /* Converts seconds value into format string
2741 * result is returned in buf
2743 * 1. result is in descenting order: 1w2d3h4m5s
2744 * 2. zero fields are not filled (except for p. 3): 5d1s
2745 * 3. zero seconds value is presented as "0s"
2747 static char * __sec2str(time_t seconds, char *buf)
2749 const char spec[] = "smhdw";
2750 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2755 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2756 c = seconds / mult[i];
2758 if (c > 0 || (i == 0 && buf == tail))
2759 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2767 static void sec2str(time_t seconds, char *buf, int rc)
2774 tail = __sec2str(seconds, tail);
2776 if (rc && tail - buf < 39) {
2782 static void diff2str(time_t seconds, char *buf, time_t now)
2788 if (seconds <= now) {
2789 strcpy(buf, "none");
2792 __sec2str(seconds - now, buf);
2795 static void print_quota_title(char *name, struct if_quotactl *qctl,
2796 bool human_readable)
2798 printf("Disk quotas for %s %s (%cid %u):\n",
2799 type2name(qctl->qc_type), name,
2800 *type2name(qctl->qc_type), qctl->qc_id);
2801 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2802 "Filesystem", human_readable ? "used" : "kbytes",
2803 "quota", "limit", "grace",
2804 "files", "quota", "limit", "grace");
2807 static void kbytes2str(__u64 num, char *buf, bool h)
2810 sprintf(buf, LPU64, num);
2813 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2815 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2817 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2819 sprintf(buf, LPU64"%s", num, "k");
2823 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2830 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2831 int bover = 0, iover = 0;
2832 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2837 if (dqb->dqb_bhardlimit &&
2838 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2840 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2841 if (dqb->dqb_btime > now) {
2848 if (dqb->dqb_ihardlimit &&
2849 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2851 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2852 if (dqb->dqb_itime > now) {
2860 if (strlen(mnt) > 15)
2861 printf("%s\n%15s", mnt, "");
2863 printf("%15s", mnt);
2866 diff2str(dqb->dqb_btime, timebuf, now);
2868 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2869 if (rc == -EREMOTEIO)
2870 sprintf(numbuf[0], "%s*", strbuf);
2872 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2873 "%s" : "[%s]", strbuf);
2875 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2876 if (type == QC_GENERAL)
2877 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2878 "%s" : "[%s]", strbuf);
2880 sprintf(numbuf[1], "%s", "-");
2882 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2883 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2884 "%s" : "[%s]", strbuf);
2886 printf(" %7s%c %6s %7s %7s",
2887 numbuf[0], bover ? '*' : ' ', numbuf[1],
2888 numbuf[2], bover > 1 ? timebuf : "-");
2891 diff2str(dqb->dqb_itime, timebuf, now);
2893 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2894 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2896 if (type == QC_GENERAL)
2897 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2898 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2900 sprintf(numbuf[1], "%s", "-");
2902 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2903 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2905 if (type != QC_OSTIDX)
2906 printf(" %7s%c %6s %7s %7s",
2907 numbuf[0], iover ? '*' : ' ', numbuf[1],
2908 numbuf[2], iover > 1 ? timebuf : "-");
2910 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2913 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2914 qctl->qc_cmd == Q_GETOINFO) {
2918 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2919 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2920 printf("Block grace time: %s; Inode grace time: %s\n",
2921 bgtimebuf, igtimebuf);
2925 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2926 bool h, __u64 *total)
2928 int rc = 0, rc1 = 0, count = 0;
2929 __u32 valid = qctl->qc_valid;
2931 rc = llapi_get_obd_count(mnt, &count, is_mdt);
2933 fprintf(stderr, "can not get %s count: %s\n",
2934 is_mdt ? "mdt": "ost", strerror(-rc));
2938 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2939 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2940 rc = llapi_quotactl(mnt, qctl);
2942 /* It is remote client case. */
2943 if (-rc == EOPNOTSUPP) {
2950 fprintf(stderr, "quotactl %s%d failed.\n",
2951 is_mdt ? "mdt": "ost", qctl->qc_idx);
2955 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
2956 qctl->qc_valid, 0, h);
2957 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
2958 qctl->qc_dqblk.dqb_bhardlimit;
2961 qctl->qc_valid = valid;
2965 static int lfs_quota(int argc, char **argv)
2968 char *mnt, *name = NULL;
2969 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2970 .qc_type = UGQUOTA };
2971 char *obd_type = (char *)qctl.obd_type;
2972 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2973 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2974 verbose = 0, pass = 0, quiet = 0, inacc;
2976 __u32 valid = QC_GENERAL, idx = 0;
2977 __u64 total_ialloc = 0, total_balloc = 0;
2978 bool human_readable = false;
2980 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
2983 if (qctl.qc_type != UGQUOTA) {
2984 fprintf(stderr, "error: use either -u or -g\n");
2987 qctl.qc_type = USRQUOTA;
2990 if (qctl.qc_type != UGQUOTA) {
2991 fprintf(stderr, "error: use either -u or -g\n");
2994 qctl.qc_type = GRPQUOTA;
2997 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3000 valid = qctl.qc_valid = QC_UUID;
3001 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3004 valid = qctl.qc_valid = QC_MDTIDX;
3005 idx = qctl.qc_idx = atoi(optarg);
3008 valid = qctl.qc_valid = QC_OSTIDX;
3009 idx = qctl.qc_idx = atoi(optarg);
3018 human_readable = true;
3021 fprintf(stderr, "error: %s: option '-%c' "
3022 "unrecognized\n", argv[0], c);
3027 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3028 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3029 optind == argc - 1) {
3031 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3032 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3033 qctl.qc_valid = valid;
3036 qctl.qc_type = USRQUOTA;
3037 qctl.qc_id = geteuid();
3039 qctl.qc_type = GRPQUOTA;
3040 qctl.qc_id = getegid();
3042 rc = id2name(&name, qctl.qc_id,
3043 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3046 /* lfs quota -u username /path/to/lustre/mount */
3047 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3048 /* options should be followed by u/g-name and mntpoint */
3049 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3050 fprintf(stderr, "error: missing quota argument(s)\n");
3054 name = argv[optind++];
3055 rc = name2id(&qctl.qc_id, name,
3056 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3058 qctl.qc_id = strtoul(name, &endptr, 10);
3059 if (*endptr != '\0') {
3060 fprintf(stderr, "error: can't find id for name "
3065 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3066 fprintf(stderr, "error: missing quota info argument(s)\n");
3072 rc1 = llapi_quotactl(mnt, &qctl);
3076 fprintf(stderr, "%s quotas are not enabled.\n",
3077 qctl.qc_type == USRQUOTA ? "user" : "group");
3080 fprintf(stderr, "Permission denied.\n");
3082 /* We already got a "No such file..." message. */
3085 fprintf(stderr, "Unexpected quotactl error: %s\n",
3090 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3091 print_quota_title(name, &qctl, human_readable);
3093 if (rc1 && *obd_type)
3094 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3096 if (qctl.qc_valid != QC_GENERAL)
3099 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3100 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3101 (QIF_LIMITS|QIF_USAGE));
3103 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3105 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3109 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3111 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3113 kbytes2str(total_balloc, strbuf, human_readable);
3114 printf("Total allocated inode limit: "LPU64", total "
3115 "allocated block limit: %s\n", total_ialloc, strbuf);
3118 if (rc1 || rc2 || rc3 || inacc)
3119 printf("Some errors happened when getting quota info. "
3120 "Some devices may be not working or deactivated. "
3121 "The data in \"[]\" is inaccurate.\n");
3129 #endif /* HAVE_SYS_QUOTA_H! */
3131 static int flushctx_ioctl(char *mp)
3135 fd = open(mp, O_RDONLY);
3137 fprintf(stderr, "flushctx: error open %s: %s\n",
3138 mp, strerror(errno));
3142 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3144 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3145 mp, strerror(errno));
3151 static int lfs_flushctx(int argc, char **argv)
3153 int kdestroy = 0, c;
3154 char mntdir[PATH_MAX] = {'\0'};
3158 while ((c = getopt(argc, argv, "k")) != -1) {
3164 fprintf(stderr, "error: %s: option '-%c' "
3165 "unrecognized\n", argv[0], c);
3171 if ((rc = system("kdestroy > /dev/null")) != 0) {
3172 rc = WEXITSTATUS(rc);
3173 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3177 if (optind >= argc) {
3178 /* flush for all mounted lustre fs. */
3179 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3180 /* Check if we have a mount point */
3181 if (mntdir[0] == '\0')
3184 if (flushctx_ioctl(mntdir))
3187 mntdir[0] = '\0'; /* avoid matching in next loop */
3190 /* flush fs as specified */
3191 while (optind < argc) {
3192 if (flushctx_ioctl(argv[optind++]))
3199 static int lfs_lsetfacl(int argc, char **argv)
3202 return(llapi_lsetfacl(argc, argv));
3205 static int lfs_lgetfacl(int argc, char **argv)
3208 return(llapi_lgetfacl(argc, argv));
3211 static int lfs_rsetfacl(int argc, char **argv)
3214 return(llapi_rsetfacl(argc, argv));
3217 static int lfs_rgetfacl(int argc, char **argv)
3220 return(llapi_rgetfacl(argc, argv));
3223 static int lfs_cp(int argc, char **argv)
3225 return(llapi_cp(argc, argv));
3228 static int lfs_ls(int argc, char **argv)
3230 return(llapi_ls(argc, argv));
3233 static int lfs_changelog(int argc, char **argv)
3235 void *changelog_priv;
3236 struct changelog_rec *rec;
3237 long long startrec = 0, endrec = 0;
3239 struct option long_opts[] = {
3240 {"follow", no_argument, 0, 'f'},
3243 char short_opts[] = "f";
3246 while ((rc = getopt_long(argc, argv, short_opts,
3247 long_opts, NULL)) != -1) {
3255 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3256 argv[0], argv[optind - 1]);
3263 mdd = argv[optind++];
3265 startrec = strtoll(argv[optind++], NULL, 10);
3267 endrec = strtoll(argv[optind++], NULL, 10);
3269 rc = llapi_changelog_start(&changelog_priv,
3270 CHANGELOG_FLAG_BLOCK |
3271 CHANGELOG_FLAG_JOBID |
3272 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3275 fprintf(stderr, "Can't start changelog: %s\n",
3276 strerror(errno = -rc));
3280 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3284 if (endrec && rec->cr_index > endrec) {
3285 llapi_changelog_free(&rec);
3288 if (rec->cr_index < startrec) {
3289 llapi_changelog_free(&rec);
3293 secs = rec->cr_time >> 30;
3294 gmtime_r(&secs, &ts);
3295 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3296 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3297 changelog_type2str(rec->cr_type),
3298 ts.tm_hour, ts.tm_min, ts.tm_sec,
3299 (int)(rec->cr_time & ((1<<30) - 1)),
3300 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3301 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3303 if (rec->cr_flags & CLF_JOBID) {
3304 struct changelog_ext_jobid *jid =
3305 changelog_rec_jobid(rec);
3307 if (jid->cr_jobid[0] != '\0')
3308 printf(" j=%s", jid->cr_jobid);
3311 if (rec->cr_namelen)
3312 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3313 rec->cr_namelen, changelog_rec_name(rec));
3315 if (rec->cr_flags & CLF_RENAME) {
3316 struct changelog_ext_rename *rnm =
3317 changelog_rec_rename(rec);
3319 if (!fid_is_zero(&rnm->cr_sfid))
3320 printf(" s="DFID" sp="DFID" %.*s",
3321 PFID(&rnm->cr_sfid),
3322 PFID(&rnm->cr_spfid),
3323 (int)changelog_rec_snamelen(rec),
3324 changelog_rec_sname(rec));
3328 llapi_changelog_free(&rec);
3331 llapi_changelog_fini(&changelog_priv);
3334 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3336 return (rc == 1 ? 0 : rc);
3339 static int lfs_changelog_clear(int argc, char **argv)
3347 endrec = strtoll(argv[3], NULL, 10);
3349 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3351 fprintf(stderr, "%s error: %s\n", argv[0],
3352 strerror(errno = -rc));
3356 static int lfs_fid2path(int argc, char **argv)
3358 struct option long_opts[] = {
3359 {"cur", no_argument, 0, 'c'},
3360 {"link", required_argument, 0, 'l'},
3361 {"rec", required_argument, 0, 'r'},
3364 char short_opts[] = "cl:r:";
3365 char *device, *fid, *path;
3366 long long recno = -1;
3372 while ((rc = getopt_long(argc, argv, short_opts,
3373 long_opts, NULL)) != -1) {
3379 linkno = strtol(optarg, NULL, 10);
3382 recno = strtoll(optarg, NULL, 10);
3387 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3388 argv[0], argv[optind - 1]);
3396 device = argv[optind++];
3397 path = calloc(1, PATH_MAX);
3399 fprintf(stderr, "error: Not enough memory\n");
3404 while (optind < argc) {
3405 fid = argv[optind++];
3407 lnktmp = (linkno >= 0) ? linkno : 0;
3409 int oldtmp = lnktmp;
3410 long long rectmp = recno;
3412 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3415 fprintf(stderr, "%s: error on FID %s: %s\n",
3416 argv[0], fid, strerror(errno = -rc2));
3423 fprintf(stdout, "%lld ", rectmp);
3424 if (device[0] == '/') {
3425 fprintf(stdout, "%s", device);
3426 if (device[strlen(device) - 1] != '/')
3427 fprintf(stdout, "/");
3428 } else if (path[0] == '\0') {
3429 fprintf(stdout, "/");
3431 fprintf(stdout, "%s\n", path);
3434 /* specified linkno */
3436 if (oldtmp == lnktmp)
3446 static int lfs_path2fid(int argc, char **argv)
3448 struct option long_opts[] = {
3449 {"parents", no_argument, 0, 'p'},
3453 const char short_opts[] = "p";
3454 const char *sep = "";
3457 bool show_parents = false;
3459 while ((rc = getopt_long(argc, argv, short_opts,
3460 long_opts, NULL)) != -1) {
3463 show_parents = true;
3466 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3467 argv[0], argv[optind - 1]);
3472 if (optind > argc - 1)
3474 else if (optind < argc - 1)
3478 for (path = argv + optind; *path != NULL; path++) {
3480 if (!show_parents) {
3481 err = llapi_path2fid(*path, &fid);
3483 printf("%s%s"DFID"\n",
3484 *sep != '\0' ? *path : "", sep,
3487 char name[NAME_MAX + 1];
3488 unsigned int linkno = 0;
3490 while ((err = llapi_path2parent(*path, linkno, &fid,
3491 name, sizeof(name))) == 0) {
3492 if (*sep != '\0' && linkno == 0)
3493 printf("%s%s", *path, sep);
3495 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3500 /* err == -ENODATA is end-of-loop */
3501 if (linkno > 0 && err == -ENODATA) {
3508 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3509 argv[0], show_parents ? "parent " : "", *path,
3521 static int lfs_data_version(int argc, char **argv)
3528 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3533 while ((c = getopt(argc, argv, "nrw")) != -1) {
3536 data_version_flags = 0;
3539 data_version_flags |= LL_DV_RD_FLUSH;
3542 data_version_flags |= LL_DV_WR_FLUSH;
3551 path = argv[optind];
3552 fd = open(path, O_RDONLY);
3554 err(errno, "cannot open file %s", path);
3556 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3558 err(errno, "cannot get version for %s", path);
3560 printf(LPU64 "\n", data_version);
3566 static int lfs_hsm_state(int argc, char **argv)
3571 struct hsm_user_state hus;
3579 rc = llapi_hsm_state_get(path, &hus);
3581 fprintf(stderr, "can't get hsm state for %s: %s\n",
3582 path, strerror(errno = -rc));
3586 /* Display path name and status flags */
3587 printf("%s: (0x%08x)", path, hus.hus_states);
3589 if (hus.hus_states & HS_RELEASED)
3590 printf(" released");
3591 if (hus.hus_states & HS_EXISTS)
3593 if (hus.hus_states & HS_DIRTY)
3595 if (hus.hus_states & HS_ARCHIVED)
3596 printf(" archived");
3597 /* Display user-settable flags */
3598 if (hus.hus_states & HS_NORELEASE)
3599 printf(" never_release");
3600 if (hus.hus_states & HS_NOARCHIVE)
3601 printf(" never_archive");
3602 if (hus.hus_states & HS_LOST)
3603 printf(" lost_from_hsm");
3605 if (hus.hus_archive_id != 0)
3606 printf(", archive_id:%d", hus.hus_archive_id);
3609 } while (++i < argc);
3614 #define LFS_HSM_SET 0
3615 #define LFS_HSM_CLEAR 1
3618 * Generic function to set or clear HSM flags.
3619 * Used by hsm_set and hsm_clear.
3621 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3623 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3625 struct option long_opts[] = {
3626 {"lost", 0, 0, 'l'},
3627 {"norelease", 0, 0, 'r'},
3628 {"noarchive", 0, 0, 'a'},
3629 {"archived", 0, 0, 'A'},
3630 {"dirty", 0, 0, 'd'},
3631 {"exists", 0, 0, 'e'},
3634 char short_opts[] = "lraAde";
3642 while ((c = getopt_long(argc, argv, short_opts,
3643 long_opts, NULL)) != -1) {
3649 mask |= HS_NOARCHIVE;
3652 mask |= HS_ARCHIVED;
3655 mask |= HS_NORELEASE;
3666 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3667 argv[0], argv[optind - 1]);
3672 /* User should have specified a flag */
3676 while (optind < argc) {
3678 path = argv[optind];
3680 /* If mode == 0, this means we apply the mask. */
3681 if (mode == LFS_HSM_SET)
3682 rc = llapi_hsm_state_set(path, mask, 0, 0);
3684 rc = llapi_hsm_state_set(path, 0, mask, 0);
3687 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3688 path, strerror(errno = -rc));
3697 static int lfs_hsm_action(int argc, char **argv)
3702 struct hsm_current_action hca;
3703 struct hsm_extent he;
3704 enum hsm_user_action hua;
3705 enum hsm_progress_states hps;
3713 rc = llapi_hsm_current_action(path, &hca);
3715 fprintf(stderr, "can't get hsm action for %s: %s\n",
3716 path, strerror(errno = -rc));
3719 he = hca.hca_location;
3720 hua = hca.hca_action;
3721 hps = hca.hca_state;
3723 printf("%s: %s", path, hsm_user_action2name(hua));
3725 /* Skip file without action */
3726 if (hca.hca_action == HUA_NONE) {
3731 printf(" %s ", hsm_progress_state2name(hps));
3733 if ((hps == HPS_RUNNING) &&
3734 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3735 printf("(%llu bytes moved)\n",
3736 (unsigned long long)he.length);
3737 else if ((he.offset + he.length) == LUSTRE_EOF)
3738 printf("(from %llu to EOF)\n",
3739 (unsigned long long)he.offset);
3741 printf("(from %llu to %llu)\n",
3742 (unsigned long long)he.offset,
3743 (unsigned long long)(he.offset + he.length));
3745 } while (++i < argc);
3750 static int lfs_hsm_set(int argc, char **argv)
3752 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3755 static int lfs_hsm_clear(int argc, char **argv)
3757 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3761 * Check file state and return its fid, to be used by lfs_hsm_request().
3763 * \param[in] file Path to file to check
3764 * \param[in,out] fid Pointer to allocated lu_fid struct.
3765 * \param[in,out] last_dev Pointer to last device id used.
3767 * \return 0 on success.
3769 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3775 rc = lstat(file, &st);
3777 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3780 /* Checking for regular file as archiving as posix copytool
3781 * rejects archiving files other than regular files
3783 if (!S_ISREG(st.st_mode)) {
3784 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3787 /* A request should be ... */
3788 if (*last_dev != st.st_dev && *last_dev != 0) {
3789 fprintf(stderr, "All files should be "
3790 "on the same filesystem: %s\n", file);
3793 *last_dev = st.st_dev;
3795 rc = llapi_path2fid(file, fid);
3797 fprintf(stderr, "Cannot read FID of %s: %s\n",
3798 file, strerror(-rc));
3804 /* Fill an HSM HUR item with a given file name.
3806 * If mntpath is set, then the filename is actually a FID, and no
3807 * lookup on the filesystem will be performed.
3809 * \param[in] hur the user request to fill
3810 * \param[in] idx index of the item inside the HUR to fill
3811 * \param[in] mntpath mountpoint of Lustre
3812 * \param[in] fname filename (if mtnpath is NULL)
3813 * or FID (if mntpath is set)
3814 * \param[in] last_dev pointer to last device id used
3816 * \retval 0 on success
3817 * \retval CMD_HELP or a negative errno on error
3819 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3820 const char *mntpath, const char *fname,
3823 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3826 hui->hui_extent.length = -1;
3828 if (mntpath != NULL) {
3831 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3835 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3840 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3844 hur->hur_request.hr_itemcount++;
3849 static int lfs_hsm_request(int argc, char **argv, int action)
3851 struct option long_opts[] = {
3852 {"filelist", 1, 0, 'l'},
3853 {"data", 1, 0, 'D'},
3854 {"archive", 1, 0, 'a'},
3855 {"mntpath", 1, 0, 'm'},
3859 char short_opts[] = "l:D:a:m:";
3860 struct hsm_user_request *hur, *oldhur;
3865 char *filelist = NULL;
3866 char fullpath[PATH_MAX];
3867 char *opaque = NULL;
3871 int nbfile_alloc = 0;
3872 char *some_file = NULL;
3873 char *mntpath = NULL;
3879 while ((c = getopt_long(argc, argv, short_opts,
3880 long_opts, NULL)) != -1) {
3889 if (action != HUA_ARCHIVE &&
3890 action != HUA_REMOVE) {
3892 "error: -a is supported only "
3893 "when archiving or removing\n");
3896 archive_id = atoi(optarg);
3899 if (some_file == NULL) {
3901 some_file = strdup(optarg);
3907 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3908 argv[0], argv[optind - 1]);
3913 /* All remaining args are files, so we have at least nbfile */
3914 nbfile = argc - optind;
3916 if ((nbfile == 0) && (filelist == NULL))
3920 opaque_len = strlen(opaque);
3922 /* Alloc the request structure with enough place to store all files
3923 * from command line. */
3924 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3926 fprintf(stderr, "Cannot create the request: %s\n",
3930 nbfile_alloc = nbfile;
3932 hur->hur_request.hr_action = action;
3933 hur->hur_request.hr_archive_id = archive_id;
3934 hur->hur_request.hr_flags = 0;
3936 /* All remaining args are files, add them */
3937 if (nbfile != 0 && some_file == NULL)
3938 some_file = strdup(argv[optind]);
3940 for (i = 0; i < nbfile; i++) {
3941 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
3947 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3949 /* If a filelist was specified, read the filelist from it. */
3950 if (filelist != NULL) {
3951 fp = fopen(filelist, "r");
3953 fprintf(stderr, "Cannot read the file list %s: %s\n",
3954 filelist, strerror(errno));
3959 while ((rc = getline(&line, &len, fp)) != -1) {
3960 /* If allocated buffer was too small, get something
3962 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3965 nbfile_alloc = nbfile_alloc * 2 + 1;
3967 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3970 fprintf(stderr, "hsm: cannot allocate "
3971 "the request: %s\n",
3978 size = hur_len(oldhur);
3980 fprintf(stderr, "hsm: cannot allocate "
3981 "%u files + %u bytes data\n",
3982 oldhur->hur_request.hr_itemcount,
3983 oldhur->hur_request.hr_data_len);
3990 memcpy(hur, oldhur, size);
3995 if (line[strlen(line) - 1] == '\n')
3996 line[strlen(line) - 1] = '\0';
3998 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
3999 mntpath, line, &last_dev);
4005 if (some_file == NULL) {
4015 /* If a --data was used, add it to the request */
4016 hur->hur_request.hr_data_len = opaque_len;
4018 memcpy(hur_data(hur), opaque, opaque_len);
4020 /* Send the HSM request */
4021 if (realpath(some_file, fullpath) == NULL) {
4022 fprintf(stderr, "Could not find path '%s': %s\n",
4023 some_file, strerror(errno));
4025 rc = llapi_hsm_request(fullpath, hur);
4027 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4028 some_file, strerror(-rc));
4038 static int lfs_hsm_archive(int argc, char **argv)
4040 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4043 static int lfs_hsm_restore(int argc, char **argv)
4045 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4048 static int lfs_hsm_release(int argc, char **argv)
4050 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4053 static int lfs_hsm_remove(int argc, char **argv)
4055 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4058 static int lfs_hsm_cancel(int argc, char **argv)
4060 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4063 static int lfs_swap_layouts(int argc, char **argv)
4068 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4069 SWAP_LAYOUTS_KEEP_MTIME |
4070 SWAP_LAYOUTS_KEEP_ATIME);
4073 int main(int argc, char **argv)
4077 /* Ensure that liblustreapi constructor has run */
4078 if (!liblustreapi_initialized)
4079 fprintf(stderr, "liblustreapi was not properly initialized\n");
4083 Parser_init("lfs > ", cmdlist);
4085 progname = argv[0]; /* Used in error messages */
4087 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4089 rc = Parser_commands();
4092 return rc < 0 ? -rc : rc;
4095 #ifdef _LUSTRE_IDL_H_
4096 /* Everything we need here should be included by lustreapi.h. */
4097 # error "lfs should not depend on lustre_idl.h"
4098 #endif /* _LUSTRE_IDL_H_ */