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 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
80 #endif /* !ARRAY_SIZE */
83 static int lfs_setstripe(int argc, char **argv);
84 static int lfs_find(int argc, char **argv);
85 static int lfs_getstripe(int argc, char **argv);
86 static int lfs_getdirstripe(int argc, char **argv);
87 static int lfs_setdirstripe(int argc, char **argv);
88 static int lfs_rmentry(int argc, char **argv);
89 static int lfs_osts(int argc, char **argv);
90 static int lfs_mdts(int argc, char **argv);
91 static int lfs_df(int argc, char **argv);
92 static int lfs_getname(int argc, char **argv);
93 static int lfs_check(int argc, char **argv);
94 #ifdef HAVE_SYS_QUOTA_H
95 static int lfs_setquota(int argc, char **argv);
96 static int lfs_quota(int argc, char **argv);
98 static int lfs_flushctx(int argc, char **argv);
99 static int lfs_join(int argc, char **argv);
100 static int lfs_lsetfacl(int argc, char **argv);
101 static int lfs_lgetfacl(int argc, char **argv);
102 static int lfs_rsetfacl(int argc, char **argv);
103 static int lfs_rgetfacl(int argc, char **argv);
104 static int lfs_cp(int argc, char **argv);
105 static int lfs_ls(int argc, char **argv);
106 static int lfs_poollist(int argc, char **argv);
107 static int lfs_changelog(int argc, char **argv);
108 static int lfs_changelog_clear(int argc, char **argv);
109 static int lfs_fid2path(int argc, char **argv);
110 static int lfs_path2fid(int argc, char **argv);
111 static int lfs_data_version(int argc, char **argv);
112 static int lfs_hsm_state(int argc, char **argv);
113 static int lfs_hsm_set(int argc, char **argv);
114 static int lfs_hsm_clear(int argc, char **argv);
115 static int lfs_hsm_action(int argc, char **argv);
116 static int lfs_hsm_archive(int argc, char **argv);
117 static int lfs_hsm_restore(int argc, char **argv);
118 static int lfs_hsm_release(int argc, char **argv);
119 static int lfs_hsm_remove(int argc, char **argv);
120 static int lfs_hsm_cancel(int argc, char **argv);
121 static int lfs_swap_layouts(int argc, char **argv);
122 static int lfs_mv(int argc, char **argv);
123 static int lfs_ladvise(int argc, char **argv);
125 /* Setstripe and migrate share mostly the same parameters */
126 #define SSM_CMD_COMMON(cmd) \
127 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
128 " [--stripe-index|-i <start_ost_idx>]\n" \
129 " [--stripe-size|-S <stripe_size>]\n" \
130 " [--pool|-p <pool_name>]\n" \
131 " [--ost-list|-o <ost_indices>]\n"
133 #define SSM_HELP_COMMON \
134 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
135 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
136 "\t respectively)\n" \
137 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
138 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
139 "\tpool_name: Name of OST pool to use (default none)\n" \
140 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
141 "\t Indices be specified in a format of:\n" \
142 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
144 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
145 "\t If --pool is set with --ost-list, then the OSTs\n" \
146 "\t must be the members of the pool."
148 #define SETSTRIPE_USAGE \
149 SSM_CMD_COMMON("setstripe") \
150 " <directory|filename>\n" \
153 #define MIGRATE_USAGE \
154 SSM_CMD_COMMON("migrate ") \
156 " [--non-block|-n]\n" \
160 "\tblock: Block file access during data migration (default)\n" \
161 "\tnon-block: Abort migrations if concurrent access is detected\n" \
163 static const char *progname;
164 static bool file_lease_supported = true;
166 /* all available commands */
167 command_t cmdlist[] = {
168 {"setstripe", lfs_setstripe, 0,
169 "Create a new file with a specific striping pattern or\n"
170 "set the default striping pattern on an existing directory or\n"
171 "delete the default striping pattern from an existing directory\n"
172 "usage: setstripe -d <directory> (to delete default striping)\n"\
175 {"getstripe", lfs_getstripe, 0,
176 "To list the striping info for a given file or files in a\n"
177 "directory or recursively for all files in a directory tree.\n"
178 "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
179 " [--stripe-count|-c] [--stripe-index|-i]\n"
180 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
181 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
183 " <directory|filename> ..."},
184 {"setdirstripe", lfs_setdirstripe, 0,
185 "To create a striped directory on a specified MDT. This can only\n"
186 "be done on MDT0 with the right of administrator.\n"
187 "usage: setdirstripe <--count|-c stripe_count>\n"
188 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
189 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
190 "\tstripe_count: stripe count of the striped directory\n"
191 "\tmdt_index: MDT index of first stripe\n"
192 "\thash_type: hash type of the striped directory. Hash types:\n"
193 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
194 " all_char sum of characters % MDT_COUNT (not recommended)\n"
195 "\tdefault_stripe: set default dirstripe of the directory\n"
196 "\tmode: the mode of the directory\n"},
197 {"getdirstripe", lfs_getdirstripe, 0,
198 "To list the striping info for a given directory\n"
199 "or recursively for all directories in a directory tree.\n"
200 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
202 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
203 {"mkdir", lfs_setdirstripe, 0,
204 "To create a striped directory on a specified MDT. This can only\n"
205 "be done on MDT0 with the right of administrator.\n"
206 "usage: mkdir <--count|-c stripe_count>\n"
207 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
208 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
209 "\tstripe_count: stripe count of the striped directory\n"
210 "\tmdt_index: MDT index of first stripe\n"
211 "\thash_type: hash type of the striped directory. Hash types:\n"
212 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
213 " all_char sum of characters % MDT_COUNT (not recommended)\n"
214 "\tdefault_stripe: set default dirstripe of the directory\n"
215 "\tmode: the mode of the directory\n"},
216 {"rm_entry", lfs_rmentry, 0,
217 "To remove the name entry of the remote directory. Note: This\n"
218 "command will only delete the name entry, i.e. the remote directory\n"
219 "will become inaccessable after this command. This can only be done\n"
220 "by the administrator\n"
221 "usage: rm_entry <dir>\n"},
222 {"pool_list", lfs_poollist, 0,
223 "List pools or pool OSTs\n"
224 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
225 {"find", lfs_find, 0,
226 "find files matching given attributes recursively in directory tree.\n"
227 "usage: find <directory|filename> ...\n"
228 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
229 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
230 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
231 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
232 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
233 " [[!] --stripe-count|-c [+-]<stripes>]\n"
234 " [[!] --stripe-index|-i <index,...>]\n"
235 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
236 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
237 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
238 " [[!] --layout|-L released,raid0]\n"
239 "\t !: used before an option indicates 'NOT' requested attribute\n"
240 "\t -: used before a value indicates 'AT MOST' requested value\n"
241 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
242 {"check", lfs_check, 0,
243 "Display the status of MDS or OSTs (as specified in the command)\n"
244 "or all the servers (MDS and OSTs).\n"
245 "usage: check <osts|mds|servers>"},
246 {"join", lfs_join, 0,
247 "join two lustre files into one.\n"
248 "obsolete, HEAD does not support it anymore.\n"},
249 {"osts", lfs_osts, 0, "list OSTs connected to client "
250 "[for specified path only]\n" "usage: osts [path]"},
251 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
252 "[for specified path only]\n" "usage: mdts [path]"},
254 "report filesystem disk space usage or inodes usage"
255 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
256 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
257 {"getname", lfs_getname, 0, "list instances and specified mount points "
258 "[for specified path only]\n"
259 "Usage: getname [-h]|[path ...] "},
260 #ifdef HAVE_SYS_QUOTA_H
261 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
262 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
263 " -b <block-softlimit> -B <block-hardlimit>\n"
264 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
265 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
266 " [--block-softlimit <block-softlimit>]\n"
267 " [--block-hardlimit <block-hardlimit>]\n"
268 " [--inode-softlimit <inode-softlimit>]\n"
269 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
270 " setquota [-t] <-u|--user|-g|--group>\n"
271 " [--block-grace <block-grace>]\n"
272 " [--inode-grace <inode-grace>] <filesystem>\n"
273 " -b can be used instead of --block-softlimit/--block-grace\n"
274 " -B can be used instead of --block-hardlimit\n"
275 " -i can be used instead of --inode-softlimit/--inode-grace\n"
276 " -I can be used instead of --inode-hardlimit\n\n"
277 "Note: The total quota space will be split into many qunits and\n"
278 " balanced over all server targets, the minimal qunit size is\n"
279 " 1M bytes for block space and 1K inodes for inode space.\n\n"
280 " Quota space rebalancing process will stop when this mininum\n"
281 " value is reached. As a result, quota exceeded can be returned\n"
282 " while many targets still have 1MB or 1K inodes of spare\n"
284 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
285 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
287 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
288 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
290 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
291 "usage: flushctx [-k] [mountpoint...]"},
292 {"lsetfacl", lfs_lsetfacl, 0,
293 "Remote user setfacl for user/group on the same remote client.\n"
294 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
295 {"lgetfacl", lfs_lgetfacl, 0,
296 "Remote user getfacl for user/group on the same remote client.\n"
297 "usage: lgetfacl [-dRLPvh] file ..."},
298 {"rsetfacl", lfs_rsetfacl, 0,
299 "Remote user setfacl for user/group on other clients.\n"
300 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
301 {"rgetfacl", lfs_rgetfacl, 0,
302 "Remote user getfacl for user/group on other clients.\n"
303 "usage: rgetfacl [-dRLPvh] file ..."},
305 "Remote user copy files and directories.\n"
306 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
308 "Remote user list directory contents.\n"
309 "usage: ls [OPTION]... [FILE]..."},
310 {"changelog", lfs_changelog, 0,
311 "Show the metadata changes on an MDT."
312 "\nusage: changelog <mdtname> [startrec [endrec]]"},
313 {"changelog_clear", lfs_changelog_clear, 0,
314 "Indicate that old changelog records up to <endrec> are no longer of "
315 "interest to consumer <id>, allowing the system to free up space.\n"
316 "An <endrec> of 0 means all records.\n"
317 "usage: changelog_clear <mdtname> <id> <endrec>"},
318 {"fid2path", lfs_fid2path, 0,
319 "Resolve the full path(s) for given FID(s). For a specific hardlink "
320 "specify link number <linkno>.\n"
321 /* "For a historical link name, specify changelog record <recno>.\n" */
322 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
323 /* [ --rec <recno> ] */ },
324 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
325 "usage: path2fid [--parents] <path> ..."},
326 {"data_version", lfs_data_version, 0, "Display file data version for "
327 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
328 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
329 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
330 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
331 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
332 "[--archived] [--lost] <file> ..."},
333 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
335 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
336 "[--archived] [--lost] <file> ..."},
337 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
338 "given files.\n" "usage: hsm_action <file> ..."},
339 {"hsm_archive", lfs_hsm_archive, 0,
340 "Archive file to external storage.\n"
341 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
343 {"hsm_restore", lfs_hsm_restore, 0,
344 "Restore file from external storage.\n"
345 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
346 {"hsm_release", lfs_hsm_release, 0,
347 "Release files from Lustre.\n"
348 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
349 {"hsm_remove", lfs_hsm_remove, 0,
350 "Remove file copy from external storage.\n"
351 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
352 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
354 "Note: To remove files from the archive that have been deleted on\n"
355 "Lustre, set mntpath and optionally archive. In that case, all the\n"
356 "positional arguments and entries in the file list must be FIDs."
358 {"hsm_cancel", lfs_hsm_cancel, 0,
359 "Cancel requests related to specified files.\n"
360 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
361 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
362 "usage: swap_layouts <path1> <path2>"},
363 {"migrate", lfs_setstripe, 0,
364 "migrate a directory between MDTs.\n"
365 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
367 "\tmdt_idx: index of the destination MDT\n"},
368 {"migrate", lfs_setstripe, 0,
369 "migrate file objects from one OST "
370 "layout\nto another (may be not safe with concurent writes).\n"
372 "[--stripe-count|-c] <stripe_count>\n"
373 "[--stripe-index|-i] <start_ost_index>\n"
374 "[--stripe-size|-S] <stripe_size>\n"
375 "[--pool|-p] <pool_name>\n"
376 "[--ost-list|-o] <ost_indices>\n"
380 "\tstripe_count: number of OSTs to stripe a file over\n"
381 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
382 "\tstripe_size: number of bytes to store before moving to the next OST\n"
383 "\tpool_name: name of the predefined pool of OSTs\n"
384 "\tost_indices: OSTs to stripe over, in order\n"
385 "\tblock: wait for the operation to return before continuing\n"
386 "\tnon-block: do not wait for the operation to return.\n"},
388 "To move directories between MDTs. This command is deprecated, "
389 "use \"migrate\" instead.\n"
390 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
392 {"ladvise", lfs_ladvise, 0,
393 "Provide servers with advice about access patterns for a file.\n"
394 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
395 " [--background|-b]\n"
396 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
398 {"help", Parser_help, 0, "help"},
399 {"exit", Parser_quit, 0, "quit"},
400 {"quit", Parser_quit, 0, "quit"},
401 {"--version", Parser_version, 0,
402 "output build version of the utility and exit"},
407 #define MIGRATION_NONBLOCK 1
410 * Internal helper for migrate_copy_data(). Check lease and report error if
413 * \param[in] fd File descriptor on which to check the lease.
414 * \param[out] lease_broken Set to true if the lease was broken.
415 * \param[in] group_locked Whether a group lock was taken or not.
416 * \param[in] path Name of the file being processed, for error
419 * \retval 0 Migration can keep on going.
420 * \retval -errno Error occurred, abort migration.
422 static int check_lease(int fd, bool *lease_broken, bool group_locked,
427 if (!file_lease_supported)
430 rc = llapi_lease_check(fd);
432 return 0; /* llapi_check_lease returns > 0 on success. */
435 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
437 rc = rc ? rc : -EAGAIN;
439 fprintf(stderr, "%s: external attempt to access file '%s' "
440 "blocked until migration ends.\n", progname, path);
443 *lease_broken = true;
447 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
448 bool group_locked, const char *fname)
457 bool lease_broken = false;
459 /* Use a page-aligned buffer for direct I/O */
460 rc = posix_memalign(&buf, getpagesize(), buf_size);
465 /* read new data only if we have written all
466 * previously read data */
469 rc = check_lease(fd_src, &lease_broken,
470 group_locked, fname);
474 rsize = read(fd_src, buf, buf_size);
477 fprintf(stderr, "%s: %s: read failed: %s\n",
478 progname, fname, strerror(-rc));
488 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
492 "%s: %s: write failed on volatile: %s\n",
493 progname, fname, strerror(-rc));
503 fprintf(stderr, "%s: %s: fsync failed: %s\n",
504 progname, fname, strerror(-rc));
512 static int migrate_copy_timestamps(int fdv, const struct stat *st)
514 struct timeval tv[2] = {
515 {.tv_sec = st->st_atime},
516 {.tv_sec = st->st_mtime}
519 return futimes(fdv, tv);
522 static int migrate_block(int fd, int fdv, const struct stat *st,
523 size_t buf_size, const char *name)
530 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
532 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
533 progname, name, strerror(-rc));
541 /* The grouplock blocks all concurrent accesses to the file.
542 * It has to be taken after llapi_get_data_version as it would
544 rc = llapi_group_lock(fd, gid);
546 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
547 progname, name, strerror(-rc));
551 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
553 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
557 /* Make sure we keep original atime/mtime values */
558 rc = migrate_copy_timestamps(fdv, st);
560 fprintf(stderr, "%s: %s: timestamp copy failed\n",
566 * for a migration we need to check data version on file did
569 * Pass in gid=0 since we already own grouplock. */
570 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
571 SWAP_LAYOUTS_CHECK_DV1);
573 fprintf(stderr, "%s: %s: dataversion changed during copy, "
574 "migration aborted\n", progname, name);
577 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
578 name, strerror(-rc));
583 rc2 = llapi_group_unlock(fd, gid);
584 if (rc2 < 0 && rc == 0) {
585 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
586 progname, name, strerror(-rc2));
593 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
594 size_t buf_size, const char *name)
600 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
602 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
603 progname, name, strerror(-rc));
607 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
609 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
613 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
615 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
616 progname, name, strerror(-rc));
622 fprintf(stderr, "%s: %s: data version changed during "
628 /* Make sure we keep original atime/mtime values */
629 rc = migrate_copy_timestamps(fdv, st);
631 fprintf(stderr, "%s: %s: timestamp copy failed\n",
636 /* Atomically put lease, swap layouts and close.
637 * for a migration we need to check data version on file did
639 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
641 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
642 progname, name, strerror(-rc));
649 static int lfs_migrate(char *name, __u64 migration_flags,
650 struct llapi_stripe_param *param)
654 char parent[PATH_MAX];
657 char volatile_file[sizeof(parent) +
658 LUSTRE_VOLATILE_HDR_LEN +
659 2 * sizeof(mdt_index) +
660 2 * sizeof(random_value) + 4];
663 struct lov_user_md *lum = NULL;
666 bool have_lease_rdlck = false;
670 /* find the right size for the IO and allocate the buffer */
671 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
672 lum = malloc(lum_size);
678 rc = llapi_file_get_stripe(name, lum);
679 /* failure can happen for many reasons and some may be not real errors
681 * in case of a real error, a later call will fail with better
682 * error management */
684 buf_size = 1024 * 1024;
686 buf_size = lum->lmm_stripe_size;
688 /* open file, direct io */
689 /* even if the file is only read, WR mode is nedeed to allow
690 * layout swap on fd */
691 fd = open(name, O_RDWR | O_DIRECT);
694 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
699 if (file_lease_supported) {
700 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
701 if (rc == -EOPNOTSUPP) {
702 /* Older servers do not support file lease.
703 * Disable related checks. This opens race conditions
704 * as explained in LU-4840 */
705 file_lease_supported = false;
707 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
708 progname, name, strerror(-rc));
711 have_lease_rdlck = true;
715 /* search for file directory pathname */
716 if (strlen(name) > sizeof(parent)-1) {
720 strncpy(parent, name, sizeof(parent));
721 ptr = strrchr(parent, '/');
723 if (getcwd(parent, sizeof(parent)) == NULL) {
734 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
736 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
737 progname, name, strerror(-rc));
742 random_value = random();
743 rc = snprintf(volatile_file, sizeof(volatile_file),
744 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
745 mdt_index, random_value);
746 if (rc >= sizeof(volatile_file)) {
751 /* create, open a volatile file, use caching (ie no directio) */
752 fdv = llapi_file_open_param(volatile_file,
753 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
754 S_IRUSR | S_IWUSR, param);
755 } while (fdv == -EEXIST);
759 fprintf(stderr, "%s: %s: cannot create volatile file in"
761 progname, parent, strerror(-rc));
765 /* Not-owner (root?) special case.
766 * Need to set owner/group of volatile file like original.
767 * This will allow to pass related check during layout_swap.
772 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
776 rc = fstat(fdv, &stv);
779 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
780 volatile_file, strerror(errno));
783 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
784 rc = fchown(fdv, st.st_uid, st.st_gid);
787 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
788 name, strerror(errno));
793 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
794 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
796 have_lease_rdlck = false;
797 fdv = -1; /* The volatile file is closed as we put the
798 * lease in non-blocking mode. */
801 /* Blocking mode (forced if servers do not support file lease).
802 * It is also the default mode, since we cannot distinguish
803 * between a broken lease and a server that does not support
804 * atomic swap/close (LU-6785) */
805 rc = migrate_block(fd, fdv, &st, buf_size, name);
809 if (have_lease_rdlck)
826 * Parse a string containing an OST index list into an array of integers.
828 * The input string contains a comma delimited list of individual
829 * indices and ranges, for example "1,2-4,7". Add the indices into the
830 * \a osts array and remove duplicates.
832 * \param[out] osts array to store indices in
833 * \param[in] size size of \a osts array
834 * \param[in] offset starting index in \a osts
835 * \param[in] arg string containing OST index list
837 * \retval positive number of indices in \a osts
838 * \retval -EINVAL unable to parse \a arg
840 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
844 int slots = size - offset;
852 while (!end_of_loop) {
860 ptr = strchrnul(arg, ',');
862 end_of_loop = *ptr == '\0';
865 start_index = strtol(arg, &endptr, 0);
866 if (endptr == arg) /* no data at all */
868 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
873 end_index = start_index;
874 if (*endptr == '-') {
875 end_index = strtol(endptr + 1, &endptr, 0);
878 if (end_index < start_index)
882 for (i = start_index; i <= end_index && slots > 0; i++) {
885 /* remove duplicate */
886 for (j = 0; j < offset; j++) {
890 if (j == offset) { /* no duplicate */
895 if (slots == 0 && i < end_index)
903 if (!end_of_loop && ptr != NULL)
906 return rc < 0 ? rc : nr;
910 static int lfs_setstripe(int argc, char **argv)
912 struct llapi_stripe_param *param = NULL;
913 struct find_param migrate_mdt_param = {
920 unsigned long long st_size;
921 int st_offset, st_count;
925 char *stripe_size_arg = NULL;
926 char *stripe_off_arg = NULL;
927 char *stripe_count_arg = NULL;
928 char *pool_name_arg = NULL;
929 char *mdt_idx_arg = NULL;
930 unsigned long long size_units = 1;
931 bool migrate_mode = false;
932 bool migration_block = false;
933 __u64 migration_flags = 0;
934 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
937 struct option long_opts[] = {
938 /* --block is only valid in migrate mode */
939 {"block", no_argument, 0, 'b'},
940 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
941 /* This formerly implied "stripe-count", but was explicitly
942 * made "stripe-count" for consistency with other options,
943 * and to separate it from "mdt-count" when DNE arrives. */
944 {"count", required_argument, 0, 'c'},
946 {"stripe-count", required_argument, 0, 'c'},
947 {"stripe_count", required_argument, 0, 'c'},
948 {"delete", no_argument, 0, 'd'},
949 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
950 /* This formerly implied "stripe-index", but was explicitly
951 * made "stripe-index" for consistency with other options,
952 * and to separate it from "mdt-index" when DNE arrives. */
953 {"index", required_argument, 0, 'i'},
955 {"stripe-index", required_argument, 0, 'i'},
956 {"stripe_index", required_argument, 0, 'i'},
957 {"mdt-index", required_argument, 0, 'm'},
958 {"mdt_index", required_argument, 0, 'm'},
959 /* --non-block is only valid in migrate mode */
960 {"non-block", no_argument, 0, 'n'},
961 {"ost-list", required_argument, 0, 'o'},
962 {"ost_list", required_argument, 0, 'o'},
963 {"pool", required_argument, 0, 'p'},
964 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
965 /* This formerly implied "--stripe-size", but was confusing
966 * with "lfs find --size|-s", which means "file size", so use
967 * the consistent "--stripe-size|-S" for all commands. */
968 {"size", required_argument, 0, 's'},
970 {"stripe-size", required_argument, 0, 'S'},
971 {"stripe_size", required_argument, 0, 'S'},
972 /* --verbose is only valid in migrate mode */
973 {"verbose", no_argument, 0, 'v'},
981 if (strcmp(argv[0], "migrate") == 0)
984 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
985 long_opts, NULL)) >= 0) {
992 fprintf(stderr, "--block is valid only for"
996 migration_block = true;
999 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1000 if (strcmp(argv[optind - 1], "--count") == 0)
1001 fprintf(stderr, "warning: '--count' deprecated"
1002 ", use '--stripe-count' instead\n");
1004 stripe_count_arg = optarg;
1007 /* delete the default striping pattern */
1011 nr_osts = parse_targets(osts,
1012 sizeof(osts) / sizeof(__u32),
1016 "error: %s: bad OST indices '%s'\n",
1021 if (st_offset == -1) /* first in the command line */
1022 st_offset = osts[0];
1025 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1026 if (strcmp(argv[optind - 1], "--index") == 0)
1027 fprintf(stderr, "warning: '--index' deprecated"
1028 ", use '--stripe-index' instead\n");
1030 stripe_off_arg = optarg;
1033 if (!migrate_mode) {
1034 fprintf(stderr, "--mdt-index is valid only for"
1038 mdt_idx_arg = optarg;
1041 if (!migrate_mode) {
1042 fprintf(stderr, "--non-block is valid only for"
1046 migration_flags |= MIGRATION_NONBLOCK;
1048 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1050 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1051 fprintf(stderr, "warning: '--size|-s' deprecated, "
1052 "use '--stripe-size|-S' instead\n");
1054 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1056 stripe_size_arg = optarg;
1059 pool_name_arg = optarg;
1062 if (!migrate_mode) {
1063 fprintf(stderr, "--verbose is valid only for"
1067 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1074 fname = argv[optind];
1077 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1078 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1079 fprintf(stderr, "error: %s: cannot specify -d with "
1080 "-s, -c, -o, or -p options\n",
1085 if (optind == argc) {
1086 fprintf(stderr, "error: %s: missing filename|dirname\n",
1091 if (mdt_idx_arg != NULL && optind > 3) {
1092 fprintf(stderr, "error: %s: cannot specify -m with other "
1093 "options\n", argv[0]);
1097 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1099 "error: %s: cannot specify --non-block and --block\n",
1104 if (pool_name_arg != NULL) {
1108 ptr = strchr(pool_name_arg, '.');
1110 ptr = pool_name_arg;
1112 if ((ptr - pool_name_arg) == 0) {
1113 fprintf(stderr, "error: %s: fsname is empty "
1114 "in pool name '%s'\n",
1115 argv[0], pool_name_arg);
1122 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1124 fprintf(stderr, "error: %s: poolname '%s' is "
1126 argv[0], pool_name_arg);
1128 } else if (rc == -2) {
1129 fprintf(stderr, "error: %s: pool name '%s' is too long "
1130 "(max is %d characters)\n",
1131 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1133 } else if (rc > 0) {
1134 fprintf(stderr, "error: %s: char '%c' not allowed in "
1136 argv[0], rc, pool_name_arg);
1141 /* get the stripe size */
1142 if (stripe_size_arg != NULL) {
1143 result = llapi_parse_size(stripe_size_arg, &st_size,
1146 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1147 argv[0], stripe_size_arg);
1151 /* get the stripe offset */
1152 if (stripe_off_arg != NULL) {
1153 st_offset = strtol(stripe_off_arg, &end, 0);
1155 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1156 argv[0], stripe_off_arg);
1160 /* get the stripe count */
1161 if (stripe_count_arg != NULL) {
1162 st_count = strtoul(stripe_count_arg, &end, 0);
1164 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1165 argv[0], stripe_count_arg);
1170 if (mdt_idx_arg != NULL) {
1171 /* initialize migrate mdt parameters */
1172 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1174 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1175 argv[0], mdt_idx_arg);
1178 migrate_mdt_param.fp_migrate = 1;
1180 /* initialize stripe parameters */
1181 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1182 if (param == NULL) {
1183 fprintf(stderr, "error: %s: run out of memory\n",
1188 param->lsp_stripe_size = st_size;
1189 param->lsp_stripe_offset = st_offset;
1190 param->lsp_stripe_count = st_count;
1191 param->lsp_stripe_pattern = 0;
1192 param->lsp_pool = pool_name_arg;
1193 param->lsp_is_specific = false;
1195 if (st_count > 0 && nr_osts != st_count) {
1196 fprintf(stderr, "error: %s: stripe count '%d' "
1197 "doesn't match the number of OSTs: %d\n"
1198 , argv[0], st_count, nr_osts);
1203 param->lsp_is_specific = true;
1204 param->lsp_stripe_count = nr_osts;
1205 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1209 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1210 if (!migrate_mode) {
1211 result = llapi_file_open_param(fname,
1218 } else if (mdt_idx_arg != NULL) {
1219 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1221 result = lfs_migrate(fname, migration_flags, param);
1224 /* Save the first error encountered. */
1228 "error: %s: %s file '%s' failed\n",
1229 argv[0], migrate_mode ? "migrate" : "create",
1239 static int lfs_poollist(int argc, char **argv)
1244 return llapi_poollist(argv[1]);
1247 static int set_time(time_t *time, time_t *set, char *str)
1254 else if (str[0] == '-')
1260 t = strtol(str, NULL, 0);
1261 if (*time < t * 24 * 60 * 60) {
1264 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1268 *set = *time - t * 24 * 60 * 60;
1275 static int name2id(unsigned int *id, char *name, int type)
1278 struct passwd *entry;
1280 if (!(entry = getpwnam(name))) {
1286 *id = entry->pw_uid;
1288 struct group *entry;
1290 if (!(entry = getgrnam(name))) {
1296 *id = entry->gr_gid;
1302 static int id2name(char **name, unsigned int id, int type)
1305 struct passwd *entry;
1307 if (!(entry = getpwuid(id))) {
1313 *name = entry->pw_name;
1315 struct group *entry;
1317 if (!(entry = getgrgid(id))) {
1323 *name = entry->gr_name;
1329 static int name2layout(__u32 *layout, char *name)
1334 for (ptr = name; ; ptr = NULL) {
1335 lyt = strtok(ptr, ",");
1338 if (strcmp(lyt, "released") == 0)
1339 *layout |= LOV_PATTERN_F_RELEASED;
1340 else if (strcmp(lyt, "raid0") == 0)
1341 *layout |= LOV_PATTERN_RAID0;
1348 #define FIND_POOL_OPT 3
1349 static int lfs_find(int argc, char **argv)
1354 struct find_param param = {
1358 struct option long_opts[] = {
1359 {"atime", required_argument, 0, 'A'},
1360 {"stripe-count", required_argument, 0, 'c'},
1361 {"stripe_count", required_argument, 0, 'c'},
1362 {"ctime", required_argument, 0, 'C'},
1363 {"maxdepth", required_argument, 0, 'D'},
1364 {"gid", required_argument, 0, 'g'},
1365 {"group", required_argument, 0, 'G'},
1366 {"stripe-index", required_argument, 0, 'i'},
1367 {"stripe_index", required_argument, 0, 'i'},
1368 {"layout", required_argument, 0, 'L'},
1369 {"mdt", required_argument, 0, 'm'},
1370 {"mtime", required_argument, 0, 'M'},
1371 {"name", required_argument, 0, 'n'},
1372 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1373 {"obd", required_argument, 0, 'O'},
1374 {"ost", required_argument, 0, 'O'},
1375 /* no short option for pool, p/P already used */
1376 {"pool", required_argument, 0, FIND_POOL_OPT},
1377 {"print0", no_argument, 0, 'p'},
1378 {"print", no_argument, 0, 'P'},
1379 {"size", required_argument, 0, 's'},
1380 {"stripe-size", required_argument, 0, 'S'},
1381 {"stripe_size", required_argument, 0, 'S'},
1382 {"type", required_argument, 0, 't'},
1383 {"uid", required_argument, 0, 'u'},
1384 {"user", required_argument, 0, 'U'},
1397 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1398 while ((c = getopt_long_only(argc, argv,
1399 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1400 long_opts, NULL)) >= 0) {
1405 /* '!' is part of option */
1406 /* when getopt_long_only() finds a string which is not
1407 * an option nor a known option argument it returns 1
1408 * in that case if we already have found pathstart and pathend
1409 * (i.e. we have the list of pathnames),
1410 * the only supported value is "!"
1412 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1413 if (!isoption && pathend != -1) {
1414 fprintf(stderr, "err: %s: filename|dirname must either "
1415 "precede options or follow options\n",
1420 if (!isoption && pathstart == -1)
1421 pathstart = optind - 1;
1422 if (isoption && pathstart != -1 && pathend == -1)
1423 pathend = optind - 2;
1429 /* unknown; opt is "!" or path component,
1430 * checking done above.
1432 if (strcmp(optarg, "!") == 0)
1436 xtime = ¶m.fp_atime;
1437 xsign = ¶m.fp_asign;
1438 param.fp_exclude_atime = !!neg_opt;
1439 /* no break, this falls through to 'C' for ctime */
1442 xtime = ¶m.fp_ctime;
1443 xsign = ¶m.fp_csign;
1444 param.fp_exclude_ctime = !!neg_opt;
1446 /* no break, this falls through to 'M' for mtime */
1449 xtime = ¶m.fp_mtime;
1450 xsign = ¶m.fp_msign;
1451 param.fp_exclude_mtime = !!neg_opt;
1453 rc = set_time(&t, xtime, optarg);
1454 if (rc == INT_MAX) {
1462 if (optarg[0] == '+') {
1463 param.fp_stripe_count_sign = -1;
1465 } else if (optarg[0] == '-') {
1466 param.fp_stripe_count_sign = 1;
1470 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1471 if (*endptr != '\0') {
1472 fprintf(stderr,"error: bad stripe_count '%s'\n",
1477 param.fp_check_stripe_count = 1;
1478 param.fp_exclude_stripe_count = !!neg_opt;
1481 param.fp_max_depth = strtol(optarg, 0, 0);
1485 rc = name2id(¶m.fp_gid, optarg, GROUP);
1487 param.fp_gid = strtoul(optarg, &endptr, 10);
1488 if (*endptr != '\0') {
1489 fprintf(stderr, "Group/GID: %s cannot "
1490 "be found.\n", optarg);
1495 param.fp_exclude_gid = !!neg_opt;
1496 param.fp_check_gid = 1;
1499 ret = name2layout(¶m.fp_layout, optarg);
1502 param.fp_exclude_layout = !!neg_opt;
1503 param.fp_check_layout = 1;
1507 rc = name2id(¶m.fp_uid, optarg, USER);
1509 param.fp_uid = strtoul(optarg, &endptr, 10);
1510 if (*endptr != '\0') {
1511 fprintf(stderr, "User/UID: %s cannot "
1512 "be found.\n", optarg);
1517 param.fp_exclude_uid = !!neg_opt;
1518 param.fp_check_uid = 1;
1521 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1523 "Pool name %s is too long"
1524 " (max is %d)\n", optarg,
1529 /* we do check for empty pool because empty pool
1530 * is used to find V1 lov attributes */
1531 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1532 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1533 param.fp_exclude_pool = !!neg_opt;
1534 param.fp_check_pool = 1;
1537 param.fp_pattern = (char *)optarg;
1538 param.fp_exclude_pattern = !!neg_opt;
1543 char *buf, *token, *next, *p;
1547 buf = strdup(optarg);
1553 param.fp_exclude_obd = !!neg_opt;
1556 while (token && *token) {
1557 token = strchr(token, ',');
1564 param.fp_exclude_mdt = !!neg_opt;
1565 param.fp_num_alloc_mdts += len;
1566 tmp = realloc(param.fp_mdt_uuid,
1567 param.fp_num_alloc_mdts *
1568 sizeof(*param.fp_mdt_uuid));
1574 param.fp_mdt_uuid = tmp;
1576 param.fp_exclude_obd = !!neg_opt;
1577 param.fp_num_alloc_obds += len;
1578 tmp = realloc(param.fp_obd_uuid,
1579 param.fp_num_alloc_obds *
1580 sizeof(*param.fp_obd_uuid));
1586 param.fp_obd_uuid = tmp;
1588 for (token = buf; token && *token; token = next) {
1589 struct obd_uuid *puuid;
1592 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1595 ¶m.fp_obd_uuid[param.fp_num_obds++];
1597 p = strchr(token, ',');
1604 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1609 strncpy(puuid->uuid, token,
1610 sizeof(puuid->uuid));
1618 param.fp_zero_end = 1;
1623 if (optarg[0] == '+') {
1624 param.fp_size_sign = -1;
1626 } else if (optarg[0] == '-') {
1627 param.fp_size_sign = 1;
1631 ret = llapi_parse_size(optarg, ¶m.fp_size,
1632 ¶m.fp_size_units, 0);
1634 fprintf(stderr, "error: bad file size '%s'\n",
1638 param.fp_check_size = 1;
1639 param.fp_exclude_size = !!neg_opt;
1642 if (optarg[0] == '+') {
1643 param.fp_stripe_size_sign = -1;
1645 } else if (optarg[0] == '-') {
1646 param.fp_stripe_size_sign = 1;
1650 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1651 ¶m.fp_stripe_size_units, 0);
1653 fprintf(stderr, "error: bad stripe_size '%s'\n",
1657 param.fp_check_stripe_size = 1;
1658 param.fp_exclude_stripe_size = !!neg_opt;
1661 param.fp_exclude_type = !!neg_opt;
1662 switch (optarg[0]) {
1664 param.fp_type = S_IFBLK;
1667 param.fp_type = S_IFCHR;
1670 param.fp_type = S_IFDIR;
1673 param.fp_type = S_IFREG;
1676 param.fp_type = S_IFLNK;
1679 param.fp_type = S_IFIFO;
1682 param.fp_type = S_IFSOCK;
1685 fprintf(stderr, "error: %s: bad type '%s'\n",
1697 if (pathstart == -1) {
1698 fprintf(stderr, "error: %s: no filename|pathname\n",
1702 } else if (pathend == -1) {
1708 rc = llapi_find(argv[pathstart], ¶m);
1709 if (rc != 0 && ret == 0)
1711 } while (++pathstart < pathend);
1714 fprintf(stderr, "error: %s failed for %s.\n",
1715 argv[0], argv[optind - 1]);
1717 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1718 free(param.fp_obd_uuid);
1720 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1721 free(param.fp_mdt_uuid);
1726 static int lfs_getstripe_internal(int argc, char **argv,
1727 struct find_param *param)
1729 struct option long_opts[] = {
1730 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1731 /* This formerly implied "stripe-count", but was explicitly
1732 * made "stripe-count" for consistency with other options,
1733 * and to separate it from "mdt-count" when DNE arrives. */
1734 {"count", no_argument, 0, 'c'},
1736 {"stripe-count", no_argument, 0, 'c'},
1737 {"stripe_count", no_argument, 0, 'c'},
1738 {"directory", no_argument, 0, 'd'},
1739 {"default", no_argument, 0, 'D'},
1740 {"generation", no_argument, 0, 'g'},
1741 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1742 /* This formerly implied "stripe-index", but was explicitly
1743 * made "stripe-index" for consistency with other options,
1744 * and to separate it from "mdt-index" when DNE arrives. */
1745 {"index", no_argument, 0, 'i'},
1747 {"stripe-index", no_argument, 0, 'i'},
1748 {"stripe_index", no_argument, 0, 'i'},
1749 {"layout", no_argument, 0, 'L'},
1750 {"mdt-index", no_argument, 0, 'M'},
1751 {"mdt_index", no_argument, 0, 'M'},
1752 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1753 /* This formerly implied "stripe-index", but was confusing
1754 * with "file offset" (which will eventually be needed for
1755 * with different layouts by offset), so deprecate it. */
1756 {"offset", no_argument, 0, 'o'},
1758 {"obd", required_argument, 0, 'O'},
1759 {"ost", required_argument, 0, 'O'},
1760 {"pool", no_argument, 0, 'p'},
1761 {"quiet", no_argument, 0, 'q'},
1762 {"recursive", no_argument, 0, 'r'},
1763 {"raw", no_argument, 0, 'R'},
1764 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1765 /* This formerly implied "--stripe-size", but was confusing
1766 * with "lfs find --size|-s", which means "file size", so use
1767 * the consistent "--stripe-size|-S" for all commands. */
1768 {"size", no_argument, 0, 's'},
1770 {"stripe-size", no_argument, 0, 'S'},
1771 {"stripe_size", no_argument, 0, 'S'},
1772 {"verbose", no_argument, 0, 'v'},
1777 param->fp_max_depth = 1;
1778 while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1779 long_opts, NULL)) != -1) {
1782 if (param->fp_obd_uuid) {
1784 "error: %s: only one obduuid allowed",
1788 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1794 param->fp_max_depth = 0;
1797 param->fp_get_default_lmv = 1;
1800 param->fp_recursive = 1;
1803 param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1806 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1807 if (strcmp(argv[optind - 1], "--count") == 0)
1808 fprintf(stderr, "warning: '--count' deprecated,"
1809 " use '--stripe-count' instead\n");
1811 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1812 param->fp_verbose |= VERBOSE_COUNT;
1813 param->fp_max_depth = 0;
1816 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1818 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1819 fprintf(stderr, "warning: '--size|-s' deprecated, "
1820 "use '--stripe-size|-S' instead\n");
1822 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1824 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1825 param->fp_verbose |= VERBOSE_SIZE;
1826 param->fp_max_depth = 0;
1829 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1831 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1832 "use '--stripe-index|-i' instead\n");
1835 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1836 if (strcmp(argv[optind - 1], "--index") == 0)
1837 fprintf(stderr, "warning: '--index' deprecated"
1838 ", use '--stripe-index' instead\n");
1840 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1841 param->fp_verbose |= VERBOSE_OFFSET;
1842 param->fp_max_depth = 0;
1846 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1847 param->fp_verbose |= VERBOSE_POOL;
1848 param->fp_max_depth = 0;
1852 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1853 param->fp_verbose |= VERBOSE_GENERATION;
1854 param->fp_max_depth = 0;
1858 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1859 param->fp_verbose |= VERBOSE_LAYOUT;
1860 param->fp_max_depth = 0;
1864 if (!(param->fp_verbose & VERBOSE_DETAIL))
1865 param->fp_max_depth = 0;
1866 param->fp_verbose |= VERBOSE_MDTINDEX;
1879 if (param->fp_recursive)
1880 param->fp_max_depth = -1;
1882 if (!param->fp_verbose)
1883 param->fp_verbose = VERBOSE_ALL;
1884 if (param->fp_quiet)
1885 param->fp_verbose = VERBOSE_OBJID;
1888 rc = llapi_getstripe(argv[optind], param);
1889 } while (++optind < argc && !rc);
1892 fprintf(stderr, "error: %s failed for %s.\n",
1893 argv[0], argv[optind - 1]);
1897 static int lfs_tgts(int argc, char **argv)
1899 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1900 struct find_param param;
1901 int index = 0, rc=0;
1906 if (argc == 2 && !realpath(argv[1], path)) {
1908 fprintf(stderr, "error: invalid path '%s': %s\n",
1909 argv[1], strerror(-rc));
1913 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1914 /* Check if we have a mount point */
1915 if (mntdir[0] == '\0')
1918 memset(¶m, 0, sizeof(param));
1919 if (!strcmp(argv[0], "mdts"))
1920 param.fp_get_lmv = 1;
1922 rc = llapi_ostlist(mntdir, ¶m);
1924 fprintf(stderr, "error: %s: failed on %s\n",
1927 if (path[0] != '\0')
1929 memset(mntdir, 0, PATH_MAX);
1935 static int lfs_getstripe(int argc, char **argv)
1937 struct find_param param = { 0 };
1938 return lfs_getstripe_internal(argc, argv, ¶m);
1942 static int lfs_getdirstripe(int argc, char **argv)
1944 struct find_param param = { 0 };
1946 param.fp_get_lmv = 1;
1947 return lfs_getstripe_internal(argc, argv, ¶m);
1951 static int lfs_setdirstripe(int argc, char **argv)
1955 unsigned int stripe_offset = -1;
1956 unsigned int stripe_count = 1;
1957 enum lmv_hash_type hash_type;
1960 char *stripe_offset_opt = NULL;
1961 char *stripe_count_opt = NULL;
1962 char *stripe_hash_opt = NULL;
1963 char *mode_opt = NULL;
1964 bool default_stripe = false;
1965 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1966 mode_t previous_mode = 0;
1967 bool delete = false;
1969 struct option long_opts[] = {
1970 {"count", required_argument, 0, 'c'},
1971 {"delete", no_argument, 0, 'd'},
1972 {"index", required_argument, 0, 'i'},
1973 {"mode", required_argument, 0, 'm'},
1974 {"hash-type", required_argument, 0, 't'},
1975 {"default_stripe", no_argument, 0, 'D'},
1979 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1986 stripe_count_opt = optarg;
1990 default_stripe = true;
1993 default_stripe = true;
1996 stripe_offset_opt = optarg;
2002 stripe_hash_opt = optarg;
2005 fprintf(stderr, "error: %s: option '%s' "
2007 argv[0], argv[optind - 1]);
2012 if (optind == argc) {
2013 fprintf(stderr, "error: %s: missing dirname\n",
2018 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2019 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2024 if (stripe_offset_opt != NULL) {
2025 /* get the stripe offset */
2026 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2028 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2029 argv[0], stripe_offset_opt);
2035 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2036 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2037 " or -i options.\n", argv[0]);
2045 if (mode_opt != NULL) {
2046 mode = strtoul(mode_opt, &end, 8);
2048 fprintf(stderr, "error: %s: bad mode '%s'\n",
2052 previous_mode = umask(0);
2055 if (stripe_hash_opt == NULL ||
2056 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2057 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2058 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2059 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2061 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2062 argv[0], stripe_hash_opt);
2066 /* get the stripe count */
2067 if (stripe_count_opt != NULL) {
2068 stripe_count = strtoul(stripe_count_opt, &end, 0);
2070 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2071 argv[0], stripe_count_opt);
2076 dname = argv[optind];
2078 if (default_stripe) {
2079 result = llapi_dir_set_default_lmv_stripe(dname,
2080 stripe_offset, stripe_count,
2083 result = llapi_dir_create_pool(dname, mode,
2085 stripe_count, hash_type,
2090 fprintf(stderr, "error: %s: create stripe dir '%s' "
2091 "failed\n", argv[0], dname);
2094 dname = argv[++optind];
2095 } while (dname != NULL);
2097 if (mode_opt != NULL)
2098 umask(previous_mode);
2104 static int lfs_rmentry(int argc, char **argv)
2111 fprintf(stderr, "error: %s: missing dirname\n",
2117 dname = argv[index];
2118 while (dname != NULL) {
2119 result = llapi_direntry_remove(dname);
2121 fprintf(stderr, "error: %s: remove dir entry '%s' "
2122 "failed\n", argv[0], dname);
2125 dname = argv[++index];
2130 static int lfs_mv(int argc, char **argv)
2132 struct find_param param = {
2139 struct option long_opts[] = {
2140 {"mdt-index", required_argument, 0, 'M'},
2141 {"verbose", no_argument, 0, 'v'},
2145 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2148 param.fp_mdt_index = strtoul(optarg, &end, 0);
2150 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2157 param.fp_verbose = VERBOSE_DETAIL;
2161 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2162 argv[0], argv[optind - 1]);
2167 if (param.fp_mdt_index == -1) {
2168 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2172 if (optind >= argc) {
2173 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2177 param.fp_migrate = 1;
2178 rc = llapi_migrate_mdt(argv[optind], ¶m);
2180 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2181 argv[0], argv[optind], param.fp_mdt_index,
2186 static int lfs_osts(int argc, char **argv)
2188 return lfs_tgts(argc, argv);
2191 static int lfs_mdts(int argc, char **argv)
2193 return lfs_tgts(argc, argv);
2196 #define COOK(value) \
2199 while (value > 1024) { \
2207 #define CDF "%11llu"
2208 #define HDF "%8.1f%c"
2212 static int showdf(char *mntdir, struct obd_statfs *stat,
2213 char *uuid, int ishow, int cooked,
2214 char *type, int index, int rc)
2216 long long avail, used, total;
2218 char *suffix = "KMGTPEZY";
2219 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2220 char tbuf[3 * sizeof(__u64)];
2221 char ubuf[3 * sizeof(__u64)];
2222 char abuf[3 * sizeof(__u64)];
2223 char rbuf[3 * sizeof(__u64)];
2231 avail = stat->os_ffree;
2232 used = stat->os_files - stat->os_ffree;
2233 total = stat->os_files;
2235 int shift = cooked ? 0 : 10;
2237 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2238 used = ((stat->os_blocks - stat->os_bfree) *
2239 stat->os_bsize) >> shift;
2240 total = (stat->os_blocks * stat->os_bsize) >> shift;
2243 if ((used + avail) > 0)
2244 ratio = (double)used / (double)(used + avail);
2250 cook_val = (double)total;
2253 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2255 sprintf(tbuf, CDF, total);
2257 cook_val = (double)used;
2260 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2262 sprintf(ubuf, CDF, used);
2264 cook_val = (double)avail;
2267 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2269 sprintf(abuf, CDF, avail);
2271 sprintf(tbuf, CDF, total);
2272 sprintf(ubuf, CDF, used);
2273 sprintf(abuf, CDF, avail);
2276 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2277 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2278 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2280 printf("[%s:%d]\n", type, index);
2286 printf(UUF": inactive device\n", uuid);
2289 printf(UUF": %s\n", uuid, strerror(-rc));
2296 struct ll_stat_type {
2301 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2302 int cooked, int lazy)
2304 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2305 struct obd_uuid uuid_buf;
2306 char *poolname = NULL;
2307 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2308 { LL_STATFS_LOV, "OST" },
2310 struct ll_stat_type *tp;
2311 __u64 ost_ffree = 0;
2317 poolname = strchr(pool, '.');
2318 if (poolname != NULL) {
2319 if (strncmp(fsname, pool, strlen(fsname))) {
2320 fprintf(stderr, "filesystem name incorrect\n");
2329 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2330 "UUID", "Inodes", "IUsed", "IFree",
2331 "IUse%", "Mounted on");
2333 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2334 "UUID", cooked ? "bytes" : "1K-blocks",
2335 "Used", "Available", "Use%", "Mounted on");
2337 for (tp = types; tp->st_name != NULL; tp++) {
2338 for (index = 0; ; index++) {
2339 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2340 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2341 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2342 rc = llapi_obd_statfs(mntdir, type, index,
2343 &stat_buf, &uuid_buf);
2350 if (poolname && tp->st_op == LL_STATFS_LOV &&
2351 llapi_search_ost(fsname, poolname,
2352 obd_uuid2str(&uuid_buf)) != 1)
2355 /* the llapi_obd_statfs() call may have returned with
2356 * an error, but if it filled in uuid_buf we will at
2357 * lease use that to print out a message for that OBD.
2358 * If we didn't get anything in the uuid_buf, then fill
2359 * it in so that we can print an error message. */
2360 if (uuid_buf.uuid[0] == '\0')
2361 sprintf(uuid_buf.uuid, "%s%04x",
2362 tp->st_name, index);
2363 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2364 ishow, cooked, tp->st_name, index, rc);
2367 if (tp->st_op == LL_STATFS_LMV) {
2368 sum.os_ffree += stat_buf.os_ffree;
2369 sum.os_files += stat_buf.os_files;
2370 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2371 sum.os_blocks += stat_buf.os_blocks *
2373 sum.os_bfree += stat_buf.os_bfree *
2375 sum.os_bavail += stat_buf.os_bavail *
2377 ost_ffree += stat_buf.os_ffree;
2379 } else if (rc == -EINVAL || rc == -EFAULT) {
2385 /* If we don't have as many objects free on the OST as inodes
2386 * on the MDS, we reduce the total number of inodes to
2387 * compensate, so that the "inodes in use" number is correct.
2388 * Matches ll_statfs_internal() so the results are consistent. */
2389 if (ost_ffree < sum.os_ffree) {
2390 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2391 sum.os_ffree = ost_ffree;
2394 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2399 static int lfs_df(int argc, char **argv)
2401 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2402 int ishow = 0, cooked = 0;
2404 int c, rc = 0, index = 0;
2405 char fsname[PATH_MAX] = "", *pool_name = NULL;
2406 struct option long_opts[] = {
2407 {"pool", required_argument, 0, 'p'},
2408 {"lazy", 0, 0, 'l'},
2412 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2430 if (optind < argc && !realpath(argv[optind], path)) {
2432 fprintf(stderr, "error: invalid path '%s': %s\n",
2433 argv[optind], strerror(-rc));
2437 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2438 /* Check if we have a mount point */
2439 if (mntdir[0] == '\0')
2442 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2443 if (rc || path[0] != '\0')
2445 fsname[0] = '\0'; /* avoid matching in next loop */
2446 mntdir[0] = '\0'; /* avoid matching in next loop */
2452 static int lfs_getname(int argc, char **argv)
2454 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2455 int rc = 0, index = 0, c;
2456 char buf[sizeof(struct obd_uuid)];
2458 while ((c = getopt(argc, argv, "h")) != -1)
2461 if (optind == argc) { /* no paths specified, get all paths. */
2462 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2463 rc = llapi_getname(mntdir, buf, sizeof(buf));
2466 "cannot get name for `%s': %s\n",
2467 mntdir, strerror(-rc));
2471 printf("%s %s\n", buf, mntdir);
2473 path[0] = fsname[0] = mntdir[0] = 0;
2475 } else { /* paths specified, only attempt to search these. */
2476 for (; optind < argc; optind++) {
2477 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2480 "cannot get name for `%s': %s\n",
2481 argv[optind], strerror(-rc));
2485 printf("%s %s\n", buf, argv[optind]);
2491 static int lfs_check(int argc, char **argv)
2494 char mntdir[PATH_MAX] = {'\0'};
2503 obd_types[0] = obd_type1;
2504 obd_types[1] = obd_type2;
2506 if (strcmp(argv[1], "osts") == 0) {
2507 strcpy(obd_types[0], "osc");
2508 } else if (strcmp(argv[1], "mds") == 0) {
2509 strcpy(obd_types[0], "mdc");
2510 } else if (strcmp(argv[1], "servers") == 0) {
2512 strcpy(obd_types[0], "osc");
2513 strcpy(obd_types[1], "mdc");
2515 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2520 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2521 if (rc < 0 || mntdir[0] == '\0') {
2522 fprintf(stderr, "No suitable Lustre mount found\n");
2526 rc = llapi_target_check(num_types, obd_types, mntdir);
2528 fprintf(stderr, "error: %s: %s status failed\n",
2535 static int lfs_join(int argc, char **argv)
2537 fprintf(stderr, "join two lustre files into one.\n"
2538 "obsolete, HEAD does not support it anymore.\n");
2542 #ifdef HAVE_SYS_QUOTA_H
2543 #define ARG2INT(nr, str, msg) \
2546 nr = strtol(str, &endp, 0); \
2548 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2553 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2555 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2556 * returns the value or ULONG_MAX on integer overflow or incorrect format
2558 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2559 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2560 * 3. empty integer value is interpreted as 0
2562 static unsigned long str2sec(const char* timestr)
2564 const char spec[] = "smhdw";
2565 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2566 unsigned long val = 0;
2569 if (strpbrk(timestr, spec) == NULL) {
2570 /* no specifiers inside the time string,
2571 should treat it as an integer value */
2572 val = strtoul(timestr, &tail, 10);
2573 return *tail ? ULONG_MAX : val;
2576 /* format string is XXwXXdXXhXXmXXs */
2582 v = strtoul(timestr, &tail, 10);
2583 if (v == ULONG_MAX || *tail == '\0')
2584 /* value too large (ULONG_MAX or more)
2585 or missing specifier */
2588 ptr = strchr(spec, *tail);
2590 /* unknown specifier */
2595 /* check if product will overflow the type */
2596 if (!(v < ULONG_MAX / mult[ind]))
2599 ADD_OVERFLOW(val, mult[ind] * v);
2600 if (val == ULONG_MAX)
2612 #define ARG2ULL(nr, str, def_units) \
2614 unsigned long long limit, units = def_units; \
2617 rc = llapi_parse_size(str, &limit, &units, 1); \
2619 fprintf(stderr, "error: bad limit value %s\n", str); \
2625 static inline int has_times_option(int argc, char **argv)
2629 for (i = 1; i < argc; i++)
2630 if (!strcmp(argv[i], "-t"))
2636 int lfs_setquota_times(int argc, char **argv)
2639 struct if_quotactl qctl;
2640 char *mnt, *obd_type = (char *)qctl.obd_type;
2641 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2642 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2643 struct option long_opts[] = {
2644 {"block-grace", required_argument, 0, 'b'},
2645 {"group", no_argument, 0, 'g'},
2646 {"inode-grace", required_argument, 0, 'i'},
2647 {"times", no_argument, 0, 't'},
2648 {"user", no_argument, 0, 'u'},
2652 memset(&qctl, 0, sizeof(qctl));
2653 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2654 qctl.qc_type = UGQUOTA;
2656 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2660 if (qctl.qc_type != UGQUOTA) {
2661 fprintf(stderr, "error: -u and -g can't be used "
2662 "more than once\n");
2665 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2668 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2669 fprintf(stderr, "error: bad block-grace: %s\n",
2673 dqb->dqb_valid |= QIF_BTIME;
2676 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2677 fprintf(stderr, "error: bad inode-grace: %s\n",
2681 dqb->dqb_valid |= QIF_ITIME;
2683 case 't': /* Yes, of course! */
2685 default: /* getopt prints error message for us when opterr != 0 */
2690 if (qctl.qc_type == UGQUOTA) {
2691 fprintf(stderr, "error: neither -u nor -g specified\n");
2695 if (optind != argc - 1) {
2696 fprintf(stderr, "error: unexpected parameters encountered\n");
2701 rc = llapi_quotactl(mnt, &qctl);
2704 fprintf(stderr, "%s %s ", obd_type,
2705 obd_uuid2str(&qctl.obd_uuid));
2706 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2713 #define BSLIMIT (1 << 0)
2714 #define BHLIMIT (1 << 1)
2715 #define ISLIMIT (1 << 2)
2716 #define IHLIMIT (1 << 3)
2718 int lfs_setquota(int argc, char **argv)
2721 struct if_quotactl qctl;
2722 char *mnt, *obd_type = (char *)qctl.obd_type;
2723 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2724 struct option long_opts[] = {
2725 {"block-softlimit", required_argument, 0, 'b'},
2726 {"block-hardlimit", required_argument, 0, 'B'},
2727 {"group", required_argument, 0, 'g'},
2728 {"inode-softlimit", required_argument, 0, 'i'},
2729 {"inode-hardlimit", required_argument, 0, 'I'},
2730 {"user", required_argument, 0, 'u'},
2733 unsigned limit_mask = 0;
2736 if (has_times_option(argc, argv))
2737 return lfs_setquota_times(argc, argv);
2739 memset(&qctl, 0, sizeof(qctl));
2740 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2741 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2742 * so it can be used as a marker that qc_type
2743 * isn't reinitialized from command line */
2745 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2749 if (qctl.qc_type != UGQUOTA) {
2750 fprintf(stderr, "error: -u and -g can't be used"
2751 " more than once\n");
2754 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2755 rc = name2id(&qctl.qc_id, optarg,
2756 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2758 qctl.qc_id = strtoul(optarg, &endptr, 10);
2759 if (*endptr != '\0') {
2760 fprintf(stderr, "error: can't find id "
2761 "for name %s\n", optarg);
2767 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2768 dqb->dqb_bsoftlimit >>= 10;
2769 limit_mask |= BSLIMIT;
2770 if (dqb->dqb_bsoftlimit &&
2771 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2772 fprintf(stderr, "warning: block softlimit is "
2773 "smaller than the miminal qunit size, "
2774 "please see the help of setquota or "
2775 "Lustre manual for details.\n");
2778 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2779 dqb->dqb_bhardlimit >>= 10;
2780 limit_mask |= BHLIMIT;
2781 if (dqb->dqb_bhardlimit &&
2782 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2783 fprintf(stderr, "warning: block hardlimit is "
2784 "smaller than the miminal qunit size, "
2785 "please see the help of setquota or "
2786 "Lustre manual for details.\n");
2789 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2790 limit_mask |= ISLIMIT;
2791 if (dqb->dqb_isoftlimit &&
2792 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2793 fprintf(stderr, "warning: inode softlimit is "
2794 "smaller than the miminal qunit size, "
2795 "please see the help of setquota or "
2796 "Lustre manual for details.\n");
2799 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2800 limit_mask |= IHLIMIT;
2801 if (dqb->dqb_ihardlimit &&
2802 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2803 fprintf(stderr, "warning: inode hardlimit is "
2804 "smaller than the miminal qunit size, "
2805 "please see the help of setquota or "
2806 "Lustre manual for details.\n");
2808 default: /* getopt prints error message for us when opterr != 0 */
2813 if (qctl.qc_type == UGQUOTA) {
2814 fprintf(stderr, "error: neither -u nor -g was specified\n");
2818 if (limit_mask == 0) {
2819 fprintf(stderr, "error: at least one limit must be specified\n");
2823 if (optind != argc - 1) {
2824 fprintf(stderr, "error: unexpected parameters encountered\n");
2830 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2831 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2832 /* sigh, we can't just set blimits/ilimits */
2833 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2834 .qc_type = qctl.qc_type,
2835 .qc_id = qctl.qc_id};
2837 rc = llapi_quotactl(mnt, &tmp_qctl);
2839 fprintf(stderr, "error: setquota failed while retrieving"
2840 " current quota settings (%s)\n",
2845 if (!(limit_mask & BHLIMIT))
2846 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2847 if (!(limit_mask & BSLIMIT))
2848 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2849 if (!(limit_mask & IHLIMIT))
2850 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2851 if (!(limit_mask & ISLIMIT))
2852 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2854 /* Keep grace times if we have got no softlimit arguments */
2855 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2856 dqb->dqb_valid |= QIF_BTIME;
2857 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2860 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2861 dqb->dqb_valid |= QIF_ITIME;
2862 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2866 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2867 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2869 rc = llapi_quotactl(mnt, &qctl);
2872 fprintf(stderr, "%s %s ", obd_type,
2873 obd_uuid2str(&qctl.obd_uuid));
2874 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2881 static inline char *type2name(int check_type)
2883 if (check_type == USRQUOTA)
2885 else if (check_type == GRPQUOTA)
2891 /* Converts seconds value into format string
2892 * result is returned in buf
2894 * 1. result is in descenting order: 1w2d3h4m5s
2895 * 2. zero fields are not filled (except for p. 3): 5d1s
2896 * 3. zero seconds value is presented as "0s"
2898 static char * __sec2str(time_t seconds, char *buf)
2900 const char spec[] = "smhdw";
2901 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2906 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2907 c = seconds / mult[i];
2909 if (c > 0 || (i == 0 && buf == tail))
2910 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2918 static void sec2str(time_t seconds, char *buf, int rc)
2925 tail = __sec2str(seconds, tail);
2927 if (rc && tail - buf < 39) {
2933 static void diff2str(time_t seconds, char *buf, time_t now)
2939 if (seconds <= now) {
2940 strcpy(buf, "none");
2943 __sec2str(seconds - now, buf);
2946 static void print_quota_title(char *name, struct if_quotactl *qctl,
2947 bool human_readable)
2949 printf("Disk quotas for %s %s (%cid %u):\n",
2950 type2name(qctl->qc_type), name,
2951 *type2name(qctl->qc_type), qctl->qc_id);
2952 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2953 "Filesystem", human_readable ? "used" : "kbytes",
2954 "quota", "limit", "grace",
2955 "files", "quota", "limit", "grace");
2958 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
2961 snprintf(buf, buflen, "%ju", (uintmax_t)num);
2964 snprintf(buf, buflen, "%5.4gP",
2965 (double)num / ((__u64)1 << 40));
2967 snprintf(buf, buflen, "%5.4gT",
2968 (double)num / (1 << 30));
2970 snprintf(buf, buflen, "%5.4gG",
2971 (double)num / (1 << 20));
2973 snprintf(buf, buflen, "%5.4gM",
2974 (double)num / (1 << 10));
2976 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
2980 #define STRBUF_LEN 32
2981 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2988 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2989 int bover = 0, iover = 0;
2990 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2991 char numbuf[3][STRBUF_LEN];
2993 char strbuf[STRBUF_LEN];
2995 if (dqb->dqb_bhardlimit &&
2996 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2998 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2999 if (dqb->dqb_btime > now) {
3006 if (dqb->dqb_ihardlimit &&
3007 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3009 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3010 if (dqb->dqb_itime > now) {
3018 if (strlen(mnt) > 15)
3019 printf("%s\n%15s", mnt, "");
3021 printf("%15s", mnt);
3024 diff2str(dqb->dqb_btime, timebuf, now);
3026 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3027 strbuf, sizeof(strbuf), h);
3028 if (rc == -EREMOTEIO)
3029 sprintf(numbuf[0], "%s*", strbuf);
3031 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3032 "%s" : "[%s]", strbuf);
3034 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3035 if (type == QC_GENERAL)
3036 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3037 "%s" : "[%s]", strbuf);
3039 sprintf(numbuf[1], "%s", "-");
3041 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3042 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3043 "%s" : "[%s]", strbuf);
3045 printf(" %7s%c %6s %7s %7s",
3046 numbuf[0], bover ? '*' : ' ', numbuf[1],
3047 numbuf[2], bover > 1 ? timebuf : "-");
3050 diff2str(dqb->dqb_itime, timebuf, now);
3052 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3053 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3055 if (type == QC_GENERAL)
3056 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3058 (uintmax_t)dqb->dqb_isoftlimit);
3060 sprintf(numbuf[1], "%s", "-");
3062 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3063 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3065 if (type != QC_OSTIDX)
3066 printf(" %7s%c %6s %7s %7s",
3067 numbuf[0], iover ? '*' : ' ', numbuf[1],
3068 numbuf[2], iover > 1 ? timebuf : "-");
3070 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3073 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3074 qctl->qc_cmd == Q_GETOINFO) {
3078 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3079 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3080 printf("Block grace time: %s; Inode grace time: %s\n",
3081 bgtimebuf, igtimebuf);
3085 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3086 bool h, __u64 *total)
3088 int rc = 0, rc1 = 0, count = 0;
3089 __u32 valid = qctl->qc_valid;
3091 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3093 fprintf(stderr, "can not get %s count: %s\n",
3094 is_mdt ? "mdt": "ost", strerror(-rc));
3098 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3099 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3100 rc = llapi_quotactl(mnt, qctl);
3102 /* It is remote client case. */
3103 if (-rc == EOPNOTSUPP) {
3110 fprintf(stderr, "quotactl %s%d failed.\n",
3111 is_mdt ? "mdt": "ost", qctl->qc_idx);
3115 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3116 qctl->qc_valid, 0, h);
3117 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3118 qctl->qc_dqblk.dqb_bhardlimit;
3121 qctl->qc_valid = valid;
3125 static int lfs_quota(int argc, char **argv)
3128 char *mnt, *name = NULL;
3129 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3130 .qc_type = UGQUOTA };
3131 char *obd_type = (char *)qctl.obd_type;
3132 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3133 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3134 verbose = 0, pass = 0, quiet = 0, inacc;
3136 __u32 valid = QC_GENERAL, idx = 0;
3137 __u64 total_ialloc = 0, total_balloc = 0;
3138 bool human_readable = false;
3140 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3143 if (qctl.qc_type != UGQUOTA) {
3144 fprintf(stderr, "error: use either -u or -g\n");
3147 qctl.qc_type = USRQUOTA;
3150 if (qctl.qc_type != UGQUOTA) {
3151 fprintf(stderr, "error: use either -u or -g\n");
3154 qctl.qc_type = GRPQUOTA;
3157 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3160 valid = qctl.qc_valid = QC_UUID;
3161 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3164 valid = qctl.qc_valid = QC_MDTIDX;
3165 idx = qctl.qc_idx = atoi(optarg);
3168 valid = qctl.qc_valid = QC_OSTIDX;
3169 idx = qctl.qc_idx = atoi(optarg);
3178 human_readable = true;
3181 fprintf(stderr, "error: %s: option '-%c' "
3182 "unrecognized\n", argv[0], c);
3187 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3188 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3189 optind == argc - 1) {
3191 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3192 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3193 qctl.qc_valid = valid;
3196 qctl.qc_type = USRQUOTA;
3197 qctl.qc_id = geteuid();
3199 qctl.qc_type = GRPQUOTA;
3200 qctl.qc_id = getegid();
3202 rc = id2name(&name, qctl.qc_id,
3203 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3206 /* lfs quota -u username /path/to/lustre/mount */
3207 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3208 /* options should be followed by u/g-name and mntpoint */
3209 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3210 fprintf(stderr, "error: missing quota argument(s)\n");
3214 name = argv[optind++];
3215 rc = name2id(&qctl.qc_id, name,
3216 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3218 qctl.qc_id = strtoul(name, &endptr, 10);
3219 if (*endptr != '\0') {
3220 fprintf(stderr, "error: can't find id for name "
3225 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3226 fprintf(stderr, "error: missing quota info argument(s)\n");
3232 rc1 = llapi_quotactl(mnt, &qctl);
3236 fprintf(stderr, "%s quotas are not enabled.\n",
3237 qctl.qc_type == USRQUOTA ? "user" : "group");
3240 fprintf(stderr, "Permission denied.\n");
3242 /* We already got a "No such file..." message. */
3245 fprintf(stderr, "Unexpected quotactl error: %s\n",
3250 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3251 print_quota_title(name, &qctl, human_readable);
3253 if (rc1 && *obd_type)
3254 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3256 if (qctl.qc_valid != QC_GENERAL)
3259 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3260 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3261 (QIF_LIMITS|QIF_USAGE));
3263 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3265 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3267 char strbuf[STRBUF_LEN];
3269 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3271 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3273 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3275 printf("Total allocated inode limit: %ju, total "
3276 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3280 if (rc1 || rc2 || rc3 || inacc)
3281 printf("Some errors happened when getting quota info. "
3282 "Some devices may be not working or deactivated. "
3283 "The data in \"[]\" is inaccurate.\n");
3291 #endif /* HAVE_SYS_QUOTA_H! */
3293 static int flushctx_ioctl(char *mp)
3297 fd = open(mp, O_RDONLY);
3299 fprintf(stderr, "flushctx: error open %s: %s\n",
3300 mp, strerror(errno));
3304 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3306 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3307 mp, strerror(errno));
3313 static int lfs_flushctx(int argc, char **argv)
3315 int kdestroy = 0, c;
3316 char mntdir[PATH_MAX] = {'\0'};
3320 while ((c = getopt(argc, argv, "k")) != -1) {
3326 fprintf(stderr, "error: %s: option '-%c' "
3327 "unrecognized\n", argv[0], c);
3333 if ((rc = system("kdestroy > /dev/null")) != 0) {
3334 rc = WEXITSTATUS(rc);
3335 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3339 if (optind >= argc) {
3340 /* flush for all mounted lustre fs. */
3341 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3342 /* Check if we have a mount point */
3343 if (mntdir[0] == '\0')
3346 if (flushctx_ioctl(mntdir))
3349 mntdir[0] = '\0'; /* avoid matching in next loop */
3352 /* flush fs as specified */
3353 while (optind < argc) {
3354 if (flushctx_ioctl(argv[optind++]))
3361 static int lfs_lsetfacl(int argc, char **argv)
3364 return(llapi_lsetfacl(argc, argv));
3367 static int lfs_lgetfacl(int argc, char **argv)
3370 return(llapi_lgetfacl(argc, argv));
3373 static int lfs_rsetfacl(int argc, char **argv)
3376 return(llapi_rsetfacl(argc, argv));
3379 static int lfs_rgetfacl(int argc, char **argv)
3382 return(llapi_rgetfacl(argc, argv));
3385 static int lfs_cp(int argc, char **argv)
3387 return(llapi_cp(argc, argv));
3390 static int lfs_ls(int argc, char **argv)
3392 return(llapi_ls(argc, argv));
3395 static int lfs_changelog(int argc, char **argv)
3397 void *changelog_priv;
3398 struct changelog_rec *rec;
3399 long long startrec = 0, endrec = 0;
3401 struct option long_opts[] = {
3402 {"follow", no_argument, 0, 'f'},
3405 char short_opts[] = "f";
3408 while ((rc = getopt_long(argc, argv, short_opts,
3409 long_opts, NULL)) != -1) {
3417 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3418 argv[0], argv[optind - 1]);
3425 mdd = argv[optind++];
3427 startrec = strtoll(argv[optind++], NULL, 10);
3429 endrec = strtoll(argv[optind++], NULL, 10);
3431 rc = llapi_changelog_start(&changelog_priv,
3432 CHANGELOG_FLAG_BLOCK |
3433 CHANGELOG_FLAG_JOBID |
3434 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3437 fprintf(stderr, "Can't start changelog: %s\n",
3438 strerror(errno = -rc));
3442 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3446 if (endrec && rec->cr_index > endrec) {
3447 llapi_changelog_free(&rec);
3450 if (rec->cr_index < startrec) {
3451 llapi_changelog_free(&rec);
3455 secs = rec->cr_time >> 30;
3456 gmtime_r(&secs, &ts);
3457 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3458 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3459 changelog_type2str(rec->cr_type),
3460 ts.tm_hour, ts.tm_min, ts.tm_sec,
3461 (int)(rec->cr_time & ((1<<30) - 1)),
3462 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3463 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3465 if (rec->cr_flags & CLF_JOBID) {
3466 struct changelog_ext_jobid *jid =
3467 changelog_rec_jobid(rec);
3469 if (jid->cr_jobid[0] != '\0')
3470 printf(" j=%s", jid->cr_jobid);
3473 if (rec->cr_namelen)
3474 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3475 rec->cr_namelen, changelog_rec_name(rec));
3477 if (rec->cr_flags & CLF_RENAME) {
3478 struct changelog_ext_rename *rnm =
3479 changelog_rec_rename(rec);
3481 if (!fid_is_zero(&rnm->cr_sfid))
3482 printf(" s="DFID" sp="DFID" %.*s",
3483 PFID(&rnm->cr_sfid),
3484 PFID(&rnm->cr_spfid),
3485 (int)changelog_rec_snamelen(rec),
3486 changelog_rec_sname(rec));
3490 llapi_changelog_free(&rec);
3493 llapi_changelog_fini(&changelog_priv);
3496 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3498 return (rc == 1 ? 0 : rc);
3501 static int lfs_changelog_clear(int argc, char **argv)
3509 endrec = strtoll(argv[3], NULL, 10);
3511 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3513 fprintf(stderr, "%s error: %s\n", argv[0],
3514 strerror(errno = -rc));
3518 static int lfs_fid2path(int argc, char **argv)
3520 struct option long_opts[] = {
3521 {"cur", no_argument, 0, 'c'},
3522 {"link", required_argument, 0, 'l'},
3523 {"rec", required_argument, 0, 'r'},
3526 char short_opts[] = "cl:r:";
3527 char *device, *fid, *path;
3528 long long recno = -1;
3534 while ((rc = getopt_long(argc, argv, short_opts,
3535 long_opts, NULL)) != -1) {
3541 linkno = strtol(optarg, NULL, 10);
3544 recno = strtoll(optarg, NULL, 10);
3549 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3550 argv[0], argv[optind - 1]);
3558 device = argv[optind++];
3559 path = calloc(1, PATH_MAX);
3561 fprintf(stderr, "error: Not enough memory\n");
3566 while (optind < argc) {
3567 fid = argv[optind++];
3569 lnktmp = (linkno >= 0) ? linkno : 0;
3571 int oldtmp = lnktmp;
3572 long long rectmp = recno;
3574 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3577 fprintf(stderr, "%s: error on FID %s: %s\n",
3578 argv[0], fid, strerror(errno = -rc2));
3585 fprintf(stdout, "%lld ", rectmp);
3586 if (device[0] == '/') {
3587 fprintf(stdout, "%s", device);
3588 if (device[strlen(device) - 1] != '/')
3589 fprintf(stdout, "/");
3590 } else if (path[0] == '\0') {
3591 fprintf(stdout, "/");
3593 fprintf(stdout, "%s\n", path);
3596 /* specified linkno */
3598 if (oldtmp == lnktmp)
3608 static int lfs_path2fid(int argc, char **argv)
3610 struct option long_opts[] = {
3611 {"parents", no_argument, 0, 'p'},
3615 const char short_opts[] = "p";
3616 const char *sep = "";
3619 bool show_parents = false;
3621 while ((rc = getopt_long(argc, argv, short_opts,
3622 long_opts, NULL)) != -1) {
3625 show_parents = true;
3628 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3629 argv[0], argv[optind - 1]);
3634 if (optind > argc - 1)
3636 else if (optind < argc - 1)
3640 for (path = argv + optind; *path != NULL; path++) {
3642 if (!show_parents) {
3643 err = llapi_path2fid(*path, &fid);
3645 printf("%s%s"DFID"\n",
3646 *sep != '\0' ? *path : "", sep,
3649 char name[NAME_MAX + 1];
3650 unsigned int linkno = 0;
3652 while ((err = llapi_path2parent(*path, linkno, &fid,
3653 name, sizeof(name))) == 0) {
3654 if (*sep != '\0' && linkno == 0)
3655 printf("%s%s", *path, sep);
3657 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3662 /* err == -ENODATA is end-of-loop */
3663 if (linkno > 0 && err == -ENODATA) {
3670 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3671 argv[0], show_parents ? "parent " : "", *path,
3683 static int lfs_data_version(int argc, char **argv)
3690 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3695 while ((c = getopt(argc, argv, "nrw")) != -1) {
3698 data_version_flags = 0;
3701 data_version_flags |= LL_DV_RD_FLUSH;
3704 data_version_flags |= LL_DV_WR_FLUSH;
3713 path = argv[optind];
3714 fd = open(path, O_RDONLY);
3716 err(errno, "cannot open file %s", path);
3718 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3720 err(errno, "cannot get version for %s", path);
3722 printf("%ju" "\n", (uintmax_t)data_version);
3728 static int lfs_hsm_state(int argc, char **argv)
3733 struct hsm_user_state hus;
3741 rc = llapi_hsm_state_get(path, &hus);
3743 fprintf(stderr, "can't get hsm state for %s: %s\n",
3744 path, strerror(errno = -rc));
3748 /* Display path name and status flags */
3749 printf("%s: (0x%08x)", path, hus.hus_states);
3751 if (hus.hus_states & HS_RELEASED)
3752 printf(" released");
3753 if (hus.hus_states & HS_EXISTS)
3755 if (hus.hus_states & HS_DIRTY)
3757 if (hus.hus_states & HS_ARCHIVED)
3758 printf(" archived");
3759 /* Display user-settable flags */
3760 if (hus.hus_states & HS_NORELEASE)
3761 printf(" never_release");
3762 if (hus.hus_states & HS_NOARCHIVE)
3763 printf(" never_archive");
3764 if (hus.hus_states & HS_LOST)
3765 printf(" lost_from_hsm");
3767 if (hus.hus_archive_id != 0)
3768 printf(", archive_id:%d", hus.hus_archive_id);
3771 } while (++i < argc);
3776 #define LFS_HSM_SET 0
3777 #define LFS_HSM_CLEAR 1
3780 * Generic function to set or clear HSM flags.
3781 * Used by hsm_set and hsm_clear.
3783 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3785 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3787 struct option long_opts[] = {
3788 {"lost", 0, 0, 'l'},
3789 {"norelease", 0, 0, 'r'},
3790 {"noarchive", 0, 0, 'a'},
3791 {"archived", 0, 0, 'A'},
3792 {"dirty", 0, 0, 'd'},
3793 {"exists", 0, 0, 'e'},
3796 char short_opts[] = "lraAde";
3804 while ((c = getopt_long(argc, argv, short_opts,
3805 long_opts, NULL)) != -1) {
3811 mask |= HS_NOARCHIVE;
3814 mask |= HS_ARCHIVED;
3817 mask |= HS_NORELEASE;
3828 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3829 argv[0], argv[optind - 1]);
3834 /* User should have specified a flag */
3838 while (optind < argc) {
3840 path = argv[optind];
3842 /* If mode == 0, this means we apply the mask. */
3843 if (mode == LFS_HSM_SET)
3844 rc = llapi_hsm_state_set(path, mask, 0, 0);
3846 rc = llapi_hsm_state_set(path, 0, mask, 0);
3849 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3850 path, strerror(errno = -rc));
3859 static int lfs_hsm_action(int argc, char **argv)
3864 struct hsm_current_action hca;
3865 struct hsm_extent he;
3866 enum hsm_user_action hua;
3867 enum hsm_progress_states hps;
3875 rc = llapi_hsm_current_action(path, &hca);
3877 fprintf(stderr, "can't get hsm action for %s: %s\n",
3878 path, strerror(errno = -rc));
3881 he = hca.hca_location;
3882 hua = hca.hca_action;
3883 hps = hca.hca_state;
3885 printf("%s: %s", path, hsm_user_action2name(hua));
3887 /* Skip file without action */
3888 if (hca.hca_action == HUA_NONE) {
3893 printf(" %s ", hsm_progress_state2name(hps));
3895 if ((hps == HPS_RUNNING) &&
3896 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3897 printf("(%llu bytes moved)\n",
3898 (unsigned long long)he.length);
3899 else if ((he.offset + he.length) == LUSTRE_EOF)
3900 printf("(from %llu to EOF)\n",
3901 (unsigned long long)he.offset);
3903 printf("(from %llu to %llu)\n",
3904 (unsigned long long)he.offset,
3905 (unsigned long long)(he.offset + he.length));
3907 } while (++i < argc);
3912 static int lfs_hsm_set(int argc, char **argv)
3914 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3917 static int lfs_hsm_clear(int argc, char **argv)
3919 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3923 * Check file state and return its fid, to be used by lfs_hsm_request().
3925 * \param[in] file Path to file to check
3926 * \param[in,out] fid Pointer to allocated lu_fid struct.
3927 * \param[in,out] last_dev Pointer to last device id used.
3929 * \return 0 on success.
3931 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3937 rc = lstat(file, &st);
3939 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3942 /* Checking for regular file as archiving as posix copytool
3943 * rejects archiving files other than regular files
3945 if (!S_ISREG(st.st_mode)) {
3946 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3949 /* A request should be ... */
3950 if (*last_dev != st.st_dev && *last_dev != 0) {
3951 fprintf(stderr, "All files should be "
3952 "on the same filesystem: %s\n", file);
3955 *last_dev = st.st_dev;
3957 rc = llapi_path2fid(file, fid);
3959 fprintf(stderr, "Cannot read FID of %s: %s\n",
3960 file, strerror(-rc));
3966 /* Fill an HSM HUR item with a given file name.
3968 * If mntpath is set, then the filename is actually a FID, and no
3969 * lookup on the filesystem will be performed.
3971 * \param[in] hur the user request to fill
3972 * \param[in] idx index of the item inside the HUR to fill
3973 * \param[in] mntpath mountpoint of Lustre
3974 * \param[in] fname filename (if mtnpath is NULL)
3975 * or FID (if mntpath is set)
3976 * \param[in] last_dev pointer to last device id used
3978 * \retval 0 on success
3979 * \retval CMD_HELP or a negative errno on error
3981 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3982 const char *mntpath, const char *fname,
3985 struct hsm_user_item *hui = &hur->hur_user_item[idx];
3988 hui->hui_extent.length = -1;
3990 if (mntpath != NULL) {
3993 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3997 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4002 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4006 hur->hur_request.hr_itemcount++;
4011 static int lfs_hsm_request(int argc, char **argv, int action)
4013 struct option long_opts[] = {
4014 {"filelist", 1, 0, 'l'},
4015 {"data", 1, 0, 'D'},
4016 {"archive", 1, 0, 'a'},
4017 {"mntpath", 1, 0, 'm'},
4021 char short_opts[] = "l:D:a:m:";
4022 struct hsm_user_request *hur, *oldhur;
4027 char *filelist = NULL;
4028 char fullpath[PATH_MAX];
4029 char *opaque = NULL;
4033 int nbfile_alloc = 0;
4034 char *some_file = NULL;
4035 char *mntpath = NULL;
4041 while ((c = getopt_long(argc, argv, short_opts,
4042 long_opts, NULL)) != -1) {
4051 if (action != HUA_ARCHIVE &&
4052 action != HUA_REMOVE) {
4054 "error: -a is supported only "
4055 "when archiving or removing\n");
4058 archive_id = atoi(optarg);
4061 if (some_file == NULL) {
4063 some_file = strdup(optarg);
4069 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4070 argv[0], argv[optind - 1]);
4075 /* All remaining args are files, so we have at least nbfile */
4076 nbfile = argc - optind;
4078 if ((nbfile == 0) && (filelist == NULL))
4082 opaque_len = strlen(opaque);
4084 /* Alloc the request structure with enough place to store all files
4085 * from command line. */
4086 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4088 fprintf(stderr, "Cannot create the request: %s\n",
4092 nbfile_alloc = nbfile;
4094 hur->hur_request.hr_action = action;
4095 hur->hur_request.hr_archive_id = archive_id;
4096 hur->hur_request.hr_flags = 0;
4098 /* All remaining args are files, add them */
4099 if (nbfile != 0 && some_file == NULL)
4100 some_file = strdup(argv[optind]);
4102 for (i = 0; i < nbfile; i++) {
4103 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4109 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4111 /* If a filelist was specified, read the filelist from it. */
4112 if (filelist != NULL) {
4113 fp = fopen(filelist, "r");
4115 fprintf(stderr, "Cannot read the file list %s: %s\n",
4116 filelist, strerror(errno));
4121 while ((rc = getline(&line, &len, fp)) != -1) {
4122 /* If allocated buffer was too small, get something
4124 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4127 nbfile_alloc = nbfile_alloc * 2 + 1;
4129 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4132 fprintf(stderr, "hsm: cannot allocate "
4133 "the request: %s\n",
4140 size = hur_len(oldhur);
4142 fprintf(stderr, "hsm: cannot allocate "
4143 "%u files + %u bytes data\n",
4144 oldhur->hur_request.hr_itemcount,
4145 oldhur->hur_request.hr_data_len);
4152 memcpy(hur, oldhur, size);
4157 if (line[strlen(line) - 1] == '\n')
4158 line[strlen(line) - 1] = '\0';
4160 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4161 mntpath, line, &last_dev);
4167 if (some_file == NULL) {
4177 /* If a --data was used, add it to the request */
4178 hur->hur_request.hr_data_len = opaque_len;
4180 memcpy(hur_data(hur), opaque, opaque_len);
4182 /* Send the HSM request */
4183 if (realpath(some_file, fullpath) == NULL) {
4184 fprintf(stderr, "Could not find path '%s': %s\n",
4185 some_file, strerror(errno));
4187 rc = llapi_hsm_request(fullpath, hur);
4189 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4190 some_file, strerror(-rc));
4200 static int lfs_hsm_archive(int argc, char **argv)
4202 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4205 static int lfs_hsm_restore(int argc, char **argv)
4207 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4210 static int lfs_hsm_release(int argc, char **argv)
4212 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4215 static int lfs_hsm_remove(int argc, char **argv)
4217 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4220 static int lfs_hsm_cancel(int argc, char **argv)
4222 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4225 static int lfs_swap_layouts(int argc, char **argv)
4230 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4231 SWAP_LAYOUTS_KEEP_MTIME |
4232 SWAP_LAYOUTS_KEEP_ATIME);
4235 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4237 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4239 enum lu_ladvise_type advice;
4242 advice < ARRAY_SIZE(ladvise_names); advice++) {
4243 if (ladvise_names[advice] == NULL)
4245 if (strcmp(string, ladvise_names[advice]) == 0)
4249 return LU_LADVISE_INVALID;
4252 static int lfs_ladvise(int argc, char **argv)
4254 struct option long_opts[] = {
4255 {"advice", required_argument, 0, 'a'},
4256 {"background", no_argument, 0, 'b'},
4257 {"end", required_argument, 0, 'e'},
4258 {"start", required_argument, 0, 's'},
4259 {"length", required_argument, 0, 'l'},
4262 char short_opts[] = "a:be:l:s:";
4267 struct lu_ladvise advice;
4268 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4269 unsigned long long start = 0;
4270 unsigned long long end = LUSTRE_EOF;
4271 unsigned long long length = 0;
4272 unsigned long long size_units;
4273 unsigned long long flags = 0;
4276 while ((c = getopt_long(argc, argv, short_opts,
4277 long_opts, NULL)) != -1) {
4280 advice_type = lfs_get_ladvice(optarg);
4281 if (advice_type == LU_LADVISE_INVALID) {
4282 fprintf(stderr, "%s: invalid advice type "
4283 "'%s'\n", argv[0], optarg);
4284 fprintf(stderr, "Valid types:");
4286 for (advice_type = 0;
4287 advice_type < ARRAY_SIZE(ladvise_names);
4289 if (ladvise_names[advice_type] == NULL)
4291 fprintf(stderr, " %s",
4292 ladvise_names[advice_type]);
4294 fprintf(stderr, "\n");
4304 rc = llapi_parse_size(optarg, &end,
4307 fprintf(stderr, "%s: bad end offset '%s'\n",
4314 rc = llapi_parse_size(optarg, &start,
4317 fprintf(stderr, "%s: bad start offset "
4318 "'%s'\n", argv[0], optarg);
4324 rc = llapi_parse_size(optarg, &length,
4327 fprintf(stderr, "%s: bad length '%s'\n",
4335 fprintf(stderr, "%s: option '%s' unrecognized\n",
4336 argv[0], argv[optind - 1]);
4341 if (advice_type == LU_LADVISE_INVALID) {
4342 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4343 fprintf(stderr, "Valid types:");
4344 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4346 if (ladvise_names[advice_type] == NULL)
4348 fprintf(stderr, " %s", ladvise_names[advice_type]);
4350 fprintf(stderr, "\n");
4354 if (argc <= optind) {
4355 fprintf(stderr, "%s: please give one or more file names\n",
4360 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4361 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4366 if (end == LUSTRE_EOF && length != 0)
4367 end = start + length;
4370 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4371 argv[0], start, end);
4375 while (optind < argc) {
4378 path = argv[optind++];
4380 fd = open(path, O_RDONLY);
4382 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4383 argv[0], path, strerror(errno));
4388 advice.lla_start = start;
4389 advice.lla_end = end;
4390 advice.lla_advice = advice_type;
4391 advice.lla_padding = 0;
4392 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4395 fprintf(stderr, "%s: cannot give advice '%s' to file "
4396 "'%s': %s\n", argv[0],
4397 ladvise_names[advice_type],
4398 path, strerror(errno));
4401 if (rc == 0 && rc2 < 0)
4407 int main(int argc, char **argv)
4411 /* Ensure that liblustreapi constructor has run */
4412 if (!liblustreapi_initialized)
4413 fprintf(stderr, "liblustreapi was not properly initialized\n");
4417 Parser_init("lfs > ", cmdlist);
4419 progname = argv[0]; /* Used in error messages */
4421 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4423 rc = Parser_commands();
4426 return rc < 0 ? -rc : rc;
4429 #ifdef _LUSTRE_IDL_H_
4430 /* Everything we need here should be included by lustreapi.h. */
4431 # error "lfs should not depend on lustre_idl.h"
4432 #endif /* _LUSTRE_IDL_H_ */