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.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2015, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
63 #ifdef HAVE_SYS_QUOTA_H
64 # include <sys/quota.h>
67 #include <libcfs/util/string.h>
68 #include <libcfs/util/ioctl.h>
69 #include <libcfs/util/parser.h>
70 #include <lustre/lustreapi.h>
71 #include <lustre_ver.h>
72 #include <lustre_param.h>
75 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
76 #endif /* !ARRAY_SIZE */
79 static int lfs_setstripe(int argc, char **argv);
80 static int lfs_find(int argc, char **argv);
81 static int lfs_getstripe(int argc, char **argv);
82 static int lfs_getdirstripe(int argc, char **argv);
83 static int lfs_setdirstripe(int argc, char **argv);
84 static int lfs_rmentry(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_mdts(int argc, char **argv);
87 static int lfs_df(int argc, char **argv);
88 static int lfs_getname(int argc, char **argv);
89 static int lfs_check(int argc, char **argv);
90 #ifdef HAVE_SYS_QUOTA_H
91 static int lfs_setquota(int argc, char **argv);
92 static int lfs_quota(int argc, char **argv);
94 static int lfs_flushctx(int argc, char **argv);
95 static int lfs_join(int argc, char **argv);
96 static int lfs_lsetfacl(int argc, char **argv);
97 static int lfs_lgetfacl(int argc, char **argv);
98 static int lfs_rsetfacl(int argc, char **argv);
99 static int lfs_rgetfacl(int argc, char **argv);
100 static int lfs_cp(int argc, char **argv);
101 static int lfs_ls(int argc, char **argv);
102 static int lfs_poollist(int argc, char **argv);
103 static int lfs_changelog(int argc, char **argv);
104 static int lfs_changelog_clear(int argc, char **argv);
105 static int lfs_fid2path(int argc, char **argv);
106 static int lfs_path2fid(int argc, char **argv);
107 static int lfs_data_version(int argc, char **argv);
108 static int lfs_hsm_state(int argc, char **argv);
109 static int lfs_hsm_set(int argc, char **argv);
110 static int lfs_hsm_clear(int argc, char **argv);
111 static int lfs_hsm_action(int argc, char **argv);
112 static int lfs_hsm_archive(int argc, char **argv);
113 static int lfs_hsm_restore(int argc, char **argv);
114 static int lfs_hsm_release(int argc, char **argv);
115 static int lfs_hsm_remove(int argc, char **argv);
116 static int lfs_hsm_cancel(int argc, char **argv);
117 static int lfs_swap_layouts(int argc, char **argv);
118 static int lfs_mv(int argc, char **argv);
119 static int lfs_ladvise(int argc, char **argv);
121 /* Setstripe and migrate share mostly the same parameters */
122 #define SSM_CMD_COMMON(cmd) \
123 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
124 " [--stripe-index|-i <start_ost_idx>]\n" \
125 " [--stripe-size|-S <stripe_size>]\n" \
126 " [--pool|-p <pool_name>]\n" \
127 " [--ost-list|-o <ost_indices>]\n"
129 #define SSM_HELP_COMMON \
130 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
131 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
132 "\t respectively)\n" \
133 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
134 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
135 "\tpool_name: Name of OST pool to use (default none)\n" \
136 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
137 "\t Indices be specified in a format of:\n" \
138 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
140 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
141 "\t If --pool is set with --ost-list, then the OSTs\n" \
142 "\t must be the members of the pool."
144 #define SETSTRIPE_USAGE \
145 SSM_CMD_COMMON("setstripe") \
146 " <directory|filename>\n" \
149 #define MIGRATE_USAGE \
150 SSM_CMD_COMMON("migrate ") \
152 " [--non-block|-n]\n" \
156 "\tblock: Block file access during data migration (default)\n" \
157 "\tnon-block: Abort migrations if concurrent access is detected\n" \
159 static const char *progname;
160 static bool file_lease_supported = true;
162 /* all available commands */
163 command_t cmdlist[] = {
164 {"setstripe", lfs_setstripe, 0,
165 "Create a new file with a specific striping pattern or\n"
166 "set the default striping pattern on an existing directory or\n"
167 "delete the default striping pattern from an existing directory\n"
168 "usage: setstripe -d <directory> (to delete default striping)\n"\
171 {"getstripe", lfs_getstripe, 0,
172 "To list the striping info for a given file or files in a\n"
173 "directory or recursively for all files in a directory tree.\n"
174 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
175 " [--stripe-count|-c] [--stripe-index|-i]\n"
176 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
177 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
178 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
179 " <directory|filename> ..."},
180 {"setdirstripe", lfs_setdirstripe, 0,
181 "To create a striped directory on a specified MDT. This can only\n"
182 "be done on MDT0 with the right of administrator.\n"
183 "usage: setdirstripe <--count|-c stripe_count>\n"
184 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
185 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
186 "\tstripe_count: stripe count of the striped directory\n"
187 "\tmdt_index: MDT index of first stripe\n"
188 "\thash_type: hash type of the striped directory. Hash types:\n"
189 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
190 " all_char sum of characters % MDT_COUNT (not recommended)\n"
191 "\tdefault_stripe: set default dirstripe of the directory\n"
192 "\tmode: the mode of the directory\n"},
193 {"getdirstripe", lfs_getdirstripe, 0,
194 "To list the striping info for a given directory\n"
195 "or recursively for all directories in a directory tree.\n"
196 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
197 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
198 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
199 {"mkdir", lfs_setdirstripe, 0,
200 "To create a striped directory on a specified MDT. This can only\n"
201 "be done on MDT0 with the right of administrator.\n"
202 "usage: mkdir <--count|-c stripe_count>\n"
203 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
204 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
205 "\tstripe_count: stripe count of the striped directory\n"
206 "\tmdt_index: MDT index of first stripe\n"
207 "\thash_type: hash type of the striped directory. Hash types:\n"
208 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
209 " all_char sum of characters % MDT_COUNT (not recommended)\n"
210 "\tdefault_stripe: set default dirstripe of the directory\n"
211 "\tmode: the mode of the directory\n"},
212 {"rm_entry", lfs_rmentry, 0,
213 "To remove the name entry of the remote directory. Note: This\n"
214 "command will only delete the name entry, i.e. the remote directory\n"
215 "will become inaccessable after this command. This can only be done\n"
216 "by the administrator\n"
217 "usage: rm_entry <dir>\n"},
218 {"pool_list", lfs_poollist, 0,
219 "List pools or pool OSTs\n"
220 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
221 {"find", lfs_find, 0,
222 "find files matching given attributes recursively in directory tree.\n"
223 "usage: find <directory|filename> ...\n"
224 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
225 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
226 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
227 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
228 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
229 " [[!] --stripe-count|-c [+-]<stripes>]\n"
230 " [[!] --stripe-index|-i <index,...>]\n"
231 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
232 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
233 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
234 " [[!] --layout|-L released,raid0]\n"
235 "\t !: used before an option indicates 'NOT' requested attribute\n"
236 "\t -: used before a value indicates 'AT MOST' requested value\n"
237 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
238 {"check", lfs_check, 0,
239 "Display the status of MDS or OSTs (as specified in the command)\n"
240 "or all the servers (MDS and OSTs).\n"
241 "usage: check <osts|mds|servers>"},
242 {"join", lfs_join, 0,
243 "join two lustre files into one.\n"
244 "obsolete, HEAD does not support it anymore.\n"},
245 {"osts", lfs_osts, 0, "list OSTs connected to client "
246 "[for specified path only]\n" "usage: osts [path]"},
247 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
248 "[for specified path only]\n" "usage: mdts [path]"},
250 "report filesystem disk space usage or inodes usage"
251 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
252 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
253 {"getname", lfs_getname, 0, "list instances and specified mount points "
254 "[for specified path only]\n"
255 "Usage: getname [-h]|[path ...] "},
256 #ifdef HAVE_SYS_QUOTA_H
257 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
258 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
259 " -b <block-softlimit> -B <block-hardlimit>\n"
260 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
261 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
262 " [--block-softlimit <block-softlimit>]\n"
263 " [--block-hardlimit <block-hardlimit>]\n"
264 " [--inode-softlimit <inode-softlimit>]\n"
265 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
266 " setquota [-t] <-u|--user|-g|--group>\n"
267 " [--block-grace <block-grace>]\n"
268 " [--inode-grace <inode-grace>] <filesystem>\n"
269 " -b can be used instead of --block-softlimit/--block-grace\n"
270 " -B can be used instead of --block-hardlimit\n"
271 " -i can be used instead of --inode-softlimit/--inode-grace\n"
272 " -I can be used instead of --inode-hardlimit\n\n"
273 "Note: The total quota space will be split into many qunits and\n"
274 " balanced over all server targets, the minimal qunit size is\n"
275 " 1M bytes for block space and 1K inodes for inode space.\n\n"
276 " Quota space rebalancing process will stop when this mininum\n"
277 " value is reached. As a result, quota exceeded can be returned\n"
278 " while many targets still have 1MB or 1K inodes of spare\n"
280 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
281 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
283 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
284 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
286 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
287 "usage: flushctx [-k] [mountpoint...]"},
288 {"lsetfacl", lfs_lsetfacl, 0,
289 "Remote user setfacl for user/group on the same remote client.\n"
290 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
291 {"lgetfacl", lfs_lgetfacl, 0,
292 "Remote user getfacl for user/group on the same remote client.\n"
293 "usage: lgetfacl [-dRLPvh] file ..."},
294 {"rsetfacl", lfs_rsetfacl, 0,
295 "Remote user setfacl for user/group on other clients.\n"
296 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
297 {"rgetfacl", lfs_rgetfacl, 0,
298 "Remote user getfacl for user/group on other clients.\n"
299 "usage: rgetfacl [-dRLPvh] file ..."},
301 "Remote user copy files and directories.\n"
302 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
304 "Remote user list directory contents.\n"
305 "usage: ls [OPTION]... [FILE]..."},
306 {"changelog", lfs_changelog, 0,
307 "Show the metadata changes on an MDT."
308 "\nusage: changelog <mdtname> [startrec [endrec]]"},
309 {"changelog_clear", lfs_changelog_clear, 0,
310 "Indicate that old changelog records up to <endrec> are no longer of "
311 "interest to consumer <id>, allowing the system to free up space.\n"
312 "An <endrec> of 0 means all records.\n"
313 "usage: changelog_clear <mdtname> <id> <endrec>"},
314 {"fid2path", lfs_fid2path, 0,
315 "Resolve the full path(s) for given FID(s). For a specific hardlink "
316 "specify link number <linkno>.\n"
317 /* "For a historical link name, specify changelog record <recno>.\n" */
318 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
319 /* [ --rec <recno> ] */ },
320 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
321 "usage: path2fid [--parents] <path> ..."},
322 {"data_version", lfs_data_version, 0, "Display file data version for "
323 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
324 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
325 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
326 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
327 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
328 "[--archived] [--lost] <file> ..."},
329 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
331 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
332 "[--archived] [--lost] <file> ..."},
333 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
334 "given files.\n" "usage: hsm_action <file> ..."},
335 {"hsm_archive", lfs_hsm_archive, 0,
336 "Archive file to external storage.\n"
337 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
339 {"hsm_restore", lfs_hsm_restore, 0,
340 "Restore file from external storage.\n"
341 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
342 {"hsm_release", lfs_hsm_release, 0,
343 "Release files from Lustre.\n"
344 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
345 {"hsm_remove", lfs_hsm_remove, 0,
346 "Remove file copy from external storage.\n"
347 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
348 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
350 "Note: To remove files from the archive that have been deleted on\n"
351 "Lustre, set mntpath and optionally archive. In that case, all the\n"
352 "positional arguments and entries in the file list must be FIDs."
354 {"hsm_cancel", lfs_hsm_cancel, 0,
355 "Cancel requests related to specified files.\n"
356 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
358 "usage: swap_layouts <path1> <path2>"},
359 {"migrate", lfs_setstripe, 0,
360 "migrate a directory between MDTs.\n"
361 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
363 "\tmdt_idx: index of the destination MDT\n"
365 "migrate file objects from one OST "
366 "layout\nto another (may be not safe with concurent writes).\n"
368 "[--stripe-count|-c] <stripe_count>\n"
369 " [--stripe-index|-i] <start_ost_index>\n"
370 " [--stripe-size|-S] <stripe_size>\n"
371 " [--pool|-p] <pool_name>\n"
372 " [--ost-list|-o] <ost_indices>\n"
374 " [--non-block|-n]\n"
375 " <file|directory>\n"
376 "\tstripe_count: number of OSTs to stripe a file over\n"
377 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
378 "\tstripe_size: number of bytes to store before moving to the next OST\n"
379 "\tpool_name: name of the predefined pool of OSTs\n"
380 "\tost_indices: OSTs to stripe over, in order\n"
381 "\tblock: wait for the operation to return before continuing\n"
382 "\tnon-block: do not wait for the operation to return.\n"},
384 "To move directories between MDTs. This command is deprecated, "
385 "use \"migrate\" instead.\n"
386 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
388 {"ladvise", lfs_ladvise, 0,
389 "Provide servers with advice about access patterns for a file.\n"
390 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
391 " [--background|-b]\n"
392 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
394 {"help", Parser_help, 0, "help"},
395 {"exit", Parser_quit, 0, "quit"},
396 {"quit", Parser_quit, 0, "quit"},
397 {"--version", Parser_version, 0,
398 "output build version of the utility and exit"},
403 #define MIGRATION_NONBLOCK 1
406 * Internal helper for migrate_copy_data(). Check lease and report error if
409 * \param[in] fd File descriptor on which to check the lease.
410 * \param[out] lease_broken Set to true if the lease was broken.
411 * \param[in] group_locked Whether a group lock was taken or not.
412 * \param[in] path Name of the file being processed, for error
415 * \retval 0 Migration can keep on going.
416 * \retval -errno Error occurred, abort migration.
418 static int check_lease(int fd, bool *lease_broken, bool group_locked,
423 if (!file_lease_supported)
426 rc = llapi_lease_check(fd);
428 return 0; /* llapi_check_lease returns > 0 on success. */
431 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
433 rc = rc ? rc : -EAGAIN;
435 fprintf(stderr, "%s: external attempt to access file '%s' "
436 "blocked until migration ends.\n", progname, path);
439 *lease_broken = true;
443 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
444 bool group_locked, const char *fname)
453 bool lease_broken = false;
455 /* Use a page-aligned buffer for direct I/O */
456 rc = posix_memalign(&buf, getpagesize(), buf_size);
461 /* read new data only if we have written all
462 * previously read data */
465 rc = check_lease(fd_src, &lease_broken,
466 group_locked, fname);
470 rsize = read(fd_src, buf, buf_size);
473 fprintf(stderr, "%s: %s: read failed: %s\n",
474 progname, fname, strerror(-rc));
484 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
488 "%s: %s: write failed on volatile: %s\n",
489 progname, fname, strerror(-rc));
499 fprintf(stderr, "%s: %s: fsync failed: %s\n",
500 progname, fname, strerror(-rc));
508 static int migrate_copy_timestamps(int fdv, const struct stat *st)
510 struct timeval tv[2] = {
511 {.tv_sec = st->st_atime},
512 {.tv_sec = st->st_mtime}
515 return futimes(fdv, tv);
518 static int migrate_block(int fd, int fdv, const struct stat *st,
519 size_t buf_size, const char *name)
526 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
528 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
529 progname, name, strerror(-rc));
537 /* The grouplock blocks all concurrent accesses to the file.
538 * It has to be taken after llapi_get_data_version as it would
540 rc = llapi_group_lock(fd, gid);
542 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
543 progname, name, strerror(-rc));
547 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
549 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
553 /* Make sure we keep original atime/mtime values */
554 rc = migrate_copy_timestamps(fdv, st);
556 fprintf(stderr, "%s: %s: timestamp copy failed\n",
562 * for a migration we need to check data version on file did
565 * Pass in gid=0 since we already own grouplock. */
566 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
567 SWAP_LAYOUTS_CHECK_DV1);
569 fprintf(stderr, "%s: %s: dataversion changed during copy, "
570 "migration aborted\n", progname, name);
573 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
574 name, strerror(-rc));
579 rc2 = llapi_group_unlock(fd, gid);
580 if (rc2 < 0 && rc == 0) {
581 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
582 progname, name, strerror(-rc2));
589 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
590 size_t buf_size, const char *name)
596 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
598 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
599 progname, name, strerror(-rc));
603 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
605 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
609 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
611 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
612 progname, name, strerror(-rc));
618 fprintf(stderr, "%s: %s: data version changed during "
624 /* Make sure we keep original atime/mtime values */
625 rc = migrate_copy_timestamps(fdv, st);
627 fprintf(stderr, "%s: %s: timestamp copy failed\n",
632 /* Atomically put lease, swap layouts and close.
633 * for a migration we need to check data version on file did
635 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
637 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
638 progname, name, strerror(-rc));
645 static int lfs_migrate(char *name, __u64 migration_flags,
646 struct llapi_stripe_param *param)
650 char parent[PATH_MAX];
653 char volatile_file[sizeof(parent) +
654 LUSTRE_VOLATILE_HDR_LEN +
655 2 * sizeof(mdt_index) +
656 2 * sizeof(random_value) + 4];
659 struct lov_user_md *lum = NULL;
662 bool have_lease_rdlck = false;
666 /* find the right size for the IO and allocate the buffer */
667 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
668 lum = malloc(lum_size);
674 rc = llapi_file_get_stripe(name, lum);
675 /* failure can happen for many reasons and some may be not real errors
677 * in case of a real error, a later call will fail with better
678 * error management */
680 buf_size = 1024 * 1024;
682 buf_size = lum->lmm_stripe_size;
684 /* open file, direct io */
685 /* even if the file is only read, WR mode is nedeed to allow
686 * layout swap on fd */
687 fd = open(name, O_RDWR | O_DIRECT);
690 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
695 if (file_lease_supported) {
696 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
697 if (rc == -EOPNOTSUPP) {
698 /* Older servers do not support file lease.
699 * Disable related checks. This opens race conditions
700 * as explained in LU-4840 */
701 file_lease_supported = false;
703 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
704 progname, name, strerror(-rc));
707 have_lease_rdlck = true;
711 /* search for file directory pathname */
712 if (strlen(name) > sizeof(parent)-1) {
716 strncpy(parent, name, sizeof(parent));
717 ptr = strrchr(parent, '/');
719 if (getcwd(parent, sizeof(parent)) == NULL) {
730 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
732 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
733 progname, name, strerror(-rc));
738 random_value = random();
739 rc = snprintf(volatile_file, sizeof(volatile_file),
740 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
741 mdt_index, random_value);
742 if (rc >= sizeof(volatile_file)) {
747 /* create, open a volatile file, use caching (ie no directio) */
748 fdv = llapi_file_open_param(volatile_file,
749 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
750 S_IRUSR | S_IWUSR, param);
751 } while (fdv == -EEXIST);
755 fprintf(stderr, "%s: %s: cannot create volatile file in"
757 progname, parent, strerror(-rc));
761 /* Not-owner (root?) special case.
762 * Need to set owner/group of volatile file like original.
763 * This will allow to pass related check during layout_swap.
768 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
772 rc = fstat(fdv, &stv);
775 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
776 volatile_file, strerror(errno));
779 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
780 rc = fchown(fdv, st.st_uid, st.st_gid);
783 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
784 name, strerror(errno));
789 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
790 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
792 have_lease_rdlck = false;
793 fdv = -1; /* The volatile file is closed as we put the
794 * lease in non-blocking mode. */
797 /* Blocking mode (forced if servers do not support file lease).
798 * It is also the default mode, since we cannot distinguish
799 * between a broken lease and a server that does not support
800 * atomic swap/close (LU-6785) */
801 rc = migrate_block(fd, fdv, &st, buf_size, name);
805 if (have_lease_rdlck)
822 * Parse a string containing an OST index list into an array of integers.
824 * The input string contains a comma delimited list of individual
825 * indices and ranges, for example "1,2-4,7". Add the indices into the
826 * \a osts array and remove duplicates.
828 * \param[out] osts array to store indices in
829 * \param[in] size size of \a osts array
830 * \param[in] offset starting index in \a osts
831 * \param[in] arg string containing OST index list
833 * \retval positive number of indices in \a osts
834 * \retval -EINVAL unable to parse \a arg
836 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
840 int slots = size - offset;
848 while (!end_of_loop) {
856 ptr = strchrnul(arg, ',');
858 end_of_loop = *ptr == '\0';
861 start_index = strtol(arg, &endptr, 0);
862 if (endptr == arg) /* no data at all */
864 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
869 end_index = start_index;
870 if (*endptr == '-') {
871 end_index = strtol(endptr + 1, &endptr, 0);
874 if (end_index < start_index)
878 for (i = start_index; i <= end_index && slots > 0; i++) {
881 /* remove duplicate */
882 for (j = 0; j < offset; j++) {
886 if (j == offset) { /* no duplicate */
891 if (slots == 0 && i < end_index)
899 if (!end_of_loop && ptr != NULL)
902 return rc < 0 ? rc : nr;
906 static int lfs_setstripe(int argc, char **argv)
908 struct llapi_stripe_param *param = NULL;
909 struct find_param migrate_mdt_param = {
916 unsigned long long st_size;
917 int st_offset, st_count;
921 char *stripe_size_arg = NULL;
922 char *stripe_off_arg = NULL;
923 char *stripe_count_arg = NULL;
924 char *pool_name_arg = NULL;
925 char *mdt_idx_arg = NULL;
926 unsigned long long size_units = 1;
927 bool migrate_mode = false;
928 bool migration_block = false;
929 __u64 migration_flags = 0;
930 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
933 struct option long_opts[] = {
934 /* --block is only valid in migrate mode */
935 {"block", no_argument, 0, 'b'},
936 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
937 /* This formerly implied "stripe-count", but was explicitly
938 * made "stripe-count" for consistency with other options,
939 * and to separate it from "mdt-count" when DNE arrives. */
940 {"count", required_argument, 0, 'c'},
942 {"stripe-count", required_argument, 0, 'c'},
943 {"stripe_count", required_argument, 0, 'c'},
944 {"delete", no_argument, 0, 'd'},
945 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
946 /* This formerly implied "stripe-index", but was explicitly
947 * made "stripe-index" for consistency with other options,
948 * and to separate it from "mdt-index" when DNE arrives. */
949 {"index", required_argument, 0, 'i'},
951 {"stripe-index", required_argument, 0, 'i'},
952 {"stripe_index", required_argument, 0, 'i'},
953 {"mdt-index", required_argument, 0, 'm'},
954 {"mdt_index", required_argument, 0, 'm'},
955 /* --non-block is only valid in migrate mode */
956 {"non-block", no_argument, 0, 'n'},
957 {"ost-list", required_argument, 0, 'o'},
958 {"ost_list", required_argument, 0, 'o'},
959 {"pool", required_argument, 0, 'p'},
960 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
961 /* This formerly implied "--stripe-size", but was confusing
962 * with "lfs find --size|-s", which means "file size", so use
963 * the consistent "--stripe-size|-S" for all commands. */
964 {"size", required_argument, 0, 's'},
966 {"stripe-size", required_argument, 0, 'S'},
967 {"stripe_size", required_argument, 0, 'S'},
968 /* --verbose is only valid in migrate mode */
969 {"verbose", no_argument, 0, 'v'},
977 if (strcmp(argv[0], "migrate") == 0)
980 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
981 long_opts, NULL)) >= 0) {
988 fprintf(stderr, "--block is valid only for"
992 migration_block = true;
995 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
996 if (strcmp(argv[optind - 1], "--count") == 0)
997 fprintf(stderr, "warning: '--count' deprecated"
998 ", use '--stripe-count' instead\n");
1000 stripe_count_arg = optarg;
1003 /* delete the default striping pattern */
1007 nr_osts = parse_targets(osts,
1008 sizeof(osts) / sizeof(__u32),
1012 "error: %s: bad OST indices '%s'\n",
1017 if (st_offset == -1) /* first in the command line */
1018 st_offset = osts[0];
1021 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1022 if (strcmp(argv[optind - 1], "--index") == 0)
1023 fprintf(stderr, "warning: '--index' deprecated"
1024 ", use '--stripe-index' instead\n");
1026 stripe_off_arg = optarg;
1029 if (!migrate_mode) {
1030 fprintf(stderr, "--mdt-index is valid only for"
1034 mdt_idx_arg = optarg;
1037 if (!migrate_mode) {
1038 fprintf(stderr, "--non-block is valid only for"
1042 migration_flags |= MIGRATION_NONBLOCK;
1044 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1046 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1047 fprintf(stderr, "warning: '--size|-s' deprecated, "
1048 "use '--stripe-size|-S' instead\n");
1050 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1052 stripe_size_arg = optarg;
1055 pool_name_arg = optarg;
1058 if (!migrate_mode) {
1059 fprintf(stderr, "--verbose is valid only for"
1063 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1070 fname = argv[optind];
1073 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1074 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1075 fprintf(stderr, "error: %s: cannot specify -d with "
1076 "-s, -c, -o, or -p options\n",
1081 if (optind == argc) {
1082 fprintf(stderr, "error: %s: missing filename|dirname\n",
1087 if (mdt_idx_arg != NULL && optind > 3) {
1088 fprintf(stderr, "error: %s: cannot specify -m with other "
1089 "options\n", argv[0]);
1093 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1095 "error: %s: cannot specify --non-block and --block\n",
1100 if (pool_name_arg != NULL) {
1104 ptr = strchr(pool_name_arg, '.');
1106 ptr = pool_name_arg;
1108 if ((ptr - pool_name_arg) == 0) {
1109 fprintf(stderr, "error: %s: fsname is empty "
1110 "in pool name '%s'\n",
1111 argv[0], pool_name_arg);
1118 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1120 fprintf(stderr, "error: %s: poolname '%s' is "
1122 argv[0], pool_name_arg);
1124 } else if (rc == -2) {
1125 fprintf(stderr, "error: %s: pool name '%s' is too long "
1126 "(max is %d characters)\n",
1127 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1129 } else if (rc > 0) {
1130 fprintf(stderr, "error: %s: char '%c' not allowed in "
1132 argv[0], rc, pool_name_arg);
1137 /* get the stripe size */
1138 if (stripe_size_arg != NULL) {
1139 result = llapi_parse_size(stripe_size_arg, &st_size,
1142 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1143 argv[0], stripe_size_arg);
1147 /* get the stripe offset */
1148 if (stripe_off_arg != NULL) {
1149 st_offset = strtol(stripe_off_arg, &end, 0);
1151 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1152 argv[0], stripe_off_arg);
1156 /* get the stripe count */
1157 if (stripe_count_arg != NULL) {
1158 st_count = strtoul(stripe_count_arg, &end, 0);
1160 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1161 argv[0], stripe_count_arg);
1166 if (mdt_idx_arg != NULL) {
1167 /* initialize migrate mdt parameters */
1168 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1170 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1171 argv[0], mdt_idx_arg);
1174 migrate_mdt_param.fp_migrate = 1;
1176 /* initialize stripe parameters */
1177 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1178 if (param == NULL) {
1179 fprintf(stderr, "error: %s: run out of memory\n",
1184 param->lsp_stripe_size = st_size;
1185 param->lsp_stripe_offset = st_offset;
1186 param->lsp_stripe_count = st_count;
1187 param->lsp_stripe_pattern = 0;
1188 param->lsp_pool = pool_name_arg;
1189 param->lsp_is_specific = false;
1191 if (st_count > 0 && nr_osts != st_count) {
1192 fprintf(stderr, "error: %s: stripe count '%d' "
1193 "doesn't match the number of OSTs: %d\n"
1194 , argv[0], st_count, nr_osts);
1199 param->lsp_is_specific = true;
1200 param->lsp_stripe_count = nr_osts;
1201 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1205 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1206 if (!migrate_mode) {
1207 result = llapi_file_open_param(fname,
1214 } else if (mdt_idx_arg != NULL) {
1215 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1217 result = lfs_migrate(fname, migration_flags, param);
1220 /* Save the first error encountered. */
1223 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1224 argv[0], migrate_mode ? "migrate" : "create",
1226 pool_name_arg != NULL && result == EINVAL ?
1227 "OST not in pool?" : strerror(errno));
1236 static int lfs_poollist(int argc, char **argv)
1241 return llapi_poollist(argv[1]);
1244 static int set_time(time_t *time, time_t *set, char *str)
1251 else if (str[0] == '-')
1257 t = strtol(str, NULL, 0);
1258 if (*time < t * 24 * 60 * 60) {
1261 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1265 *set = *time - t * 24 * 60 * 60;
1272 static int name2id(unsigned int *id, char *name, int type)
1275 struct passwd *entry;
1277 if (!(entry = getpwnam(name))) {
1283 *id = entry->pw_uid;
1285 struct group *entry;
1287 if (!(entry = getgrnam(name))) {
1293 *id = entry->gr_gid;
1299 static int id2name(char **name, unsigned int id, int type)
1302 struct passwd *entry;
1304 if (!(entry = getpwuid(id))) {
1310 *name = entry->pw_name;
1312 struct group *entry;
1314 if (!(entry = getgrgid(id))) {
1320 *name = entry->gr_name;
1326 static int name2layout(__u32 *layout, char *name)
1331 for (ptr = name; ; ptr = NULL) {
1332 lyt = strtok(ptr, ",");
1335 if (strcmp(lyt, "released") == 0)
1336 *layout |= LOV_PATTERN_F_RELEASED;
1337 else if (strcmp(lyt, "raid0") == 0)
1338 *layout |= LOV_PATTERN_RAID0;
1345 #define FIND_POOL_OPT 3
1346 static int lfs_find(int argc, char **argv)
1351 struct find_param param = {
1355 struct option long_opts[] = {
1356 {"atime", required_argument, 0, 'A'},
1357 {"stripe-count", required_argument, 0, 'c'},
1358 {"stripe_count", required_argument, 0, 'c'},
1359 {"ctime", required_argument, 0, 'C'},
1360 {"maxdepth", required_argument, 0, 'D'},
1361 {"gid", required_argument, 0, 'g'},
1362 {"group", required_argument, 0, 'G'},
1363 {"stripe-index", required_argument, 0, 'i'},
1364 {"stripe_index", required_argument, 0, 'i'},
1365 {"layout", required_argument, 0, 'L'},
1366 {"mdt", required_argument, 0, 'm'},
1367 {"mtime", required_argument, 0, 'M'},
1368 {"name", required_argument, 0, 'n'},
1369 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1370 {"obd", required_argument, 0, 'O'},
1371 {"ost", required_argument, 0, 'O'},
1372 /* no short option for pool, p/P already used */
1373 {"pool", required_argument, 0, FIND_POOL_OPT},
1374 {"print0", no_argument, 0, 'p'},
1375 {"print", no_argument, 0, 'P'},
1376 {"size", required_argument, 0, 's'},
1377 {"stripe-size", required_argument, 0, 'S'},
1378 {"stripe_size", required_argument, 0, 'S'},
1379 {"type", required_argument, 0, 't'},
1380 {"uid", required_argument, 0, 'u'},
1381 {"user", required_argument, 0, 'U'},
1394 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1395 while ((c = getopt_long_only(argc, argv,
1396 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1397 long_opts, NULL)) >= 0) {
1402 /* '!' is part of option */
1403 /* when getopt_long_only() finds a string which is not
1404 * an option nor a known option argument it returns 1
1405 * in that case if we already have found pathstart and pathend
1406 * (i.e. we have the list of pathnames),
1407 * the only supported value is "!"
1409 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1410 if (!isoption && pathend != -1) {
1411 fprintf(stderr, "err: %s: filename|dirname must either "
1412 "precede options or follow options\n",
1417 if (!isoption && pathstart == -1)
1418 pathstart = optind - 1;
1419 if (isoption && pathstart != -1 && pathend == -1)
1420 pathend = optind - 2;
1426 /* unknown; opt is "!" or path component,
1427 * checking done above.
1429 if (strcmp(optarg, "!") == 0)
1433 xtime = ¶m.fp_atime;
1434 xsign = ¶m.fp_asign;
1435 param.fp_exclude_atime = !!neg_opt;
1436 /* no break, this falls through to 'C' for ctime */
1439 xtime = ¶m.fp_ctime;
1440 xsign = ¶m.fp_csign;
1441 param.fp_exclude_ctime = !!neg_opt;
1443 /* no break, this falls through to 'M' for mtime */
1446 xtime = ¶m.fp_mtime;
1447 xsign = ¶m.fp_msign;
1448 param.fp_exclude_mtime = !!neg_opt;
1450 rc = set_time(&t, xtime, optarg);
1451 if (rc == INT_MAX) {
1459 if (optarg[0] == '+') {
1460 param.fp_stripe_count_sign = -1;
1462 } else if (optarg[0] == '-') {
1463 param.fp_stripe_count_sign = 1;
1467 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1468 if (*endptr != '\0') {
1469 fprintf(stderr,"error: bad stripe_count '%s'\n",
1474 param.fp_check_stripe_count = 1;
1475 param.fp_exclude_stripe_count = !!neg_opt;
1478 param.fp_max_depth = strtol(optarg, 0, 0);
1482 rc = name2id(¶m.fp_gid, optarg, GROUP);
1484 param.fp_gid = strtoul(optarg, &endptr, 10);
1485 if (*endptr != '\0') {
1486 fprintf(stderr, "Group/GID: %s cannot "
1487 "be found.\n", optarg);
1492 param.fp_exclude_gid = !!neg_opt;
1493 param.fp_check_gid = 1;
1496 ret = name2layout(¶m.fp_layout, optarg);
1499 param.fp_exclude_layout = !!neg_opt;
1500 param.fp_check_layout = 1;
1504 rc = name2id(¶m.fp_uid, optarg, USER);
1506 param.fp_uid = strtoul(optarg, &endptr, 10);
1507 if (*endptr != '\0') {
1508 fprintf(stderr, "User/UID: %s cannot "
1509 "be found.\n", optarg);
1514 param.fp_exclude_uid = !!neg_opt;
1515 param.fp_check_uid = 1;
1518 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1520 "Pool name %s is too long"
1521 " (max is %d)\n", optarg,
1526 /* we do check for empty pool because empty pool
1527 * is used to find V1 lov attributes */
1528 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1529 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1530 param.fp_exclude_pool = !!neg_opt;
1531 param.fp_check_pool = 1;
1534 param.fp_pattern = (char *)optarg;
1535 param.fp_exclude_pattern = !!neg_opt;
1540 char *buf, *token, *next, *p;
1544 buf = strdup(optarg);
1550 param.fp_exclude_obd = !!neg_opt;
1553 while (token && *token) {
1554 token = strchr(token, ',');
1561 param.fp_exclude_mdt = !!neg_opt;
1562 param.fp_num_alloc_mdts += len;
1563 tmp = realloc(param.fp_mdt_uuid,
1564 param.fp_num_alloc_mdts *
1565 sizeof(*param.fp_mdt_uuid));
1571 param.fp_mdt_uuid = tmp;
1573 param.fp_exclude_obd = !!neg_opt;
1574 param.fp_num_alloc_obds += len;
1575 tmp = realloc(param.fp_obd_uuid,
1576 param.fp_num_alloc_obds *
1577 sizeof(*param.fp_obd_uuid));
1583 param.fp_obd_uuid = tmp;
1585 for (token = buf; token && *token; token = next) {
1586 struct obd_uuid *puuid;
1589 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1592 ¶m.fp_obd_uuid[param.fp_num_obds++];
1594 p = strchr(token, ',');
1601 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1606 strncpy(puuid->uuid, token,
1607 sizeof(puuid->uuid));
1615 param.fp_zero_end = 1;
1620 if (optarg[0] == '+') {
1621 param.fp_size_sign = -1;
1623 } else if (optarg[0] == '-') {
1624 param.fp_size_sign = 1;
1628 ret = llapi_parse_size(optarg, ¶m.fp_size,
1629 ¶m.fp_size_units, 0);
1631 fprintf(stderr, "error: bad file size '%s'\n",
1635 param.fp_check_size = 1;
1636 param.fp_exclude_size = !!neg_opt;
1639 if (optarg[0] == '+') {
1640 param.fp_stripe_size_sign = -1;
1642 } else if (optarg[0] == '-') {
1643 param.fp_stripe_size_sign = 1;
1647 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1648 ¶m.fp_stripe_size_units, 0);
1650 fprintf(stderr, "error: bad stripe_size '%s'\n",
1654 param.fp_check_stripe_size = 1;
1655 param.fp_exclude_stripe_size = !!neg_opt;
1658 param.fp_exclude_type = !!neg_opt;
1659 switch (optarg[0]) {
1661 param.fp_type = S_IFBLK;
1664 param.fp_type = S_IFCHR;
1667 param.fp_type = S_IFDIR;
1670 param.fp_type = S_IFREG;
1673 param.fp_type = S_IFLNK;
1676 param.fp_type = S_IFIFO;
1679 param.fp_type = S_IFSOCK;
1682 fprintf(stderr, "error: %s: bad type '%s'\n",
1694 if (pathstart == -1) {
1695 fprintf(stderr, "error: %s: no filename|pathname\n",
1699 } else if (pathend == -1) {
1705 rc = llapi_find(argv[pathstart], ¶m);
1706 if (rc != 0 && ret == 0)
1708 } while (++pathstart < pathend);
1711 fprintf(stderr, "error: %s failed for %s.\n",
1712 argv[0], argv[optind - 1]);
1714 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1715 free(param.fp_obd_uuid);
1717 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1718 free(param.fp_mdt_uuid);
1723 static int lfs_getstripe_internal(int argc, char **argv,
1724 struct find_param *param)
1726 struct option long_opts[] = {
1727 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1728 /* This formerly implied "stripe-count", but was explicitly
1729 * made "stripe-count" for consistency with other options,
1730 * and to separate it from "mdt-count" when DNE arrives. */
1731 {"count", no_argument, 0, 'c'},
1733 {"stripe-count", no_argument, 0, 'c'},
1734 {"stripe_count", no_argument, 0, 'c'},
1735 {"directory", no_argument, 0, 'd'},
1736 {"default", no_argument, 0, 'D'},
1737 {"fid", no_argument, 0, 'F'},
1738 {"generation", no_argument, 0, 'g'},
1739 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1740 /* This formerly implied "stripe-index", but was explicitly
1741 * made "stripe-index" for consistency with other options,
1742 * and to separate it from "mdt-index" when DNE arrives. */
1743 {"index", no_argument, 0, 'i'},
1745 {"stripe-index", no_argument, 0, 'i'},
1746 {"stripe_index", no_argument, 0, 'i'},
1747 {"layout", no_argument, 0, 'L'},
1748 {"mdt-index", no_argument, 0, 'M'},
1749 {"mdt_index", no_argument, 0, 'M'},
1750 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1751 /* This formerly implied "stripe-index", but was confusing
1752 * with "file offset" (which will eventually be needed for
1753 * with different layouts by offset), so deprecate it. */
1754 {"offset", no_argument, 0, 'o'},
1756 {"obd", required_argument, 0, 'O'},
1757 {"ost", required_argument, 0, 'O'},
1758 {"pool", no_argument, 0, 'p'},
1759 {"quiet", no_argument, 0, 'q'},
1760 {"recursive", no_argument, 0, 'r'},
1761 {"raw", no_argument, 0, 'R'},
1762 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1763 /* This formerly implied "--stripe-size", but was confusing
1764 * with "lfs find --size|-s", which means "file size", so use
1765 * the consistent "--stripe-size|-S" for all commands. */
1766 {"size", no_argument, 0, 's'},
1768 {"stripe-size", no_argument, 0, 'S'},
1769 {"stripe_size", no_argument, 0, 'S'},
1770 {"verbose", no_argument, 0, 'v'},
1775 while ((c = getopt_long(argc, argv, "cdDFghiLMoO:pqrRsSv",
1776 long_opts, NULL)) != -1) {
1779 if (param->fp_obd_uuid) {
1781 "error: %s: only one obduuid allowed",
1785 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1791 param->fp_max_depth = 0;
1794 param->fp_get_default_lmv = 1;
1797 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1798 param->fp_verbose |= VERBOSE_DFID;
1799 param->fp_max_depth = 0;
1803 param->fp_recursive = 1;
1806 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
1809 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1810 if (strcmp(argv[optind - 1], "--count") == 0)
1811 fprintf(stderr, "warning: '--count' deprecated,"
1812 " use '--stripe-count' instead\n");
1814 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1815 param->fp_verbose |= VERBOSE_COUNT;
1816 param->fp_max_depth = 0;
1819 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1821 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1822 fprintf(stderr, "warning: '--size|-s' deprecated, "
1823 "use '--stripe-size|-S' instead\n");
1825 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1827 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1828 param->fp_verbose |= VERBOSE_SIZE;
1829 param->fp_max_depth = 0;
1832 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1834 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1835 "use '--stripe-index|-i' instead\n");
1838 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1839 if (strcmp(argv[optind - 1], "--index") == 0)
1840 fprintf(stderr, "warning: '--index' deprecated"
1841 ", use '--stripe-index' instead\n");
1843 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1844 param->fp_verbose |= VERBOSE_OFFSET;
1845 param->fp_max_depth = 0;
1849 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1850 param->fp_verbose |= VERBOSE_POOL;
1851 param->fp_max_depth = 0;
1855 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1856 param->fp_verbose |= VERBOSE_GENERATION;
1857 param->fp_max_depth = 0;
1861 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1862 param->fp_verbose |= VERBOSE_LAYOUT;
1863 param->fp_max_depth = 0;
1867 if (!(param->fp_verbose & VERBOSE_DETAIL))
1868 param->fp_max_depth = 0;
1869 param->fp_verbose |= VERBOSE_MDTINDEX;
1882 if (param->fp_recursive)
1883 param->fp_max_depth = -1;
1885 if (!param->fp_verbose)
1886 param->fp_verbose = VERBOSE_DEFAULT;
1887 if (param->fp_quiet)
1888 param->fp_verbose = VERBOSE_OBJID;
1891 rc = llapi_getstripe(argv[optind], param);
1892 } while (++optind < argc && !rc);
1895 fprintf(stderr, "error: %s failed for %s.\n",
1896 argv[0], argv[optind - 1]);
1900 static int lfs_tgts(int argc, char **argv)
1902 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1903 struct find_param param;
1904 int index = 0, rc=0;
1909 if (argc == 2 && !realpath(argv[1], path)) {
1911 fprintf(stderr, "error: invalid path '%s': %s\n",
1912 argv[1], strerror(-rc));
1916 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1917 /* Check if we have a mount point */
1918 if (mntdir[0] == '\0')
1921 memset(¶m, 0, sizeof(param));
1922 if (!strcmp(argv[0], "mdts"))
1923 param.fp_get_lmv = 1;
1925 rc = llapi_ostlist(mntdir, ¶m);
1927 fprintf(stderr, "error: %s: failed on %s\n",
1930 if (path[0] != '\0')
1932 memset(mntdir, 0, PATH_MAX);
1938 static int lfs_getstripe(int argc, char **argv)
1940 struct find_param param = { 0 };
1942 param.fp_max_depth = 1;
1943 return lfs_getstripe_internal(argc, argv, ¶m);
1947 static int lfs_getdirstripe(int argc, char **argv)
1949 struct find_param param = { 0 };
1951 param.fp_get_lmv = 1;
1952 return lfs_getstripe_internal(argc, argv, ¶m);
1956 static int lfs_setdirstripe(int argc, char **argv)
1960 unsigned int stripe_offset = -1;
1961 unsigned int stripe_count = 1;
1962 enum lmv_hash_type hash_type;
1965 char *stripe_offset_opt = NULL;
1966 char *stripe_count_opt = NULL;
1967 char *stripe_hash_opt = NULL;
1968 char *mode_opt = NULL;
1969 bool default_stripe = false;
1970 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1971 mode_t previous_mode = 0;
1972 bool delete = false;
1974 struct option long_opts[] = {
1975 {"count", required_argument, 0, 'c'},
1976 {"delete", no_argument, 0, 'd'},
1977 {"index", required_argument, 0, 'i'},
1978 {"mode", required_argument, 0, 'm'},
1979 {"hash-type", required_argument, 0, 't'},
1980 {"default_stripe", no_argument, 0, 'D'},
1984 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1991 stripe_count_opt = optarg;
1995 default_stripe = true;
1998 default_stripe = true;
2001 stripe_offset_opt = optarg;
2007 stripe_hash_opt = optarg;
2010 fprintf(stderr, "error: %s: option '%s' "
2012 argv[0], argv[optind - 1]);
2017 if (optind == argc) {
2018 fprintf(stderr, "error: %s: missing dirname\n",
2023 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2024 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2029 if (stripe_offset_opt != NULL) {
2030 /* get the stripe offset */
2031 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2033 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2034 argv[0], stripe_offset_opt);
2040 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2041 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2042 " or -i options.\n", argv[0]);
2050 if (mode_opt != NULL) {
2051 mode = strtoul(mode_opt, &end, 8);
2053 fprintf(stderr, "error: %s: bad mode '%s'\n",
2057 previous_mode = umask(0);
2060 if (stripe_hash_opt == NULL ||
2061 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2062 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2063 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2064 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2066 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2067 argv[0], stripe_hash_opt);
2071 /* get the stripe count */
2072 if (stripe_count_opt != NULL) {
2073 stripe_count = strtoul(stripe_count_opt, &end, 0);
2075 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2076 argv[0], stripe_count_opt);
2081 dname = argv[optind];
2083 if (default_stripe) {
2084 result = llapi_dir_set_default_lmv_stripe(dname,
2085 stripe_offset, stripe_count,
2088 result = llapi_dir_create_pool(dname, mode,
2090 stripe_count, hash_type,
2095 fprintf(stderr, "error: %s: create stripe dir '%s' "
2096 "failed\n", argv[0], dname);
2099 dname = argv[++optind];
2100 } while (dname != NULL);
2102 if (mode_opt != NULL)
2103 umask(previous_mode);
2109 static int lfs_rmentry(int argc, char **argv)
2116 fprintf(stderr, "error: %s: missing dirname\n",
2122 dname = argv[index];
2123 while (dname != NULL) {
2124 result = llapi_direntry_remove(dname);
2126 fprintf(stderr, "error: %s: remove dir entry '%s' "
2127 "failed\n", argv[0], dname);
2130 dname = argv[++index];
2135 static int lfs_mv(int argc, char **argv)
2137 struct find_param param = {
2144 struct option long_opts[] = {
2145 {"mdt-index", required_argument, 0, 'M'},
2146 {"verbose", no_argument, 0, 'v'},
2150 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2153 param.fp_mdt_index = strtoul(optarg, &end, 0);
2155 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2162 param.fp_verbose = VERBOSE_DETAIL;
2166 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2167 argv[0], argv[optind - 1]);
2172 if (param.fp_mdt_index == -1) {
2173 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2177 if (optind >= argc) {
2178 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2182 param.fp_migrate = 1;
2183 rc = llapi_migrate_mdt(argv[optind], ¶m);
2185 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2186 argv[0], argv[optind], param.fp_mdt_index,
2191 static int lfs_osts(int argc, char **argv)
2193 return lfs_tgts(argc, argv);
2196 static int lfs_mdts(int argc, char **argv)
2198 return lfs_tgts(argc, argv);
2201 #define COOK(value) \
2204 while (value > 1024) { \
2212 #define CDF "%11llu"
2213 #define HDF "%8.1f%c"
2217 static int showdf(char *mntdir, struct obd_statfs *stat,
2218 char *uuid, int ishow, int cooked,
2219 char *type, int index, int rc)
2221 long long avail, used, total;
2223 char *suffix = "KMGTPEZY";
2224 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2225 char tbuf[3 * sizeof(__u64)];
2226 char ubuf[3 * sizeof(__u64)];
2227 char abuf[3 * sizeof(__u64)];
2228 char rbuf[3 * sizeof(__u64)];
2236 avail = stat->os_ffree;
2237 used = stat->os_files - stat->os_ffree;
2238 total = stat->os_files;
2240 int shift = cooked ? 0 : 10;
2242 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2243 used = ((stat->os_blocks - stat->os_bfree) *
2244 stat->os_bsize) >> shift;
2245 total = (stat->os_blocks * stat->os_bsize) >> shift;
2248 if ((used + avail) > 0)
2249 ratio = (double)used / (double)(used + avail);
2255 cook_val = (double)total;
2258 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2260 sprintf(tbuf, CDF, total);
2262 cook_val = (double)used;
2265 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2267 sprintf(ubuf, CDF, used);
2269 cook_val = (double)avail;
2272 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2274 sprintf(abuf, CDF, avail);
2276 sprintf(tbuf, CDF, total);
2277 sprintf(ubuf, CDF, used);
2278 sprintf(abuf, CDF, avail);
2281 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2282 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2283 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2285 printf("[%s:%d]\n", type, index);
2291 printf(UUF": inactive device\n", uuid);
2294 printf(UUF": %s\n", uuid, strerror(-rc));
2301 struct ll_stat_type {
2306 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2307 int cooked, int lazy)
2309 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2310 struct obd_uuid uuid_buf;
2311 char *poolname = NULL;
2312 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2313 { LL_STATFS_LOV, "OST" },
2315 struct ll_stat_type *tp;
2316 __u64 ost_ffree = 0;
2322 poolname = strchr(pool, '.');
2323 if (poolname != NULL) {
2324 if (strncmp(fsname, pool, strlen(fsname))) {
2325 fprintf(stderr, "filesystem name incorrect\n");
2334 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2335 "UUID", "Inodes", "IUsed", "IFree",
2336 "IUse%", "Mounted on");
2338 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2339 "UUID", cooked ? "bytes" : "1K-blocks",
2340 "Used", "Available", "Use%", "Mounted on");
2342 for (tp = types; tp->st_name != NULL; tp++) {
2343 for (index = 0; ; index++) {
2344 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2345 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2346 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2347 rc = llapi_obd_statfs(mntdir, type, index,
2348 &stat_buf, &uuid_buf);
2355 if (poolname && tp->st_op == LL_STATFS_LOV &&
2356 llapi_search_ost(fsname, poolname,
2357 obd_uuid2str(&uuid_buf)) != 1)
2360 /* the llapi_obd_statfs() call may have returned with
2361 * an error, but if it filled in uuid_buf we will at
2362 * lease use that to print out a message for that OBD.
2363 * If we didn't get anything in the uuid_buf, then fill
2364 * it in so that we can print an error message. */
2365 if (uuid_buf.uuid[0] == '\0')
2366 sprintf(uuid_buf.uuid, "%s%04x",
2367 tp->st_name, index);
2368 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2369 ishow, cooked, tp->st_name, index, rc);
2372 if (tp->st_op == LL_STATFS_LMV) {
2373 sum.os_ffree += stat_buf.os_ffree;
2374 sum.os_files += stat_buf.os_files;
2375 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2376 sum.os_blocks += stat_buf.os_blocks *
2378 sum.os_bfree += stat_buf.os_bfree *
2380 sum.os_bavail += stat_buf.os_bavail *
2382 ost_ffree += stat_buf.os_ffree;
2384 } else if (rc == -EINVAL || rc == -EFAULT) {
2390 /* If we don't have as many objects free on the OST as inodes
2391 * on the MDS, we reduce the total number of inodes to
2392 * compensate, so that the "inodes in use" number is correct.
2393 * Matches ll_statfs_internal() so the results are consistent. */
2394 if (ost_ffree < sum.os_ffree) {
2395 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2396 sum.os_ffree = ost_ffree;
2399 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2404 static int lfs_df(int argc, char **argv)
2406 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2407 int ishow = 0, cooked = 0;
2409 int c, rc = 0, index = 0;
2410 char fsname[PATH_MAX] = "", *pool_name = NULL;
2411 struct option long_opts[] = {
2412 {"pool", required_argument, 0, 'p'},
2413 {"lazy", 0, 0, 'l'},
2417 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2435 if (optind < argc && !realpath(argv[optind], path)) {
2437 fprintf(stderr, "error: invalid path '%s': %s\n",
2438 argv[optind], strerror(-rc));
2442 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2443 /* Check if we have a mount point */
2444 if (mntdir[0] == '\0')
2447 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2448 if (rc || path[0] != '\0')
2450 fsname[0] = '\0'; /* avoid matching in next loop */
2451 mntdir[0] = '\0'; /* avoid matching in next loop */
2457 static int lfs_getname(int argc, char **argv)
2459 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2460 int rc = 0, index = 0, c;
2461 char buf[sizeof(struct obd_uuid)];
2463 while ((c = getopt(argc, argv, "h")) != -1)
2466 if (optind == argc) { /* no paths specified, get all paths. */
2467 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2468 rc = llapi_getname(mntdir, buf, sizeof(buf));
2471 "cannot get name for `%s': %s\n",
2472 mntdir, strerror(-rc));
2476 printf("%s %s\n", buf, mntdir);
2478 path[0] = fsname[0] = mntdir[0] = 0;
2480 } else { /* paths specified, only attempt to search these. */
2481 for (; optind < argc; optind++) {
2482 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2485 "cannot get name for `%s': %s\n",
2486 argv[optind], strerror(-rc));
2490 printf("%s %s\n", buf, argv[optind]);
2496 static int lfs_check(int argc, char **argv)
2499 char mntdir[PATH_MAX] = {'\0'};
2508 obd_types[0] = obd_type1;
2509 obd_types[1] = obd_type2;
2511 if (strcmp(argv[1], "osts") == 0) {
2512 strcpy(obd_types[0], "osc");
2513 } else if (strcmp(argv[1], "mds") == 0) {
2514 strcpy(obd_types[0], "mdc");
2515 } else if (strcmp(argv[1], "servers") == 0) {
2517 strcpy(obd_types[0], "osc");
2518 strcpy(obd_types[1], "mdc");
2520 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2525 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2526 if (rc < 0 || mntdir[0] == '\0') {
2527 fprintf(stderr, "No suitable Lustre mount found\n");
2531 rc = llapi_target_check(num_types, obd_types, mntdir);
2533 fprintf(stderr, "error: %s: %s status failed\n",
2540 static int lfs_join(int argc, char **argv)
2542 fprintf(stderr, "join two lustre files into one.\n"
2543 "obsolete, HEAD does not support it anymore.\n");
2547 #ifdef HAVE_SYS_QUOTA_H
2548 #define ARG2INT(nr, str, msg) \
2551 nr = strtol(str, &endp, 0); \
2553 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2558 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2560 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2561 * returns the value or ULONG_MAX on integer overflow or incorrect format
2563 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2564 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2565 * 3. empty integer value is interpreted as 0
2567 static unsigned long str2sec(const char* timestr)
2569 const char spec[] = "smhdw";
2570 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2571 unsigned long val = 0;
2574 if (strpbrk(timestr, spec) == NULL) {
2575 /* no specifiers inside the time string,
2576 should treat it as an integer value */
2577 val = strtoul(timestr, &tail, 10);
2578 return *tail ? ULONG_MAX : val;
2581 /* format string is XXwXXdXXhXXmXXs */
2587 v = strtoul(timestr, &tail, 10);
2588 if (v == ULONG_MAX || *tail == '\0')
2589 /* value too large (ULONG_MAX or more)
2590 or missing specifier */
2593 ptr = strchr(spec, *tail);
2595 /* unknown specifier */
2600 /* check if product will overflow the type */
2601 if (!(v < ULONG_MAX / mult[ind]))
2604 ADD_OVERFLOW(val, mult[ind] * v);
2605 if (val == ULONG_MAX)
2617 #define ARG2ULL(nr, str, def_units) \
2619 unsigned long long limit, units = def_units; \
2622 rc = llapi_parse_size(str, &limit, &units, 1); \
2624 fprintf(stderr, "error: bad limit value %s\n", str); \
2630 static inline int has_times_option(int argc, char **argv)
2634 for (i = 1; i < argc; i++)
2635 if (!strcmp(argv[i], "-t"))
2641 int lfs_setquota_times(int argc, char **argv)
2644 struct if_quotactl qctl;
2645 char *mnt, *obd_type = (char *)qctl.obd_type;
2646 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2647 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2648 struct option long_opts[] = {
2649 {"block-grace", required_argument, 0, 'b'},
2650 {"group", no_argument, 0, 'g'},
2651 {"inode-grace", required_argument, 0, 'i'},
2652 {"times", no_argument, 0, 't'},
2653 {"user", no_argument, 0, 'u'},
2657 memset(&qctl, 0, sizeof(qctl));
2658 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2659 qctl.qc_type = UGQUOTA;
2661 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2665 if (qctl.qc_type != UGQUOTA) {
2666 fprintf(stderr, "error: -u and -g can't be used "
2667 "more than once\n");
2670 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2673 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2674 fprintf(stderr, "error: bad block-grace: %s\n",
2678 dqb->dqb_valid |= QIF_BTIME;
2681 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2682 fprintf(stderr, "error: bad inode-grace: %s\n",
2686 dqb->dqb_valid |= QIF_ITIME;
2688 case 't': /* Yes, of course! */
2690 default: /* getopt prints error message for us when opterr != 0 */
2695 if (qctl.qc_type == UGQUOTA) {
2696 fprintf(stderr, "error: neither -u nor -g specified\n");
2700 if (optind != argc - 1) {
2701 fprintf(stderr, "error: unexpected parameters encountered\n");
2706 rc = llapi_quotactl(mnt, &qctl);
2709 fprintf(stderr, "%s %s ", obd_type,
2710 obd_uuid2str(&qctl.obd_uuid));
2711 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2718 #define BSLIMIT (1 << 0)
2719 #define BHLIMIT (1 << 1)
2720 #define ISLIMIT (1 << 2)
2721 #define IHLIMIT (1 << 3)
2723 int lfs_setquota(int argc, char **argv)
2726 struct if_quotactl qctl;
2727 char *mnt, *obd_type = (char *)qctl.obd_type;
2728 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2729 struct option long_opts[] = {
2730 {"block-softlimit", required_argument, 0, 'b'},
2731 {"block-hardlimit", required_argument, 0, 'B'},
2732 {"group", required_argument, 0, 'g'},
2733 {"inode-softlimit", required_argument, 0, 'i'},
2734 {"inode-hardlimit", required_argument, 0, 'I'},
2735 {"user", required_argument, 0, 'u'},
2738 unsigned limit_mask = 0;
2741 if (has_times_option(argc, argv))
2742 return lfs_setquota_times(argc, argv);
2744 memset(&qctl, 0, sizeof(qctl));
2745 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2746 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2747 * so it can be used as a marker that qc_type
2748 * isn't reinitialized from command line */
2750 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2754 if (qctl.qc_type != UGQUOTA) {
2755 fprintf(stderr, "error: -u and -g can't be used"
2756 " more than once\n");
2759 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2760 rc = name2id(&qctl.qc_id, optarg,
2761 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2763 qctl.qc_id = strtoul(optarg, &endptr, 10);
2764 if (*endptr != '\0') {
2765 fprintf(stderr, "error: can't find id "
2766 "for name %s\n", optarg);
2772 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2773 dqb->dqb_bsoftlimit >>= 10;
2774 limit_mask |= BSLIMIT;
2775 if (dqb->dqb_bsoftlimit &&
2776 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2777 fprintf(stderr, "warning: block softlimit is "
2778 "smaller than the miminal qunit size, "
2779 "please see the help of setquota or "
2780 "Lustre manual for details.\n");
2783 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2784 dqb->dqb_bhardlimit >>= 10;
2785 limit_mask |= BHLIMIT;
2786 if (dqb->dqb_bhardlimit &&
2787 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2788 fprintf(stderr, "warning: block hardlimit is "
2789 "smaller than the miminal qunit size, "
2790 "please see the help of setquota or "
2791 "Lustre manual for details.\n");
2794 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2795 limit_mask |= ISLIMIT;
2796 if (dqb->dqb_isoftlimit &&
2797 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2798 fprintf(stderr, "warning: inode softlimit is "
2799 "smaller than the miminal qunit size, "
2800 "please see the help of setquota or "
2801 "Lustre manual for details.\n");
2804 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2805 limit_mask |= IHLIMIT;
2806 if (dqb->dqb_ihardlimit &&
2807 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2808 fprintf(stderr, "warning: inode hardlimit is "
2809 "smaller than the miminal qunit size, "
2810 "please see the help of setquota or "
2811 "Lustre manual for details.\n");
2813 default: /* getopt prints error message for us when opterr != 0 */
2818 if (qctl.qc_type == UGQUOTA) {
2819 fprintf(stderr, "error: neither -u nor -g was specified\n");
2823 if (limit_mask == 0) {
2824 fprintf(stderr, "error: at least one limit must be specified\n");
2828 if (optind != argc - 1) {
2829 fprintf(stderr, "error: unexpected parameters encountered\n");
2835 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2836 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2837 /* sigh, we can't just set blimits/ilimits */
2838 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2839 .qc_type = qctl.qc_type,
2840 .qc_id = qctl.qc_id};
2842 rc = llapi_quotactl(mnt, &tmp_qctl);
2844 fprintf(stderr, "error: setquota failed while retrieving"
2845 " current quota settings (%s)\n",
2850 if (!(limit_mask & BHLIMIT))
2851 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2852 if (!(limit_mask & BSLIMIT))
2853 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2854 if (!(limit_mask & IHLIMIT))
2855 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2856 if (!(limit_mask & ISLIMIT))
2857 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2859 /* Keep grace times if we have got no softlimit arguments */
2860 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2861 dqb->dqb_valid |= QIF_BTIME;
2862 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2865 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2866 dqb->dqb_valid |= QIF_ITIME;
2867 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2871 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2872 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2874 rc = llapi_quotactl(mnt, &qctl);
2877 fprintf(stderr, "%s %s ", obd_type,
2878 obd_uuid2str(&qctl.obd_uuid));
2879 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2886 static inline char *type2name(int check_type)
2888 if (check_type == USRQUOTA)
2890 else if (check_type == GRPQUOTA)
2896 /* Converts seconds value into format string
2897 * result is returned in buf
2899 * 1. result is in descenting order: 1w2d3h4m5s
2900 * 2. zero fields are not filled (except for p. 3): 5d1s
2901 * 3. zero seconds value is presented as "0s"
2903 static char * __sec2str(time_t seconds, char *buf)
2905 const char spec[] = "smhdw";
2906 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2911 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2912 c = seconds / mult[i];
2914 if (c > 0 || (i == 0 && buf == tail))
2915 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2923 static void sec2str(time_t seconds, char *buf, int rc)
2930 tail = __sec2str(seconds, tail);
2932 if (rc && tail - buf < 39) {
2938 static void diff2str(time_t seconds, char *buf, time_t now)
2944 if (seconds <= now) {
2945 strcpy(buf, "none");
2948 __sec2str(seconds - now, buf);
2951 static void print_quota_title(char *name, struct if_quotactl *qctl,
2952 bool human_readable)
2954 printf("Disk quotas for %s %s (%cid %u):\n",
2955 type2name(qctl->qc_type), name,
2956 *type2name(qctl->qc_type), qctl->qc_id);
2957 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2958 "Filesystem", human_readable ? "used" : "kbytes",
2959 "quota", "limit", "grace",
2960 "files", "quota", "limit", "grace");
2963 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
2966 snprintf(buf, buflen, "%ju", (uintmax_t)num);
2969 snprintf(buf, buflen, "%5.4gP",
2970 (double)num / ((__u64)1 << 40));
2972 snprintf(buf, buflen, "%5.4gT",
2973 (double)num / (1 << 30));
2975 snprintf(buf, buflen, "%5.4gG",
2976 (double)num / (1 << 20));
2978 snprintf(buf, buflen, "%5.4gM",
2979 (double)num / (1 << 10));
2981 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
2985 #define STRBUF_LEN 32
2986 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2993 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2994 int bover = 0, iover = 0;
2995 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2996 char numbuf[3][STRBUF_LEN];
2998 char strbuf[STRBUF_LEN];
3000 if (dqb->dqb_bhardlimit &&
3001 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3003 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3004 if (dqb->dqb_btime > now) {
3011 if (dqb->dqb_ihardlimit &&
3012 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3014 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3015 if (dqb->dqb_itime > now) {
3023 if (strlen(mnt) > 15)
3024 printf("%s\n%15s", mnt, "");
3026 printf("%15s", mnt);
3029 diff2str(dqb->dqb_btime, timebuf, now);
3031 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3032 strbuf, sizeof(strbuf), h);
3033 if (rc == -EREMOTEIO)
3034 sprintf(numbuf[0], "%s*", strbuf);
3036 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3037 "%s" : "[%s]", strbuf);
3039 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3040 if (type == QC_GENERAL)
3041 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3042 "%s" : "[%s]", strbuf);
3044 sprintf(numbuf[1], "%s", "-");
3046 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3047 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3048 "%s" : "[%s]", strbuf);
3050 printf(" %7s%c %6s %7s %7s",
3051 numbuf[0], bover ? '*' : ' ', numbuf[1],
3052 numbuf[2], bover > 1 ? timebuf : "-");
3055 diff2str(dqb->dqb_itime, timebuf, now);
3057 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3058 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3060 if (type == QC_GENERAL)
3061 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3063 (uintmax_t)dqb->dqb_isoftlimit);
3065 sprintf(numbuf[1], "%s", "-");
3067 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3068 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3070 if (type != QC_OSTIDX)
3071 printf(" %7s%c %6s %7s %7s",
3072 numbuf[0], iover ? '*' : ' ', numbuf[1],
3073 numbuf[2], iover > 1 ? timebuf : "-");
3075 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3078 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3079 qctl->qc_cmd == Q_GETOINFO) {
3083 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3084 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3085 printf("Block grace time: %s; Inode grace time: %s\n",
3086 bgtimebuf, igtimebuf);
3090 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3091 bool h, __u64 *total)
3093 int rc = 0, rc1 = 0, count = 0;
3094 __u32 valid = qctl->qc_valid;
3096 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3098 fprintf(stderr, "can not get %s count: %s\n",
3099 is_mdt ? "mdt": "ost", strerror(-rc));
3103 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3104 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3105 rc = llapi_quotactl(mnt, qctl);
3107 /* It is remote client case. */
3108 if (-rc == EOPNOTSUPP) {
3115 fprintf(stderr, "quotactl %s%d failed.\n",
3116 is_mdt ? "mdt": "ost", qctl->qc_idx);
3120 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3121 qctl->qc_valid, 0, h);
3122 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3123 qctl->qc_dqblk.dqb_bhardlimit;
3126 qctl->qc_valid = valid;
3130 static int lfs_quota(int argc, char **argv)
3133 char *mnt, *name = NULL;
3134 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3135 .qc_type = UGQUOTA };
3136 char *obd_type = (char *)qctl.obd_type;
3137 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3138 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3139 verbose = 0, pass = 0, quiet = 0, inacc;
3141 __u32 valid = QC_GENERAL, idx = 0;
3142 __u64 total_ialloc = 0, total_balloc = 0;
3143 bool human_readable = false;
3145 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3148 if (qctl.qc_type != UGQUOTA) {
3149 fprintf(stderr, "error: use either -u or -g\n");
3152 qctl.qc_type = USRQUOTA;
3155 if (qctl.qc_type != UGQUOTA) {
3156 fprintf(stderr, "error: use either -u or -g\n");
3159 qctl.qc_type = GRPQUOTA;
3162 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3165 valid = qctl.qc_valid = QC_UUID;
3166 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3169 valid = qctl.qc_valid = QC_MDTIDX;
3170 idx = qctl.qc_idx = atoi(optarg);
3173 valid = qctl.qc_valid = QC_OSTIDX;
3174 idx = qctl.qc_idx = atoi(optarg);
3183 human_readable = true;
3186 fprintf(stderr, "error: %s: option '-%c' "
3187 "unrecognized\n", argv[0], c);
3192 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3193 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3194 optind == argc - 1) {
3196 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3197 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3198 qctl.qc_valid = valid;
3201 qctl.qc_type = USRQUOTA;
3202 qctl.qc_id = geteuid();
3204 qctl.qc_type = GRPQUOTA;
3205 qctl.qc_id = getegid();
3207 rc = id2name(&name, qctl.qc_id,
3208 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3211 /* lfs quota -u username /path/to/lustre/mount */
3212 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3213 /* options should be followed by u/g-name and mntpoint */
3214 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3215 fprintf(stderr, "error: missing quota argument(s)\n");
3219 name = argv[optind++];
3220 rc = name2id(&qctl.qc_id, name,
3221 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3223 qctl.qc_id = strtoul(name, &endptr, 10);
3224 if (*endptr != '\0') {
3225 fprintf(stderr, "error: can't find id for name "
3230 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3231 fprintf(stderr, "error: missing quota info argument(s)\n");
3237 rc1 = llapi_quotactl(mnt, &qctl);
3241 fprintf(stderr, "%s quotas are not enabled.\n",
3242 qctl.qc_type == USRQUOTA ? "user" : "group");
3245 fprintf(stderr, "Permission denied.\n");
3247 /* We already got a "No such file..." message. */
3250 fprintf(stderr, "Unexpected quotactl error: %s\n",
3255 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3256 print_quota_title(name, &qctl, human_readable);
3258 if (rc1 && *obd_type)
3259 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3261 if (qctl.qc_valid != QC_GENERAL)
3264 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3265 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3266 (QIF_LIMITS|QIF_USAGE));
3268 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3270 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3272 char strbuf[STRBUF_LEN];
3274 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3276 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3278 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3280 printf("Total allocated inode limit: %ju, total "
3281 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3285 if (rc1 || rc2 || rc3 || inacc)
3286 printf("Some errors happened when getting quota info. "
3287 "Some devices may be not working or deactivated. "
3288 "The data in \"[]\" is inaccurate.\n");
3296 #endif /* HAVE_SYS_QUOTA_H! */
3298 static int flushctx_ioctl(char *mp)
3302 fd = open(mp, O_RDONLY);
3304 fprintf(stderr, "flushctx: error open %s: %s\n",
3305 mp, strerror(errno));
3309 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3311 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3312 mp, strerror(errno));
3318 static int lfs_flushctx(int argc, char **argv)
3320 int kdestroy = 0, c;
3321 char mntdir[PATH_MAX] = {'\0'};
3325 while ((c = getopt(argc, argv, "k")) != -1) {
3331 fprintf(stderr, "error: %s: option '-%c' "
3332 "unrecognized\n", argv[0], c);
3338 if ((rc = system("kdestroy > /dev/null")) != 0) {
3339 rc = WEXITSTATUS(rc);
3340 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3344 if (optind >= argc) {
3345 /* flush for all mounted lustre fs. */
3346 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3347 /* Check if we have a mount point */
3348 if (mntdir[0] == '\0')
3351 if (flushctx_ioctl(mntdir))
3354 mntdir[0] = '\0'; /* avoid matching in next loop */
3357 /* flush fs as specified */
3358 while (optind < argc) {
3359 if (flushctx_ioctl(argv[optind++]))
3366 static int lfs_lsetfacl(int argc, char **argv)
3368 fprintf(stderr, "local client sets facl for remote client.\n"
3369 "obsolete, does not support it anymore.\n");
3373 static int lfs_lgetfacl(int argc, char **argv)
3375 fprintf(stderr, "local client gets facl for remote client.\n"
3376 "obsolete, does not support it anymore.\n");
3380 static int lfs_rsetfacl(int argc, char **argv)
3382 fprintf(stderr, "remote client sets facl for remote client.\n"
3383 "obsolete, does not support it anymore.\n");
3387 static int lfs_rgetfacl(int argc, char **argv)
3389 fprintf(stderr, "remote client gets facl for remote client.\n"
3390 "obsolete, does not support it anymore.\n");
3394 static int lfs_cp(int argc, char **argv)
3396 fprintf(stderr, "remote client copy file(s).\n"
3397 "obsolete, does not support it anymore.\n");
3401 static int lfs_ls(int argc, char **argv)
3403 fprintf(stderr, "remote client lists directory contents.\n"
3404 "obsolete, does not support it anymore.\n");
3408 static int lfs_changelog(int argc, char **argv)
3410 void *changelog_priv;
3411 struct changelog_rec *rec;
3412 long long startrec = 0, endrec = 0;
3414 struct option long_opts[] = {
3415 {"follow", no_argument, 0, 'f'},
3418 char short_opts[] = "f";
3421 while ((rc = getopt_long(argc, argv, short_opts,
3422 long_opts, NULL)) != -1) {
3430 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3431 argv[0], argv[optind - 1]);
3438 mdd = argv[optind++];
3440 startrec = strtoll(argv[optind++], NULL, 10);
3442 endrec = strtoll(argv[optind++], NULL, 10);
3444 rc = llapi_changelog_start(&changelog_priv,
3445 CHANGELOG_FLAG_BLOCK |
3446 CHANGELOG_FLAG_JOBID |
3447 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3450 fprintf(stderr, "Can't start changelog: %s\n",
3451 strerror(errno = -rc));
3455 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3459 if (endrec && rec->cr_index > endrec) {
3460 llapi_changelog_free(&rec);
3463 if (rec->cr_index < startrec) {
3464 llapi_changelog_free(&rec);
3468 secs = rec->cr_time >> 30;
3469 gmtime_r(&secs, &ts);
3470 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3471 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3472 changelog_type2str(rec->cr_type),
3473 ts.tm_hour, ts.tm_min, ts.tm_sec,
3474 (int)(rec->cr_time & ((1<<30) - 1)),
3475 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3476 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3478 if (rec->cr_flags & CLF_JOBID) {
3479 struct changelog_ext_jobid *jid =
3480 changelog_rec_jobid(rec);
3482 if (jid->cr_jobid[0] != '\0')
3483 printf(" j=%s", jid->cr_jobid);
3486 if (rec->cr_namelen)
3487 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3488 rec->cr_namelen, changelog_rec_name(rec));
3490 if (rec->cr_flags & CLF_RENAME) {
3491 struct changelog_ext_rename *rnm =
3492 changelog_rec_rename(rec);
3494 if (!fid_is_zero(&rnm->cr_sfid))
3495 printf(" s="DFID" sp="DFID" %.*s",
3496 PFID(&rnm->cr_sfid),
3497 PFID(&rnm->cr_spfid),
3498 (int)changelog_rec_snamelen(rec),
3499 changelog_rec_sname(rec));
3503 llapi_changelog_free(&rec);
3506 llapi_changelog_fini(&changelog_priv);
3509 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3511 return (rc == 1 ? 0 : rc);
3514 static int lfs_changelog_clear(int argc, char **argv)
3522 endrec = strtoll(argv[3], NULL, 10);
3524 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3526 fprintf(stderr, "%s error: %s\n", argv[0],
3527 strerror(errno = -rc));
3531 static int lfs_fid2path(int argc, char **argv)
3533 struct option long_opts[] = {
3534 {"cur", no_argument, 0, 'c'},
3535 {"link", required_argument, 0, 'l'},
3536 {"rec", required_argument, 0, 'r'},
3539 char short_opts[] = "cl:r:";
3540 char *device, *fid, *path;
3541 long long recno = -1;
3547 while ((rc = getopt_long(argc, argv, short_opts,
3548 long_opts, NULL)) != -1) {
3554 linkno = strtol(optarg, NULL, 10);
3557 recno = strtoll(optarg, NULL, 10);
3562 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3563 argv[0], argv[optind - 1]);
3571 device = argv[optind++];
3572 path = calloc(1, PATH_MAX);
3574 fprintf(stderr, "error: Not enough memory\n");
3579 while (optind < argc) {
3580 fid = argv[optind++];
3582 lnktmp = (linkno >= 0) ? linkno : 0;
3584 int oldtmp = lnktmp;
3585 long long rectmp = recno;
3587 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3590 fprintf(stderr, "%s: error on FID %s: %s\n",
3591 argv[0], fid, strerror(errno = -rc2));
3598 fprintf(stdout, "%lld ", rectmp);
3599 if (device[0] == '/') {
3600 fprintf(stdout, "%s", device);
3601 if (device[strlen(device) - 1] != '/')
3602 fprintf(stdout, "/");
3603 } else if (path[0] == '\0') {
3604 fprintf(stdout, "/");
3606 fprintf(stdout, "%s\n", path);
3609 /* specified linkno */
3611 if (oldtmp == lnktmp)
3621 static int lfs_path2fid(int argc, char **argv)
3623 struct option long_opts[] = {
3624 {"parents", no_argument, 0, 'p'},
3628 const char short_opts[] = "p";
3629 const char *sep = "";
3632 bool show_parents = false;
3634 while ((rc = getopt_long(argc, argv, short_opts,
3635 long_opts, NULL)) != -1) {
3638 show_parents = true;
3641 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3642 argv[0], argv[optind - 1]);
3647 if (optind > argc - 1)
3649 else if (optind < argc - 1)
3653 for (path = argv + optind; *path != NULL; path++) {
3655 if (!show_parents) {
3656 err = llapi_path2fid(*path, &fid);
3658 printf("%s%s"DFID"\n",
3659 *sep != '\0' ? *path : "", sep,
3662 char name[NAME_MAX + 1];
3663 unsigned int linkno = 0;
3665 while ((err = llapi_path2parent(*path, linkno, &fid,
3666 name, sizeof(name))) == 0) {
3667 if (*sep != '\0' && linkno == 0)
3668 printf("%s%s", *path, sep);
3670 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3675 /* err == -ENODATA is end-of-loop */
3676 if (linkno > 0 && err == -ENODATA) {
3683 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3684 argv[0], show_parents ? "parent " : "", *path,
3696 static int lfs_data_version(int argc, char **argv)
3703 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3708 while ((c = getopt(argc, argv, "nrw")) != -1) {
3711 data_version_flags = 0;
3714 data_version_flags |= LL_DV_RD_FLUSH;
3717 data_version_flags |= LL_DV_WR_FLUSH;
3726 path = argv[optind];
3727 fd = open(path, O_RDONLY);
3729 err(errno, "cannot open file %s", path);
3731 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3733 err(errno, "cannot get version for %s", path);
3735 printf("%ju" "\n", (uintmax_t)data_version);
3741 static int lfs_hsm_state(int argc, char **argv)
3746 struct hsm_user_state hus;
3754 rc = llapi_hsm_state_get(path, &hus);
3756 fprintf(stderr, "can't get hsm state for %s: %s\n",
3757 path, strerror(errno = -rc));
3761 /* Display path name and status flags */
3762 printf("%s: (0x%08x)", path, hus.hus_states);
3764 if (hus.hus_states & HS_RELEASED)
3765 printf(" released");
3766 if (hus.hus_states & HS_EXISTS)
3768 if (hus.hus_states & HS_DIRTY)
3770 if (hus.hus_states & HS_ARCHIVED)
3771 printf(" archived");
3772 /* Display user-settable flags */
3773 if (hus.hus_states & HS_NORELEASE)
3774 printf(" never_release");
3775 if (hus.hus_states & HS_NOARCHIVE)
3776 printf(" never_archive");
3777 if (hus.hus_states & HS_LOST)
3778 printf(" lost_from_hsm");
3780 if (hus.hus_archive_id != 0)
3781 printf(", archive_id:%d", hus.hus_archive_id);
3784 } while (++i < argc);
3789 #define LFS_HSM_SET 0
3790 #define LFS_HSM_CLEAR 1
3793 * Generic function to set or clear HSM flags.
3794 * Used by hsm_set and hsm_clear.
3796 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3798 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3800 struct option long_opts[] = {
3801 {"lost", 0, 0, 'l'},
3802 {"norelease", 0, 0, 'r'},
3803 {"noarchive", 0, 0, 'a'},
3804 {"archived", 0, 0, 'A'},
3805 {"dirty", 0, 0, 'd'},
3806 {"exists", 0, 0, 'e'},
3809 char short_opts[] = "lraAde";
3817 while ((c = getopt_long(argc, argv, short_opts,
3818 long_opts, NULL)) != -1) {
3824 mask |= HS_NOARCHIVE;
3827 mask |= HS_ARCHIVED;
3830 mask |= HS_NORELEASE;
3841 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3842 argv[0], argv[optind - 1]);
3847 /* User should have specified a flag */
3851 while (optind < argc) {
3853 path = argv[optind];
3855 /* If mode == 0, this means we apply the mask. */
3856 if (mode == LFS_HSM_SET)
3857 rc = llapi_hsm_state_set(path, mask, 0, 0);
3859 rc = llapi_hsm_state_set(path, 0, mask, 0);
3862 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3863 path, strerror(errno = -rc));
3872 static int lfs_hsm_action(int argc, char **argv)
3877 struct hsm_current_action hca;
3878 struct hsm_extent he;
3879 enum hsm_user_action hua;
3880 enum hsm_progress_states hps;
3888 rc = llapi_hsm_current_action(path, &hca);
3890 fprintf(stderr, "can't get hsm action for %s: %s\n",
3891 path, strerror(errno = -rc));
3894 he = hca.hca_location;
3895 hua = hca.hca_action;
3896 hps = hca.hca_state;
3898 printf("%s: %s", path, hsm_user_action2name(hua));
3900 /* Skip file without action */
3901 if (hca.hca_action == HUA_NONE) {
3906 printf(" %s ", hsm_progress_state2name(hps));
3908 if ((hps == HPS_RUNNING) &&
3909 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3910 printf("(%llu bytes moved)\n",
3911 (unsigned long long)he.length);
3912 else if ((he.offset + he.length) == LUSTRE_EOF)
3913 printf("(from %llu to EOF)\n",
3914 (unsigned long long)he.offset);
3916 printf("(from %llu to %llu)\n",
3917 (unsigned long long)he.offset,
3918 (unsigned long long)(he.offset + he.length));
3920 } while (++i < argc);
3925 static int lfs_hsm_set(int argc, char **argv)
3927 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3930 static int lfs_hsm_clear(int argc, char **argv)
3932 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3936 * Check file state and return its fid, to be used by lfs_hsm_request().
3938 * \param[in] file Path to file to check
3939 * \param[in,out] fid Pointer to allocated lu_fid struct.
3940 * \param[in,out] last_dev Pointer to last device id used.
3942 * \return 0 on success.
3944 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3950 rc = lstat(file, &st);
3952 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3955 /* Checking for regular file as archiving as posix copytool
3956 * rejects archiving files other than regular files
3958 if (!S_ISREG(st.st_mode)) {
3959 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3962 /* A request should be ... */
3963 if (*last_dev != st.st_dev && *last_dev != 0) {
3964 fprintf(stderr, "All files should be "
3965 "on the same filesystem: %s\n", file);
3968 *last_dev = st.st_dev;
3970 rc = llapi_path2fid(file, fid);
3972 fprintf(stderr, "Cannot read FID of %s: %s\n",
3973 file, strerror(-rc));
3979 /* Fill an HSM HUR item with a given file name.
3981 * If mntpath is set, then the filename is actually a FID, and no
3982 * lookup on the filesystem will be performed.
3984 * \param[in] hur the user request to fill
3985 * \param[in] idx index of the item inside the HUR to fill
3986 * \param[in] mntpath mountpoint of Lustre
3987 * \param[in] fname filename (if mtnpath is NULL)
3988 * or FID (if mntpath is set)
3989 * \param[in] last_dev pointer to last device id used
3991 * \retval 0 on success
3992 * \retval CMD_HELP or a negative errno on error
3994 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3995 const char *mntpath, const char *fname,
3998 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4001 hui->hui_extent.length = -1;
4003 if (mntpath != NULL) {
4006 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4010 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4015 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4019 hur->hur_request.hr_itemcount++;
4024 static int lfs_hsm_request(int argc, char **argv, int action)
4026 struct option long_opts[] = {
4027 {"filelist", 1, 0, 'l'},
4028 {"data", 1, 0, 'D'},
4029 {"archive", 1, 0, 'a'},
4030 {"mntpath", 1, 0, 'm'},
4034 char short_opts[] = "l:D:a:m:";
4035 struct hsm_user_request *hur, *oldhur;
4040 char *filelist = NULL;
4041 char fullpath[PATH_MAX];
4042 char *opaque = NULL;
4046 int nbfile_alloc = 0;
4047 char *some_file = NULL;
4048 char *mntpath = NULL;
4054 while ((c = getopt_long(argc, argv, short_opts,
4055 long_opts, NULL)) != -1) {
4064 if (action != HUA_ARCHIVE &&
4065 action != HUA_REMOVE) {
4067 "error: -a is supported only "
4068 "when archiving or removing\n");
4071 archive_id = atoi(optarg);
4074 if (some_file == NULL) {
4076 some_file = strdup(optarg);
4082 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4083 argv[0], argv[optind - 1]);
4088 /* All remaining args are files, so we have at least nbfile */
4089 nbfile = argc - optind;
4091 if ((nbfile == 0) && (filelist == NULL))
4095 opaque_len = strlen(opaque);
4097 /* Alloc the request structure with enough place to store all files
4098 * from command line. */
4099 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4101 fprintf(stderr, "Cannot create the request: %s\n",
4105 nbfile_alloc = nbfile;
4107 hur->hur_request.hr_action = action;
4108 hur->hur_request.hr_archive_id = archive_id;
4109 hur->hur_request.hr_flags = 0;
4111 /* All remaining args are files, add them */
4112 if (nbfile != 0 && some_file == NULL)
4113 some_file = strdup(argv[optind]);
4115 for (i = 0; i < nbfile; i++) {
4116 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4122 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4124 /* If a filelist was specified, read the filelist from it. */
4125 if (filelist != NULL) {
4126 fp = fopen(filelist, "r");
4128 fprintf(stderr, "Cannot read the file list %s: %s\n",
4129 filelist, strerror(errno));
4134 while ((rc = getline(&line, &len, fp)) != -1) {
4135 /* If allocated buffer was too small, get something
4137 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4140 nbfile_alloc = nbfile_alloc * 2 + 1;
4142 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4145 fprintf(stderr, "hsm: cannot allocate "
4146 "the request: %s\n",
4153 size = hur_len(oldhur);
4155 fprintf(stderr, "hsm: cannot allocate "
4156 "%u files + %u bytes data\n",
4157 oldhur->hur_request.hr_itemcount,
4158 oldhur->hur_request.hr_data_len);
4165 memcpy(hur, oldhur, size);
4170 if (line[strlen(line) - 1] == '\n')
4171 line[strlen(line) - 1] = '\0';
4173 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4174 mntpath, line, &last_dev);
4180 if (some_file == NULL) {
4190 /* If a --data was used, add it to the request */
4191 hur->hur_request.hr_data_len = opaque_len;
4193 memcpy(hur_data(hur), opaque, opaque_len);
4195 /* Send the HSM request */
4196 if (realpath(some_file, fullpath) == NULL) {
4197 fprintf(stderr, "Could not find path '%s': %s\n",
4198 some_file, strerror(errno));
4200 rc = llapi_hsm_request(fullpath, hur);
4202 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4203 some_file, strerror(-rc));
4213 static int lfs_hsm_archive(int argc, char **argv)
4215 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4218 static int lfs_hsm_restore(int argc, char **argv)
4220 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4223 static int lfs_hsm_release(int argc, char **argv)
4225 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4228 static int lfs_hsm_remove(int argc, char **argv)
4230 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4233 static int lfs_hsm_cancel(int argc, char **argv)
4235 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4238 static int lfs_swap_layouts(int argc, char **argv)
4243 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4244 SWAP_LAYOUTS_KEEP_MTIME |
4245 SWAP_LAYOUTS_KEEP_ATIME);
4248 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4250 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4252 enum lu_ladvise_type advice;
4255 advice < ARRAY_SIZE(ladvise_names); advice++) {
4256 if (ladvise_names[advice] == NULL)
4258 if (strcmp(string, ladvise_names[advice]) == 0)
4262 return LU_LADVISE_INVALID;
4265 static int lfs_ladvise(int argc, char **argv)
4267 struct option long_opts[] = {
4268 {"advice", required_argument, 0, 'a'},
4269 {"background", no_argument, 0, 'b'},
4270 {"end", required_argument, 0, 'e'},
4271 {"start", required_argument, 0, 's'},
4272 {"length", required_argument, 0, 'l'},
4275 char short_opts[] = "a:be:l:s:";
4280 struct llapi_lu_ladvise advice;
4281 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4282 unsigned long long start = 0;
4283 unsigned long long end = LUSTRE_EOF;
4284 unsigned long long length = 0;
4285 unsigned long long size_units;
4286 unsigned long long flags = 0;
4289 while ((c = getopt_long(argc, argv, short_opts,
4290 long_opts, NULL)) != -1) {
4293 advice_type = lfs_get_ladvice(optarg);
4294 if (advice_type == LU_LADVISE_INVALID) {
4295 fprintf(stderr, "%s: invalid advice type "
4296 "'%s'\n", argv[0], optarg);
4297 fprintf(stderr, "Valid types:");
4299 for (advice_type = 0;
4300 advice_type < ARRAY_SIZE(ladvise_names);
4302 if (ladvise_names[advice_type] == NULL)
4304 fprintf(stderr, " %s",
4305 ladvise_names[advice_type]);
4307 fprintf(stderr, "\n");
4317 rc = llapi_parse_size(optarg, &end,
4320 fprintf(stderr, "%s: bad end offset '%s'\n",
4327 rc = llapi_parse_size(optarg, &start,
4330 fprintf(stderr, "%s: bad start offset "
4331 "'%s'\n", argv[0], optarg);
4337 rc = llapi_parse_size(optarg, &length,
4340 fprintf(stderr, "%s: bad length '%s'\n",
4348 fprintf(stderr, "%s: option '%s' unrecognized\n",
4349 argv[0], argv[optind - 1]);
4354 if (advice_type == LU_LADVISE_INVALID) {
4355 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4356 fprintf(stderr, "Valid types:");
4357 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4359 if (ladvise_names[advice_type] == NULL)
4361 fprintf(stderr, " %s", ladvise_names[advice_type]);
4363 fprintf(stderr, "\n");
4367 if (argc <= optind) {
4368 fprintf(stderr, "%s: please give one or more file names\n",
4373 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4374 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4379 if (end == LUSTRE_EOF && length != 0)
4380 end = start + length;
4383 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4384 argv[0], start, end);
4388 while (optind < argc) {
4391 path = argv[optind++];
4393 fd = open(path, O_RDONLY);
4395 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4396 argv[0], path, strerror(errno));
4401 advice.lla_start = start;
4402 advice.lla_end = end;
4403 advice.lla_advice = advice_type;
4404 advice.lla_value1 = 0;
4405 advice.lla_value2 = 0;
4406 advice.lla_value3 = 0;
4407 advice.lla_value4 = 0;
4408 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4411 fprintf(stderr, "%s: cannot give advice '%s' to file "
4412 "'%s': %s\n", argv[0],
4413 ladvise_names[advice_type],
4414 path, strerror(errno));
4417 if (rc == 0 && rc2 < 0)
4423 int main(int argc, char **argv)
4427 /* Ensure that liblustreapi constructor has run */
4428 if (!liblustreapi_initialized)
4429 fprintf(stderr, "liblustreapi was not properly initialized\n");
4433 Parser_init("lfs > ", cmdlist);
4435 progname = argv[0]; /* Used in error messages */
4437 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4439 rc = Parser_commands();
4442 return rc < 0 ? -rc : rc;
4445 #ifdef _LUSTRE_IDL_H_
4446 /* Everything we need here should be included by lustreapi.h. */
4447 # error "lfs should not depend on lustre_idl.h"
4448 #endif /* _LUSTRE_IDL_H_ */