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, 2015, 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 ") \
151 " [--non-block|-n]\n" \
155 "\tblock: Block file access during data migration (default)\n" \
156 "\tnon-block: Abort migrations if concurrent access is detected\n" \
158 static const char *progname;
159 static bool file_lease_supported = true;
161 /* all available commands */
162 command_t cmdlist[] = {
163 {"setstripe", lfs_setstripe, 0,
164 "Create a new file with a specific striping pattern or\n"
165 "set the default striping pattern on an existing directory or\n"
166 "delete the default striping pattern from an existing directory\n"
167 "usage: setstripe -d <directory> (to delete default striping)\n"\
170 {"getstripe", lfs_getstripe, 0,
171 "To list the striping info for a given file or files in a\n"
172 "directory or recursively for all files in a directory tree.\n"
173 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
174 " [--stripe-count|-c] [--stripe-index|-i]\n"
175 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
176 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
178 " <directory|filename> ..."},
179 {"setdirstripe", lfs_setdirstripe, 0,
180 "To create a striped directory on a specified MDT. This can only\n"
181 "be done on MDT0 with the right of administrator.\n"
182 "usage: setdirstripe <--count|-c stripe_count>\n"
183 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
184 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
185 "\tstripe_count: stripe count of the striped directory\n"
186 "\tmdt_index: MDT index of first stripe\n"
187 "\thash_type: hash type of the striped directory. Hash types:\n"
188 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
189 " all_char sum of characters % MDT_COUNT (not recommended)\n"
190 "\tdefault_stripe: set default dirstripe of the directory\n"
191 "\tmode: the mode of the directory\n"},
192 {"getdirstripe", lfs_getdirstripe, 0,
193 "To list the striping info for a given directory\n"
194 "or recursively for all directories in a directory tree.\n"
195 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
196 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
197 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
198 {"mkdir", lfs_setdirstripe, 0,
199 "To create a striped directory on a specified MDT. This can only\n"
200 "be done on MDT0 with the right of administrator.\n"
201 "usage: mkdir <--count|-c stripe_count>\n"
202 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
203 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
204 "\tstripe_count: stripe count of the striped directory\n"
205 "\tmdt_index: MDT index of first stripe\n"
206 "\thash_type: hash type of the striped directory. Hash types:\n"
207 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
208 " all_char sum of characters % MDT_COUNT (not recommended)\n"
209 "\tdefault_stripe: set default dirstripe of the directory\n"
210 "\tmode: the mode of the directory\n"},
211 {"rm_entry", lfs_rmentry, 0,
212 "To remove the name entry of the remote directory. Note: This\n"
213 "command will only delete the name entry, i.e. the remote directory\n"
214 "will become inaccessable after this command. This can only be done\n"
215 "by the administrator\n"
216 "usage: rm_entry <dir>\n"},
217 {"pool_list", lfs_poollist, 0,
218 "List pools or pool OSTs\n"
219 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
220 {"find", lfs_find, 0,
221 "find files matching given attributes recursively in directory tree.\n"
222 "usage: find <directory|filename> ...\n"
223 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
224 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
225 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
226 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
227 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
228 " [[!] --stripe-count|-c [+-]<stripes>]\n"
229 " [[!] --stripe-index|-i <index,...>]\n"
230 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
231 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
232 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
233 " [[!] --layout|-L released,raid0]\n"
234 "\t !: used before an option indicates 'NOT' requested attribute\n"
235 "\t -: used before a value indicates 'AT MOST' requested value\n"
236 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
237 {"check", lfs_check, 0,
238 "Display the status of MDS or OSTs (as specified in the command)\n"
239 "or all the servers (MDS and OSTs).\n"
240 "usage: check <osts|mds|servers>"},
241 {"join", lfs_join, 0,
242 "join two lustre files into one.\n"
243 "obsolete, HEAD does not support it anymore.\n"},
244 {"osts", lfs_osts, 0, "list OSTs connected to client "
245 "[for specified path only]\n" "usage: osts [path]"},
246 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
247 "[for specified path only]\n" "usage: mdts [path]"},
249 "report filesystem disk space usage or inodes usage"
250 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
251 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
252 {"getname", lfs_getname, 0, "list instances and specified mount points "
253 "[for specified path only]\n"
254 "Usage: getname [-h]|[path ...] "},
255 #ifdef HAVE_SYS_QUOTA_H
256 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
257 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
258 " -b <block-softlimit> -B <block-hardlimit>\n"
259 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
260 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
261 " [--block-softlimit <block-softlimit>]\n"
262 " [--block-hardlimit <block-hardlimit>]\n"
263 " [--inode-softlimit <inode-softlimit>]\n"
264 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
265 " setquota [-t] <-u|--user|-g|--group>\n"
266 " [--block-grace <block-grace>]\n"
267 " [--inode-grace <inode-grace>] <filesystem>\n"
268 " -b can be used instead of --block-softlimit/--block-grace\n"
269 " -B can be used instead of --block-hardlimit\n"
270 " -i can be used instead of --inode-softlimit/--inode-grace\n"
271 " -I can be used instead of --inode-hardlimit\n\n"
272 "Note: The total quota space will be split into many qunits and\n"
273 " balanced over all server targets, the minimal qunit size is\n"
274 " 1M bytes for block space and 1K inodes for inode space.\n\n"
275 " Quota space rebalancing process will stop when this mininum\n"
276 " value is reached. As a result, quota exceeded can be returned\n"
277 " while many targets still have 1MB or 1K inodes of spare\n"
279 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
280 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
282 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
283 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
285 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
286 "usage: flushctx [-k] [mountpoint...]"},
287 {"lsetfacl", lfs_lsetfacl, 0,
288 "Remote user setfacl for user/group on the same remote client.\n"
289 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
290 {"lgetfacl", lfs_lgetfacl, 0,
291 "Remote user getfacl for user/group on the same remote client.\n"
292 "usage: lgetfacl [-dRLPvh] file ..."},
293 {"rsetfacl", lfs_rsetfacl, 0,
294 "Remote user setfacl for user/group on other clients.\n"
295 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
296 {"rgetfacl", lfs_rgetfacl, 0,
297 "Remote user getfacl for user/group on other clients.\n"
298 "usage: rgetfacl [-dRLPvh] file ..."},
300 "Remote user copy files and directories.\n"
301 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
303 "Remote user list directory contents.\n"
304 "usage: ls [OPTION]... [FILE]..."},
305 {"changelog", lfs_changelog, 0,
306 "Show the metadata changes on an MDT."
307 "\nusage: changelog <mdtname> [startrec [endrec]]"},
308 {"changelog_clear", lfs_changelog_clear, 0,
309 "Indicate that old changelog records up to <endrec> are no longer of "
310 "interest to consumer <id>, allowing the system to free up space.\n"
311 "An <endrec> of 0 means all records.\n"
312 "usage: changelog_clear <mdtname> <id> <endrec>"},
313 {"fid2path", lfs_fid2path, 0,
314 "Resolve the full path(s) for given FID(s). For a specific hardlink "
315 "specify link number <linkno>.\n"
316 /* "For a historical link name, specify changelog record <recno>.\n" */
317 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
318 /* [ --rec <recno> ] */ },
319 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
320 "usage: path2fid [--parents] <path> ..."},
321 {"data_version", lfs_data_version, 0, "Display file data version for "
322 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
323 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
324 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
325 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
326 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
327 "[--archived] [--lost] <file> ..."},
328 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
330 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
331 "[--archived] [--lost] <file> ..."},
332 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
333 "given files.\n" "usage: hsm_action <file> ..."},
334 {"hsm_archive", lfs_hsm_archive, 0,
335 "Archive file to external storage.\n"
336 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
338 {"hsm_restore", lfs_hsm_restore, 0,
339 "Restore file from external storage.\n"
340 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
341 {"hsm_release", lfs_hsm_release, 0,
342 "Release files from Lustre.\n"
343 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
344 {"hsm_remove", lfs_hsm_remove, 0,
345 "Remove file copy from external storage.\n"
346 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
347 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
349 "Note: To remove files from the archive that have been deleted on\n"
350 "Lustre, set mntpath and optionally archive. In that case, all the\n"
351 "positional arguments and entries in the file list must be FIDs."
353 {"hsm_cancel", lfs_hsm_cancel, 0,
354 "Cancel requests related to specified files.\n"
355 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
356 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
357 "usage: swap_layouts <path1> <path2>"},
358 {"migrate", lfs_setstripe, 0,
359 "migrate file/directory between MDTs, or migrate file from one OST "
360 "layout\nto another (may be not safe with concurent writes).\n"
361 "usage: migrate [--mdt-index|-m <mdt_idx>] <directory|filename>]\n"
362 "\tmdt_idx: MDT index to migrate to\n"
366 "To move directories between MDTs. This command is deprecated, "
367 "use \"migrate\" instead.\n"
368 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
370 {"help", Parser_help, 0, "help"},
371 {"exit", Parser_quit, 0, "quit"},
372 {"quit", Parser_quit, 0, "quit"},
373 {"--version", Parser_version, 0,
374 "output build version of the utility and exit"},
379 #define MIGRATION_NONBLOCK 1
382 * Internal helper for migrate_copy_data(). Check lease and report error if
385 * \param[in] fd File descriptor on which to check the lease.
386 * \param[out] lease_broken Set to true if the lease was broken.
387 * \param[in] group_locked Whether a group lock was taken or not.
388 * \param[in] path Name of the file being processed, for error
391 * \retval 0 Migration can keep on going.
392 * \retval -errno Error occurred, abort migration.
394 static int check_lease(int fd, bool *lease_broken, bool group_locked,
399 if (!file_lease_supported)
402 rc = llapi_lease_check(fd);
404 return 0; /* llapi_check_lease returns > 0 on success. */
407 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
409 rc = rc ? rc : -EAGAIN;
411 fprintf(stderr, "%s: external attempt to access file '%s' "
412 "blocked until migration ends.\n", progname, path);
415 *lease_broken = true;
419 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
420 bool group_locked, const char *fname)
429 bool lease_broken = false;
431 /* Use a page-aligned buffer for direct I/O */
432 rc = posix_memalign(&buf, getpagesize(), buf_size);
437 /* read new data only if we have written all
438 * previously read data */
441 rc = check_lease(fd_src, &lease_broken,
442 group_locked, fname);
446 rsize = read(fd_src, buf, buf_size);
449 fprintf(stderr, "%s: %s: read failed: %s\n",
450 progname, fname, strerror(-rc));
460 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
464 "%s: %s: write failed on volatile: %s\n",
465 progname, fname, strerror(-rc));
475 fprintf(stderr, "%s: %s: fsync failed: %s\n",
476 progname, fname, strerror(-rc));
484 static int migrate_copy_timestamps(int fdv, const struct stat *st)
486 struct timeval tv[2] = {
487 {.tv_sec = st->st_atime},
488 {.tv_sec = st->st_mtime}
491 return futimes(fdv, tv);
494 static int migrate_block(int fd, int fdv, const struct stat *st,
495 size_t buf_size, const char *name)
502 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
504 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
505 progname, name, strerror(-rc));
513 /* The grouplock blocks all concurrent accesses to the file.
514 * It has to be taken after llapi_get_data_version as it would
516 rc = llapi_group_lock(fd, gid);
518 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
519 progname, name, strerror(-rc));
523 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
525 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
529 /* Make sure we keep original atime/mtime values */
530 rc = migrate_copy_timestamps(fdv, st);
532 fprintf(stderr, "%s: %s: timestamp copy failed\n",
538 * for a migration we need to check data version on file did
541 * Pass in gid=0 since we already own grouplock. */
542 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
543 SWAP_LAYOUTS_CHECK_DV1);
545 fprintf(stderr, "%s: %s: dataversion changed during copy, "
546 "migration aborted\n", progname, name);
549 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
550 name, strerror(-rc));
555 rc2 = llapi_group_unlock(fd, gid);
556 if (rc2 < 0 && rc == 0) {
557 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
558 progname, name, strerror(-rc2));
565 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
566 size_t buf_size, const char *name)
572 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
574 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
575 progname, name, strerror(-rc));
579 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
581 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
585 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
587 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
588 progname, name, strerror(-rc));
594 fprintf(stderr, "%s: %s: data version changed during "
600 /* Make sure we keep original atime/mtime values */
601 rc = migrate_copy_timestamps(fdv, st);
603 fprintf(stderr, "%s: %s: timestamp copy failed\n",
608 /* Atomically put lease, swap layouts and close.
609 * for a migration we need to check data version on file did
611 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
613 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
614 progname, name, strerror(-rc));
621 static int lfs_migrate(char *name, __u64 migration_flags,
622 struct llapi_stripe_param *param)
626 char parent[PATH_MAX];
629 char volatile_file[sizeof(parent) +
630 LUSTRE_VOLATILE_HDR_LEN +
631 2 * sizeof(mdt_index) +
632 2 * sizeof(random_value) + 4];
635 struct lov_user_md *lum = NULL;
638 bool have_lease_rdlck = false;
642 /* find the right size for the IO and allocate the buffer */
643 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
644 lum = malloc(lum_size);
650 rc = llapi_file_get_stripe(name, lum);
651 /* failure can happen for many reasons and some may be not real errors
653 * in case of a real error, a later call will fail with better
654 * error management */
656 buf_size = 1024 * 1024;
658 buf_size = lum->lmm_stripe_size;
660 /* open file, direct io */
661 /* even if the file is only read, WR mode is nedeed to allow
662 * layout swap on fd */
663 fd = open(name, O_RDWR | O_DIRECT);
666 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
671 if (file_lease_supported) {
672 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
673 if (rc == -EOPNOTSUPP) {
674 /* Older servers do not support file lease.
675 * Disable related checks. This opens race conditions
676 * as explained in LU-4840 */
677 file_lease_supported = false;
679 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
680 progname, name, strerror(-rc));
683 have_lease_rdlck = true;
687 /* search for file directory pathname */
688 if (strlen(name) > sizeof(parent)-1) {
692 strncpy(parent, name, sizeof(parent));
693 ptr = strrchr(parent, '/');
695 if (getcwd(parent, sizeof(parent)) == NULL) {
706 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
708 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
709 progname, name, strerror(-rc));
714 random_value = random();
715 rc = snprintf(volatile_file, sizeof(volatile_file),
716 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
717 mdt_index, random_value);
718 if (rc >= sizeof(volatile_file)) {
723 /* create, open a volatile file, use caching (ie no directio) */
724 fdv = llapi_file_open_param(volatile_file,
725 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
726 S_IRUSR | S_IWUSR, param);
727 } while (fdv == -EEXIST);
731 fprintf(stderr, "%s: %s: cannot create volatile file in"
733 progname, parent, strerror(-rc));
737 /* Not-owner (root?) special case.
738 * Need to set owner/group of volatile file like original.
739 * This will allow to pass related check during layout_swap.
744 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
748 rc = fstat(fdv, &stv);
751 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
752 volatile_file, strerror(errno));
755 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
756 rc = fchown(fdv, st.st_uid, st.st_gid);
759 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
760 name, strerror(errno));
765 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
766 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
768 have_lease_rdlck = false;
769 fdv = -1; /* The volatile file is closed as we put the
770 * lease in non-blocking mode. */
773 /* Blocking mode (forced if servers do not support file lease).
774 * It is also the default mode, since we cannot distinguish
775 * between a broken lease and a server that does not support
776 * atomic swap/close (LU-6785) */
777 rc = migrate_block(fd, fdv, &st, buf_size, name);
781 if (have_lease_rdlck)
798 * Parse a string containing an OST index list into an array of integers.
800 * The input string contains a comma delimited list of individual
801 * indices and ranges, for example "1,2-4,7". Add the indices into the
802 * \a osts array and remove duplicates.
804 * \param[out] osts array to store indices in
805 * \param[in] size size of \a osts array
806 * \param[in] offset starting index in \a osts
807 * \param[in] arg string containing OST index list
809 * \retval positive number of indices in \a osts
810 * \retval -EINVAL unable to parse \a arg
812 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
816 int slots = size - offset;
824 while (!end_of_loop) {
832 ptr = strchrnul(arg, ',');
834 end_of_loop = *ptr == '\0';
837 start_index = strtol(arg, &endptr, 0);
838 if (endptr == arg) /* no data at all */
840 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
845 end_index = start_index;
846 if (*endptr == '-') {
847 end_index = strtol(endptr + 1, &endptr, 0);
850 if (end_index < start_index)
854 for (i = start_index; i <= end_index && slots > 0; i++) {
857 /* remove duplicate */
858 for (j = 0; j < offset; j++) {
862 if (j == offset) { /* no duplicate */
867 if (slots == 0 && i < end_index)
875 if (!end_of_loop && ptr != NULL)
878 return rc < 0 ? rc : nr;
882 static int lfs_setstripe(int argc, char **argv)
884 struct llapi_stripe_param *param = NULL;
885 struct find_param migrate_mdt_param = {
892 unsigned long long st_size;
893 int st_offset, st_count;
897 char *stripe_size_arg = NULL;
898 char *stripe_off_arg = NULL;
899 char *stripe_count_arg = NULL;
900 char *pool_name_arg = NULL;
901 char *mdt_idx_arg = NULL;
902 unsigned long long size_units = 1;
903 bool migrate_mode = false;
904 bool migration_block = false;
905 __u64 migration_flags = 0;
906 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
909 struct option long_opts[] = {
910 /* --block is only valid in migrate mode */
911 {"block", no_argument, 0, 'b'},
912 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
913 /* This formerly implied "stripe-count", but was explicitly
914 * made "stripe-count" for consistency with other options,
915 * and to separate it from "mdt-count" when DNE arrives. */
916 {"count", required_argument, 0, 'c'},
918 {"stripe-count", required_argument, 0, 'c'},
919 {"stripe_count", required_argument, 0, 'c'},
920 {"delete", no_argument, 0, 'd'},
921 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
922 /* This formerly implied "stripe-index", but was explicitly
923 * made "stripe-index" for consistency with other options,
924 * and to separate it from "mdt-index" when DNE arrives. */
925 {"index", required_argument, 0, 'i'},
927 {"stripe-index", required_argument, 0, 'i'},
928 {"stripe_index", required_argument, 0, 'i'},
929 {"mdt-index", required_argument, 0, 'm'},
930 {"mdt_index", required_argument, 0, 'm'},
931 /* --non-block is only valid in migrate mode */
932 {"non-block", no_argument, 0, 'n'},
933 {"ost-list", required_argument, 0, 'o'},
934 {"ost_list", required_argument, 0, 'o'},
935 {"pool", required_argument, 0, 'p'},
936 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
937 /* This formerly implied "--stripe-size", but was confusing
938 * with "lfs find --size|-s", which means "file size", so use
939 * the consistent "--stripe-size|-S" for all commands. */
940 {"size", required_argument, 0, 's'},
942 {"stripe-size", required_argument, 0, 'S'},
943 {"stripe_size", required_argument, 0, 'S'},
951 if (strcmp(argv[0], "migrate") == 0)
954 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:",
955 long_opts, NULL)) >= 0) {
962 fprintf(stderr, "--block is valid only for"
966 migration_block = true;
969 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
970 if (strcmp(argv[optind - 1], "--count") == 0)
971 fprintf(stderr, "warning: '--count' deprecated"
972 ", use '--stripe-count' instead\n");
974 stripe_count_arg = optarg;
977 /* delete the default striping pattern */
981 nr_osts = parse_targets(osts,
982 sizeof(osts) / sizeof(__u32),
986 "error: %s: bad OST indices '%s'\n",
991 if (st_offset == -1) /* first in the command line */
995 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
996 if (strcmp(argv[optind - 1], "--index") == 0)
997 fprintf(stderr, "warning: '--index' deprecated"
998 ", use '--stripe-index' instead\n");
1000 stripe_off_arg = optarg;
1003 if (!migrate_mode) {
1004 fprintf(stderr, "--mdt-index is valid only for"
1008 mdt_idx_arg = optarg;
1011 if (!migrate_mode) {
1012 fprintf(stderr, "--non-block is valid only for"
1016 migration_flags |= MIGRATION_NONBLOCK;
1018 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1020 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1021 fprintf(stderr, "warning: '--size|-s' deprecated, "
1022 "use '--stripe-size|-S' instead\n");
1024 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1026 stripe_size_arg = optarg;
1029 pool_name_arg = optarg;
1036 fname = argv[optind];
1039 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1040 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1041 fprintf(stderr, "error: %s: cannot specify -d with "
1042 "-s, -c, -o, or -p options\n",
1047 if (optind == argc) {
1048 fprintf(stderr, "error: %s: missing filename|dirname\n",
1053 if (mdt_idx_arg != NULL && optind > 3) {
1054 fprintf(stderr, "error: %s: cannot specify -m with other "
1055 "options\n", argv[0]);
1059 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1061 "error: %s: cannot specify --non-block and --block\n",
1066 if (pool_name_arg != NULL) {
1070 ptr = strchr(pool_name_arg, '.');
1072 ptr = pool_name_arg;
1074 if ((ptr - pool_name_arg) == 0) {
1075 fprintf(stderr, "error: %s: fsname is empty "
1076 "in pool name '%s'\n",
1077 argv[0], pool_name_arg);
1084 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1086 fprintf(stderr, "error: %s: poolname '%s' is "
1088 argv[0], pool_name_arg);
1090 } else if (rc == -2) {
1091 fprintf(stderr, "error: %s: pool name '%s' is too long "
1092 "(max is %d characters)\n",
1093 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1095 } else if (rc > 0) {
1096 fprintf(stderr, "error: %s: char '%c' not allowed in "
1098 argv[0], rc, pool_name_arg);
1103 /* get the stripe size */
1104 if (stripe_size_arg != NULL) {
1105 result = llapi_parse_size(stripe_size_arg, &st_size,
1108 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1109 argv[0], stripe_size_arg);
1113 /* get the stripe offset */
1114 if (stripe_off_arg != NULL) {
1115 st_offset = strtol(stripe_off_arg, &end, 0);
1117 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1118 argv[0], stripe_off_arg);
1122 /* get the stripe count */
1123 if (stripe_count_arg != NULL) {
1124 st_count = strtoul(stripe_count_arg, &end, 0);
1126 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1127 argv[0], stripe_count_arg);
1132 if (mdt_idx_arg != NULL) {
1133 /* initialize migrate mdt parameters */
1134 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1136 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1137 argv[0], mdt_idx_arg);
1140 migrate_mdt_param.fp_migrate = 1;
1142 /* initialize stripe parameters */
1143 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1144 if (param == NULL) {
1145 fprintf(stderr, "error: %s: run out of memory\n",
1150 param->lsp_stripe_size = st_size;
1151 param->lsp_stripe_offset = st_offset;
1152 param->lsp_stripe_count = st_count;
1153 param->lsp_stripe_pattern = 0;
1154 param->lsp_pool = pool_name_arg;
1155 param->lsp_is_specific = false;
1157 if (st_count > 0 && nr_osts != st_count) {
1158 fprintf(stderr, "error: %s: stripe count '%d' "
1159 "doesn't match the number of OSTs: %d\n"
1160 , argv[0], st_count, nr_osts);
1165 param->lsp_is_specific = true;
1166 param->lsp_stripe_count = nr_osts;
1167 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1171 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1172 if (!migrate_mode) {
1173 result = llapi_file_open_param(fname,
1180 } else if (mdt_idx_arg != NULL) {
1181 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1183 result = lfs_migrate(fname, migration_flags, param);
1186 /* Save the first error encountered. */
1190 "error: %s: %s file '%s' failed\n",
1191 argv[0], migrate_mode ? "migrate" : "create",
1201 static int lfs_poollist(int argc, char **argv)
1206 return llapi_poollist(argv[1]);
1209 static int set_time(time_t *time, time_t *set, char *str)
1216 else if (str[0] == '-')
1222 t = strtol(str, NULL, 0);
1223 if (*time < t * 24 * 60 * 60) {
1226 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1230 *set = *time - t * 24 * 60 * 60;
1237 static int name2id(unsigned int *id, char *name, int type)
1240 struct passwd *entry;
1242 if (!(entry = getpwnam(name))) {
1248 *id = entry->pw_uid;
1250 struct group *entry;
1252 if (!(entry = getgrnam(name))) {
1258 *id = entry->gr_gid;
1264 static int id2name(char **name, unsigned int id, int type)
1267 struct passwd *entry;
1269 if (!(entry = getpwuid(id))) {
1275 *name = entry->pw_name;
1277 struct group *entry;
1279 if (!(entry = getgrgid(id))) {
1285 *name = entry->gr_name;
1291 static int name2layout(__u32 *layout, char *name)
1296 for (ptr = name; ; ptr = NULL) {
1297 lyt = strtok(ptr, ",");
1300 if (strcmp(lyt, "released") == 0)
1301 *layout |= LOV_PATTERN_F_RELEASED;
1302 else if (strcmp(lyt, "raid0") == 0)
1303 *layout |= LOV_PATTERN_RAID0;
1310 #define FIND_POOL_OPT 3
1311 static int lfs_find(int argc, char **argv)
1316 struct find_param param = {
1320 struct option long_opts[] = {
1321 {"atime", required_argument, 0, 'A'},
1322 {"stripe-count", required_argument, 0, 'c'},
1323 {"stripe_count", required_argument, 0, 'c'},
1324 {"ctime", required_argument, 0, 'C'},
1325 {"maxdepth", required_argument, 0, 'D'},
1326 {"gid", required_argument, 0, 'g'},
1327 {"group", required_argument, 0, 'G'},
1328 {"stripe-index", required_argument, 0, 'i'},
1329 {"stripe_index", required_argument, 0, 'i'},
1330 {"layout", required_argument, 0, 'L'},
1331 {"mdt", required_argument, 0, 'm'},
1332 {"mtime", required_argument, 0, 'M'},
1333 {"name", required_argument, 0, 'n'},
1334 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1335 {"obd", required_argument, 0, 'O'},
1336 {"ost", required_argument, 0, 'O'},
1337 /* no short option for pool, p/P already used */
1338 {"pool", required_argument, 0, FIND_POOL_OPT},
1339 {"print0", no_argument, 0, 'p'},
1340 {"print", no_argument, 0, 'P'},
1341 {"size", required_argument, 0, 's'},
1342 {"stripe-size", required_argument, 0, 'S'},
1343 {"stripe_size", required_argument, 0, 'S'},
1344 {"type", required_argument, 0, 't'},
1345 {"uid", required_argument, 0, 'u'},
1346 {"user", required_argument, 0, 'U'},
1359 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1360 while ((c = getopt_long_only(argc, argv,
1361 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1362 long_opts, NULL)) >= 0) {
1367 /* '!' is part of option */
1368 /* when getopt_long_only() finds a string which is not
1369 * an option nor a known option argument it returns 1
1370 * in that case if we already have found pathstart and pathend
1371 * (i.e. we have the list of pathnames),
1372 * the only supported value is "!"
1374 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1375 if (!isoption && pathend != -1) {
1376 fprintf(stderr, "err: %s: filename|dirname must either "
1377 "precede options or follow options\n",
1382 if (!isoption && pathstart == -1)
1383 pathstart = optind - 1;
1384 if (isoption && pathstart != -1 && pathend == -1)
1385 pathend = optind - 2;
1391 /* unknown; opt is "!" or path component,
1392 * checking done above.
1394 if (strcmp(optarg, "!") == 0)
1398 xtime = ¶m.fp_atime;
1399 xsign = ¶m.fp_asign;
1400 param.fp_exclude_atime = !!neg_opt;
1401 /* no break, this falls through to 'C' for ctime */
1404 xtime = ¶m.fp_ctime;
1405 xsign = ¶m.fp_csign;
1406 param.fp_exclude_ctime = !!neg_opt;
1408 /* no break, this falls through to 'M' for mtime */
1411 xtime = ¶m.fp_mtime;
1412 xsign = ¶m.fp_msign;
1413 param.fp_exclude_mtime = !!neg_opt;
1415 rc = set_time(&t, xtime, optarg);
1416 if (rc == INT_MAX) {
1424 if (optarg[0] == '+') {
1425 param.fp_stripe_count_sign = -1;
1427 } else if (optarg[0] == '-') {
1428 param.fp_stripe_count_sign = 1;
1432 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1433 if (*endptr != '\0') {
1434 fprintf(stderr,"error: bad stripe_count '%s'\n",
1439 param.fp_check_stripe_count = 1;
1440 param.fp_exclude_stripe_count = !!neg_opt;
1443 param.fp_max_depth = strtol(optarg, 0, 0);
1447 rc = name2id(¶m.fp_gid, optarg, GROUP);
1449 param.fp_gid = strtoul(optarg, &endptr, 10);
1450 if (*endptr != '\0') {
1451 fprintf(stderr, "Group/GID: %s cannot "
1452 "be found.\n", optarg);
1457 param.fp_exclude_gid = !!neg_opt;
1458 param.fp_check_gid = 1;
1461 ret = name2layout(¶m.fp_layout, optarg);
1464 param.fp_exclude_layout = !!neg_opt;
1465 param.fp_check_layout = 1;
1469 rc = name2id(¶m.fp_uid, optarg, USER);
1471 param.fp_uid = strtoul(optarg, &endptr, 10);
1472 if (*endptr != '\0') {
1473 fprintf(stderr, "User/UID: %s cannot "
1474 "be found.\n", optarg);
1479 param.fp_exclude_uid = !!neg_opt;
1480 param.fp_check_uid = 1;
1483 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1485 "Pool name %s is too long"
1486 " (max is %d)\n", optarg,
1491 /* we do check for empty pool because empty pool
1492 * is used to find V1 lov attributes */
1493 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1494 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1495 param.fp_exclude_pool = !!neg_opt;
1496 param.fp_check_pool = 1;
1499 param.fp_pattern = (char *)optarg;
1500 param.fp_exclude_pattern = !!neg_opt;
1505 char *buf, *token, *next, *p;
1509 buf = strdup(optarg);
1515 param.fp_exclude_obd = !!neg_opt;
1518 while (token && *token) {
1519 token = strchr(token, ',');
1526 param.fp_exclude_mdt = !!neg_opt;
1527 param.fp_num_alloc_mdts += len;
1528 tmp = realloc(param.fp_mdt_uuid,
1529 param.fp_num_alloc_mdts *
1530 sizeof(*param.fp_mdt_uuid));
1536 param.fp_mdt_uuid = tmp;
1538 param.fp_exclude_obd = !!neg_opt;
1539 param.fp_num_alloc_obds += len;
1540 tmp = realloc(param.fp_obd_uuid,
1541 param.fp_num_alloc_obds *
1542 sizeof(*param.fp_obd_uuid));
1548 param.fp_obd_uuid = tmp;
1550 for (token = buf; token && *token; token = next) {
1551 struct obd_uuid *puuid;
1554 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1557 ¶m.fp_obd_uuid[param.fp_num_obds++];
1559 p = strchr(token, ',');
1566 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1571 strncpy(puuid->uuid, token,
1572 sizeof(puuid->uuid));
1580 param.fp_zero_end = 1;
1585 if (optarg[0] == '+') {
1586 param.fp_size_sign = -1;
1588 } else if (optarg[0] == '-') {
1589 param.fp_size_sign = 1;
1593 ret = llapi_parse_size(optarg, ¶m.fp_size,
1594 ¶m.fp_size_units, 0);
1596 fprintf(stderr, "error: bad file size '%s'\n",
1600 param.fp_check_size = 1;
1601 param.fp_exclude_size = !!neg_opt;
1604 if (optarg[0] == '+') {
1605 param.fp_stripe_size_sign = -1;
1607 } else if (optarg[0] == '-') {
1608 param.fp_stripe_size_sign = 1;
1612 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1613 ¶m.fp_stripe_size_units, 0);
1615 fprintf(stderr, "error: bad stripe_size '%s'\n",
1619 param.fp_check_stripe_size = 1;
1620 param.fp_exclude_stripe_size = !!neg_opt;
1623 param.fp_exclude_type = !!neg_opt;
1624 switch (optarg[0]) {
1626 param.fp_type = S_IFBLK;
1629 param.fp_type = S_IFCHR;
1632 param.fp_type = S_IFDIR;
1635 param.fp_type = S_IFREG;
1638 param.fp_type = S_IFLNK;
1641 param.fp_type = S_IFIFO;
1644 param.fp_type = S_IFSOCK;
1647 fprintf(stderr, "error: %s: bad type '%s'\n",
1659 if (pathstart == -1) {
1660 fprintf(stderr, "error: %s: no filename|pathname\n",
1664 } else if (pathend == -1) {
1670 rc = llapi_find(argv[pathstart], ¶m);
1671 if (rc != 0 && ret == 0)
1673 } while (++pathstart < pathend);
1676 fprintf(stderr, "error: %s failed for %s.\n",
1677 argv[0], argv[optind - 1]);
1679 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1680 free(param.fp_obd_uuid);
1682 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1683 free(param.fp_mdt_uuid);
1688 static int lfs_getstripe_internal(int argc, char **argv,
1689 struct find_param *param)
1691 struct option long_opts[] = {
1692 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1693 /* This formerly implied "stripe-count", but was explicitly
1694 * made "stripe-count" for consistency with other options,
1695 * and to separate it from "mdt-count" when DNE arrives. */
1696 {"count", no_argument, 0, 'c'},
1698 {"stripe-count", no_argument, 0, 'c'},
1699 {"stripe_count", no_argument, 0, 'c'},
1700 {"directory", no_argument, 0, 'd'},
1701 {"default", no_argument, 0, 'D'},
1702 {"generation", no_argument, 0, 'g'},
1703 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1704 /* This formerly implied "stripe-index", but was explicitly
1705 * made "stripe-index" for consistency with other options,
1706 * and to separate it from "mdt-index" when DNE arrives. */
1707 {"index", no_argument, 0, 'i'},
1709 {"stripe-index", no_argument, 0, 'i'},
1710 {"stripe_index", no_argument, 0, 'i'},
1711 {"layout", no_argument, 0, 'L'},
1712 {"mdt-index", no_argument, 0, 'M'},
1713 {"mdt_index", no_argument, 0, 'M'},
1714 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1715 /* This formerly implied "stripe-index", but was confusing
1716 * with "file offset" (which will eventually be needed for
1717 * with different layouts by offset), so deprecate it. */
1718 {"offset", no_argument, 0, 'o'},
1720 {"obd", required_argument, 0, 'O'},
1721 {"ost", required_argument, 0, 'O'},
1722 {"pool", no_argument, 0, 'p'},
1723 {"quiet", no_argument, 0, 'q'},
1724 {"recursive", no_argument, 0, 'r'},
1725 {"raw", no_argument, 0, 'R'},
1726 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1727 /* This formerly implied "--stripe-size", but was confusing
1728 * with "lfs find --size|-s", which means "file size", so use
1729 * the consistent "--stripe-size|-S" for all commands. */
1730 {"size", no_argument, 0, 's'},
1732 {"stripe-size", no_argument, 0, 'S'},
1733 {"stripe_size", no_argument, 0, 'S'},
1734 {"verbose", no_argument, 0, 'v'},
1739 param->fp_max_depth = 1;
1740 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1741 long_opts, NULL)) != -1) {
1744 if (param->fp_obd_uuid) {
1746 "error: %s: only one obduuid allowed",
1750 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1756 param->fp_max_depth = 0;
1759 param->fp_get_default_lmv = 1;
1762 param->fp_recursive = 1;
1765 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1768 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1769 if (strcmp(argv[optind - 1], "--count") == 0)
1770 fprintf(stderr, "warning: '--count' deprecated,"
1771 " use '--stripe-count' instead\n");
1773 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1774 param->fp_verbose |= VERBOSE_COUNT;
1775 param->fp_max_depth = 0;
1778 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1780 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1781 fprintf(stderr, "warning: '--size|-s' deprecated, "
1782 "use '--stripe-size|-S' instead\n");
1784 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1786 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1787 param->fp_verbose |= VERBOSE_SIZE;
1788 param->fp_max_depth = 0;
1791 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1793 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1794 "use '--stripe-index|-i' instead\n");
1797 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1798 if (strcmp(argv[optind - 1], "--index") == 0)
1799 fprintf(stderr, "warning: '--index' deprecated"
1800 ", use '--stripe-index' instead\n");
1802 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1803 param->fp_verbose |= VERBOSE_OFFSET;
1804 param->fp_max_depth = 0;
1808 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1809 param->fp_verbose |= VERBOSE_POOL;
1810 param->fp_max_depth = 0;
1814 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1815 param->fp_verbose |= VERBOSE_GENERATION;
1816 param->fp_max_depth = 0;
1820 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1821 param->fp_verbose |= VERBOSE_LAYOUT;
1822 param->fp_max_depth = 0;
1826 if (!(param->fp_verbose & VERBOSE_DETAIL))
1827 param->fp_max_depth = 0;
1828 param->fp_verbose |= VERBOSE_MDTINDEX;
1841 if (param->fp_recursive)
1842 param->fp_max_depth = -1;
1844 if (!param->fp_verbose)
1845 param->fp_verbose = VERBOSE_ALL;
1846 if (param->fp_quiet)
1847 param->fp_verbose = VERBOSE_OBJID;
1850 rc = llapi_getstripe(argv[optind], param);
1851 } while (++optind < argc && !rc);
1854 fprintf(stderr, "error: %s failed for %s.\n",
1855 argv[0], argv[optind - 1]);
1859 static int lfs_tgts(int argc, char **argv)
1861 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1862 struct find_param param;
1863 int index = 0, rc=0;
1868 if (argc == 2 && !realpath(argv[1], path)) {
1870 fprintf(stderr, "error: invalid path '%s': %s\n",
1871 argv[1], strerror(-rc));
1875 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1876 /* Check if we have a mount point */
1877 if (mntdir[0] == '\0')
1880 memset(¶m, 0, sizeof(param));
1881 if (!strcmp(argv[0], "mdts"))
1882 param.fp_get_lmv = 1;
1884 rc = llapi_ostlist(mntdir, ¶m);
1886 fprintf(stderr, "error: %s: failed on %s\n",
1889 if (path[0] != '\0')
1891 memset(mntdir, 0, PATH_MAX);
1897 static int lfs_getstripe(int argc, char **argv)
1899 struct find_param param = { 0 };
1900 return lfs_getstripe_internal(argc, argv, ¶m);
1904 static int lfs_getdirstripe(int argc, char **argv)
1906 struct find_param param = { 0 };
1908 param.fp_get_lmv = 1;
1909 return lfs_getstripe_internal(argc, argv, ¶m);
1913 static int lfs_setdirstripe(int argc, char **argv)
1917 unsigned int stripe_offset = -1;
1918 unsigned int stripe_count = 1;
1919 enum lmv_hash_type hash_type;
1922 char *stripe_offset_opt = NULL;
1923 char *stripe_count_opt = NULL;
1924 char *stripe_hash_opt = NULL;
1925 char *mode_opt = NULL;
1926 bool default_stripe = false;
1927 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1928 mode_t previous_mode = 0;
1929 bool delete = false;
1931 struct option long_opts[] = {
1932 {"count", required_argument, 0, 'c'},
1933 {"delete", no_argument, 0, 'd'},
1934 {"index", required_argument, 0, 'i'},
1935 {"mode", required_argument, 0, 'm'},
1936 {"hash-type", required_argument, 0, 't'},
1937 {"default_stripe", no_argument, 0, 'D'},
1941 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1948 stripe_count_opt = optarg;
1952 default_stripe = true;
1955 default_stripe = true;
1958 stripe_offset_opt = optarg;
1964 stripe_hash_opt = optarg;
1967 fprintf(stderr, "error: %s: option '%s' "
1969 argv[0], argv[optind - 1]);
1974 if (optind == argc) {
1975 fprintf(stderr, "error: %s: missing dirname\n",
1980 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1981 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1986 if (stripe_offset_opt != NULL) {
1987 /* get the stripe offset */
1988 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1990 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1991 argv[0], stripe_offset_opt);
1997 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1998 fprintf(stderr, "error: %s: cannot specify -d with -s,"
1999 " or -i options.\n", argv[0]);
2007 if (mode_opt != NULL) {
2008 mode = strtoul(mode_opt, &end, 8);
2010 fprintf(stderr, "error: %s: bad mode '%s'\n",
2014 previous_mode = umask(0);
2017 if (stripe_hash_opt == NULL ||
2018 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2019 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2020 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2021 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2023 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2024 argv[0], stripe_hash_opt);
2028 /* get the stripe count */
2029 if (stripe_count_opt != NULL) {
2030 stripe_count = strtoul(stripe_count_opt, &end, 0);
2032 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2033 argv[0], stripe_count_opt);
2038 dname = argv[optind];
2040 if (default_stripe) {
2041 result = llapi_dir_set_default_lmv_stripe(dname,
2042 stripe_offset, stripe_count,
2045 result = llapi_dir_create_pool(dname, mode,
2047 stripe_count, hash_type,
2052 fprintf(stderr, "error: %s: create stripe dir '%s' "
2053 "failed\n", argv[0], dname);
2056 dname = argv[++optind];
2057 } while (dname != NULL);
2059 if (mode_opt != NULL)
2060 umask(previous_mode);
2066 static int lfs_rmentry(int argc, char **argv)
2073 fprintf(stderr, "error: %s: missing dirname\n",
2079 dname = argv[index];
2080 while (dname != NULL) {
2081 result = llapi_direntry_remove(dname);
2083 fprintf(stderr, "error: %s: remove dir entry '%s' "
2084 "failed\n", argv[0], dname);
2087 dname = argv[++index];
2092 static int lfs_mv(int argc, char **argv)
2094 struct find_param param = {
2101 struct option long_opts[] = {
2102 {"mdt-index", required_argument, 0, 'M'},
2103 {"verbose", no_argument, 0, 'v'},
2107 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2110 param.fp_mdt_index = strtoul(optarg, &end, 0);
2112 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2119 param.fp_verbose = VERBOSE_DETAIL;
2123 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2124 argv[0], argv[optind - 1]);
2129 if (param.fp_mdt_index == -1) {
2130 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2134 if (optind >= argc) {
2135 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2139 param.fp_migrate = 1;
2140 rc = llapi_migrate_mdt(argv[optind], ¶m);
2142 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2143 argv[0], argv[optind], param.fp_mdt_index,
2148 static int lfs_osts(int argc, char **argv)
2150 return lfs_tgts(argc, argv);
2153 static int lfs_mdts(int argc, char **argv)
2155 return lfs_tgts(argc, argv);
2158 #define COOK(value) \
2161 while (value > 1024) { \
2169 #define CDF "%11llu"
2170 #define HDF "%8.1f%c"
2174 static int showdf(char *mntdir, struct obd_statfs *stat,
2175 char *uuid, int ishow, int cooked,
2176 char *type, int index, int rc)
2178 long long avail, used, total;
2180 char *suffix = "KMGTPEZY";
2181 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2182 char tbuf[3 * sizeof(__u64)];
2183 char ubuf[3 * sizeof(__u64)];
2184 char abuf[3 * sizeof(__u64)];
2185 char rbuf[3 * sizeof(__u64)];
2193 avail = stat->os_ffree;
2194 used = stat->os_files - stat->os_ffree;
2195 total = stat->os_files;
2197 int shift = cooked ? 0 : 10;
2199 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2200 used = ((stat->os_blocks - stat->os_bfree) *
2201 stat->os_bsize) >> shift;
2202 total = (stat->os_blocks * stat->os_bsize) >> shift;
2205 if ((used + avail) > 0)
2206 ratio = (double)used / (double)(used + avail);
2212 cook_val = (double)total;
2215 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2217 sprintf(tbuf, CDF, total);
2219 cook_val = (double)used;
2222 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2224 sprintf(ubuf, CDF, used);
2226 cook_val = (double)avail;
2229 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2231 sprintf(abuf, CDF, avail);
2233 sprintf(tbuf, CDF, total);
2234 sprintf(ubuf, CDF, used);
2235 sprintf(abuf, CDF, avail);
2238 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2239 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2240 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2242 printf("[%s:%d]\n", type, index);
2248 printf(UUF": inactive device\n", uuid);
2251 printf(UUF": %s\n", uuid, strerror(-rc));
2258 struct ll_stat_type {
2263 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2264 int cooked, int lazy)
2266 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2267 struct obd_uuid uuid_buf;
2268 char *poolname = NULL;
2269 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2270 { LL_STATFS_LOV, "OST" },
2272 struct ll_stat_type *tp;
2273 __u64 ost_ffree = 0;
2279 poolname = strchr(pool, '.');
2280 if (poolname != NULL) {
2281 if (strncmp(fsname, pool, strlen(fsname))) {
2282 fprintf(stderr, "filesystem name incorrect\n");
2291 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2292 "UUID", "Inodes", "IUsed", "IFree",
2293 "IUse%", "Mounted on");
2295 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2296 "UUID", cooked ? "bytes" : "1K-blocks",
2297 "Used", "Available", "Use%", "Mounted on");
2299 for (tp = types; tp->st_name != NULL; tp++) {
2300 for (index = 0; ; index++) {
2301 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2302 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2303 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2304 rc = llapi_obd_statfs(mntdir, type, index,
2305 &stat_buf, &uuid_buf);
2312 if (poolname && tp->st_op == LL_STATFS_LOV &&
2313 llapi_search_ost(fsname, poolname,
2314 obd_uuid2str(&uuid_buf)) != 1)
2317 /* the llapi_obd_statfs() call may have returned with
2318 * an error, but if it filled in uuid_buf we will at
2319 * lease use that to print out a message for that OBD.
2320 * If we didn't get anything in the uuid_buf, then fill
2321 * it in so that we can print an error message. */
2322 if (uuid_buf.uuid[0] == '\0')
2323 sprintf(uuid_buf.uuid, "%s%04x",
2324 tp->st_name, index);
2325 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2326 ishow, cooked, tp->st_name, index, rc);
2329 if (tp->st_op == LL_STATFS_LMV) {
2330 sum.os_ffree += stat_buf.os_ffree;
2331 sum.os_files += stat_buf.os_files;
2332 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2333 sum.os_blocks += stat_buf.os_blocks *
2335 sum.os_bfree += stat_buf.os_bfree *
2337 sum.os_bavail += stat_buf.os_bavail *
2339 ost_ffree += stat_buf.os_ffree;
2341 } else if (rc == -EINVAL || rc == -EFAULT) {
2347 /* If we don't have as many objects free on the OST as inodes
2348 * on the MDS, we reduce the total number of inodes to
2349 * compensate, so that the "inodes in use" number is correct.
2350 * Matches ll_statfs_internal() so the results are consistent. */
2351 if (ost_ffree < sum.os_ffree) {
2352 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2353 sum.os_ffree = ost_ffree;
2356 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2361 static int lfs_df(int argc, char **argv)
2363 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2364 int ishow = 0, cooked = 0;
2366 int c, rc = 0, index = 0;
2367 char fsname[PATH_MAX] = "", *pool_name = NULL;
2368 struct option long_opts[] = {
2369 {"pool", required_argument, 0, 'p'},
2370 {"lazy", 0, 0, 'l'},
2374 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2392 if (optind < argc && !realpath(argv[optind], path)) {
2394 fprintf(stderr, "error: invalid path '%s': %s\n",
2395 argv[optind], strerror(-rc));
2399 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2400 /* Check if we have a mount point */
2401 if (mntdir[0] == '\0')
2404 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2405 if (rc || path[0] != '\0')
2407 fsname[0] = '\0'; /* avoid matching in next loop */
2408 mntdir[0] = '\0'; /* avoid matching in next loop */
2414 static int lfs_getname(int argc, char **argv)
2416 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2417 int rc = 0, index = 0, c;
2418 char buf[sizeof(struct obd_uuid)];
2420 while ((c = getopt(argc, argv, "h")) != -1)
2423 if (optind == argc) { /* no paths specified, get all paths. */
2424 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2425 rc = llapi_getname(mntdir, buf, sizeof(buf));
2428 "cannot get name for `%s': %s\n",
2429 mntdir, strerror(-rc));
2433 printf("%s %s\n", buf, mntdir);
2435 path[0] = fsname[0] = mntdir[0] = 0;
2437 } else { /* paths specified, only attempt to search these. */
2438 for (; optind < argc; optind++) {
2439 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2442 "cannot get name for `%s': %s\n",
2443 argv[optind], strerror(-rc));
2447 printf("%s %s\n", buf, argv[optind]);
2453 static int lfs_check(int argc, char **argv)
2456 char mntdir[PATH_MAX] = {'\0'};
2465 obd_types[0] = obd_type1;
2466 obd_types[1] = obd_type2;
2468 if (strcmp(argv[1], "osts") == 0) {
2469 strcpy(obd_types[0], "osc");
2470 } else if (strcmp(argv[1], "mds") == 0) {
2471 strcpy(obd_types[0], "mdc");
2472 } else if (strcmp(argv[1], "servers") == 0) {
2474 strcpy(obd_types[0], "osc");
2475 strcpy(obd_types[1], "mdc");
2477 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2482 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2483 if (rc < 0 || mntdir[0] == '\0') {
2484 fprintf(stderr, "No suitable Lustre mount found\n");
2488 rc = llapi_target_check(num_types, obd_types, mntdir);
2490 fprintf(stderr, "error: %s: %s status failed\n",
2497 static int lfs_join(int argc, char **argv)
2499 fprintf(stderr, "join two lustre files into one.\n"
2500 "obsolete, HEAD does not support it anymore.\n");
2504 #ifdef HAVE_SYS_QUOTA_H
2505 #define ARG2INT(nr, str, msg) \
2508 nr = strtol(str, &endp, 0); \
2510 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2515 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2517 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2518 * returns the value or ULONG_MAX on integer overflow or incorrect format
2520 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2521 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2522 * 3. empty integer value is interpreted as 0
2524 static unsigned long str2sec(const char* timestr)
2526 const char spec[] = "smhdw";
2527 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2528 unsigned long val = 0;
2531 if (strpbrk(timestr, spec) == NULL) {
2532 /* no specifiers inside the time string,
2533 should treat it as an integer value */
2534 val = strtoul(timestr, &tail, 10);
2535 return *tail ? ULONG_MAX : val;
2538 /* format string is XXwXXdXXhXXmXXs */
2544 v = strtoul(timestr, &tail, 10);
2545 if (v == ULONG_MAX || *tail == '\0')
2546 /* value too large (ULONG_MAX or more)
2547 or missing specifier */
2550 ptr = strchr(spec, *tail);
2552 /* unknown specifier */
2557 /* check if product will overflow the type */
2558 if (!(v < ULONG_MAX / mult[ind]))
2561 ADD_OVERFLOW(val, mult[ind] * v);
2562 if (val == ULONG_MAX)
2574 #define ARG2ULL(nr, str, def_units) \
2576 unsigned long long limit, units = def_units; \
2579 rc = llapi_parse_size(str, &limit, &units, 1); \
2581 fprintf(stderr, "error: bad limit value %s\n", str); \
2587 static inline int has_times_option(int argc, char **argv)
2591 for (i = 1; i < argc; i++)
2592 if (!strcmp(argv[i], "-t"))
2598 int lfs_setquota_times(int argc, char **argv)
2601 struct if_quotactl qctl;
2602 char *mnt, *obd_type = (char *)qctl.obd_type;
2603 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2604 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2605 struct option long_opts[] = {
2606 {"block-grace", required_argument, 0, 'b'},
2607 {"group", no_argument, 0, 'g'},
2608 {"inode-grace", required_argument, 0, 'i'},
2609 {"times", no_argument, 0, 't'},
2610 {"user", no_argument, 0, 'u'},
2614 memset(&qctl, 0, sizeof(qctl));
2615 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2616 qctl.qc_type = UGQUOTA;
2618 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2622 if (qctl.qc_type != UGQUOTA) {
2623 fprintf(stderr, "error: -u and -g can't be used "
2624 "more than once\n");
2627 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2630 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2631 fprintf(stderr, "error: bad block-grace: %s\n",
2635 dqb->dqb_valid |= QIF_BTIME;
2638 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2639 fprintf(stderr, "error: bad inode-grace: %s\n",
2643 dqb->dqb_valid |= QIF_ITIME;
2645 case 't': /* Yes, of course! */
2647 default: /* getopt prints error message for us when opterr != 0 */
2652 if (qctl.qc_type == UGQUOTA) {
2653 fprintf(stderr, "error: neither -u nor -g specified\n");
2657 if (optind != argc - 1) {
2658 fprintf(stderr, "error: unexpected parameters encountered\n");
2663 rc = llapi_quotactl(mnt, &qctl);
2666 fprintf(stderr, "%s %s ", obd_type,
2667 obd_uuid2str(&qctl.obd_uuid));
2668 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2675 #define BSLIMIT (1 << 0)
2676 #define BHLIMIT (1 << 1)
2677 #define ISLIMIT (1 << 2)
2678 #define IHLIMIT (1 << 3)
2680 int lfs_setquota(int argc, char **argv)
2683 struct if_quotactl qctl;
2684 char *mnt, *obd_type = (char *)qctl.obd_type;
2685 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2686 struct option long_opts[] = {
2687 {"block-softlimit", required_argument, 0, 'b'},
2688 {"block-hardlimit", required_argument, 0, 'B'},
2689 {"group", required_argument, 0, 'g'},
2690 {"inode-softlimit", required_argument, 0, 'i'},
2691 {"inode-hardlimit", required_argument, 0, 'I'},
2692 {"user", required_argument, 0, 'u'},
2695 unsigned limit_mask = 0;
2698 if (has_times_option(argc, argv))
2699 return lfs_setquota_times(argc, argv);
2701 memset(&qctl, 0, sizeof(qctl));
2702 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2703 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2704 * so it can be used as a marker that qc_type
2705 * isn't reinitialized from command line */
2707 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2711 if (qctl.qc_type != UGQUOTA) {
2712 fprintf(stderr, "error: -u and -g can't be used"
2713 " more than once\n");
2716 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2717 rc = name2id(&qctl.qc_id, optarg,
2718 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2720 qctl.qc_id = strtoul(optarg, &endptr, 10);
2721 if (*endptr != '\0') {
2722 fprintf(stderr, "error: can't find id "
2723 "for name %s\n", optarg);
2729 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2730 dqb->dqb_bsoftlimit >>= 10;
2731 limit_mask |= BSLIMIT;
2732 if (dqb->dqb_bsoftlimit &&
2733 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2734 fprintf(stderr, "warning: block softlimit is "
2735 "smaller than the miminal qunit size, "
2736 "please see the help of setquota or "
2737 "Lustre manual for details.\n");
2740 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2741 dqb->dqb_bhardlimit >>= 10;
2742 limit_mask |= BHLIMIT;
2743 if (dqb->dqb_bhardlimit &&
2744 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2745 fprintf(stderr, "warning: block hardlimit is "
2746 "smaller than the miminal qunit size, "
2747 "please see the help of setquota or "
2748 "Lustre manual for details.\n");
2751 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2752 limit_mask |= ISLIMIT;
2753 if (dqb->dqb_isoftlimit &&
2754 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2755 fprintf(stderr, "warning: inode softlimit is "
2756 "smaller than the miminal qunit size, "
2757 "please see the help of setquota or "
2758 "Lustre manual for details.\n");
2761 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2762 limit_mask |= IHLIMIT;
2763 if (dqb->dqb_ihardlimit &&
2764 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2765 fprintf(stderr, "warning: inode hardlimit is "
2766 "smaller than the miminal qunit size, "
2767 "please see the help of setquota or "
2768 "Lustre manual for details.\n");
2770 default: /* getopt prints error message for us when opterr != 0 */
2775 if (qctl.qc_type == UGQUOTA) {
2776 fprintf(stderr, "error: neither -u nor -g was specified\n");
2780 if (limit_mask == 0) {
2781 fprintf(stderr, "error: at least one limit must be specified\n");
2785 if (optind != argc - 1) {
2786 fprintf(stderr, "error: unexpected parameters encountered\n");
2792 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2793 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2794 /* sigh, we can't just set blimits/ilimits */
2795 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2796 .qc_type = qctl.qc_type,
2797 .qc_id = qctl.qc_id};
2799 rc = llapi_quotactl(mnt, &tmp_qctl);
2801 fprintf(stderr, "error: setquota failed while retrieving"
2802 " current quota settings (%s)\n",
2807 if (!(limit_mask & BHLIMIT))
2808 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2809 if (!(limit_mask & BSLIMIT))
2810 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2811 if (!(limit_mask & IHLIMIT))
2812 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2813 if (!(limit_mask & ISLIMIT))
2814 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2816 /* Keep grace times if we have got no softlimit arguments */
2817 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2818 dqb->dqb_valid |= QIF_BTIME;
2819 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2822 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2823 dqb->dqb_valid |= QIF_ITIME;
2824 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2828 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2829 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2831 rc = llapi_quotactl(mnt, &qctl);
2834 fprintf(stderr, "%s %s ", obd_type,
2835 obd_uuid2str(&qctl.obd_uuid));
2836 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2843 static inline char *type2name(int check_type)
2845 if (check_type == USRQUOTA)
2847 else if (check_type == GRPQUOTA)
2853 /* Converts seconds value into format string
2854 * result is returned in buf
2856 * 1. result is in descenting order: 1w2d3h4m5s
2857 * 2. zero fields are not filled (except for p. 3): 5d1s
2858 * 3. zero seconds value is presented as "0s"
2860 static char * __sec2str(time_t seconds, char *buf)
2862 const char spec[] = "smhdw";
2863 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2868 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2869 c = seconds / mult[i];
2871 if (c > 0 || (i == 0 && buf == tail))
2872 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2880 static void sec2str(time_t seconds, char *buf, int rc)
2887 tail = __sec2str(seconds, tail);
2889 if (rc && tail - buf < 39) {
2895 static void diff2str(time_t seconds, char *buf, time_t now)
2901 if (seconds <= now) {
2902 strcpy(buf, "none");
2905 __sec2str(seconds - now, buf);
2908 static void print_quota_title(char *name, struct if_quotactl *qctl,
2909 bool human_readable)
2911 printf("Disk quotas for %s %s (%cid %u):\n",
2912 type2name(qctl->qc_type), name,
2913 *type2name(qctl->qc_type), qctl->qc_id);
2914 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2915 "Filesystem", human_readable ? "used" : "kbytes",
2916 "quota", "limit", "grace",
2917 "files", "quota", "limit", "grace");
2920 static void kbytes2str(__u64 num, char *buf, bool h)
2923 sprintf(buf, LPU64, num);
2926 sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2928 sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2930 sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2932 sprintf(buf, LPU64"%s", num, "k");
2936 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2943 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2944 int bover = 0, iover = 0;
2945 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2950 if (dqb->dqb_bhardlimit &&
2951 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2953 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2954 if (dqb->dqb_btime > now) {
2961 if (dqb->dqb_ihardlimit &&
2962 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2964 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2965 if (dqb->dqb_itime > now) {
2973 if (strlen(mnt) > 15)
2974 printf("%s\n%15s", mnt, "");
2976 printf("%15s", mnt);
2979 diff2str(dqb->dqb_btime, timebuf, now);
2981 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2982 if (rc == -EREMOTEIO)
2983 sprintf(numbuf[0], "%s*", strbuf);
2985 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2986 "%s" : "[%s]", strbuf);
2988 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2989 if (type == QC_GENERAL)
2990 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2991 "%s" : "[%s]", strbuf);
2993 sprintf(numbuf[1], "%s", "-");
2995 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2996 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2997 "%s" : "[%s]", strbuf);
2999 printf(" %7s%c %6s %7s %7s",
3000 numbuf[0], bover ? '*' : ' ', numbuf[1],
3001 numbuf[2], bover > 1 ? timebuf : "-");
3004 diff2str(dqb->dqb_itime, timebuf, now);
3006 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3007 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
3009 if (type == QC_GENERAL)
3010 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3011 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
3013 sprintf(numbuf[1], "%s", "-");
3015 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3016 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
3018 if (type != QC_OSTIDX)
3019 printf(" %7s%c %6s %7s %7s",
3020 numbuf[0], iover ? '*' : ' ', numbuf[1],
3021 numbuf[2], iover > 1 ? timebuf : "-");
3023 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3026 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3027 qctl->qc_cmd == Q_GETOINFO) {
3031 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3032 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3033 printf("Block grace time: %s; Inode grace time: %s\n",
3034 bgtimebuf, igtimebuf);
3038 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3039 bool h, __u64 *total)
3041 int rc = 0, rc1 = 0, count = 0;
3042 __u32 valid = qctl->qc_valid;
3044 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3046 fprintf(stderr, "can not get %s count: %s\n",
3047 is_mdt ? "mdt": "ost", strerror(-rc));
3051 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3052 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3053 rc = llapi_quotactl(mnt, qctl);
3055 /* It is remote client case. */
3056 if (-rc == EOPNOTSUPP) {
3063 fprintf(stderr, "quotactl %s%d failed.\n",
3064 is_mdt ? "mdt": "ost", qctl->qc_idx);
3068 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3069 qctl->qc_valid, 0, h);
3070 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3071 qctl->qc_dqblk.dqb_bhardlimit;
3074 qctl->qc_valid = valid;
3078 static int lfs_quota(int argc, char **argv)
3081 char *mnt, *name = NULL;
3082 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3083 .qc_type = UGQUOTA };
3084 char *obd_type = (char *)qctl.obd_type;
3085 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3086 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3087 verbose = 0, pass = 0, quiet = 0, inacc;
3089 __u32 valid = QC_GENERAL, idx = 0;
3090 __u64 total_ialloc = 0, total_balloc = 0;
3091 bool human_readable = false;
3093 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3096 if (qctl.qc_type != UGQUOTA) {
3097 fprintf(stderr, "error: use either -u or -g\n");
3100 qctl.qc_type = USRQUOTA;
3103 if (qctl.qc_type != UGQUOTA) {
3104 fprintf(stderr, "error: use either -u or -g\n");
3107 qctl.qc_type = GRPQUOTA;
3110 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3113 valid = qctl.qc_valid = QC_UUID;
3114 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3117 valid = qctl.qc_valid = QC_MDTIDX;
3118 idx = qctl.qc_idx = atoi(optarg);
3121 valid = qctl.qc_valid = QC_OSTIDX;
3122 idx = qctl.qc_idx = atoi(optarg);
3131 human_readable = true;
3134 fprintf(stderr, "error: %s: option '-%c' "
3135 "unrecognized\n", argv[0], c);
3140 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3141 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3142 optind == argc - 1) {
3144 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3145 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3146 qctl.qc_valid = valid;
3149 qctl.qc_type = USRQUOTA;
3150 qctl.qc_id = geteuid();
3152 qctl.qc_type = GRPQUOTA;
3153 qctl.qc_id = getegid();
3155 rc = id2name(&name, qctl.qc_id,
3156 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3159 /* lfs quota -u username /path/to/lustre/mount */
3160 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3161 /* options should be followed by u/g-name and mntpoint */
3162 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3163 fprintf(stderr, "error: missing quota argument(s)\n");
3167 name = argv[optind++];
3168 rc = name2id(&qctl.qc_id, name,
3169 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3171 qctl.qc_id = strtoul(name, &endptr, 10);
3172 if (*endptr != '\0') {
3173 fprintf(stderr, "error: can't find id for name "
3178 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3179 fprintf(stderr, "error: missing quota info argument(s)\n");
3185 rc1 = llapi_quotactl(mnt, &qctl);
3189 fprintf(stderr, "%s quotas are not enabled.\n",
3190 qctl.qc_type == USRQUOTA ? "user" : "group");
3193 fprintf(stderr, "Permission denied.\n");
3195 /* We already got a "No such file..." message. */
3198 fprintf(stderr, "Unexpected quotactl error: %s\n",
3203 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3204 print_quota_title(name, &qctl, human_readable);
3206 if (rc1 && *obd_type)
3207 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3209 if (qctl.qc_valid != QC_GENERAL)
3212 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3213 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3214 (QIF_LIMITS|QIF_USAGE));
3216 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3218 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3222 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3224 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3226 kbytes2str(total_balloc, strbuf, human_readable);
3227 printf("Total allocated inode limit: "LPU64", total "
3228 "allocated block limit: %s\n", total_ialloc, strbuf);
3231 if (rc1 || rc2 || rc3 || inacc)
3232 printf("Some errors happened when getting quota info. "
3233 "Some devices may be not working or deactivated. "
3234 "The data in \"[]\" is inaccurate.\n");
3242 #endif /* HAVE_SYS_QUOTA_H! */
3244 static int flushctx_ioctl(char *mp)
3248 fd = open(mp, O_RDONLY);
3250 fprintf(stderr, "flushctx: error open %s: %s\n",
3251 mp, strerror(errno));
3255 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3257 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3258 mp, strerror(errno));
3264 static int lfs_flushctx(int argc, char **argv)
3266 int kdestroy = 0, c;
3267 char mntdir[PATH_MAX] = {'\0'};
3271 while ((c = getopt(argc, argv, "k")) != -1) {
3277 fprintf(stderr, "error: %s: option '-%c' "
3278 "unrecognized\n", argv[0], c);
3284 if ((rc = system("kdestroy > /dev/null")) != 0) {
3285 rc = WEXITSTATUS(rc);
3286 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3290 if (optind >= argc) {
3291 /* flush for all mounted lustre fs. */
3292 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3293 /* Check if we have a mount point */
3294 if (mntdir[0] == '\0')
3297 if (flushctx_ioctl(mntdir))
3300 mntdir[0] = '\0'; /* avoid matching in next loop */
3303 /* flush fs as specified */
3304 while (optind < argc) {
3305 if (flushctx_ioctl(argv[optind++]))
3312 static int lfs_lsetfacl(int argc, char **argv)
3315 return(llapi_lsetfacl(argc, argv));
3318 static int lfs_lgetfacl(int argc, char **argv)
3321 return(llapi_lgetfacl(argc, argv));
3324 static int lfs_rsetfacl(int argc, char **argv)
3327 return(llapi_rsetfacl(argc, argv));
3330 static int lfs_rgetfacl(int argc, char **argv)
3333 return(llapi_rgetfacl(argc, argv));
3336 static int lfs_cp(int argc, char **argv)
3338 return(llapi_cp(argc, argv));
3341 static int lfs_ls(int argc, char **argv)
3343 return(llapi_ls(argc, argv));
3346 static int lfs_changelog(int argc, char **argv)
3348 void *changelog_priv;
3349 struct changelog_rec *rec;
3350 long long startrec = 0, endrec = 0;
3352 struct option long_opts[] = {
3353 {"follow", no_argument, 0, 'f'},
3356 char short_opts[] = "f";
3359 while ((rc = getopt_long(argc, argv, short_opts,
3360 long_opts, NULL)) != -1) {
3368 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3369 argv[0], argv[optind - 1]);
3376 mdd = argv[optind++];
3378 startrec = strtoll(argv[optind++], NULL, 10);
3380 endrec = strtoll(argv[optind++], NULL, 10);
3382 rc = llapi_changelog_start(&changelog_priv,
3383 CHANGELOG_FLAG_BLOCK |
3384 CHANGELOG_FLAG_JOBID |
3385 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3388 fprintf(stderr, "Can't start changelog: %s\n",
3389 strerror(errno = -rc));
3393 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3397 if (endrec && rec->cr_index > endrec) {
3398 llapi_changelog_free(&rec);
3401 if (rec->cr_index < startrec) {
3402 llapi_changelog_free(&rec);
3406 secs = rec->cr_time >> 30;
3407 gmtime_r(&secs, &ts);
3408 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3409 "0x%x t="DFID, rec->cr_index, rec->cr_type,
3410 changelog_type2str(rec->cr_type),
3411 ts.tm_hour, ts.tm_min, ts.tm_sec,
3412 (int)(rec->cr_time & ((1<<30) - 1)),
3413 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3414 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3416 if (rec->cr_flags & CLF_JOBID) {
3417 struct changelog_ext_jobid *jid =
3418 changelog_rec_jobid(rec);
3420 if (jid->cr_jobid[0] != '\0')
3421 printf(" j=%s", jid->cr_jobid);
3424 if (rec->cr_namelen)
3425 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3426 rec->cr_namelen, changelog_rec_name(rec));
3428 if (rec->cr_flags & CLF_RENAME) {
3429 struct changelog_ext_rename *rnm =
3430 changelog_rec_rename(rec);
3432 if (!fid_is_zero(&rnm->cr_sfid))
3433 printf(" s="DFID" sp="DFID" %.*s",
3434 PFID(&rnm->cr_sfid),
3435 PFID(&rnm->cr_spfid),
3436 (int)changelog_rec_snamelen(rec),
3437 changelog_rec_sname(rec));
3441 llapi_changelog_free(&rec);
3444 llapi_changelog_fini(&changelog_priv);
3447 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3449 return (rc == 1 ? 0 : rc);
3452 static int lfs_changelog_clear(int argc, char **argv)
3460 endrec = strtoll(argv[3], NULL, 10);
3462 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3464 fprintf(stderr, "%s error: %s\n", argv[0],
3465 strerror(errno = -rc));
3469 static int lfs_fid2path(int argc, char **argv)
3471 struct option long_opts[] = {
3472 {"cur", no_argument, 0, 'c'},
3473 {"link", required_argument, 0, 'l'},
3474 {"rec", required_argument, 0, 'r'},
3477 char short_opts[] = "cl:r:";
3478 char *device, *fid, *path;
3479 long long recno = -1;
3485 while ((rc = getopt_long(argc, argv, short_opts,
3486 long_opts, NULL)) != -1) {
3492 linkno = strtol(optarg, NULL, 10);
3495 recno = strtoll(optarg, NULL, 10);
3500 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3501 argv[0], argv[optind - 1]);
3509 device = argv[optind++];
3510 path = calloc(1, PATH_MAX);
3512 fprintf(stderr, "error: Not enough memory\n");
3517 while (optind < argc) {
3518 fid = argv[optind++];
3520 lnktmp = (linkno >= 0) ? linkno : 0;
3522 int oldtmp = lnktmp;
3523 long long rectmp = recno;
3525 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3528 fprintf(stderr, "%s: error on FID %s: %s\n",
3529 argv[0], fid, strerror(errno = -rc2));
3536 fprintf(stdout, "%lld ", rectmp);
3537 if (device[0] == '/') {
3538 fprintf(stdout, "%s", device);
3539 if (device[strlen(device) - 1] != '/')
3540 fprintf(stdout, "/");
3541 } else if (path[0] == '\0') {
3542 fprintf(stdout, "/");
3544 fprintf(stdout, "%s\n", path);
3547 /* specified linkno */
3549 if (oldtmp == lnktmp)
3559 static int lfs_path2fid(int argc, char **argv)
3561 struct option long_opts[] = {
3562 {"parents", no_argument, 0, 'p'},
3566 const char short_opts[] = "p";
3567 const char *sep = "";
3570 bool show_parents = false;
3572 while ((rc = getopt_long(argc, argv, short_opts,
3573 long_opts, NULL)) != -1) {
3576 show_parents = true;
3579 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3580 argv[0], argv[optind - 1]);
3585 if (optind > argc - 1)
3587 else if (optind < argc - 1)
3591 for (path = argv + optind; *path != NULL; path++) {
3593 if (!show_parents) {
3594 err = llapi_path2fid(*path, &fid);
3596 printf("%s%s"DFID"\n",
3597 *sep != '\0' ? *path : "", sep,
3600 char name[NAME_MAX + 1];
3601 unsigned int linkno = 0;
3603 while ((err = llapi_path2parent(*path, linkno, &fid,
3604 name, sizeof(name))) == 0) {
3605 if (*sep != '\0' && linkno == 0)
3606 printf("%s%s", *path, sep);
3608 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3613 /* err == -ENODATA is end-of-loop */
3614 if (linkno > 0 && err == -ENODATA) {
3621 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3622 argv[0], show_parents ? "parent " : "", *path,
3634 static int lfs_data_version(int argc, char **argv)
3641 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3646 while ((c = getopt(argc, argv, "nrw")) != -1) {
3649 data_version_flags = 0;
3652 data_version_flags |= LL_DV_RD_FLUSH;
3655 data_version_flags |= LL_DV_WR_FLUSH;
3664 path = argv[optind];
3665 fd = open(path, O_RDONLY);
3667 err(errno, "cannot open file %s", path);
3669 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3671 err(errno, "cannot get version for %s", path);
3673 printf(LPU64 "\n", data_version);
3679 static int lfs_hsm_state(int argc, char **argv)
3684 struct hsm_user_state hus;
3692 rc = llapi_hsm_state_get(path, &hus);
3694 fprintf(stderr, "can't get hsm state for %s: %s\n",
3695 path, strerror(errno = -rc));
3699 /* Display path name and status flags */
3700 printf("%s: (0x%08x)", path, hus.hus_states);
3702 if (hus.hus_states & HS_RELEASED)
3703 printf(" released");
3704 if (hus.hus_states & HS_EXISTS)
3706 if (hus.hus_states & HS_DIRTY)
3708 if (hus.hus_states & HS_ARCHIVED)
3709 printf(" archived");
3710 /* Display user-settable flags */
3711 if (hus.hus_states & HS_NORELEASE)
3712 printf(" never_release");
3713 if (hus.hus_states & HS_NOARCHIVE)
3714 printf(" never_archive");
3715 if (hus.hus_states & HS_LOST)
3716 printf(" lost_from_hsm");
3718 if (hus.hus_archive_id != 0)
3719 printf(", archive_id:%d", hus.hus_archive_id);
3722 } while (++i < argc);
3727 #define LFS_HSM_SET 0
3728 #define LFS_HSM_CLEAR 1
3731 * Generic function to set or clear HSM flags.
3732 * Used by hsm_set and hsm_clear.
3734 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3736 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3738 struct option long_opts[] = {
3739 {"lost", 0, 0, 'l'},
3740 {"norelease", 0, 0, 'r'},
3741 {"noarchive", 0, 0, 'a'},
3742 {"archived", 0, 0, 'A'},
3743 {"dirty", 0, 0, 'd'},
3744 {"exists", 0, 0, 'e'},
3747 char short_opts[] = "lraAde";
3755 while ((c = getopt_long(argc, argv, short_opts,
3756 long_opts, NULL)) != -1) {
3762 mask |= HS_NOARCHIVE;
3765 mask |= HS_ARCHIVED;
3768 mask |= HS_NORELEASE;
3779 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3780 argv[0], argv[optind - 1]);
3785 /* User should have specified a flag */
3789 while (optind < argc) {
3791 path = argv[optind];
3793 /* If mode == 0, this means we apply the mask. */
3794 if (mode == LFS_HSM_SET)
3795 rc = llapi_hsm_state_set(path, mask, 0, 0);
3797 rc = llapi_hsm_state_set(path, 0, mask, 0);
3800 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3801 path, strerror(errno = -rc));
3810 static int lfs_hsm_action(int argc, char **argv)
3815 struct hsm_current_action hca;
3816 struct hsm_extent he;
3817 enum hsm_user_action hua;
3818 enum hsm_progress_states hps;
3826 rc = llapi_hsm_current_action(path, &hca);
3828 fprintf(stderr, "can't get hsm action for %s: %s\n",
3829 path, strerror(errno = -rc));
3832 he = hca.hca_location;
3833 hua = hca.hca_action;
3834 hps = hca.hca_state;
3836 printf("%s: %s", path, hsm_user_action2name(hua));
3838 /* Skip file without action */
3839 if (hca.hca_action == HUA_NONE) {
3844 printf(" %s ", hsm_progress_state2name(hps));
3846 if ((hps == HPS_RUNNING) &&
3847 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3848 printf("(%llu bytes moved)\n",
3849 (unsigned long long)he.length);
3850 else if ((he.offset + he.length) == LUSTRE_EOF)
3851 printf("(from %llu to EOF)\n",
3852 (unsigned long long)he.offset);
3854 printf("(from %llu to %llu)\n",
3855 (unsigned long long)he.offset,
3856 (unsigned long long)(he.offset + he.length));
3858 } while (++i < argc);
3863 static int lfs_hsm_set(int argc, char **argv)
3865 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3868 static int lfs_hsm_clear(int argc, char **argv)
3870 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3874 * Check file state and return its fid, to be used by lfs_hsm_request().
3876 * \param[in] file Path to file to check
3877 * \param[in,out] fid Pointer to allocated lu_fid struct.
3878 * \param[in,out] last_dev Pointer to last device id used.
3880 * \return 0 on success.
3882 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3888 rc = lstat(file, &st);
3890 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3893 /* Checking for regular file as archiving as posix copytool
3894 * rejects archiving files other than regular files
3896 if (!S_ISREG(st.st_mode)) {
3897 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3900 /* A request should be ... */
3901 if (*last_dev != st.st_dev && *last_dev != 0) {
3902 fprintf(stderr, "All files should be "
3903 "on the same filesystem: %s\n", file);
3906 *last_dev = st.st_dev;
3908 rc = llapi_path2fid(file, fid);
3910 fprintf(stderr, "Cannot read FID of %s: %s\n",
3911 file, strerror(-rc));
3917 /* Fill an HSM HUR item with a given file name.
3919 * If mntpath is set, then the filename is actually a FID, and no
3920 * lookup on the filesystem will be performed.
3922 * \param[in] hur the user request to fill
3923 * \param[in] idx index of the item inside the HUR to fill
3924 * \param[in] mntpath mountpoint of Lustre
3925 * \param[in] fname filename (if mtnpath is NULL)
3926 * or FID (if mntpath is set)
3927 * \param[in] last_dev pointer to last device id used
3929 * \retval 0 on success
3930 * \retval CMD_HELP or a negative errno on error
3932 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3933 const char *mntpath, const char *fname,
3936 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3939 hui->hui_extent.length = -1;
3941 if (mntpath != NULL) {
3944 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3948 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3953 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3957 hur->hur_request.hr_itemcount++;
3962 static int lfs_hsm_request(int argc, char **argv, int action)
3964 struct option long_opts[] = {
3965 {"filelist", 1, 0, 'l'},
3966 {"data", 1, 0, 'D'},
3967 {"archive", 1, 0, 'a'},
3968 {"mntpath", 1, 0, 'm'},
3972 char short_opts[] = "l:D:a:m:";
3973 struct hsm_user_request *hur, *oldhur;
3978 char *filelist = NULL;
3979 char fullpath[PATH_MAX];
3980 char *opaque = NULL;
3984 int nbfile_alloc = 0;
3985 char *some_file = NULL;
3986 char *mntpath = NULL;
3992 while ((c = getopt_long(argc, argv, short_opts,
3993 long_opts, NULL)) != -1) {
4002 if (action != HUA_ARCHIVE &&
4003 action != HUA_REMOVE) {
4005 "error: -a is supported only "
4006 "when archiving or removing\n");
4009 archive_id = atoi(optarg);
4012 if (some_file == NULL) {
4014 some_file = strdup(optarg);
4020 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4021 argv[0], argv[optind - 1]);
4026 /* All remaining args are files, so we have at least nbfile */
4027 nbfile = argc - optind;
4029 if ((nbfile == 0) && (filelist == NULL))
4033 opaque_len = strlen(opaque);
4035 /* Alloc the request structure with enough place to store all files
4036 * from command line. */
4037 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4039 fprintf(stderr, "Cannot create the request: %s\n",
4043 nbfile_alloc = nbfile;
4045 hur->hur_request.hr_action = action;
4046 hur->hur_request.hr_archive_id = archive_id;
4047 hur->hur_request.hr_flags = 0;
4049 /* All remaining args are files, add them */
4050 if (nbfile != 0 && some_file == NULL)
4051 some_file = strdup(argv[optind]);
4053 for (i = 0; i < nbfile; i++) {
4054 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4060 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4062 /* If a filelist was specified, read the filelist from it. */
4063 if (filelist != NULL) {
4064 fp = fopen(filelist, "r");
4066 fprintf(stderr, "Cannot read the file list %s: %s\n",
4067 filelist, strerror(errno));
4072 while ((rc = getline(&line, &len, fp)) != -1) {
4073 /* If allocated buffer was too small, get something
4075 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4078 nbfile_alloc = nbfile_alloc * 2 + 1;
4080 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4083 fprintf(stderr, "hsm: cannot allocate "
4084 "the request: %s\n",
4091 size = hur_len(oldhur);
4093 fprintf(stderr, "hsm: cannot allocate "
4094 "%u files + %u bytes data\n",
4095 oldhur->hur_request.hr_itemcount,
4096 oldhur->hur_request.hr_data_len);
4103 memcpy(hur, oldhur, size);
4108 if (line[strlen(line) - 1] == '\n')
4109 line[strlen(line) - 1] = '\0';
4111 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4112 mntpath, line, &last_dev);
4118 if (some_file == NULL) {
4128 /* If a --data was used, add it to the request */
4129 hur->hur_request.hr_data_len = opaque_len;
4131 memcpy(hur_data(hur), opaque, opaque_len);
4133 /* Send the HSM request */
4134 if (realpath(some_file, fullpath) == NULL) {
4135 fprintf(stderr, "Could not find path '%s': %s\n",
4136 some_file, strerror(errno));
4138 rc = llapi_hsm_request(fullpath, hur);
4140 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4141 some_file, strerror(-rc));
4151 static int lfs_hsm_archive(int argc, char **argv)
4153 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4156 static int lfs_hsm_restore(int argc, char **argv)
4158 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4161 static int lfs_hsm_release(int argc, char **argv)
4163 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4166 static int lfs_hsm_remove(int argc, char **argv)
4168 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4171 static int lfs_hsm_cancel(int argc, char **argv)
4173 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4176 static int lfs_swap_layouts(int argc, char **argv)
4181 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4182 SWAP_LAYOUTS_KEEP_MTIME |
4183 SWAP_LAYOUTS_KEEP_ATIME);
4186 int main(int argc, char **argv)
4190 /* Ensure that liblustreapi constructor has run */
4191 if (!liblustreapi_initialized)
4192 fprintf(stderr, "liblustreapi was not properly initialized\n");
4196 Parser_init("lfs > ", cmdlist);
4198 progname = argv[0]; /* Used in error messages */
4200 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4202 rc = Parser_commands();
4205 return rc < 0 ? -rc : rc;
4208 #ifdef _LUSTRE_IDL_H_
4209 /* Everything we need here should be included by lustreapi.h. */
4210 # error "lfs should not depend on lustre_idl.h"
4211 #endif /* _LUSTRE_IDL_H_ */