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);
1056 param->lsp_is_specific = true;
1057 param->lsp_stripe_count = nr_osts;
1058 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1061 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1063 result = lfs_migrate(fname, migration_flags, param);
1065 result = llapi_file_open_param(fname,
1074 /* Save the first error encountered. */
1078 "error: %s: %s stripe file '%s' failed\n",
1079 argv[0], migrate_mode ? "migrate" : "create",
1089 static int lfs_poollist(int argc, char **argv)
1094 return llapi_poollist(argv[1]);
1097 static int set_time(time_t *time, time_t *set, char *str)
1104 else if (str[0] == '-')
1110 t = strtol(str, NULL, 0);
1111 if (*time < t * 24 * 60 * 60) {
1114 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1118 *set = *time - t * 24 * 60 * 60;
1125 static int name2id(unsigned int *id, char *name, int type)
1128 struct passwd *entry;
1130 if (!(entry = getpwnam(name))) {
1136 *id = entry->pw_uid;
1138 struct group *entry;
1140 if (!(entry = getgrnam(name))) {
1146 *id = entry->gr_gid;
1152 static int id2name(char **name, unsigned int id, int type)
1155 struct passwd *entry;
1157 if (!(entry = getpwuid(id))) {
1163 *name = entry->pw_name;
1165 struct group *entry;
1167 if (!(entry = getgrgid(id))) {
1173 *name = entry->gr_name;
1179 static int name2layout(__u32 *layout, char *name)
1184 for (ptr = name; ; ptr = NULL) {
1185 lyt = strtok(ptr, ",");
1188 if (strcmp(lyt, "released") == 0)
1189 *layout |= LOV_PATTERN_F_RELEASED;
1190 else if (strcmp(lyt, "raid0") == 0)
1191 *layout |= LOV_PATTERN_RAID0;
1198 #define FIND_POOL_OPT 3
1199 static int lfs_find(int argc, char **argv)
1204 struct find_param param = {
1208 struct option long_opts[] = {
1209 {"atime", required_argument, 0, 'A'},
1210 {"stripe-count", required_argument, 0, 'c'},
1211 {"stripe_count", required_argument, 0, 'c'},
1212 {"ctime", required_argument, 0, 'C'},
1213 {"maxdepth", required_argument, 0, 'D'},
1214 {"gid", required_argument, 0, 'g'},
1215 {"group", required_argument, 0, 'G'},
1216 {"stripe-index", required_argument, 0, 'i'},
1217 {"stripe_index", required_argument, 0, 'i'},
1218 {"layout", required_argument, 0, 'L'},
1219 {"mdt", required_argument, 0, 'm'},
1220 {"mtime", required_argument, 0, 'M'},
1221 {"name", required_argument, 0, 'n'},
1222 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1223 {"obd", required_argument, 0, 'O'},
1224 {"ost", required_argument, 0, 'O'},
1225 /* no short option for pool, p/P already used */
1226 {"pool", required_argument, 0, FIND_POOL_OPT},
1227 {"print0", no_argument, 0, 'p'},
1228 {"print", no_argument, 0, 'P'},
1229 {"size", required_argument, 0, 's'},
1230 {"stripe-size", required_argument, 0, 'S'},
1231 {"stripe_size", required_argument, 0, 'S'},
1232 {"type", required_argument, 0, 't'},
1233 {"uid", required_argument, 0, 'u'},
1234 {"user", required_argument, 0, 'U'},
1247 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1248 while ((c = getopt_long_only(argc, argv,
1249 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1250 long_opts, NULL)) >= 0) {
1255 /* '!' is part of option */
1256 /* when getopt_long_only() finds a string which is not
1257 * an option nor a known option argument it returns 1
1258 * in that case if we already have found pathstart and pathend
1259 * (i.e. we have the list of pathnames),
1260 * the only supported value is "!"
1262 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1263 if (!isoption && pathend != -1) {
1264 fprintf(stderr, "err: %s: filename|dirname must either "
1265 "precede options or follow options\n",
1270 if (!isoption && pathstart == -1)
1271 pathstart = optind - 1;
1272 if (isoption && pathstart != -1 && pathend == -1)
1273 pathend = optind - 2;
1279 /* unknown; opt is "!" or path component,
1280 * checking done above.
1282 if (strcmp(optarg, "!") == 0)
1286 xtime = ¶m.fp_atime;
1287 xsign = ¶m.fp_asign;
1288 param.fp_exclude_atime = !!neg_opt;
1289 /* no break, this falls through to 'C' for ctime */
1292 xtime = ¶m.fp_ctime;
1293 xsign = ¶m.fp_csign;
1294 param.fp_exclude_ctime = !!neg_opt;
1296 /* no break, this falls through to 'M' for mtime */
1299 xtime = ¶m.fp_mtime;
1300 xsign = ¶m.fp_msign;
1301 param.fp_exclude_mtime = !!neg_opt;
1303 rc = set_time(&t, xtime, optarg);
1304 if (rc == INT_MAX) {
1312 if (optarg[0] == '+') {
1313 param.fp_stripe_count_sign = -1;
1315 } else if (optarg[0] == '-') {
1316 param.fp_stripe_count_sign = 1;
1320 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1321 if (*endptr != '\0') {
1322 fprintf(stderr,"error: bad stripe_count '%s'\n",
1327 param.fp_check_stripe_count = 1;
1328 param.fp_exclude_stripe_count = !!neg_opt;
1331 param.fp_max_depth = strtol(optarg, 0, 0);
1335 rc = name2id(¶m.fp_gid, optarg, GROUP);
1337 param.fp_gid = strtoul(optarg, &endptr, 10);
1338 if (*endptr != '\0') {
1339 fprintf(stderr, "Group/GID: %s cannot "
1340 "be found.\n", optarg);
1345 param.fp_exclude_gid = !!neg_opt;
1346 param.fp_check_gid = 1;
1349 ret = name2layout(¶m.fp_layout, optarg);
1352 param.fp_exclude_layout = !!neg_opt;
1353 param.fp_check_layout = 1;
1357 rc = name2id(¶m.fp_uid, optarg, USER);
1359 param.fp_uid = strtoul(optarg, &endptr, 10);
1360 if (*endptr != '\0') {
1361 fprintf(stderr, "User/UID: %s cannot "
1362 "be found.\n", optarg);
1367 param.fp_exclude_uid = !!neg_opt;
1368 param.fp_check_uid = 1;
1371 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1373 "Pool name %s is too long"
1374 " (max is %d)\n", optarg,
1379 /* we do check for empty pool because empty pool
1380 * is used to find V1 lov attributes */
1381 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1382 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1383 param.fp_exclude_pool = !!neg_opt;
1384 param.fp_check_pool = 1;
1387 param.fp_pattern = (char *)optarg;
1388 param.fp_exclude_pattern = !!neg_opt;
1393 char *buf, *token, *next, *p;
1397 buf = strdup(optarg);
1403 param.fp_exclude_obd = !!neg_opt;
1406 while (token && *token) {
1407 token = strchr(token, ',');
1414 param.fp_exclude_mdt = !!neg_opt;
1415 param.fp_num_alloc_mdts += len;
1416 tmp = realloc(param.fp_mdt_uuid,
1417 param.fp_num_alloc_mdts *
1418 sizeof(*param.fp_mdt_uuid));
1424 param.fp_mdt_uuid = tmp;
1426 param.fp_exclude_obd = !!neg_opt;
1427 param.fp_num_alloc_obds += len;
1428 tmp = realloc(param.fp_obd_uuid,
1429 param.fp_num_alloc_obds *
1430 sizeof(*param.fp_obd_uuid));
1436 param.fp_obd_uuid = tmp;
1438 for (token = buf; token && *token; token = next) {
1439 struct obd_uuid *puuid;
1442 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1445 ¶m.fp_obd_uuid[param.fp_num_obds++];
1447 p = strchr(token, ',');
1454 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1459 strncpy(puuid->uuid, token,
1460 sizeof(puuid->uuid));
1468 param.fp_zero_end = 1;
1473 if (optarg[0] == '+') {
1474 param.fp_size_sign = -1;
1476 } else if (optarg[0] == '-') {
1477 param.fp_size_sign = 1;
1481 ret = llapi_parse_size(optarg, ¶m.fp_size,
1482 ¶m.fp_size_units, 0);
1484 fprintf(stderr, "error: bad file size '%s'\n",
1488 param.fp_check_size = 1;
1489 param.fp_exclude_size = !!neg_opt;
1492 if (optarg[0] == '+') {
1493 param.fp_stripe_size_sign = -1;
1495 } else if (optarg[0] == '-') {
1496 param.fp_stripe_size_sign = 1;
1500 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1501 ¶m.fp_stripe_size_units, 0);
1503 fprintf(stderr, "error: bad stripe_size '%s'\n",
1507 param.fp_check_stripe_size = 1;
1508 param.fp_exclude_stripe_size = !!neg_opt;
1511 param.fp_exclude_type = !!neg_opt;
1512 switch (optarg[0]) {
1514 param.fp_type = S_IFBLK;
1517 param.fp_type = S_IFCHR;
1520 param.fp_type = S_IFDIR;
1523 param.fp_type = S_IFREG;
1526 param.fp_type = S_IFLNK;
1529 param.fp_type = S_IFIFO;
1532 param.fp_type = S_IFSOCK;
1535 fprintf(stderr, "error: %s: bad type '%s'\n",
1547 if (pathstart == -1) {
1548 fprintf(stderr, "error: %s: no filename|pathname\n",
1552 } else if (pathend == -1) {
1558 rc = llapi_find(argv[pathstart], ¶m);
1559 if (rc != 0 && ret == 0)
1561 } while (++pathstart < pathend);
1564 fprintf(stderr, "error: %s failed for %s.\n",
1565 argv[0], argv[optind - 1]);
1567 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1568 free(param.fp_obd_uuid);
1570 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1571 free(param.fp_mdt_uuid);
1576 static int lfs_getstripe_internal(int argc, char **argv,
1577 struct find_param *param)
1579 struct option long_opts[] = {
1580 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1581 /* This formerly implied "stripe-count", but was explicitly
1582 * made "stripe-count" for consistency with other options,
1583 * and to separate it from "mdt-count" when DNE arrives. */
1584 {"count", no_argument, 0, 'c'},
1586 {"stripe-count", no_argument, 0, 'c'},
1587 {"stripe_count", no_argument, 0, 'c'},
1588 {"directory", no_argument, 0, 'd'},
1589 {"default", no_argument, 0, 'D'},
1590 {"generation", no_argument, 0, 'g'},
1591 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1592 /* This formerly implied "stripe-index", but was explicitly
1593 * made "stripe-index" for consistency with other options,
1594 * and to separate it from "mdt-index" when DNE arrives. */
1595 {"index", no_argument, 0, 'i'},
1597 {"stripe-index", no_argument, 0, 'i'},
1598 {"stripe_index", no_argument, 0, 'i'},
1599 {"layout", no_argument, 0, 'L'},
1600 {"mdt-index", no_argument, 0, 'M'},
1601 {"mdt_index", no_argument, 0, 'M'},
1602 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1603 /* This formerly implied "stripe-index", but was confusing
1604 * with "file offset" (which will eventually be needed for
1605 * with different layouts by offset), so deprecate it. */
1606 {"offset", no_argument, 0, 'o'},
1608 {"obd", required_argument, 0, 'O'},
1609 {"ost", required_argument, 0, 'O'},
1610 {"pool", no_argument, 0, 'p'},
1611 {"quiet", no_argument, 0, 'q'},
1612 {"recursive", no_argument, 0, 'r'},
1613 {"raw", no_argument, 0, 'R'},
1614 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1615 /* This formerly implied "--stripe-size", but was confusing
1616 * with "lfs find --size|-s", which means "file size", so use
1617 * the consistent "--stripe-size|-S" for all commands. */
1618 {"size", no_argument, 0, 's'},
1620 {"stripe-size", no_argument, 0, 'S'},
1621 {"stripe_size", no_argument, 0, 'S'},
1622 {"verbose", no_argument, 0, 'v'},
1627 param->fp_max_depth = 1;
1628 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1629 long_opts, NULL)) != -1) {
1632 if (param->fp_obd_uuid) {
1634 "error: %s: only one obduuid allowed",
1638 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1644 param->fp_max_depth = 0;
1647 param->fp_get_default_lmv = 1;
1650 param->fp_recursive = 1;
1653 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1656 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1657 if (strcmp(argv[optind - 1], "--count") == 0)
1658 fprintf(stderr, "warning: '--count' deprecated,"
1659 " use '--stripe-count' instead\n");
1661 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1662 param->fp_verbose |= VERBOSE_COUNT;
1663 param->fp_max_depth = 0;
1666 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1668 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1669 fprintf(stderr, "warning: '--size|-s' deprecated, "
1670 "use '--stripe-size|-S' instead\n");
1672 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1674 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1675 param->fp_verbose |= VERBOSE_SIZE;
1676 param->fp_max_depth = 0;
1679 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1681 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1682 "use '--stripe-index|-i' instead\n");
1685 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1686 if (strcmp(argv[optind - 1], "--index") == 0)
1687 fprintf(stderr, "warning: '--index' deprecated"
1688 ", use '--stripe-index' instead\n");
1690 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1691 param->fp_verbose |= VERBOSE_OFFSET;
1692 param->fp_max_depth = 0;
1696 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1697 param->fp_verbose |= VERBOSE_POOL;
1698 param->fp_max_depth = 0;
1702 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1703 param->fp_verbose |= VERBOSE_GENERATION;
1704 param->fp_max_depth = 0;
1708 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1709 param->fp_verbose |= VERBOSE_LAYOUT;
1710 param->fp_max_depth = 0;
1714 if (!(param->fp_verbose & VERBOSE_DETAIL))
1715 param->fp_max_depth = 0;
1716 param->fp_verbose |= VERBOSE_MDTINDEX;
1729 if (param->fp_recursive)
1730 param->fp_max_depth = -1;
1732 if (!param->fp_verbose)
1733 param->fp_verbose = VERBOSE_ALL;
1734 if (param->fp_quiet)
1735 param->fp_verbose = VERBOSE_OBJID;
1738 rc = llapi_getstripe(argv[optind], param);
1739 } while (++optind < argc && !rc);
1742 fprintf(stderr, "error: %s failed for %s.\n",
1743 argv[0], argv[optind - 1]);
1747 static int lfs_tgts(int argc, char **argv)
1749 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1750 struct find_param param;
1751 int index = 0, rc=0;
1756 if (argc == 2 && !realpath(argv[1], path)) {
1758 fprintf(stderr, "error: invalid path '%s': %s\n",
1759 argv[1], strerror(-rc));
1763 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1764 /* Check if we have a mount point */
1765 if (mntdir[0] == '\0')
1768 memset(¶m, 0, sizeof(param));
1769 if (!strcmp(argv[0], "mdts"))
1770 param.fp_get_lmv = 1;
1772 rc = llapi_ostlist(mntdir, ¶m);
1774 fprintf(stderr, "error: %s: failed on %s\n",
1777 if (path[0] != '\0')
1779 memset(mntdir, 0, PATH_MAX);
1785 static int lfs_getstripe(int argc, char **argv)
1787 struct find_param param = { 0 };
1788 return lfs_getstripe_internal(argc, argv, ¶m);
1792 static int lfs_getdirstripe(int argc, char **argv)
1794 struct find_param param = { 0 };
1796 param.fp_get_lmv = 1;
1797 return lfs_getstripe_internal(argc, argv, ¶m);
1801 static int lfs_setdirstripe(int argc, char **argv)
1805 unsigned int stripe_offset = -1;
1806 unsigned int stripe_count = 1;
1807 enum lmv_hash_type hash_type;
1810 char *stripe_offset_opt = NULL;
1811 char *stripe_count_opt = NULL;
1812 char *stripe_hash_opt = NULL;
1813 char *mode_opt = NULL;
1814 bool default_stripe = false;
1815 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1816 mode_t previous_mode = 0;
1817 bool delete = false;
1819 struct option long_opts[] = {
1820 {"count", required_argument, 0, 'c'},
1821 {"delete", no_argument, 0, 'd'},
1822 {"index", required_argument, 0, 'i'},
1823 {"mode", required_argument, 0, 'm'},
1824 {"hash-type", required_argument, 0, 't'},
1825 {"default_stripe", no_argument, 0, 'D'},
1829 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1836 stripe_count_opt = optarg;
1840 default_stripe = true;
1843 default_stripe = true;
1846 stripe_offset_opt = optarg;
1852 stripe_hash_opt = optarg;
1855 fprintf(stderr, "error: %s: option '%s' "
1857 argv[0], argv[optind - 1]);
1862 if (optind == argc) {
1863 fprintf(stderr, "error: %s: missing dirname\n",
1868 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1869 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1874 if (stripe_offset_opt != NULL) {
1875 /* get the stripe offset */
1876 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1878 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1879 argv[0], stripe_offset_opt);
1885 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1886 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1887 " or -i options.\n", argv[0]);
1895 if (mode_opt != NULL) {
1896 mode = strtoul(mode_opt, &end, 8);
1898 fprintf(stderr, "error: %s: bad mode '%s'\n",
1902 previous_mode = umask(0);
1905 if (stripe_hash_opt == NULL ||
1906 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1907 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1908 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1909 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1911 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1912 argv[0], stripe_hash_opt);
1916 /* get the stripe count */
1917 if (stripe_count_opt != NULL) {
1918 stripe_count = strtoul(stripe_count_opt, &end, 0);
1920 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1921 argv[0], stripe_count_opt);
1926 dname = argv[optind];
1928 if (default_stripe) {
1929 result = llapi_dir_set_default_lmv_stripe(dname,
1930 stripe_offset, stripe_count,
1933 result = llapi_dir_create_pool(dname, mode,
1935 stripe_count, hash_type,
1940 fprintf(stderr, "error: %s: create stripe dir '%s' "
1941 "failed\n", argv[0], dname);
1944 dname = argv[++optind];
1945 } while (dname != NULL);
1947 if (mode_opt != NULL)
1948 umask(previous_mode);
1954 static int lfs_rmentry(int argc, char **argv)
1961 fprintf(stderr, "error: %s: missing dirname\n",
1967 dname = argv[index];
1968 while (dname != NULL) {
1969 result = llapi_direntry_remove(dname);
1971 fprintf(stderr, "error: %s: remove dir entry '%s' "
1972 "failed\n", argv[0], dname);
1975 dname = argv[++index];
1980 static int lfs_mv(int argc, char **argv)
1982 struct find_param param = {
1989 struct option long_opts[] = {
1990 {"mdt-index", required_argument, 0, 'M'},
1991 {"verbose", no_argument, 0, 'v'},
1995 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
1998 param.fp_mdt_index = strtoul(optarg, &end, 0);
2000 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2007 param.fp_verbose = VERBOSE_DETAIL;
2011 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2012 argv[0], argv[optind - 1]);
2017 if (param.fp_mdt_index == -1) {
2018 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2022 if (optind >= argc) {
2023 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2027 param.fp_migrate = 1;
2028 rc = llapi_mv(argv[optind], ¶m);
2030 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2031 argv[0], argv[optind], param.fp_mdt_index,
2036 static int lfs_osts(int argc, char **argv)
2038 return lfs_tgts(argc, argv);
2041 static int lfs_mdts(int argc, char **argv)
2043 return lfs_tgts(argc, argv);
2046 #define COOK(value) \
2049 while (value > 1024) { \
2057 #define CDF "%11llu"
2058 #define HDF "%8.1f%c"
2062 static int showdf(char *mntdir, struct obd_statfs *stat,
2063 char *uuid, int ishow, int cooked,
2064 char *type, int index, int rc)
2066 long long avail, used, total;
2068 char *suffix = "KMGTPEZY";
2069 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2070 char tbuf[3 * sizeof(__u64)];
2071 char ubuf[3 * sizeof(__u64)];
2072 char abuf[3 * sizeof(__u64)];
2073 char rbuf[3 * sizeof(__u64)];
2081 avail = stat->os_ffree;
2082 used = stat->os_files - stat->os_ffree;
2083 total = stat->os_files;
2085 int shift = cooked ? 0 : 10;
2087 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2088 used = ((stat->os_blocks - stat->os_bfree) *
2089 stat->os_bsize) >> shift;
2090 total = (stat->os_blocks * stat->os_bsize) >> shift;
2093 if ((used + avail) > 0)
2094 ratio = (double)used / (double)(used + avail);
2100 cook_val = (double)total;
2103 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2105 sprintf(tbuf, CDF, total);
2107 cook_val = (double)used;
2110 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2112 sprintf(ubuf, CDF, used);
2114 cook_val = (double)avail;
2117 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2119 sprintf(abuf, CDF, avail);
2121 sprintf(tbuf, CDF, total);
2122 sprintf(ubuf, CDF, used);
2123 sprintf(abuf, CDF, avail);
2126 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2127 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2128 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2130 printf("[%s:%d]\n", type, index);
2136 printf(UUF": inactive device\n", uuid);
2139 printf(UUF": %s\n", uuid, strerror(-rc));
2146 struct ll_stat_type {
2151 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2152 int cooked, int lazy)
2154 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2155 struct obd_uuid uuid_buf;
2156 char *poolname = NULL;
2157 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2158 { LL_STATFS_LOV, "OST" },
2160 struct ll_stat_type *tp;
2161 __u64 ost_ffree = 0;
2167 poolname = strchr(pool, '.');
2168 if (poolname != NULL) {
2169 if (strncmp(fsname, pool, strlen(fsname))) {
2170 fprintf(stderr, "filesystem name incorrect\n");
2179 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2180 "UUID", "Inodes", "IUsed", "IFree",
2181 "IUse%", "Mounted on");
2183 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2184 "UUID", cooked ? "bytes" : "1K-blocks",
2185 "Used", "Available", "Use%", "Mounted on");
2187 for (tp = types; tp->st_name != NULL; tp++) {
2188 for (index = 0; ; index++) {
2189 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2190 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2191 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2192 rc = llapi_obd_statfs(mntdir, type, index,
2193 &stat_buf, &uuid_buf);
2200 if (poolname && tp->st_op == LL_STATFS_LOV &&
2201 llapi_search_ost(fsname, poolname,
2202 obd_uuid2str(&uuid_buf)) != 1)
2205 /* the llapi_obd_statfs() call may have returned with
2206 * an error, but if it filled in uuid_buf we will at
2207 * lease use that to print out a message for that OBD.
2208 * If we didn't get anything in the uuid_buf, then fill
2209 * it in so that we can print an error message. */
2210 if (uuid_buf.uuid[0] == '\0')
2211 sprintf(uuid_buf.uuid, "%s%04x",
2212 tp->st_name, index);
2213 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2214 ishow, cooked, tp->st_name, index, rc);
2217 if (tp->st_op == LL_STATFS_LMV) {
2218 sum.os_ffree += stat_buf.os_ffree;
2219 sum.os_files += stat_buf.os_files;
2220 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2221 sum.os_blocks += stat_buf.os_blocks *
2223 sum.os_bfree += stat_buf.os_bfree *
2225 sum.os_bavail += stat_buf.os_bavail *
2227 ost_ffree += stat_buf.os_ffree;
2229 } else if (rc == -EINVAL || rc == -EFAULT) {
2235 /* If we don't have as many objects free on the OST as inodes
2236 * on the MDS, we reduce the total number of inodes to
2237 * compensate, so that the "inodes in use" number is correct.
2238 * Matches ll_statfs_internal() so the results are consistent. */
2239 if (ost_ffree < sum.os_ffree) {
2240 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2241 sum.os_ffree = ost_ffree;
2244 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2249 static int lfs_df(int argc, char **argv)
2251 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2252 int ishow = 0, cooked = 0;
2254 int c, rc = 0, index = 0;
2255 char fsname[PATH_MAX] = "", *pool_name = NULL;
2256 struct option long_opts[] = {
2257 {"pool", required_argument, 0, 'p'},
2258 {"lazy", 0, 0, 'l'},
2262 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2280 if (optind < argc && !realpath(argv[optind], path)) {
2282 fprintf(stderr, "error: invalid path '%s': %s\n",
2283 argv[optind], strerror(-rc));
2287 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2288 /* Check if we have a mount point */
2289 if (mntdir[0] == '\0')
2292 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2293 if (rc || path[0] != '\0')
2295 fsname[0] = '\0'; /* avoid matching in next loop */
2296 mntdir[0] = '\0'; /* avoid matching in next loop */
2302 static int lfs_getname(int argc, char **argv)
2304 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2305 int rc = 0, index = 0, c;
2306 char buf[sizeof(struct obd_uuid)];
2308 while ((c = getopt(argc, argv, "h")) != -1)
2311 if (optind == argc) { /* no paths specified, get all paths. */
2312 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2313 rc = llapi_getname(mntdir, buf, sizeof(buf));
2316 "cannot get name for `%s': %s\n",
2317 mntdir, strerror(-rc));
2321 printf("%s %s\n", buf, mntdir);
2323 path[0] = fsname[0] = mntdir[0] = 0;
2325 } else { /* paths specified, only attempt to search these. */
2326 for (; optind < argc; optind++) {
2327 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2330 "cannot get name for `%s': %s\n",
2331 argv[optind], strerror(-rc));
2335 printf("%s %s\n", buf, argv[optind]);
2341 static int lfs_check(int argc, char **argv)
2344 char mntdir[PATH_MAX] = {'\0'};
2353 obd_types[0] = obd_type1;
2354 obd_types[1] = obd_type2;
2356 if (strcmp(argv[1], "osts") == 0) {
2357 strcpy(obd_types[0], "osc");
2358 } else if (strcmp(argv[1], "mds") == 0) {
2359 strcpy(obd_types[0], "mdc");
2360 } else if (strcmp(argv[1], "servers") == 0) {
2362 strcpy(obd_types[0], "osc");
2363 strcpy(obd_types[1], "mdc");
2365 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2370 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2371 if (rc < 0 || mntdir[0] == '\0') {
2372 fprintf(stderr, "No suitable Lustre mount found\n");
2376 rc = llapi_target_check(num_types, obd_types, mntdir);
2378 fprintf(stderr, "error: %s: %s status failed\n",
2385 static int lfs_join(int argc, char **argv)
2387 fprintf(stderr, "join two lustre files into one.\n"
2388 "obsolete, HEAD does not support it anymore.\n");
2392 #ifdef HAVE_SYS_QUOTA_H
2393 #define ARG2INT(nr, str, msg) \
2396 nr = strtol(str, &endp, 0); \
2398 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2403 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2405 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2406 * returns the value or ULONG_MAX on integer overflow or incorrect format
2408 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2409 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2410 * 3. empty integer value is interpreted as 0
2412 static unsigned long str2sec(const char* timestr)
2414 const char spec[] = "smhdw";
2415 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2416 unsigned long val = 0;
2419 if (strpbrk(timestr, spec) == NULL) {
2420 /* no specifiers inside the time string,
2421 should treat it as an integer value */
2422 val = strtoul(timestr, &tail, 10);
2423 return *tail ? ULONG_MAX : val;
2426 /* format string is XXwXXdXXhXXmXXs */
2432 v = strtoul(timestr, &tail, 10);
2433 if (v == ULONG_MAX || *tail == '\0')
2434 /* value too large (ULONG_MAX or more)
2435 or missing specifier */
2438 ptr = strchr(spec, *tail);
2440 /* unknown specifier */
2445 /* check if product will overflow the type */
2446 if (!(v < ULONG_MAX / mult[ind]))
2449 ADD_OVERFLOW(val, mult[ind] * v);
2450 if (val == ULONG_MAX)
2462 #define ARG2ULL(nr, str, def_units) \
2464 unsigned long long limit, units = def_units; \
2467 rc = llapi_parse_size(str, &limit, &units, 1); \
2469 fprintf(stderr, "error: bad limit value %s\n", str); \
2475 static inline int has_times_option(int argc, char **argv)
2479 for (i = 1; i < argc; i++)
2480 if (!strcmp(argv[i], "-t"))
2486 int lfs_setquota_times(int argc, char **argv)
2489 struct if_quotactl qctl;
2490 char *mnt, *obd_type = (char *)qctl.obd_type;
2491 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2492 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2493 struct option long_opts[] = {
2494 {"block-grace", required_argument, 0, 'b'},
2495 {"group", no_argument, 0, 'g'},
2496 {"inode-grace", required_argument, 0, 'i'},
2497 {"times", no_argument, 0, 't'},
2498 {"user", no_argument, 0, 'u'},
2502 memset(&qctl, 0, sizeof(qctl));
2503 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2504 qctl.qc_type = UGQUOTA;
2506 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2510 if (qctl.qc_type != UGQUOTA) {
2511 fprintf(stderr, "error: -u and -g can't be used "
2512 "more than once\n");
2515 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2518 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2519 fprintf(stderr, "error: bad block-grace: %s\n",
2523 dqb->dqb_valid |= QIF_BTIME;
2526 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2527 fprintf(stderr, "error: bad inode-grace: %s\n",
2531 dqb->dqb_valid |= QIF_ITIME;
2533 case 't': /* Yes, of course! */
2535 default: /* getopt prints error message for us when opterr != 0 */
2540 if (qctl.qc_type == UGQUOTA) {
2541 fprintf(stderr, "error: neither -u nor -g specified\n");
2545 if (optind != argc - 1) {
2546 fprintf(stderr, "error: unexpected parameters encountered\n");
2551 rc = llapi_quotactl(mnt, &qctl);
2554 fprintf(stderr, "%s %s ", obd_type,
2555 obd_uuid2str(&qctl.obd_uuid));
2556 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2563 #define BSLIMIT (1 << 0)
2564 #define BHLIMIT (1 << 1)
2565 #define ISLIMIT (1 << 2)
2566 #define IHLIMIT (1 << 3)
2568 int lfs_setquota(int argc, char **argv)
2571 struct if_quotactl qctl;
2572 char *mnt, *obd_type = (char *)qctl.obd_type;
2573 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2574 struct option long_opts[] = {
2575 {"block-softlimit", required_argument, 0, 'b'},
2576 {"block-hardlimit", required_argument, 0, 'B'},
2577 {"group", required_argument, 0, 'g'},
2578 {"inode-softlimit", required_argument, 0, 'i'},
2579 {"inode-hardlimit", required_argument, 0, 'I'},
2580 {"user", required_argument, 0, 'u'},
2583 unsigned limit_mask = 0;
2586 if (has_times_option(argc, argv))
2587 return lfs_setquota_times(argc, argv);
2589 memset(&qctl, 0, sizeof(qctl));
2590 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2591 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2592 * so it can be used as a marker that qc_type
2593 * isn't reinitialized from command line */
2595 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2599 if (qctl.qc_type != UGQUOTA) {
2600 fprintf(stderr, "error: -u and -g can't be used"
2601 " more than once\n");
2604 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2605 rc = name2id(&qctl.qc_id, optarg,
2606 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2608 qctl.qc_id = strtoul(optarg, &endptr, 10);
2609 if (*endptr != '\0') {
2610 fprintf(stderr, "error: can't find id "
2611 "for name %s\n", optarg);
2617 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2618 dqb->dqb_bsoftlimit >>= 10;
2619 limit_mask |= BSLIMIT;
2620 if (dqb->dqb_bsoftlimit &&
2621 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2622 fprintf(stderr, "warning: block softlimit is "
2623 "smaller than the miminal qunit size, "
2624 "please see the help of setquota or "
2625 "Lustre manual for details.\n");
2628 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2629 dqb->dqb_bhardlimit >>= 10;
2630 limit_mask |= BHLIMIT;
2631 if (dqb->dqb_bhardlimit &&
2632 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2633 fprintf(stderr, "warning: block hardlimit is "
2634 "smaller than the miminal qunit size, "
2635 "please see the help of setquota or "
2636 "Lustre manual for details.\n");
2639 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2640 limit_mask |= ISLIMIT;
2641 if (dqb->dqb_isoftlimit &&
2642 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2643 fprintf(stderr, "warning: inode softlimit is "
2644 "smaller than the miminal qunit size, "
2645 "please see the help of setquota or "
2646 "Lustre manual for details.\n");
2649 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2650 limit_mask |= IHLIMIT;
2651 if (dqb->dqb_ihardlimit &&
2652 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2653 fprintf(stderr, "warning: inode hardlimit is "
2654 "smaller than the miminal qunit size, "
2655 "please see the help of setquota or "
2656 "Lustre manual for details.\n");
2658 default: /* getopt prints error message for us when opterr != 0 */
2663 if (qctl.qc_type == UGQUOTA) {
2664 fprintf(stderr, "error: neither -u nor -g was specified\n");
2668 if (limit_mask == 0) {
2669 fprintf(stderr, "error: at least one limit must be specified\n");
2673 if (optind != argc - 1) {
2674 fprintf(stderr, "error: unexpected parameters encountered\n");
2680 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2681 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2682 /* sigh, we can't just set blimits/ilimits */
2683 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2684 .qc_type = qctl.qc_type,
2685 .qc_id = qctl.qc_id};
2687 rc = llapi_quotactl(mnt, &tmp_qctl);
2689 fprintf(stderr, "error: setquota failed while retrieving"
2690 " current quota settings (%s)\n",
2695 if (!(limit_mask & BHLIMIT))
2696 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2697 if (!(limit_mask & BSLIMIT))
2698 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2699 if (!(limit_mask & IHLIMIT))
2700 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2701 if (!(limit_mask & ISLIMIT))
2702 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2704 /* Keep grace times if we have got no softlimit arguments */
2705 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2706 dqb->dqb_valid |= QIF_BTIME;
2707 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2710 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2711 dqb->dqb_valid |= QIF_ITIME;
2712 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2716 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2717 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2719 rc = llapi_quotactl(mnt, &qctl);
2722 fprintf(stderr, "%s %s ", obd_type,
2723 obd_uuid2str(&qctl.obd_uuid));
2724 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2731 static inline char *type2name(int check_type)
2733 if (check_type == USRQUOTA)
2735 else if (check_type == GRPQUOTA)
2741 /* Converts seconds value into format string
2742 * result is returned in buf
2744 * 1. result is in descenting order: 1w2d3h4m5s
2745 * 2. zero fields are not filled (except for p. 3): 5d1s
2746 * 3. zero seconds value is presented as "0s"
2748 static char * __sec2str(time_t seconds, char *buf)
2750 const char spec[] = "smhdw";
2751 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2756 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2757 c = seconds / mult[i];
2759 if (c > 0 || (i == 0 && buf == tail))
2760 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2768 static void sec2str(time_t seconds, char *buf, int rc)
2775 tail = __sec2str(seconds, tail);
2777 if (rc && tail - buf < 39) {
2783 static void diff2str(time_t seconds, char *buf, time_t now)
2789 if (seconds <= now) {
2790 strcpy(buf, "none");
2793 __sec2str(seconds - now, buf);
2796 static void print_quota_title(char *name, struct if_quotactl *qctl,
2797 bool human_readable)
2799 printf("Disk quotas for %s %s (%cid %u):\n",
2800 type2name(qctl->qc_type), name,
2801 *type2name(qctl->qc_type), qctl->qc_id);
2802 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2803 "Filesystem", human_readable ? "used" : "kbytes",
2804 "quota", "limit", "grace",
2805 "files", "quota", "limit", "grace");
2808 static void kbytes2str(__u64 num, char *buf, bool h)
2811 sprintf(buf, LPU64, num);
2814 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2816 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2818 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2820 sprintf(buf, LPU64"%s", num, "k");
2824 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2831 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2832 int bover = 0, iover = 0;
2833 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2838 if (dqb->dqb_bhardlimit &&
2839 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2841 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2842 if (dqb->dqb_btime > now) {
2849 if (dqb->dqb_ihardlimit &&
2850 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2852 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2853 if (dqb->dqb_itime > now) {
2861 if (strlen(mnt) > 15)
2862 printf("%s\n%15s", mnt, "");
2864 printf("%15s", mnt);
2867 diff2str(dqb->dqb_btime, timebuf, now);
2869 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2870 if (rc == -EREMOTEIO)
2871 sprintf(numbuf[0], "%s*", strbuf);
2873 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2874 "%s" : "[%s]", strbuf);
2876 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2877 if (type == QC_GENERAL)
2878 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2879 "%s" : "[%s]", strbuf);
2881 sprintf(numbuf[1], "%s", "-");
2883 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2884 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2885 "%s" : "[%s]", strbuf);
2887 printf(" %7s%c %6s %7s %7s",
2888 numbuf[0], bover ? '*' : ' ', numbuf[1],
2889 numbuf[2], bover > 1 ? timebuf : "-");
2892 diff2str(dqb->dqb_itime, timebuf, now);
2894 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2895 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2897 if (type == QC_GENERAL)
2898 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2899 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2901 sprintf(numbuf[1], "%s", "-");
2903 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2904 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2906 if (type != QC_OSTIDX)
2907 printf(" %7s%c %6s %7s %7s",
2908 numbuf[0], iover ? '*' : ' ', numbuf[1],
2909 numbuf[2], iover > 1 ? timebuf : "-");
2911 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2914 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2915 qctl->qc_cmd == Q_GETOINFO) {
2919 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2920 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2921 printf("Block grace time: %s; Inode grace time: %s\n",
2922 bgtimebuf, igtimebuf);
2926 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2927 bool h, __u64 *total)
2929 int rc = 0, rc1 = 0, count = 0;
2930 __u32 valid = qctl->qc_valid;
2932 rc = llapi_get_obd_count(mnt, &count, is_mdt);
2934 fprintf(stderr, "can not get %s count: %s\n",
2935 is_mdt ? "mdt": "ost", strerror(-rc));
2939 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2940 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2941 rc = llapi_quotactl(mnt, qctl);
2943 /* It is remote client case. */
2944 if (-rc == EOPNOTSUPP) {
2951 fprintf(stderr, "quotactl %s%d failed.\n",
2952 is_mdt ? "mdt": "ost", qctl->qc_idx);
2956 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
2957 qctl->qc_valid, 0, h);
2958 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
2959 qctl->qc_dqblk.dqb_bhardlimit;
2962 qctl->qc_valid = valid;
2966 static int lfs_quota(int argc, char **argv)
2969 char *mnt, *name = NULL;
2970 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2971 .qc_type = UGQUOTA };
2972 char *obd_type = (char *)qctl.obd_type;
2973 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2974 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2975 verbose = 0, pass = 0, quiet = 0, inacc;
2977 __u32 valid = QC_GENERAL, idx = 0;
2978 __u64 total_ialloc = 0, total_balloc = 0;
2979 bool human_readable = false;
2981 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
2984 if (qctl.qc_type != UGQUOTA) {
2985 fprintf(stderr, "error: use either -u or -g\n");
2988 qctl.qc_type = USRQUOTA;
2991 if (qctl.qc_type != UGQUOTA) {
2992 fprintf(stderr, "error: use either -u or -g\n");
2995 qctl.qc_type = GRPQUOTA;
2998 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3001 valid = qctl.qc_valid = QC_UUID;
3002 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3005 valid = qctl.qc_valid = QC_MDTIDX;
3006 idx = qctl.qc_idx = atoi(optarg);
3009 valid = qctl.qc_valid = QC_OSTIDX;
3010 idx = qctl.qc_idx = atoi(optarg);
3019 human_readable = true;
3022 fprintf(stderr, "error: %s: option '-%c' "
3023 "unrecognized\n", argv[0], c);
3028 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3029 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3030 optind == argc - 1) {
3032 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3033 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3034 qctl.qc_valid = valid;
3037 qctl.qc_type = USRQUOTA;
3038 qctl.qc_id = geteuid();
3040 qctl.qc_type = GRPQUOTA;
3041 qctl.qc_id = getegid();
3043 rc = id2name(&name, qctl.qc_id,
3044 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3047 /* lfs quota -u username /path/to/lustre/mount */
3048 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3049 /* options should be followed by u/g-name and mntpoint */
3050 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3051 fprintf(stderr, "error: missing quota argument(s)\n");
3055 name = argv[optind++];
3056 rc = name2id(&qctl.qc_id, name,
3057 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3059 qctl.qc_id = strtoul(name, &endptr, 10);
3060 if (*endptr != '\0') {
3061 fprintf(stderr, "error: can't find id for name "
3066 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3067 fprintf(stderr, "error: missing quota info argument(s)\n");
3073 rc1 = llapi_quotactl(mnt, &qctl);
3077 fprintf(stderr, "%s quotas are not enabled.\n",
3078 qctl.qc_type == USRQUOTA ? "user" : "group");
3081 fprintf(stderr, "Permission denied.\n");
3083 /* We already got a "No such file..." message. */
3086 fprintf(stderr, "Unexpected quotactl error: %s\n",
3091 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3092 print_quota_title(name, &qctl, human_readable);
3094 if (rc1 && *obd_type)
3095 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3097 if (qctl.qc_valid != QC_GENERAL)
3100 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3101 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3102 (QIF_LIMITS|QIF_USAGE));
3104 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3106 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3110 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3112 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3114 kbytes2str(total_balloc, strbuf, human_readable);
3115 printf("Total allocated inode limit: "LPU64", total "
3116 "allocated block limit: %s\n", total_ialloc, strbuf);
3119 if (rc1 || rc2 || rc3 || inacc)
3120 printf("Some errors happened when getting quota info. "
3121 "Some devices may be not working or deactivated. "
3122 "The data in \"[]\" is inaccurate.\n");
3130 #endif /* HAVE_SYS_QUOTA_H! */
3132 static int flushctx_ioctl(char *mp)
3136 fd = open(mp, O_RDONLY);
3138 fprintf(stderr, "flushctx: error open %s: %s\n",
3139 mp, strerror(errno));
3143 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3145 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3146 mp, strerror(errno));
3152 static int lfs_flushctx(int argc, char **argv)
3154 int kdestroy = 0, c;
3155 char mntdir[PATH_MAX] = {'\0'};
3159 while ((c = getopt(argc, argv, "k")) != -1) {
3165 fprintf(stderr, "error: %s: option '-%c' "
3166 "unrecognized\n", argv[0], c);
3172 if ((rc = system("kdestroy > /dev/null")) != 0) {
3173 rc = WEXITSTATUS(rc);
3174 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3178 if (optind >= argc) {
3179 /* flush for all mounted lustre fs. */
3180 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3181 /* Check if we have a mount point */
3182 if (mntdir[0] == '\0')
3185 if (flushctx_ioctl(mntdir))
3188 mntdir[0] = '\0'; /* avoid matching in next loop */
3191 /* flush fs as specified */
3192 while (optind < argc) {
3193 if (flushctx_ioctl(argv[optind++]))
3200 static int lfs_lsetfacl(int argc, char **argv)
3203 return(llapi_lsetfacl(argc, argv));
3206 static int lfs_lgetfacl(int argc, char **argv)
3209 return(llapi_lgetfacl(argc, argv));
3212 static int lfs_rsetfacl(int argc, char **argv)
3215 return(llapi_rsetfacl(argc, argv));
3218 static int lfs_rgetfacl(int argc, char **argv)
3221 return(llapi_rgetfacl(argc, argv));
3224 static int lfs_cp(int argc, char **argv)
3226 return(llapi_cp(argc, argv));
3229 static int lfs_ls(int argc, char **argv)
3231 return(llapi_ls(argc, argv));
3234 static int lfs_changelog(int argc, char **argv)
3236 void *changelog_priv;
3237 struct changelog_rec *rec;
3238 long long startrec = 0, endrec = 0;
3240 struct option long_opts[] = {
3241 {"follow", no_argument, 0, 'f'},
3244 char short_opts[] = "f";
3247 while ((rc = getopt_long(argc, argv, short_opts,
3248 long_opts, NULL)) != -1) {
3256 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3257 argv[0], argv[optind - 1]);
3264 mdd = argv[optind++];
3266 startrec = strtoll(argv[optind++], NULL, 10);
3268 endrec = strtoll(argv[optind++], NULL, 10);
3270 rc = llapi_changelog_start(&changelog_priv,
3271 CHANGELOG_FLAG_BLOCK |
3272 CHANGELOG_FLAG_JOBID |
3273 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3276 fprintf(stderr, "Can't start changelog: %s\n",
3277 strerror(errno = -rc));
3281 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3285 if (endrec && rec->cr_index > endrec) {
3286 llapi_changelog_free(&rec);
3289 if (rec->cr_index < startrec) {
3290 llapi_changelog_free(&rec);
3294 secs = rec->cr_time >> 30;
3295 gmtime_r(&secs, &ts);
3296 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3297 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3298 changelog_type2str(rec->cr_type),
3299 ts.tm_hour, ts.tm_min, ts.tm_sec,
3300 (int)(rec->cr_time & ((1<<30) - 1)),
3301 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3302 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3304 if (rec->cr_flags & CLF_JOBID) {
3305 struct changelog_ext_jobid *jid =
3306 changelog_rec_jobid(rec);
3308 if (jid->cr_jobid[0] != '\0')
3309 printf(" j=%s", jid->cr_jobid);
3312 if (rec->cr_namelen)
3313 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3314 rec->cr_namelen, changelog_rec_name(rec));
3316 if (rec->cr_flags & CLF_RENAME) {
3317 struct changelog_ext_rename *rnm =
3318 changelog_rec_rename(rec);
3320 if (!fid_is_zero(&rnm->cr_sfid))
3321 printf(" s="DFID" sp="DFID" %.*s",
3322 PFID(&rnm->cr_sfid),
3323 PFID(&rnm->cr_spfid),
3324 (int)changelog_rec_snamelen(rec),
3325 changelog_rec_sname(rec));
3329 llapi_changelog_free(&rec);
3332 llapi_changelog_fini(&changelog_priv);
3335 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3337 return (rc == 1 ? 0 : rc);
3340 static int lfs_changelog_clear(int argc, char **argv)
3348 endrec = strtoll(argv[3], NULL, 10);
3350 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3352 fprintf(stderr, "%s error: %s\n", argv[0],
3353 strerror(errno = -rc));
3357 static int lfs_fid2path(int argc, char **argv)
3359 struct option long_opts[] = {
3360 {"cur", no_argument, 0, 'c'},
3361 {"link", required_argument, 0, 'l'},
3362 {"rec", required_argument, 0, 'r'},
3365 char short_opts[] = "cl:r:";
3366 char *device, *fid, *path;
3367 long long recno = -1;
3373 while ((rc = getopt_long(argc, argv, short_opts,
3374 long_opts, NULL)) != -1) {
3380 linkno = strtol(optarg, NULL, 10);
3383 recno = strtoll(optarg, NULL, 10);
3388 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3389 argv[0], argv[optind - 1]);
3397 device = argv[optind++];
3398 path = calloc(1, PATH_MAX);
3400 fprintf(stderr, "error: Not enough memory\n");
3405 while (optind < argc) {
3406 fid = argv[optind++];
3408 lnktmp = (linkno >= 0) ? linkno : 0;
3410 int oldtmp = lnktmp;
3411 long long rectmp = recno;
3413 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3416 fprintf(stderr, "%s: error on FID %s: %s\n",
3417 argv[0], fid, strerror(errno = -rc2));
3424 fprintf(stdout, "%lld ", rectmp);
3425 if (device[0] == '/') {
3426 fprintf(stdout, "%s", device);
3427 if (device[strlen(device) - 1] != '/')
3428 fprintf(stdout, "/");
3429 } else if (path[0] == '\0') {
3430 fprintf(stdout, "/");
3432 fprintf(stdout, "%s\n", path);
3435 /* specified linkno */
3437 if (oldtmp == lnktmp)
3447 static int lfs_path2fid(int argc, char **argv)
3449 struct option long_opts[] = {
3450 {"parents", no_argument, 0, 'p'},
3454 const char short_opts[] = "p";
3455 const char *sep = "";
3458 bool show_parents = false;
3460 while ((rc = getopt_long(argc, argv, short_opts,
3461 long_opts, NULL)) != -1) {
3464 show_parents = true;
3467 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3468 argv[0], argv[optind - 1]);
3473 if (optind > argc - 1)
3475 else if (optind < argc - 1)
3479 for (path = argv + optind; *path != NULL; path++) {
3481 if (!show_parents) {
3482 err = llapi_path2fid(*path, &fid);
3484 printf("%s%s"DFID"\n",
3485 *sep != '\0' ? *path : "", sep,
3488 char name[NAME_MAX + 1];
3489 unsigned int linkno = 0;
3491 while ((err = llapi_path2parent(*path, linkno, &fid,
3492 name, sizeof(name))) == 0) {
3493 if (*sep != '\0' && linkno == 0)
3494 printf("%s%s", *path, sep);
3496 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3501 /* err == -ENODATA is end-of-loop */
3502 if (linkno > 0 && err == -ENODATA) {
3509 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3510 argv[0], show_parents ? "parent " : "", *path,
3522 static int lfs_data_version(int argc, char **argv)
3529 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3534 while ((c = getopt(argc, argv, "nrw")) != -1) {
3537 data_version_flags = 0;
3540 data_version_flags |= LL_DV_RD_FLUSH;
3543 data_version_flags |= LL_DV_WR_FLUSH;
3552 path = argv[optind];
3553 fd = open(path, O_RDONLY);
3555 err(errno, "cannot open file %s", path);
3557 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3559 err(errno, "cannot get version for %s", path);
3561 printf(LPU64 "\n", data_version);
3567 static int lfs_hsm_state(int argc, char **argv)
3572 struct hsm_user_state hus;
3580 rc = llapi_hsm_state_get(path, &hus);
3582 fprintf(stderr, "can't get hsm state for %s: %s\n",
3583 path, strerror(errno = -rc));
3587 /* Display path name and status flags */
3588 printf("%s: (0x%08x)", path, hus.hus_states);
3590 if (hus.hus_states & HS_RELEASED)
3591 printf(" released");
3592 if (hus.hus_states & HS_EXISTS)
3594 if (hus.hus_states & HS_DIRTY)
3596 if (hus.hus_states & HS_ARCHIVED)
3597 printf(" archived");
3598 /* Display user-settable flags */
3599 if (hus.hus_states & HS_NORELEASE)
3600 printf(" never_release");
3601 if (hus.hus_states & HS_NOARCHIVE)
3602 printf(" never_archive");
3603 if (hus.hus_states & HS_LOST)
3604 printf(" lost_from_hsm");
3606 if (hus.hus_archive_id != 0)
3607 printf(", archive_id:%d", hus.hus_archive_id);
3610 } while (++i < argc);
3615 #define LFS_HSM_SET 0
3616 #define LFS_HSM_CLEAR 1
3619 * Generic function to set or clear HSM flags.
3620 * Used by hsm_set and hsm_clear.
3622 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3624 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3626 struct option long_opts[] = {
3627 {"lost", 0, 0, 'l'},
3628 {"norelease", 0, 0, 'r'},
3629 {"noarchive", 0, 0, 'a'},
3630 {"archived", 0, 0, 'A'},
3631 {"dirty", 0, 0, 'd'},
3632 {"exists", 0, 0, 'e'},
3635 char short_opts[] = "lraAde";
3643 while ((c = getopt_long(argc, argv, short_opts,
3644 long_opts, NULL)) != -1) {
3650 mask |= HS_NOARCHIVE;
3653 mask |= HS_ARCHIVED;
3656 mask |= HS_NORELEASE;
3667 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3668 argv[0], argv[optind - 1]);
3673 /* User should have specified a flag */
3677 while (optind < argc) {
3679 path = argv[optind];
3681 /* If mode == 0, this means we apply the mask. */
3682 if (mode == LFS_HSM_SET)
3683 rc = llapi_hsm_state_set(path, mask, 0, 0);
3685 rc = llapi_hsm_state_set(path, 0, mask, 0);
3688 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3689 path, strerror(errno = -rc));
3698 static int lfs_hsm_action(int argc, char **argv)
3703 struct hsm_current_action hca;
3704 struct hsm_extent he;
3705 enum hsm_user_action hua;
3706 enum hsm_progress_states hps;
3714 rc = llapi_hsm_current_action(path, &hca);
3716 fprintf(stderr, "can't get hsm action for %s: %s\n",
3717 path, strerror(errno = -rc));
3720 he = hca.hca_location;
3721 hua = hca.hca_action;
3722 hps = hca.hca_state;
3724 printf("%s: %s", path, hsm_user_action2name(hua));
3726 /* Skip file without action */
3727 if (hca.hca_action == HUA_NONE) {
3732 printf(" %s ", hsm_progress_state2name(hps));
3734 if ((hps == HPS_RUNNING) &&
3735 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3736 printf("(%llu bytes moved)\n",
3737 (unsigned long long)he.length);
3738 else if ((he.offset + he.length) == LUSTRE_EOF)
3739 printf("(from %llu to EOF)\n",
3740 (unsigned long long)he.offset);
3742 printf("(from %llu to %llu)\n",
3743 (unsigned long long)he.offset,
3744 (unsigned long long)(he.offset + he.length));
3746 } while (++i < argc);
3751 static int lfs_hsm_set(int argc, char **argv)
3753 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3756 static int lfs_hsm_clear(int argc, char **argv)
3758 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3762 * Check file state and return its fid, to be used by lfs_hsm_request().
3764 * \param[in] file Path to file to check
3765 * \param[in,out] fid Pointer to allocated lu_fid struct.
3766 * \param[in,out] last_dev Pointer to last device id used.
3768 * \return 0 on success.
3770 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3776 rc = lstat(file, &st);
3778 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3781 /* Checking for regular file as archiving as posix copytool
3782 * rejects archiving files other than regular files
3784 if (!S_ISREG(st.st_mode)) {
3785 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3788 /* A request should be ... */
3789 if (*last_dev != st.st_dev && *last_dev != 0) {
3790 fprintf(stderr, "All files should be "
3791 "on the same filesystem: %s\n", file);
3794 *last_dev = st.st_dev;
3796 rc = llapi_path2fid(file, fid);
3798 fprintf(stderr, "Cannot read FID of %s: %s\n",
3799 file, strerror(-rc));
3805 /* Fill an HSM HUR item with a given file name.
3807 * If mntpath is set, then the filename is actually a FID, and no
3808 * lookup on the filesystem will be performed.
3810 * \param[in] hur the user request to fill
3811 * \param[in] idx index of the item inside the HUR to fill
3812 * \param[in] mntpath mountpoint of Lustre
3813 * \param[in] fname filename (if mtnpath is NULL)
3814 * or FID (if mntpath is set)
3815 * \param[in] last_dev pointer to last device id used
3817 * \retval 0 on success
3818 * \retval CMD_HELP or a negative errno on error
3820 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3821 const char *mntpath, const char *fname,
3824 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3827 hui->hui_extent.length = -1;
3829 if (mntpath != NULL) {
3832 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3836 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3841 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3845 hur->hur_request.hr_itemcount++;
3850 static int lfs_hsm_request(int argc, char **argv, int action)
3852 struct option long_opts[] = {
3853 {"filelist", 1, 0, 'l'},
3854 {"data", 1, 0, 'D'},
3855 {"archive", 1, 0, 'a'},
3856 {"mntpath", 1, 0, 'm'},
3860 char short_opts[] = "l:D:a:m:";
3861 struct hsm_user_request *hur, *oldhur;
3866 char *filelist = NULL;
3867 char fullpath[PATH_MAX];
3868 char *opaque = NULL;
3872 int nbfile_alloc = 0;
3873 char *some_file = NULL;
3874 char *mntpath = NULL;
3880 while ((c = getopt_long(argc, argv, short_opts,
3881 long_opts, NULL)) != -1) {
3890 if (action != HUA_ARCHIVE &&
3891 action != HUA_REMOVE) {
3893 "error: -a is supported only "
3894 "when archiving or removing\n");
3897 archive_id = atoi(optarg);
3900 if (some_file == NULL) {
3902 some_file = strdup(optarg);
3908 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3909 argv[0], argv[optind - 1]);
3914 /* All remaining args are files, so we have at least nbfile */
3915 nbfile = argc - optind;
3917 if ((nbfile == 0) && (filelist == NULL))
3921 opaque_len = strlen(opaque);
3923 /* Alloc the request structure with enough place to store all files
3924 * from command line. */
3925 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3927 fprintf(stderr, "Cannot create the request: %s\n",
3931 nbfile_alloc = nbfile;
3933 hur->hur_request.hr_action = action;
3934 hur->hur_request.hr_archive_id = archive_id;
3935 hur->hur_request.hr_flags = 0;
3937 /* All remaining args are files, add them */
3938 if (nbfile != 0 && some_file == NULL)
3939 some_file = strdup(argv[optind]);
3941 for (i = 0; i < nbfile; i++) {
3942 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
3948 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3950 /* If a filelist was specified, read the filelist from it. */
3951 if (filelist != NULL) {
3952 fp = fopen(filelist, "r");
3954 fprintf(stderr, "Cannot read the file list %s: %s\n",
3955 filelist, strerror(errno));
3960 while ((rc = getline(&line, &len, fp)) != -1) {
3961 /* If allocated buffer was too small, get something
3963 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3966 nbfile_alloc = nbfile_alloc * 2 + 1;
3968 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3971 fprintf(stderr, "hsm: cannot allocate "
3972 "the request: %s\n",
3979 size = hur_len(oldhur);
3981 fprintf(stderr, "hsm: cannot allocate "
3982 "%u files + %u bytes data\n",
3983 oldhur->hur_request.hr_itemcount,
3984 oldhur->hur_request.hr_data_len);
3991 memcpy(hur, oldhur, size);
3996 if (line[strlen(line) - 1] == '\n')
3997 line[strlen(line) - 1] = '\0';
3999 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4000 mntpath, line, &last_dev);
4006 if (some_file == NULL) {
4016 /* If a --data was used, add it to the request */
4017 hur->hur_request.hr_data_len = opaque_len;
4019 memcpy(hur_data(hur), opaque, opaque_len);
4021 /* Send the HSM request */
4022 if (realpath(some_file, fullpath) == NULL) {
4023 fprintf(stderr, "Could not find path '%s': %s\n",
4024 some_file, strerror(errno));
4026 rc = llapi_hsm_request(fullpath, hur);
4028 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4029 some_file, strerror(-rc));
4039 static int lfs_hsm_archive(int argc, char **argv)
4041 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4044 static int lfs_hsm_restore(int argc, char **argv)
4046 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4049 static int lfs_hsm_release(int argc, char **argv)
4051 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4054 static int lfs_hsm_remove(int argc, char **argv)
4056 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4059 static int lfs_hsm_cancel(int argc, char **argv)
4061 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4064 static int lfs_swap_layouts(int argc, char **argv)
4069 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4070 SWAP_LAYOUTS_KEEP_MTIME |
4071 SWAP_LAYOUTS_KEEP_ATIME);
4074 int main(int argc, char **argv)
4078 /* Ensure that liblustreapi constructor has run */
4079 if (!liblustreapi_initialized)
4080 fprintf(stderr, "liblustreapi was not properly initialized\n");
4084 Parser_init("lfs > ", cmdlist);
4086 progname = argv[0]; /* Used in error messages */
4088 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4090 rc = Parser_commands();
4093 return rc < 0 ? -rc : rc;
4096 #ifdef _LUSTRE_IDL_H_
4097 /* Everything we need here should be included by lustreapi.h. */
4098 # error "lfs should not depend on lustre_idl.h"
4099 #endif /* _LUSTRE_IDL_H_ */