4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <linux/lustre/lustre_ver.h>
69 #include <linux/lustre/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--layout|-L <pattern>]\n" \
120 " [--pool|-p <pool_name>]\n" \
121 " [--ost|-o <ost_indices>]\n" \
122 " [--component-end|-E <comp_end>]\n"
124 #define SSM_HELP_COMMON \
125 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
126 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
127 "\t respectively)\n" \
128 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
129 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
130 "\tpool_name: Name of OST pool to use (default none)\n" \
131 "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\
132 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
133 "\t Indices be specified in a format of:\n" \
134 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
136 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
137 "\t If --pool is set with --ost, then the OSTs\n" \
138 "\t must be the members of the pool." \
139 "\tcomp_end: Extent end of the component\n" \
140 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
141 "\t respectively, -1 for EOF), it must be aligned with\n"\
142 "\t the stripe_size\n"
144 #define SETSTRIPE_USAGE \
145 SSM_CMD_COMMON("setstripe") \
146 " <directory|filename>\n" \
149 #define MIGRATE_USAGE \
150 SSM_CMD_COMMON("migrate ") \
152 " [--non-block|-n]\n" \
156 "\tblock: Block file access during data migration (default)\n" \
157 "\tnon-block: Abort migrations if concurrent access is detected\n" \
159 #define SETDIRSTRIPE_USAGE \
160 " [--mdt-count|-c stripe_count>\n" \
161 " [--mdt-index|-i mdt_index]\n" \
162 " [--mdt-hash|-H mdt_hash]\n" \
163 " [--default|-D] [--mode|-m mode] <dir>\n" \
164 "\tstripe_count: stripe count of the striped directory\n" \
165 "\tmdt_index: MDT index of first stripe\n" \
166 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
167 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
168 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
169 "\tdefault_stripe: set default dirstripe of the directory\n" \
170 "\tmode: the mode of the directory\n"
172 static const char *progname;
173 static bool file_lease_supported = true;
175 /* all available commands */
176 command_t cmdlist[] = {
177 {"setstripe", lfs_setstripe, 0,
178 "Create a new file with a specific striping pattern or\n"
179 "set the default striping pattern on an existing directory or\n"
180 "delete the default striping pattern from an existing directory or\n"
181 "add layout component(s) to an existing composite file or\n"
182 "delete specified component(s) from an existing composite file\n\n"
183 "To delete default striping from an existing directory:\n"
184 "usage: setstripe -d <directory>\n"
186 "To delete component(s) from an existing composite file:\n"
187 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
188 " [--component-flags|-F <comp_flags>]\n"
190 "\tcomp_id: Unique component ID\n"
191 "\tcomp_flags: 'init' indicating all instantiated components\n"
192 "\t '^init' indicating all uninstantiated components\n"
193 "\t-I and -F can't be specified at the same time\n"
195 "To add component(s) to an existing composite file:\n"
196 SSM_CMD_COMMON("setstripe --component-add")
198 "To create a file with specified striping/composite layout:\n"
200 {"getstripe", lfs_getstripe, 0,
201 "To list the striping info for a given file or files in a\n"
202 "directory or recursively for all files in a directory tree.\n"
203 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
204 " [--stripe-count|-c] [--stripe-index|-i]\n"
205 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
206 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
207 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
208 " [--component-id[=comp_id]|-I[comp_id]]\n"
209 " [--component-flags[=comp_flags]]\n"
210 " [--component-count]\n"
211 " [--component-start[=[+-]comp_start]]\n"
212 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
213 " <directory|filename> ..."},
214 {"setdirstripe", lfs_setdirstripe, 0,
215 "To create a striped directory on a specified MDT. This can only\n"
216 "be done on MDT0 with the right of administrator.\n"
217 "usage: setdirstripe [OPTION] <directory>\n"
219 {"getdirstripe", lfs_getdirstripe, 0,
220 "To list the striping info for a given directory\n"
221 "or recursively for all directories in a directory tree.\n"
222 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
223 " [--mdt-index|-i] [--mdt-hash|-t]\n"
224 " [--recursive|-r] [--yaml|-y]\n"
225 " [--default|-D] <dir> ..."},
226 {"mkdir", lfs_setdirstripe, 0,
227 "To create a striped directory on a specified MDT. This can only\n"
228 "be done on MDT0 with the right of administrator.\n"
229 "usage: mkdir [OPTION] <directory>\n"
231 {"rm_entry", lfs_rmentry, 0,
232 "To remove the name entry of the remote directory. Note: This\n"
233 "command will only delete the name entry, i.e. the remote directory\n"
234 "will become inaccessable after this command. This can only be done\n"
235 "by the administrator\n"
236 "usage: rm_entry <dir>\n"},
237 {"pool_list", lfs_poollist, 0,
238 "List pools or pool OSTs\n"
239 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
240 {"find", lfs_find, 0,
241 "find files matching given attributes recursively in directory tree.\n"
242 "usage: find <directory|filename> ...\n"
243 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
244 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
245 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
246 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
247 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
248 " [[!] --stripe-count|-c [+-]<stripes>]\n"
249 " [[!] --stripe-index|-i <index,...>]\n"
250 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
251 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
252 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
253 " [[!] --projid <projid>]\n"
254 " [[!] --layout|-L released,raid0,mdt]\n"
255 " [[!] --component-count [+-]<comp_cnt>]\n"
256 " [[!] --component-start [+-]N[kMGTPE]]\n"
257 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
258 " [[!] --component-flags <comp_flags>]\n"
259 " [[!] --mdt-count|-T [+-]<stripes>]\n"
260 " [[!] --mdt-hash|-H <hashtype>\n"
261 "\t !: used before an option indicates 'NOT' requested attribute\n"
262 "\t -: used before a value indicates less than requested value\n"
263 "\t +: used before a value indicates more than requested value\n"
264 "\tmdt-hash: hash type of the striped directory.\n"
265 "\t fnv_1a_64 FNV-1a hash algorithm\n"
266 "\t all_char sum of characters % MDT_COUNT\n"},
267 {"check", lfs_check, 0,
268 "Display the status of MDS or OSTs (as specified in the command)\n"
269 "or all the servers (MDS and OSTs).\n"
270 "usage: check <osts|mds|servers>"},
271 {"osts", lfs_osts, 0, "list OSTs connected to client "
272 "[for specified path only]\n" "usage: osts [path]"},
273 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
274 "[for specified path only]\n" "usage: mdts [path]"},
276 "report filesystem disk space usage or inodes usage"
277 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
278 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
279 {"getname", lfs_getname, 0, "list instances and specified mount points "
280 "[for specified path only]\n"
281 "Usage: getname [-h]|[path ...] "},
282 #ifdef HAVE_SYS_QUOTA_H
283 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
284 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
285 " -b <block-softlimit> -B <block-hardlimit>\n"
286 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
287 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
288 " [--block-softlimit <block-softlimit>]\n"
289 " [--block-hardlimit <block-hardlimit>]\n"
290 " [--inode-softlimit <inode-softlimit>]\n"
291 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
292 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
293 " [--block-grace <block-grace>]\n"
294 " [--inode-grace <inode-grace>] <filesystem>\n"
295 " -b can be used instead of --block-softlimit/--block-grace\n"
296 " -B can be used instead of --block-hardlimit\n"
297 " -i can be used instead of --inode-softlimit/--inode-grace\n"
298 " -I can be used instead of --inode-hardlimit\n\n"
299 "Note: The total quota space will be split into many qunits and\n"
300 " balanced over all server targets, the minimal qunit size is\n"
301 " 1M bytes for block space and 1K inodes for inode space.\n\n"
302 " Quota space rebalancing process will stop when this mininum\n"
303 " value is reached. As a result, quota exceeded can be returned\n"
304 " while many targets still have 1MB or 1K inodes of spare\n"
306 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
307 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
309 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
310 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
312 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
313 "usage: flushctx [-k] [mountpoint...]"},
315 "Remote user copy files and directories.\n"
316 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
318 "Remote user list directory contents.\n"
319 "usage: ls [OPTION]... [FILE]..."},
320 {"changelog", lfs_changelog, 0,
321 "Show the metadata changes on an MDT."
322 "\nusage: changelog <mdtname> [startrec [endrec]]"},
323 {"changelog_clear", lfs_changelog_clear, 0,
324 "Indicate that old changelog records up to <endrec> are no longer of "
325 "interest to consumer <id>, allowing the system to free up space.\n"
326 "An <endrec> of 0 means all records.\n"
327 "usage: changelog_clear <mdtname> <id> <endrec>"},
328 {"fid2path", lfs_fid2path, 0,
329 "Resolve the full path(s) for given FID(s). For a specific hardlink "
330 "specify link number <linkno>.\n"
331 /* "For a historical link name, specify changelog record <recno>.\n" */
332 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
333 /* [ --rec <recno> ] */ },
334 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
335 "usage: path2fid [--parents] <path> ..."},
336 {"data_version", lfs_data_version, 0, "Display file data version for "
337 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
338 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
339 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
340 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
341 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
342 "[--archived] [--lost] <file> ..."},
343 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
345 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
346 "[--archived] [--lost] <file> ..."},
347 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
348 "given files.\n" "usage: hsm_action <file> ..."},
349 {"hsm_archive", lfs_hsm_archive, 0,
350 "Archive file to external storage.\n"
351 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
353 {"hsm_restore", lfs_hsm_restore, 0,
354 "Restore file from external storage.\n"
355 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
356 {"hsm_release", lfs_hsm_release, 0,
357 "Release files from Lustre.\n"
358 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
359 {"hsm_remove", lfs_hsm_remove, 0,
360 "Remove file copy from external storage.\n"
361 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
362 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
364 "Note: To remove files from the archive that have been deleted on\n"
365 "Lustre, set mntpath and optionally archive. In that case, all the\n"
366 "positional arguments and entries in the file list must be FIDs."
368 {"hsm_cancel", lfs_hsm_cancel, 0,
369 "Cancel requests related to specified files.\n"
370 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
371 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
372 "usage: swap_layouts <path1> <path2>"},
373 {"migrate", lfs_setstripe, 0,
374 "migrate a directory between MDTs.\n"
375 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
377 "\tmdt_idx: index of the destination MDT\n"
379 "migrate file objects from one OST "
380 "layout\nto another (may be not safe with concurent writes).\n"
382 "[--stripe-count|-c] <stripe_count>\n"
383 " [--stripe-index|-i] <start_ost_index>\n"
384 " [--stripe-size|-S] <stripe_size>\n"
385 " [--pool|-p] <pool_name>\n"
386 " [--ost-list|-o] <ost_indices>\n"
388 " [--non-block|-n]\n"
389 " <file|directory>\n"
390 "\tstripe_count: number of OSTs to stripe a file over\n"
391 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
392 "\tstripe_size: number of bytes to store before moving to the next OST\n"
393 "\tpool_name: name of the predefined pool of OSTs\n"
394 "\tost_indices: OSTs to stripe over, in order\n"
395 "\tblock: wait for the operation to return before continuing\n"
396 "\tnon-block: do not wait for the operation to return.\n"},
398 "To move directories between MDTs. This command is deprecated, "
399 "use \"migrate\" instead.\n"
400 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
402 {"ladvise", lfs_ladvise, 0,
403 "Provide servers with advice about access patterns for a file.\n"
404 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
405 " [--background|-b] [--unset|-u]\n\n"
406 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
407 " {[--mode|-m [READ,WRITE]}\n"
409 {"help", Parser_help, 0, "help"},
410 {"exit", Parser_quit, 0, "quit"},
411 {"quit", Parser_quit, 0, "quit"},
412 {"--version", Parser_version, 0,
413 "output build version of the utility and exit"},
414 {"--list-commands", lfs_list_commands, 0,
415 "list commands supported by the utility and exit"},
420 #define MIGRATION_NONBLOCK 1
422 static int check_hashtype(const char *hashtype)
426 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
427 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
434 * Internal helper for migrate_copy_data(). Check lease and report error if
437 * \param[in] fd File descriptor on which to check the lease.
438 * \param[out] lease_broken Set to true if the lease was broken.
439 * \param[in] group_locked Whether a group lock was taken or not.
440 * \param[in] path Name of the file being processed, for error
443 * \retval 0 Migration can keep on going.
444 * \retval -errno Error occurred, abort migration.
446 static int check_lease(int fd, bool *lease_broken, bool group_locked,
451 if (!file_lease_supported)
454 rc = llapi_lease_check(fd);
456 return 0; /* llapi_check_lease returns > 0 on success. */
459 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
461 rc = rc ? rc : -EAGAIN;
463 fprintf(stderr, "%s: external attempt to access file '%s' "
464 "blocked until migration ends.\n", progname, path);
467 *lease_broken = true;
471 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
472 bool group_locked, const char *fname)
481 bool lease_broken = false;
483 /* Use a page-aligned buffer for direct I/O */
484 rc = posix_memalign(&buf, getpagesize(), buf_size);
489 /* read new data only if we have written all
490 * previously read data */
493 rc = check_lease(fd_src, &lease_broken,
494 group_locked, fname);
498 rsize = read(fd_src, buf, buf_size);
501 fprintf(stderr, "%s: %s: read failed: %s\n",
502 progname, fname, strerror(-rc));
512 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
516 "%s: %s: write failed on volatile: %s\n",
517 progname, fname, strerror(-rc));
527 fprintf(stderr, "%s: %s: fsync failed: %s\n",
528 progname, fname, strerror(-rc));
536 static int migrate_copy_timestamps(int fdv, const struct stat *st)
538 struct timeval tv[2] = {
539 {.tv_sec = st->st_atime},
540 {.tv_sec = st->st_mtime}
543 return futimes(fdv, tv);
546 static int migrate_block(int fd, int fdv, const struct stat *st,
547 size_t buf_size, const char *name)
554 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
556 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
557 progname, name, strerror(-rc));
565 /* The grouplock blocks all concurrent accesses to the file.
566 * It has to be taken after llapi_get_data_version as it would
568 rc = llapi_group_lock(fd, gid);
570 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
571 progname, name, strerror(-rc));
575 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
577 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
581 /* Make sure we keep original atime/mtime values */
582 rc = migrate_copy_timestamps(fdv, st);
584 fprintf(stderr, "%s: %s: timestamp copy failed\n",
590 * for a migration we need to check data version on file did
593 * Pass in gid=0 since we already own grouplock. */
594 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
595 SWAP_LAYOUTS_CHECK_DV1);
597 fprintf(stderr, "%s: %s: dataversion changed during copy, "
598 "migration aborted\n", progname, name);
601 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
602 name, strerror(-rc));
607 rc2 = llapi_group_unlock(fd, gid);
608 if (rc2 < 0 && rc == 0) {
609 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
610 progname, name, strerror(-rc2));
617 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
618 size_t buf_size, const char *name)
624 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
626 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
627 progname, name, strerror(-rc));
631 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
633 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
637 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
639 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
640 progname, name, strerror(-rc));
646 fprintf(stderr, "%s: %s: data version changed during "
652 /* Make sure we keep original atime/mtime values */
653 rc = migrate_copy_timestamps(fdv, st);
655 fprintf(stderr, "%s: %s: timestamp copy failed\n",
660 /* Atomically put lease, swap layouts and close.
661 * for a migration we need to check data version on file did
663 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
665 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
666 progname, name, strerror(-rc));
673 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
678 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
682 if (flags != 0 && comp_id != 0)
685 /* LCME_FL_INIT is the only supported flag in PFL */
687 if (flags & ~LCME_KNOWN_FLAGS) {
688 fprintf(stderr, "Invalid component flags %#x\n", flags);
691 } else if (comp_id > LCME_ID_MAX) {
692 fprintf(stderr, "Invalid component id %u\n", comp_id);
696 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
698 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
699 comp_id, fname, strerror(errno));
703 static int lfs_component_add(char *fname, struct llapi_layout *layout)
710 rc = llapi_layout_file_comp_add(fname, layout);
712 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
713 fname, strerror(errno));
717 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
718 struct llapi_layout *layout)
726 fd = lstat(fname, &st);
727 if (fd == 0 && S_ISDIR(st.st_mode))
728 open_flags = O_DIRECTORY | O_RDONLY;
730 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
732 fprintf(stderr, "%s %s failed. %s\n",
733 S_ISDIR(st.st_mode) ?
734 "Set default composite layout to " :
735 "Create composite file",
736 fname, strerror(errno));
740 static int lfs_migrate(char *name, __u64 migration_flags,
741 struct llapi_stripe_param *param,
742 struct llapi_layout *layout)
746 char parent[PATH_MAX];
749 char volatile_file[sizeof(parent) +
750 LUSTRE_VOLATILE_HDR_LEN +
751 2 * sizeof(mdt_index) +
752 2 * sizeof(random_value) + 4];
755 struct lov_user_md *lum = NULL;
757 int buf_size = 1024 * 1024 * 4;
758 bool have_lease_rdlck = false;
762 /* find the right size for the IO and allocate the buffer */
763 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
764 lum = malloc(lum_size);
770 rc = llapi_file_get_stripe(name, lum);
771 /* failure can happen for many reasons and some may be not real errors
773 * in case of a real error, a later call will fail with better
774 * error management */
776 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
777 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
778 lum->lmm_stripe_size != 0)
779 buf_size = lum->lmm_stripe_size;
782 /* open file, direct io */
783 /* even if the file is only read, WR mode is nedeed to allow
784 * layout swap on fd */
785 fd = open(name, O_RDWR | O_DIRECT);
788 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
793 if (file_lease_supported) {
794 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
795 if (rc == -EOPNOTSUPP) {
796 /* Older servers do not support file lease.
797 * Disable related checks. This opens race conditions
798 * as explained in LU-4840 */
799 file_lease_supported = false;
801 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
802 progname, name, strerror(-rc));
805 have_lease_rdlck = true;
809 /* search for file directory pathname */
810 if (strlen(name) > sizeof(parent)-1) {
814 strncpy(parent, name, sizeof(parent));
815 ptr = strrchr(parent, '/');
817 if (getcwd(parent, sizeof(parent)) == NULL) {
828 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
830 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
831 progname, name, strerror(-rc));
836 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
837 mode_t open_mode = S_IRUSR | S_IWUSR;
839 random_value = random();
840 rc = snprintf(volatile_file, sizeof(volatile_file),
841 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
842 mdt_index, random_value);
843 if (rc >= sizeof(volatile_file)) {
848 /* create, open a volatile file, use caching (ie no directio) */
850 fdv = llapi_file_open_param(volatile_file, open_flags,
852 else if (layout != NULL)
853 fdv = lfs_component_create(volatile_file, open_flags,
857 } while (fdv == -EEXIST);
861 fprintf(stderr, "%s: %s: cannot create volatile file in"
863 progname, parent, strerror(-rc));
867 /* In case the MDT does not support creation of volatile files
868 * we should try to unlink it. */
869 (void)unlink(volatile_file);
871 /* Not-owner (root?) special case.
872 * Need to set owner/group of volatile file like original.
873 * This will allow to pass related check during layout_swap.
878 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
882 rc = fstat(fdv, &stv);
885 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
886 volatile_file, strerror(errno));
889 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
890 rc = fchown(fdv, st.st_uid, st.st_gid);
893 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
894 name, strerror(errno));
899 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
900 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
902 have_lease_rdlck = false;
903 fdv = -1; /* The volatile file is closed as we put the
904 * lease in non-blocking mode. */
907 /* Blocking mode (forced if servers do not support file lease).
908 * It is also the default mode, since we cannot distinguish
909 * between a broken lease and a server that does not support
910 * atomic swap/close (LU-6785) */
911 rc = migrate_block(fd, fdv, &st, buf_size, name);
915 if (have_lease_rdlck)
932 * Parse a string containing an OST index list into an array of integers.
934 * The input string contains a comma delimited list of individual
935 * indices and ranges, for example "1,2-4,7". Add the indices into the
936 * \a osts array and remove duplicates.
938 * \param[out] osts array to store indices in
939 * \param[in] size size of \a osts array
940 * \param[in] offset starting index in \a osts
941 * \param[in] arg string containing OST index list
943 * \retval positive number of indices in \a osts
944 * \retval -EINVAL unable to parse \a arg
946 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
950 int slots = size - offset;
958 while (!end_of_loop) {
966 ptr = strchrnul(arg, ',');
968 end_of_loop = *ptr == '\0';
971 start_index = strtol(arg, &endptr, 0);
972 if (endptr == arg) /* no data at all */
974 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
979 end_index = start_index;
980 if (*endptr == '-') {
981 end_index = strtol(endptr + 1, &endptr, 0);
984 if (end_index < start_index)
988 for (i = start_index; i <= end_index && slots > 0; i++) {
991 /* remove duplicate */
992 for (j = 0; j < offset; j++) {
996 if (j == offset) { /* no duplicate */
1001 if (slots == 0 && i < end_index)
1009 if (!end_of_loop && ptr != NULL)
1012 return rc < 0 ? rc : nr;
1015 struct lfs_setstripe_args {
1016 unsigned long long lsa_comp_end;
1017 unsigned long long lsa_stripe_size;
1018 int lsa_stripe_count;
1020 __u32 lsa_comp_flags;
1024 char *lsa_pool_name;
1027 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1029 memset(lsa, 0, sizeof(*lsa));
1030 lsa->lsa_stripe_off = -1;
1033 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1035 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1036 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1037 lsa->lsa_comp_end != 0 || lsa->lsa_pattern != 0);
1040 static int comp_args_to_layout(struct llapi_layout **composite,
1041 struct lfs_setstripe_args *lsa)
1043 struct llapi_layout *layout = *composite;
1044 uint64_t prev_end = 0;
1047 if (layout == NULL) {
1048 layout = llapi_layout_alloc();
1049 if (layout == NULL) {
1050 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1054 *composite = layout;
1058 /* Get current component extent, current component
1059 * must be the tail component. */
1060 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1062 fprintf(stderr, "Get comp extent failed. %s\n",
1067 rc = llapi_layout_comp_add(layout);
1069 fprintf(stderr, "Add component failed. %s\n",
1075 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1077 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1078 prev_end, lsa->lsa_comp_end, strerror(errno));
1082 /* Data-on-MDT component setting */
1083 if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1084 /* In case of Data-on-MDT patterns the only extra option
1085 * applicable is stripe size option. */
1086 if (lsa->lsa_stripe_count) {
1087 fprintf(stderr, "Option 'stripe-count' can't be "
1088 "specified with Data-on-MDT component: %i\n",
1089 lsa->lsa_stripe_count);
1092 if (lsa->lsa_stripe_size) {
1093 fprintf(stderr, "Option 'stripe-size' can't be "
1094 "specified with Data-on-MDT component: %llu\n",
1095 lsa->lsa_stripe_size);
1098 if (lsa->lsa_nr_osts != 0) {
1099 fprintf(stderr, "Option 'ost-list' can't be specified "
1100 "with Data-on-MDT component: '%i'\n",
1104 if (lsa->lsa_stripe_off != -1) {
1105 fprintf(stderr, "Option 'stripe-offset' can't be "
1106 "specified with Data-on-MDT component: %i\n",
1107 lsa->lsa_stripe_off);
1110 if (lsa->lsa_pool_name != 0) {
1111 fprintf(stderr, "Option 'pool' can't be specified "
1112 "with Data-on-MDT component: '%s'\n",
1113 lsa->lsa_pool_name);
1117 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1119 fprintf(stderr, "Set stripe pattern %#x failed. %s\n",
1120 lsa->lsa_pattern, strerror(errno));
1123 /* Data-on-MDT component has always single stripe up to end */
1124 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1127 if (lsa->lsa_stripe_size != 0) {
1128 rc = llapi_layout_stripe_size_set(layout,
1129 lsa->lsa_stripe_size);
1131 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1132 lsa->lsa_stripe_size, strerror(errno));
1137 if (lsa->lsa_stripe_count != 0) {
1138 rc = llapi_layout_stripe_count_set(layout,
1139 lsa->lsa_stripe_count == -1 ?
1141 lsa->lsa_stripe_count);
1143 fprintf(stderr, "Set stripe count %d failed. %s\n",
1144 lsa->lsa_stripe_count, strerror(errno));
1149 if (lsa->lsa_pool_name != NULL) {
1150 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1152 fprintf(stderr, "Set pool name: %s failed. %s\n",
1153 lsa->lsa_pool_name, strerror(errno));
1158 if (lsa->lsa_nr_osts > 0) {
1159 if (lsa->lsa_stripe_count > 0 &&
1160 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1161 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1162 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1165 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1166 rc = llapi_layout_ost_index_set(layout, i,
1171 } else if (lsa->lsa_stripe_off != -1) {
1172 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1175 fprintf(stderr, "Set ost index %d failed. %s\n",
1176 i, strerror(errno));
1183 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1184 * end of the last component in the existing file, and adjust the
1185 * first extent start of the components to be added accordingly. */
1186 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1188 struct llapi_layout *head;
1189 uint64_t start, end, stripe_size, prev_end = 0;
1196 head = llapi_layout_get_by_path(fname, 0);
1198 fprintf(stderr, "Read layout from %s failed. %s\n",
1199 fname, strerror(errno));
1201 } else if (errno == ENODATA) {
1202 /* file without LOVEA, this component-add will be turned
1203 * into a component-create. */
1204 llapi_layout_free(head);
1206 } else if (!llapi_layout_is_composite(head)) {
1207 fprintf(stderr, "'%s' isn't a composite file.\n",
1209 llapi_layout_free(head);
1213 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1215 fprintf(stderr, "Get prev extent failed. %s\n",
1217 llapi_layout_free(head);
1221 llapi_layout_free(head);
1223 /* Make sure we use the first component of the layout to be added. */
1224 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1226 fprintf(stderr, "Move component cursor failed. %s\n",
1231 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1233 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1237 if (start > prev_end || end <= prev_end) {
1238 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1239 "adjacent with the existing file extent end: %lu\n",
1240 start, end, prev_end);
1244 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1246 fprintf(stderr, "Get stripe size failed. %s\n",
1251 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1252 (prev_end & (stripe_size - 1))) {
1253 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1254 stripe_size, prev_end);
1258 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1260 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1261 prev_end, end, strerror(errno));
1268 static inline bool comp_flags_is_neg(__u32 flags)
1270 return flags & LCME_FL_NEG;
1273 static inline void comp_flags_set_neg(__u32 *flags)
1275 *flags |= LCME_FL_NEG;
1278 static inline void comp_flags_clear_neg(__u32 *flags)
1280 *flags &= ~LCME_FL_NEG;
1283 static int comp_str2flags(__u32 *flags, char *string)
1286 __u32 neg_flags = 0;
1292 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1296 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1297 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1298 const char *comp_name = comp_flags_table[i].cfn_name;
1300 if (strcmp(name, comp_name) == 0) {
1301 *flags |= comp_flag;
1303 } else if (strncmp(name, "^", 1) == 0 &&
1304 strcmp(name + 1, comp_name) == 0) {
1305 neg_flags |= comp_flag;
1310 llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1311 "'%s' is not supported.\n", name);
1316 if (*flags == 0 && neg_flags == 0)
1318 /* don't support mixed flags for now */
1319 if (*flags && neg_flags)
1324 comp_flags_set_neg(flags);
1330 static inline bool arg_is_eof(char *arg)
1332 return !strncmp(arg, "-1", strlen("-1")) ||
1333 !strncmp(arg, "EOF", strlen("EOF")) ||
1334 !strncmp(arg, "eof", strlen("eof"));
1349 static int lfs_setstripe(int argc, char **argv)
1351 struct lfs_setstripe_args lsa;
1352 struct llapi_stripe_param *param = NULL;
1353 struct find_param migrate_mdt_param = {
1363 char *mdt_idx_arg = NULL;
1364 unsigned long long size_units = 1;
1365 bool migrate_mode = false;
1366 bool migration_block = false;
1367 __u64 migration_flags = 0;
1368 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1369 int comp_del = 0, comp_set = 0;
1372 struct llapi_layout *layout = NULL;
1374 struct option long_opts[] = {
1375 /* --block is only valid in migrate mode */
1376 { .val = 'b', .name = "block", .has_arg = no_argument},
1377 { .val = LFS_COMP_ADD_OPT,
1378 .name = "comp-add", .has_arg = no_argument},
1379 { .val = LFS_COMP_ADD_OPT,
1380 .name = "component-add",
1381 .has_arg = no_argument},
1382 { .val = LFS_COMP_DEL_OPT,
1383 .name = "comp-del", .has_arg = no_argument},
1384 { .val = LFS_COMP_DEL_OPT,
1385 .name = "component-del",
1386 .has_arg = no_argument},
1387 { .val = LFS_COMP_FLAGS_OPT,
1388 .name = "comp-flags", .has_arg = required_argument},
1389 { .val = LFS_COMP_FLAGS_OPT,
1390 .name = "component-flags",
1391 .has_arg = required_argument},
1392 { .val = LFS_COMP_SET_OPT,
1393 .name = "comp-set", .has_arg = no_argument},
1394 { .val = LFS_COMP_SET_OPT,
1395 .name = "component-set",
1396 .has_arg = no_argument},
1397 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1398 /* This formerly implied "stripe-count", but was explicitly
1399 * made "stripe-count" for consistency with other options,
1400 * and to separate it from "mdt-count" when DNE arrives. */
1401 { .val = 'c', .name = "count", .has_arg = required_argument },
1403 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1404 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1405 { .val = 'd', .name = "delete", .has_arg = no_argument},
1406 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1407 { .val = 'E', .name = "component-end",
1408 .has_arg = required_argument},
1409 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1410 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1411 /* This formerly implied "stripe-index", but was explicitly
1412 * made "stripe-index" for consistency with other options,
1413 * and to separate it from "mdt-index" when DNE arrives. */
1414 { .val = 'i', .name = "index", .has_arg = required_argument },
1416 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1417 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1418 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1419 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1420 { .val = 'L', .name = "layout", .has_arg = required_argument },
1421 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1422 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1423 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1424 /* --non-block is only valid in migrate mode */
1425 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1426 { .val = 'o', .name = "ost", .has_arg = required_argument},
1427 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1428 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1429 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1431 { .val = 'p', .name = "pool", .has_arg = required_argument },
1432 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1433 /* This formerly implied "--stripe-size", but was confusing
1434 * with "lfs find --size|-s", which means "file size", so use
1435 * the consistent "--stripe-size|-S" for all commands. */
1436 { .val = 's', .name = "size", .has_arg = required_argument },
1438 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1439 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1440 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1441 /* --verbose is only valid in migrate mode */
1442 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1443 { .val = LFS_COMP_ADD_OPT,
1444 .name = "component-add",
1445 .has_arg = no_argument },
1446 { .val = LFS_COMP_DEL_OPT,
1447 .name = "component-del",
1448 .has_arg = no_argument },
1449 { .val = LFS_COMP_FLAGS_OPT,
1450 .name = "component-flags",
1451 .has_arg = required_argument },
1452 { .val = LFS_COMP_SET_OPT,
1453 .name = "component-set",
1454 .has_arg = no_argument },
1457 setstripe_args_init(&lsa);
1459 if (strcmp(argv[0], "migrate") == 0)
1460 migrate_mode = true;
1462 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:L:s:S:v",
1463 long_opts, NULL)) >= 0) {
1468 case LFS_COMP_ADD_OPT:
1471 case LFS_COMP_DEL_OPT:
1474 case LFS_COMP_FLAGS_OPT:
1475 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1477 fprintf(stderr, "error: %s: bad comp flags "
1478 "'%s'\n", argv[0], optarg);
1482 case LFS_COMP_SET_OPT:
1486 if (!migrate_mode) {
1487 fprintf(stderr, "--block is valid only for"
1491 migration_block = true;
1494 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1495 if (strcmp(argv[optind - 1], "--count") == 0)
1496 fprintf(stderr, "warning: '--count' deprecated"
1497 ", use '--stripe-count' instead\n");
1499 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1501 fprintf(stderr, "error: %s: bad stripe count "
1502 "'%s'\n", argv[0], optarg);
1507 /* delete the default striping pattern */
1511 if (lsa.lsa_comp_end != 0) {
1512 result = comp_args_to_layout(&layout, &lsa);
1516 setstripe_args_init(&lsa);
1519 if (arg_is_eof(optarg)) {
1520 lsa.lsa_comp_end = LUSTRE_EOF;
1522 result = llapi_parse_size(optarg,
1526 fprintf(stderr, "error: %s: "
1527 "bad component end '%s'\n",
1534 if (strcmp(argv[optind - 1], "--index") == 0)
1535 fprintf(stderr, "warning: '--index' deprecated"
1536 ", use '--stripe-index' instead\n");
1537 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1539 fprintf(stderr, "error: %s: bad stripe offset "
1540 "'%s'\n", argv[0], optarg);
1545 comp_id = strtoul(optarg, &end, 0);
1546 if (*end != '\0' || comp_id == 0 ||
1547 comp_id > LCME_ID_MAX) {
1548 fprintf(stderr, "error: %s: bad comp ID "
1549 "'%s'\n", argv[0], optarg);
1554 if (strcmp(argv[optind - 1], "mdt") == 0) {
1555 /* Can be only the first component */
1556 if (layout != NULL) {
1558 fprintf(stderr, "error: 'mdt' layout "
1559 "can be only the first one\n");
1562 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
1564 fprintf(stderr, "error: 'mdt' layout "
1565 "size is too big\n");
1568 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
1569 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
1571 fprintf(stderr, "error: layout '%s' is "
1572 "unknown, supported layouts are: "
1573 "'mdt', 'raid0'\n", argv[optind]);
1578 if (!migrate_mode) {
1579 fprintf(stderr, "--mdt-index is valid only for"
1583 mdt_idx_arg = optarg;
1586 if (!migrate_mode) {
1587 fprintf(stderr, "--non-block is valid only for"
1591 migration_flags |= MIGRATION_NONBLOCK;
1594 lsa.lsa_nr_osts = parse_targets(osts,
1595 sizeof(osts) / sizeof(__u32),
1596 lsa.lsa_nr_osts, optarg);
1597 if (lsa.lsa_nr_osts < 0) {
1599 "error: %s: bad OST indices '%s'\n",
1604 lsa.lsa_osts = osts;
1605 if (lsa.lsa_stripe_off == -1)
1606 lsa.lsa_stripe_off = osts[0];
1611 lsa.lsa_pool_name = optarg;
1613 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1615 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1616 fprintf(stderr, "warning: '--size|-s' deprecated, "
1617 "use '--stripe-size|-S' instead\n");
1619 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1621 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1624 fprintf(stderr, "error: %s: bad stripe size "
1625 "'%s'\n", argv[0], optarg);
1630 if (!migrate_mode) {
1631 fprintf(stderr, "--verbose is valid only for"
1635 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1642 fname = argv[optind];
1644 if (lsa.lsa_comp_end != 0) {
1645 result = comp_args_to_layout(&layout, &lsa);
1650 if (optind == argc) {
1651 fprintf(stderr, "error: %s: missing filename|dirname\n",
1656 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1657 * altered by user space tool, so we don't need to support the
1658 * --component-set for this moment. */
1659 if (comp_set != 0) {
1660 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1665 if ((delete + comp_set + comp_del + comp_add) > 1) {
1666 fprintf(stderr, "error: %s: can't specify --component-set, "
1667 "--component-del, --component-add or -d together\n",
1672 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1673 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1674 fprintf(stderr, "error: %s: can't specify -d with "
1675 "-s, -c, -o, -p, -I, -F or -E options\n",
1680 if ((comp_set || comp_del) &&
1681 (setstripe_args_specified(&lsa) || layout != NULL)) {
1682 fprintf(stderr, "error: %s: can't specify --component-del or "
1683 "--component-set with -s, -c, -o, -p or -E options.\n",
1688 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1689 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1690 "--component-del option.\n", argv[0]);
1694 if (comp_add || comp_del) {
1697 result = lstat(fname, &st);
1698 if (result == 0 && S_ISDIR(st.st_mode)) {
1699 fprintf(stderr, "error: %s: can't use --component-add "
1700 "or --component-del for directory.\n",
1707 if (layout == NULL) {
1708 fprintf(stderr, "error: %s: -E option must be present"
1709 "in --component-add mode.\n", argv[0]);
1712 result = adjust_first_extent(fname, layout);
1713 if (result == -ENODATA)
1715 else if (result != 0)
1719 if (mdt_idx_arg != NULL && optind > 3) {
1720 fprintf(stderr, "error: %s: cannot specify -m with other "
1721 "options\n", argv[0]);
1725 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1727 "error: %s: cannot specify --non-block and --block\n",
1732 if (!comp_del && !comp_set && comp_id != 0) {
1733 fprintf(stderr, "error: %s: -I can only be used with "
1734 "--component-del.\n", argv[0]);
1738 if (mdt_idx_arg != NULL) {
1739 /* initialize migrate mdt parameters */
1740 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1742 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1743 argv[0], mdt_idx_arg);
1746 migrate_mdt_param.fp_migrate = 1;
1747 } else if (layout == NULL) {
1748 /* initialize stripe parameters */
1749 param = calloc(1, offsetof(typeof(*param),
1750 lsp_osts[lsa.lsa_nr_osts]));
1751 if (param == NULL) {
1752 fprintf(stderr, "error: %s: %s\n", argv[0],
1757 param->lsp_stripe_size = lsa.lsa_stripe_size;
1758 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1759 param->lsp_stripe_count = lsa.lsa_stripe_count;
1760 param->lsp_pool = lsa.lsa_pool_name;
1761 param->lsp_is_specific = false;
1762 if (lsa.lsa_nr_osts > 0) {
1763 if (lsa.lsa_stripe_count > 0 &&
1764 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1765 fprintf(stderr, "error: %s: stripe count '%d' "
1766 "doesn't match the number of OSTs: %d\n"
1767 , argv[0], lsa.lsa_stripe_count,
1773 param->lsp_is_specific = true;
1774 param->lsp_stripe_count = lsa.lsa_nr_osts;
1775 memcpy(param->lsp_osts, osts,
1776 sizeof(*osts) * lsa.lsa_nr_osts);
1780 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1782 if (mdt_idx_arg != NULL) {
1783 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1784 op = "migrate mdt objects of";
1785 } else if (migrate_mode) {
1786 result = lfs_migrate(fname, migration_flags, param,
1788 op = "migrate ost objects of";
1789 } else if (comp_set != 0) {
1790 result = lfs_component_set(fname, comp_id,
1791 lsa.lsa_comp_flags);
1792 op = "modify component flags of";
1793 } else if (comp_del != 0) {
1794 result = lfs_component_del(fname, comp_id,
1795 lsa.lsa_comp_flags);
1796 op = "delete component of";
1797 } else if (comp_add != 0) {
1798 result = lfs_component_add(fname, layout);
1799 op = "add component to";
1800 } else if (layout != NULL) {
1801 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1807 op = "create composite";
1809 result = llapi_file_open_param(fname,
1816 op = "create striped";
1819 /* Save the first error encountered. */
1822 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1824 lsa.lsa_pool_name != NULL && result == EINVAL ?
1825 "OST not in pool?" : strerror(errno));
1831 llapi_layout_free(layout);
1834 llapi_layout_free(layout);
1838 static int lfs_poollist(int argc, char **argv)
1843 return llapi_poollist(argv[1]);
1846 static int set_time(time_t *time, time_t *set, char *str)
1853 else if (str[0] == '-')
1859 t = strtol(str, NULL, 0);
1860 if (*time < t * 24 * 60 * 60) {
1863 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1867 *set = *time - t * 24 * 60 * 60;
1870 static int name2uid(unsigned int *id, const char *name)
1872 struct passwd *passwd;
1874 passwd = getpwnam(name);
1877 *id = passwd->pw_uid;
1882 static int name2gid(unsigned int *id, const char *name)
1884 struct group *group;
1886 group = getgrnam(name);
1889 *id = group->gr_gid;
1894 static inline int name2projid(unsigned int *id, const char *name)
1899 static int uid2name(char **name, unsigned int id)
1901 struct passwd *passwd;
1903 passwd = getpwuid(id);
1906 *name = passwd->pw_name;
1911 static inline int gid2name(char **name, unsigned int id)
1913 struct group *group;
1915 group = getgrgid(id);
1918 *name = group->gr_name;
1923 static int name2layout(__u32 *layout, char *name)
1925 char *ptr, *layout_name;
1928 for (ptr = name; ; ptr = NULL) {
1929 layout_name = strtok(ptr, ",");
1930 if (layout_name == NULL)
1932 if (strcmp(layout_name, "released") == 0)
1933 *layout |= LOV_PATTERN_F_RELEASED;
1934 else if (strcmp(layout_name, "raid0") == 0)
1935 *layout |= LOV_PATTERN_RAID0;
1936 else if (strcmp(layout_name, "mdt") == 0)
1937 *layout |= LOV_PATTERN_MDT;
1944 static int lfs_find(int argc, char **argv)
1949 struct find_param param = {
1953 struct option long_opts[] = {
1954 { .val = 'A', .name = "atime", .has_arg = required_argument },
1955 { .val = LFS_COMP_COUNT_OPT,
1956 .name = "comp-count", .has_arg = required_argument },
1957 { .val = LFS_COMP_COUNT_OPT,
1958 .name = "component-count",
1959 .has_arg = required_argument },
1960 { .val = LFS_COMP_FLAGS_OPT,
1961 .name = "comp-flags", .has_arg = required_argument },
1962 { .val = LFS_COMP_FLAGS_OPT,
1963 .name = "component-flags",
1964 .has_arg = required_argument },
1965 { .val = LFS_COMP_START_OPT,
1966 .name = "comp-start", .has_arg = required_argument },
1967 { .val = LFS_COMP_START_OPT,
1968 .name = "component-start",
1969 .has_arg = required_argument },
1970 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1971 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1972 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1973 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1974 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1975 { .val = 'E', .name = "component-end",
1976 .has_arg = required_argument },
1977 { .val = 'g', .name = "gid", .has_arg = required_argument },
1978 { .val = 'G', .name = "group", .has_arg = required_argument },
1979 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1980 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1981 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1982 /*{"component-id", required_argument, 0, 'I'},*/
1983 { .val = 'L', .name = "layout", .has_arg = required_argument },
1984 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1985 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1986 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1987 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1988 { .val = 'n', .name = "name", .has_arg = required_argument },
1989 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1990 { .val = 'O', .name = "obd", .has_arg = required_argument },
1991 { .val = 'O', .name = "ost", .has_arg = required_argument },
1992 /* no short option for pool, p/P already used */
1993 { .val = LFS_POOL_OPT,
1994 .name = "pool", .has_arg = required_argument },
1995 { .val = 'p', .name = "print0", .has_arg = no_argument },
1996 { .val = 'P', .name = "print", .has_arg = no_argument },
1997 { .val = LFS_PROJID_OPT,
1998 .name = "projid", .has_arg = required_argument },
1999 { .val = 's', .name = "size", .has_arg = required_argument },
2000 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
2001 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
2002 { .val = 't', .name = "type", .has_arg = required_argument },
2003 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
2004 { .val = 'u', .name = "uid", .has_arg = required_argument },
2005 { .val = 'U', .name = "user", .has_arg = required_argument },
2017 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2018 while ((c = getopt_long_only(argc, argv,
2019 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2020 long_opts, NULL)) >= 0) {
2025 /* '!' is part of option */
2026 /* when getopt_long_only() finds a string which is not
2027 * an option nor a known option argument it returns 1
2028 * in that case if we already have found pathstart and pathend
2029 * (i.e. we have the list of pathnames),
2030 * the only supported value is "!"
2032 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2033 if (!isoption && pathend != -1) {
2034 fprintf(stderr, "err: %s: filename|dirname must either "
2035 "precede options or follow options\n",
2040 if (!isoption && pathstart == -1)
2041 pathstart = optind - 1;
2042 if (isoption && pathstart != -1 && pathend == -1)
2043 pathend = optind - 2;
2049 /* unknown; opt is "!" or path component,
2050 * checking done above.
2052 if (strcmp(optarg, "!") == 0)
2056 xtime = ¶m.fp_atime;
2057 xsign = ¶m.fp_asign;
2058 param.fp_exclude_atime = !!neg_opt;
2059 /* no break, this falls through to 'C' for ctime */
2062 xtime = ¶m.fp_ctime;
2063 xsign = ¶m.fp_csign;
2064 param.fp_exclude_ctime = !!neg_opt;
2066 /* no break, this falls through to 'M' for mtime */
2069 xtime = ¶m.fp_mtime;
2070 xsign = ¶m.fp_msign;
2071 param.fp_exclude_mtime = !!neg_opt;
2073 rc = set_time(&t, xtime, optarg);
2074 if (rc == INT_MAX) {
2081 case LFS_COMP_COUNT_OPT:
2082 if (optarg[0] == '+') {
2083 param.fp_comp_count_sign = -1;
2085 } else if (optarg[0] == '-') {
2086 param.fp_comp_count_sign = 1;
2090 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2091 if (*endptr != '\0') {
2092 fprintf(stderr, "error: bad component count "
2096 param.fp_check_comp_count = 1;
2097 param.fp_exclude_comp_count = !!neg_opt;
2099 case LFS_COMP_FLAGS_OPT:
2100 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2101 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2102 fprintf(stderr, "error: bad component flags "
2106 param.fp_check_comp_flags = 1;
2107 param.fp_exclude_comp_flags = !!neg_opt;
2109 case LFS_COMP_START_OPT:
2110 if (optarg[0] == '+') {
2111 param.fp_comp_start_sign = -1;
2113 } else if (optarg[0] == '-') {
2114 param.fp_comp_start_sign = 1;
2118 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2119 ¶m.fp_comp_start_units, 0);
2121 fprintf(stderr, "error: bad component start "
2125 param.fp_check_comp_start = 1;
2126 param.fp_exclude_comp_start = !!neg_opt;
2129 if (optarg[0] == '+') {
2130 param.fp_stripe_count_sign = -1;
2132 } else if (optarg[0] == '-') {
2133 param.fp_stripe_count_sign = 1;
2137 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2138 if (*endptr != '\0') {
2139 fprintf(stderr,"error: bad stripe_count '%s'\n",
2144 param.fp_check_stripe_count = 1;
2145 param.fp_exclude_stripe_count = !!neg_opt;
2148 param.fp_max_depth = strtol(optarg, 0, 0);
2151 if (optarg[0] == '+') {
2152 param.fp_comp_end_sign = -1;
2154 } else if (optarg[0] == '-') {
2155 param.fp_comp_end_sign = 1;
2159 if (arg_is_eof(optarg)) {
2160 param.fp_comp_end = LUSTRE_EOF;
2161 param.fp_comp_end_units = 1;
2164 rc = llapi_parse_size(optarg,
2166 ¶m.fp_comp_end_units, 0);
2169 fprintf(stderr, "error: bad component end "
2173 param.fp_check_comp_end = 1;
2174 param.fp_exclude_comp_end = !!neg_opt;
2178 rc = name2gid(¶m.fp_gid, optarg);
2180 param.fp_gid = strtoul(optarg, &endptr, 10);
2181 if (*endptr != '\0') {
2182 fprintf(stderr, "Group/GID: %s cannot "
2183 "be found.\n", optarg);
2188 param.fp_exclude_gid = !!neg_opt;
2189 param.fp_check_gid = 1;
2192 param.fp_hash_type = check_hashtype(optarg);
2193 if (param.fp_hash_type == 0) {
2194 fprintf(stderr, "error: bad hash_type '%s'\n",
2199 param.fp_check_hash_type = 1;
2200 param.fp_exclude_hash_type = !!neg_opt;
2203 ret = name2layout(¶m.fp_layout, optarg);
2206 param.fp_exclude_layout = !!neg_opt;
2207 param.fp_check_layout = 1;
2211 rc = name2uid(¶m.fp_uid, optarg);
2213 param.fp_uid = strtoul(optarg, &endptr, 10);
2214 if (*endptr != '\0') {
2215 fprintf(stderr, "User/UID: %s cannot "
2216 "be found.\n", optarg);
2221 param.fp_exclude_uid = !!neg_opt;
2222 param.fp_check_uid = 1;
2225 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2227 "Pool name %s is too long"
2228 " (max is %d)\n", optarg,
2233 /* we do check for empty pool because empty pool
2234 * is used to find V1 lov attributes */
2235 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2236 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2237 param.fp_exclude_pool = !!neg_opt;
2238 param.fp_check_pool = 1;
2241 param.fp_pattern = (char *)optarg;
2242 param.fp_exclude_pattern = !!neg_opt;
2247 char *buf, *token, *next, *p;
2251 buf = strdup(optarg);
2257 param.fp_exclude_obd = !!neg_opt;
2260 while (token && *token) {
2261 token = strchr(token, ',');
2268 param.fp_exclude_mdt = !!neg_opt;
2269 param.fp_num_alloc_mdts += len;
2270 tmp = realloc(param.fp_mdt_uuid,
2271 param.fp_num_alloc_mdts *
2272 sizeof(*param.fp_mdt_uuid));
2278 param.fp_mdt_uuid = tmp;
2280 param.fp_exclude_obd = !!neg_opt;
2281 param.fp_num_alloc_obds += len;
2282 tmp = realloc(param.fp_obd_uuid,
2283 param.fp_num_alloc_obds *
2284 sizeof(*param.fp_obd_uuid));
2290 param.fp_obd_uuid = tmp;
2292 for (token = buf; token && *token; token = next) {
2293 struct obd_uuid *puuid;
2296 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2299 ¶m.fp_obd_uuid[param.fp_num_obds++];
2301 p = strchr(token, ',');
2308 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2313 strncpy(puuid->uuid, token,
2314 sizeof(puuid->uuid));
2322 param.fp_zero_end = 1;
2326 case LFS_PROJID_OPT:
2327 rc = name2projid(¶m.fp_projid, optarg);
2329 param.fp_projid = strtoul(optarg, &endptr, 10);
2330 if (*endptr != '\0') {
2332 "Invalid project ID: %s",
2338 param.fp_exclude_projid = !!neg_opt;
2339 param.fp_check_projid = 1;
2342 if (optarg[0] == '+') {
2343 param.fp_size_sign = -1;
2345 } else if (optarg[0] == '-') {
2346 param.fp_size_sign = 1;
2350 ret = llapi_parse_size(optarg, ¶m.fp_size,
2351 ¶m.fp_size_units, 0);
2353 fprintf(stderr, "error: bad file size '%s'\n",
2357 param.fp_check_size = 1;
2358 param.fp_exclude_size = !!neg_opt;
2361 if (optarg[0] == '+') {
2362 param.fp_stripe_size_sign = -1;
2364 } else if (optarg[0] == '-') {
2365 param.fp_stripe_size_sign = 1;
2369 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2370 ¶m.fp_stripe_size_units, 0);
2372 fprintf(stderr, "error: bad stripe_size '%s'\n",
2376 param.fp_check_stripe_size = 1;
2377 param.fp_exclude_stripe_size = !!neg_opt;
2380 param.fp_exclude_type = !!neg_opt;
2381 switch (optarg[0]) {
2383 param.fp_type = S_IFBLK;
2386 param.fp_type = S_IFCHR;
2389 param.fp_type = S_IFDIR;
2392 param.fp_type = S_IFREG;
2395 param.fp_type = S_IFLNK;
2398 param.fp_type = S_IFIFO;
2401 param.fp_type = S_IFSOCK;
2404 fprintf(stderr, "error: %s: bad type '%s'\n",
2411 if (optarg[0] == '+') {
2412 param.fp_mdt_count_sign = -1;
2414 } else if (optarg[0] == '-') {
2415 param.fp_mdt_count_sign = 1;
2419 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2420 if (*endptr != '\0') {
2421 fprintf(stderr, "error: bad mdt_count '%s'\n",
2426 param.fp_check_mdt_count = 1;
2427 param.fp_exclude_mdt_count = !!neg_opt;
2435 if (pathstart == -1) {
2436 fprintf(stderr, "error: %s: no filename|pathname\n",
2440 } else if (pathend == -1) {
2446 rc = llapi_find(argv[pathstart], ¶m);
2447 if (rc != 0 && ret == 0)
2449 } while (++pathstart < pathend);
2452 fprintf(stderr, "error: %s failed for %s.\n",
2453 argv[0], argv[optind - 1]);
2455 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2456 free(param.fp_obd_uuid);
2458 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2459 free(param.fp_mdt_uuid);
2464 static int lfs_getstripe_internal(int argc, char **argv,
2465 struct find_param *param)
2467 struct option long_opts[] = {
2468 { .val = LFS_COMP_COUNT_OPT,
2469 .name = "comp-count", .has_arg = no_argument },
2470 { .val = LFS_COMP_COUNT_OPT,
2471 .name = "component-count", .has_arg = no_argument },
2472 { .val = LFS_COMP_FLAGS_OPT,
2473 .name = "comp-flags", .has_arg = optional_argument },
2474 { .val = LFS_COMP_FLAGS_OPT,
2475 .name = "component-flags", .has_arg = optional_argument },
2476 { .val = LFS_COMP_START_OPT,
2477 .name = "comp-start", .has_arg = optional_argument },
2478 { .val = LFS_COMP_START_OPT,
2479 .name = "component-start", .has_arg = optional_argument },
2480 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2481 /* This formerly implied "stripe-count", but was explicitly
2482 * made "stripe-count" for consistency with other options,
2483 * and to separate it from "mdt-count" when DNE arrives. */
2484 { .val = 'c', .name = "count", .has_arg = no_argument },
2486 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2487 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2488 { .val = 'd', .name = "directory", .has_arg = no_argument },
2489 { .val = 'D', .name = "default", .has_arg = no_argument },
2490 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2491 { .val = 'E', .name = "component-end",
2492 .has_arg = optional_argument },
2493 { .val = 'F', .name = "fid", .has_arg = no_argument },
2494 { .val = 'g', .name = "generation", .has_arg = no_argument },
2495 /* dirstripe { .val = 'H', .name = "mdt-hash",
2496 * .has_arg = required_argument }, */
2497 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2498 /* This formerly implied "stripe-index", but was explicitly
2499 * made "stripe-index" for consistency with other options,
2500 * and to separate it from "mdt-index" when DNE arrives. */
2501 { .val = 'i', .name = "index", .has_arg = no_argument },
2503 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2504 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2505 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2506 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2507 { .val = 'L', .name = "layout", .has_arg = no_argument },
2508 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2509 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2510 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2511 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2512 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2513 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2515 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2516 /* This formerly implied "stripe-index", but was confusing
2517 * with "file offset" (which will eventually be needed for
2518 * with different layouts by offset), so deprecate it. */
2519 { .val = 'o', .name = "offset", .has_arg = no_argument },
2521 { .val = 'O', .name = "obd", .has_arg = required_argument },
2522 { .val = 'O', .name = "ost", .has_arg = required_argument },
2523 { .val = 'p', .name = "pool", .has_arg = no_argument },
2524 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2525 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2526 { .val = 'R', .name = "raw", .has_arg = no_argument },
2527 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2528 /* This formerly implied "--stripe-size", but was confusing
2529 * with "lfs find --size|-s", which means "file size", so use
2530 * the consistent "--stripe-size|-S" for all commands. */
2531 { .val = 's', .name = "size", .has_arg = no_argument },
2533 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2534 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2535 /* dirstripe { .val = 'T', .name = "mdt-count",
2536 * .has_arg = required_argument }, */
2537 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2538 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2543 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2544 long_opts, NULL)) != -1) {
2547 if (strcmp(argv[optind - 1], "--count") == 0)
2548 fprintf(stderr, "warning: '--count' deprecated,"
2549 " use '--stripe-count' instead\n");
2550 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2551 param->fp_verbose |= VERBOSE_COUNT;
2552 param->fp_max_depth = 0;
2555 case LFS_COMP_COUNT_OPT:
2556 param->fp_verbose |= VERBOSE_COMP_COUNT;
2557 param->fp_max_depth = 0;
2559 case LFS_COMP_FLAGS_OPT:
2560 if (optarg != NULL) {
2561 __u32 *flags = ¶m->fp_comp_flags;
2562 rc = comp_str2flags(flags, optarg);
2564 fprintf(stderr, "error: %s bad "
2565 "component flags '%s'.\n",
2569 param->fp_check_comp_flags = 1;
2570 param->fp_exclude_comp_flags =
2571 comp_flags_is_neg(*flags);
2572 comp_flags_clear_neg(flags);
2575 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2576 param->fp_max_depth = 0;
2579 case LFS_COMP_START_OPT:
2580 if (optarg != NULL) {
2582 if (tmp[0] == '+') {
2583 param->fp_comp_start_sign = -1;
2585 } else if (tmp[0] == '-') {
2586 param->fp_comp_start_sign = 1;
2589 rc = llapi_parse_size(tmp,
2590 ¶m->fp_comp_start,
2591 ¶m->fp_comp_start_units, 0);
2593 fprintf(stderr, "error: %s bad "
2594 "component start '%s'.\n",
2598 param->fp_check_comp_start = 1;
2601 param->fp_verbose |= VERBOSE_COMP_START;
2602 param->fp_max_depth = 0;
2606 param->fp_max_depth = 0;
2609 param->fp_get_default_lmv = 1;
2612 if (optarg != NULL) {
2614 if (tmp[0] == '+') {
2615 param->fp_comp_end_sign = -1;
2617 } else if (tmp[0] == '-') {
2618 param->fp_comp_end_sign = 1;
2622 if (arg_is_eof(tmp)) {
2623 param->fp_comp_end = LUSTRE_EOF;
2624 param->fp_comp_end_units = 1;
2627 rc = llapi_parse_size(tmp,
2628 ¶m->fp_comp_end,
2629 ¶m->fp_comp_end_units, 0);
2632 fprintf(stderr, "error: %s bad "
2633 "component end '%s'.\n",
2637 param->fp_check_comp_end = 1;
2639 param->fp_verbose |= VERBOSE_COMP_END;
2640 param->fp_max_depth = 0;
2644 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2645 param->fp_verbose |= VERBOSE_DFID;
2646 param->fp_max_depth = 0;
2650 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2651 param->fp_verbose |= VERBOSE_GENERATION;
2652 param->fp_max_depth = 0;
2655 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2657 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2658 "use '--stripe-index|-i' instead\n");
2661 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2662 if (strcmp(argv[optind - 1], "--index") == 0)
2663 fprintf(stderr, "warning: '--index' deprecated"
2664 ", use '--stripe-index' instead\n");
2666 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2667 param->fp_verbose |= VERBOSE_OFFSET;
2668 param->fp_max_depth = 0;
2672 if (optarg != NULL) {
2673 param->fp_comp_id = strtoul(optarg, &end, 0);
2674 if (*end != '\0' || param->fp_comp_id == 0 ||
2675 param->fp_comp_id > LCME_ID_MAX) {
2676 fprintf(stderr, "error: %s bad "
2677 "component id '%s'\n",
2681 param->fp_check_comp_id = 1;
2684 param->fp_max_depth = 0;
2685 param->fp_verbose |= VERBOSE_COMP_ID;
2689 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2690 param->fp_verbose |= VERBOSE_LAYOUT;
2691 param->fp_max_depth = 0;
2694 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2696 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2697 fprintf(stderr, "warning: '-M' deprecated"
2698 ", use '-m' instead\n");
2702 if (!(param->fp_verbose & VERBOSE_DETAIL))
2703 param->fp_max_depth = 0;
2704 param->fp_verbose |= VERBOSE_MDTINDEX;
2707 if (param->fp_obd_uuid) {
2709 "error: %s: only one obduuid allowed",
2713 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2716 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2717 param->fp_verbose |= VERBOSE_POOL;
2718 param->fp_max_depth = 0;
2725 param->fp_recursive = 1;
2730 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2732 fprintf(stderr, "warning: '--size|-s' deprecated, "
2733 "use '--stripe-size|-S' instead\n");
2734 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2736 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2737 param->fp_verbose |= VERBOSE_SIZE;
2738 param->fp_max_depth = 0;
2742 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2755 if (param->fp_recursive)
2756 param->fp_max_depth = -1;
2757 else if (param->fp_verbose & VERBOSE_DETAIL)
2758 param->fp_max_depth = 1;
2760 if (!param->fp_verbose)
2761 param->fp_verbose = VERBOSE_DEFAULT;
2762 if (param->fp_quiet)
2763 param->fp_verbose = VERBOSE_OBJID;
2766 rc = llapi_getstripe(argv[optind], param);
2767 } while (++optind < argc && !rc);
2770 fprintf(stderr, "error: %s failed for %s.\n",
2771 argv[0], argv[optind - 1]);
2775 static int lfs_tgts(int argc, char **argv)
2777 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2778 struct find_param param;
2779 int index = 0, rc=0;
2784 if (argc == 2 && !realpath(argv[1], path)) {
2786 fprintf(stderr, "error: invalid path '%s': %s\n",
2787 argv[1], strerror(-rc));
2791 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2792 /* Check if we have a mount point */
2793 if (mntdir[0] == '\0')
2796 memset(¶m, 0, sizeof(param));
2797 if (!strcmp(argv[0], "mdts"))
2798 param.fp_get_lmv = 1;
2800 rc = llapi_ostlist(mntdir, ¶m);
2802 fprintf(stderr, "error: %s: failed on %s\n",
2805 if (path[0] != '\0')
2807 memset(mntdir, 0, PATH_MAX);
2813 static int lfs_getstripe(int argc, char **argv)
2815 struct find_param param = { 0 };
2817 param.fp_max_depth = 1;
2818 return lfs_getstripe_internal(argc, argv, ¶m);
2822 static int lfs_getdirstripe(int argc, char **argv)
2824 struct find_param param = { 0 };
2825 struct option long_opts[] = {
2826 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2827 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2829 { .val = 'D', .name = "default", .has_arg = no_argument },
2830 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2831 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2832 { .val = 'O', .name = "obd", .has_arg = required_argument },
2833 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2834 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2835 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2837 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2838 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2842 param.fp_get_lmv = 1;
2844 while ((c = getopt_long(argc, argv,
2845 "cDHiO:rtTy", long_opts, NULL)) != -1)
2849 if (param.fp_obd_uuid) {
2851 "error: %s: only one obduuid allowed",
2855 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2857 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2859 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2860 fprintf(stderr, "warning: '-c' deprecated"
2861 ", use '-T' instead\n");
2865 param.fp_verbose |= VERBOSE_COUNT;
2868 param.fp_verbose |= VERBOSE_OFFSET;
2870 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2874 param.fp_verbose |= VERBOSE_HASH_TYPE;
2877 param.fp_get_default_lmv = 1;
2880 param.fp_recursive = 1;
2893 if (param.fp_recursive)
2894 param.fp_max_depth = -1;
2896 if (!param.fp_verbose)
2897 param.fp_verbose = VERBOSE_DEFAULT;
2900 rc = llapi_getstripe(argv[optind], ¶m);
2901 } while (++optind < argc && !rc);
2904 fprintf(stderr, "error: %s failed for %s.\n",
2905 argv[0], argv[optind - 1]);
2910 static int lfs_setdirstripe(int argc, char **argv)
2914 unsigned int stripe_offset = -1;
2915 unsigned int stripe_count = 1;
2916 enum lmv_hash_type hash_type;
2919 char *stripe_offset_opt = NULL;
2920 char *stripe_count_opt = NULL;
2921 char *stripe_hash_opt = NULL;
2922 char *mode_opt = NULL;
2923 bool default_stripe = false;
2924 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2925 mode_t previous_mode = 0;
2926 bool delete = false;
2928 struct option long_opts[] = {
2929 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2930 { .val = 'c', .name = "count", .has_arg = required_argument },
2932 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2933 { .val = 'd', .name = "delete", .has_arg = no_argument },
2934 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2935 { .val = 'i', .name = "index", .has_arg = required_argument },
2937 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2938 { .val = 'm', .name = "mode", .has_arg = required_argument },
2939 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2940 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2941 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2943 {"mdt-hash", required_argument, 0, 'H'},
2944 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2945 { .val = 'D', .name = "default_stripe",
2946 .has_arg = no_argument },
2948 { .val = 'D', .name = "default", .has_arg = no_argument },
2951 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2958 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2959 if (strcmp(argv[optind - 1], "--count") == 0)
2961 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
2964 stripe_count_opt = optarg;
2968 default_stripe = true;
2971 default_stripe = true;
2974 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2975 if (strcmp(argv[optind - 1], "--index") == 0)
2977 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
2980 stripe_offset_opt = optarg;
2985 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2989 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2990 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2992 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
2995 stripe_hash_opt = optarg;
2998 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2999 progname, argv[0], argv[optind - 1]);
3004 if (optind == argc) {
3005 fprintf(stderr, "%s %s: DIR must be specified\n",
3010 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
3012 "%s %s: stripe offset and count must be specified\n",
3017 if (stripe_offset_opt != NULL) {
3018 /* get the stripe offset */
3019 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
3022 "%s %s: bad stripe offset '%s'\n",
3023 progname, argv[0], stripe_offset_opt);
3029 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3031 "%s %s: cannot specify -d with -c or -i options\n",
3040 if (mode_opt != NULL) {
3041 mode = strtoul(mode_opt, &end, 8);
3044 "%s %s: bad MODE '%s'\n",
3045 progname, argv[0], mode_opt);
3048 previous_mode = umask(0);
3051 if (stripe_hash_opt == NULL) {
3052 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3054 hash_type = check_hashtype(stripe_hash_opt);
3055 if (hash_type == 0) {
3056 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3057 progname, argv[0], stripe_hash_opt);
3062 /* get the stripe count */
3063 if (stripe_count_opt != NULL) {
3064 stripe_count = strtoul(stripe_count_opt, &end, 0);
3067 "%s %s: bad stripe count '%s'\n",
3068 progname, argv[0], stripe_count_opt);
3073 dname = argv[optind];
3075 if (default_stripe) {
3076 result = llapi_dir_set_default_lmv_stripe(dname,
3077 stripe_offset, stripe_count,
3080 result = llapi_dir_create_pool(dname, mode,
3082 stripe_count, hash_type,
3088 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3089 progname, dname, strerror(-result));
3092 dname = argv[++optind];
3093 } while (dname != NULL);
3095 if (mode_opt != NULL)
3096 umask(previous_mode);
3102 static int lfs_rmentry(int argc, char **argv)
3109 fprintf(stderr, "error: %s: missing dirname\n",
3115 dname = argv[index];
3116 while (dname != NULL) {
3117 result = llapi_direntry_remove(dname);
3119 fprintf(stderr, "error: %s: remove dir entry '%s' "
3120 "failed\n", argv[0], dname);
3123 dname = argv[++index];
3128 static int lfs_mv(int argc, char **argv)
3130 struct find_param param = {
3137 struct option long_opts[] = {
3138 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3139 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3142 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3145 param.fp_mdt_index = strtoul(optarg, &end, 0);
3147 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3154 param.fp_verbose = VERBOSE_DETAIL;
3158 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3159 argv[0], argv[optind - 1]);
3164 if (param.fp_mdt_index == -1) {
3165 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3169 if (optind >= argc) {
3170 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3174 param.fp_migrate = 1;
3175 rc = llapi_migrate_mdt(argv[optind], ¶m);
3177 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3178 argv[0], argv[optind], param.fp_mdt_index,
3183 static int lfs_osts(int argc, char **argv)
3185 return lfs_tgts(argc, argv);
3188 static int lfs_mdts(int argc, char **argv)
3190 return lfs_tgts(argc, argv);
3193 #define COOK(value) \
3196 while (value > 1024) { \
3204 #define CDF "%11llu"
3205 #define HDF "%8.1f%c"
3210 MNTDF_INODES = 0x0001,
3211 MNTDF_COOKED = 0x0002,
3212 MNTDF_LAZY = 0x0004,
3213 MNTDF_VERBOSE = 0x0008,
3216 static int showdf(char *mntdir, struct obd_statfs *stat,
3217 char *uuid, enum mntdf_flags flags,
3218 char *type, int index, int rc)
3220 long long avail, used, total;
3222 char *suffix = "KMGTPEZY";
3223 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3224 char tbuf[3 * sizeof(__u64)];
3225 char ubuf[3 * sizeof(__u64)];
3226 char abuf[3 * sizeof(__u64)];
3227 char rbuf[3 * sizeof(__u64)];
3234 if (flags & MNTDF_INODES) {
3235 avail = stat->os_ffree;
3236 used = stat->os_files - stat->os_ffree;
3237 total = stat->os_files;
3239 int shift = flags & MNTDF_COOKED ? 0 : 10;
3241 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3242 used = ((stat->os_blocks - stat->os_bfree) *
3243 stat->os_bsize) >> shift;
3244 total = (stat->os_blocks * stat->os_bsize) >> shift;
3247 if ((used + avail) > 0)
3248 ratio = (double)used / (double)(used + avail);
3250 if (flags & MNTDF_COOKED) {
3254 cook_val = (double)total;
3257 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3260 snprintf(tbuf, sizeof(tbuf), CDF, total);
3262 cook_val = (double)used;
3265 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3268 snprintf(ubuf, sizeof(ubuf), CDF, used);
3270 cook_val = (double)avail;
3273 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3276 snprintf(abuf, sizeof(abuf), CDF, avail);
3278 snprintf(tbuf, sizeof(tbuf), CDF, total);
3279 snprintf(ubuf, sizeof(tbuf), CDF, used);
3280 snprintf(abuf, sizeof(tbuf), CDF, avail);
3283 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3284 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3285 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3287 printf("[%s:%d]", type, index);
3289 if (stat->os_state) {
3291 * Each character represents the matching
3294 const char state_names[] = "DRSI";
3299 for (i = 0, state = stat->os_state;
3300 state && i < sizeof(state_names); i++) {
3301 if (!(state & (1 << i)))
3303 printf("%c", state_names[i]);
3311 printf(UUF": inactive device\n", uuid);
3314 printf(UUF": %s\n", uuid, strerror(-rc));
3321 struct ll_stat_type {
3326 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3328 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3329 struct obd_uuid uuid_buf;
3330 char *poolname = NULL;
3331 struct ll_stat_type types[] = {
3332 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3333 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3334 { .st_name = NULL } };
3335 struct ll_stat_type *tp;
3336 __u64 ost_ffree = 0;
3344 poolname = strchr(pool, '.');
3345 if (poolname != NULL) {
3346 if (strncmp(fsname, pool, strlen(fsname))) {
3347 fprintf(stderr, "filesystem name incorrect\n");
3355 fd = open(mntdir, O_RDONLY);
3358 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3363 if (flags & MNTDF_INODES)
3364 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3365 "UUID", "Inodes", "IUsed", "IFree",
3366 "IUse%", "Mounted on");
3368 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3369 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3370 "Used", "Available", "Use%", "Mounted on");
3372 for (tp = types; tp->st_name != NULL; tp++) {
3373 for (index = 0; ; index++) {
3374 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3375 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3376 type = flags & MNTDF_LAZY ?
3377 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3378 rc2 = llapi_obd_fstatfs(fd, type, index,
3379 &stat_buf, &uuid_buf);
3384 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3385 if (!(flags & MNTDF_VERBOSE))
3387 } else if (rc2 < 0 && rc == 0) {
3391 if (poolname && tp->st_op == LL_STATFS_LOV &&
3392 llapi_search_ost(fsname, poolname,
3393 obd_uuid2str(&uuid_buf)) != 1)
3396 /* the llapi_obd_statfs() call may have returned with
3397 * an error, but if it filled in uuid_buf we will at
3398 * lease use that to print out a message for that OBD.
3399 * If we didn't get anything in the uuid_buf, then fill
3400 * it in so that we can print an error message. */
3401 if (uuid_buf.uuid[0] == '\0')
3402 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3403 "%s%04x", tp->st_name, index);
3404 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3405 flags, tp->st_name, index, rc2);
3408 if (tp->st_op == LL_STATFS_LMV) {
3409 sum.os_ffree += stat_buf.os_ffree;
3410 sum.os_files += stat_buf.os_files;
3411 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3412 sum.os_blocks += stat_buf.os_blocks *
3414 sum.os_bfree += stat_buf.os_bfree *
3416 sum.os_bavail += stat_buf.os_bavail *
3418 ost_ffree += stat_buf.os_ffree;
3426 /* If we don't have as many objects free on the OST as inodes
3427 * on the MDS, we reduce the total number of inodes to
3428 * compensate, so that the "inodes in use" number is correct.
3429 * Matches ll_statfs_internal() so the results are consistent. */
3430 if (ost_ffree < sum.os_ffree) {
3431 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3432 sum.os_ffree = ost_ffree;
3435 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3441 static int lfs_df(int argc, char **argv)
3443 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3444 enum mntdf_flags flags = 0;
3445 int c, rc = 0, index = 0;
3446 char fsname[PATH_MAX] = "", *pool_name = NULL;
3447 struct option long_opts[] = {
3448 { .val = 'h', .name = "human-readable",
3449 .has_arg = no_argument },
3450 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3451 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3452 { .val = 'p', .name = "pool", .has_arg = required_argument },
3453 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3456 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3459 flags |= MNTDF_COOKED;
3462 flags |= MNTDF_INODES;
3465 flags |= MNTDF_LAZY;
3471 flags |= MNTDF_VERBOSE;
3477 if (optind < argc && !realpath(argv[optind], path)) {
3479 fprintf(stderr, "error: invalid path '%s': %s\n",
3480 argv[optind], strerror(-rc));
3484 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3485 /* Check if we have a mount point */
3486 if (mntdir[0] == '\0')
3489 rc = mntdf(mntdir, fsname, pool_name, flags);
3490 if (rc || path[0] != '\0')
3492 fsname[0] = '\0'; /* avoid matching in next loop */
3493 mntdir[0] = '\0'; /* avoid matching in next loop */
3499 static int lfs_getname(int argc, char **argv)
3501 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3502 int rc = 0, index = 0, c;
3503 char buf[sizeof(struct obd_uuid)];
3505 while ((c = getopt(argc, argv, "h")) != -1)
3508 if (optind == argc) { /* no paths specified, get all paths. */
3509 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3510 rc = llapi_getname(mntdir, buf, sizeof(buf));
3513 "cannot get name for `%s': %s\n",
3514 mntdir, strerror(-rc));
3518 printf("%s %s\n", buf, mntdir);
3520 path[0] = fsname[0] = mntdir[0] = 0;
3522 } else { /* paths specified, only attempt to search these. */
3523 for (; optind < argc; optind++) {
3524 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3527 "cannot get name for `%s': %s\n",
3528 argv[optind], strerror(-rc));
3532 printf("%s %s\n", buf, argv[optind]);
3538 static int lfs_check(int argc, char **argv)
3541 char mntdir[PATH_MAX] = {'\0'};
3550 obd_types[0] = obd_type1;
3551 obd_types[1] = obd_type2;
3553 if (strcmp(argv[1], "osts") == 0) {
3554 strcpy(obd_types[0], "osc");
3555 } else if (strcmp(argv[1], "mds") == 0) {
3556 strcpy(obd_types[0], "mdc");
3557 } else if (strcmp(argv[1], "servers") == 0) {
3559 strcpy(obd_types[0], "osc");
3560 strcpy(obd_types[1], "mdc");
3562 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3567 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3568 if (rc < 0 || mntdir[0] == '\0') {
3569 fprintf(stderr, "No suitable Lustre mount found\n");
3573 rc = llapi_target_check(num_types, obd_types, mntdir);
3575 fprintf(stderr, "error: %s: %s status failed\n",
3582 #ifdef HAVE_SYS_QUOTA_H
3583 #define ARG2INT(nr, str, msg) \
3586 nr = strtol(str, &endp, 0); \
3588 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3593 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3595 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3596 * returns the value or ULONG_MAX on integer overflow or incorrect format
3598 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3599 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3600 * 3. empty integer value is interpreted as 0
3602 static unsigned long str2sec(const char* timestr)
3604 const char spec[] = "smhdw";
3605 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3606 unsigned long val = 0;
3609 if (strpbrk(timestr, spec) == NULL) {
3610 /* no specifiers inside the time string,
3611 should treat it as an integer value */
3612 val = strtoul(timestr, &tail, 10);
3613 return *tail ? ULONG_MAX : val;
3616 /* format string is XXwXXdXXhXXmXXs */
3622 v = strtoul(timestr, &tail, 10);
3623 if (v == ULONG_MAX || *tail == '\0')
3624 /* value too large (ULONG_MAX or more)
3625 or missing specifier */
3628 ptr = strchr(spec, *tail);
3630 /* unknown specifier */
3635 /* check if product will overflow the type */
3636 if (!(v < ULONG_MAX / mult[ind]))
3639 ADD_OVERFLOW(val, mult[ind] * v);
3640 if (val == ULONG_MAX)
3652 #define ARG2ULL(nr, str, def_units) \
3654 unsigned long long limit, units = def_units; \
3657 rc = llapi_parse_size(str, &limit, &units, 1); \
3659 fprintf(stderr, "error: bad limit value %s\n", str); \
3665 static inline int has_times_option(int argc, char **argv)
3669 for (i = 1; i < argc; i++)
3670 if (!strcmp(argv[i], "-t"))
3676 int lfs_setquota_times(int argc, char **argv)
3679 struct if_quotactl qctl;
3680 char *mnt, *obd_type = (char *)qctl.obd_type;
3681 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3682 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3683 struct option long_opts[] = {
3684 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3685 { .val = 'g', .name = "group", .has_arg = no_argument },
3686 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3687 { .val = 'p', .name = "projid", .has_arg = no_argument },
3688 { .val = 't', .name = "times", .has_arg = no_argument },
3689 { .val = 'u', .name = "user", .has_arg = no_argument },
3693 memset(&qctl, 0, sizeof(qctl));
3694 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3695 qctl.qc_type = ALLQUOTA;
3697 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3698 long_opts, NULL)) != -1) {
3709 if (qctl.qc_type != ALLQUOTA) {
3710 fprintf(stderr, "error: -u/g/p can't be used "
3711 "more than once\n");
3714 qctl.qc_type = qtype;
3717 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3718 fprintf(stderr, "error: bad block-grace: %s\n",
3722 dqb->dqb_valid |= QIF_BTIME;
3725 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3726 fprintf(stderr, "error: bad inode-grace: %s\n",
3730 dqb->dqb_valid |= QIF_ITIME;
3732 case 't': /* Yes, of course! */
3734 default: /* getopt prints error message for us when opterr != 0 */
3739 if (qctl.qc_type == ALLQUOTA) {
3740 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3744 if (optind != argc - 1) {
3745 fprintf(stderr, "error: unexpected parameters encountered\n");
3750 rc = llapi_quotactl(mnt, &qctl);
3753 fprintf(stderr, "%s %s ", obd_type,
3754 obd_uuid2str(&qctl.obd_uuid));
3755 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3762 #define BSLIMIT (1 << 0)
3763 #define BHLIMIT (1 << 1)
3764 #define ISLIMIT (1 << 2)
3765 #define IHLIMIT (1 << 3)
3767 int lfs_setquota(int argc, char **argv)
3770 struct if_quotactl qctl;
3771 char *mnt, *obd_type = (char *)qctl.obd_type;
3772 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3773 struct option long_opts[] = {
3774 { .val = 'b', .name = "block-softlimit",
3775 .has_arg = required_argument },
3776 { .val = 'B', .name = "block-hardlimit",
3777 .has_arg = required_argument },
3778 { .val = 'g', .name = "group", .has_arg = required_argument },
3779 { .val = 'i', .name = "inode-softlimit",
3780 .has_arg = required_argument },
3781 { .val = 'I', .name = "inode-hardlimit",
3782 .has_arg = required_argument },
3783 { .val = 'p', .name = "projid", .has_arg = required_argument },
3784 { .val = 'u', .name = "user", .has_arg = required_argument },
3786 unsigned limit_mask = 0;
3790 if (has_times_option(argc, argv))
3791 return lfs_setquota_times(argc, argv);
3793 memset(&qctl, 0, sizeof(qctl));
3794 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3795 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3796 * so it can be used as a marker that qc_type
3797 * isn't reinitialized from command line */
3799 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3800 long_opts, NULL)) != -1) {
3804 rc = name2uid(&qctl.qc_id, optarg);
3808 rc = name2gid(&qctl.qc_id, optarg);
3812 rc = name2projid(&qctl.qc_id, optarg);
3814 if (qctl.qc_type != ALLQUOTA) {
3815 fprintf(stderr, "error: -u and -g can't be used"
3816 " more than once\n");
3819 qctl.qc_type = qtype;
3821 qctl.qc_id = strtoul(optarg, &endptr, 10);
3822 if (*endptr != '\0') {
3823 fprintf(stderr, "error: can't find id "
3824 "for name %s\n", optarg);
3830 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3831 dqb->dqb_bsoftlimit >>= 10;
3832 limit_mask |= BSLIMIT;
3833 if (dqb->dqb_bsoftlimit &&
3834 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3835 fprintf(stderr, "warning: block softlimit is "
3836 "smaller than the miminal qunit size, "
3837 "please see the help of setquota or "
3838 "Lustre manual for details.\n");
3841 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3842 dqb->dqb_bhardlimit >>= 10;
3843 limit_mask |= BHLIMIT;
3844 if (dqb->dqb_bhardlimit &&
3845 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3846 fprintf(stderr, "warning: block hardlimit is "
3847 "smaller than the miminal qunit size, "
3848 "please see the help of setquota or "
3849 "Lustre manual for details.\n");
3852 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3853 limit_mask |= ISLIMIT;
3854 if (dqb->dqb_isoftlimit &&
3855 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3856 fprintf(stderr, "warning: inode softlimit is "
3857 "smaller than the miminal qunit size, "
3858 "please see the help of setquota or "
3859 "Lustre manual for details.\n");
3862 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3863 limit_mask |= IHLIMIT;
3864 if (dqb->dqb_ihardlimit &&
3865 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3866 fprintf(stderr, "warning: inode hardlimit is "
3867 "smaller than the miminal qunit size, "
3868 "please see the help of setquota or "
3869 "Lustre manual for details.\n");
3871 default: /* getopt prints error message for us when opterr != 0 */
3876 if (qctl.qc_type == ALLQUOTA) {
3877 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3881 if (limit_mask == 0) {
3882 fprintf(stderr, "error: at least one limit must be specified\n");
3886 if (optind != argc - 1) {
3887 fprintf(stderr, "error: unexpected parameters encountered\n");
3893 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3894 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3895 /* sigh, we can't just set blimits/ilimits */
3896 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3897 .qc_type = qctl.qc_type,
3898 .qc_id = qctl.qc_id};
3900 rc = llapi_quotactl(mnt, &tmp_qctl);
3902 fprintf(stderr, "error: setquota failed while retrieving"
3903 " current quota settings (%s)\n",
3908 if (!(limit_mask & BHLIMIT))
3909 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3910 if (!(limit_mask & BSLIMIT))
3911 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3912 if (!(limit_mask & IHLIMIT))
3913 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3914 if (!(limit_mask & ISLIMIT))
3915 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3917 /* Keep grace times if we have got no softlimit arguments */
3918 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3919 dqb->dqb_valid |= QIF_BTIME;
3920 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3923 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3924 dqb->dqb_valid |= QIF_ITIME;
3925 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3929 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3930 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3932 rc = llapi_quotactl(mnt, &qctl);
3935 fprintf(stderr, "%s %s ", obd_type,
3936 obd_uuid2str(&qctl.obd_uuid));
3937 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3944 /* Converts seconds value into format string
3945 * result is returned in buf
3947 * 1. result is in descenting order: 1w2d3h4m5s
3948 * 2. zero fields are not filled (except for p. 3): 5d1s
3949 * 3. zero seconds value is presented as "0s"
3951 static char * __sec2str(time_t seconds, char *buf)
3953 const char spec[] = "smhdw";
3954 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3959 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3960 c = seconds / mult[i];
3962 if (c > 0 || (i == 0 && buf == tail))
3963 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3971 static void sec2str(time_t seconds, char *buf, int rc)
3978 tail = __sec2str(seconds, tail);
3980 if (rc && tail - buf < 39) {
3986 static void diff2str(time_t seconds, char *buf, time_t now)
3992 if (seconds <= now) {
3993 strcpy(buf, "none");
3996 __sec2str(seconds - now, buf);
3999 static void print_quota_title(char *name, struct if_quotactl *qctl,
4000 bool human_readable)
4002 printf("Disk quotas for %s %s (%cid %u):\n",
4003 qtype_name(qctl->qc_type), name,
4004 *qtype_name(qctl->qc_type), qctl->qc_id);
4005 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4006 "Filesystem", human_readable ? "used" : "kbytes",
4007 "quota", "limit", "grace",
4008 "files", "quota", "limit", "grace");
4011 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4014 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4017 snprintf(buf, buflen, "%5.4gP",
4018 (double)num / ((__u64)1 << 40));
4020 snprintf(buf, buflen, "%5.4gT",
4021 (double)num / (1 << 30));
4023 snprintf(buf, buflen, "%5.4gG",
4024 (double)num / (1 << 20));
4026 snprintf(buf, buflen, "%5.4gM",
4027 (double)num / (1 << 10));
4029 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4033 #define STRBUF_LEN 32
4034 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4041 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4042 int bover = 0, iover = 0;
4043 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4044 char numbuf[3][STRBUF_LEN];
4046 char strbuf[STRBUF_LEN];
4048 if (dqb->dqb_bhardlimit &&
4049 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4051 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4052 if (dqb->dqb_btime > now) {
4059 if (dqb->dqb_ihardlimit &&
4060 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4062 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4063 if (dqb->dqb_itime > now) {
4071 if (strlen(mnt) > 15)
4072 printf("%s\n%15s", mnt, "");
4074 printf("%15s", mnt);
4077 diff2str(dqb->dqb_btime, timebuf, now);
4079 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4080 strbuf, sizeof(strbuf), h);
4081 if (rc == -EREMOTEIO)
4082 sprintf(numbuf[0], "%s*", strbuf);
4084 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4085 "%s" : "[%s]", strbuf);
4087 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4088 if (type == QC_GENERAL)
4089 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4090 "%s" : "[%s]", strbuf);
4092 sprintf(numbuf[1], "%s", "-");
4094 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4095 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4096 "%s" : "[%s]", strbuf);
4098 printf(" %7s%c %6s %7s %7s",
4099 numbuf[0], bover ? '*' : ' ', numbuf[1],
4100 numbuf[2], bover > 1 ? timebuf : "-");
4103 diff2str(dqb->dqb_itime, timebuf, now);
4105 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4106 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4108 if (type == QC_GENERAL)
4109 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4111 (uintmax_t)dqb->dqb_isoftlimit);
4113 sprintf(numbuf[1], "%s", "-");
4115 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4116 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4118 if (type != QC_OSTIDX)
4119 printf(" %7s%c %6s %7s %7s",
4120 numbuf[0], iover ? '*' : ' ', numbuf[1],
4121 numbuf[2], iover > 1 ? timebuf : "-");
4123 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4126 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4127 qctl->qc_cmd == Q_GETOINFO) {
4131 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4132 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4133 printf("Block grace time: %s; Inode grace time: %s\n",
4134 bgtimebuf, igtimebuf);
4138 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4139 bool h, __u64 *total)
4141 int rc = 0, rc1 = 0, count = 0;
4142 __u32 valid = qctl->qc_valid;
4144 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4146 fprintf(stderr, "can not get %s count: %s\n",
4147 is_mdt ? "mdt": "ost", strerror(-rc));
4151 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4152 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4153 rc = llapi_quotactl(mnt, qctl);
4155 /* It is remote client case. */
4156 if (rc == -EOPNOTSUPP) {
4163 fprintf(stderr, "quotactl %s%d failed.\n",
4164 is_mdt ? "mdt": "ost", qctl->qc_idx);
4168 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4169 qctl->qc_valid, 0, h);
4170 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4171 qctl->qc_dqblk.dqb_bhardlimit;
4174 qctl->qc_valid = valid;
4178 static int lfs_quota(int argc, char **argv)
4181 char *mnt, *name = NULL;
4182 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4183 .qc_type = ALLQUOTA };
4184 char *obd_type = (char *)qctl.obd_type;
4185 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4186 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4187 verbose = 0, pass = 0, quiet = 0, inacc;
4189 __u32 valid = QC_GENERAL, idx = 0;
4190 __u64 total_ialloc = 0, total_balloc = 0;
4191 bool human_readable = false;
4194 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4205 if (qctl.qc_type != ALLQUOTA) {
4206 fprintf(stderr, "error: use either -u or -g\n");
4209 qctl.qc_type = qtype;
4212 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4215 valid = qctl.qc_valid = QC_UUID;
4216 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4219 valid = qctl.qc_valid = QC_MDTIDX;
4220 idx = qctl.qc_idx = atoi(optarg);
4223 valid = qctl.qc_valid = QC_OSTIDX;
4224 idx = qctl.qc_idx = atoi(optarg);
4233 human_readable = true;
4236 fprintf(stderr, "error: %s: option '-%c' "
4237 "unrecognized\n", argv[0], c);
4242 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4243 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4244 optind == argc - 1) {
4246 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4247 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4248 qctl.qc_valid = valid;
4250 qctl.qc_type = pass;
4251 switch (qctl.qc_type) {
4253 qctl.qc_id = geteuid();
4254 rc = uid2name(&name, qctl.qc_id);
4257 qctl.qc_id = getegid();
4258 rc = gid2name(&name, qctl.qc_id);
4267 /* lfs quota -u username /path/to/lustre/mount */
4268 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4269 /* options should be followed by u/g-name and mntpoint */
4270 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4271 fprintf(stderr, "error: missing quota argument(s)\n");
4275 name = argv[optind++];
4276 switch (qctl.qc_type) {
4278 rc = name2uid(&qctl.qc_id, name);
4281 rc = name2gid(&qctl.qc_id, name);
4284 rc = name2projid(&qctl.qc_id, name);
4291 qctl.qc_id = strtoul(name, &endptr, 10);
4292 if (*endptr != '\0') {
4293 fprintf(stderr, "error: can't find id for name: %s\n",
4298 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4299 fprintf(stderr, "error: missing quota info argument(s)\n");
4304 rc1 = llapi_quotactl(mnt, &qctl);
4308 fprintf(stderr, "%s quotas are not enabled.\n",
4309 qtype_name(qctl.qc_type));
4312 fprintf(stderr, "Permission denied.\n");
4315 /* We already got error message. */
4318 fprintf(stderr, "Unexpected quotactl error: %s\n",
4323 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4324 print_quota_title(name, &qctl, human_readable);
4326 if (rc1 && *obd_type)
4327 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4329 if (qctl.qc_valid != QC_GENERAL)
4332 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4333 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4334 (QIF_LIMITS|QIF_USAGE));
4336 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4338 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4340 char strbuf[STRBUF_LEN];
4342 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4344 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4346 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4348 printf("Total allocated inode limit: %ju, total "
4349 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4353 if (rc1 || rc2 || rc3 || inacc)
4354 printf("Some errors happened when getting quota info. "
4355 "Some devices may be not working or deactivated. "
4356 "The data in \"[]\" is inaccurate.\n");
4359 if (pass > 0 && pass < LL_MAXQUOTAS)
4364 #endif /* HAVE_SYS_QUOTA_H! */
4366 static int flushctx_ioctl(char *mp)
4370 fd = open(mp, O_RDONLY);
4372 fprintf(stderr, "flushctx: error open %s: %s\n",
4373 mp, strerror(errno));
4377 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4379 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4380 mp, strerror(errno));
4386 static int lfs_flushctx(int argc, char **argv)
4388 int kdestroy = 0, c;
4389 char mntdir[PATH_MAX] = {'\0'};
4393 while ((c = getopt(argc, argv, "k")) != -1) {
4399 fprintf(stderr, "error: %s: option '-%c' "
4400 "unrecognized\n", argv[0], c);
4406 if ((rc = system("kdestroy > /dev/null")) != 0) {
4407 rc = WEXITSTATUS(rc);
4408 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4412 if (optind >= argc) {
4413 /* flush for all mounted lustre fs. */
4414 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4415 /* Check if we have a mount point */
4416 if (mntdir[0] == '\0')
4419 if (flushctx_ioctl(mntdir))
4422 mntdir[0] = '\0'; /* avoid matching in next loop */
4425 /* flush fs as specified */
4426 while (optind < argc) {
4427 if (flushctx_ioctl(argv[optind++]))
4434 static int lfs_cp(int argc, char **argv)
4436 fprintf(stderr, "remote client copy file(s).\n"
4437 "obsolete, does not support it anymore.\n");
4441 static int lfs_ls(int argc, char **argv)
4443 fprintf(stderr, "remote client lists directory contents.\n"
4444 "obsolete, does not support it anymore.\n");
4448 static int lfs_changelog(int argc, char **argv)
4450 void *changelog_priv;
4451 struct changelog_rec *rec;
4452 long long startrec = 0, endrec = 0;
4454 struct option long_opts[] = {
4455 { .val = 'f', .name = "follow", .has_arg = no_argument },
4457 char short_opts[] = "f";
4460 while ((rc = getopt_long(argc, argv, short_opts,
4461 long_opts, NULL)) != -1) {
4469 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4470 argv[0], argv[optind - 1]);
4477 mdd = argv[optind++];
4479 startrec = strtoll(argv[optind++], NULL, 10);
4481 endrec = strtoll(argv[optind++], NULL, 10);
4483 rc = llapi_changelog_start(&changelog_priv,
4484 CHANGELOG_FLAG_BLOCK |
4485 CHANGELOG_FLAG_JOBID |
4486 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4489 fprintf(stderr, "Can't start changelog: %s\n",
4490 strerror(errno = -rc));
4494 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4498 if (endrec && rec->cr_index > endrec) {
4499 llapi_changelog_free(&rec);
4502 if (rec->cr_index < startrec) {
4503 llapi_changelog_free(&rec);
4507 secs = rec->cr_time >> 30;
4508 gmtime_r(&secs, &ts);
4509 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4510 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4511 changelog_type2str(rec->cr_type),
4512 ts.tm_hour, ts.tm_min, ts.tm_sec,
4513 (int)(rec->cr_time & ((1 << 30) - 1)),
4514 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4515 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4517 if (rec->cr_flags & CLF_JOBID) {
4518 struct changelog_ext_jobid *jid =
4519 changelog_rec_jobid(rec);
4521 if (jid->cr_jobid[0] != '\0')
4522 printf(" j=%s", jid->cr_jobid);
4525 if (rec->cr_namelen)
4526 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4527 rec->cr_namelen, changelog_rec_name(rec));
4529 if (rec->cr_flags & CLF_RENAME) {
4530 struct changelog_ext_rename *rnm =
4531 changelog_rec_rename(rec);
4533 if (!fid_is_zero(&rnm->cr_sfid))
4534 printf(" s="DFID" sp="DFID" %.*s",
4535 PFID(&rnm->cr_sfid),
4536 PFID(&rnm->cr_spfid),
4537 (int)changelog_rec_snamelen(rec),
4538 changelog_rec_sname(rec));
4542 llapi_changelog_free(&rec);
4545 llapi_changelog_fini(&changelog_priv);
4548 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4550 return (rc == 1 ? 0 : rc);
4553 static int lfs_changelog_clear(int argc, char **argv)
4561 endrec = strtoll(argv[3], NULL, 10);
4563 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4566 fprintf(stderr, "%s: record out of range: %llu\n",
4568 else if (rc == -ENOENT)
4569 fprintf(stderr, "%s: no changelog user: %s\n",
4572 fprintf(stderr, "%s error: %s\n", argv[0],
4581 static int lfs_fid2path(int argc, char **argv)
4583 struct option long_opts[] = {
4584 { .val = 'c', .name = "cur", .has_arg = no_argument },
4585 { .val = 'l', .name = "link", .has_arg = required_argument },
4586 { .val = 'r', .name = "rec", .has_arg = required_argument },
4588 char short_opts[] = "cl:r:";
4589 char *device, *fid, *path;
4590 long long recno = -1;
4596 while ((rc = getopt_long(argc, argv, short_opts,
4597 long_opts, NULL)) != -1) {
4603 linkno = strtol(optarg, NULL, 10);
4606 recno = strtoll(optarg, NULL, 10);
4611 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4612 argv[0], argv[optind - 1]);
4620 device = argv[optind++];
4621 path = calloc(1, PATH_MAX);
4623 fprintf(stderr, "error: Not enough memory\n");
4628 while (optind < argc) {
4629 fid = argv[optind++];
4631 lnktmp = (linkno >= 0) ? linkno : 0;
4633 int oldtmp = lnktmp;
4634 long long rectmp = recno;
4636 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4639 fprintf(stderr, "%s: error on FID %s: %s\n",
4640 argv[0], fid, strerror(errno = -rc2));
4647 fprintf(stdout, "%lld ", rectmp);
4648 if (device[0] == '/') {
4649 fprintf(stdout, "%s", device);
4650 if (device[strlen(device) - 1] != '/')
4651 fprintf(stdout, "/");
4652 } else if (path[0] == '\0') {
4653 fprintf(stdout, "/");
4655 fprintf(stdout, "%s\n", path);
4658 /* specified linkno */
4660 if (oldtmp == lnktmp)
4670 static int lfs_path2fid(int argc, char **argv)
4672 struct option long_opts[] = {
4673 { .val = 'p', .name = "parents", .has_arg = no_argument },
4676 const char short_opts[] = "p";
4677 const char *sep = "";
4680 bool show_parents = false;
4682 while ((rc = getopt_long(argc, argv, short_opts,
4683 long_opts, NULL)) != -1) {
4686 show_parents = true;
4689 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4690 argv[0], argv[optind - 1]);
4695 if (optind > argc - 1)
4697 else if (optind < argc - 1)
4701 for (path = argv + optind; *path != NULL; path++) {
4703 if (!show_parents) {
4704 err = llapi_path2fid(*path, &fid);
4706 printf("%s%s"DFID"\n",
4707 *sep != '\0' ? *path : "", sep,
4710 char name[NAME_MAX + 1];
4711 unsigned int linkno = 0;
4713 while ((err = llapi_path2parent(*path, linkno, &fid,
4714 name, sizeof(name))) == 0) {
4715 if (*sep != '\0' && linkno == 0)
4716 printf("%s%s", *path, sep);
4718 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4723 /* err == -ENODATA is end-of-loop */
4724 if (linkno > 0 && err == -ENODATA) {
4731 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4732 argv[0], show_parents ? "parent " : "", *path,
4744 static int lfs_data_version(int argc, char **argv)
4751 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4756 while ((c = getopt(argc, argv, "nrw")) != -1) {
4759 data_version_flags = 0;
4762 data_version_flags |= LL_DV_RD_FLUSH;
4765 data_version_flags |= LL_DV_WR_FLUSH;
4774 path = argv[optind];
4775 fd = open(path, O_RDONLY);
4777 err(errno, "cannot open file %s", path);
4779 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4781 err(errno, "cannot get version for %s", path);
4783 printf("%ju" "\n", (uintmax_t)data_version);
4789 static int lfs_hsm_state(int argc, char **argv)
4794 struct hsm_user_state hus;
4802 rc = llapi_hsm_state_get(path, &hus);
4804 fprintf(stderr, "can't get hsm state for %s: %s\n",
4805 path, strerror(errno = -rc));
4809 /* Display path name and status flags */
4810 printf("%s: (0x%08x)", path, hus.hus_states);
4812 if (hus.hus_states & HS_RELEASED)
4813 printf(" released");
4814 if (hus.hus_states & HS_EXISTS)
4816 if (hus.hus_states & HS_DIRTY)
4818 if (hus.hus_states & HS_ARCHIVED)
4819 printf(" archived");
4820 /* Display user-settable flags */
4821 if (hus.hus_states & HS_NORELEASE)
4822 printf(" never_release");
4823 if (hus.hus_states & HS_NOARCHIVE)
4824 printf(" never_archive");
4825 if (hus.hus_states & HS_LOST)
4826 printf(" lost_from_hsm");
4828 if (hus.hus_archive_id != 0)
4829 printf(", archive_id:%d", hus.hus_archive_id);
4832 } while (++i < argc);
4837 #define LFS_HSM_SET 0
4838 #define LFS_HSM_CLEAR 1
4841 * Generic function to set or clear HSM flags.
4842 * Used by hsm_set and hsm_clear.
4844 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4846 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4848 struct option long_opts[] = {
4849 { .val = 'A', .name = "archived", .has_arg = no_argument },
4850 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4851 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4852 { .val = 'e', .name = "exists", .has_arg = no_argument },
4853 { .val = 'l', .name = "lost", .has_arg = no_argument },
4854 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4856 char short_opts[] = "lraAde";
4864 while ((c = getopt_long(argc, argv, short_opts,
4865 long_opts, NULL)) != -1) {
4871 mask |= HS_NOARCHIVE;
4874 mask |= HS_ARCHIVED;
4877 mask |= HS_NORELEASE;
4888 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4889 argv[0], argv[optind - 1]);
4894 /* User should have specified a flag */
4898 while (optind < argc) {
4900 path = argv[optind];
4902 /* If mode == 0, this means we apply the mask. */
4903 if (mode == LFS_HSM_SET)
4904 rc = llapi_hsm_state_set(path, mask, 0, 0);
4906 rc = llapi_hsm_state_set(path, 0, mask, 0);
4909 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4910 path, strerror(errno = -rc));
4919 static int lfs_hsm_action(int argc, char **argv)
4924 struct hsm_current_action hca;
4925 struct hsm_extent he;
4926 enum hsm_user_action hua;
4927 enum hsm_progress_states hps;
4935 rc = llapi_hsm_current_action(path, &hca);
4937 fprintf(stderr, "can't get hsm action for %s: %s\n",
4938 path, strerror(errno = -rc));
4941 he = hca.hca_location;
4942 hua = hca.hca_action;
4943 hps = hca.hca_state;
4945 printf("%s: %s", path, hsm_user_action2name(hua));
4947 /* Skip file without action */
4948 if (hca.hca_action == HUA_NONE) {
4953 printf(" %s ", hsm_progress_state2name(hps));
4955 if ((hps == HPS_RUNNING) &&
4956 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4957 printf("(%llu bytes moved)\n",
4958 (unsigned long long)he.length);
4959 else if ((he.offset + he.length) == LUSTRE_EOF)
4960 printf("(from %llu to EOF)\n",
4961 (unsigned long long)he.offset);
4963 printf("(from %llu to %llu)\n",
4964 (unsigned long long)he.offset,
4965 (unsigned long long)(he.offset + he.length));
4967 } while (++i < argc);
4972 static int lfs_hsm_set(int argc, char **argv)
4974 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4977 static int lfs_hsm_clear(int argc, char **argv)
4979 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4983 * Check file state and return its fid, to be used by lfs_hsm_request().
4985 * \param[in] file Path to file to check
4986 * \param[in,out] fid Pointer to allocated lu_fid struct.
4987 * \param[in,out] last_dev Pointer to last device id used.
4989 * \return 0 on success.
4991 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4997 rc = lstat(file, &st);
4999 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5002 /* Checking for regular file as archiving as posix copytool
5003 * rejects archiving files other than regular files
5005 if (!S_ISREG(st.st_mode)) {
5006 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5009 /* A request should be ... */
5010 if (*last_dev != st.st_dev && *last_dev != 0) {
5011 fprintf(stderr, "All files should be "
5012 "on the same filesystem: %s\n", file);
5015 *last_dev = st.st_dev;
5017 rc = llapi_path2fid(file, fid);
5019 fprintf(stderr, "Cannot read FID of %s: %s\n",
5020 file, strerror(-rc));
5026 /* Fill an HSM HUR item with a given file name.
5028 * If mntpath is set, then the filename is actually a FID, and no
5029 * lookup on the filesystem will be performed.
5031 * \param[in] hur the user request to fill
5032 * \param[in] idx index of the item inside the HUR to fill
5033 * \param[in] mntpath mountpoint of Lustre
5034 * \param[in] fname filename (if mtnpath is NULL)
5035 * or FID (if mntpath is set)
5036 * \param[in] last_dev pointer to last device id used
5038 * \retval 0 on success
5039 * \retval CMD_HELP or a negative errno on error
5041 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5042 const char *mntpath, const char *fname,
5045 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5048 hui->hui_extent.length = -1;
5050 if (mntpath != NULL) {
5053 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5057 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5062 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5066 hur->hur_request.hr_itemcount++;
5071 static int lfs_hsm_request(int argc, char **argv, int action)
5073 struct option long_opts[] = {
5074 { .val = 'a', .name = "archive", .has_arg = required_argument },
5075 { .val = 'D', .name = "data", .has_arg = required_argument },
5076 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5077 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5080 char short_opts[] = "l:D:a:m:";
5081 struct hsm_user_request *hur, *oldhur;
5086 char *filelist = NULL;
5087 char fullpath[PATH_MAX];
5088 char *opaque = NULL;
5092 int nbfile_alloc = 0;
5093 char *some_file = NULL;
5094 char *mntpath = NULL;
5100 while ((c = getopt_long(argc, argv, short_opts,
5101 long_opts, NULL)) != -1) {
5110 if (action != HUA_ARCHIVE &&
5111 action != HUA_REMOVE) {
5113 "error: -a is supported only "
5114 "when archiving or removing\n");
5117 archive_id = atoi(optarg);
5120 if (some_file == NULL) {
5122 some_file = strdup(optarg);
5128 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5129 argv[0], argv[optind - 1]);
5134 /* All remaining args are files, so we have at least nbfile */
5135 nbfile = argc - optind;
5137 if ((nbfile == 0) && (filelist == NULL))
5141 opaque_len = strlen(opaque);
5143 /* Alloc the request structure with enough place to store all files
5144 * from command line. */
5145 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5147 fprintf(stderr, "Cannot create the request: %s\n",
5151 nbfile_alloc = nbfile;
5153 hur->hur_request.hr_action = action;
5154 hur->hur_request.hr_archive_id = archive_id;
5155 hur->hur_request.hr_flags = 0;
5157 /* All remaining args are files, add them */
5158 if (nbfile != 0 && some_file == NULL)
5159 some_file = strdup(argv[optind]);
5161 for (i = 0; i < nbfile; i++) {
5162 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5168 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5170 /* If a filelist was specified, read the filelist from it. */
5171 if (filelist != NULL) {
5172 fp = fopen(filelist, "r");
5174 fprintf(stderr, "Cannot read the file list %s: %s\n",
5175 filelist, strerror(errno));
5180 while ((rc = getline(&line, &len, fp)) != -1) {
5181 /* If allocated buffer was too small, get something
5183 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5186 nbfile_alloc = nbfile_alloc * 2 + 1;
5188 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5191 fprintf(stderr, "hsm: cannot allocate "
5192 "the request: %s\n",
5199 size = hur_len(oldhur);
5201 fprintf(stderr, "hsm: cannot allocate "
5202 "%u files + %u bytes data\n",
5203 oldhur->hur_request.hr_itemcount,
5204 oldhur->hur_request.hr_data_len);
5211 memcpy(hur, oldhur, size);
5216 if (line[strlen(line) - 1] == '\n')
5217 line[strlen(line) - 1] = '\0';
5219 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5220 mntpath, line, &last_dev);
5226 if (some_file == NULL) {
5236 /* If a --data was used, add it to the request */
5237 hur->hur_request.hr_data_len = opaque_len;
5239 memcpy(hur_data(hur), opaque, opaque_len);
5241 /* Send the HSM request */
5242 if (realpath(some_file, fullpath) == NULL) {
5243 fprintf(stderr, "Could not find path '%s': %s\n",
5244 some_file, strerror(errno));
5246 rc = llapi_hsm_request(fullpath, hur);
5248 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5249 some_file, strerror(-rc));
5259 static int lfs_hsm_archive(int argc, char **argv)
5261 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5264 static int lfs_hsm_restore(int argc, char **argv)
5266 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5269 static int lfs_hsm_release(int argc, char **argv)
5271 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5274 static int lfs_hsm_remove(int argc, char **argv)
5276 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5279 static int lfs_hsm_cancel(int argc, char **argv)
5281 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5284 static int lfs_swap_layouts(int argc, char **argv)
5289 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5290 SWAP_LAYOUTS_KEEP_MTIME |
5291 SWAP_LAYOUTS_KEEP_ATIME);
5294 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5296 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5298 static const char *const lockahead_results[] = {
5299 [LLA_RESULT_SENT] = "Lock request sent",
5300 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5301 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5304 int lfs_get_mode(const char *string)
5306 enum lock_mode_user mode;
5308 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5309 if (lock_mode_names[mode] == NULL)
5311 if (strcmp(string, lock_mode_names[mode]) == 0)
5318 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5320 enum lu_ladvise_type advice;
5323 advice < ARRAY_SIZE(ladvise_names); advice++) {
5324 if (ladvise_names[advice] == NULL)
5326 if (strcmp(string, ladvise_names[advice]) == 0)
5330 return LU_LADVISE_INVALID;
5333 static int lfs_ladvise(int argc, char **argv)
5335 struct option long_opts[] = {
5336 { .val = 'a', .name = "advice", .has_arg = required_argument },
5337 { .val = 'b', .name = "background", .has_arg = no_argument },
5338 { .val = 'e', .name = "end", .has_arg = required_argument },
5339 { .val = 'l', .name = "length", .has_arg = required_argument },
5340 { .val = 'm', .name = "mode", .has_arg = required_argument },
5341 { .val = 's', .name = "start", .has_arg = required_argument },
5342 { .val = 'u', .name = "unset", .has_arg = no_argument },
5344 char short_opts[] = "a:be:l:m:s:u";
5349 struct llapi_lu_ladvise advice;
5350 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5351 unsigned long long start = 0;
5352 unsigned long long end = LUSTRE_EOF;
5353 unsigned long long length = 0;
5354 unsigned long long size_units;
5355 unsigned long long flags = 0;
5359 while ((c = getopt_long(argc, argv, short_opts,
5360 long_opts, NULL)) != -1) {
5363 advice_type = lfs_get_ladvice(optarg);
5364 if (advice_type == LU_LADVISE_INVALID) {
5365 fprintf(stderr, "%s: invalid advice type "
5366 "'%s'\n", argv[0], optarg);
5367 fprintf(stderr, "Valid types:");
5369 for (advice_type = 0;
5370 advice_type < ARRAY_SIZE(ladvise_names);
5372 if (ladvise_names[advice_type] == NULL)
5374 fprintf(stderr, " %s",
5375 ladvise_names[advice_type]);
5377 fprintf(stderr, "\n");
5390 rc = llapi_parse_size(optarg, &end,
5393 fprintf(stderr, "%s: bad end offset '%s'\n",
5400 rc = llapi_parse_size(optarg, &start,
5403 fprintf(stderr, "%s: bad start offset "
5404 "'%s'\n", argv[0], optarg);
5410 rc = llapi_parse_size(optarg, &length,
5413 fprintf(stderr, "%s: bad length '%s'\n",
5419 mode = lfs_get_mode(optarg);
5421 fprintf(stderr, "%s: bad mode '%s', valid "
5422 "modes are READ or WRITE\n",
5430 fprintf(stderr, "%s: option '%s' unrecognized\n",
5431 argv[0], argv[optind - 1]);
5436 if (advice_type == LU_LADVISE_INVALID) {
5437 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5438 fprintf(stderr, "Valid types:");
5439 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5441 if (ladvise_names[advice_type] == NULL)
5443 fprintf(stderr, " %s", ladvise_names[advice_type]);
5445 fprintf(stderr, "\n");
5449 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
5450 fprintf(stderr, "%s: Lock no expand advice is a per file "
5451 "descriptor advice, so when called from lfs, "
5452 "it does nothing.\n", argv[0]);
5456 if (argc <= optind) {
5457 fprintf(stderr, "%s: please give one or more file names\n",
5462 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5463 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5468 if (end == LUSTRE_EOF && length != 0)
5469 end = start + length;
5472 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5473 argv[0], start, end);
5477 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
5478 fprintf(stderr, "%s: mode is only valid with lockahead\n",
5483 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
5484 fprintf(stderr, "%s: mode is required with lockahead\n",
5489 while (optind < argc) {
5492 path = argv[optind++];
5494 fd = open(path, O_RDONLY);
5496 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5497 argv[0], path, strerror(errno));
5502 advice.lla_start = start;
5503 advice.lla_end = end;
5504 advice.lla_advice = advice_type;
5505 advice.lla_value1 = 0;
5506 advice.lla_value2 = 0;
5507 advice.lla_value3 = 0;
5508 advice.lla_value4 = 0;
5509 if (advice_type == LU_LADVISE_LOCKAHEAD) {
5510 advice.lla_lockahead_mode = mode;
5511 advice.lla_peradvice_flags = flags;
5514 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5517 fprintf(stderr, "%s: cannot give advice '%s' to file "
5518 "'%s': %s\n", argv[0],
5519 ladvise_names[advice_type],
5520 path, strerror(errno));
5526 if (rc == 0 && rc2 < 0)
5532 static int lfs_list_commands(int argc, char **argv)
5534 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5536 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5541 int main(int argc, char **argv)
5545 /* Ensure that liblustreapi constructor has run */
5546 if (!liblustreapi_initialized)
5547 fprintf(stderr, "liblustreapi was not properly initialized\n");
5551 Parser_init("lfs > ", cmdlist);
5553 progname = argv[0]; /* Used in error messages */
5555 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5557 rc = Parser_commands();
5560 return rc < 0 ? -rc : rc;
5563 #ifdef _LUSTRE_IDL_H_
5564 /* Everything we need here should be included by lustreapi.h. */
5565 # error "lfs should not depend on lustre_idl.h"
5566 #endif /* _LUSTRE_IDL_H_ */