4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2014, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
38 * Author: Peter J. Braam <braam@clusterfs.com>
39 * Author: Phil Schwan <phil@clusterfs.com>
40 * Author: Robert Read <rread@clusterfs.com>
58 #include <sys/ioctl.h>
59 #include <sys/quota.h>
61 #include <sys/types.h>
67 #ifdef HAVE_SYS_QUOTA_H
68 # include <sys/quota.h>
71 #include <libcfs/util/string.h>
72 #include <libcfs/util/ioctl.h>
73 #include <libcfs/util/parser.h>
74 #include <lustre/lustreapi.h>
75 #include <lustre_ver.h>
76 #include <lustre_param.h>
79 static int lfs_setstripe(int argc, char **argv);
80 static int lfs_find(int argc, char **argv);
81 static int lfs_getstripe(int argc, char **argv);
82 static int lfs_getdirstripe(int argc, char **argv);
83 static int lfs_setdirstripe(int argc, char **argv);
84 static int lfs_rmentry(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_mdts(int argc, char **argv);
87 static int lfs_df(int argc, char **argv);
88 static int lfs_getname(int argc, char **argv);
89 static int lfs_check(int argc, char **argv);
90 #ifdef HAVE_SYS_QUOTA_H
91 static int lfs_setquota(int argc, char **argv);
92 static int lfs_quota(int argc, char **argv);
94 static int lfs_flushctx(int argc, char **argv);
95 static int lfs_join(int argc, char **argv);
96 static int lfs_lsetfacl(int argc, char **argv);
97 static int lfs_lgetfacl(int argc, char **argv);
98 static int lfs_rsetfacl(int argc, char **argv);
99 static int lfs_rgetfacl(int argc, char **argv);
100 static int lfs_cp(int argc, char **argv);
101 static int lfs_ls(int argc, char **argv);
102 static int lfs_poollist(int argc, char **argv);
103 static int lfs_changelog(int argc, char **argv);
104 static int lfs_changelog_clear(int argc, char **argv);
105 static int lfs_fid2path(int argc, char **argv);
106 static int lfs_path2fid(int argc, char **argv);
107 static int lfs_data_version(int argc, char **argv);
108 static int lfs_hsm_state(int argc, char **argv);
109 static int lfs_hsm_set(int argc, char **argv);
110 static int lfs_hsm_clear(int argc, char **argv);
111 static int lfs_hsm_action(int argc, char **argv);
112 static int lfs_hsm_archive(int argc, char **argv);
113 static int lfs_hsm_restore(int argc, char **argv);
114 static int lfs_hsm_release(int argc, char **argv);
115 static int lfs_hsm_remove(int argc, char **argv);
116 static int lfs_hsm_cancel(int argc, char **argv);
117 static int lfs_swap_layouts(int argc, char **argv);
118 static int lfs_mv(int argc, char **argv);
120 /* Setstripe and migrate share mostly the same parameters */
121 #define SSM_CMD_COMMON(cmd) \
122 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
123 " [--stripe-index|-i <start_ost_idx>]\n" \
124 " [--stripe-size|-S <stripe_size>]\n" \
125 " [--pool|-p <pool_name>]\n" \
126 " [--ost-list|-o <ost_indices>]\n"
128 #define SSM_HELP_COMMON \
129 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
130 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
131 "\t respectively)\n" \
132 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
133 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
134 "\tpool_name: Name of OST pool to use (default none)\n" \
135 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
136 "\t Indices be specified in a format of:\n" \
137 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
139 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
140 "\t If --pool is set with --ost-list, then the OSTs\n" \
141 "\t must be the members of the pool."
143 #define SETSTRIPE_USAGE \
144 SSM_CMD_COMMON("setstripe") \
145 " <directory|filename>\n" \
148 #define MIGRATE_USAGE \
149 SSM_CMD_COMMON("migrate ") \
154 "\tblock: Block file access during data migration\n" \
156 static const char *progname;
157 static bool file_lease_supported = true;
159 /* all available commands */
160 command_t cmdlist[] = {
161 {"setstripe", lfs_setstripe, 0,
162 "Create a new file with a specific striping pattern or\n"
163 "set the default striping pattern on an existing directory or\n"
164 "delete the default striping pattern from an existing directory\n"
165 "usage: setstripe -d <directory> (to delete default striping)\n"\
168 {"getstripe", lfs_getstripe, 0,
169 "To list the striping info for a given file or files in a\n"
170 "directory or recursively for all files in a directory tree.\n"
171 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
172 " [--stripe-count|-c] [--stripe-index|-i]\n"
173 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
174 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
176 " <directory|filename> ..."},
177 {"setdirstripe", lfs_setdirstripe, 0,
178 "To create a striped directory on a specified MDT. This can only\n"
179 "be done on MDT0 with the right of administrator.\n"
180 "usage: setdirstripe <--count|-c stripe_count>\n"
181 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
182 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
183 "\tstripe_count: stripe count of the striped directory\n"
184 "\tmdt_index: MDT index of first stripe\n"
185 "\thash_type: hash type of the striped directory. Hash types:\n"
186 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
187 " all_char sum of characters % MDT_COUNT (not recommended)\n"
188 "\tdefault_stripe: set default dirstripe of the directory\n"
189 "\tmode: the mode of the directory\n"},
190 {"getdirstripe", lfs_getdirstripe, 0,
191 "To list the striping info for a given directory\n"
192 "or recursively for all directories in a directory tree.\n"
193 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
194 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
195 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
196 {"mkdir", lfs_setdirstripe, 0,
197 "To create a striped directory on a specified MDT. This can only\n"
198 "be done on MDT0 with the right of administrator.\n"
199 "usage: mkdir <--count|-c stripe_count>\n"
200 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
201 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
202 "\tstripe_count: stripe count of the striped directory\n"
203 "\tmdt_index: MDT index of first stripe\n"
204 "\thash_type: hash type of the striped directory. Hash types:\n"
205 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
206 " all_char sum of characters % MDT_COUNT (not recommended)\n"
207 "\tdefault_stripe: set default dirstripe of the directory\n"
208 "\tmode: the mode of the directory\n"},
209 {"rm_entry", lfs_rmentry, 0,
210 "To remove the name entry of the remote directory. Note: This\n"
211 "command will only delete the name entry, i.e. the remote directory\n"
212 "will become inaccessable after this command. This can only be done\n"
213 "by the administrator\n"
214 "usage: rm_entry <dir>\n"},
215 {"pool_list", lfs_poollist, 0,
216 "List pools or pool OSTs\n"
217 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
218 {"find", lfs_find, 0,
219 "find files matching given attributes recursively in directory tree.\n"
220 "usage: find <directory|filename> ...\n"
221 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
222 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
223 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
224 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
225 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
226 " [[!] --stripe-count|-c [+-]<stripes>]\n"
227 " [[!] --stripe-index|-i <index,...>]\n"
228 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
229 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
230 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
231 " [[!] --layout|-L released,raid0]\n"
232 "\t !: used before an option indicates 'NOT' requested attribute\n"
233 "\t -: used before a value indicates 'AT MOST' requested value\n"
234 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
235 {"check", lfs_check, 0,
236 "Display the status of MDS or OSTs (as specified in the command)\n"
237 "or all the servers (MDS and OSTs).\n"
238 "usage: check <osts|mds|servers>"},
239 {"join", lfs_join, 0,
240 "join two lustre files into one.\n"
241 "obsolete, HEAD does not support it anymore.\n"},
242 {"osts", lfs_osts, 0, "list OSTs connected to client "
243 "[for specified path only]\n" "usage: osts [path]"},
244 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
245 "[for specified path only]\n" "usage: mdts [path]"},
247 "report filesystem disk space usage or inodes usage"
248 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
249 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
250 {"getname", lfs_getname, 0, "list instances and specified mount points "
251 "[for specified path only]\n"
252 "Usage: getname [-h]|[path ...] "},
253 #ifdef HAVE_SYS_QUOTA_H
254 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
255 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
256 " -b <block-softlimit> -B <block-hardlimit>\n"
257 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
258 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
259 " [--block-softlimit <block-softlimit>]\n"
260 " [--block-hardlimit <block-hardlimit>]\n"
261 " [--inode-softlimit <inode-softlimit>]\n"
262 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
263 " setquota [-t] <-u|--user|-g|--group>\n"
264 " [--block-grace <block-grace>]\n"
265 " [--inode-grace <inode-grace>] <filesystem>\n"
266 " -b can be used instead of --block-softlimit/--block-grace\n"
267 " -B can be used instead of --block-hardlimit\n"
268 " -i can be used instead of --inode-softlimit/--inode-grace\n"
269 " -I can be used instead of --inode-hardlimit\n\n"
270 "Note: The total quota space will be split into many qunits and\n"
271 " balanced over all server targets, the minimal qunit size is\n"
272 " 1M bytes for block space and 1K inodes for inode space.\n\n"
273 " Quota space rebalancing process will stop when this mininum\n"
274 " value is reached. As a result, quota exceeded can be returned\n"
275 " while many targets still have 1MB or 1K inodes of spare\n"
277 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
278 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
280 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
281 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
283 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
284 "usage: flushctx [-k] [mountpoint...]"},
285 {"lsetfacl", lfs_lsetfacl, 0,
286 "Remote user setfacl for user/group on the same remote client.\n"
287 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
288 {"lgetfacl", lfs_lgetfacl, 0,
289 "Remote user getfacl for user/group on the same remote client.\n"
290 "usage: lgetfacl [-dRLPvh] file ..."},
291 {"rsetfacl", lfs_rsetfacl, 0,
292 "Remote user setfacl for user/group on other clients.\n"
293 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
294 {"rgetfacl", lfs_rgetfacl, 0,
295 "Remote user getfacl for user/group on other clients.\n"
296 "usage: rgetfacl [-dRLPvh] file ..."},
298 "Remote user copy files and directories.\n"
299 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
301 "Remote user list directory contents.\n"
302 "usage: ls [OPTION]... [FILE]..."},
303 {"changelog", lfs_changelog, 0,
304 "Show the metadata changes on an MDT."
305 "\nusage: changelog <mdtname> [startrec [endrec]]"},
306 {"changelog_clear", lfs_changelog_clear, 0,
307 "Indicate that old changelog records up to <endrec> are no longer of "
308 "interest to consumer <id>, allowing the system to free up space.\n"
309 "An <endrec> of 0 means all records.\n"
310 "usage: changelog_clear <mdtname> <id> <endrec>"},
311 {"fid2path", lfs_fid2path, 0,
312 "Resolve the full path(s) for given FID(s). For a specific hardlink "
313 "specify link number <linkno>.\n"
314 /* "For a historical link name, specify changelog record <recno>.\n" */
315 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
316 /* [ --rec <recno> ] */ },
317 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
318 "usage: path2fid [--parents] <path> ..."},
319 {"data_version", lfs_data_version, 0, "Display file data version for "
320 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
321 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
322 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
323 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
324 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
325 "[--archived] [--lost] <file> ..."},
326 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
328 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
329 "[--archived] [--lost] <file> ..."},
330 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
331 "given files.\n" "usage: hsm_action <file> ..."},
332 {"hsm_archive", lfs_hsm_archive, 0,
333 "Archive file to external storage.\n"
334 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
336 {"hsm_restore", lfs_hsm_restore, 0,
337 "Restore file from external storage.\n"
338 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
339 {"hsm_release", lfs_hsm_release, 0,
340 "Release files from Lustre.\n"
341 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
342 {"hsm_remove", lfs_hsm_remove, 0,
343 "Remove file copy from external storage.\n"
344 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
345 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
347 "Note: To remove files from the archive that have been deleted on\n"
348 "Lustre, set mntpath and optionally archive. In that case, all the\n"
349 "positional arguments and entries in the file list must be FIDs."
351 {"hsm_cancel", lfs_hsm_cancel, 0,
352 "Cancel requests related to specified files.\n"
353 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
355 "usage: swap_layouts <path1> <path2>"},
356 {"migrate", lfs_setstripe, 0,
357 "migrate file/directory between MDTs, or migrate file from one OST "
358 "layout\nto another (may be not safe with concurent writes).\n"
359 "usage: migrate [--mdt-index|-m <mdt_idx>] <directory|filename>]\n"
360 "\tmdt_idx: MDT index to migrate to\n"
364 "To move directories between MDTs. This command is deprecated, "
365 "use \"migrate\" instead.\n"
366 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
368 {"help", Parser_help, 0, "help"},
369 {"exit", Parser_quit, 0, "quit"},
370 {"quit", Parser_quit, 0, "quit"},
371 {"--version", Parser_version, 0,
372 "output build version of the utility and exit"},
377 #define MIGRATION_BLOCKS 1
380 * Internal helper for migrate_copy_data(). Check lease and report error if
383 * \param[in] fd File descriptor on which to check the lease.
384 * \param[out] lease_broken Set to true if the lease was broken.
385 * \param[in] group_locked Whether a group lock was taken or not.
386 * \param[in] path Name of the file being processed, for error
389 * \retval 0 Migration can keep on going.
390 * \retval -errno Error occurred, abort migration.
392 static int check_lease(int fd, bool *lease_broken, bool group_locked,
397 if (!file_lease_supported)
400 rc = llapi_lease_check(fd);
402 return 0; /* llapi_check_lease returns > 0 on success. */
405 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
407 rc = rc ? rc : -EAGAIN;
409 fprintf(stderr, "%s: external attempt to access file '%s' "
410 "blocked until migration ends.\n", progname, path);
413 *lease_broken = true;
417 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
418 bool group_locked, const char *fname)
427 bool lease_broken = false;
429 /* Use a page-aligned buffer for direct I/O */
430 rc = posix_memalign(&buf, getpagesize(), buf_size);
435 /* read new data only if we have written all
436 * previously read data */
439 rc = check_lease(fd_src, &lease_broken,
440 group_locked, fname);
444 rsize = read(fd_src, buf, buf_size);
447 fprintf(stderr, "%s: %s: read failed: %s\n",
448 progname, fname, strerror(-rc));
458 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
462 "%s: %s: write failed on volatile: %s\n",
463 progname, fname, strerror(-rc));
473 fprintf(stderr, "%s: %s: fsync failed: %s\n",
474 progname, fname, strerror(-rc));
482 static int migrate_copy_timestamps(int fdv, const struct stat *st)
484 struct timeval tv[2] = {
485 {.tv_sec = st->st_atime},
486 {.tv_sec = st->st_mtime}
489 return futimes(fdv, tv);
492 static int migrate_block(int fd, int fdv, const struct stat *st,
493 size_t buf_size, const char *name)
500 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
502 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
503 progname, name, strerror(-rc));
511 /* The grouplock blocks all concurrent accesses to the file.
512 * It has to be taken after llapi_get_data_version as it would
514 rc = llapi_group_lock(fd, gid);
516 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
517 progname, name, strerror(-rc));
521 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
523 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
527 /* Make sure we keep original atime/mtime values */
528 rc = migrate_copy_timestamps(fdv, st);
530 fprintf(stderr, "%s: %s: timestamp copy failed\n",
536 * for a migration we need to check data version on file did
539 * Pass in gid=0 since we already own grouplock. */
540 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
541 SWAP_LAYOUTS_CHECK_DV1);
543 fprintf(stderr, "%s: %s: dataversion changed during copy, "
544 "migration aborted\n", progname, name);
547 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
548 name, strerror(-rc));
553 rc2 = llapi_group_unlock(fd, gid);
554 if (rc2 < 0 && rc == 0) {
555 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
556 progname, name, strerror(-rc2));
563 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
564 size_t buf_size, const char *name)
570 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
572 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
573 progname, name, strerror(-rc));
577 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
579 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
583 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
585 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
586 progname, name, strerror(-rc));
592 fprintf(stderr, "%s: %s: data version changed during "
598 /* Make sure we keep original atime/mtime values */
599 rc = migrate_copy_timestamps(fdv, st);
601 fprintf(stderr, "%s: %s: timestamp copy failed\n",
606 /* Atomically put lease, swap layouts and close.
607 * for a migration we need to check data version on file did
609 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
611 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
612 progname, name, strerror(-rc));
619 static int lfs_migrate(char *name, __u64 migration_flags,
620 struct llapi_stripe_param *param)
624 char volatile_file[PATH_MAX +
625 LUSTRE_VOLATILE_HDR_LEN + 4];
626 char parent[PATH_MAX];
629 struct lov_user_md *lum = NULL;
632 bool have_lease_rdlck = false;
636 /* find the right size for the IO and allocate the buffer */
637 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
638 lum = malloc(lum_size);
644 rc = llapi_file_get_stripe(name, lum);
645 /* failure can happen for many reasons and some may be not real errors
647 * in case of a real error, a later call will fail with better
648 * error management */
650 buf_size = 1024 * 1024;
652 buf_size = lum->lmm_stripe_size;
654 /* open file, direct io */
655 /* even if the file is only read, WR mode is nedeed to allow
656 * layout swap on fd */
657 fd = open(name, O_RDWR | O_DIRECT);
660 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
665 if (file_lease_supported) {
666 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
667 if (rc == -EOPNOTSUPP) {
668 /* Older servers do not support file lease.
669 * Disable related checks. This opens race conditions
670 * as explained in LU-4840 */
671 file_lease_supported = false;
673 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
674 progname, name, strerror(-rc));
677 have_lease_rdlck = true;
681 /* search for file directory pathname */
682 if (strlen(name) > sizeof(parent)-1) {
686 strncpy(parent, name, sizeof(parent));
687 ptr = strrchr(parent, '/');
689 if (getcwd(parent, sizeof(parent)) == NULL) {
700 rc = snprintf(volatile_file, sizeof(volatile_file), "%s/%s::", parent,
701 LUSTRE_VOLATILE_HDR);
702 if (rc >= sizeof(volatile_file)) {
707 /* create, open a volatile file, use caching (ie no directio) */
708 /* exclusive create is not needed because volatile files cannot
709 * conflict on name by construction */
710 fdv = llapi_file_open_param(volatile_file, O_CREAT | O_WRONLY, 0644,
714 fprintf(stderr, "%s: %s: cannot create volatile file in"
716 progname, parent, strerror(-rc));
720 /* Not-owner (root?) special case.
721 * Need to set owner/group of volatile file like original.
722 * This will allow to pass related check during layout_swap.
727 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
731 rc = fstat(fdv, &stv);
734 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
735 volatile_file, strerror(errno));
738 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
739 rc = fchown(fdv, st.st_uid, st.st_gid);
742 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
743 name, strerror(errno));
748 if (migration_flags & MIGRATION_BLOCKS || !file_lease_supported) {
749 /* Blocking mode, forced if servers do not support file lease */
750 rc = migrate_block(fd, fdv, &st, buf_size, name);
752 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
754 have_lease_rdlck = false;
755 fdv = -1; /* The volatile file is closed as we put the
756 * lease in non-blocking mode. */
761 if (have_lease_rdlck)
778 * Parse a string containing an OST index list into an array of integers.
780 * The input string contains a comma delimited list of individual
781 * indices and ranges, for example "1,2-4,7". Add the indices into the
782 * \a osts array and remove duplicates.
784 * \param[out] osts array to store indices in
785 * \param[in] size size of \a osts array
786 * \param[in] offset starting index in \a osts
787 * \param[in] arg string containing OST index list
789 * \retval positive number of indices in \a osts
790 * \retval -EINVAL unable to parse \a arg
792 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
796 int slots = size - offset;
804 while (!end_of_loop) {
812 ptr = strchrnul(arg, ',');
814 end_of_loop = *ptr == '\0';
817 start_index = strtol(arg, &endptr, 0);
818 if (endptr == arg) /* no data at all */
820 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
825 end_index = start_index;
826 if (*endptr == '-') {
827 end_index = strtol(endptr + 1, &endptr, 0);
830 if (end_index < start_index)
834 for (i = start_index; i <= end_index && slots > 0; i++) {
837 /* remove duplicate */
838 for (j = 0; j < offset; j++) {
842 if (j == offset) { /* no duplicate */
847 if (slots == 0 && i < end_index)
855 if (!end_of_loop && ptr != NULL)
858 return rc < 0 ? rc : nr;
862 static int lfs_setstripe(int argc, char **argv)
864 struct llapi_stripe_param *param = NULL;
865 struct find_param migrate_mdt_param = {
872 unsigned long long st_size;
873 int st_offset, st_count;
877 char *stripe_size_arg = NULL;
878 char *stripe_off_arg = NULL;
879 char *stripe_count_arg = NULL;
880 char *pool_name_arg = NULL;
881 char *mdt_idx_arg = NULL;
882 unsigned long long size_units = 1;
883 bool migrate_mode = false;
884 __u64 migration_flags = 0;
885 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
888 struct option long_opts[] = {
889 /* valid only in migrate mode */
890 {"block", no_argument, 0, 'b'},
891 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
892 /* This formerly implied "stripe-count", but was explicitly
893 * made "stripe-count" for consistency with other options,
894 * and to separate it from "mdt-count" when DNE arrives. */
895 {"count", required_argument, 0, 'c'},
897 {"stripe-count", required_argument, 0, 'c'},
898 {"stripe_count", required_argument, 0, 'c'},
899 {"delete", no_argument, 0, 'd'},
900 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
901 /* This formerly implied "stripe-index", but was explicitly
902 * made "stripe-index" for consistency with other options,
903 * and to separate it from "mdt-index" when DNE arrives. */
904 {"index", required_argument, 0, 'i'},
906 {"stripe-index", required_argument, 0, 'i'},
907 {"stripe_index", required_argument, 0, 'i'},
908 {"mdt-index", required_argument, 0, 'm'},
909 {"mdt_index", required_argument, 0, 'm'},
910 {"ost-list", required_argument, 0, 'o'},
911 {"ost_list", required_argument, 0, 'o'},
912 {"pool", required_argument, 0, 'p'},
913 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
914 /* This formerly implied "--stripe-size", but was confusing
915 * with "lfs find --size|-s", which means "file size", so use
916 * the consistent "--stripe-size|-S" for all commands. */
917 {"size", required_argument, 0, 's'},
919 {"stripe-size", required_argument, 0, 'S'},
920 {"stripe_size", required_argument, 0, 'S'},
928 if (strcmp(argv[0], "migrate") == 0)
931 while ((c = getopt_long(argc, argv, "bc:di:m:o:p:s:S:",
932 long_opts, NULL)) >= 0) {
939 fprintf(stderr, "--block is valid only for"
943 migration_flags |= MIGRATION_BLOCKS;
946 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
947 if (strcmp(argv[optind - 1], "--count") == 0)
948 fprintf(stderr, "warning: '--count' deprecated"
949 ", use '--stripe-count' instead\n");
951 stripe_count_arg = optarg;
954 /* delete the default striping pattern */
958 nr_osts = parse_targets(osts,
959 sizeof(osts) / sizeof(__u32),
963 "error: %s: bad OST indices '%s'\n",
968 if (st_offset == -1) /* first in the command line */
972 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
973 if (strcmp(argv[optind - 1], "--index") == 0)
974 fprintf(stderr, "warning: '--index' deprecated"
975 ", use '--stripe-index' instead\n");
977 stripe_off_arg = optarg;
981 fprintf(stderr, "--mdt-index is valid only for"
985 mdt_idx_arg = optarg;
987 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
989 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
990 fprintf(stderr, "warning: '--size|-s' deprecated, "
991 "use '--stripe-size|-S' instead\n");
993 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
995 stripe_size_arg = optarg;
998 pool_name_arg = optarg;
1005 fname = argv[optind];
1008 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1009 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1010 fprintf(stderr, "error: %s: cannot specify -d with "
1011 "-s, -c, -o, or -p options\n",
1016 if (optind == argc) {
1017 fprintf(stderr, "error: %s: missing filename|dirname\n",
1022 if (mdt_idx_arg != NULL && optind > 3) {
1023 fprintf(stderr, "error: %s: cannot specify -m with other "
1024 "options\n", argv[0]);
1028 if (pool_name_arg != NULL) {
1032 ptr = strchr(pool_name_arg, '.');
1034 ptr = pool_name_arg;
1036 if ((ptr - pool_name_arg) == 0) {
1037 fprintf(stderr, "error: %s: fsname is empty "
1038 "in pool name '%s'\n",
1039 argv[0], pool_name_arg);
1046 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1048 fprintf(stderr, "error: %s: poolname '%s' is "
1050 argv[0], pool_name_arg);
1052 } else if (rc == -2) {
1053 fprintf(stderr, "error: %s: pool name '%s' is too long "
1054 "(max is %d characters)\n",
1055 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1057 } else if (rc > 0) {
1058 fprintf(stderr, "error: %s: char '%c' not allowed in "
1060 argv[0], rc, pool_name_arg);
1065 /* get the stripe size */
1066 if (stripe_size_arg != NULL) {
1067 result = llapi_parse_size(stripe_size_arg, &st_size,
1070 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1071 argv[0], stripe_size_arg);
1075 /* get the stripe offset */
1076 if (stripe_off_arg != NULL) {
1077 st_offset = strtol(stripe_off_arg, &end, 0);
1079 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1080 argv[0], stripe_off_arg);
1084 /* get the stripe count */
1085 if (stripe_count_arg != NULL) {
1086 st_count = strtoul(stripe_count_arg, &end, 0);
1088 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1089 argv[0], stripe_count_arg);
1094 if (mdt_idx_arg != NULL) {
1095 /* initialize migrate mdt parameters */
1096 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1098 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1099 argv[0], mdt_idx_arg);
1102 migrate_mdt_param.fp_migrate = 1;
1104 /* initialize stripe parameters */
1105 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1106 if (param == NULL) {
1107 fprintf(stderr, "error: %s: run out of memory\n",
1112 param->lsp_stripe_size = st_size;
1113 param->lsp_stripe_offset = st_offset;
1114 param->lsp_stripe_count = st_count;
1115 param->lsp_stripe_pattern = 0;
1116 param->lsp_pool = pool_name_arg;
1117 param->lsp_is_specific = false;
1119 if (st_count > 0 && nr_osts != st_count) {
1120 fprintf(stderr, "error: %s: stripe count '%d' "
1121 "doesn't match the number of OSTs: %d\n"
1122 , argv[0], st_count, nr_osts);
1127 param->lsp_is_specific = true;
1128 param->lsp_stripe_count = nr_osts;
1129 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1133 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1134 if (!migrate_mode) {
1135 result = llapi_file_open_param(fname,
1142 } else if (mdt_idx_arg != NULL) {
1143 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1145 result = lfs_migrate(fname, migration_flags, param);
1148 /* Save the first error encountered. */
1152 "error: %s: %s file '%s' failed\n",
1153 argv[0], migrate_mode ? "migrate" : "create",
1163 static int lfs_poollist(int argc, char **argv)
1168 return llapi_poollist(argv[1]);
1171 static int set_time(time_t *time, time_t *set, char *str)
1178 else if (str[0] == '-')
1184 t = strtol(str, NULL, 0);
1185 if (*time < t * 24 * 60 * 60) {
1188 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1192 *set = *time - t * 24 * 60 * 60;
1199 static int name2id(unsigned int *id, char *name, int type)
1202 struct passwd *entry;
1204 if (!(entry = getpwnam(name))) {
1210 *id = entry->pw_uid;
1212 struct group *entry;
1214 if (!(entry = getgrnam(name))) {
1220 *id = entry->gr_gid;
1226 static int id2name(char **name, unsigned int id, int type)
1229 struct passwd *entry;
1231 if (!(entry = getpwuid(id))) {
1237 *name = entry->pw_name;
1239 struct group *entry;
1241 if (!(entry = getgrgid(id))) {
1247 *name = entry->gr_name;
1253 static int name2layout(__u32 *layout, char *name)
1258 for (ptr = name; ; ptr = NULL) {
1259 lyt = strtok(ptr, ",");
1262 if (strcmp(lyt, "released") == 0)
1263 *layout |= LOV_PATTERN_F_RELEASED;
1264 else if (strcmp(lyt, "raid0") == 0)
1265 *layout |= LOV_PATTERN_RAID0;
1272 #define FIND_POOL_OPT 3
1273 static int lfs_find(int argc, char **argv)
1278 struct find_param param = {
1282 struct option long_opts[] = {
1283 {"atime", required_argument, 0, 'A'},
1284 {"stripe-count", required_argument, 0, 'c'},
1285 {"stripe_count", required_argument, 0, 'c'},
1286 {"ctime", required_argument, 0, 'C'},
1287 {"maxdepth", required_argument, 0, 'D'},
1288 {"gid", required_argument, 0, 'g'},
1289 {"group", required_argument, 0, 'G'},
1290 {"stripe-index", required_argument, 0, 'i'},
1291 {"stripe_index", required_argument, 0, 'i'},
1292 {"layout", required_argument, 0, 'L'},
1293 {"mdt", required_argument, 0, 'm'},
1294 {"mtime", required_argument, 0, 'M'},
1295 {"name", required_argument, 0, 'n'},
1296 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1297 {"obd", required_argument, 0, 'O'},
1298 {"ost", required_argument, 0, 'O'},
1299 /* no short option for pool, p/P already used */
1300 {"pool", required_argument, 0, FIND_POOL_OPT},
1301 {"print0", no_argument, 0, 'p'},
1302 {"print", no_argument, 0, 'P'},
1303 {"size", required_argument, 0, 's'},
1304 {"stripe-size", required_argument, 0, 'S'},
1305 {"stripe_size", required_argument, 0, 'S'},
1306 {"type", required_argument, 0, 't'},
1307 {"uid", required_argument, 0, 'u'},
1308 {"user", required_argument, 0, 'U'},
1321 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1322 while ((c = getopt_long_only(argc, argv,
1323 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1324 long_opts, NULL)) >= 0) {
1329 /* '!' is part of option */
1330 /* when getopt_long_only() finds a string which is not
1331 * an option nor a known option argument it returns 1
1332 * in that case if we already have found pathstart and pathend
1333 * (i.e. we have the list of pathnames),
1334 * the only supported value is "!"
1336 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1337 if (!isoption && pathend != -1) {
1338 fprintf(stderr, "err: %s: filename|dirname must either "
1339 "precede options or follow options\n",
1344 if (!isoption && pathstart == -1)
1345 pathstart = optind - 1;
1346 if (isoption && pathstart != -1 && pathend == -1)
1347 pathend = optind - 2;
1353 /* unknown; opt is "!" or path component,
1354 * checking done above.
1356 if (strcmp(optarg, "!") == 0)
1360 xtime = ¶m.fp_atime;
1361 xsign = ¶m.fp_asign;
1362 param.fp_exclude_atime = !!neg_opt;
1363 /* no break, this falls through to 'C' for ctime */
1366 xtime = ¶m.fp_ctime;
1367 xsign = ¶m.fp_csign;
1368 param.fp_exclude_ctime = !!neg_opt;
1370 /* no break, this falls through to 'M' for mtime */
1373 xtime = ¶m.fp_mtime;
1374 xsign = ¶m.fp_msign;
1375 param.fp_exclude_mtime = !!neg_opt;
1377 rc = set_time(&t, xtime, optarg);
1378 if (rc == INT_MAX) {
1386 if (optarg[0] == '+') {
1387 param.fp_stripe_count_sign = -1;
1389 } else if (optarg[0] == '-') {
1390 param.fp_stripe_count_sign = 1;
1394 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1395 if (*endptr != '\0') {
1396 fprintf(stderr,"error: bad stripe_count '%s'\n",
1401 param.fp_check_stripe_count = 1;
1402 param.fp_exclude_stripe_count = !!neg_opt;
1405 param.fp_max_depth = strtol(optarg, 0, 0);
1409 rc = name2id(¶m.fp_gid, optarg, GROUP);
1411 param.fp_gid = strtoul(optarg, &endptr, 10);
1412 if (*endptr != '\0') {
1413 fprintf(stderr, "Group/GID: %s cannot "
1414 "be found.\n", optarg);
1419 param.fp_exclude_gid = !!neg_opt;
1420 param.fp_check_gid = 1;
1423 ret = name2layout(¶m.fp_layout, optarg);
1426 param.fp_exclude_layout = !!neg_opt;
1427 param.fp_check_layout = 1;
1431 rc = name2id(¶m.fp_uid, optarg, USER);
1433 param.fp_uid = strtoul(optarg, &endptr, 10);
1434 if (*endptr != '\0') {
1435 fprintf(stderr, "User/UID: %s cannot "
1436 "be found.\n", optarg);
1441 param.fp_exclude_uid = !!neg_opt;
1442 param.fp_check_uid = 1;
1445 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1447 "Pool name %s is too long"
1448 " (max is %d)\n", optarg,
1453 /* we do check for empty pool because empty pool
1454 * is used to find V1 lov attributes */
1455 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1456 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1457 param.fp_exclude_pool = !!neg_opt;
1458 param.fp_check_pool = 1;
1461 param.fp_pattern = (char *)optarg;
1462 param.fp_exclude_pattern = !!neg_opt;
1467 char *buf, *token, *next, *p;
1471 buf = strdup(optarg);
1477 param.fp_exclude_obd = !!neg_opt;
1480 while (token && *token) {
1481 token = strchr(token, ',');
1488 param.fp_exclude_mdt = !!neg_opt;
1489 param.fp_num_alloc_mdts += len;
1490 tmp = realloc(param.fp_mdt_uuid,
1491 param.fp_num_alloc_mdts *
1492 sizeof(*param.fp_mdt_uuid));
1498 param.fp_mdt_uuid = tmp;
1500 param.fp_exclude_obd = !!neg_opt;
1501 param.fp_num_alloc_obds += len;
1502 tmp = realloc(param.fp_obd_uuid,
1503 param.fp_num_alloc_obds *
1504 sizeof(*param.fp_obd_uuid));
1510 param.fp_obd_uuid = tmp;
1512 for (token = buf; token && *token; token = next) {
1513 struct obd_uuid *puuid;
1516 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1519 ¶m.fp_obd_uuid[param.fp_num_obds++];
1521 p = strchr(token, ',');
1528 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1533 strncpy(puuid->uuid, token,
1534 sizeof(puuid->uuid));
1542 param.fp_zero_end = 1;
1547 if (optarg[0] == '+') {
1548 param.fp_size_sign = -1;
1550 } else if (optarg[0] == '-') {
1551 param.fp_size_sign = 1;
1555 ret = llapi_parse_size(optarg, ¶m.fp_size,
1556 ¶m.fp_size_units, 0);
1558 fprintf(stderr, "error: bad file size '%s'\n",
1562 param.fp_check_size = 1;
1563 param.fp_exclude_size = !!neg_opt;
1566 if (optarg[0] == '+') {
1567 param.fp_stripe_size_sign = -1;
1569 } else if (optarg[0] == '-') {
1570 param.fp_stripe_size_sign = 1;
1574 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1575 ¶m.fp_stripe_size_units, 0);
1577 fprintf(stderr, "error: bad stripe_size '%s'\n",
1581 param.fp_check_stripe_size = 1;
1582 param.fp_exclude_stripe_size = !!neg_opt;
1585 param.fp_exclude_type = !!neg_opt;
1586 switch (optarg[0]) {
1588 param.fp_type = S_IFBLK;
1591 param.fp_type = S_IFCHR;
1594 param.fp_type = S_IFDIR;
1597 param.fp_type = S_IFREG;
1600 param.fp_type = S_IFLNK;
1603 param.fp_type = S_IFIFO;
1606 param.fp_type = S_IFSOCK;
1609 fprintf(stderr, "error: %s: bad type '%s'\n",
1621 if (pathstart == -1) {
1622 fprintf(stderr, "error: %s: no filename|pathname\n",
1626 } else if (pathend == -1) {
1632 rc = llapi_find(argv[pathstart], ¶m);
1633 if (rc != 0 && ret == 0)
1635 } while (++pathstart < pathend);
1638 fprintf(stderr, "error: %s failed for %s.\n",
1639 argv[0], argv[optind - 1]);
1641 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1642 free(param.fp_obd_uuid);
1644 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1645 free(param.fp_mdt_uuid);
1650 static int lfs_getstripe_internal(int argc, char **argv,
1651 struct find_param *param)
1653 struct option long_opts[] = {
1654 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1655 /* This formerly implied "stripe-count", but was explicitly
1656 * made "stripe-count" for consistency with other options,
1657 * and to separate it from "mdt-count" when DNE arrives. */
1658 {"count", no_argument, 0, 'c'},
1660 {"stripe-count", no_argument, 0, 'c'},
1661 {"stripe_count", no_argument, 0, 'c'},
1662 {"directory", no_argument, 0, 'd'},
1663 {"default", no_argument, 0, 'D'},
1664 {"generation", no_argument, 0, 'g'},
1665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1666 /* This formerly implied "stripe-index", but was explicitly
1667 * made "stripe-index" for consistency with other options,
1668 * and to separate it from "mdt-index" when DNE arrives. */
1669 {"index", no_argument, 0, 'i'},
1671 {"stripe-index", no_argument, 0, 'i'},
1672 {"stripe_index", no_argument, 0, 'i'},
1673 {"layout", no_argument, 0, 'L'},
1674 {"mdt-index", no_argument, 0, 'M'},
1675 {"mdt_index", no_argument, 0, 'M'},
1676 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1677 /* This formerly implied "stripe-index", but was confusing
1678 * with "file offset" (which will eventually be needed for
1679 * with different layouts by offset), so deprecate it. */
1680 {"offset", no_argument, 0, 'o'},
1682 {"obd", required_argument, 0, 'O'},
1683 {"ost", required_argument, 0, 'O'},
1684 {"pool", no_argument, 0, 'p'},
1685 {"quiet", no_argument, 0, 'q'},
1686 {"recursive", no_argument, 0, 'r'},
1687 {"raw", no_argument, 0, 'R'},
1688 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1689 /* This formerly implied "--stripe-size", but was confusing
1690 * with "lfs find --size|-s", which means "file size", so use
1691 * the consistent "--stripe-size|-S" for all commands. */
1692 {"size", no_argument, 0, 's'},
1694 {"stripe-size", no_argument, 0, 'S'},
1695 {"stripe_size", no_argument, 0, 'S'},
1696 {"verbose", no_argument, 0, 'v'},
1701 param->fp_max_depth = 1;
1702 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1703 long_opts, NULL)) != -1) {
1706 if (param->fp_obd_uuid) {
1708 "error: %s: only one obduuid allowed",
1712 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1718 param->fp_max_depth = 0;
1721 param->fp_get_default_lmv = 1;
1724 param->fp_recursive = 1;
1727 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1730 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1731 if (strcmp(argv[optind - 1], "--count") == 0)
1732 fprintf(stderr, "warning: '--count' deprecated,"
1733 " use '--stripe-count' instead\n");
1735 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1736 param->fp_verbose |= VERBOSE_COUNT;
1737 param->fp_max_depth = 0;
1740 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1742 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1743 fprintf(stderr, "warning: '--size|-s' deprecated, "
1744 "use '--stripe-size|-S' instead\n");
1746 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1748 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1749 param->fp_verbose |= VERBOSE_SIZE;
1750 param->fp_max_depth = 0;
1753 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1755 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1756 "use '--stripe-index|-i' instead\n");
1759 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1760 if (strcmp(argv[optind - 1], "--index") == 0)
1761 fprintf(stderr, "warning: '--index' deprecated"
1762 ", use '--stripe-index' instead\n");
1764 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1765 param->fp_verbose |= VERBOSE_OFFSET;
1766 param->fp_max_depth = 0;
1770 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1771 param->fp_verbose |= VERBOSE_POOL;
1772 param->fp_max_depth = 0;
1776 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1777 param->fp_verbose |= VERBOSE_GENERATION;
1778 param->fp_max_depth = 0;
1782 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1783 param->fp_verbose |= VERBOSE_LAYOUT;
1784 param->fp_max_depth = 0;
1788 if (!(param->fp_verbose & VERBOSE_DETAIL))
1789 param->fp_max_depth = 0;
1790 param->fp_verbose |= VERBOSE_MDTINDEX;
1803 if (param->fp_recursive)
1804 param->fp_max_depth = -1;
1806 if (!param->fp_verbose)
1807 param->fp_verbose = VERBOSE_ALL;
1808 if (param->fp_quiet)
1809 param->fp_verbose = VERBOSE_OBJID;
1812 rc = llapi_getstripe(argv[optind], param);
1813 } while (++optind < argc && !rc);
1816 fprintf(stderr, "error: %s failed for %s.\n",
1817 argv[0], argv[optind - 1]);
1821 static int lfs_tgts(int argc, char **argv)
1823 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1824 struct find_param param;
1825 int index = 0, rc=0;
1830 if (argc == 2 && !realpath(argv[1], path)) {
1832 fprintf(stderr, "error: invalid path '%s': %s\n",
1833 argv[1], strerror(-rc));
1837 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1838 /* Check if we have a mount point */
1839 if (mntdir[0] == '\0')
1842 memset(¶m, 0, sizeof(param));
1843 if (!strcmp(argv[0], "mdts"))
1844 param.fp_get_lmv = 1;
1846 rc = llapi_ostlist(mntdir, ¶m);
1848 fprintf(stderr, "error: %s: failed on %s\n",
1851 if (path[0] != '\0')
1853 memset(mntdir, 0, PATH_MAX);
1859 static int lfs_getstripe(int argc, char **argv)
1861 struct find_param param = { 0 };
1862 return lfs_getstripe_internal(argc, argv, ¶m);
1866 static int lfs_getdirstripe(int argc, char **argv)
1868 struct find_param param = { 0 };
1870 param.fp_get_lmv = 1;
1871 return lfs_getstripe_internal(argc, argv, ¶m);
1875 static int lfs_setdirstripe(int argc, char **argv)
1879 unsigned int stripe_offset = -1;
1880 unsigned int stripe_count = 1;
1881 enum lmv_hash_type hash_type;
1884 char *stripe_offset_opt = NULL;
1885 char *stripe_count_opt = NULL;
1886 char *stripe_hash_opt = NULL;
1887 char *mode_opt = NULL;
1888 bool default_stripe = false;
1889 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1890 mode_t previous_mode = 0;
1891 bool delete = false;
1893 struct option long_opts[] = {
1894 {"count", required_argument, 0, 'c'},
1895 {"delete", no_argument, 0, 'd'},
1896 {"index", required_argument, 0, 'i'},
1897 {"mode", required_argument, 0, 'm'},
1898 {"hash-type", required_argument, 0, 't'},
1899 {"default_stripe", no_argument, 0, 'D'},
1903 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1910 stripe_count_opt = optarg;
1914 default_stripe = true;
1917 default_stripe = true;
1920 stripe_offset_opt = optarg;
1926 stripe_hash_opt = optarg;
1929 fprintf(stderr, "error: %s: option '%s' "
1931 argv[0], argv[optind - 1]);
1936 if (optind == argc) {
1937 fprintf(stderr, "error: %s: missing dirname\n",
1942 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1943 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1948 if (stripe_offset_opt != NULL) {
1949 /* get the stripe offset */
1950 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1952 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1953 argv[0], stripe_offset_opt);
1959 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1960 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1961 " or -i options.\n", argv[0]);
1969 if (mode_opt != NULL) {
1970 mode = strtoul(mode_opt, &end, 8);
1972 fprintf(stderr, "error: %s: bad mode '%s'\n",
1976 previous_mode = umask(0);
1979 if (stripe_hash_opt == NULL ||
1980 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1981 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1982 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1983 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1985 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1986 argv[0], stripe_hash_opt);
1990 /* get the stripe count */
1991 if (stripe_count_opt != NULL) {
1992 stripe_count = strtoul(stripe_count_opt, &end, 0);
1994 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1995 argv[0], stripe_count_opt);
2000 dname = argv[optind];
2002 if (default_stripe) {
2003 result = llapi_dir_set_default_lmv_stripe(dname,
2004 stripe_offset, stripe_count,
2007 result = llapi_dir_create_pool(dname, mode,
2009 stripe_count, hash_type,
2014 fprintf(stderr, "error: %s: create stripe dir '%s' "
2015 "failed\n", argv[0], dname);
2018 dname = argv[++optind];
2019 } while (dname != NULL);
2021 if (mode_opt != NULL)
2022 umask(previous_mode);
2028 static int lfs_rmentry(int argc, char **argv)
2035 fprintf(stderr, "error: %s: missing dirname\n",
2041 dname = argv[index];
2042 while (dname != NULL) {
2043 result = llapi_direntry_remove(dname);
2045 fprintf(stderr, "error: %s: remove dir entry '%s' "
2046 "failed\n", argv[0], dname);
2049 dname = argv[++index];
2054 static int lfs_mv(int argc, char **argv)
2056 struct find_param param = {
2063 struct option long_opts[] = {
2064 {"mdt-index", required_argument, 0, 'M'},
2065 {"verbose", no_argument, 0, 'v'},
2069 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2072 param.fp_mdt_index = strtoul(optarg, &end, 0);
2074 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2081 param.fp_verbose = VERBOSE_DETAIL;
2085 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2086 argv[0], argv[optind - 1]);
2091 if (param.fp_mdt_index == -1) {
2092 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2096 if (optind >= argc) {
2097 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2101 param.fp_migrate = 1;
2102 rc = llapi_migrate_mdt(argv[optind], ¶m);
2104 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2105 argv[0], argv[optind], param.fp_mdt_index,
2110 static int lfs_osts(int argc, char **argv)
2112 return lfs_tgts(argc, argv);
2115 static int lfs_mdts(int argc, char **argv)
2117 return lfs_tgts(argc, argv);
2120 #define COOK(value) \
2123 while (value > 1024) { \
2131 #define CDF "%11llu"
2132 #define HDF "%8.1f%c"
2136 static int showdf(char *mntdir, struct obd_statfs *stat,
2137 char *uuid, int ishow, int cooked,
2138 char *type, int index, int rc)
2140 long long avail, used, total;
2142 char *suffix = "KMGTPEZY";
2143 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2144 char tbuf[3 * sizeof(__u64)];
2145 char ubuf[3 * sizeof(__u64)];
2146 char abuf[3 * sizeof(__u64)];
2147 char rbuf[3 * sizeof(__u64)];
2155 avail = stat->os_ffree;
2156 used = stat->os_files - stat->os_ffree;
2157 total = stat->os_files;
2159 int shift = cooked ? 0 : 10;
2161 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2162 used = ((stat->os_blocks - stat->os_bfree) *
2163 stat->os_bsize) >> shift;
2164 total = (stat->os_blocks * stat->os_bsize) >> shift;
2167 if ((used + avail) > 0)
2168 ratio = (double)used / (double)(used + avail);
2174 cook_val = (double)total;
2177 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2179 sprintf(tbuf, CDF, total);
2181 cook_val = (double)used;
2184 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2186 sprintf(ubuf, CDF, used);
2188 cook_val = (double)avail;
2191 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2193 sprintf(abuf, CDF, avail);
2195 sprintf(tbuf, CDF, total);
2196 sprintf(ubuf, CDF, used);
2197 sprintf(abuf, CDF, avail);
2200 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2201 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2202 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2204 printf("[%s:%d]\n", type, index);
2210 printf(UUF": inactive device\n", uuid);
2213 printf(UUF": %s\n", uuid, strerror(-rc));
2220 struct ll_stat_type {
2225 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2226 int cooked, int lazy)
2228 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2229 struct obd_uuid uuid_buf;
2230 char *poolname = NULL;
2231 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2232 { LL_STATFS_LOV, "OST" },
2234 struct ll_stat_type *tp;
2235 __u64 ost_ffree = 0;
2241 poolname = strchr(pool, '.');
2242 if (poolname != NULL) {
2243 if (strncmp(fsname, pool, strlen(fsname))) {
2244 fprintf(stderr, "filesystem name incorrect\n");
2253 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2254 "UUID", "Inodes", "IUsed", "IFree",
2255 "IUse%", "Mounted on");
2257 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2258 "UUID", cooked ? "bytes" : "1K-blocks",
2259 "Used", "Available", "Use%", "Mounted on");
2261 for (tp = types; tp->st_name != NULL; tp++) {
2262 for (index = 0; ; index++) {
2263 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2264 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2265 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2266 rc = llapi_obd_statfs(mntdir, type, index,
2267 &stat_buf, &uuid_buf);
2274 if (poolname && tp->st_op == LL_STATFS_LOV &&
2275 llapi_search_ost(fsname, poolname,
2276 obd_uuid2str(&uuid_buf)) != 1)
2279 /* the llapi_obd_statfs() call may have returned with
2280 * an error, but if it filled in uuid_buf we will at
2281 * lease use that to print out a message for that OBD.
2282 * If we didn't get anything in the uuid_buf, then fill
2283 * it in so that we can print an error message. */
2284 if (uuid_buf.uuid[0] == '\0')
2285 sprintf(uuid_buf.uuid, "%s%04x",
2286 tp->st_name, index);
2287 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2288 ishow, cooked, tp->st_name, index, rc);
2291 if (tp->st_op == LL_STATFS_LMV) {
2292 sum.os_ffree += stat_buf.os_ffree;
2293 sum.os_files += stat_buf.os_files;
2294 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2295 sum.os_blocks += stat_buf.os_blocks *
2297 sum.os_bfree += stat_buf.os_bfree *
2299 sum.os_bavail += stat_buf.os_bavail *
2301 ost_ffree += stat_buf.os_ffree;
2303 } else if (rc == -EINVAL || rc == -EFAULT) {
2309 /* If we don't have as many objects free on the OST as inodes
2310 * on the MDS, we reduce the total number of inodes to
2311 * compensate, so that the "inodes in use" number is correct.
2312 * Matches ll_statfs_internal() so the results are consistent. */
2313 if (ost_ffree < sum.os_ffree) {
2314 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2315 sum.os_ffree = ost_ffree;
2318 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2323 static int lfs_df(int argc, char **argv)
2325 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2326 int ishow = 0, cooked = 0;
2328 int c, rc = 0, index = 0;
2329 char fsname[PATH_MAX] = "", *pool_name = NULL;
2330 struct option long_opts[] = {
2331 {"pool", required_argument, 0, 'p'},
2332 {"lazy", 0, 0, 'l'},
2336 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2354 if (optind < argc && !realpath(argv[optind], path)) {
2356 fprintf(stderr, "error: invalid path '%s': %s\n",
2357 argv[optind], strerror(-rc));
2361 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2362 /* Check if we have a mount point */
2363 if (mntdir[0] == '\0')
2366 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2367 if (rc || path[0] != '\0')
2369 fsname[0] = '\0'; /* avoid matching in next loop */
2370 mntdir[0] = '\0'; /* avoid matching in next loop */
2376 static int lfs_getname(int argc, char **argv)
2378 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2379 int rc = 0, index = 0, c;
2380 char buf[sizeof(struct obd_uuid)];
2382 while ((c = getopt(argc, argv, "h")) != -1)
2385 if (optind == argc) { /* no paths specified, get all paths. */
2386 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2387 rc = llapi_getname(mntdir, buf, sizeof(buf));
2390 "cannot get name for `%s': %s\n",
2391 mntdir, strerror(-rc));
2395 printf("%s %s\n", buf, mntdir);
2397 path[0] = fsname[0] = mntdir[0] = 0;
2399 } else { /* paths specified, only attempt to search these. */
2400 for (; optind < argc; optind++) {
2401 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2404 "cannot get name for `%s': %s\n",
2405 argv[optind], strerror(-rc));
2409 printf("%s %s\n", buf, argv[optind]);
2415 static int lfs_check(int argc, char **argv)
2418 char mntdir[PATH_MAX] = {'\0'};
2427 obd_types[0] = obd_type1;
2428 obd_types[1] = obd_type2;
2430 if (strcmp(argv[1], "osts") == 0) {
2431 strcpy(obd_types[0], "osc");
2432 } else if (strcmp(argv[1], "mds") == 0) {
2433 strcpy(obd_types[0], "mdc");
2434 } else if (strcmp(argv[1], "servers") == 0) {
2436 strcpy(obd_types[0], "osc");
2437 strcpy(obd_types[1], "mdc");
2439 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2444 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2445 if (rc < 0 || mntdir[0] == '\0') {
2446 fprintf(stderr, "No suitable Lustre mount found\n");
2450 rc = llapi_target_check(num_types, obd_types, mntdir);
2452 fprintf(stderr, "error: %s: %s status failed\n",
2459 static int lfs_join(int argc, char **argv)
2461 fprintf(stderr, "join two lustre files into one.\n"
2462 "obsolete, HEAD does not support it anymore.\n");
2466 #ifdef HAVE_SYS_QUOTA_H
2467 #define ARG2INT(nr, str, msg) \
2470 nr = strtol(str, &endp, 0); \
2472 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2477 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2479 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2480 * returns the value or ULONG_MAX on integer overflow or incorrect format
2482 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2483 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2484 * 3. empty integer value is interpreted as 0
2486 static unsigned long str2sec(const char* timestr)
2488 const char spec[] = "smhdw";
2489 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2490 unsigned long val = 0;
2493 if (strpbrk(timestr, spec) == NULL) {
2494 /* no specifiers inside the time string,
2495 should treat it as an integer value */
2496 val = strtoul(timestr, &tail, 10);
2497 return *tail ? ULONG_MAX : val;
2500 /* format string is XXwXXdXXhXXmXXs */
2506 v = strtoul(timestr, &tail, 10);
2507 if (v == ULONG_MAX || *tail == '\0')
2508 /* value too large (ULONG_MAX or more)
2509 or missing specifier */
2512 ptr = strchr(spec, *tail);
2514 /* unknown specifier */
2519 /* check if product will overflow the type */
2520 if (!(v < ULONG_MAX / mult[ind]))
2523 ADD_OVERFLOW(val, mult[ind] * v);
2524 if (val == ULONG_MAX)
2536 #define ARG2ULL(nr, str, def_units) \
2538 unsigned long long limit, units = def_units; \
2541 rc = llapi_parse_size(str, &limit, &units, 1); \
2543 fprintf(stderr, "error: bad limit value %s\n", str); \
2549 static inline int has_times_option(int argc, char **argv)
2553 for (i = 1; i < argc; i++)
2554 if (!strcmp(argv[i], "-t"))
2560 int lfs_setquota_times(int argc, char **argv)
2563 struct if_quotactl qctl;
2564 char *mnt, *obd_type = (char *)qctl.obd_type;
2565 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2566 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2567 struct option long_opts[] = {
2568 {"block-grace", required_argument, 0, 'b'},
2569 {"group", no_argument, 0, 'g'},
2570 {"inode-grace", required_argument, 0, 'i'},
2571 {"times", no_argument, 0, 't'},
2572 {"user", no_argument, 0, 'u'},
2576 memset(&qctl, 0, sizeof(qctl));
2577 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2578 qctl.qc_type = UGQUOTA;
2580 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2584 if (qctl.qc_type != UGQUOTA) {
2585 fprintf(stderr, "error: -u and -g can't be used "
2586 "more than once\n");
2589 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2592 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2593 fprintf(stderr, "error: bad block-grace: %s\n",
2597 dqb->dqb_valid |= QIF_BTIME;
2600 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2601 fprintf(stderr, "error: bad inode-grace: %s\n",
2605 dqb->dqb_valid |= QIF_ITIME;
2607 case 't': /* Yes, of course! */
2609 default: /* getopt prints error message for us when opterr != 0 */
2614 if (qctl.qc_type == UGQUOTA) {
2615 fprintf(stderr, "error: neither -u nor -g specified\n");
2619 if (optind != argc - 1) {
2620 fprintf(stderr, "error: unexpected parameters encountered\n");
2625 rc = llapi_quotactl(mnt, &qctl);
2628 fprintf(stderr, "%s %s ", obd_type,
2629 obd_uuid2str(&qctl.obd_uuid));
2630 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2637 #define BSLIMIT (1 << 0)
2638 #define BHLIMIT (1 << 1)
2639 #define ISLIMIT (1 << 2)
2640 #define IHLIMIT (1 << 3)
2642 int lfs_setquota(int argc, char **argv)
2645 struct if_quotactl qctl;
2646 char *mnt, *obd_type = (char *)qctl.obd_type;
2647 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2648 struct option long_opts[] = {
2649 {"block-softlimit", required_argument, 0, 'b'},
2650 {"block-hardlimit", required_argument, 0, 'B'},
2651 {"group", required_argument, 0, 'g'},
2652 {"inode-softlimit", required_argument, 0, 'i'},
2653 {"inode-hardlimit", required_argument, 0, 'I'},
2654 {"user", required_argument, 0, 'u'},
2657 unsigned limit_mask = 0;
2660 if (has_times_option(argc, argv))
2661 return lfs_setquota_times(argc, argv);
2663 memset(&qctl, 0, sizeof(qctl));
2664 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2665 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2666 * so it can be used as a marker that qc_type
2667 * isn't reinitialized from command line */
2669 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2673 if (qctl.qc_type != UGQUOTA) {
2674 fprintf(stderr, "error: -u and -g can't be used"
2675 " more than once\n");
2678 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2679 rc = name2id(&qctl.qc_id, optarg,
2680 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2682 qctl.qc_id = strtoul(optarg, &endptr, 10);
2683 if (*endptr != '\0') {
2684 fprintf(stderr, "error: can't find id "
2685 "for name %s\n", optarg);
2691 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2692 dqb->dqb_bsoftlimit >>= 10;
2693 limit_mask |= BSLIMIT;
2694 if (dqb->dqb_bsoftlimit &&
2695 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2696 fprintf(stderr, "warning: block softlimit is "
2697 "smaller than the miminal qunit size, "
2698 "please see the help of setquota or "
2699 "Lustre manual for details.\n");
2702 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2703 dqb->dqb_bhardlimit >>= 10;
2704 limit_mask |= BHLIMIT;
2705 if (dqb->dqb_bhardlimit &&
2706 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2707 fprintf(stderr, "warning: block hardlimit is "
2708 "smaller than the miminal qunit size, "
2709 "please see the help of setquota or "
2710 "Lustre manual for details.\n");
2713 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2714 limit_mask |= ISLIMIT;
2715 if (dqb->dqb_isoftlimit &&
2716 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2717 fprintf(stderr, "warning: inode softlimit is "
2718 "smaller than the miminal qunit size, "
2719 "please see the help of setquota or "
2720 "Lustre manual for details.\n");
2723 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2724 limit_mask |= IHLIMIT;
2725 if (dqb->dqb_ihardlimit &&
2726 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2727 fprintf(stderr, "warning: inode hardlimit is "
2728 "smaller than the miminal qunit size, "
2729 "please see the help of setquota or "
2730 "Lustre manual for details.\n");
2732 default: /* getopt prints error message for us when opterr != 0 */
2737 if (qctl.qc_type == UGQUOTA) {
2738 fprintf(stderr, "error: neither -u nor -g was specified\n");
2742 if (limit_mask == 0) {
2743 fprintf(stderr, "error: at least one limit must be specified\n");
2747 if (optind != argc - 1) {
2748 fprintf(stderr, "error: unexpected parameters encountered\n");
2754 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2755 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2756 /* sigh, we can't just set blimits/ilimits */
2757 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2758 .qc_type = qctl.qc_type,
2759 .qc_id = qctl.qc_id};
2761 rc = llapi_quotactl(mnt, &tmp_qctl);
2763 fprintf(stderr, "error: setquota failed while retrieving"
2764 " current quota settings (%s)\n",
2769 if (!(limit_mask & BHLIMIT))
2770 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2771 if (!(limit_mask & BSLIMIT))
2772 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2773 if (!(limit_mask & IHLIMIT))
2774 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2775 if (!(limit_mask & ISLIMIT))
2776 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2778 /* Keep grace times if we have got no softlimit arguments */
2779 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2780 dqb->dqb_valid |= QIF_BTIME;
2781 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2784 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2785 dqb->dqb_valid |= QIF_ITIME;
2786 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2790 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2791 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2793 rc = llapi_quotactl(mnt, &qctl);
2796 fprintf(stderr, "%s %s ", obd_type,
2797 obd_uuid2str(&qctl.obd_uuid));
2798 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2805 static inline char *type2name(int check_type)
2807 if (check_type == USRQUOTA)
2809 else if (check_type == GRPQUOTA)
2815 /* Converts seconds value into format string
2816 * result is returned in buf
2818 * 1. result is in descenting order: 1w2d3h4m5s
2819 * 2. zero fields are not filled (except for p. 3): 5d1s
2820 * 3. zero seconds value is presented as "0s"
2822 static char * __sec2str(time_t seconds, char *buf)
2824 const char spec[] = "smhdw";
2825 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2830 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2831 c = seconds / mult[i];
2833 if (c > 0 || (i == 0 && buf == tail))
2834 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2842 static void sec2str(time_t seconds, char *buf, int rc)
2849 tail = __sec2str(seconds, tail);
2851 if (rc && tail - buf < 39) {
2857 static void diff2str(time_t seconds, char *buf, time_t now)
2863 if (seconds <= now) {
2864 strcpy(buf, "none");
2867 __sec2str(seconds - now, buf);
2870 static void print_quota_title(char *name, struct if_quotactl *qctl,
2871 bool human_readable)
2873 printf("Disk quotas for %s %s (%cid %u):\n",
2874 type2name(qctl->qc_type), name,
2875 *type2name(qctl->qc_type), qctl->qc_id);
2876 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2877 "Filesystem", human_readable ? "used" : "kbytes",
2878 "quota", "limit", "grace",
2879 "files", "quota", "limit", "grace");
2882 static void kbytes2str(__u64 num, char *buf, bool h)
2885 sprintf(buf, LPU64, num);
2888 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2890 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2892 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2894 sprintf(buf, LPU64"%s", num, "k");
2898 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2905 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2906 int bover = 0, iover = 0;
2907 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2912 if (dqb->dqb_bhardlimit &&
2913 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2915 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2916 if (dqb->dqb_btime > now) {
2923 if (dqb->dqb_ihardlimit &&
2924 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2926 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2927 if (dqb->dqb_itime > now) {
2935 if (strlen(mnt) > 15)
2936 printf("%s\n%15s", mnt, "");
2938 printf("%15s", mnt);
2941 diff2str(dqb->dqb_btime, timebuf, now);
2943 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2944 if (rc == -EREMOTEIO)
2945 sprintf(numbuf[0], "%s*", strbuf);
2947 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2948 "%s" : "[%s]", strbuf);
2950 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2951 if (type == QC_GENERAL)
2952 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2953 "%s" : "[%s]", strbuf);
2955 sprintf(numbuf[1], "%s", "-");
2957 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2958 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2959 "%s" : "[%s]", strbuf);
2961 printf(" %7s%c %6s %7s %7s",
2962 numbuf[0], bover ? '*' : ' ', numbuf[1],
2963 numbuf[2], bover > 1 ? timebuf : "-");
2966 diff2str(dqb->dqb_itime, timebuf, now);
2968 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2969 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2971 if (type == QC_GENERAL)
2972 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2973 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2975 sprintf(numbuf[1], "%s", "-");
2977 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2978 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2980 if (type != QC_OSTIDX)
2981 printf(" %7s%c %6s %7s %7s",
2982 numbuf[0], iover ? '*' : ' ', numbuf[1],
2983 numbuf[2], iover > 1 ? timebuf : "-");
2985 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2988 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2989 qctl->qc_cmd == Q_GETOINFO) {
2993 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2994 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2995 printf("Block grace time: %s; Inode grace time: %s\n",
2996 bgtimebuf, igtimebuf);
3000 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3001 bool h, __u64 *total)
3003 int rc = 0, rc1 = 0, count = 0;
3004 __u32 valid = qctl->qc_valid;
3006 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3008 fprintf(stderr, "can not get %s count: %s\n",
3009 is_mdt ? "mdt": "ost", strerror(-rc));
3013 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3014 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3015 rc = llapi_quotactl(mnt, qctl);
3017 /* It is remote client case. */
3018 if (-rc == EOPNOTSUPP) {
3025 fprintf(stderr, "quotactl %s%d failed.\n",
3026 is_mdt ? "mdt": "ost", qctl->qc_idx);
3030 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3031 qctl->qc_valid, 0, h);
3032 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3033 qctl->qc_dqblk.dqb_bhardlimit;
3036 qctl->qc_valid = valid;
3040 static int lfs_quota(int argc, char **argv)
3043 char *mnt, *name = NULL;
3044 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3045 .qc_type = UGQUOTA };
3046 char *obd_type = (char *)qctl.obd_type;
3047 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3048 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3049 verbose = 0, pass = 0, quiet = 0, inacc;
3051 __u32 valid = QC_GENERAL, idx = 0;
3052 __u64 total_ialloc = 0, total_balloc = 0;
3053 bool human_readable = false;
3055 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3058 if (qctl.qc_type != UGQUOTA) {
3059 fprintf(stderr, "error: use either -u or -g\n");
3062 qctl.qc_type = USRQUOTA;
3065 if (qctl.qc_type != UGQUOTA) {
3066 fprintf(stderr, "error: use either -u or -g\n");
3069 qctl.qc_type = GRPQUOTA;
3072 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3075 valid = qctl.qc_valid = QC_UUID;
3076 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3079 valid = qctl.qc_valid = QC_MDTIDX;
3080 idx = qctl.qc_idx = atoi(optarg);
3083 valid = qctl.qc_valid = QC_OSTIDX;
3084 idx = qctl.qc_idx = atoi(optarg);
3093 human_readable = true;
3096 fprintf(stderr, "error: %s: option '-%c' "
3097 "unrecognized\n", argv[0], c);
3102 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3103 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3104 optind == argc - 1) {
3106 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3107 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3108 qctl.qc_valid = valid;
3111 qctl.qc_type = USRQUOTA;
3112 qctl.qc_id = geteuid();
3114 qctl.qc_type = GRPQUOTA;
3115 qctl.qc_id = getegid();
3117 rc = id2name(&name, qctl.qc_id,
3118 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3121 /* lfs quota -u username /path/to/lustre/mount */
3122 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3123 /* options should be followed by u/g-name and mntpoint */
3124 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3125 fprintf(stderr, "error: missing quota argument(s)\n");
3129 name = argv[optind++];
3130 rc = name2id(&qctl.qc_id, name,
3131 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3133 qctl.qc_id = strtoul(name, &endptr, 10);
3134 if (*endptr != '\0') {
3135 fprintf(stderr, "error: can't find id for name "
3140 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3141 fprintf(stderr, "error: missing quota info argument(s)\n");
3147 rc1 = llapi_quotactl(mnt, &qctl);
3151 fprintf(stderr, "%s quotas are not enabled.\n",
3152 qctl.qc_type == USRQUOTA ? "user" : "group");
3155 fprintf(stderr, "Permission denied.\n");
3157 /* We already got a "No such file..." message. */
3160 fprintf(stderr, "Unexpected quotactl error: %s\n",
3165 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3166 print_quota_title(name, &qctl, human_readable);
3168 if (rc1 && *obd_type)
3169 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3171 if (qctl.qc_valid != QC_GENERAL)
3174 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3175 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3176 (QIF_LIMITS|QIF_USAGE));
3178 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3180 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3184 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3186 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3188 kbytes2str(total_balloc, strbuf, human_readable);
3189 printf("Total allocated inode limit: "LPU64", total "
3190 "allocated block limit: %s\n", total_ialloc, strbuf);
3193 if (rc1 || rc2 || rc3 || inacc)
3194 printf("Some errors happened when getting quota info. "
3195 "Some devices may be not working or deactivated. "
3196 "The data in \"[]\" is inaccurate.\n");
3204 #endif /* HAVE_SYS_QUOTA_H! */
3206 static int flushctx_ioctl(char *mp)
3210 fd = open(mp, O_RDONLY);
3212 fprintf(stderr, "flushctx: error open %s: %s\n",
3213 mp, strerror(errno));
3217 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3219 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3220 mp, strerror(errno));
3226 static int lfs_flushctx(int argc, char **argv)
3228 int kdestroy = 0, c;
3229 char mntdir[PATH_MAX] = {'\0'};
3233 while ((c = getopt(argc, argv, "k")) != -1) {
3239 fprintf(stderr, "error: %s: option '-%c' "
3240 "unrecognized\n", argv[0], c);
3246 if ((rc = system("kdestroy > /dev/null")) != 0) {
3247 rc = WEXITSTATUS(rc);
3248 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3252 if (optind >= argc) {
3253 /* flush for all mounted lustre fs. */
3254 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3255 /* Check if we have a mount point */
3256 if (mntdir[0] == '\0')
3259 if (flushctx_ioctl(mntdir))
3262 mntdir[0] = '\0'; /* avoid matching in next loop */
3265 /* flush fs as specified */
3266 while (optind < argc) {
3267 if (flushctx_ioctl(argv[optind++]))
3274 static int lfs_lsetfacl(int argc, char **argv)
3277 return(llapi_lsetfacl(argc, argv));
3280 static int lfs_lgetfacl(int argc, char **argv)
3283 return(llapi_lgetfacl(argc, argv));
3286 static int lfs_rsetfacl(int argc, char **argv)
3289 return(llapi_rsetfacl(argc, argv));
3292 static int lfs_rgetfacl(int argc, char **argv)
3295 return(llapi_rgetfacl(argc, argv));
3298 static int lfs_cp(int argc, char **argv)
3300 return(llapi_cp(argc, argv));
3303 static int lfs_ls(int argc, char **argv)
3305 return(llapi_ls(argc, argv));
3308 static int lfs_changelog(int argc, char **argv)
3310 void *changelog_priv;
3311 struct changelog_rec *rec;
3312 long long startrec = 0, endrec = 0;
3314 struct option long_opts[] = {
3315 {"follow", no_argument, 0, 'f'},
3318 char short_opts[] = "f";
3321 while ((rc = getopt_long(argc, argv, short_opts,
3322 long_opts, NULL)) != -1) {
3330 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3331 argv[0], argv[optind - 1]);
3338 mdd = argv[optind++];
3340 startrec = strtoll(argv[optind++], NULL, 10);
3342 endrec = strtoll(argv[optind++], NULL, 10);
3344 rc = llapi_changelog_start(&changelog_priv,
3345 CHANGELOG_FLAG_BLOCK |
3346 CHANGELOG_FLAG_JOBID |
3347 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3350 fprintf(stderr, "Can't start changelog: %s\n",
3351 strerror(errno = -rc));
3355 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3359 if (endrec && rec->cr_index > endrec) {
3360 llapi_changelog_free(&rec);
3363 if (rec->cr_index < startrec) {
3364 llapi_changelog_free(&rec);
3368 secs = rec->cr_time >> 30;
3369 gmtime_r(&secs, &ts);
3370 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3371 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3372 changelog_type2str(rec->cr_type),
3373 ts.tm_hour, ts.tm_min, ts.tm_sec,
3374 (int)(rec->cr_time & ((1<<30) - 1)),
3375 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3376 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3378 if (rec->cr_flags & CLF_JOBID) {
3379 struct changelog_ext_jobid *jid =
3380 changelog_rec_jobid(rec);
3382 if (jid->cr_jobid[0] != '\0')
3383 printf(" j=%s", jid->cr_jobid);
3386 if (rec->cr_namelen)
3387 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3388 rec->cr_namelen, changelog_rec_name(rec));
3390 if (rec->cr_flags & CLF_RENAME) {
3391 struct changelog_ext_rename *rnm =
3392 changelog_rec_rename(rec);
3394 if (!fid_is_zero(&rnm->cr_sfid))
3395 printf(" s="DFID" sp="DFID" %.*s",
3396 PFID(&rnm->cr_sfid),
3397 PFID(&rnm->cr_spfid),
3398 (int)changelog_rec_snamelen(rec),
3399 changelog_rec_sname(rec));
3403 llapi_changelog_free(&rec);
3406 llapi_changelog_fini(&changelog_priv);
3409 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3411 return (rc == 1 ? 0 : rc);
3414 static int lfs_changelog_clear(int argc, char **argv)
3422 endrec = strtoll(argv[3], NULL, 10);
3424 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3426 fprintf(stderr, "%s error: %s\n", argv[0],
3427 strerror(errno = -rc));
3431 static int lfs_fid2path(int argc, char **argv)
3433 struct option long_opts[] = {
3434 {"cur", no_argument, 0, 'c'},
3435 {"link", required_argument, 0, 'l'},
3436 {"rec", required_argument, 0, 'r'},
3439 char short_opts[] = "cl:r:";
3440 char *device, *fid, *path;
3441 long long recno = -1;
3447 while ((rc = getopt_long(argc, argv, short_opts,
3448 long_opts, NULL)) != -1) {
3454 linkno = strtol(optarg, NULL, 10);
3457 recno = strtoll(optarg, NULL, 10);
3462 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3463 argv[0], argv[optind - 1]);
3471 device = argv[optind++];
3472 path = calloc(1, PATH_MAX);
3474 fprintf(stderr, "error: Not enough memory\n");
3479 while (optind < argc) {
3480 fid = argv[optind++];
3482 lnktmp = (linkno >= 0) ? linkno : 0;
3484 int oldtmp = lnktmp;
3485 long long rectmp = recno;
3487 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3490 fprintf(stderr, "%s: error on FID %s: %s\n",
3491 argv[0], fid, strerror(errno = -rc2));
3498 fprintf(stdout, "%lld ", rectmp);
3499 if (device[0] == '/') {
3500 fprintf(stdout, "%s", device);
3501 if (device[strlen(device) - 1] != '/')
3502 fprintf(stdout, "/");
3503 } else if (path[0] == '\0') {
3504 fprintf(stdout, "/");
3506 fprintf(stdout, "%s\n", path);
3509 /* specified linkno */
3511 if (oldtmp == lnktmp)
3521 static int lfs_path2fid(int argc, char **argv)
3523 struct option long_opts[] = {
3524 {"parents", no_argument, 0, 'p'},
3528 const char short_opts[] = "p";
3529 const char *sep = "";
3532 bool show_parents = false;
3534 while ((rc = getopt_long(argc, argv, short_opts,
3535 long_opts, NULL)) != -1) {
3538 show_parents = true;
3541 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3542 argv[0], argv[optind - 1]);
3547 if (optind > argc - 1)
3549 else if (optind < argc - 1)
3553 for (path = argv + optind; *path != NULL; path++) {
3555 if (!show_parents) {
3556 err = llapi_path2fid(*path, &fid);
3558 printf("%s%s"DFID"\n",
3559 *sep != '\0' ? *path : "", sep,
3562 char name[NAME_MAX + 1];
3563 unsigned int linkno = 0;
3565 while ((err = llapi_path2parent(*path, linkno, &fid,
3566 name, sizeof(name))) == 0) {
3567 if (*sep != '\0' && linkno == 0)
3568 printf("%s%s", *path, sep);
3570 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3575 /* err == -ENODATA is end-of-loop */
3576 if (linkno > 0 && err == -ENODATA) {
3583 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3584 argv[0], show_parents ? "parent " : "", *path,
3596 static int lfs_data_version(int argc, char **argv)
3603 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3608 while ((c = getopt(argc, argv, "nrw")) != -1) {
3611 data_version_flags = 0;
3614 data_version_flags |= LL_DV_RD_FLUSH;
3617 data_version_flags |= LL_DV_WR_FLUSH;
3626 path = argv[optind];
3627 fd = open(path, O_RDONLY);
3629 err(errno, "cannot open file %s", path);
3631 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3633 err(errno, "cannot get version for %s", path);
3635 printf(LPU64 "\n", data_version);
3641 static int lfs_hsm_state(int argc, char **argv)
3646 struct hsm_user_state hus;
3654 rc = llapi_hsm_state_get(path, &hus);
3656 fprintf(stderr, "can't get hsm state for %s: %s\n",
3657 path, strerror(errno = -rc));
3661 /* Display path name and status flags */
3662 printf("%s: (0x%08x)", path, hus.hus_states);
3664 if (hus.hus_states & HS_RELEASED)
3665 printf(" released");
3666 if (hus.hus_states & HS_EXISTS)
3668 if (hus.hus_states & HS_DIRTY)
3670 if (hus.hus_states & HS_ARCHIVED)
3671 printf(" archived");
3672 /* Display user-settable flags */
3673 if (hus.hus_states & HS_NORELEASE)
3674 printf(" never_release");
3675 if (hus.hus_states & HS_NOARCHIVE)
3676 printf(" never_archive");
3677 if (hus.hus_states & HS_LOST)
3678 printf(" lost_from_hsm");
3680 if (hus.hus_archive_id != 0)
3681 printf(", archive_id:%d", hus.hus_archive_id);
3684 } while (++i < argc);
3689 #define LFS_HSM_SET 0
3690 #define LFS_HSM_CLEAR 1
3693 * Generic function to set or clear HSM flags.
3694 * Used by hsm_set and hsm_clear.
3696 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3698 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3700 struct option long_opts[] = {
3701 {"lost", 0, 0, 'l'},
3702 {"norelease", 0, 0, 'r'},
3703 {"noarchive", 0, 0, 'a'},
3704 {"archived", 0, 0, 'A'},
3705 {"dirty", 0, 0, 'd'},
3706 {"exists", 0, 0, 'e'},
3709 char short_opts[] = "lraAde";
3717 while ((c = getopt_long(argc, argv, short_opts,
3718 long_opts, NULL)) != -1) {
3724 mask |= HS_NOARCHIVE;
3727 mask |= HS_ARCHIVED;
3730 mask |= HS_NORELEASE;
3741 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3742 argv[0], argv[optind - 1]);
3747 /* User should have specified a flag */
3751 while (optind < argc) {
3753 path = argv[optind];
3755 /* If mode == 0, this means we apply the mask. */
3756 if (mode == LFS_HSM_SET)
3757 rc = llapi_hsm_state_set(path, mask, 0, 0);
3759 rc = llapi_hsm_state_set(path, 0, mask, 0);
3762 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3763 path, strerror(errno = -rc));
3772 static int lfs_hsm_action(int argc, char **argv)
3777 struct hsm_current_action hca;
3778 struct hsm_extent he;
3779 enum hsm_user_action hua;
3780 enum hsm_progress_states hps;
3788 rc = llapi_hsm_current_action(path, &hca);
3790 fprintf(stderr, "can't get hsm action for %s: %s\n",
3791 path, strerror(errno = -rc));
3794 he = hca.hca_location;
3795 hua = hca.hca_action;
3796 hps = hca.hca_state;
3798 printf("%s: %s", path, hsm_user_action2name(hua));
3800 /* Skip file without action */
3801 if (hca.hca_action == HUA_NONE) {
3806 printf(" %s ", hsm_progress_state2name(hps));
3808 if ((hps == HPS_RUNNING) &&
3809 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3810 printf("(%llu bytes moved)\n",
3811 (unsigned long long)he.length);
3812 else if ((he.offset + he.length) == LUSTRE_EOF)
3813 printf("(from %llu to EOF)\n",
3814 (unsigned long long)he.offset);
3816 printf("(from %llu to %llu)\n",
3817 (unsigned long long)he.offset,
3818 (unsigned long long)(he.offset + he.length));
3820 } while (++i < argc);
3825 static int lfs_hsm_set(int argc, char **argv)
3827 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3830 static int lfs_hsm_clear(int argc, char **argv)
3832 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3836 * Check file state and return its fid, to be used by lfs_hsm_request().
3838 * \param[in] file Path to file to check
3839 * \param[in,out] fid Pointer to allocated lu_fid struct.
3840 * \param[in,out] last_dev Pointer to last device id used.
3842 * \return 0 on success.
3844 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3850 rc = lstat(file, &st);
3852 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3855 /* Checking for regular file as archiving as posix copytool
3856 * rejects archiving files other than regular files
3858 if (!S_ISREG(st.st_mode)) {
3859 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3862 /* A request should be ... */
3863 if (*last_dev != st.st_dev && *last_dev != 0) {
3864 fprintf(stderr, "All files should be "
3865 "on the same filesystem: %s\n", file);
3868 *last_dev = st.st_dev;
3870 rc = llapi_path2fid(file, fid);
3872 fprintf(stderr, "Cannot read FID of %s: %s\n",
3873 file, strerror(-rc));
3879 /* Fill an HSM HUR item with a given file name.
3881 * If mntpath is set, then the filename is actually a FID, and no
3882 * lookup on the filesystem will be performed.
3884 * \param[in] hur the user request to fill
3885 * \param[in] idx index of the item inside the HUR to fill
3886 * \param[in] mntpath mountpoint of Lustre
3887 * \param[in] fname filename (if mtnpath is NULL)
3888 * or FID (if mntpath is set)
3889 * \param[in] last_dev pointer to last device id used
3891 * \retval 0 on success
3892 * \retval CMD_HELP or a negative errno on error
3894 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3895 const char *mntpath, const char *fname,
3898 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3901 hui->hui_extent.length = -1;
3903 if (mntpath != NULL) {
3906 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3910 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3915 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3919 hur->hur_request.hr_itemcount++;
3924 static int lfs_hsm_request(int argc, char **argv, int action)
3926 struct option long_opts[] = {
3927 {"filelist", 1, 0, 'l'},
3928 {"data", 1, 0, 'D'},
3929 {"archive", 1, 0, 'a'},
3930 {"mntpath", 1, 0, 'm'},
3934 char short_opts[] = "l:D:a:m:";
3935 struct hsm_user_request *hur, *oldhur;
3940 char *filelist = NULL;
3941 char fullpath[PATH_MAX];
3942 char *opaque = NULL;
3946 int nbfile_alloc = 0;
3947 char *some_file = NULL;
3948 char *mntpath = NULL;
3954 while ((c = getopt_long(argc, argv, short_opts,
3955 long_opts, NULL)) != -1) {
3964 if (action != HUA_ARCHIVE &&
3965 action != HUA_REMOVE) {
3967 "error: -a is supported only "
3968 "when archiving or removing\n");
3971 archive_id = atoi(optarg);
3974 if (some_file == NULL) {
3976 some_file = strdup(optarg);
3982 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3983 argv[0], argv[optind - 1]);
3988 /* All remaining args are files, so we have at least nbfile */
3989 nbfile = argc - optind;
3991 if ((nbfile == 0) && (filelist == NULL))
3995 opaque_len = strlen(opaque);
3997 /* Alloc the request structure with enough place to store all files
3998 * from command line. */
3999 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4001 fprintf(stderr, "Cannot create the request: %s\n",
4005 nbfile_alloc = nbfile;
4007 hur->hur_request.hr_action = action;
4008 hur->hur_request.hr_archive_id = archive_id;
4009 hur->hur_request.hr_flags = 0;
4011 /* All remaining args are files, add them */
4012 if (nbfile != 0 && some_file == NULL)
4013 some_file = strdup(argv[optind]);
4015 for (i = 0; i < nbfile; i++) {
4016 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4022 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4024 /* If a filelist was specified, read the filelist from it. */
4025 if (filelist != NULL) {
4026 fp = fopen(filelist, "r");
4028 fprintf(stderr, "Cannot read the file list %s: %s\n",
4029 filelist, strerror(errno));
4034 while ((rc = getline(&line, &len, fp)) != -1) {
4035 /* If allocated buffer was too small, get something
4037 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4040 nbfile_alloc = nbfile_alloc * 2 + 1;
4042 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4045 fprintf(stderr, "hsm: cannot allocate "
4046 "the request: %s\n",
4053 size = hur_len(oldhur);
4055 fprintf(stderr, "hsm: cannot allocate "
4056 "%u files + %u bytes data\n",
4057 oldhur->hur_request.hr_itemcount,
4058 oldhur->hur_request.hr_data_len);
4065 memcpy(hur, oldhur, size);
4070 if (line[strlen(line) - 1] == '\n')
4071 line[strlen(line) - 1] = '\0';
4073 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4074 mntpath, line, &last_dev);
4080 if (some_file == NULL) {
4090 /* If a --data was used, add it to the request */
4091 hur->hur_request.hr_data_len = opaque_len;
4093 memcpy(hur_data(hur), opaque, opaque_len);
4095 /* Send the HSM request */
4096 if (realpath(some_file, fullpath) == NULL) {
4097 fprintf(stderr, "Could not find path '%s': %s\n",
4098 some_file, strerror(errno));
4100 rc = llapi_hsm_request(fullpath, hur);
4102 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4103 some_file, strerror(-rc));
4113 static int lfs_hsm_archive(int argc, char **argv)
4115 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4118 static int lfs_hsm_restore(int argc, char **argv)
4120 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4123 static int lfs_hsm_release(int argc, char **argv)
4125 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4128 static int lfs_hsm_remove(int argc, char **argv)
4130 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4133 static int lfs_hsm_cancel(int argc, char **argv)
4135 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4138 static int lfs_swap_layouts(int argc, char **argv)
4143 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4144 SWAP_LAYOUTS_KEEP_MTIME |
4145 SWAP_LAYOUTS_KEEP_ATIME);
4148 int main(int argc, char **argv)
4152 /* Ensure that liblustreapi constructor has run */
4153 if (!liblustreapi_initialized)
4154 fprintf(stderr, "liblustreapi was not properly initialized\n");
4158 Parser_init("lfs > ", cmdlist);
4160 progname = argv[0]; /* Used in error messages */
4162 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4164 rc = Parser_commands();
4167 return rc < 0 ? -rc : rc;
4170 #ifdef _LUSTRE_IDL_H_
4171 /* Everything we need here should be included by lustreapi.h. */
4172 # error "lfs should not depend on lustre_idl.h"
4173 #endif /* _LUSTRE_IDL_H_ */