4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2015, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
38 * Author: Peter J. Braam <braam@clusterfs.com>
39 * Author: Phil Schwan <phil@clusterfs.com>
40 * Author: Robert Read <rread@clusterfs.com>
58 #include <sys/ioctl.h>
59 #include <sys/quota.h>
61 #include <sys/types.h>
67 #ifdef HAVE_SYS_QUOTA_H
68 # include <sys/quota.h>
71 #include <libcfs/util/string.h>
72 #include <libcfs/util/ioctl.h>
73 #include <libcfs/util/parser.h>
74 #include <lustre/lustreapi.h>
75 #include <lustre_ver.h>
76 #include <lustre_param.h>
79 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
80 #endif /* !ARRAY_SIZE */
83 static int lfs_setstripe(int argc, char **argv);
84 static int lfs_find(int argc, char **argv);
85 static int lfs_getstripe(int argc, char **argv);
86 static int lfs_getdirstripe(int argc, char **argv);
87 static int lfs_setdirstripe(int argc, char **argv);
88 static int lfs_rmentry(int argc, char **argv);
89 static int lfs_osts(int argc, char **argv);
90 static int lfs_mdts(int argc, char **argv);
91 static int lfs_df(int argc, char **argv);
92 static int lfs_getname(int argc, char **argv);
93 static int lfs_check(int argc, char **argv);
94 #ifdef HAVE_SYS_QUOTA_H
95 static int lfs_setquota(int argc, char **argv);
96 static int lfs_quota(int argc, char **argv);
98 static int lfs_flushctx(int argc, char **argv);
99 static int lfs_join(int argc, char **argv);
100 static int lfs_lsetfacl(int argc, char **argv);
101 static int lfs_lgetfacl(int argc, char **argv);
102 static int lfs_rsetfacl(int argc, char **argv);
103 static int lfs_rgetfacl(int argc, char **argv);
104 static int lfs_cp(int argc, char **argv);
105 static int lfs_ls(int argc, char **argv);
106 static int lfs_poollist(int argc, char **argv);
107 static int lfs_changelog(int argc, char **argv);
108 static int lfs_changelog_clear(int argc, char **argv);
109 static int lfs_fid2path(int argc, char **argv);
110 static int lfs_path2fid(int argc, char **argv);
111 static int lfs_data_version(int argc, char **argv);
112 static int lfs_hsm_state(int argc, char **argv);
113 static int lfs_hsm_set(int argc, char **argv);
114 static int lfs_hsm_clear(int argc, char **argv);
115 static int lfs_hsm_action(int argc, char **argv);
116 static int lfs_hsm_archive(int argc, char **argv);
117 static int lfs_hsm_restore(int argc, char **argv);
118 static int lfs_hsm_release(int argc, char **argv);
119 static int lfs_hsm_remove(int argc, char **argv);
120 static int lfs_hsm_cancel(int argc, char **argv);
121 static int lfs_swap_layouts(int argc, char **argv);
122 static int lfs_mv(int argc, char **argv);
123 static int lfs_ladvise(int argc, char **argv);
125 /* Setstripe and migrate share mostly the same parameters */
126 #define SSM_CMD_COMMON(cmd) \
127 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
128 " [--stripe-index|-i <start_ost_idx>]\n" \
129 " [--stripe-size|-S <stripe_size>]\n" \
130 " [--pool|-p <pool_name>]\n" \
131 " [--ost-list|-o <ost_indices>]\n"
133 #define SSM_HELP_COMMON \
134 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
135 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
136 "\t respectively)\n" \
137 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
138 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
139 "\tpool_name: Name of OST pool to use (default none)\n" \
140 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
141 "\t Indices be specified in a format of:\n" \
142 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
144 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
145 "\t If --pool is set with --ost-list, then the OSTs\n" \
146 "\t must be the members of the pool."
148 #define SETSTRIPE_USAGE \
149 SSM_CMD_COMMON("setstripe") \
150 " <directory|filename>\n" \
153 #define MIGRATE_USAGE \
154 SSM_CMD_COMMON("migrate ") \
156 " [--non-block|-n]\n" \
160 "\tblock: Block file access during data migration (default)\n" \
161 "\tnon-block: Abort migrations if concurrent access is detected\n" \
163 static const char *progname;
164 static bool file_lease_supported = true;
166 /* all available commands */
167 command_t cmdlist[] = {
168 {"setstripe", lfs_setstripe, 0,
169 "Create a new file with a specific striping pattern or\n"
170 "set the default striping pattern on an existing directory or\n"
171 "delete the default striping pattern from an existing directory\n"
172 "usage: setstripe -d <directory> (to delete default striping)\n"\
175 {"getstripe", lfs_getstripe, 0,
176 "To list the striping info for a given file or files in a\n"
177 "directory or recursively for all files in a directory tree.\n"
178 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
179 " [--stripe-count|-c] [--stripe-index|-i]\n"
180 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
181 " [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
182 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
183 " <directory|filename> ..."},
184 {"setdirstripe", lfs_setdirstripe, 0,
185 "To create a striped directory on a specified MDT. This can only\n"
186 "be done on MDT0 with the right of administrator.\n"
187 "usage: setdirstripe <--count|-c stripe_count>\n"
188 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
189 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
190 "\tstripe_count: stripe count of the striped directory\n"
191 "\tmdt_index: MDT index of first stripe\n"
192 "\thash_type: hash type of the striped directory. Hash types:\n"
193 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
194 " all_char sum of characters % MDT_COUNT (not recommended)\n"
195 "\tdefault_stripe: set default dirstripe of the directory\n"
196 "\tmode: the mode of the directory\n"},
197 {"getdirstripe", lfs_getdirstripe, 0,
198 "To list the striping info for a given directory\n"
199 "or recursively for all directories in a directory tree.\n"
200 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
202 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
203 {"mkdir", lfs_setdirstripe, 0,
204 "To create a striped directory on a specified MDT. This can only\n"
205 "be done on MDT0 with the right of administrator.\n"
206 "usage: mkdir <--count|-c stripe_count>\n"
207 " [--index|-i mdt_index] [--hash-type|-t hash_type]\n"
208 " [--default_stripe|-D ] [--mode|-m mode] <dir>\n"
209 "\tstripe_count: stripe count of the striped directory\n"
210 "\tmdt_index: MDT index of first stripe\n"
211 "\thash_type: hash type of the striped directory. Hash types:\n"
212 " fnv_1a_64 FNV-1a hash algorithm (default)\n"
213 " all_char sum of characters % MDT_COUNT (not recommended)\n"
214 "\tdefault_stripe: set default dirstripe of the directory\n"
215 "\tmode: the mode of the directory\n"},
216 {"rm_entry", lfs_rmentry, 0,
217 "To remove the name entry of the remote directory. Note: This\n"
218 "command will only delete the name entry, i.e. the remote directory\n"
219 "will become inaccessable after this command. This can only be done\n"
220 "by the administrator\n"
221 "usage: rm_entry <dir>\n"},
222 {"pool_list", lfs_poollist, 0,
223 "List pools or pool OSTs\n"
224 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
225 {"find", lfs_find, 0,
226 "find files matching given attributes recursively in directory tree.\n"
227 "usage: find <directory|filename> ...\n"
228 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
229 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
230 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
231 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
232 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
233 " [[!] --stripe-count|-c [+-]<stripes>]\n"
234 " [[!] --stripe-index|-i <index,...>]\n"
235 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
236 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
237 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
238 " [[!] --layout|-L released,raid0]\n"
239 "\t !: used before an option indicates 'NOT' requested attribute\n"
240 "\t -: used before a value indicates 'AT MOST' requested value\n"
241 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
242 {"check", lfs_check, 0,
243 "Display the status of MDS or OSTs (as specified in the command)\n"
244 "or all the servers (MDS and OSTs).\n"
245 "usage: check <osts|mds|servers>"},
246 {"join", lfs_join, 0,
247 "join two lustre files into one.\n"
248 "obsolete, HEAD does not support it anymore.\n"},
249 {"osts", lfs_osts, 0, "list OSTs connected to client "
250 "[for specified path only]\n" "usage: osts [path]"},
251 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
252 "[for specified path only]\n" "usage: mdts [path]"},
254 "report filesystem disk space usage or inodes usage"
255 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
256 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
257 {"getname", lfs_getname, 0, "list instances and specified mount points "
258 "[for specified path only]\n"
259 "Usage: getname [-h]|[path ...] "},
260 #ifdef HAVE_SYS_QUOTA_H
261 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
262 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
263 " -b <block-softlimit> -B <block-hardlimit>\n"
264 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
265 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
266 " [--block-softlimit <block-softlimit>]\n"
267 " [--block-hardlimit <block-hardlimit>]\n"
268 " [--inode-softlimit <inode-softlimit>]\n"
269 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
270 " setquota [-t] <-u|--user|-g|--group>\n"
271 " [--block-grace <block-grace>]\n"
272 " [--inode-grace <inode-grace>] <filesystem>\n"
273 " -b can be used instead of --block-softlimit/--block-grace\n"
274 " -B can be used instead of --block-hardlimit\n"
275 " -i can be used instead of --inode-softlimit/--inode-grace\n"
276 " -I can be used instead of --inode-hardlimit\n\n"
277 "Note: The total quota space will be split into many qunits and\n"
278 " balanced over all server targets, the minimal qunit size is\n"
279 " 1M bytes for block space and 1K inodes for inode space.\n\n"
280 " Quota space rebalancing process will stop when this mininum\n"
281 " value is reached. As a result, quota exceeded can be returned\n"
282 " while many targets still have 1MB or 1K inodes of spare\n"
284 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
285 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
287 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
288 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
290 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
291 "usage: flushctx [-k] [mountpoint...]"},
292 {"lsetfacl", lfs_lsetfacl, 0,
293 "Remote user setfacl for user/group on the same remote client.\n"
294 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
295 {"lgetfacl", lfs_lgetfacl, 0,
296 "Remote user getfacl for user/group on the same remote client.\n"
297 "usage: lgetfacl [-dRLPvh] file ..."},
298 {"rsetfacl", lfs_rsetfacl, 0,
299 "Remote user setfacl for user/group on other clients.\n"
300 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
301 {"rgetfacl", lfs_rgetfacl, 0,
302 "Remote user getfacl for user/group on other clients.\n"
303 "usage: rgetfacl [-dRLPvh] file ..."},
305 "Remote user copy files and directories.\n"
306 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
308 "Remote user list directory contents.\n"
309 "usage: ls [OPTION]... [FILE]..."},
310 {"changelog", lfs_changelog, 0,
311 "Show the metadata changes on an MDT."
312 "\nusage: changelog <mdtname> [startrec [endrec]]"},
313 {"changelog_clear", lfs_changelog_clear, 0,
314 "Indicate that old changelog records up to <endrec> are no longer of "
315 "interest to consumer <id>, allowing the system to free up space.\n"
316 "An <endrec> of 0 means all records.\n"
317 "usage: changelog_clear <mdtname> <id> <endrec>"},
318 {"fid2path", lfs_fid2path, 0,
319 "Resolve the full path(s) for given FID(s). For a specific hardlink "
320 "specify link number <linkno>.\n"
321 /* "For a historical link name, specify changelog record <recno>.\n" */
322 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
323 /* [ --rec <recno> ] */ },
324 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
325 "usage: path2fid [--parents] <path> ..."},
326 {"data_version", lfs_data_version, 0, "Display file data version for "
327 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
328 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
329 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
330 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
331 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
332 "[--archived] [--lost] <file> ..."},
333 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
335 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
336 "[--archived] [--lost] <file> ..."},
337 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
338 "given files.\n" "usage: hsm_action <file> ..."},
339 {"hsm_archive", lfs_hsm_archive, 0,
340 "Archive file to external storage.\n"
341 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
343 {"hsm_restore", lfs_hsm_restore, 0,
344 "Restore file from external storage.\n"
345 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
346 {"hsm_release", lfs_hsm_release, 0,
347 "Release files from Lustre.\n"
348 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
349 {"hsm_remove", lfs_hsm_remove, 0,
350 "Remove file copy from external storage.\n"
351 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
352 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
354 "Note: To remove files from the archive that have been deleted on\n"
355 "Lustre, set mntpath and optionally archive. In that case, all the\n"
356 "positional arguments and entries in the file list must be FIDs."
358 {"hsm_cancel", lfs_hsm_cancel, 0,
359 "Cancel requests related to specified files.\n"
360 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
361 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
362 "usage: swap_layouts <path1> <path2>"},
363 {"migrate", lfs_setstripe, 0,
364 "migrate a directory between MDTs.\n"
365 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
367 "\tmdt_idx: index of the destination MDT\n"
369 "migrate file objects from one OST "
370 "layout\nto another (may be not safe with concurent writes).\n"
372 "[--stripe-count|-c] <stripe_count>\n"
373 " [--stripe-index|-i] <start_ost_index>\n"
374 " [--stripe-size|-S] <stripe_size>\n"
375 " [--pool|-p] <pool_name>\n"
376 " [--ost-list|-o] <ost_indices>\n"
378 " [--non-block|-n]\n"
379 " <file|directory>\n"
380 "\tstripe_count: number of OSTs to stripe a file over\n"
381 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
382 "\tstripe_size: number of bytes to store before moving to the next OST\n"
383 "\tpool_name: name of the predefined pool of OSTs\n"
384 "\tost_indices: OSTs to stripe over, in order\n"
385 "\tblock: wait for the operation to return before continuing\n"
386 "\tnon-block: do not wait for the operation to return.\n"},
388 "To move directories between MDTs. This command is deprecated, "
389 "use \"migrate\" instead.\n"
390 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
392 {"ladvise", lfs_ladvise, 0,
393 "Provide servers with advice about access patterns for a file.\n"
394 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
395 " [--background|-b]\n"
396 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
398 {"help", Parser_help, 0, "help"},
399 {"exit", Parser_quit, 0, "quit"},
400 {"quit", Parser_quit, 0, "quit"},
401 {"--version", Parser_version, 0,
402 "output build version of the utility and exit"},
407 #define MIGRATION_NONBLOCK 1
410 * Internal helper for migrate_copy_data(). Check lease and report error if
413 * \param[in] fd File descriptor on which to check the lease.
414 * \param[out] lease_broken Set to true if the lease was broken.
415 * \param[in] group_locked Whether a group lock was taken or not.
416 * \param[in] path Name of the file being processed, for error
419 * \retval 0 Migration can keep on going.
420 * \retval -errno Error occurred, abort migration.
422 static int check_lease(int fd, bool *lease_broken, bool group_locked,
427 if (!file_lease_supported)
430 rc = llapi_lease_check(fd);
432 return 0; /* llapi_check_lease returns > 0 on success. */
435 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
437 rc = rc ? rc : -EAGAIN;
439 fprintf(stderr, "%s: external attempt to access file '%s' "
440 "blocked until migration ends.\n", progname, path);
443 *lease_broken = true;
447 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
448 bool group_locked, const char *fname)
457 bool lease_broken = false;
459 /* Use a page-aligned buffer for direct I/O */
460 rc = posix_memalign(&buf, getpagesize(), buf_size);
465 /* read new data only if we have written all
466 * previously read data */
469 rc = check_lease(fd_src, &lease_broken,
470 group_locked, fname);
474 rsize = read(fd_src, buf, buf_size);
477 fprintf(stderr, "%s: %s: read failed: %s\n",
478 progname, fname, strerror(-rc));
488 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
492 "%s: %s: write failed on volatile: %s\n",
493 progname, fname, strerror(-rc));
503 fprintf(stderr, "%s: %s: fsync failed: %s\n",
504 progname, fname, strerror(-rc));
512 static int migrate_copy_timestamps(int fdv, const struct stat *st)
514 struct timeval tv[2] = {
515 {.tv_sec = st->st_atime},
516 {.tv_sec = st->st_mtime}
519 return futimes(fdv, tv);
522 static int migrate_block(int fd, int fdv, const struct stat *st,
523 size_t buf_size, const char *name)
530 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
532 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
533 progname, name, strerror(-rc));
541 /* The grouplock blocks all concurrent accesses to the file.
542 * It has to be taken after llapi_get_data_version as it would
544 rc = llapi_group_lock(fd, gid);
546 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
547 progname, name, strerror(-rc));
551 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
553 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
557 /* Make sure we keep original atime/mtime values */
558 rc = migrate_copy_timestamps(fdv, st);
560 fprintf(stderr, "%s: %s: timestamp copy failed\n",
566 * for a migration we need to check data version on file did
569 * Pass in gid=0 since we already own grouplock. */
570 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
571 SWAP_LAYOUTS_CHECK_DV1);
573 fprintf(stderr, "%s: %s: dataversion changed during copy, "
574 "migration aborted\n", progname, name);
577 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
578 name, strerror(-rc));
583 rc2 = llapi_group_unlock(fd, gid);
584 if (rc2 < 0 && rc == 0) {
585 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
586 progname, name, strerror(-rc2));
593 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
594 size_t buf_size, const char *name)
600 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
602 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
603 progname, name, strerror(-rc));
607 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
609 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
613 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
615 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
616 progname, name, strerror(-rc));
622 fprintf(stderr, "%s: %s: data version changed during "
628 /* Make sure we keep original atime/mtime values */
629 rc = migrate_copy_timestamps(fdv, st);
631 fprintf(stderr, "%s: %s: timestamp copy failed\n",
636 /* Atomically put lease, swap layouts and close.
637 * for a migration we need to check data version on file did
639 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
641 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
642 progname, name, strerror(-rc));
649 static int lfs_migrate(char *name, __u64 migration_flags,
650 struct llapi_stripe_param *param)
654 char parent[PATH_MAX];
657 char volatile_file[sizeof(parent) +
658 LUSTRE_VOLATILE_HDR_LEN +
659 2 * sizeof(mdt_index) +
660 2 * sizeof(random_value) + 4];
663 struct lov_user_md *lum = NULL;
666 bool have_lease_rdlck = false;
670 /* find the right size for the IO and allocate the buffer */
671 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
672 lum = malloc(lum_size);
678 rc = llapi_file_get_stripe(name, lum);
679 /* failure can happen for many reasons and some may be not real errors
681 * in case of a real error, a later call will fail with better
682 * error management */
684 buf_size = 1024 * 1024;
686 buf_size = lum->lmm_stripe_size;
688 /* open file, direct io */
689 /* even if the file is only read, WR mode is nedeed to allow
690 * layout swap on fd */
691 fd = open(name, O_RDWR | O_DIRECT);
694 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
699 if (file_lease_supported) {
700 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
701 if (rc == -EOPNOTSUPP) {
702 /* Older servers do not support file lease.
703 * Disable related checks. This opens race conditions
704 * as explained in LU-4840 */
705 file_lease_supported = false;
707 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
708 progname, name, strerror(-rc));
711 have_lease_rdlck = true;
715 /* search for file directory pathname */
716 if (strlen(name) > sizeof(parent)-1) {
720 strncpy(parent, name, sizeof(parent));
721 ptr = strrchr(parent, '/');
723 if (getcwd(parent, sizeof(parent)) == NULL) {
734 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
736 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
737 progname, name, strerror(-rc));
742 random_value = random();
743 rc = snprintf(volatile_file, sizeof(volatile_file),
744 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
745 mdt_index, random_value);
746 if (rc >= sizeof(volatile_file)) {
751 /* create, open a volatile file, use caching (ie no directio) */
752 fdv = llapi_file_open_param(volatile_file,
753 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
754 S_IRUSR | S_IWUSR, param);
755 } while (fdv == -EEXIST);
759 fprintf(stderr, "%s: %s: cannot create volatile file in"
761 progname, parent, strerror(-rc));
765 /* Not-owner (root?) special case.
766 * Need to set owner/group of volatile file like original.
767 * This will allow to pass related check during layout_swap.
772 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
776 rc = fstat(fdv, &stv);
779 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
780 volatile_file, strerror(errno));
783 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
784 rc = fchown(fdv, st.st_uid, st.st_gid);
787 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
788 name, strerror(errno));
793 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
794 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
796 have_lease_rdlck = false;
797 fdv = -1; /* The volatile file is closed as we put the
798 * lease in non-blocking mode. */
801 /* Blocking mode (forced if servers do not support file lease).
802 * It is also the default mode, since we cannot distinguish
803 * between a broken lease and a server that does not support
804 * atomic swap/close (LU-6785) */
805 rc = migrate_block(fd, fdv, &st, buf_size, name);
809 if (have_lease_rdlck)
826 * Parse a string containing an OST index list into an array of integers.
828 * The input string contains a comma delimited list of individual
829 * indices and ranges, for example "1,2-4,7". Add the indices into the
830 * \a osts array and remove duplicates.
832 * \param[out] osts array to store indices in
833 * \param[in] size size of \a osts array
834 * \param[in] offset starting index in \a osts
835 * \param[in] arg string containing OST index list
837 * \retval positive number of indices in \a osts
838 * \retval -EINVAL unable to parse \a arg
840 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
844 int slots = size - offset;
852 while (!end_of_loop) {
860 ptr = strchrnul(arg, ',');
862 end_of_loop = *ptr == '\0';
865 start_index = strtol(arg, &endptr, 0);
866 if (endptr == arg) /* no data at all */
868 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
873 end_index = start_index;
874 if (*endptr == '-') {
875 end_index = strtol(endptr + 1, &endptr, 0);
878 if (end_index < start_index)
882 for (i = start_index; i <= end_index && slots > 0; i++) {
885 /* remove duplicate */
886 for (j = 0; j < offset; j++) {
890 if (j == offset) { /* no duplicate */
895 if (slots == 0 && i < end_index)
903 if (!end_of_loop && ptr != NULL)
906 return rc < 0 ? rc : nr;
910 static int lfs_setstripe(int argc, char **argv)
912 struct llapi_stripe_param *param = NULL;
913 struct find_param migrate_mdt_param = {
920 unsigned long long st_size;
921 int st_offset, st_count;
925 char *stripe_size_arg = NULL;
926 char *stripe_off_arg = NULL;
927 char *stripe_count_arg = NULL;
928 char *pool_name_arg = NULL;
929 char *mdt_idx_arg = NULL;
930 unsigned long long size_units = 1;
931 bool migrate_mode = false;
932 bool migration_block = false;
933 __u64 migration_flags = 0;
934 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
937 struct option long_opts[] = {
938 /* --block is only valid in migrate mode */
939 {"block", no_argument, 0, 'b'},
940 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
941 /* This formerly implied "stripe-count", but was explicitly
942 * made "stripe-count" for consistency with other options,
943 * and to separate it from "mdt-count" when DNE arrives. */
944 {"count", required_argument, 0, 'c'},
946 {"stripe-count", required_argument, 0, 'c'},
947 {"stripe_count", required_argument, 0, 'c'},
948 {"delete", no_argument, 0, 'd'},
949 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
950 /* This formerly implied "stripe-index", but was explicitly
951 * made "stripe-index" for consistency with other options,
952 * and to separate it from "mdt-index" when DNE arrives. */
953 {"index", required_argument, 0, 'i'},
955 {"stripe-index", required_argument, 0, 'i'},
956 {"stripe_index", required_argument, 0, 'i'},
957 {"mdt-index", required_argument, 0, 'm'},
958 {"mdt_index", required_argument, 0, 'm'},
959 /* --non-block is only valid in migrate mode */
960 {"non-block", no_argument, 0, 'n'},
961 {"ost-list", required_argument, 0, 'o'},
962 {"ost_list", required_argument, 0, 'o'},
963 {"pool", required_argument, 0, 'p'},
964 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
965 /* This formerly implied "--stripe-size", but was confusing
966 * with "lfs find --size|-s", which means "file size", so use
967 * the consistent "--stripe-size|-S" for all commands. */
968 {"size", required_argument, 0, 's'},
970 {"stripe-size", required_argument, 0, 'S'},
971 {"stripe_size", required_argument, 0, 'S'},
972 /* --verbose is only valid in migrate mode */
973 {"verbose", no_argument, 0, 'v'},
981 if (strcmp(argv[0], "migrate") == 0)
984 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
985 long_opts, NULL)) >= 0) {
992 fprintf(stderr, "--block is valid only for"
996 migration_block = true;
999 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1000 if (strcmp(argv[optind - 1], "--count") == 0)
1001 fprintf(stderr, "warning: '--count' deprecated"
1002 ", use '--stripe-count' instead\n");
1004 stripe_count_arg = optarg;
1007 /* delete the default striping pattern */
1011 nr_osts = parse_targets(osts,
1012 sizeof(osts) / sizeof(__u32),
1016 "error: %s: bad OST indices '%s'\n",
1021 if (st_offset == -1) /* first in the command line */
1022 st_offset = osts[0];
1025 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1026 if (strcmp(argv[optind - 1], "--index") == 0)
1027 fprintf(stderr, "warning: '--index' deprecated"
1028 ", use '--stripe-index' instead\n");
1030 stripe_off_arg = optarg;
1033 if (!migrate_mode) {
1034 fprintf(stderr, "--mdt-index is valid only for"
1038 mdt_idx_arg = optarg;
1041 if (!migrate_mode) {
1042 fprintf(stderr, "--non-block is valid only for"
1046 migration_flags |= MIGRATION_NONBLOCK;
1048 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1050 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1051 fprintf(stderr, "warning: '--size|-s' deprecated, "
1052 "use '--stripe-size|-S' instead\n");
1054 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1056 stripe_size_arg = optarg;
1059 pool_name_arg = optarg;
1062 if (!migrate_mode) {
1063 fprintf(stderr, "--verbose is valid only for"
1067 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1074 fname = argv[optind];
1077 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1078 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1079 fprintf(stderr, "error: %s: cannot specify -d with "
1080 "-s, -c, -o, or -p options\n",
1085 if (optind == argc) {
1086 fprintf(stderr, "error: %s: missing filename|dirname\n",
1091 if (mdt_idx_arg != NULL && optind > 3) {
1092 fprintf(stderr, "error: %s: cannot specify -m with other "
1093 "options\n", argv[0]);
1097 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1099 "error: %s: cannot specify --non-block and --block\n",
1104 if (pool_name_arg != NULL) {
1108 ptr = strchr(pool_name_arg, '.');
1110 ptr = pool_name_arg;
1112 if ((ptr - pool_name_arg) == 0) {
1113 fprintf(stderr, "error: %s: fsname is empty "
1114 "in pool name '%s'\n",
1115 argv[0], pool_name_arg);
1122 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1124 fprintf(stderr, "error: %s: poolname '%s' is "
1126 argv[0], pool_name_arg);
1128 } else if (rc == -2) {
1129 fprintf(stderr, "error: %s: pool name '%s' is too long "
1130 "(max is %d characters)\n",
1131 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1133 } else if (rc > 0) {
1134 fprintf(stderr, "error: %s: char '%c' not allowed in "
1136 argv[0], rc, pool_name_arg);
1141 /* get the stripe size */
1142 if (stripe_size_arg != NULL) {
1143 result = llapi_parse_size(stripe_size_arg, &st_size,
1146 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1147 argv[0], stripe_size_arg);
1151 /* get the stripe offset */
1152 if (stripe_off_arg != NULL) {
1153 st_offset = strtol(stripe_off_arg, &end, 0);
1155 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1156 argv[0], stripe_off_arg);
1160 /* get the stripe count */
1161 if (stripe_count_arg != NULL) {
1162 st_count = strtoul(stripe_count_arg, &end, 0);
1164 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1165 argv[0], stripe_count_arg);
1170 if (mdt_idx_arg != NULL) {
1171 /* initialize migrate mdt parameters */
1172 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1174 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1175 argv[0], mdt_idx_arg);
1178 migrate_mdt_param.fp_migrate = 1;
1180 /* initialize stripe parameters */
1181 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1182 if (param == NULL) {
1183 fprintf(stderr, "error: %s: run out of memory\n",
1188 param->lsp_stripe_size = st_size;
1189 param->lsp_stripe_offset = st_offset;
1190 param->lsp_stripe_count = st_count;
1191 param->lsp_stripe_pattern = 0;
1192 param->lsp_pool = pool_name_arg;
1193 param->lsp_is_specific = false;
1195 if (st_count > 0 && nr_osts != st_count) {
1196 fprintf(stderr, "error: %s: stripe count '%d' "
1197 "doesn't match the number of OSTs: %d\n"
1198 , argv[0], st_count, nr_osts);
1203 param->lsp_is_specific = true;
1204 param->lsp_stripe_count = nr_osts;
1205 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1209 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1210 if (!migrate_mode) {
1211 result = llapi_file_open_param(fname,
1218 } else if (mdt_idx_arg != NULL) {
1219 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1221 result = lfs_migrate(fname, migration_flags, param);
1224 /* Save the first error encountered. */
1227 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1228 argv[0], migrate_mode ? "migrate" : "create",
1230 pool_name_arg != NULL && result == EINVAL ?
1231 "OST not in pool?" : strerror(errno));
1240 static int lfs_poollist(int argc, char **argv)
1245 return llapi_poollist(argv[1]);
1248 static int set_time(time_t *time, time_t *set, char *str)
1255 else if (str[0] == '-')
1261 t = strtol(str, NULL, 0);
1262 if (*time < t * 24 * 60 * 60) {
1265 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1269 *set = *time - t * 24 * 60 * 60;
1276 static int name2id(unsigned int *id, char *name, int type)
1279 struct passwd *entry;
1281 if (!(entry = getpwnam(name))) {
1287 *id = entry->pw_uid;
1289 struct group *entry;
1291 if (!(entry = getgrnam(name))) {
1297 *id = entry->gr_gid;
1303 static int id2name(char **name, unsigned int id, int type)
1306 struct passwd *entry;
1308 if (!(entry = getpwuid(id))) {
1314 *name = entry->pw_name;
1316 struct group *entry;
1318 if (!(entry = getgrgid(id))) {
1324 *name = entry->gr_name;
1330 static int name2layout(__u32 *layout, char *name)
1335 for (ptr = name; ; ptr = NULL) {
1336 lyt = strtok(ptr, ",");
1339 if (strcmp(lyt, "released") == 0)
1340 *layout |= LOV_PATTERN_F_RELEASED;
1341 else if (strcmp(lyt, "raid0") == 0)
1342 *layout |= LOV_PATTERN_RAID0;
1349 #define FIND_POOL_OPT 3
1350 static int lfs_find(int argc, char **argv)
1355 struct find_param param = {
1359 struct option long_opts[] = {
1360 {"atime", required_argument, 0, 'A'},
1361 {"stripe-count", required_argument, 0, 'c'},
1362 {"stripe_count", required_argument, 0, 'c'},
1363 {"ctime", required_argument, 0, 'C'},
1364 {"maxdepth", required_argument, 0, 'D'},
1365 {"gid", required_argument, 0, 'g'},
1366 {"group", required_argument, 0, 'G'},
1367 {"stripe-index", required_argument, 0, 'i'},
1368 {"stripe_index", required_argument, 0, 'i'},
1369 {"layout", required_argument, 0, 'L'},
1370 {"mdt", required_argument, 0, 'm'},
1371 {"mtime", required_argument, 0, 'M'},
1372 {"name", required_argument, 0, 'n'},
1373 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1374 {"obd", required_argument, 0, 'O'},
1375 {"ost", required_argument, 0, 'O'},
1376 /* no short option for pool, p/P already used */
1377 {"pool", required_argument, 0, FIND_POOL_OPT},
1378 {"print0", no_argument, 0, 'p'},
1379 {"print", no_argument, 0, 'P'},
1380 {"size", required_argument, 0, 's'},
1381 {"stripe-size", required_argument, 0, 'S'},
1382 {"stripe_size", required_argument, 0, 'S'},
1383 {"type", required_argument, 0, 't'},
1384 {"uid", required_argument, 0, 'u'},
1385 {"user", required_argument, 0, 'U'},
1398 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1399 while ((c = getopt_long_only(argc, argv,
1400 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1401 long_opts, NULL)) >= 0) {
1406 /* '!' is part of option */
1407 /* when getopt_long_only() finds a string which is not
1408 * an option nor a known option argument it returns 1
1409 * in that case if we already have found pathstart and pathend
1410 * (i.e. we have the list of pathnames),
1411 * the only supported value is "!"
1413 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1414 if (!isoption && pathend != -1) {
1415 fprintf(stderr, "err: %s: filename|dirname must either "
1416 "precede options or follow options\n",
1421 if (!isoption && pathstart == -1)
1422 pathstart = optind - 1;
1423 if (isoption && pathstart != -1 && pathend == -1)
1424 pathend = optind - 2;
1430 /* unknown; opt is "!" or path component,
1431 * checking done above.
1433 if (strcmp(optarg, "!") == 0)
1437 xtime = ¶m.fp_atime;
1438 xsign = ¶m.fp_asign;
1439 param.fp_exclude_atime = !!neg_opt;
1440 /* no break, this falls through to 'C' for ctime */
1443 xtime = ¶m.fp_ctime;
1444 xsign = ¶m.fp_csign;
1445 param.fp_exclude_ctime = !!neg_opt;
1447 /* no break, this falls through to 'M' for mtime */
1450 xtime = ¶m.fp_mtime;
1451 xsign = ¶m.fp_msign;
1452 param.fp_exclude_mtime = !!neg_opt;
1454 rc = set_time(&t, xtime, optarg);
1455 if (rc == INT_MAX) {
1463 if (optarg[0] == '+') {
1464 param.fp_stripe_count_sign = -1;
1466 } else if (optarg[0] == '-') {
1467 param.fp_stripe_count_sign = 1;
1471 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1472 if (*endptr != '\0') {
1473 fprintf(stderr,"error: bad stripe_count '%s'\n",
1478 param.fp_check_stripe_count = 1;
1479 param.fp_exclude_stripe_count = !!neg_opt;
1482 param.fp_max_depth = strtol(optarg, 0, 0);
1486 rc = name2id(¶m.fp_gid, optarg, GROUP);
1488 param.fp_gid = strtoul(optarg, &endptr, 10);
1489 if (*endptr != '\0') {
1490 fprintf(stderr, "Group/GID: %s cannot "
1491 "be found.\n", optarg);
1496 param.fp_exclude_gid = !!neg_opt;
1497 param.fp_check_gid = 1;
1500 ret = name2layout(¶m.fp_layout, optarg);
1503 param.fp_exclude_layout = !!neg_opt;
1504 param.fp_check_layout = 1;
1508 rc = name2id(¶m.fp_uid, optarg, USER);
1510 param.fp_uid = strtoul(optarg, &endptr, 10);
1511 if (*endptr != '\0') {
1512 fprintf(stderr, "User/UID: %s cannot "
1513 "be found.\n", optarg);
1518 param.fp_exclude_uid = !!neg_opt;
1519 param.fp_check_uid = 1;
1522 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1524 "Pool name %s is too long"
1525 " (max is %d)\n", optarg,
1530 /* we do check for empty pool because empty pool
1531 * is used to find V1 lov attributes */
1532 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1533 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1534 param.fp_exclude_pool = !!neg_opt;
1535 param.fp_check_pool = 1;
1538 param.fp_pattern = (char *)optarg;
1539 param.fp_exclude_pattern = !!neg_opt;
1544 char *buf, *token, *next, *p;
1548 buf = strdup(optarg);
1554 param.fp_exclude_obd = !!neg_opt;
1557 while (token && *token) {
1558 token = strchr(token, ',');
1565 param.fp_exclude_mdt = !!neg_opt;
1566 param.fp_num_alloc_mdts += len;
1567 tmp = realloc(param.fp_mdt_uuid,
1568 param.fp_num_alloc_mdts *
1569 sizeof(*param.fp_mdt_uuid));
1575 param.fp_mdt_uuid = tmp;
1577 param.fp_exclude_obd = !!neg_opt;
1578 param.fp_num_alloc_obds += len;
1579 tmp = realloc(param.fp_obd_uuid,
1580 param.fp_num_alloc_obds *
1581 sizeof(*param.fp_obd_uuid));
1587 param.fp_obd_uuid = tmp;
1589 for (token = buf; token && *token; token = next) {
1590 struct obd_uuid *puuid;
1593 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1596 ¶m.fp_obd_uuid[param.fp_num_obds++];
1598 p = strchr(token, ',');
1605 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1610 strncpy(puuid->uuid, token,
1611 sizeof(puuid->uuid));
1619 param.fp_zero_end = 1;
1624 if (optarg[0] == '+') {
1625 param.fp_size_sign = -1;
1627 } else if (optarg[0] == '-') {
1628 param.fp_size_sign = 1;
1632 ret = llapi_parse_size(optarg, ¶m.fp_size,
1633 ¶m.fp_size_units, 0);
1635 fprintf(stderr, "error: bad file size '%s'\n",
1639 param.fp_check_size = 1;
1640 param.fp_exclude_size = !!neg_opt;
1643 if (optarg[0] == '+') {
1644 param.fp_stripe_size_sign = -1;
1646 } else if (optarg[0] == '-') {
1647 param.fp_stripe_size_sign = 1;
1651 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1652 ¶m.fp_stripe_size_units, 0);
1654 fprintf(stderr, "error: bad stripe_size '%s'\n",
1658 param.fp_check_stripe_size = 1;
1659 param.fp_exclude_stripe_size = !!neg_opt;
1662 param.fp_exclude_type = !!neg_opt;
1663 switch (optarg[0]) {
1665 param.fp_type = S_IFBLK;
1668 param.fp_type = S_IFCHR;
1671 param.fp_type = S_IFDIR;
1674 param.fp_type = S_IFREG;
1677 param.fp_type = S_IFLNK;
1680 param.fp_type = S_IFIFO;
1683 param.fp_type = S_IFSOCK;
1686 fprintf(stderr, "error: %s: bad type '%s'\n",
1698 if (pathstart == -1) {
1699 fprintf(stderr, "error: %s: no filename|pathname\n",
1703 } else if (pathend == -1) {
1709 rc = llapi_find(argv[pathstart], ¶m);
1710 if (rc != 0 && ret == 0)
1712 } while (++pathstart < pathend);
1715 fprintf(stderr, "error: %s failed for %s.\n",
1716 argv[0], argv[optind - 1]);
1718 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1719 free(param.fp_obd_uuid);
1721 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1722 free(param.fp_mdt_uuid);
1727 static int lfs_getstripe_internal(int argc, char **argv,
1728 struct find_param *param)
1730 struct option long_opts[] = {
1731 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1732 /* This formerly implied "stripe-count", but was explicitly
1733 * made "stripe-count" for consistency with other options,
1734 * and to separate it from "mdt-count" when DNE arrives. */
1735 {"count", no_argument, 0, 'c'},
1737 {"stripe-count", no_argument, 0, 'c'},
1738 {"stripe_count", no_argument, 0, 'c'},
1739 {"directory", no_argument, 0, 'd'},
1740 {"default", no_argument, 0, 'D'},
1741 {"fid", no_argument, 0, 'F'},
1742 {"generation", no_argument, 0, 'g'},
1743 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1744 /* This formerly implied "stripe-index", but was explicitly
1745 * made "stripe-index" for consistency with other options,
1746 * and to separate it from "mdt-index" when DNE arrives. */
1747 {"index", no_argument, 0, 'i'},
1749 {"stripe-index", no_argument, 0, 'i'},
1750 {"stripe_index", no_argument, 0, 'i'},
1751 {"layout", no_argument, 0, 'L'},
1752 {"mdt-index", no_argument, 0, 'M'},
1753 {"mdt_index", no_argument, 0, 'M'},
1754 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1755 /* This formerly implied "stripe-index", but was confusing
1756 * with "file offset" (which will eventually be needed for
1757 * with different layouts by offset), so deprecate it. */
1758 {"offset", no_argument, 0, 'o'},
1760 {"obd", required_argument, 0, 'O'},
1761 {"ost", required_argument, 0, 'O'},
1762 {"pool", no_argument, 0, 'p'},
1763 {"quiet", no_argument, 0, 'q'},
1764 {"recursive", no_argument, 0, 'r'},
1765 {"raw", no_argument, 0, 'R'},
1766 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1767 /* This formerly implied "--stripe-size", but was confusing
1768 * with "lfs find --size|-s", which means "file size", so use
1769 * the consistent "--stripe-size|-S" for all commands. */
1770 {"size", no_argument, 0, 's'},
1772 {"stripe-size", no_argument, 0, 'S'},
1773 {"stripe_size", no_argument, 0, 'S'},
1774 {"verbose", no_argument, 0, 'v'},
1779 while ((c = getopt_long(argc, argv, "cdDFghiLMoO:pqrRsSv",
1780 long_opts, NULL)) != -1) {
1783 if (param->fp_obd_uuid) {
1785 "error: %s: only one obduuid allowed",
1789 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1795 param->fp_max_depth = 0;
1798 param->fp_get_default_lmv = 1;
1801 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1802 param->fp_verbose |= VERBOSE_DFID;
1803 param->fp_max_depth = 0;
1807 param->fp_recursive = 1;
1810 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
1813 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1814 if (strcmp(argv[optind - 1], "--count") == 0)
1815 fprintf(stderr, "warning: '--count' deprecated,"
1816 " use '--stripe-count' instead\n");
1818 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1819 param->fp_verbose |= VERBOSE_COUNT;
1820 param->fp_max_depth = 0;
1823 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1825 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1826 fprintf(stderr, "warning: '--size|-s' deprecated, "
1827 "use '--stripe-size|-S' instead\n");
1829 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1831 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1832 param->fp_verbose |= VERBOSE_SIZE;
1833 param->fp_max_depth = 0;
1836 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1838 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1839 "use '--stripe-index|-i' instead\n");
1842 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1843 if (strcmp(argv[optind - 1], "--index") == 0)
1844 fprintf(stderr, "warning: '--index' deprecated"
1845 ", use '--stripe-index' instead\n");
1847 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1848 param->fp_verbose |= VERBOSE_OFFSET;
1849 param->fp_max_depth = 0;
1853 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1854 param->fp_verbose |= VERBOSE_POOL;
1855 param->fp_max_depth = 0;
1859 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1860 param->fp_verbose |= VERBOSE_GENERATION;
1861 param->fp_max_depth = 0;
1865 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1866 param->fp_verbose |= VERBOSE_LAYOUT;
1867 param->fp_max_depth = 0;
1871 if (!(param->fp_verbose & VERBOSE_DETAIL))
1872 param->fp_max_depth = 0;
1873 param->fp_verbose |= VERBOSE_MDTINDEX;
1886 if (param->fp_recursive)
1887 param->fp_max_depth = -1;
1889 if (!param->fp_verbose)
1890 param->fp_verbose = VERBOSE_DEFAULT;
1891 if (param->fp_quiet)
1892 param->fp_verbose = VERBOSE_OBJID;
1895 rc = llapi_getstripe(argv[optind], param);
1896 } while (++optind < argc && !rc);
1899 fprintf(stderr, "error: %s failed for %s.\n",
1900 argv[0], argv[optind - 1]);
1904 static int lfs_tgts(int argc, char **argv)
1906 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1907 struct find_param param;
1908 int index = 0, rc=0;
1913 if (argc == 2 && !realpath(argv[1], path)) {
1915 fprintf(stderr, "error: invalid path '%s': %s\n",
1916 argv[1], strerror(-rc));
1920 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1921 /* Check if we have a mount point */
1922 if (mntdir[0] == '\0')
1925 memset(¶m, 0, sizeof(param));
1926 if (!strcmp(argv[0], "mdts"))
1927 param.fp_get_lmv = 1;
1929 rc = llapi_ostlist(mntdir, ¶m);
1931 fprintf(stderr, "error: %s: failed on %s\n",
1934 if (path[0] != '\0')
1936 memset(mntdir, 0, PATH_MAX);
1942 static int lfs_getstripe(int argc, char **argv)
1944 struct find_param param = { 0 };
1946 param.fp_max_depth = 1;
1947 return lfs_getstripe_internal(argc, argv, ¶m);
1951 static int lfs_getdirstripe(int argc, char **argv)
1953 struct find_param param = { 0 };
1955 param.fp_get_lmv = 1;
1956 return lfs_getstripe_internal(argc, argv, ¶m);
1960 static int lfs_setdirstripe(int argc, char **argv)
1964 unsigned int stripe_offset = -1;
1965 unsigned int stripe_count = 1;
1966 enum lmv_hash_type hash_type;
1969 char *stripe_offset_opt = NULL;
1970 char *stripe_count_opt = NULL;
1971 char *stripe_hash_opt = NULL;
1972 char *mode_opt = NULL;
1973 bool default_stripe = false;
1974 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1975 mode_t previous_mode = 0;
1976 bool delete = false;
1978 struct option long_opts[] = {
1979 {"count", required_argument, 0, 'c'},
1980 {"delete", no_argument, 0, 'd'},
1981 {"index", required_argument, 0, 'i'},
1982 {"mode", required_argument, 0, 'm'},
1983 {"hash-type", required_argument, 0, 't'},
1984 {"default_stripe", no_argument, 0, 'D'},
1988 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1995 stripe_count_opt = optarg;
1999 default_stripe = true;
2002 default_stripe = true;
2005 stripe_offset_opt = optarg;
2011 stripe_hash_opt = optarg;
2014 fprintf(stderr, "error: %s: option '%s' "
2016 argv[0], argv[optind - 1]);
2021 if (optind == argc) {
2022 fprintf(stderr, "error: %s: missing dirname\n",
2027 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2028 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2033 if (stripe_offset_opt != NULL) {
2034 /* get the stripe offset */
2035 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2037 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2038 argv[0], stripe_offset_opt);
2044 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2045 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2046 " or -i options.\n", argv[0]);
2054 if (mode_opt != NULL) {
2055 mode = strtoul(mode_opt, &end, 8);
2057 fprintf(stderr, "error: %s: bad mode '%s'\n",
2061 previous_mode = umask(0);
2064 if (stripe_hash_opt == NULL ||
2065 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2066 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2067 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2068 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2070 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2071 argv[0], stripe_hash_opt);
2075 /* get the stripe count */
2076 if (stripe_count_opt != NULL) {
2077 stripe_count = strtoul(stripe_count_opt, &end, 0);
2079 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2080 argv[0], stripe_count_opt);
2085 dname = argv[optind];
2087 if (default_stripe) {
2088 result = llapi_dir_set_default_lmv_stripe(dname,
2089 stripe_offset, stripe_count,
2092 result = llapi_dir_create_pool(dname, mode,
2094 stripe_count, hash_type,
2099 fprintf(stderr, "error: %s: create stripe dir '%s' "
2100 "failed\n", argv[0], dname);
2103 dname = argv[++optind];
2104 } while (dname != NULL);
2106 if (mode_opt != NULL)
2107 umask(previous_mode);
2113 static int lfs_rmentry(int argc, char **argv)
2120 fprintf(stderr, "error: %s: missing dirname\n",
2126 dname = argv[index];
2127 while (dname != NULL) {
2128 result = llapi_direntry_remove(dname);
2130 fprintf(stderr, "error: %s: remove dir entry '%s' "
2131 "failed\n", argv[0], dname);
2134 dname = argv[++index];
2139 static int lfs_mv(int argc, char **argv)
2141 struct find_param param = {
2148 struct option long_opts[] = {
2149 {"mdt-index", required_argument, 0, 'M'},
2150 {"verbose", no_argument, 0, 'v'},
2154 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2157 param.fp_mdt_index = strtoul(optarg, &end, 0);
2159 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2166 param.fp_verbose = VERBOSE_DETAIL;
2170 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2171 argv[0], argv[optind - 1]);
2176 if (param.fp_mdt_index == -1) {
2177 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2181 if (optind >= argc) {
2182 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2186 param.fp_migrate = 1;
2187 rc = llapi_migrate_mdt(argv[optind], ¶m);
2189 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2190 argv[0], argv[optind], param.fp_mdt_index,
2195 static int lfs_osts(int argc, char **argv)
2197 return lfs_tgts(argc, argv);
2200 static int lfs_mdts(int argc, char **argv)
2202 return lfs_tgts(argc, argv);
2205 #define COOK(value) \
2208 while (value > 1024) { \
2216 #define CDF "%11llu"
2217 #define HDF "%8.1f%c"
2221 static int showdf(char *mntdir, struct obd_statfs *stat,
2222 char *uuid, int ishow, int cooked,
2223 char *type, int index, int rc)
2225 long long avail, used, total;
2227 char *suffix = "KMGTPEZY";
2228 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2229 char tbuf[3 * sizeof(__u64)];
2230 char ubuf[3 * sizeof(__u64)];
2231 char abuf[3 * sizeof(__u64)];
2232 char rbuf[3 * sizeof(__u64)];
2240 avail = stat->os_ffree;
2241 used = stat->os_files - stat->os_ffree;
2242 total = stat->os_files;
2244 int shift = cooked ? 0 : 10;
2246 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2247 used = ((stat->os_blocks - stat->os_bfree) *
2248 stat->os_bsize) >> shift;
2249 total = (stat->os_blocks * stat->os_bsize) >> shift;
2252 if ((used + avail) > 0)
2253 ratio = (double)used / (double)(used + avail);
2259 cook_val = (double)total;
2262 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2264 sprintf(tbuf, CDF, total);
2266 cook_val = (double)used;
2269 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2271 sprintf(ubuf, CDF, used);
2273 cook_val = (double)avail;
2276 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2278 sprintf(abuf, CDF, avail);
2280 sprintf(tbuf, CDF, total);
2281 sprintf(ubuf, CDF, used);
2282 sprintf(abuf, CDF, avail);
2285 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2286 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2287 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2289 printf("[%s:%d]\n", type, index);
2295 printf(UUF": inactive device\n", uuid);
2298 printf(UUF": %s\n", uuid, strerror(-rc));
2305 struct ll_stat_type {
2310 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2311 int cooked, int lazy)
2313 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2314 struct obd_uuid uuid_buf;
2315 char *poolname = NULL;
2316 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2317 { LL_STATFS_LOV, "OST" },
2319 struct ll_stat_type *tp;
2320 __u64 ost_ffree = 0;
2326 poolname = strchr(pool, '.');
2327 if (poolname != NULL) {
2328 if (strncmp(fsname, pool, strlen(fsname))) {
2329 fprintf(stderr, "filesystem name incorrect\n");
2338 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2339 "UUID", "Inodes", "IUsed", "IFree",
2340 "IUse%", "Mounted on");
2342 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2343 "UUID", cooked ? "bytes" : "1K-blocks",
2344 "Used", "Available", "Use%", "Mounted on");
2346 for (tp = types; tp->st_name != NULL; tp++) {
2347 for (index = 0; ; index++) {
2348 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2349 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2350 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2351 rc = llapi_obd_statfs(mntdir, type, index,
2352 &stat_buf, &uuid_buf);
2359 if (poolname && tp->st_op == LL_STATFS_LOV &&
2360 llapi_search_ost(fsname, poolname,
2361 obd_uuid2str(&uuid_buf)) != 1)
2364 /* the llapi_obd_statfs() call may have returned with
2365 * an error, but if it filled in uuid_buf we will at
2366 * lease use that to print out a message for that OBD.
2367 * If we didn't get anything in the uuid_buf, then fill
2368 * it in so that we can print an error message. */
2369 if (uuid_buf.uuid[0] == '\0')
2370 sprintf(uuid_buf.uuid, "%s%04x",
2371 tp->st_name, index);
2372 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2373 ishow, cooked, tp->st_name, index, rc);
2376 if (tp->st_op == LL_STATFS_LMV) {
2377 sum.os_ffree += stat_buf.os_ffree;
2378 sum.os_files += stat_buf.os_files;
2379 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2380 sum.os_blocks += stat_buf.os_blocks *
2382 sum.os_bfree += stat_buf.os_bfree *
2384 sum.os_bavail += stat_buf.os_bavail *
2386 ost_ffree += stat_buf.os_ffree;
2388 } else if (rc == -EINVAL || rc == -EFAULT) {
2394 /* If we don't have as many objects free on the OST as inodes
2395 * on the MDS, we reduce the total number of inodes to
2396 * compensate, so that the "inodes in use" number is correct.
2397 * Matches ll_statfs_internal() so the results are consistent. */
2398 if (ost_ffree < sum.os_ffree) {
2399 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2400 sum.os_ffree = ost_ffree;
2403 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2408 static int lfs_df(int argc, char **argv)
2410 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2411 int ishow = 0, cooked = 0;
2413 int c, rc = 0, index = 0;
2414 char fsname[PATH_MAX] = "", *pool_name = NULL;
2415 struct option long_opts[] = {
2416 {"pool", required_argument, 0, 'p'},
2417 {"lazy", 0, 0, 'l'},
2421 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2439 if (optind < argc && !realpath(argv[optind], path)) {
2441 fprintf(stderr, "error: invalid path '%s': %s\n",
2442 argv[optind], strerror(-rc));
2446 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2447 /* Check if we have a mount point */
2448 if (mntdir[0] == '\0')
2451 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2452 if (rc || path[0] != '\0')
2454 fsname[0] = '\0'; /* avoid matching in next loop */
2455 mntdir[0] = '\0'; /* avoid matching in next loop */
2461 static int lfs_getname(int argc, char **argv)
2463 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2464 int rc = 0, index = 0, c;
2465 char buf[sizeof(struct obd_uuid)];
2467 while ((c = getopt(argc, argv, "h")) != -1)
2470 if (optind == argc) { /* no paths specified, get all paths. */
2471 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2472 rc = llapi_getname(mntdir, buf, sizeof(buf));
2475 "cannot get name for `%s': %s\n",
2476 mntdir, strerror(-rc));
2480 printf("%s %s\n", buf, mntdir);
2482 path[0] = fsname[0] = mntdir[0] = 0;
2484 } else { /* paths specified, only attempt to search these. */
2485 for (; optind < argc; optind++) {
2486 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2489 "cannot get name for `%s': %s\n",
2490 argv[optind], strerror(-rc));
2494 printf("%s %s\n", buf, argv[optind]);
2500 static int lfs_check(int argc, char **argv)
2503 char mntdir[PATH_MAX] = {'\0'};
2512 obd_types[0] = obd_type1;
2513 obd_types[1] = obd_type2;
2515 if (strcmp(argv[1], "osts") == 0) {
2516 strcpy(obd_types[0], "osc");
2517 } else if (strcmp(argv[1], "mds") == 0) {
2518 strcpy(obd_types[0], "mdc");
2519 } else if (strcmp(argv[1], "servers") == 0) {
2521 strcpy(obd_types[0], "osc");
2522 strcpy(obd_types[1], "mdc");
2524 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2529 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2530 if (rc < 0 || mntdir[0] == '\0') {
2531 fprintf(stderr, "No suitable Lustre mount found\n");
2535 rc = llapi_target_check(num_types, obd_types, mntdir);
2537 fprintf(stderr, "error: %s: %s status failed\n",
2544 static int lfs_join(int argc, char **argv)
2546 fprintf(stderr, "join two lustre files into one.\n"
2547 "obsolete, HEAD does not support it anymore.\n");
2551 #ifdef HAVE_SYS_QUOTA_H
2552 #define ARG2INT(nr, str, msg) \
2555 nr = strtol(str, &endp, 0); \
2557 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2562 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2564 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2565 * returns the value or ULONG_MAX on integer overflow or incorrect format
2567 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2568 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2569 * 3. empty integer value is interpreted as 0
2571 static unsigned long str2sec(const char* timestr)
2573 const char spec[] = "smhdw";
2574 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2575 unsigned long val = 0;
2578 if (strpbrk(timestr, spec) == NULL) {
2579 /* no specifiers inside the time string,
2580 should treat it as an integer value */
2581 val = strtoul(timestr, &tail, 10);
2582 return *tail ? ULONG_MAX : val;
2585 /* format string is XXwXXdXXhXXmXXs */
2591 v = strtoul(timestr, &tail, 10);
2592 if (v == ULONG_MAX || *tail == '\0')
2593 /* value too large (ULONG_MAX or more)
2594 or missing specifier */
2597 ptr = strchr(spec, *tail);
2599 /* unknown specifier */
2604 /* check if product will overflow the type */
2605 if (!(v < ULONG_MAX / mult[ind]))
2608 ADD_OVERFLOW(val, mult[ind] * v);
2609 if (val == ULONG_MAX)
2621 #define ARG2ULL(nr, str, def_units) \
2623 unsigned long long limit, units = def_units; \
2626 rc = llapi_parse_size(str, &limit, &units, 1); \
2628 fprintf(stderr, "error: bad limit value %s\n", str); \
2634 static inline int has_times_option(int argc, char **argv)
2638 for (i = 1; i < argc; i++)
2639 if (!strcmp(argv[i], "-t"))
2645 int lfs_setquota_times(int argc, char **argv)
2648 struct if_quotactl qctl;
2649 char *mnt, *obd_type = (char *)qctl.obd_type;
2650 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2651 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2652 struct option long_opts[] = {
2653 {"block-grace", required_argument, 0, 'b'},
2654 {"group", no_argument, 0, 'g'},
2655 {"inode-grace", required_argument, 0, 'i'},
2656 {"times", no_argument, 0, 't'},
2657 {"user", no_argument, 0, 'u'},
2661 memset(&qctl, 0, sizeof(qctl));
2662 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2663 qctl.qc_type = UGQUOTA;
2665 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2669 if (qctl.qc_type != UGQUOTA) {
2670 fprintf(stderr, "error: -u and -g can't be used "
2671 "more than once\n");
2674 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2677 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2678 fprintf(stderr, "error: bad block-grace: %s\n",
2682 dqb->dqb_valid |= QIF_BTIME;
2685 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2686 fprintf(stderr, "error: bad inode-grace: %s\n",
2690 dqb->dqb_valid |= QIF_ITIME;
2692 case 't': /* Yes, of course! */
2694 default: /* getopt prints error message for us when opterr != 0 */
2699 if (qctl.qc_type == UGQUOTA) {
2700 fprintf(stderr, "error: neither -u nor -g specified\n");
2704 if (optind != argc - 1) {
2705 fprintf(stderr, "error: unexpected parameters encountered\n");
2710 rc = llapi_quotactl(mnt, &qctl);
2713 fprintf(stderr, "%s %s ", obd_type,
2714 obd_uuid2str(&qctl.obd_uuid));
2715 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2722 #define BSLIMIT (1 << 0)
2723 #define BHLIMIT (1 << 1)
2724 #define ISLIMIT (1 << 2)
2725 #define IHLIMIT (1 << 3)
2727 int lfs_setquota(int argc, char **argv)
2730 struct if_quotactl qctl;
2731 char *mnt, *obd_type = (char *)qctl.obd_type;
2732 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2733 struct option long_opts[] = {
2734 {"block-softlimit", required_argument, 0, 'b'},
2735 {"block-hardlimit", required_argument, 0, 'B'},
2736 {"group", required_argument, 0, 'g'},
2737 {"inode-softlimit", required_argument, 0, 'i'},
2738 {"inode-hardlimit", required_argument, 0, 'I'},
2739 {"user", required_argument, 0, 'u'},
2742 unsigned limit_mask = 0;
2745 if (has_times_option(argc, argv))
2746 return lfs_setquota_times(argc, argv);
2748 memset(&qctl, 0, sizeof(qctl));
2749 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2750 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2751 * so it can be used as a marker that qc_type
2752 * isn't reinitialized from command line */
2754 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2758 if (qctl.qc_type != UGQUOTA) {
2759 fprintf(stderr, "error: -u and -g can't be used"
2760 " more than once\n");
2763 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2764 rc = name2id(&qctl.qc_id, optarg,
2765 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2767 qctl.qc_id = strtoul(optarg, &endptr, 10);
2768 if (*endptr != '\0') {
2769 fprintf(stderr, "error: can't find id "
2770 "for name %s\n", optarg);
2776 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2777 dqb->dqb_bsoftlimit >>= 10;
2778 limit_mask |= BSLIMIT;
2779 if (dqb->dqb_bsoftlimit &&
2780 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2781 fprintf(stderr, "warning: block softlimit is "
2782 "smaller than the miminal qunit size, "
2783 "please see the help of setquota or "
2784 "Lustre manual for details.\n");
2787 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2788 dqb->dqb_bhardlimit >>= 10;
2789 limit_mask |= BHLIMIT;
2790 if (dqb->dqb_bhardlimit &&
2791 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2792 fprintf(stderr, "warning: block hardlimit is "
2793 "smaller than the miminal qunit size, "
2794 "please see the help of setquota or "
2795 "Lustre manual for details.\n");
2798 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2799 limit_mask |= ISLIMIT;
2800 if (dqb->dqb_isoftlimit &&
2801 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2802 fprintf(stderr, "warning: inode softlimit is "
2803 "smaller than the miminal qunit size, "
2804 "please see the help of setquota or "
2805 "Lustre manual for details.\n");
2808 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2809 limit_mask |= IHLIMIT;
2810 if (dqb->dqb_ihardlimit &&
2811 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2812 fprintf(stderr, "warning: inode hardlimit is "
2813 "smaller than the miminal qunit size, "
2814 "please see the help of setquota or "
2815 "Lustre manual for details.\n");
2817 default: /* getopt prints error message for us when opterr != 0 */
2822 if (qctl.qc_type == UGQUOTA) {
2823 fprintf(stderr, "error: neither -u nor -g was specified\n");
2827 if (limit_mask == 0) {
2828 fprintf(stderr, "error: at least one limit must be specified\n");
2832 if (optind != argc - 1) {
2833 fprintf(stderr, "error: unexpected parameters encountered\n");
2839 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2840 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2841 /* sigh, we can't just set blimits/ilimits */
2842 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2843 .qc_type = qctl.qc_type,
2844 .qc_id = qctl.qc_id};
2846 rc = llapi_quotactl(mnt, &tmp_qctl);
2848 fprintf(stderr, "error: setquota failed while retrieving"
2849 " current quota settings (%s)\n",
2854 if (!(limit_mask & BHLIMIT))
2855 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2856 if (!(limit_mask & BSLIMIT))
2857 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2858 if (!(limit_mask & IHLIMIT))
2859 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2860 if (!(limit_mask & ISLIMIT))
2861 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2863 /* Keep grace times if we have got no softlimit arguments */
2864 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2865 dqb->dqb_valid |= QIF_BTIME;
2866 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2869 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2870 dqb->dqb_valid |= QIF_ITIME;
2871 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2875 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2876 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2878 rc = llapi_quotactl(mnt, &qctl);
2881 fprintf(stderr, "%s %s ", obd_type,
2882 obd_uuid2str(&qctl.obd_uuid));
2883 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2890 static inline char *type2name(int check_type)
2892 if (check_type == USRQUOTA)
2894 else if (check_type == GRPQUOTA)
2900 /* Converts seconds value into format string
2901 * result is returned in buf
2903 * 1. result is in descenting order: 1w2d3h4m5s
2904 * 2. zero fields are not filled (except for p. 3): 5d1s
2905 * 3. zero seconds value is presented as "0s"
2907 static char * __sec2str(time_t seconds, char *buf)
2909 const char spec[] = "smhdw";
2910 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2915 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2916 c = seconds / mult[i];
2918 if (c > 0 || (i == 0 && buf == tail))
2919 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2927 static void sec2str(time_t seconds, char *buf, int rc)
2934 tail = __sec2str(seconds, tail);
2936 if (rc && tail - buf < 39) {
2942 static void diff2str(time_t seconds, char *buf, time_t now)
2948 if (seconds <= now) {
2949 strcpy(buf, "none");
2952 __sec2str(seconds - now, buf);
2955 static void print_quota_title(char *name, struct if_quotactl *qctl,
2956 bool human_readable)
2958 printf("Disk quotas for %s %s (%cid %u):\n",
2959 type2name(qctl->qc_type), name,
2960 *type2name(qctl->qc_type), qctl->qc_id);
2961 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2962 "Filesystem", human_readable ? "used" : "kbytes",
2963 "quota", "limit", "grace",
2964 "files", "quota", "limit", "grace");
2967 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
2970 snprintf(buf, buflen, "%ju", (uintmax_t)num);
2973 snprintf(buf, buflen, "%5.4gP",
2974 (double)num / ((__u64)1 << 40));
2976 snprintf(buf, buflen, "%5.4gT",
2977 (double)num / (1 << 30));
2979 snprintf(buf, buflen, "%5.4gG",
2980 (double)num / (1 << 20));
2982 snprintf(buf, buflen, "%5.4gM",
2983 (double)num / (1 << 10));
2985 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
2989 #define STRBUF_LEN 32
2990 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2997 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2998 int bover = 0, iover = 0;
2999 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3000 char numbuf[3][STRBUF_LEN];
3002 char strbuf[STRBUF_LEN];
3004 if (dqb->dqb_bhardlimit &&
3005 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3007 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3008 if (dqb->dqb_btime > now) {
3015 if (dqb->dqb_ihardlimit &&
3016 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3018 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3019 if (dqb->dqb_itime > now) {
3027 if (strlen(mnt) > 15)
3028 printf("%s\n%15s", mnt, "");
3030 printf("%15s", mnt);
3033 diff2str(dqb->dqb_btime, timebuf, now);
3035 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3036 strbuf, sizeof(strbuf), h);
3037 if (rc == -EREMOTEIO)
3038 sprintf(numbuf[0], "%s*", strbuf);
3040 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3041 "%s" : "[%s]", strbuf);
3043 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3044 if (type == QC_GENERAL)
3045 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3046 "%s" : "[%s]", strbuf);
3048 sprintf(numbuf[1], "%s", "-");
3050 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3051 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3052 "%s" : "[%s]", strbuf);
3054 printf(" %7s%c %6s %7s %7s",
3055 numbuf[0], bover ? '*' : ' ', numbuf[1],
3056 numbuf[2], bover > 1 ? timebuf : "-");
3059 diff2str(dqb->dqb_itime, timebuf, now);
3061 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3062 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3064 if (type == QC_GENERAL)
3065 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3067 (uintmax_t)dqb->dqb_isoftlimit);
3069 sprintf(numbuf[1], "%s", "-");
3071 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3072 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3074 if (type != QC_OSTIDX)
3075 printf(" %7s%c %6s %7s %7s",
3076 numbuf[0], iover ? '*' : ' ', numbuf[1],
3077 numbuf[2], iover > 1 ? timebuf : "-");
3079 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3082 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3083 qctl->qc_cmd == Q_GETOINFO) {
3087 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3088 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3089 printf("Block grace time: %s; Inode grace time: %s\n",
3090 bgtimebuf, igtimebuf);
3094 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3095 bool h, __u64 *total)
3097 int rc = 0, rc1 = 0, count = 0;
3098 __u32 valid = qctl->qc_valid;
3100 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3102 fprintf(stderr, "can not get %s count: %s\n",
3103 is_mdt ? "mdt": "ost", strerror(-rc));
3107 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3108 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3109 rc = llapi_quotactl(mnt, qctl);
3111 /* It is remote client case. */
3112 if (-rc == EOPNOTSUPP) {
3119 fprintf(stderr, "quotactl %s%d failed.\n",
3120 is_mdt ? "mdt": "ost", qctl->qc_idx);
3124 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3125 qctl->qc_valid, 0, h);
3126 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3127 qctl->qc_dqblk.dqb_bhardlimit;
3130 qctl->qc_valid = valid;
3134 static int lfs_quota(int argc, char **argv)
3137 char *mnt, *name = NULL;
3138 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3139 .qc_type = UGQUOTA };
3140 char *obd_type = (char *)qctl.obd_type;
3141 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3142 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3143 verbose = 0, pass = 0, quiet = 0, inacc;
3145 __u32 valid = QC_GENERAL, idx = 0;
3146 __u64 total_ialloc = 0, total_balloc = 0;
3147 bool human_readable = false;
3149 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3152 if (qctl.qc_type != UGQUOTA) {
3153 fprintf(stderr, "error: use either -u or -g\n");
3156 qctl.qc_type = USRQUOTA;
3159 if (qctl.qc_type != UGQUOTA) {
3160 fprintf(stderr, "error: use either -u or -g\n");
3163 qctl.qc_type = GRPQUOTA;
3166 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3169 valid = qctl.qc_valid = QC_UUID;
3170 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3173 valid = qctl.qc_valid = QC_MDTIDX;
3174 idx = qctl.qc_idx = atoi(optarg);
3177 valid = qctl.qc_valid = QC_OSTIDX;
3178 idx = qctl.qc_idx = atoi(optarg);
3187 human_readable = true;
3190 fprintf(stderr, "error: %s: option '-%c' "
3191 "unrecognized\n", argv[0], c);
3196 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3197 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3198 optind == argc - 1) {
3200 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3201 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3202 qctl.qc_valid = valid;
3205 qctl.qc_type = USRQUOTA;
3206 qctl.qc_id = geteuid();
3208 qctl.qc_type = GRPQUOTA;
3209 qctl.qc_id = getegid();
3211 rc = id2name(&name, qctl.qc_id,
3212 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3215 /* lfs quota -u username /path/to/lustre/mount */
3216 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3217 /* options should be followed by u/g-name and mntpoint */
3218 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3219 fprintf(stderr, "error: missing quota argument(s)\n");
3223 name = argv[optind++];
3224 rc = name2id(&qctl.qc_id, name,
3225 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3227 qctl.qc_id = strtoul(name, &endptr, 10);
3228 if (*endptr != '\0') {
3229 fprintf(stderr, "error: can't find id for name "
3234 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3235 fprintf(stderr, "error: missing quota info argument(s)\n");
3241 rc1 = llapi_quotactl(mnt, &qctl);
3245 fprintf(stderr, "%s quotas are not enabled.\n",
3246 qctl.qc_type == USRQUOTA ? "user" : "group");
3249 fprintf(stderr, "Permission denied.\n");
3251 /* We already got a "No such file..." message. */
3254 fprintf(stderr, "Unexpected quotactl error: %s\n",
3259 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3260 print_quota_title(name, &qctl, human_readable);
3262 if (rc1 && *obd_type)
3263 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3265 if (qctl.qc_valid != QC_GENERAL)
3268 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3269 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3270 (QIF_LIMITS|QIF_USAGE));
3272 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3274 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3276 char strbuf[STRBUF_LEN];
3278 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3280 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3282 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3284 printf("Total allocated inode limit: %ju, total "
3285 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3289 if (rc1 || rc2 || rc3 || inacc)
3290 printf("Some errors happened when getting quota info. "
3291 "Some devices may be not working or deactivated. "
3292 "The data in \"[]\" is inaccurate.\n");
3300 #endif /* HAVE_SYS_QUOTA_H! */
3302 static int flushctx_ioctl(char *mp)
3306 fd = open(mp, O_RDONLY);
3308 fprintf(stderr, "flushctx: error open %s: %s\n",
3309 mp, strerror(errno));
3313 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3315 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3316 mp, strerror(errno));
3322 static int lfs_flushctx(int argc, char **argv)
3324 int kdestroy = 0, c;
3325 char mntdir[PATH_MAX] = {'\0'};
3329 while ((c = getopt(argc, argv, "k")) != -1) {
3335 fprintf(stderr, "error: %s: option '-%c' "
3336 "unrecognized\n", argv[0], c);
3342 if ((rc = system("kdestroy > /dev/null")) != 0) {
3343 rc = WEXITSTATUS(rc);
3344 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3348 if (optind >= argc) {
3349 /* flush for all mounted lustre fs. */
3350 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3351 /* Check if we have a mount point */
3352 if (mntdir[0] == '\0')
3355 if (flushctx_ioctl(mntdir))
3358 mntdir[0] = '\0'; /* avoid matching in next loop */
3361 /* flush fs as specified */
3362 while (optind < argc) {
3363 if (flushctx_ioctl(argv[optind++]))
3370 static int lfs_lsetfacl(int argc, char **argv)
3372 fprintf(stderr, "local client sets facl for remote client.\n"
3373 "obsolete, does not support it anymore.\n");
3377 static int lfs_lgetfacl(int argc, char **argv)
3379 fprintf(stderr, "local client gets facl for remote client.\n"
3380 "obsolete, does not support it anymore.\n");
3384 static int lfs_rsetfacl(int argc, char **argv)
3386 fprintf(stderr, "remote client sets facl for remote client.\n"
3387 "obsolete, does not support it anymore.\n");
3391 static int lfs_rgetfacl(int argc, char **argv)
3393 fprintf(stderr, "remote client gets facl for remote client.\n"
3394 "obsolete, does not support it anymore.\n");
3398 static int lfs_cp(int argc, char **argv)
3400 fprintf(stderr, "remote client copy file(s).\n"
3401 "obsolete, does not support it anymore.\n");
3405 static int lfs_ls(int argc, char **argv)
3407 fprintf(stderr, "remote client lists directory contents.\n"
3408 "obsolete, does not support it anymore.\n");
3412 static int lfs_changelog(int argc, char **argv)
3414 void *changelog_priv;
3415 struct changelog_rec *rec;
3416 long long startrec = 0, endrec = 0;
3418 struct option long_opts[] = {
3419 {"follow", no_argument, 0, 'f'},
3422 char short_opts[] = "f";
3425 while ((rc = getopt_long(argc, argv, short_opts,
3426 long_opts, NULL)) != -1) {
3434 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3435 argv[0], argv[optind - 1]);
3442 mdd = argv[optind++];
3444 startrec = strtoll(argv[optind++], NULL, 10);
3446 endrec = strtoll(argv[optind++], NULL, 10);
3448 rc = llapi_changelog_start(&changelog_priv,
3449 CHANGELOG_FLAG_BLOCK |
3450 CHANGELOG_FLAG_JOBID |
3451 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3454 fprintf(stderr, "Can't start changelog: %s\n",
3455 strerror(errno = -rc));
3459 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3463 if (endrec && rec->cr_index > endrec) {
3464 llapi_changelog_free(&rec);
3467 if (rec->cr_index < startrec) {
3468 llapi_changelog_free(&rec);
3472 secs = rec->cr_time >> 30;
3473 gmtime_r(&secs, &ts);
3474 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3475 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3476 changelog_type2str(rec->cr_type),
3477 ts.tm_hour, ts.tm_min, ts.tm_sec,
3478 (int)(rec->cr_time & ((1<<30) - 1)),
3479 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3480 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3482 if (rec->cr_flags & CLF_JOBID) {
3483 struct changelog_ext_jobid *jid =
3484 changelog_rec_jobid(rec);
3486 if (jid->cr_jobid[0] != '\0')
3487 printf(" j=%s", jid->cr_jobid);
3490 if (rec->cr_namelen)
3491 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3492 rec->cr_namelen, changelog_rec_name(rec));
3494 if (rec->cr_flags & CLF_RENAME) {
3495 struct changelog_ext_rename *rnm =
3496 changelog_rec_rename(rec);
3498 if (!fid_is_zero(&rnm->cr_sfid))
3499 printf(" s="DFID" sp="DFID" %.*s",
3500 PFID(&rnm->cr_sfid),
3501 PFID(&rnm->cr_spfid),
3502 (int)changelog_rec_snamelen(rec),
3503 changelog_rec_sname(rec));
3507 llapi_changelog_free(&rec);
3510 llapi_changelog_fini(&changelog_priv);
3513 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3515 return (rc == 1 ? 0 : rc);
3518 static int lfs_changelog_clear(int argc, char **argv)
3526 endrec = strtoll(argv[3], NULL, 10);
3528 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3530 fprintf(stderr, "%s error: %s\n", argv[0],
3531 strerror(errno = -rc));
3535 static int lfs_fid2path(int argc, char **argv)
3537 struct option long_opts[] = {
3538 {"cur", no_argument, 0, 'c'},
3539 {"link", required_argument, 0, 'l'},
3540 {"rec", required_argument, 0, 'r'},
3543 char short_opts[] = "cl:r:";
3544 char *device, *fid, *path;
3545 long long recno = -1;
3551 while ((rc = getopt_long(argc, argv, short_opts,
3552 long_opts, NULL)) != -1) {
3558 linkno = strtol(optarg, NULL, 10);
3561 recno = strtoll(optarg, NULL, 10);
3566 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3567 argv[0], argv[optind - 1]);
3575 device = argv[optind++];
3576 path = calloc(1, PATH_MAX);
3578 fprintf(stderr, "error: Not enough memory\n");
3583 while (optind < argc) {
3584 fid = argv[optind++];
3586 lnktmp = (linkno >= 0) ? linkno : 0;
3588 int oldtmp = lnktmp;
3589 long long rectmp = recno;
3591 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3594 fprintf(stderr, "%s: error on FID %s: %s\n",
3595 argv[0], fid, strerror(errno = -rc2));
3602 fprintf(stdout, "%lld ", rectmp);
3603 if (device[0] == '/') {
3604 fprintf(stdout, "%s", device);
3605 if (device[strlen(device) - 1] != '/')
3606 fprintf(stdout, "/");
3607 } else if (path[0] == '\0') {
3608 fprintf(stdout, "/");
3610 fprintf(stdout, "%s\n", path);
3613 /* specified linkno */
3615 if (oldtmp == lnktmp)
3625 static int lfs_path2fid(int argc, char **argv)
3627 struct option long_opts[] = {
3628 {"parents", no_argument, 0, 'p'},
3632 const char short_opts[] = "p";
3633 const char *sep = "";
3636 bool show_parents = false;
3638 while ((rc = getopt_long(argc, argv, short_opts,
3639 long_opts, NULL)) != -1) {
3642 show_parents = true;
3645 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3646 argv[0], argv[optind - 1]);
3651 if (optind > argc - 1)
3653 else if (optind < argc - 1)
3657 for (path = argv + optind; *path != NULL; path++) {
3659 if (!show_parents) {
3660 err = llapi_path2fid(*path, &fid);
3662 printf("%s%s"DFID"\n",
3663 *sep != '\0' ? *path : "", sep,
3666 char name[NAME_MAX + 1];
3667 unsigned int linkno = 0;
3669 while ((err = llapi_path2parent(*path, linkno, &fid,
3670 name, sizeof(name))) == 0) {
3671 if (*sep != '\0' && linkno == 0)
3672 printf("%s%s", *path, sep);
3674 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3679 /* err == -ENODATA is end-of-loop */
3680 if (linkno > 0 && err == -ENODATA) {
3687 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3688 argv[0], show_parents ? "parent " : "", *path,
3700 static int lfs_data_version(int argc, char **argv)
3707 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3712 while ((c = getopt(argc, argv, "nrw")) != -1) {
3715 data_version_flags = 0;
3718 data_version_flags |= LL_DV_RD_FLUSH;
3721 data_version_flags |= LL_DV_WR_FLUSH;
3730 path = argv[optind];
3731 fd = open(path, O_RDONLY);
3733 err(errno, "cannot open file %s", path);
3735 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3737 err(errno, "cannot get version for %s", path);
3739 printf("%ju" "\n", (uintmax_t)data_version);
3745 static int lfs_hsm_state(int argc, char **argv)
3750 struct hsm_user_state hus;
3758 rc = llapi_hsm_state_get(path, &hus);
3760 fprintf(stderr, "can't get hsm state for %s: %s\n",
3761 path, strerror(errno = -rc));
3765 /* Display path name and status flags */
3766 printf("%s: (0x%08x)", path, hus.hus_states);
3768 if (hus.hus_states & HS_RELEASED)
3769 printf(" released");
3770 if (hus.hus_states & HS_EXISTS)
3772 if (hus.hus_states & HS_DIRTY)
3774 if (hus.hus_states & HS_ARCHIVED)
3775 printf(" archived");
3776 /* Display user-settable flags */
3777 if (hus.hus_states & HS_NORELEASE)
3778 printf(" never_release");
3779 if (hus.hus_states & HS_NOARCHIVE)
3780 printf(" never_archive");
3781 if (hus.hus_states & HS_LOST)
3782 printf(" lost_from_hsm");
3784 if (hus.hus_archive_id != 0)
3785 printf(", archive_id:%d", hus.hus_archive_id);
3788 } while (++i < argc);
3793 #define LFS_HSM_SET 0
3794 #define LFS_HSM_CLEAR 1
3797 * Generic function to set or clear HSM flags.
3798 * Used by hsm_set and hsm_clear.
3800 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3802 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3804 struct option long_opts[] = {
3805 {"lost", 0, 0, 'l'},
3806 {"norelease", 0, 0, 'r'},
3807 {"noarchive", 0, 0, 'a'},
3808 {"archived", 0, 0, 'A'},
3809 {"dirty", 0, 0, 'd'},
3810 {"exists", 0, 0, 'e'},
3813 char short_opts[] = "lraAde";
3821 while ((c = getopt_long(argc, argv, short_opts,
3822 long_opts, NULL)) != -1) {
3828 mask |= HS_NOARCHIVE;
3831 mask |= HS_ARCHIVED;
3834 mask |= HS_NORELEASE;
3845 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3846 argv[0], argv[optind - 1]);
3851 /* User should have specified a flag */
3855 while (optind < argc) {
3857 path = argv[optind];
3859 /* If mode == 0, this means we apply the mask. */
3860 if (mode == LFS_HSM_SET)
3861 rc = llapi_hsm_state_set(path, mask, 0, 0);
3863 rc = llapi_hsm_state_set(path, 0, mask, 0);
3866 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3867 path, strerror(errno = -rc));
3876 static int lfs_hsm_action(int argc, char **argv)
3881 struct hsm_current_action hca;
3882 struct hsm_extent he;
3883 enum hsm_user_action hua;
3884 enum hsm_progress_states hps;
3892 rc = llapi_hsm_current_action(path, &hca);
3894 fprintf(stderr, "can't get hsm action for %s: %s\n",
3895 path, strerror(errno = -rc));
3898 he = hca.hca_location;
3899 hua = hca.hca_action;
3900 hps = hca.hca_state;
3902 printf("%s: %s", path, hsm_user_action2name(hua));
3904 /* Skip file without action */
3905 if (hca.hca_action == HUA_NONE) {
3910 printf(" %s ", hsm_progress_state2name(hps));
3912 if ((hps == HPS_RUNNING) &&
3913 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3914 printf("(%llu bytes moved)\n",
3915 (unsigned long long)he.length);
3916 else if ((he.offset + he.length) == LUSTRE_EOF)
3917 printf("(from %llu to EOF)\n",
3918 (unsigned long long)he.offset);
3920 printf("(from %llu to %llu)\n",
3921 (unsigned long long)he.offset,
3922 (unsigned long long)(he.offset + he.length));
3924 } while (++i < argc);
3929 static int lfs_hsm_set(int argc, char **argv)
3931 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3934 static int lfs_hsm_clear(int argc, char **argv)
3936 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3940 * Check file state and return its fid, to be used by lfs_hsm_request().
3942 * \param[in] file Path to file to check
3943 * \param[in,out] fid Pointer to allocated lu_fid struct.
3944 * \param[in,out] last_dev Pointer to last device id used.
3946 * \return 0 on success.
3948 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3954 rc = lstat(file, &st);
3956 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3959 /* Checking for regular file as archiving as posix copytool
3960 * rejects archiving files other than regular files
3962 if (!S_ISREG(st.st_mode)) {
3963 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3966 /* A request should be ... */
3967 if (*last_dev != st.st_dev && *last_dev != 0) {
3968 fprintf(stderr, "All files should be "
3969 "on the same filesystem: %s\n", file);
3972 *last_dev = st.st_dev;
3974 rc = llapi_path2fid(file, fid);
3976 fprintf(stderr, "Cannot read FID of %s: %s\n",
3977 file, strerror(-rc));
3983 /* Fill an HSM HUR item with a given file name.
3985 * If mntpath is set, then the filename is actually a FID, and no
3986 * lookup on the filesystem will be performed.
3988 * \param[in] hur the user request to fill
3989 * \param[in] idx index of the item inside the HUR to fill
3990 * \param[in] mntpath mountpoint of Lustre
3991 * \param[in] fname filename (if mtnpath is NULL)
3992 * or FID (if mntpath is set)
3993 * \param[in] last_dev pointer to last device id used
3995 * \retval 0 on success
3996 * \retval CMD_HELP or a negative errno on error
3998 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3999 const char *mntpath, const char *fname,
4002 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4005 hui->hui_extent.length = -1;
4007 if (mntpath != NULL) {
4010 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4014 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4019 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4023 hur->hur_request.hr_itemcount++;
4028 static int lfs_hsm_request(int argc, char **argv, int action)
4030 struct option long_opts[] = {
4031 {"filelist", 1, 0, 'l'},
4032 {"data", 1, 0, 'D'},
4033 {"archive", 1, 0, 'a'},
4034 {"mntpath", 1, 0, 'm'},
4038 char short_opts[] = "l:D:a:m:";
4039 struct hsm_user_request *hur, *oldhur;
4044 char *filelist = NULL;
4045 char fullpath[PATH_MAX];
4046 char *opaque = NULL;
4050 int nbfile_alloc = 0;
4051 char *some_file = NULL;
4052 char *mntpath = NULL;
4058 while ((c = getopt_long(argc, argv, short_opts,
4059 long_opts, NULL)) != -1) {
4068 if (action != HUA_ARCHIVE &&
4069 action != HUA_REMOVE) {
4071 "error: -a is supported only "
4072 "when archiving or removing\n");
4075 archive_id = atoi(optarg);
4078 if (some_file == NULL) {
4080 some_file = strdup(optarg);
4086 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4087 argv[0], argv[optind - 1]);
4092 /* All remaining args are files, so we have at least nbfile */
4093 nbfile = argc - optind;
4095 if ((nbfile == 0) && (filelist == NULL))
4099 opaque_len = strlen(opaque);
4101 /* Alloc the request structure with enough place to store all files
4102 * from command line. */
4103 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4105 fprintf(stderr, "Cannot create the request: %s\n",
4109 nbfile_alloc = nbfile;
4111 hur->hur_request.hr_action = action;
4112 hur->hur_request.hr_archive_id = archive_id;
4113 hur->hur_request.hr_flags = 0;
4115 /* All remaining args are files, add them */
4116 if (nbfile != 0 && some_file == NULL)
4117 some_file = strdup(argv[optind]);
4119 for (i = 0; i < nbfile; i++) {
4120 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4126 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4128 /* If a filelist was specified, read the filelist from it. */
4129 if (filelist != NULL) {
4130 fp = fopen(filelist, "r");
4132 fprintf(stderr, "Cannot read the file list %s: %s\n",
4133 filelist, strerror(errno));
4138 while ((rc = getline(&line, &len, fp)) != -1) {
4139 /* If allocated buffer was too small, get something
4141 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4144 nbfile_alloc = nbfile_alloc * 2 + 1;
4146 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4149 fprintf(stderr, "hsm: cannot allocate "
4150 "the request: %s\n",
4157 size = hur_len(oldhur);
4159 fprintf(stderr, "hsm: cannot allocate "
4160 "%u files + %u bytes data\n",
4161 oldhur->hur_request.hr_itemcount,
4162 oldhur->hur_request.hr_data_len);
4169 memcpy(hur, oldhur, size);
4174 if (line[strlen(line) - 1] == '\n')
4175 line[strlen(line) - 1] = '\0';
4177 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4178 mntpath, line, &last_dev);
4184 if (some_file == NULL) {
4194 /* If a --data was used, add it to the request */
4195 hur->hur_request.hr_data_len = opaque_len;
4197 memcpy(hur_data(hur), opaque, opaque_len);
4199 /* Send the HSM request */
4200 if (realpath(some_file, fullpath) == NULL) {
4201 fprintf(stderr, "Could not find path '%s': %s\n",
4202 some_file, strerror(errno));
4204 rc = llapi_hsm_request(fullpath, hur);
4206 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4207 some_file, strerror(-rc));
4217 static int lfs_hsm_archive(int argc, char **argv)
4219 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4222 static int lfs_hsm_restore(int argc, char **argv)
4224 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4227 static int lfs_hsm_release(int argc, char **argv)
4229 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4232 static int lfs_hsm_remove(int argc, char **argv)
4234 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4237 static int lfs_hsm_cancel(int argc, char **argv)
4239 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4242 static int lfs_swap_layouts(int argc, char **argv)
4247 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4248 SWAP_LAYOUTS_KEEP_MTIME |
4249 SWAP_LAYOUTS_KEEP_ATIME);
4252 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4254 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4256 enum lu_ladvise_type advice;
4259 advice < ARRAY_SIZE(ladvise_names); advice++) {
4260 if (ladvise_names[advice] == NULL)
4262 if (strcmp(string, ladvise_names[advice]) == 0)
4266 return LU_LADVISE_INVALID;
4269 static int lfs_ladvise(int argc, char **argv)
4271 struct option long_opts[] = {
4272 {"advice", required_argument, 0, 'a'},
4273 {"background", no_argument, 0, 'b'},
4274 {"end", required_argument, 0, 'e'},
4275 {"start", required_argument, 0, 's'},
4276 {"length", required_argument, 0, 'l'},
4279 char short_opts[] = "a:be:l:s:";
4284 struct llapi_lu_ladvise advice;
4285 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4286 unsigned long long start = 0;
4287 unsigned long long end = LUSTRE_EOF;
4288 unsigned long long length = 0;
4289 unsigned long long size_units;
4290 unsigned long long flags = 0;
4293 while ((c = getopt_long(argc, argv, short_opts,
4294 long_opts, NULL)) != -1) {
4297 advice_type = lfs_get_ladvice(optarg);
4298 if (advice_type == LU_LADVISE_INVALID) {
4299 fprintf(stderr, "%s: invalid advice type "
4300 "'%s'\n", argv[0], optarg);
4301 fprintf(stderr, "Valid types:");
4303 for (advice_type = 0;
4304 advice_type < ARRAY_SIZE(ladvise_names);
4306 if (ladvise_names[advice_type] == NULL)
4308 fprintf(stderr, " %s",
4309 ladvise_names[advice_type]);
4311 fprintf(stderr, "\n");
4321 rc = llapi_parse_size(optarg, &end,
4324 fprintf(stderr, "%s: bad end offset '%s'\n",
4331 rc = llapi_parse_size(optarg, &start,
4334 fprintf(stderr, "%s: bad start offset "
4335 "'%s'\n", argv[0], optarg);
4341 rc = llapi_parse_size(optarg, &length,
4344 fprintf(stderr, "%s: bad length '%s'\n",
4352 fprintf(stderr, "%s: option '%s' unrecognized\n",
4353 argv[0], argv[optind - 1]);
4358 if (advice_type == LU_LADVISE_INVALID) {
4359 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4360 fprintf(stderr, "Valid types:");
4361 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4363 if (ladvise_names[advice_type] == NULL)
4365 fprintf(stderr, " %s", ladvise_names[advice_type]);
4367 fprintf(stderr, "\n");
4371 if (argc <= optind) {
4372 fprintf(stderr, "%s: please give one or more file names\n",
4377 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4378 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4383 if (end == LUSTRE_EOF && length != 0)
4384 end = start + length;
4387 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4388 argv[0], start, end);
4392 while (optind < argc) {
4395 path = argv[optind++];
4397 fd = open(path, O_RDONLY);
4399 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4400 argv[0], path, strerror(errno));
4405 advice.lla_start = start;
4406 advice.lla_end = end;
4407 advice.lla_advice = advice_type;
4408 advice.lla_value1 = 0;
4409 advice.lla_value2 = 0;
4410 advice.lla_value3 = 0;
4411 advice.lla_value4 = 0;
4412 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4415 fprintf(stderr, "%s: cannot give advice '%s' to file "
4416 "'%s': %s\n", argv[0],
4417 ladvise_names[advice_type],
4418 path, strerror(errno));
4421 if (rc == 0 && rc2 < 0)
4427 int main(int argc, char **argv)
4431 /* Ensure that liblustreapi constructor has run */
4432 if (!liblustreapi_initialized)
4433 fprintf(stderr, "liblustreapi was not properly initialized\n");
4437 Parser_init("lfs > ", cmdlist);
4439 progname = argv[0]; /* Used in error messages */
4441 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4443 rc = Parser_commands();
4446 return rc < 0 ? -rc : rc;
4449 #ifdef _LUSTRE_IDL_H_
4450 /* Everything we need here should be included by lustreapi.h. */
4451 # error "lfs should not depend on lustre_idl.h"
4452 #endif /* _LUSTRE_IDL_H_ */