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] <file> ..."},
343 {"hsm_cancel", lfs_hsm_cancel, 0,
344 "Cancel requests related to specified files.\n"
345 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
346 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
347 "usage: swap_layouts <path1> <path2>"},
348 {"migrate", lfs_setstripe, 0, "migrate file from one OST layout to "
349 "another.\n" MIGRATE_USAGE},
351 "To move directories between MDTs.\n"
352 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
354 {"help", Parser_help, 0, "help"},
355 {"exit", Parser_quit, 0, "quit"},
356 {"quit", Parser_quit, 0, "quit"},
357 {"--version", Parser_version, 0,
358 "output build version of the utility and exit"},
363 #define MIGRATION_BLOCKS 1
366 * Internal helper for migrate_copy_data(). Check lease and report error if
369 * \param[in] fd File descriptor on which to check the lease.
370 * \param[out] lease_broken Set to true if the lease was broken.
371 * \param[in] group_locked Whether a group lock was taken or not.
372 * \param[in] path Name of the file being processed, for error
375 * \retval 0 Migration can keep on going.
376 * \retval -errno Error occurred, abort migration.
378 static int check_lease(int fd, bool *lease_broken, bool group_locked,
383 if (!file_lease_supported)
386 rc = llapi_lease_check(fd);
388 return 0; /* llapi_check_lease returns > 0 on success. */
391 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
393 rc = rc ? rc : -EAGAIN;
395 fprintf(stderr, "%s: external attempt to access file '%s' "
396 "blocked until migration ends.\n", progname, path);
399 *lease_broken = true;
403 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
404 bool group_locked, const char *fname)
413 bool lease_broken = false;
415 /* Use a page-aligned buffer for direct I/O */
416 rc = posix_memalign(&buf, getpagesize(), buf_size);
421 /* read new data only if we have written all
422 * previously read data */
425 rc = check_lease(fd_src, &lease_broken,
426 group_locked, fname);
430 rsize = read(fd_src, buf, buf_size);
433 fprintf(stderr, "%s: %s: read failed: %s\n",
434 progname, fname, strerror(-rc));
444 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
448 "%s: %s: write failed on volatile: %s\n",
449 progname, fname, strerror(-rc));
459 fprintf(stderr, "%s: %s: fsync failed: %s\n",
460 progname, fname, strerror(-rc));
468 static int migrate_copy_timestamps(int fdv, const struct stat *st)
470 struct timeval tv[2] = {
471 {.tv_sec = st->st_atime},
472 {.tv_sec = st->st_mtime}
475 return futimes(fdv, tv);
478 static int migrate_block(int fd, int fdv, const struct stat *st,
479 size_t buf_size, const char *name)
486 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
488 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
489 progname, name, strerror(-rc));
497 /* The grouplock blocks all concurrent accesses to the file.
498 * It has to be taken after llapi_get_data_version as it would
500 rc = llapi_group_lock(fd, gid);
502 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
503 progname, name, strerror(-rc));
507 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
509 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
513 /* Make sure we keep original atime/mtime values */
514 rc = migrate_copy_timestamps(fdv, st);
516 fprintf(stderr, "%s: %s: timestamp copy failed\n",
522 * for a migration we need to check data version on file did
525 * Pass in gid=0 since we already own grouplock. */
526 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
527 SWAP_LAYOUTS_CHECK_DV1);
529 fprintf(stderr, "%s: %s: dataversion changed during copy, "
530 "migration aborted\n", progname, name);
533 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
534 name, strerror(-rc));
539 rc2 = llapi_group_unlock(fd, gid);
540 if (rc2 < 0 && rc == 0) {
541 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
542 progname, name, strerror(-rc2));
549 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
550 size_t buf_size, const char *name)
556 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
558 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
559 progname, name, strerror(-rc));
563 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
565 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
569 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
571 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
572 progname, name, strerror(-rc));
578 fprintf(stderr, "%s: %s: data version changed during "
584 /* Make sure we keep original atime/mtime values */
585 rc = migrate_copy_timestamps(fdv, st);
587 fprintf(stderr, "%s: %s: timestamp copy failed\n",
592 /* Atomically put lease, swap layouts and close.
593 * for a migration we need to check data version on file did
595 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
597 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
598 progname, name, strerror(-rc));
605 static int lfs_migrate(char *name, __u64 migration_flags,
606 struct llapi_stripe_param *param)
610 char volatile_file[PATH_MAX +
611 LUSTRE_VOLATILE_HDR_LEN + 4];
612 char parent[PATH_MAX];
615 struct lov_user_md *lum = NULL;
618 bool have_lease_rdlck = false;
622 /* find the right size for the IO and allocate the buffer */
623 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
624 lum = malloc(lum_size);
630 rc = llapi_file_get_stripe(name, lum);
631 /* failure can happen for many reasons and some may be not real errors
633 * in case of a real error, a later call will fail with better
634 * error management */
636 buf_size = 1024 * 1024;
638 buf_size = lum->lmm_stripe_size;
640 /* open file, direct io */
641 /* even if the file is only read, WR mode is nedeed to allow
642 * layout swap on fd */
643 fd = open(name, O_RDWR | O_DIRECT);
646 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
651 if (file_lease_supported) {
652 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
653 if (rc == -EOPNOTSUPP) {
654 /* Older servers do not support file lease.
655 * Disable related checks. This opens race conditions
656 * as explained in LU-4840 */
657 file_lease_supported = false;
659 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
660 progname, name, strerror(-rc));
663 have_lease_rdlck = true;
667 /* search for file directory pathname */
668 if (strlen(name) > sizeof(parent)-1) {
672 strncpy(parent, name, sizeof(parent));
673 ptr = strrchr(parent, '/');
675 if (getcwd(parent, sizeof(parent)) == NULL) {
686 rc = snprintf(volatile_file, sizeof(volatile_file), "%s/%s::", parent,
687 LUSTRE_VOLATILE_HDR);
688 if (rc >= sizeof(volatile_file)) {
693 /* create, open a volatile file, use caching (ie no directio) */
694 /* exclusive create is not needed because volatile files cannot
695 * conflict on name by construction */
696 fdv = llapi_file_open_param(volatile_file, O_CREAT | O_WRONLY, 0644,
700 fprintf(stderr, "%s: %s: cannot create volatile file in"
702 progname, parent, strerror(-rc));
706 /* Not-owner (root?) special case.
707 * Need to set owner/group of volatile file like original.
708 * This will allow to pass related check during layout_swap.
713 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
717 rc = fstat(fdv, &stv);
720 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
721 volatile_file, strerror(errno));
724 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
725 rc = fchown(fdv, st.st_uid, st.st_gid);
728 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
729 name, strerror(errno));
734 if (migration_flags & MIGRATION_BLOCKS || !file_lease_supported) {
735 /* Blocking mode, forced if servers do not support file lease */
736 rc = migrate_block(fd, fdv, &st, buf_size, name);
738 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
740 have_lease_rdlck = false;
741 fdv = -1; /* The volatile file is closed as we put the
742 * lease in non-blocking mode. */
747 if (have_lease_rdlck)
764 * Parse a string containing an OST index list into an array of integers.
766 * The input string contains a comma delimited list of individual
767 * indices and ranges, for example "1,2-4,7". Add the indices into the
768 * \a osts array and remove duplicates.
770 * \param[out] osts array to store indices in
771 * \param[in] size size of \a osts array
772 * \param[in] offset starting index in \a osts
773 * \param[in] arg string containing OST index list
775 * \retval positive number of indices in \a osts
776 * \retval -EINVAL unable to parse \a arg
778 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
782 int slots = size - offset;
790 while (!end_of_loop) {
798 ptr = strchrnul(arg, ',');
800 end_of_loop = *ptr == '\0';
803 start_index = strtol(arg, &endptr, 0);
804 if (endptr == arg) /* no data at all */
806 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
811 end_index = start_index;
812 if (*endptr == '-') {
813 end_index = strtol(endptr + 1, &endptr, 0);
816 if (end_index < start_index)
820 for (i = start_index; i <= end_index && slots > 0; i++) {
823 /* remove duplicate */
824 for (j = 0; j < offset; j++) {
828 if (j == offset) { /* no duplicate */
833 if (slots == 0 && i < end_index)
841 if (!end_of_loop && ptr != NULL)
844 return rc < 0 ? rc : nr;
848 static int lfs_setstripe(int argc, char **argv)
850 struct llapi_stripe_param *param;
854 unsigned long long st_size;
855 int st_offset, st_count;
859 char *stripe_size_arg = NULL;
860 char *stripe_off_arg = NULL;
861 char *stripe_count_arg = NULL;
862 char *pool_name_arg = NULL;
863 unsigned long long size_units = 1;
864 bool migrate_mode = false;
865 __u64 migration_flags = 0;
866 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
869 struct option long_opts[] = {
870 /* valid only in migrate mode */
871 {"block", no_argument, 0, 'b'},
872 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
873 /* This formerly implied "stripe-count", but was explicitly
874 * made "stripe-count" for consistency with other options,
875 * and to separate it from "mdt-count" when DNE arrives. */
876 {"count", required_argument, 0, 'c'},
878 {"stripe-count", required_argument, 0, 'c'},
879 {"stripe_count", required_argument, 0, 'c'},
880 {"delete", no_argument, 0, 'd'},
881 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
882 /* This formerly implied "stripe-index", but was explicitly
883 * made "stripe-index" for consistency with other options,
884 * and to separate it from "mdt-index" when DNE arrives. */
885 {"index", required_argument, 0, 'i'},
887 {"stripe-index", required_argument, 0, 'i'},
888 {"stripe_index", required_argument, 0, 'i'},
889 {"ost-list", required_argument, 0, 'o'},
890 {"ost_list", required_argument, 0, 'o'},
891 {"pool", required_argument, 0, 'p'},
892 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
893 /* This formerly implied "--stripe-size", but was confusing
894 * with "lfs find --size|-s", which means "file size", so use
895 * the consistent "--stripe-size|-S" for all commands. */
896 {"size", required_argument, 0, 's'},
898 {"stripe-size", required_argument, 0, 'S'},
899 {"stripe_size", required_argument, 0, 'S'},
907 if (strcmp(argv[0], "migrate") == 0)
910 while ((c = getopt_long(argc, argv, "bc:di:o:p:s:S:",
911 long_opts, NULL)) >= 0) {
918 fprintf(stderr, "--block is valid only for"
922 migration_flags |= MIGRATION_BLOCKS;
925 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
926 if (strcmp(argv[optind - 1], "--count") == 0)
927 fprintf(stderr, "warning: '--count' deprecated"
928 ", use '--stripe-count' instead\n");
930 stripe_count_arg = optarg;
933 /* delete the default striping pattern */
937 nr_osts = parse_targets(osts, ARRAY_SIZE(osts), nr_osts,
941 "error: %s: bad OST indices '%s'\n",
946 if (st_offset == -1) /* first in the command line */
950 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
951 if (strcmp(argv[optind - 1], "--index") == 0)
952 fprintf(stderr, "warning: '--index' deprecated"
953 ", use '--stripe-index' instead\n");
955 stripe_off_arg = optarg;
957 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
959 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
960 fprintf(stderr, "warning: '--size|-s' deprecated, "
961 "use '--stripe-size|-S' instead\n");
963 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
965 stripe_size_arg = optarg;
968 pool_name_arg = optarg;
975 fname = argv[optind];
978 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
979 stripe_count_arg != NULL || pool_name_arg != NULL)) {
980 fprintf(stderr, "error: %s: cannot specify -d with "
981 "-s, -c, -o, or -p options\n",
986 if (optind == argc) {
987 fprintf(stderr, "error: %s: missing filename|dirname\n",
992 if (pool_name_arg && strlen(pool_name_arg) > LOV_MAXPOOLNAME) {
994 "error: %s: pool name '%s' is too long (max is %d characters)\n",
995 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
999 /* get the stripe size */
1000 if (stripe_size_arg != NULL) {
1001 result = llapi_parse_size(stripe_size_arg, &st_size,
1004 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1005 argv[0], stripe_size_arg);
1009 /* get the stripe offset */
1010 if (stripe_off_arg != NULL) {
1011 st_offset = strtol(stripe_off_arg, &end, 0);
1013 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1014 argv[0], stripe_off_arg);
1018 /* get the stripe count */
1019 if (stripe_count_arg != NULL) {
1020 st_count = strtoul(stripe_count_arg, &end, 0);
1022 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1023 argv[0], stripe_count_arg);
1028 /* initialize stripe parameters */
1029 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1030 if (param == NULL) {
1031 fprintf(stderr, "error: %s: run out of memory\n", argv[0]);
1035 param->lsp_stripe_size = st_size;
1036 param->lsp_stripe_offset = st_offset;
1037 param->lsp_stripe_count = st_count;
1038 param->lsp_stripe_pattern = 0;
1039 param->lsp_pool = pool_name_arg;
1040 param->lsp_is_specific = false;
1042 if (st_count > 0 && nr_osts != st_count) {
1043 fprintf(stderr, "error: %s: stripe count '%d' doesn't "
1044 "match the number of OSTs: %d\n",
1045 argv[0], st_count, nr_osts);
1049 param->lsp_is_specific = true;
1050 param->lsp_stripe_count = nr_osts;
1051 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1054 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1056 result = lfs_migrate(fname, migration_flags, param);
1058 result = llapi_file_open_param(fname,
1067 /* Save the first error encountered. */
1071 "error: %s: %s stripe file '%s' failed\n",
1072 argv[0], migrate_mode ? "migrate" : "create",
1082 static int lfs_poollist(int argc, char **argv)
1087 return llapi_poollist(argv[1]);
1090 static int set_time(time_t *time, time_t *set, char *str)
1097 else if (str[0] == '-')
1103 t = strtol(str, NULL, 0);
1104 if (*time < t * 24 * 60 * 60) {
1107 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1111 *set = *time - t * 24 * 60 * 60;
1118 static int name2id(unsigned int *id, char *name, int type)
1121 struct passwd *entry;
1123 if (!(entry = getpwnam(name))) {
1129 *id = entry->pw_uid;
1131 struct group *entry;
1133 if (!(entry = getgrnam(name))) {
1139 *id = entry->gr_gid;
1145 static int id2name(char **name, unsigned int id, int type)
1148 struct passwd *entry;
1150 if (!(entry = getpwuid(id))) {
1156 *name = entry->pw_name;
1158 struct group *entry;
1160 if (!(entry = getgrgid(id))) {
1166 *name = entry->gr_name;
1172 static int name2layout(__u32 *layout, char *name)
1177 for (ptr = name; ; ptr = NULL) {
1178 lyt = strtok(ptr, ",");
1181 if (strcmp(lyt, "released") == 0)
1182 *layout |= LOV_PATTERN_F_RELEASED;
1183 else if (strcmp(lyt, "raid0") == 0)
1184 *layout |= LOV_PATTERN_RAID0;
1191 #define FIND_POOL_OPT 3
1192 static int lfs_find(int argc, char **argv)
1197 struct find_param param = {
1201 struct option long_opts[] = {
1202 {"atime", required_argument, 0, 'A'},
1203 {"stripe-count", required_argument, 0, 'c'},
1204 {"stripe_count", required_argument, 0, 'c'},
1205 {"ctime", required_argument, 0, 'C'},
1206 {"maxdepth", required_argument, 0, 'D'},
1207 {"gid", required_argument, 0, 'g'},
1208 {"group", required_argument, 0, 'G'},
1209 {"stripe-index", required_argument, 0, 'i'},
1210 {"stripe_index", required_argument, 0, 'i'},
1211 {"layout", required_argument, 0, 'L'},
1212 {"mdt", required_argument, 0, 'm'},
1213 {"mtime", required_argument, 0, 'M'},
1214 {"name", required_argument, 0, 'n'},
1215 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1216 {"obd", required_argument, 0, 'O'},
1217 {"ost", required_argument, 0, 'O'},
1218 /* no short option for pool, p/P already used */
1219 {"pool", required_argument, 0, FIND_POOL_OPT},
1220 {"print0", no_argument, 0, 'p'},
1221 {"print", no_argument, 0, 'P'},
1222 {"size", required_argument, 0, 's'},
1223 {"stripe-size", required_argument, 0, 'S'},
1224 {"stripe_size", required_argument, 0, 'S'},
1225 {"type", required_argument, 0, 't'},
1226 {"uid", required_argument, 0, 'u'},
1227 {"user", required_argument, 0, 'U'},
1240 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1241 while ((c = getopt_long_only(argc, argv,
1242 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1243 long_opts, NULL)) >= 0) {
1248 /* '!' is part of option */
1249 /* when getopt_long_only() finds a string which is not
1250 * an option nor a known option argument it returns 1
1251 * in that case if we already have found pathstart and pathend
1252 * (i.e. we have the list of pathnames),
1253 * the only supported value is "!"
1255 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1256 if (!isoption && pathend != -1) {
1257 fprintf(stderr, "err: %s: filename|dirname must either "
1258 "precede options or follow options\n",
1263 if (!isoption && pathstart == -1)
1264 pathstart = optind - 1;
1265 if (isoption && pathstart != -1 && pathend == -1)
1266 pathend = optind - 2;
1272 /* unknown; opt is "!" or path component,
1273 * checking done above.
1275 if (strcmp(optarg, "!") == 0)
1279 xtime = ¶m.fp_atime;
1280 xsign = ¶m.fp_asign;
1281 param.fp_exclude_atime = !!neg_opt;
1282 /* no break, this falls through to 'C' for ctime */
1285 xtime = ¶m.fp_ctime;
1286 xsign = ¶m.fp_csign;
1287 param.fp_exclude_ctime = !!neg_opt;
1289 /* no break, this falls through to 'M' for mtime */
1292 xtime = ¶m.fp_mtime;
1293 xsign = ¶m.fp_msign;
1294 param.fp_exclude_mtime = !!neg_opt;
1296 rc = set_time(&t, xtime, optarg);
1297 if (rc == INT_MAX) {
1305 if (optarg[0] == '+') {
1306 param.fp_stripe_count_sign = -1;
1308 } else if (optarg[0] == '-') {
1309 param.fp_stripe_count_sign = 1;
1313 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1314 if (*endptr != '\0') {
1315 fprintf(stderr,"error: bad stripe_count '%s'\n",
1320 param.fp_check_stripe_count = 1;
1321 param.fp_exclude_stripe_count = !!neg_opt;
1324 param.fp_max_depth = strtol(optarg, 0, 0);
1328 rc = name2id(¶m.fp_gid, optarg, GROUP);
1330 param.fp_gid = strtoul(optarg, &endptr, 10);
1331 if (*endptr != '\0') {
1332 fprintf(stderr, "Group/GID: %s cannot "
1333 "be found.\n", optarg);
1338 param.fp_exclude_gid = !!neg_opt;
1339 param.fp_check_gid = 1;
1342 ret = name2layout(¶m.fp_layout, optarg);
1345 param.fp_exclude_layout = !!neg_opt;
1346 param.fp_check_layout = 1;
1350 rc = name2id(¶m.fp_uid, optarg, USER);
1352 param.fp_uid = strtoul(optarg, &endptr, 10);
1353 if (*endptr != '\0') {
1354 fprintf(stderr, "User/UID: %s cannot "
1355 "be found.\n", optarg);
1360 param.fp_exclude_uid = !!neg_opt;
1361 param.fp_check_uid = 1;
1364 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1366 "Pool name %s is too long"
1367 " (max is %d)\n", optarg,
1372 /* we do check for empty pool because empty pool
1373 * is used to find V1 lov attributes */
1374 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1375 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1376 param.fp_exclude_pool = !!neg_opt;
1377 param.fp_check_pool = 1;
1380 param.fp_pattern = (char *)optarg;
1381 param.fp_exclude_pattern = !!neg_opt;
1386 char *buf, *token, *next, *p;
1390 buf = strdup(optarg);
1396 param.fp_exclude_obd = !!neg_opt;
1399 while (token && *token) {
1400 token = strchr(token, ',');
1407 param.fp_exclude_mdt = !!neg_opt;
1408 param.fp_num_alloc_mdts += len;
1409 tmp = realloc(param.fp_mdt_uuid,
1410 param.fp_num_alloc_mdts *
1411 sizeof(*param.fp_mdt_uuid));
1417 param.fp_mdt_uuid = tmp;
1419 param.fp_exclude_obd = !!neg_opt;
1420 param.fp_num_alloc_obds += len;
1421 tmp = realloc(param.fp_obd_uuid,
1422 param.fp_num_alloc_obds *
1423 sizeof(*param.fp_obd_uuid));
1429 param.fp_obd_uuid = tmp;
1431 for (token = buf; token && *token; token = next) {
1432 struct obd_uuid *puuid;
1435 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1438 ¶m.fp_obd_uuid[param.fp_num_obds++];
1440 p = strchr(token, ',');
1447 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1452 strncpy(puuid->uuid, token,
1453 sizeof(puuid->uuid));
1461 param.fp_zero_end = 1;
1466 if (optarg[0] == '+') {
1467 param.fp_size_sign = -1;
1469 } else if (optarg[0] == '-') {
1470 param.fp_size_sign = 1;
1474 ret = llapi_parse_size(optarg, ¶m.fp_size,
1475 ¶m.fp_size_units, 0);
1477 fprintf(stderr, "error: bad file size '%s'\n",
1481 param.fp_check_size = 1;
1482 param.fp_exclude_size = !!neg_opt;
1485 if (optarg[0] == '+') {
1486 param.fp_stripe_size_sign = -1;
1488 } else if (optarg[0] == '-') {
1489 param.fp_stripe_size_sign = 1;
1493 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1494 ¶m.fp_stripe_size_units, 0);
1496 fprintf(stderr, "error: bad stripe_size '%s'\n",
1500 param.fp_check_stripe_size = 1;
1501 param.fp_exclude_stripe_size = !!neg_opt;
1504 param.fp_exclude_type = !!neg_opt;
1505 switch (optarg[0]) {
1507 param.fp_type = S_IFBLK;
1510 param.fp_type = S_IFCHR;
1513 param.fp_type = S_IFDIR;
1516 param.fp_type = S_IFREG;
1519 param.fp_type = S_IFLNK;
1522 param.fp_type = S_IFIFO;
1525 param.fp_type = S_IFSOCK;
1528 fprintf(stderr, "error: %s: bad type '%s'\n",
1540 if (pathstart == -1) {
1541 fprintf(stderr, "error: %s: no filename|pathname\n",
1545 } else if (pathend == -1) {
1551 rc = llapi_find(argv[pathstart], ¶m);
1552 if (rc != 0 && ret == 0)
1554 } while (++pathstart < pathend);
1557 fprintf(stderr, "error: %s failed for %s.\n",
1558 argv[0], argv[optind - 1]);
1560 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1561 free(param.fp_obd_uuid);
1563 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1564 free(param.fp_mdt_uuid);
1569 static int lfs_getstripe_internal(int argc, char **argv,
1570 struct find_param *param)
1572 struct option long_opts[] = {
1573 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1574 /* This formerly implied "stripe-count", but was explicitly
1575 * made "stripe-count" for consistency with other options,
1576 * and to separate it from "mdt-count" when DNE arrives. */
1577 {"count", no_argument, 0, 'c'},
1579 {"stripe-count", no_argument, 0, 'c'},
1580 {"stripe_count", no_argument, 0, 'c'},
1581 {"directory", no_argument, 0, 'd'},
1582 {"default", no_argument, 0, 'D'},
1583 {"generation", no_argument, 0, 'g'},
1584 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1585 /* This formerly implied "stripe-index", but was explicitly
1586 * made "stripe-index" for consistency with other options,
1587 * and to separate it from "mdt-index" when DNE arrives. */
1588 {"index", no_argument, 0, 'i'},
1590 {"stripe-index", no_argument, 0, 'i'},
1591 {"stripe_index", no_argument, 0, 'i'},
1592 {"layout", no_argument, 0, 'L'},
1593 {"mdt-index", no_argument, 0, 'M'},
1594 {"mdt_index", no_argument, 0, 'M'},
1595 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1596 /* This formerly implied "stripe-index", but was confusing
1597 * with "file offset" (which will eventually be needed for
1598 * with different layouts by offset), so deprecate it. */
1599 {"offset", no_argument, 0, 'o'},
1601 {"obd", required_argument, 0, 'O'},
1602 {"ost", required_argument, 0, 'O'},
1603 {"pool", no_argument, 0, 'p'},
1604 {"quiet", no_argument, 0, 'q'},
1605 {"recursive", no_argument, 0, 'r'},
1606 {"raw", no_argument, 0, 'R'},
1607 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1608 /* This formerly implied "--stripe-size", but was confusing
1609 * with "lfs find --size|-s", which means "file size", so use
1610 * the consistent "--stripe-size|-S" for all commands. */
1611 {"size", no_argument, 0, 's'},
1613 {"stripe-size", no_argument, 0, 'S'},
1614 {"stripe_size", no_argument, 0, 'S'},
1615 {"verbose", no_argument, 0, 'v'},
1620 param->fp_max_depth = 1;
1621 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1622 long_opts, NULL)) != -1) {
1625 if (param->fp_obd_uuid) {
1627 "error: %s: only one obduuid allowed",
1631 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1637 param->fp_max_depth = 0;
1640 param->fp_get_default_lmv = 1;
1643 param->fp_recursive = 1;
1646 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1649 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1650 if (strcmp(argv[optind - 1], "--count") == 0)
1651 fprintf(stderr, "warning: '--count' deprecated,"
1652 " use '--stripe-count' instead\n");
1654 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1655 param->fp_verbose |= VERBOSE_COUNT;
1656 param->fp_max_depth = 0;
1659 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1661 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1662 fprintf(stderr, "warning: '--size|-s' deprecated, "
1663 "use '--stripe-size|-S' instead\n");
1665 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1667 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1668 param->fp_verbose |= VERBOSE_SIZE;
1669 param->fp_max_depth = 0;
1672 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1674 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1675 "use '--stripe-index|-i' instead\n");
1678 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1679 if (strcmp(argv[optind - 1], "--index") == 0)
1680 fprintf(stderr, "warning: '--index' deprecated"
1681 ", use '--stripe-index' instead\n");
1683 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1684 param->fp_verbose |= VERBOSE_OFFSET;
1685 param->fp_max_depth = 0;
1689 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1690 param->fp_verbose |= VERBOSE_POOL;
1691 param->fp_max_depth = 0;
1695 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1696 param->fp_verbose |= VERBOSE_GENERATION;
1697 param->fp_max_depth = 0;
1701 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1702 param->fp_verbose |= VERBOSE_LAYOUT;
1703 param->fp_max_depth = 0;
1707 if (!(param->fp_verbose & VERBOSE_DETAIL))
1708 param->fp_max_depth = 0;
1709 param->fp_verbose |= VERBOSE_MDTINDEX;
1722 if (param->fp_recursive)
1723 param->fp_max_depth = -1;
1725 if (!param->fp_verbose)
1726 param->fp_verbose = VERBOSE_ALL;
1727 if (param->fp_quiet)
1728 param->fp_verbose = VERBOSE_OBJID;
1731 rc = llapi_getstripe(argv[optind], param);
1732 } while (++optind < argc && !rc);
1735 fprintf(stderr, "error: %s failed for %s.\n",
1736 argv[0], argv[optind - 1]);
1740 static int lfs_tgts(int argc, char **argv)
1742 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1743 struct find_param param;
1744 int index = 0, rc=0;
1749 if (argc == 2 && !realpath(argv[1], path)) {
1751 fprintf(stderr, "error: invalid path '%s': %s\n",
1752 argv[1], strerror(-rc));
1756 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1757 /* Check if we have a mount point */
1758 if (mntdir[0] == '\0')
1761 memset(¶m, 0, sizeof(param));
1762 if (!strcmp(argv[0], "mdts"))
1763 param.fp_get_lmv = 1;
1765 rc = llapi_ostlist(mntdir, ¶m);
1767 fprintf(stderr, "error: %s: failed on %s\n",
1770 if (path[0] != '\0')
1772 memset(mntdir, 0, PATH_MAX);
1778 static int lfs_getstripe(int argc, char **argv)
1780 struct find_param param = { 0 };
1781 return lfs_getstripe_internal(argc, argv, ¶m);
1785 static int lfs_getdirstripe(int argc, char **argv)
1787 struct find_param param = { 0 };
1789 param.fp_get_lmv = 1;
1790 return lfs_getstripe_internal(argc, argv, ¶m);
1794 static int lfs_setdirstripe(int argc, char **argv)
1798 unsigned int stripe_offset = -1;
1799 unsigned int stripe_count = 1;
1800 enum lmv_hash_type hash_type;
1803 char *stripe_offset_opt = NULL;
1804 char *stripe_count_opt = NULL;
1805 char *stripe_hash_opt = NULL;
1806 char *mode_opt = NULL;
1807 bool default_stripe = false;
1808 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1809 mode_t previous_mode = 0;
1810 bool delete = false;
1812 struct option long_opts[] = {
1813 {"count", required_argument, 0, 'c'},
1814 {"delete", no_argument, 0, 'd'},
1815 {"index", required_argument, 0, 'i'},
1816 {"mode", required_argument, 0, 'm'},
1817 {"hash-type", required_argument, 0, 't'},
1818 {"default_stripe", no_argument, 0, 'D'},
1822 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1829 stripe_count_opt = optarg;
1833 default_stripe = true;
1836 default_stripe = true;
1839 stripe_offset_opt = optarg;
1845 stripe_hash_opt = optarg;
1848 fprintf(stderr, "error: %s: option '%s' "
1850 argv[0], argv[optind - 1]);
1855 if (optind == argc) {
1856 fprintf(stderr, "error: %s: missing dirname\n",
1861 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1862 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1867 if (stripe_offset_opt != NULL) {
1868 /* get the stripe offset */
1869 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1871 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1872 argv[0], stripe_offset_opt);
1878 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1879 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1880 " or -i options.\n", argv[0]);
1888 if (mode_opt != NULL) {
1889 mode = strtoul(mode_opt, &end, 8);
1891 fprintf(stderr, "error: %s: bad mode '%s'\n",
1895 previous_mode = umask(0);
1898 if (stripe_hash_opt == NULL ||
1899 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1900 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1901 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1902 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1904 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1905 argv[0], stripe_hash_opt);
1909 /* get the stripe count */
1910 if (stripe_count_opt != NULL) {
1911 stripe_count = strtoul(stripe_count_opt, &end, 0);
1913 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1914 argv[0], stripe_count_opt);
1919 dname = argv[optind];
1921 if (default_stripe) {
1922 result = llapi_dir_set_default_lmv_stripe(dname,
1923 stripe_offset, stripe_count,
1926 result = llapi_dir_create_pool(dname, mode,
1928 stripe_count, hash_type,
1933 fprintf(stderr, "error: %s: create stripe dir '%s' "
1934 "failed\n", argv[0], dname);
1937 dname = argv[++optind];
1938 } while (dname != NULL);
1940 if (mode_opt != NULL)
1941 umask(previous_mode);
1947 static int lfs_rmentry(int argc, char **argv)
1954 fprintf(stderr, "error: %s: missing dirname\n",
1960 dname = argv[index];
1961 while (dname != NULL) {
1962 result = llapi_direntry_remove(dname);
1964 fprintf(stderr, "error: %s: remove dir entry '%s' "
1965 "failed\n", argv[0], dname);
1968 dname = argv[++index];
1973 static int lfs_mv(int argc, char **argv)
1975 struct find_param param = {
1982 struct option long_opts[] = {
1983 {"mdt-index", required_argument, 0, 'M'},
1984 {"verbose", no_argument, 0, 'v'},
1988 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
1991 param.fp_mdt_index = strtoul(optarg, &end, 0);
1993 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2000 param.fp_verbose = VERBOSE_DETAIL;
2004 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2005 argv[0], argv[optind - 1]);
2010 if (param.fp_mdt_index == -1) {
2011 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2015 if (optind >= argc) {
2016 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2020 param.fp_migrate = 1;
2021 rc = llapi_mv(argv[optind], ¶m);
2023 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2024 argv[0], argv[optind], param.fp_mdt_index,
2029 static int lfs_osts(int argc, char **argv)
2031 return lfs_tgts(argc, argv);
2034 static int lfs_mdts(int argc, char **argv)
2036 return lfs_tgts(argc, argv);
2039 #define COOK(value) \
2042 while (value > 1024) { \
2050 #define CDF "%11llu"
2051 #define HDF "%8.1f%c"
2055 static int showdf(char *mntdir, struct obd_statfs *stat,
2056 char *uuid, int ishow, int cooked,
2057 char *type, int index, int rc)
2059 long long avail, used, total;
2061 char *suffix = "KMGTPEZY";
2062 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2063 char tbuf[3 * sizeof(__u64)];
2064 char ubuf[3 * sizeof(__u64)];
2065 char abuf[3 * sizeof(__u64)];
2066 char rbuf[3 * sizeof(__u64)];
2074 avail = stat->os_ffree;
2075 used = stat->os_files - stat->os_ffree;
2076 total = stat->os_files;
2078 int shift = cooked ? 0 : 10;
2080 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2081 used = ((stat->os_blocks - stat->os_bfree) *
2082 stat->os_bsize) >> shift;
2083 total = (stat->os_blocks * stat->os_bsize) >> shift;
2086 if ((used + avail) > 0)
2087 ratio = (double)used / (double)(used + avail);
2093 cook_val = (double)total;
2096 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2098 sprintf(tbuf, CDF, total);
2100 cook_val = (double)used;
2103 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2105 sprintf(ubuf, CDF, used);
2107 cook_val = (double)avail;
2110 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2112 sprintf(abuf, CDF, avail);
2114 sprintf(tbuf, CDF, total);
2115 sprintf(ubuf, CDF, used);
2116 sprintf(abuf, CDF, avail);
2119 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2120 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2121 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2123 printf("[%s:%d]\n", type, index);
2129 printf(UUF": inactive device\n", uuid);
2132 printf(UUF": %s\n", uuid, strerror(-rc));
2139 struct ll_stat_type {
2144 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2145 int cooked, int lazy)
2147 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2148 struct obd_uuid uuid_buf;
2149 char *poolname = NULL;
2150 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2151 { LL_STATFS_LOV, "OST" },
2153 struct ll_stat_type *tp;
2154 __u64 ost_ffree = 0;
2160 poolname = strchr(pool, '.');
2161 if (poolname != NULL) {
2162 if (strncmp(fsname, pool, strlen(fsname))) {
2163 fprintf(stderr, "filesystem name incorrect\n");
2172 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2173 "UUID", "Inodes", "IUsed", "IFree",
2174 "IUse%", "Mounted on");
2176 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2177 "UUID", cooked ? "bytes" : "1K-blocks",
2178 "Used", "Available", "Use%", "Mounted on");
2180 for (tp = types; tp->st_name != NULL; tp++) {
2181 for (index = 0; ; index++) {
2182 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2183 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2184 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2185 rc = llapi_obd_statfs(mntdir, type, index,
2186 &stat_buf, &uuid_buf);
2193 if (poolname && tp->st_op == LL_STATFS_LOV &&
2194 llapi_search_ost(fsname, poolname,
2195 obd_uuid2str(&uuid_buf)) != 1)
2198 /* the llapi_obd_statfs() call may have returned with
2199 * an error, but if it filled in uuid_buf we will at
2200 * lease use that to print out a message for that OBD.
2201 * If we didn't get anything in the uuid_buf, then fill
2202 * it in so that we can print an error message. */
2203 if (uuid_buf.uuid[0] == '\0')
2204 sprintf(uuid_buf.uuid, "%s%04x",
2205 tp->st_name, index);
2206 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2207 ishow, cooked, tp->st_name, index, rc);
2210 if (tp->st_op == LL_STATFS_LMV) {
2211 sum.os_ffree += stat_buf.os_ffree;
2212 sum.os_files += stat_buf.os_files;
2213 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2214 sum.os_blocks += stat_buf.os_blocks *
2216 sum.os_bfree += stat_buf.os_bfree *
2218 sum.os_bavail += stat_buf.os_bavail *
2220 ost_ffree += stat_buf.os_ffree;
2222 } else if (rc == -EINVAL || rc == -EFAULT) {
2228 /* If we don't have as many objects free on the OST as inodes
2229 * on the MDS, we reduce the total number of inodes to
2230 * compensate, so that the "inodes in use" number is correct.
2231 * Matches ll_statfs_internal() so the results are consistent. */
2232 if (ost_ffree < sum.os_ffree) {
2233 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2234 sum.os_ffree = ost_ffree;
2237 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2242 static int lfs_df(int argc, char **argv)
2244 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2245 int ishow = 0, cooked = 0;
2247 int c, rc = 0, index = 0;
2248 char fsname[PATH_MAX] = "", *pool_name = NULL;
2249 struct option long_opts[] = {
2250 {"pool", required_argument, 0, 'p'},
2251 {"lazy", 0, 0, 'l'},
2255 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2273 if (optind < argc && !realpath(argv[optind], path)) {
2275 fprintf(stderr, "error: invalid path '%s': %s\n",
2276 argv[optind], strerror(-rc));
2280 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2281 /* Check if we have a mount point */
2282 if (mntdir[0] == '\0')
2285 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2286 if (rc || path[0] != '\0')
2288 fsname[0] = '\0'; /* avoid matching in next loop */
2289 mntdir[0] = '\0'; /* avoid matching in next loop */
2295 static int lfs_getname(int argc, char **argv)
2297 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2298 int rc = 0, index = 0, c;
2299 char buf[sizeof(struct obd_uuid)];
2301 while ((c = getopt(argc, argv, "h")) != -1)
2304 if (optind == argc) { /* no paths specified, get all paths. */
2305 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2306 rc = llapi_getname(mntdir, buf, sizeof(buf));
2309 "cannot get name for `%s': %s\n",
2310 mntdir, strerror(-rc));
2314 printf("%s %s\n", buf, mntdir);
2316 path[0] = fsname[0] = mntdir[0] = 0;
2318 } else { /* paths specified, only attempt to search these. */
2319 for (; optind < argc; optind++) {
2320 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2323 "cannot get name for `%s': %s\n",
2324 argv[optind], strerror(-rc));
2328 printf("%s %s\n", buf, argv[optind]);
2334 static int lfs_check(int argc, char **argv)
2337 char mntdir[PATH_MAX] = {'\0'};
2346 obd_types[0] = obd_type1;
2347 obd_types[1] = obd_type2;
2349 if (strcmp(argv[1], "osts") == 0) {
2350 strcpy(obd_types[0], "osc");
2351 } else if (strcmp(argv[1], "mds") == 0) {
2352 strcpy(obd_types[0], "mdc");
2353 } else if (strcmp(argv[1], "servers") == 0) {
2355 strcpy(obd_types[0], "osc");
2356 strcpy(obd_types[1], "mdc");
2358 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2363 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2364 if (rc < 0 || mntdir[0] == '\0') {
2365 fprintf(stderr, "No suitable Lustre mount found\n");
2369 rc = llapi_target_check(num_types, obd_types, mntdir);
2371 fprintf(stderr, "error: %s: %s status failed\n",
2378 static int lfs_join(int argc, char **argv)
2380 fprintf(stderr, "join two lustre files into one.\n"
2381 "obsolete, HEAD does not support it anymore.\n");
2385 #ifdef HAVE_SYS_QUOTA_H
2386 #define ARG2INT(nr, str, msg) \
2389 nr = strtol(str, &endp, 0); \
2391 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2396 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2398 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2399 * returns the value or ULONG_MAX on integer overflow or incorrect format
2401 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2402 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2403 * 3. empty integer value is interpreted as 0
2405 static unsigned long str2sec(const char* timestr)
2407 const char spec[] = "smhdw";
2408 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2409 unsigned long val = 0;
2412 if (strpbrk(timestr, spec) == NULL) {
2413 /* no specifiers inside the time string,
2414 should treat it as an integer value */
2415 val = strtoul(timestr, &tail, 10);
2416 return *tail ? ULONG_MAX : val;
2419 /* format string is XXwXXdXXhXXmXXs */
2425 v = strtoul(timestr, &tail, 10);
2426 if (v == ULONG_MAX || *tail == '\0')
2427 /* value too large (ULONG_MAX or more)
2428 or missing specifier */
2431 ptr = strchr(spec, *tail);
2433 /* unknown specifier */
2438 /* check if product will overflow the type */
2439 if (!(v < ULONG_MAX / mult[ind]))
2442 ADD_OVERFLOW(val, mult[ind] * v);
2443 if (val == ULONG_MAX)
2455 #define ARG2ULL(nr, str, def_units) \
2457 unsigned long long limit, units = def_units; \
2460 rc = llapi_parse_size(str, &limit, &units, 1); \
2462 fprintf(stderr, "error: bad limit value %s\n", str); \
2468 static inline int has_times_option(int argc, char **argv)
2472 for (i = 1; i < argc; i++)
2473 if (!strcmp(argv[i], "-t"))
2479 int lfs_setquota_times(int argc, char **argv)
2482 struct if_quotactl qctl;
2483 char *mnt, *obd_type = (char *)qctl.obd_type;
2484 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2485 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2486 struct option long_opts[] = {
2487 {"block-grace", required_argument, 0, 'b'},
2488 {"group", no_argument, 0, 'g'},
2489 {"inode-grace", required_argument, 0, 'i'},
2490 {"times", no_argument, 0, 't'},
2491 {"user", no_argument, 0, 'u'},
2495 memset(&qctl, 0, sizeof(qctl));
2496 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2497 qctl.qc_type = UGQUOTA;
2499 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2503 if (qctl.qc_type != UGQUOTA) {
2504 fprintf(stderr, "error: -u and -g can't be used "
2505 "more than once\n");
2508 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2511 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2512 fprintf(stderr, "error: bad block-grace: %s\n",
2516 dqb->dqb_valid |= QIF_BTIME;
2519 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2520 fprintf(stderr, "error: bad inode-grace: %s\n",
2524 dqb->dqb_valid |= QIF_ITIME;
2526 case 't': /* Yes, of course! */
2528 default: /* getopt prints error message for us when opterr != 0 */
2533 if (qctl.qc_type == UGQUOTA) {
2534 fprintf(stderr, "error: neither -u nor -g specified\n");
2538 if (optind != argc - 1) {
2539 fprintf(stderr, "error: unexpected parameters encountered\n");
2544 rc = llapi_quotactl(mnt, &qctl);
2547 fprintf(stderr, "%s %s ", obd_type,
2548 obd_uuid2str(&qctl.obd_uuid));
2549 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2556 #define BSLIMIT (1 << 0)
2557 #define BHLIMIT (1 << 1)
2558 #define ISLIMIT (1 << 2)
2559 #define IHLIMIT (1 << 3)
2561 int lfs_setquota(int argc, char **argv)
2564 struct if_quotactl qctl;
2565 char *mnt, *obd_type = (char *)qctl.obd_type;
2566 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2567 struct option long_opts[] = {
2568 {"block-softlimit", required_argument, 0, 'b'},
2569 {"block-hardlimit", required_argument, 0, 'B'},
2570 {"group", required_argument, 0, 'g'},
2571 {"inode-softlimit", required_argument, 0, 'i'},
2572 {"inode-hardlimit", required_argument, 0, 'I'},
2573 {"user", required_argument, 0, 'u'},
2576 unsigned limit_mask = 0;
2579 if (has_times_option(argc, argv))
2580 return lfs_setquota_times(argc, argv);
2582 memset(&qctl, 0, sizeof(qctl));
2583 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2584 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2585 * so it can be used as a marker that qc_type
2586 * isn't reinitialized from command line */
2588 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2592 if (qctl.qc_type != UGQUOTA) {
2593 fprintf(stderr, "error: -u and -g can't be used"
2594 " more than once\n");
2597 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2598 rc = name2id(&qctl.qc_id, optarg,
2599 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2601 qctl.qc_id = strtoul(optarg, &endptr, 10);
2602 if (*endptr != '\0') {
2603 fprintf(stderr, "error: can't find id "
2604 "for name %s\n", optarg);
2610 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2611 dqb->dqb_bsoftlimit >>= 10;
2612 limit_mask |= BSLIMIT;
2613 if (dqb->dqb_bsoftlimit &&
2614 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2615 fprintf(stderr, "warning: block softlimit is "
2616 "smaller than the miminal qunit size, "
2617 "please see the help of setquota or "
2618 "Lustre manual for details.\n");
2621 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2622 dqb->dqb_bhardlimit >>= 10;
2623 limit_mask |= BHLIMIT;
2624 if (dqb->dqb_bhardlimit &&
2625 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2626 fprintf(stderr, "warning: block hardlimit is "
2627 "smaller than the miminal qunit size, "
2628 "please see the help of setquota or "
2629 "Lustre manual for details.\n");
2632 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2633 limit_mask |= ISLIMIT;
2634 if (dqb->dqb_isoftlimit &&
2635 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2636 fprintf(stderr, "warning: inode softlimit is "
2637 "smaller than the miminal qunit size, "
2638 "please see the help of setquota or "
2639 "Lustre manual for details.\n");
2642 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2643 limit_mask |= IHLIMIT;
2644 if (dqb->dqb_ihardlimit &&
2645 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2646 fprintf(stderr, "warning: inode hardlimit is "
2647 "smaller than the miminal qunit size, "
2648 "please see the help of setquota or "
2649 "Lustre manual for details.\n");
2651 default: /* getopt prints error message for us when opterr != 0 */
2656 if (qctl.qc_type == UGQUOTA) {
2657 fprintf(stderr, "error: neither -u nor -g was specified\n");
2661 if (limit_mask == 0) {
2662 fprintf(stderr, "error: at least one limit must be specified\n");
2666 if (optind != argc - 1) {
2667 fprintf(stderr, "error: unexpected parameters encountered\n");
2673 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2674 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2675 /* sigh, we can't just set blimits/ilimits */
2676 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2677 .qc_type = qctl.qc_type,
2678 .qc_id = qctl.qc_id};
2680 rc = llapi_quotactl(mnt, &tmp_qctl);
2682 fprintf(stderr, "error: setquota failed while retrieving"
2683 " current quota settings (%s)\n",
2688 if (!(limit_mask & BHLIMIT))
2689 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2690 if (!(limit_mask & BSLIMIT))
2691 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2692 if (!(limit_mask & IHLIMIT))
2693 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2694 if (!(limit_mask & ISLIMIT))
2695 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2697 /* Keep grace times if we have got no softlimit arguments */
2698 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2699 dqb->dqb_valid |= QIF_BTIME;
2700 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2703 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2704 dqb->dqb_valid |= QIF_ITIME;
2705 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2709 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2710 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2712 rc = llapi_quotactl(mnt, &qctl);
2715 fprintf(stderr, "%s %s ", obd_type,
2716 obd_uuid2str(&qctl.obd_uuid));
2717 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2724 static inline char *type2name(int check_type)
2726 if (check_type == USRQUOTA)
2728 else if (check_type == GRPQUOTA)
2734 /* Converts seconds value into format string
2735 * result is returned in buf
2737 * 1. result is in descenting order: 1w2d3h4m5s
2738 * 2. zero fields are not filled (except for p. 3): 5d1s
2739 * 3. zero seconds value is presented as "0s"
2741 static char * __sec2str(time_t seconds, char *buf)
2743 const char spec[] = "smhdw";
2744 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2749 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2750 c = seconds / mult[i];
2752 if (c > 0 || (i == 0 && buf == tail))
2753 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2761 static void sec2str(time_t seconds, char *buf, int rc)
2768 tail = __sec2str(seconds, tail);
2770 if (rc && tail - buf < 39) {
2776 static void diff2str(time_t seconds, char *buf, time_t now)
2782 if (seconds <= now) {
2783 strcpy(buf, "none");
2786 __sec2str(seconds - now, buf);
2789 static void print_quota_title(char *name, struct if_quotactl *qctl,
2790 bool human_readable)
2792 printf("Disk quotas for %s %s (%cid %u):\n",
2793 type2name(qctl->qc_type), name,
2794 *type2name(qctl->qc_type), qctl->qc_id);
2795 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2796 "Filesystem", human_readable ? "used" : "kbytes",
2797 "quota", "limit", "grace",
2798 "files", "quota", "limit", "grace");
2801 static void kbytes2str(__u64 num, char *buf, bool h)
2804 sprintf(buf, LPU64, num);
2807 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2809 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2811 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2813 sprintf(buf, LPU64"%s", num, "k");
2817 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2824 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2825 int bover = 0, iover = 0;
2826 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2831 if (dqb->dqb_bhardlimit &&
2832 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2834 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2835 if (dqb->dqb_btime > now) {
2842 if (dqb->dqb_ihardlimit &&
2843 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2845 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2846 if (dqb->dqb_itime > now) {
2854 if (strlen(mnt) > 15)
2855 printf("%s\n%15s", mnt, "");
2857 printf("%15s", mnt);
2860 diff2str(dqb->dqb_btime, timebuf, now);
2862 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2863 if (rc == -EREMOTEIO)
2864 sprintf(numbuf[0], "%s*", strbuf);
2866 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2867 "%s" : "[%s]", strbuf);
2869 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2870 if (type == QC_GENERAL)
2871 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2872 "%s" : "[%s]", strbuf);
2874 sprintf(numbuf[1], "%s", "-");
2876 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2877 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2878 "%s" : "[%s]", strbuf);
2880 printf(" %7s%c %6s %7s %7s",
2881 numbuf[0], bover ? '*' : ' ', numbuf[1],
2882 numbuf[2], bover > 1 ? timebuf : "-");
2885 diff2str(dqb->dqb_itime, timebuf, now);
2887 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2888 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2890 if (type == QC_GENERAL)
2891 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2892 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2894 sprintf(numbuf[1], "%s", "-");
2896 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2897 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2899 if (type != QC_OSTIDX)
2900 printf(" %7s%c %6s %7s %7s",
2901 numbuf[0], iover ? '*' : ' ', numbuf[1],
2902 numbuf[2], iover > 1 ? timebuf : "-");
2904 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2907 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2908 qctl->qc_cmd == Q_GETOINFO) {
2912 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2913 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2914 printf("Block grace time: %s; Inode grace time: %s\n",
2915 bgtimebuf, igtimebuf);
2919 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2920 bool h, __u64 *total)
2922 int rc = 0, rc1 = 0, count = 0;
2923 __u32 valid = qctl->qc_valid;
2925 rc = llapi_get_obd_count(mnt, &count, is_mdt);
2927 fprintf(stderr, "can not get %s count: %s\n",
2928 is_mdt ? "mdt": "ost", strerror(-rc));
2932 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2933 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2934 rc = llapi_quotactl(mnt, qctl);
2936 /* It is remote client case. */
2937 if (-rc == EOPNOTSUPP) {
2944 fprintf(stderr, "quotactl %s%d failed.\n",
2945 is_mdt ? "mdt": "ost", qctl->qc_idx);
2949 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
2950 qctl->qc_valid, 0, h);
2951 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
2952 qctl->qc_dqblk.dqb_bhardlimit;
2955 qctl->qc_valid = valid;
2959 static int lfs_quota(int argc, char **argv)
2962 char *mnt, *name = NULL;
2963 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2964 .qc_type = UGQUOTA };
2965 char *obd_type = (char *)qctl.obd_type;
2966 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2967 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2968 verbose = 0, pass = 0, quiet = 0, inacc;
2970 __u32 valid = QC_GENERAL, idx = 0;
2971 __u64 total_ialloc = 0, total_balloc = 0;
2972 bool human_readable = false;
2974 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
2977 if (qctl.qc_type != UGQUOTA) {
2978 fprintf(stderr, "error: use either -u or -g\n");
2981 qctl.qc_type = USRQUOTA;
2984 if (qctl.qc_type != UGQUOTA) {
2985 fprintf(stderr, "error: use either -u or -g\n");
2988 qctl.qc_type = GRPQUOTA;
2991 qctl.qc_cmd = LUSTRE_Q_GETINFO;
2994 valid = qctl.qc_valid = QC_UUID;
2995 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
2998 valid = qctl.qc_valid = QC_MDTIDX;
2999 idx = qctl.qc_idx = atoi(optarg);
3002 valid = qctl.qc_valid = QC_OSTIDX;
3003 idx = qctl.qc_idx = atoi(optarg);
3012 human_readable = true;
3015 fprintf(stderr, "error: %s: option '-%c' "
3016 "unrecognized\n", argv[0], c);
3021 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3022 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3023 optind == argc - 1) {
3025 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3026 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3027 qctl.qc_valid = valid;
3030 qctl.qc_type = USRQUOTA;
3031 qctl.qc_id = geteuid();
3033 qctl.qc_type = GRPQUOTA;
3034 qctl.qc_id = getegid();
3036 rc = id2name(&name, qctl.qc_id,
3037 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3040 /* lfs quota -u username /path/to/lustre/mount */
3041 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3042 /* options should be followed by u/g-name and mntpoint */
3043 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3044 fprintf(stderr, "error: missing quota argument(s)\n");
3048 name = argv[optind++];
3049 rc = name2id(&qctl.qc_id, name,
3050 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3052 qctl.qc_id = strtoul(name, &endptr, 10);
3053 if (*endptr != '\0') {
3054 fprintf(stderr, "error: can't find id for name "
3059 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3060 fprintf(stderr, "error: missing quota info argument(s)\n");
3066 rc1 = llapi_quotactl(mnt, &qctl);
3070 fprintf(stderr, "%s quotas are not enabled.\n",
3071 qctl.qc_type == USRQUOTA ? "user" : "group");
3074 fprintf(stderr, "Permission denied.\n");
3076 /* We already got a "No such file..." message. */
3079 fprintf(stderr, "Unexpected quotactl error: %s\n",
3084 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3085 print_quota_title(name, &qctl, human_readable);
3087 if (rc1 && *obd_type)
3088 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3090 if (qctl.qc_valid != QC_GENERAL)
3093 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3094 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3095 (QIF_LIMITS|QIF_USAGE));
3097 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3099 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3103 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3105 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3107 kbytes2str(total_balloc, strbuf, human_readable);
3108 printf("Total allocated inode limit: "LPU64", total "
3109 "allocated block limit: %s\n", total_ialloc, strbuf);
3112 if (rc1 || rc2 || rc3 || inacc)
3113 printf("Some errors happened when getting quota info. "
3114 "Some devices may be not working or deactivated. "
3115 "The data in \"[]\" is inaccurate.\n");
3123 #endif /* HAVE_SYS_QUOTA_H! */
3125 static int flushctx_ioctl(char *mp)
3129 fd = open(mp, O_RDONLY);
3131 fprintf(stderr, "flushctx: error open %s: %s\n",
3132 mp, strerror(errno));
3136 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3138 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3139 mp, strerror(errno));
3145 static int lfs_flushctx(int argc, char **argv)
3147 int kdestroy = 0, c;
3148 char mntdir[PATH_MAX] = {'\0'};
3152 while ((c = getopt(argc, argv, "k")) != -1) {
3158 fprintf(stderr, "error: %s: option '-%c' "
3159 "unrecognized\n", argv[0], c);
3165 if ((rc = system("kdestroy > /dev/null")) != 0) {
3166 rc = WEXITSTATUS(rc);
3167 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3171 if (optind >= argc) {
3172 /* flush for all mounted lustre fs. */
3173 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3174 /* Check if we have a mount point */
3175 if (mntdir[0] == '\0')
3178 if (flushctx_ioctl(mntdir))
3181 mntdir[0] = '\0'; /* avoid matching in next loop */
3184 /* flush fs as specified */
3185 while (optind < argc) {
3186 if (flushctx_ioctl(argv[optind++]))
3193 static int lfs_lsetfacl(int argc, char **argv)
3196 return(llapi_lsetfacl(argc, argv));
3199 static int lfs_lgetfacl(int argc, char **argv)
3202 return(llapi_lgetfacl(argc, argv));
3205 static int lfs_rsetfacl(int argc, char **argv)
3208 return(llapi_rsetfacl(argc, argv));
3211 static int lfs_rgetfacl(int argc, char **argv)
3214 return(llapi_rgetfacl(argc, argv));
3217 static int lfs_cp(int argc, char **argv)
3219 return(llapi_cp(argc, argv));
3222 static int lfs_ls(int argc, char **argv)
3224 return(llapi_ls(argc, argv));
3227 static int lfs_changelog(int argc, char **argv)
3229 void *changelog_priv;
3230 struct changelog_rec *rec;
3231 long long startrec = 0, endrec = 0;
3233 struct option long_opts[] = {
3234 {"follow", no_argument, 0, 'f'},
3237 char short_opts[] = "f";
3240 while ((rc = getopt_long(argc, argv, short_opts,
3241 long_opts, NULL)) != -1) {
3249 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3250 argv[0], argv[optind - 1]);
3257 mdd = argv[optind++];
3259 startrec = strtoll(argv[optind++], NULL, 10);
3261 endrec = strtoll(argv[optind++], NULL, 10);
3263 rc = llapi_changelog_start(&changelog_priv,
3264 CHANGELOG_FLAG_BLOCK |
3265 CHANGELOG_FLAG_JOBID |
3266 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3269 fprintf(stderr, "Can't start changelog: %s\n",
3270 strerror(errno = -rc));
3274 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3278 if (endrec && rec->cr_index > endrec) {
3279 llapi_changelog_free(&rec);
3282 if (rec->cr_index < startrec) {
3283 llapi_changelog_free(&rec);
3287 secs = rec->cr_time >> 30;
3288 gmtime_r(&secs, &ts);
3289 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3290 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3291 changelog_type2str(rec->cr_type),
3292 ts.tm_hour, ts.tm_min, ts.tm_sec,
3293 (int)(rec->cr_time & ((1<<30) - 1)),
3294 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3295 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3297 if (rec->cr_flags & CLF_JOBID) {
3298 struct changelog_ext_jobid *jid =
3299 changelog_rec_jobid(rec);
3301 if (jid->cr_jobid[0] != '\0')
3302 printf(" j=%s", jid->cr_jobid);
3305 if (rec->cr_namelen)
3306 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3307 rec->cr_namelen, changelog_rec_name(rec));
3309 if (rec->cr_flags & CLF_RENAME) {
3310 struct changelog_ext_rename *rnm =
3311 changelog_rec_rename(rec);
3313 if (!fid_is_zero(&rnm->cr_sfid))
3314 printf(" s="DFID" sp="DFID" %.*s",
3315 PFID(&rnm->cr_sfid),
3316 PFID(&rnm->cr_spfid),
3317 (int)changelog_rec_snamelen(rec),
3318 changelog_rec_sname(rec));
3322 llapi_changelog_free(&rec);
3325 llapi_changelog_fini(&changelog_priv);
3328 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3330 return (rc == 1 ? 0 : rc);
3333 static int lfs_changelog_clear(int argc, char **argv)
3341 endrec = strtoll(argv[3], NULL, 10);
3343 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3345 fprintf(stderr, "%s error: %s\n", argv[0],
3346 strerror(errno = -rc));
3350 static int lfs_fid2path(int argc, char **argv)
3352 struct option long_opts[] = {
3353 {"cur", no_argument, 0, 'c'},
3354 {"link", required_argument, 0, 'l'},
3355 {"rec", required_argument, 0, 'r'},
3358 char short_opts[] = "cl:r:";
3359 char *device, *fid, *path;
3360 long long recno = -1;
3366 while ((rc = getopt_long(argc, argv, short_opts,
3367 long_opts, NULL)) != -1) {
3373 linkno = strtol(optarg, NULL, 10);
3376 recno = strtoll(optarg, NULL, 10);
3381 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3382 argv[0], argv[optind - 1]);
3390 device = argv[optind++];
3391 path = calloc(1, PATH_MAX);
3393 fprintf(stderr, "error: Not enough memory\n");
3398 while (optind < argc) {
3399 fid = argv[optind++];
3401 lnktmp = (linkno >= 0) ? linkno : 0;
3403 int oldtmp = lnktmp;
3404 long long rectmp = recno;
3406 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3409 fprintf(stderr, "%s: error on FID %s: %s\n",
3410 argv[0], fid, strerror(errno = -rc2));
3417 fprintf(stdout, "%lld ", rectmp);
3418 if (device[0] == '/') {
3419 fprintf(stdout, "%s", device);
3420 if (device[strlen(device) - 1] != '/')
3421 fprintf(stdout, "/");
3422 } else if (path[0] == '\0') {
3423 fprintf(stdout, "/");
3425 fprintf(stdout, "%s\n", path);
3428 /* specified linkno */
3430 if (oldtmp == lnktmp)
3440 static int lfs_path2fid(int argc, char **argv)
3442 struct option long_opts[] = {
3443 {"parents", no_argument, 0, 'p'},
3447 const char short_opts[] = "p";
3448 const char *sep = "";
3451 bool show_parents = false;
3453 while ((rc = getopt_long(argc, argv, short_opts,
3454 long_opts, NULL)) != -1) {
3457 show_parents = true;
3460 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3461 argv[0], argv[optind - 1]);
3466 if (optind > argc - 1)
3468 else if (optind < argc - 1)
3472 for (path = argv + optind; *path != NULL; path++) {
3474 if (!show_parents) {
3475 err = llapi_path2fid(*path, &fid);
3477 printf("%s%s"DFID"\n",
3478 *sep != '\0' ? *path : "", sep,
3481 char name[NAME_MAX + 1];
3482 unsigned int linkno = 0;
3484 while ((err = llapi_path2parent(*path, linkno, &fid,
3485 name, sizeof(name))) == 0) {
3486 if (*sep != '\0' && linkno == 0)
3487 printf("%s%s", *path, sep);
3489 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3494 /* err == -ENODATA is end-of-loop */
3495 if (linkno > 0 && err == -ENODATA) {
3502 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3503 argv[0], show_parents ? "parent " : "", *path,
3515 static int lfs_data_version(int argc, char **argv)
3522 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3527 while ((c = getopt(argc, argv, "nrw")) != -1) {
3530 data_version_flags = 0;
3533 data_version_flags |= LL_DV_RD_FLUSH;
3536 data_version_flags |= LL_DV_WR_FLUSH;
3545 path = argv[optind];
3546 fd = open(path, O_RDONLY);
3548 err(errno, "cannot open file %s", path);
3550 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3552 err(errno, "cannot get version for %s", path);
3554 printf(LPU64 "\n", data_version);
3560 static int lfs_hsm_state(int argc, char **argv)
3565 struct hsm_user_state hus;
3573 rc = llapi_hsm_state_get(path, &hus);
3575 fprintf(stderr, "can't get hsm state for %s: %s\n",
3576 path, strerror(errno = -rc));
3580 /* Display path name and status flags */
3581 printf("%s: (0x%08x)", path, hus.hus_states);
3583 if (hus.hus_states & HS_RELEASED)
3584 printf(" released");
3585 if (hus.hus_states & HS_EXISTS)
3587 if (hus.hus_states & HS_DIRTY)
3589 if (hus.hus_states & HS_ARCHIVED)
3590 printf(" archived");
3591 /* Display user-settable flags */
3592 if (hus.hus_states & HS_NORELEASE)
3593 printf(" never_release");
3594 if (hus.hus_states & HS_NOARCHIVE)
3595 printf(" never_archive");
3596 if (hus.hus_states & HS_LOST)
3597 printf(" lost_from_hsm");
3599 if (hus.hus_archive_id != 0)
3600 printf(", archive_id:%d", hus.hus_archive_id);
3603 } while (++i < argc);
3608 #define LFS_HSM_SET 0
3609 #define LFS_HSM_CLEAR 1
3612 * Generic function to set or clear HSM flags.
3613 * Used by hsm_set and hsm_clear.
3615 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3617 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3619 struct option long_opts[] = {
3620 {"lost", 0, 0, 'l'},
3621 {"norelease", 0, 0, 'r'},
3622 {"noarchive", 0, 0, 'a'},
3623 {"archived", 0, 0, 'A'},
3624 {"dirty", 0, 0, 'd'},
3625 {"exists", 0, 0, 'e'},
3628 char short_opts[] = "lraAde";
3636 while ((c = getopt_long(argc, argv, short_opts,
3637 long_opts, NULL)) != -1) {
3643 mask |= HS_NOARCHIVE;
3646 mask |= HS_ARCHIVED;
3649 mask |= HS_NORELEASE;
3660 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3661 argv[0], argv[optind - 1]);
3666 /* User should have specified a flag */
3670 while (optind < argc) {
3672 path = argv[optind];
3674 /* If mode == 0, this means we apply the mask. */
3675 if (mode == LFS_HSM_SET)
3676 rc = llapi_hsm_state_set(path, mask, 0, 0);
3678 rc = llapi_hsm_state_set(path, 0, mask, 0);
3681 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3682 path, strerror(errno = -rc));
3691 static int lfs_hsm_action(int argc, char **argv)
3696 struct hsm_current_action hca;
3697 struct hsm_extent he;
3698 enum hsm_user_action hua;
3699 enum hsm_progress_states hps;
3707 rc = llapi_hsm_current_action(path, &hca);
3709 fprintf(stderr, "can't get hsm action for %s: %s\n",
3710 path, strerror(errno = -rc));
3713 he = hca.hca_location;
3714 hua = hca.hca_action;
3715 hps = hca.hca_state;
3717 printf("%s: %s", path, hsm_user_action2name(hua));
3719 /* Skip file without action */
3720 if (hca.hca_action == HUA_NONE) {
3725 printf(" %s ", hsm_progress_state2name(hps));
3727 if ((hps == HPS_RUNNING) &&
3728 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3729 printf("(%llu bytes moved)\n",
3730 (unsigned long long)he.length);
3731 else if ((he.offset + he.length) == LUSTRE_EOF)
3732 printf("(from %llu to EOF)\n",
3733 (unsigned long long)he.offset);
3735 printf("(from %llu to %llu)\n",
3736 (unsigned long long)he.offset,
3737 (unsigned long long)(he.offset + he.length));
3739 } while (++i < argc);
3744 static int lfs_hsm_set(int argc, char **argv)
3746 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3749 static int lfs_hsm_clear(int argc, char **argv)
3751 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3755 * Check file state and return its fid, to be used by lfs_hsm_request().
3757 * \param[in] file Path to file to check
3758 * \param[in,out] fid Pointer to allocated lu_fid struct.
3759 * \param[in,out] last_dev Pointer to last device id used.
3761 * \return 0 on success.
3763 static int lfs_hsm_prepare_file(char *file, struct lu_fid *fid,
3769 rc = lstat(file, &st);
3771 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3774 /* Checking for regular file as archiving as posix copytool
3775 * rejects archiving files other than regular files
3777 if (!S_ISREG(st.st_mode)) {
3778 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3781 /* A request should be ... */
3782 if (*last_dev != st.st_dev && *last_dev != 0) {
3783 fprintf(stderr, "All files should be "
3784 "on the same filesystem: %s\n", file);
3787 *last_dev = st.st_dev;
3789 rc = llapi_path2fid(file, fid);
3791 fprintf(stderr, "Cannot read FID of %s: %s\n",
3792 file, strerror(-rc));
3798 static int lfs_hsm_request(int argc, char **argv, int action)
3800 struct option long_opts[] = {
3801 {"filelist", 1, 0, 'l'},
3802 {"data", 1, 0, 'D'},
3803 {"archive", 1, 0, 'a'},
3807 char short_opts[] = "l:D:a:";
3808 struct hsm_user_request *hur, *oldhur;
3813 char *filelist = NULL;
3814 char fullpath[PATH_MAX];
3815 char *opaque = NULL;
3819 int nbfile_alloc = 0;
3820 char some_file[PATH_MAX+1] = "";
3826 while ((c = getopt_long(argc, argv, short_opts,
3827 long_opts, NULL)) != -1) {
3836 if (action != HUA_ARCHIVE) {
3838 "error: -a is supported only "
3839 "when archiving\n");
3842 archive_id = atoi(optarg);
3847 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3848 argv[0], argv[optind - 1]);
3853 /* All remaining args are files, so we have at least nbfile */
3854 nbfile = argc - optind;
3856 if ((nbfile == 0) && (filelist == NULL))
3860 opaque_len = strlen(opaque);
3862 /* Alloc the request structure with enough place to store all files
3863 * from command line. */
3864 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3866 fprintf(stderr, "Cannot create the request: %s\n",
3870 nbfile_alloc = nbfile;
3872 hur->hur_request.hr_action = action;
3873 hur->hur_request.hr_archive_id = archive_id;
3874 hur->hur_request.hr_flags = 0;
3876 /* All remaining args are files, add them */
3878 if (strlen(argv[optind]) > sizeof(some_file)-1) {
3882 strncpy(some_file, argv[optind], sizeof(some_file));
3885 for (i = 0; i < nbfile; i++) {
3886 hur->hur_user_item[i].hui_extent.length = -1;
3887 rc = lfs_hsm_prepare_file(argv[optind + i],
3888 &hur->hur_user_item[i].hui_fid,
3890 hur->hur_request.hr_itemcount++;
3895 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3897 /* If a filelist was specified, read the filelist from it. */
3898 if (filelist != NULL) {
3899 fp = fopen(filelist, "r");
3901 fprintf(stderr, "Cannot read the file list %s: %s\n",
3902 filelist, strerror(errno));
3907 while ((rc = getline(&line, &len, fp)) != -1) {
3908 struct hsm_user_item *hui;
3910 /* If allocated buffer was too small, get something
3912 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3914 nbfile_alloc = nbfile_alloc * 2 + 1;
3916 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3919 fprintf(stderr, "hsm: cannot allocate "
3920 "the request: %s\n",
3927 size = hur_len(oldhur);
3929 fprintf(stderr, "hsm: cannot allocate "
3930 "%u files + %u bytes data\n",
3931 oldhur->hur_request.hr_itemcount,
3932 oldhur->hur_request.hr_data_len);
3939 memcpy(hur, oldhur, size);
3944 if (line[strlen(line) - 1] == '\n')
3945 line[strlen(line) - 1] = '\0';
3948 &hur->hur_user_item[hur->hur_request.hr_itemcount];
3949 hui->hui_extent.length = -1;
3950 rc = lfs_hsm_prepare_file(line, &hui->hui_fid,
3952 hur->hur_request.hr_itemcount++;
3958 if ((some_file[0] == '\0') &&
3959 (strlen(line) < sizeof(some_file)))
3960 strcpy(some_file, line);
3968 /* If a --data was used, add it to the request */
3969 hur->hur_request.hr_data_len = opaque_len;
3971 memcpy(hur_data(hur), opaque, opaque_len);
3973 /* Send the HSM request */
3974 if (realpath(some_file, fullpath) == NULL) {
3975 fprintf(stderr, "Could not find path '%s': %s\n",
3976 some_file, strerror(errno));
3978 rc = llapi_hsm_request(fullpath, hur);
3980 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
3981 some_file, strerror(-rc));
3990 static int lfs_hsm_archive(int argc, char **argv)
3992 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
3995 static int lfs_hsm_restore(int argc, char **argv)
3997 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4000 static int lfs_hsm_release(int argc, char **argv)
4002 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4005 static int lfs_hsm_remove(int argc, char **argv)
4007 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4010 static int lfs_hsm_cancel(int argc, char **argv)
4012 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4015 static int lfs_swap_layouts(int argc, char **argv)
4020 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4021 SWAP_LAYOUTS_KEEP_MTIME |
4022 SWAP_LAYOUTS_KEEP_ATIME);
4025 int main(int argc, char **argv)
4029 /* Ensure that liblustreapi constructor has run */
4030 if (!liblustreapi_initialized)
4031 fprintf(stderr, "liblustreapi was not properly initialized\n");
4035 Parser_init("lfs > ", cmdlist);
4037 progname = argv[0]; /* Used in error messages */
4039 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4041 rc = Parser_commands();
4044 return rc < 0 ? -rc : rc;
4047 #ifdef _LUSTRE_IDL_H_
4048 /* Everything we need here should be included by lustreapi.h. */
4049 # error "lfs should not depend on lustre_idl.h"
4050 #endif /* _LUSTRE_IDL_H_ */