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 "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\
131 "\tpool_name: Name of OST pool to use (default none)\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 = 'm', .name = "mdt", .has_arg = required_argument},
1421 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1422 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1423 /* --non-block is only valid in migrate mode */
1424 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1425 { .val = 'o', .name = "ost", .has_arg = required_argument},
1426 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1427 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1428 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1430 { .val = 'p', .name = "pool", .has_arg = required_argument },
1431 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1432 /* This formerly implied "--stripe-size", but was confusing
1433 * with "lfs find --size|-s", which means "file size", so use
1434 * the consistent "--stripe-size|-S" for all commands. */
1435 { .val = 's', .name = "size", .has_arg = required_argument },
1437 { .val = 'L', .name = "layout", .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], "mdt") == 0) {
1535 /* Can be only the first component */
1536 if (layout != NULL) {
1537 fprintf(stderr, "error: 'mdt' layout "
1538 "can be only the first one\n");
1541 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
1542 fprintf(stderr, "error: 'mdt' layout "
1543 "size is too big\n");
1546 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
1547 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
1548 fprintf(stderr, "error: layout '%s' is "
1549 "unknown, supported layouts are: "
1550 "'mdt', 'raid0'\n", argv[optind]);
1555 if (strcmp(argv[optind - 1], "--index") == 0)
1556 fprintf(stderr, "warning: '--index' deprecated"
1557 ", use '--stripe-index' instead\n");
1558 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1560 fprintf(stderr, "error: %s: bad stripe offset "
1561 "'%s'\n", argv[0], optarg);
1566 comp_id = strtoul(optarg, &end, 0);
1567 if (*end != '\0' || comp_id == 0 ||
1568 comp_id > LCME_ID_MAX) {
1569 fprintf(stderr, "error: %s: bad comp ID "
1570 "'%s'\n", argv[0], optarg);
1575 if (!migrate_mode) {
1576 fprintf(stderr, "--mdt-index is valid only for"
1580 mdt_idx_arg = optarg;
1583 if (!migrate_mode) {
1584 fprintf(stderr, "--non-block is valid only for"
1588 migration_flags |= MIGRATION_NONBLOCK;
1591 lsa.lsa_nr_osts = parse_targets(osts,
1592 sizeof(osts) / sizeof(__u32),
1593 lsa.lsa_nr_osts, optarg);
1594 if (lsa.lsa_nr_osts < 0) {
1596 "error: %s: bad OST indices '%s'\n",
1601 lsa.lsa_osts = osts;
1602 if (lsa.lsa_stripe_off == -1)
1603 lsa.lsa_stripe_off = osts[0];
1608 lsa.lsa_pool_name = optarg;
1610 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1612 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1613 fprintf(stderr, "warning: '--size|-s' deprecated, "
1614 "use '--stripe-size|-S' instead\n");
1616 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1618 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1621 fprintf(stderr, "error: %s: bad stripe size "
1622 "'%s'\n", argv[0], optarg);
1627 if (!migrate_mode) {
1628 fprintf(stderr, "--verbose is valid only for"
1632 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1639 fname = argv[optind];
1641 if (lsa.lsa_comp_end != 0) {
1642 result = comp_args_to_layout(&layout, &lsa);
1647 if (optind == argc) {
1648 fprintf(stderr, "error: %s: missing filename|dirname\n",
1653 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1654 * altered by user space tool, so we don't need to support the
1655 * --component-set for this moment. */
1656 if (comp_set != 0) {
1657 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1662 if ((delete + comp_set + comp_del + comp_add) > 1) {
1663 fprintf(stderr, "error: %s: can't specify --component-set, "
1664 "--component-del, --component-add or -d together\n",
1669 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1670 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1671 fprintf(stderr, "error: %s: can't specify -d with "
1672 "-s, -c, -o, -p, -I, -F or -E options\n",
1677 if ((comp_set || comp_del) &&
1678 (setstripe_args_specified(&lsa) || layout != NULL)) {
1679 fprintf(stderr, "error: %s: can't specify --component-del or "
1680 "--component-set with -s, -c, -o, -p or -E options.\n",
1685 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1686 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1687 "--component-del option.\n", argv[0]);
1691 if (comp_add || comp_del) {
1694 result = lstat(fname, &st);
1695 if (result == 0 && S_ISDIR(st.st_mode)) {
1696 fprintf(stderr, "error: %s: can't use --component-add "
1697 "or --component-del for directory.\n",
1704 if (layout == NULL) {
1705 fprintf(stderr, "error: %s: -E option must be present"
1706 "in --component-add mode.\n", argv[0]);
1709 result = adjust_first_extent(fname, layout);
1710 if (result == -ENODATA)
1712 else if (result != 0)
1716 if (mdt_idx_arg != NULL && optind > 3) {
1717 fprintf(stderr, "error: %s: cannot specify -m with other "
1718 "options\n", argv[0]);
1722 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1724 "error: %s: cannot specify --non-block and --block\n",
1729 if (!comp_del && !comp_set && comp_id != 0) {
1730 fprintf(stderr, "error: %s: -I can only be used with "
1731 "--component-del.\n", argv[0]);
1735 if (mdt_idx_arg != NULL) {
1736 /* initialize migrate mdt parameters */
1737 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1739 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1740 argv[0], mdt_idx_arg);
1743 migrate_mdt_param.fp_migrate = 1;
1744 } else if (layout == NULL) {
1745 /* initialize stripe parameters */
1746 param = calloc(1, offsetof(typeof(*param),
1747 lsp_osts[lsa.lsa_nr_osts]));
1748 if (param == NULL) {
1749 fprintf(stderr, "error: %s: %s\n", argv[0],
1754 param->lsp_stripe_size = lsa.lsa_stripe_size;
1755 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1756 param->lsp_stripe_count = lsa.lsa_stripe_count;
1757 param->lsp_pool = lsa.lsa_pool_name;
1758 param->lsp_is_specific = false;
1759 if (lsa.lsa_nr_osts > 0) {
1760 if (lsa.lsa_stripe_count > 0 &&
1761 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1762 fprintf(stderr, "error: %s: stripe count '%d' "
1763 "doesn't match the number of OSTs: %d\n"
1764 , argv[0], lsa.lsa_stripe_count,
1770 param->lsp_is_specific = true;
1771 param->lsp_stripe_count = lsa.lsa_nr_osts;
1772 memcpy(param->lsp_osts, osts,
1773 sizeof(*osts) * lsa.lsa_nr_osts);
1777 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1779 if (mdt_idx_arg != NULL) {
1780 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1781 op = "migrate mdt objects of";
1782 } else if (migrate_mode) {
1783 result = lfs_migrate(fname, migration_flags, param,
1785 op = "migrate ost objects of";
1786 } else if (comp_set != 0) {
1787 result = lfs_component_set(fname, comp_id,
1788 lsa.lsa_comp_flags);
1789 op = "modify component flags of";
1790 } else if (comp_del != 0) {
1791 result = lfs_component_del(fname, comp_id,
1792 lsa.lsa_comp_flags);
1793 op = "delete component of";
1794 } else if (comp_add != 0) {
1795 result = lfs_component_add(fname, layout);
1796 op = "add component to";
1797 } else if (layout != NULL) {
1798 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1804 op = "create composite";
1806 result = llapi_file_open_param(fname,
1813 op = "create striped";
1816 /* Save the first error encountered. */
1819 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1821 lsa.lsa_pool_name != NULL && result == EINVAL ?
1822 "OST not in pool?" : strerror(errno));
1828 llapi_layout_free(layout);
1831 llapi_layout_free(layout);
1835 static int lfs_poollist(int argc, char **argv)
1840 return llapi_poollist(argv[1]);
1843 static int set_time(time_t *time, time_t *set, char *str)
1850 else if (str[0] == '-')
1856 t = strtol(str, NULL, 0);
1857 if (*time < t * 24 * 60 * 60) {
1860 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1864 *set = *time - t * 24 * 60 * 60;
1867 static int name2uid(unsigned int *id, const char *name)
1869 struct passwd *passwd;
1871 passwd = getpwnam(name);
1874 *id = passwd->pw_uid;
1879 static int name2gid(unsigned int *id, const char *name)
1881 struct group *group;
1883 group = getgrnam(name);
1886 *id = group->gr_gid;
1891 static inline int name2projid(unsigned int *id, const char *name)
1896 static int uid2name(char **name, unsigned int id)
1898 struct passwd *passwd;
1900 passwd = getpwuid(id);
1903 *name = passwd->pw_name;
1908 static inline int gid2name(char **name, unsigned int id)
1910 struct group *group;
1912 group = getgrgid(id);
1915 *name = group->gr_name;
1920 static int name2layout(__u32 *layout, char *name)
1922 char *ptr, *layout_name;
1925 for (ptr = name; ; ptr = NULL) {
1926 layout_name = strtok(ptr, ",");
1927 if (layout_name == NULL)
1929 if (strcmp(layout_name, "released") == 0)
1930 *layout |= LOV_PATTERN_F_RELEASED;
1931 else if (strcmp(layout_name, "raid0") == 0)
1932 *layout |= LOV_PATTERN_RAID0;
1933 else if (strcmp(layout_name, "mdt") == 0)
1934 *layout |= LOV_PATTERN_MDT;
1941 static int lfs_find(int argc, char **argv)
1946 struct find_param param = {
1950 struct option long_opts[] = {
1951 { .val = 'A', .name = "atime", .has_arg = required_argument },
1952 { .val = LFS_COMP_COUNT_OPT,
1953 .name = "comp-count", .has_arg = required_argument },
1954 { .val = LFS_COMP_COUNT_OPT,
1955 .name = "component-count",
1956 .has_arg = required_argument },
1957 { .val = LFS_COMP_FLAGS_OPT,
1958 .name = "comp-flags", .has_arg = required_argument },
1959 { .val = LFS_COMP_FLAGS_OPT,
1960 .name = "component-flags",
1961 .has_arg = required_argument },
1962 { .val = LFS_COMP_START_OPT,
1963 .name = "comp-start", .has_arg = required_argument },
1964 { .val = LFS_COMP_START_OPT,
1965 .name = "component-start",
1966 .has_arg = required_argument },
1967 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1968 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1969 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1970 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1971 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1972 { .val = 'E', .name = "component-end",
1973 .has_arg = required_argument },
1974 { .val = 'g', .name = "gid", .has_arg = required_argument },
1975 { .val = 'G', .name = "group", .has_arg = required_argument },
1976 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1977 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1978 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1979 /*{"component-id", required_argument, 0, 'I'},*/
1980 { .val = 'L', .name = "layout", .has_arg = required_argument },
1981 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1982 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1983 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1984 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1985 { .val = 'n', .name = "name", .has_arg = required_argument },
1986 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1987 { .val = 'O', .name = "obd", .has_arg = required_argument },
1988 { .val = 'O', .name = "ost", .has_arg = required_argument },
1989 /* no short option for pool, p/P already used */
1990 { .val = LFS_POOL_OPT,
1991 .name = "pool", .has_arg = required_argument },
1992 { .val = 'p', .name = "print0", .has_arg = no_argument },
1993 { .val = 'P', .name = "print", .has_arg = no_argument },
1994 { .val = LFS_PROJID_OPT,
1995 .name = "projid", .has_arg = required_argument },
1996 { .val = 's', .name = "size", .has_arg = required_argument },
1997 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1998 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1999 { .val = 't', .name = "type", .has_arg = required_argument },
2000 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
2001 { .val = 'u', .name = "uid", .has_arg = required_argument },
2002 { .val = 'U', .name = "user", .has_arg = required_argument },
2014 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2015 while ((c = getopt_long_only(argc, argv,
2016 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2017 long_opts, NULL)) >= 0) {
2022 /* '!' is part of option */
2023 /* when getopt_long_only() finds a string which is not
2024 * an option nor a known option argument it returns 1
2025 * in that case if we already have found pathstart and pathend
2026 * (i.e. we have the list of pathnames),
2027 * the only supported value is "!"
2029 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2030 if (!isoption && pathend != -1) {
2031 fprintf(stderr, "err: %s: filename|dirname must either "
2032 "precede options or follow options\n",
2037 if (!isoption && pathstart == -1)
2038 pathstart = optind - 1;
2039 if (isoption && pathstart != -1 && pathend == -1)
2040 pathend = optind - 2;
2046 /* unknown; opt is "!" or path component,
2047 * checking done above.
2049 if (strcmp(optarg, "!") == 0)
2053 xtime = ¶m.fp_atime;
2054 xsign = ¶m.fp_asign;
2055 param.fp_exclude_atime = !!neg_opt;
2056 /* no break, this falls through to 'C' for ctime */
2059 xtime = ¶m.fp_ctime;
2060 xsign = ¶m.fp_csign;
2061 param.fp_exclude_ctime = !!neg_opt;
2063 /* no break, this falls through to 'M' for mtime */
2066 xtime = ¶m.fp_mtime;
2067 xsign = ¶m.fp_msign;
2068 param.fp_exclude_mtime = !!neg_opt;
2070 rc = set_time(&t, xtime, optarg);
2071 if (rc == INT_MAX) {
2078 case LFS_COMP_COUNT_OPT:
2079 if (optarg[0] == '+') {
2080 param.fp_comp_count_sign = -1;
2082 } else if (optarg[0] == '-') {
2083 param.fp_comp_count_sign = 1;
2087 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2088 if (*endptr != '\0') {
2089 fprintf(stderr, "error: bad component count "
2093 param.fp_check_comp_count = 1;
2094 param.fp_exclude_comp_count = !!neg_opt;
2096 case LFS_COMP_FLAGS_OPT:
2097 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2098 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2099 fprintf(stderr, "error: bad component flags "
2103 param.fp_check_comp_flags = 1;
2104 param.fp_exclude_comp_flags = !!neg_opt;
2106 case LFS_COMP_START_OPT:
2107 if (optarg[0] == '+') {
2108 param.fp_comp_start_sign = -1;
2110 } else if (optarg[0] == '-') {
2111 param.fp_comp_start_sign = 1;
2115 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2116 ¶m.fp_comp_start_units, 0);
2118 fprintf(stderr, "error: bad component start "
2122 param.fp_check_comp_start = 1;
2123 param.fp_exclude_comp_start = !!neg_opt;
2126 if (optarg[0] == '+') {
2127 param.fp_stripe_count_sign = -1;
2129 } else if (optarg[0] == '-') {
2130 param.fp_stripe_count_sign = 1;
2134 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2135 if (*endptr != '\0') {
2136 fprintf(stderr,"error: bad stripe_count '%s'\n",
2141 param.fp_check_stripe_count = 1;
2142 param.fp_exclude_stripe_count = !!neg_opt;
2145 param.fp_max_depth = strtol(optarg, 0, 0);
2148 if (optarg[0] == '+') {
2149 param.fp_comp_end_sign = -1;
2151 } else if (optarg[0] == '-') {
2152 param.fp_comp_end_sign = 1;
2156 if (arg_is_eof(optarg)) {
2157 param.fp_comp_end = LUSTRE_EOF;
2158 param.fp_comp_end_units = 1;
2161 rc = llapi_parse_size(optarg,
2163 ¶m.fp_comp_end_units, 0);
2166 fprintf(stderr, "error: bad component end "
2170 param.fp_check_comp_end = 1;
2171 param.fp_exclude_comp_end = !!neg_opt;
2175 rc = name2gid(¶m.fp_gid, optarg);
2177 param.fp_gid = strtoul(optarg, &endptr, 10);
2178 if (*endptr != '\0') {
2179 fprintf(stderr, "Group/GID: %s cannot "
2180 "be found.\n", optarg);
2185 param.fp_exclude_gid = !!neg_opt;
2186 param.fp_check_gid = 1;
2189 param.fp_hash_type = check_hashtype(optarg);
2190 if (param.fp_hash_type == 0) {
2191 fprintf(stderr, "error: bad hash_type '%s'\n",
2196 param.fp_check_hash_type = 1;
2197 param.fp_exclude_hash_type = !!neg_opt;
2200 ret = name2layout(¶m.fp_layout, optarg);
2203 param.fp_exclude_layout = !!neg_opt;
2204 param.fp_check_layout = 1;
2208 rc = name2uid(¶m.fp_uid, optarg);
2210 param.fp_uid = strtoul(optarg, &endptr, 10);
2211 if (*endptr != '\0') {
2212 fprintf(stderr, "User/UID: %s cannot "
2213 "be found.\n", optarg);
2218 param.fp_exclude_uid = !!neg_opt;
2219 param.fp_check_uid = 1;
2222 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2224 "Pool name %s is too long"
2225 " (max is %d)\n", optarg,
2230 /* we do check for empty pool because empty pool
2231 * is used to find V1 lov attributes */
2232 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2233 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2234 param.fp_exclude_pool = !!neg_opt;
2235 param.fp_check_pool = 1;
2238 param.fp_pattern = (char *)optarg;
2239 param.fp_exclude_pattern = !!neg_opt;
2244 char *buf, *token, *next, *p;
2248 buf = strdup(optarg);
2254 param.fp_exclude_obd = !!neg_opt;
2257 while (token && *token) {
2258 token = strchr(token, ',');
2265 param.fp_exclude_mdt = !!neg_opt;
2266 param.fp_num_alloc_mdts += len;
2267 tmp = realloc(param.fp_mdt_uuid,
2268 param.fp_num_alloc_mdts *
2269 sizeof(*param.fp_mdt_uuid));
2275 param.fp_mdt_uuid = tmp;
2277 param.fp_exclude_obd = !!neg_opt;
2278 param.fp_num_alloc_obds += len;
2279 tmp = realloc(param.fp_obd_uuid,
2280 param.fp_num_alloc_obds *
2281 sizeof(*param.fp_obd_uuid));
2287 param.fp_obd_uuid = tmp;
2289 for (token = buf; token && *token; token = next) {
2290 struct obd_uuid *puuid;
2293 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2296 ¶m.fp_obd_uuid[param.fp_num_obds++];
2298 p = strchr(token, ',');
2305 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2310 strncpy(puuid->uuid, token,
2311 sizeof(puuid->uuid));
2319 param.fp_zero_end = 1;
2323 case LFS_PROJID_OPT:
2324 rc = name2projid(¶m.fp_projid, optarg);
2326 param.fp_projid = strtoul(optarg, &endptr, 10);
2327 if (*endptr != '\0') {
2329 "Invalid project ID: %s",
2335 param.fp_exclude_projid = !!neg_opt;
2336 param.fp_check_projid = 1;
2339 if (optarg[0] == '+') {
2340 param.fp_size_sign = -1;
2342 } else if (optarg[0] == '-') {
2343 param.fp_size_sign = 1;
2347 ret = llapi_parse_size(optarg, ¶m.fp_size,
2348 ¶m.fp_size_units, 0);
2350 fprintf(stderr, "error: bad file size '%s'\n",
2354 param.fp_check_size = 1;
2355 param.fp_exclude_size = !!neg_opt;
2358 if (optarg[0] == '+') {
2359 param.fp_stripe_size_sign = -1;
2361 } else if (optarg[0] == '-') {
2362 param.fp_stripe_size_sign = 1;
2366 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2367 ¶m.fp_stripe_size_units, 0);
2369 fprintf(stderr, "error: bad stripe_size '%s'\n",
2373 param.fp_check_stripe_size = 1;
2374 param.fp_exclude_stripe_size = !!neg_opt;
2377 param.fp_exclude_type = !!neg_opt;
2378 switch (optarg[0]) {
2380 param.fp_type = S_IFBLK;
2383 param.fp_type = S_IFCHR;
2386 param.fp_type = S_IFDIR;
2389 param.fp_type = S_IFREG;
2392 param.fp_type = S_IFLNK;
2395 param.fp_type = S_IFIFO;
2398 param.fp_type = S_IFSOCK;
2401 fprintf(stderr, "error: %s: bad type '%s'\n",
2408 if (optarg[0] == '+') {
2409 param.fp_mdt_count_sign = -1;
2411 } else if (optarg[0] == '-') {
2412 param.fp_mdt_count_sign = 1;
2416 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2417 if (*endptr != '\0') {
2418 fprintf(stderr, "error: bad mdt_count '%s'\n",
2423 param.fp_check_mdt_count = 1;
2424 param.fp_exclude_mdt_count = !!neg_opt;
2432 if (pathstart == -1) {
2433 fprintf(stderr, "error: %s: no filename|pathname\n",
2437 } else if (pathend == -1) {
2443 rc = llapi_find(argv[pathstart], ¶m);
2444 if (rc != 0 && ret == 0)
2446 } while (++pathstart < pathend);
2449 fprintf(stderr, "error: %s failed for %s.\n",
2450 argv[0], argv[optind - 1]);
2452 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2453 free(param.fp_obd_uuid);
2455 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2456 free(param.fp_mdt_uuid);
2461 static int lfs_getstripe_internal(int argc, char **argv,
2462 struct find_param *param)
2464 struct option long_opts[] = {
2465 { .val = LFS_COMP_COUNT_OPT,
2466 .name = "comp-count", .has_arg = no_argument },
2467 { .val = LFS_COMP_COUNT_OPT,
2468 .name = "component-count", .has_arg = no_argument },
2469 { .val = LFS_COMP_FLAGS_OPT,
2470 .name = "comp-flags", .has_arg = optional_argument },
2471 { .val = LFS_COMP_FLAGS_OPT,
2472 .name = "component-flags", .has_arg = optional_argument },
2473 { .val = LFS_COMP_START_OPT,
2474 .name = "comp-start", .has_arg = optional_argument },
2475 { .val = LFS_COMP_START_OPT,
2476 .name = "component-start", .has_arg = optional_argument },
2477 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2478 /* This formerly implied "stripe-count", but was explicitly
2479 * made "stripe-count" for consistency with other options,
2480 * and to separate it from "mdt-count" when DNE arrives. */
2481 { .val = 'c', .name = "count", .has_arg = no_argument },
2483 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2484 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2485 { .val = 'd', .name = "directory", .has_arg = no_argument },
2486 { .val = 'D', .name = "default", .has_arg = no_argument },
2487 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2488 { .val = 'E', .name = "component-end",
2489 .has_arg = optional_argument },
2490 { .val = 'F', .name = "fid", .has_arg = no_argument },
2491 { .val = 'g', .name = "generation", .has_arg = no_argument },
2492 /* dirstripe { .val = 'H', .name = "mdt-hash",
2493 * .has_arg = required_argument }, */
2494 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2495 /* This formerly implied "stripe-index", but was explicitly
2496 * made "stripe-index" for consistency with other options,
2497 * and to separate it from "mdt-index" when DNE arrives. */
2498 { .val = 'i', .name = "index", .has_arg = no_argument },
2500 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2501 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2502 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2503 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2504 { .val = 'L', .name = "layout", .has_arg = no_argument },
2505 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2506 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2507 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2508 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2509 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2510 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2512 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2513 /* This formerly implied "stripe-index", but was confusing
2514 * with "file offset" (which will eventually be needed for
2515 * with different layouts by offset), so deprecate it. */
2516 { .val = 'o', .name = "offset", .has_arg = no_argument },
2518 { .val = 'O', .name = "obd", .has_arg = required_argument },
2519 { .val = 'O', .name = "ost", .has_arg = required_argument },
2520 { .val = 'p', .name = "pool", .has_arg = no_argument },
2521 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2522 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2523 { .val = 'R', .name = "raw", .has_arg = no_argument },
2524 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2525 /* This formerly implied "--stripe-size", but was confusing
2526 * with "lfs find --size|-s", which means "file size", so use
2527 * the consistent "--stripe-size|-S" for all commands. */
2528 { .val = 's', .name = "size", .has_arg = no_argument },
2530 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2531 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2532 /* dirstripe { .val = 'T', .name = "mdt-count",
2533 * .has_arg = required_argument }, */
2534 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2535 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2540 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2541 long_opts, NULL)) != -1) {
2544 if (strcmp(argv[optind - 1], "--count") == 0)
2545 fprintf(stderr, "warning: '--count' deprecated,"
2546 " use '--stripe-count' instead\n");
2547 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2548 param->fp_verbose |= VERBOSE_COUNT;
2549 param->fp_max_depth = 0;
2552 case LFS_COMP_COUNT_OPT:
2553 param->fp_verbose |= VERBOSE_COMP_COUNT;
2554 param->fp_max_depth = 0;
2556 case LFS_COMP_FLAGS_OPT:
2557 if (optarg != NULL) {
2558 __u32 *flags = ¶m->fp_comp_flags;
2559 rc = comp_str2flags(flags, optarg);
2561 fprintf(stderr, "error: %s bad "
2562 "component flags '%s'.\n",
2566 param->fp_check_comp_flags = 1;
2567 param->fp_exclude_comp_flags =
2568 comp_flags_is_neg(*flags);
2569 comp_flags_clear_neg(flags);
2572 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2573 param->fp_max_depth = 0;
2576 case LFS_COMP_START_OPT:
2577 if (optarg != NULL) {
2579 if (tmp[0] == '+') {
2580 param->fp_comp_start_sign = -1;
2582 } else if (tmp[0] == '-') {
2583 param->fp_comp_start_sign = 1;
2586 rc = llapi_parse_size(tmp,
2587 ¶m->fp_comp_start,
2588 ¶m->fp_comp_start_units, 0);
2590 fprintf(stderr, "error: %s bad "
2591 "component start '%s'.\n",
2595 param->fp_check_comp_start = 1;
2598 param->fp_verbose |= VERBOSE_COMP_START;
2599 param->fp_max_depth = 0;
2603 param->fp_max_depth = 0;
2606 param->fp_get_default_lmv = 1;
2609 if (optarg != NULL) {
2611 if (tmp[0] == '+') {
2612 param->fp_comp_end_sign = -1;
2614 } else if (tmp[0] == '-') {
2615 param->fp_comp_end_sign = 1;
2619 if (arg_is_eof(tmp)) {
2620 param->fp_comp_end = LUSTRE_EOF;
2621 param->fp_comp_end_units = 1;
2624 rc = llapi_parse_size(tmp,
2625 ¶m->fp_comp_end,
2626 ¶m->fp_comp_end_units, 0);
2629 fprintf(stderr, "error: %s bad "
2630 "component end '%s'.\n",
2634 param->fp_check_comp_end = 1;
2636 param->fp_verbose |= VERBOSE_COMP_END;
2637 param->fp_max_depth = 0;
2641 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2642 param->fp_verbose |= VERBOSE_DFID;
2643 param->fp_max_depth = 0;
2647 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2648 param->fp_verbose |= VERBOSE_GENERATION;
2649 param->fp_max_depth = 0;
2652 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2654 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2655 "use '--stripe-index|-i' instead\n");
2658 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2659 if (strcmp(argv[optind - 1], "--index") == 0)
2660 fprintf(stderr, "warning: '--index' deprecated"
2661 ", use '--stripe-index' instead\n");
2663 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2664 param->fp_verbose |= VERBOSE_OFFSET;
2665 param->fp_max_depth = 0;
2669 if (optarg != NULL) {
2670 param->fp_comp_id = strtoul(optarg, &end, 0);
2671 if (*end != '\0' || param->fp_comp_id == 0 ||
2672 param->fp_comp_id > LCME_ID_MAX) {
2673 fprintf(stderr, "error: %s bad "
2674 "component id '%s'\n",
2678 param->fp_check_comp_id = 1;
2681 param->fp_max_depth = 0;
2682 param->fp_verbose |= VERBOSE_COMP_ID;
2686 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2687 param->fp_verbose |= VERBOSE_LAYOUT;
2688 param->fp_max_depth = 0;
2691 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2693 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2694 fprintf(stderr, "warning: '-M' deprecated"
2695 ", use '-m' instead\n");
2699 if (!(param->fp_verbose & VERBOSE_DETAIL))
2700 param->fp_max_depth = 0;
2701 param->fp_verbose |= VERBOSE_MDTINDEX;
2704 if (param->fp_obd_uuid) {
2706 "error: %s: only one obduuid allowed",
2710 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2713 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2714 param->fp_verbose |= VERBOSE_POOL;
2715 param->fp_max_depth = 0;
2722 param->fp_recursive = 1;
2727 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2729 fprintf(stderr, "warning: '--size|-s' deprecated, "
2730 "use '--stripe-size|-S' instead\n");
2731 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2733 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2734 param->fp_verbose |= VERBOSE_SIZE;
2735 param->fp_max_depth = 0;
2739 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2752 if (param->fp_recursive)
2753 param->fp_max_depth = -1;
2754 else if (param->fp_verbose & VERBOSE_DETAIL)
2755 param->fp_max_depth = 1;
2757 if (!param->fp_verbose)
2758 param->fp_verbose = VERBOSE_DEFAULT;
2759 if (param->fp_quiet)
2760 param->fp_verbose = VERBOSE_OBJID;
2763 rc = llapi_getstripe(argv[optind], param);
2764 } while (++optind < argc && !rc);
2767 fprintf(stderr, "error: %s failed for %s.\n",
2768 argv[0], argv[optind - 1]);
2772 static int lfs_tgts(int argc, char **argv)
2774 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2775 struct find_param param;
2776 int index = 0, rc=0;
2781 if (argc == 2 && !realpath(argv[1], path)) {
2783 fprintf(stderr, "error: invalid path '%s': %s\n",
2784 argv[1], strerror(-rc));
2788 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2789 /* Check if we have a mount point */
2790 if (mntdir[0] == '\0')
2793 memset(¶m, 0, sizeof(param));
2794 if (!strcmp(argv[0], "mdts"))
2795 param.fp_get_lmv = 1;
2797 rc = llapi_ostlist(mntdir, ¶m);
2799 fprintf(stderr, "error: %s: failed on %s\n",
2802 if (path[0] != '\0')
2804 memset(mntdir, 0, PATH_MAX);
2810 static int lfs_getstripe(int argc, char **argv)
2812 struct find_param param = { 0 };
2814 param.fp_max_depth = 1;
2815 return lfs_getstripe_internal(argc, argv, ¶m);
2819 static int lfs_getdirstripe(int argc, char **argv)
2821 struct find_param param = { 0 };
2822 struct option long_opts[] = {
2823 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2824 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2826 { .val = 'D', .name = "default", .has_arg = no_argument },
2827 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2828 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2829 { .val = 'O', .name = "obd", .has_arg = required_argument },
2830 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2831 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2832 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2834 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2835 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2839 param.fp_get_lmv = 1;
2841 while ((c = getopt_long(argc, argv,
2842 "cDHiO:rtTy", long_opts, NULL)) != -1)
2846 if (param.fp_obd_uuid) {
2848 "error: %s: only one obduuid allowed",
2852 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2854 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2856 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2857 fprintf(stderr, "warning: '-c' deprecated"
2858 ", use '-T' instead\n");
2862 param.fp_verbose |= VERBOSE_COUNT;
2865 param.fp_verbose |= VERBOSE_OFFSET;
2867 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2871 param.fp_verbose |= VERBOSE_HASH_TYPE;
2874 param.fp_get_default_lmv = 1;
2877 param.fp_recursive = 1;
2890 if (param.fp_recursive)
2891 param.fp_max_depth = -1;
2893 if (!param.fp_verbose)
2894 param.fp_verbose = VERBOSE_DEFAULT;
2897 rc = llapi_getstripe(argv[optind], ¶m);
2898 } while (++optind < argc && !rc);
2901 fprintf(stderr, "error: %s failed for %s.\n",
2902 argv[0], argv[optind - 1]);
2907 static int lfs_setdirstripe(int argc, char **argv)
2911 unsigned int stripe_offset = -1;
2912 unsigned int stripe_count = 1;
2913 enum lmv_hash_type hash_type;
2916 char *stripe_offset_opt = NULL;
2917 char *stripe_count_opt = NULL;
2918 char *stripe_hash_opt = NULL;
2919 char *mode_opt = NULL;
2920 bool default_stripe = false;
2921 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2922 mode_t previous_mode = 0;
2923 bool delete = false;
2925 struct option long_opts[] = {
2926 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2927 { .val = 'c', .name = "count", .has_arg = required_argument },
2929 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2930 { .val = 'd', .name = "delete", .has_arg = no_argument },
2931 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2932 { .val = 'i', .name = "index", .has_arg = required_argument },
2934 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2935 { .val = 'm', .name = "mode", .has_arg = required_argument },
2936 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2937 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2938 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2940 {"mdt-hash", required_argument, 0, 'H'},
2941 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2942 { .val = 'D', .name = "default_stripe",
2943 .has_arg = no_argument },
2945 { .val = 'D', .name = "default", .has_arg = no_argument },
2948 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2955 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2956 if (strcmp(argv[optind - 1], "--count") == 0)
2958 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
2961 stripe_count_opt = optarg;
2965 default_stripe = true;
2968 default_stripe = true;
2971 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2972 if (strcmp(argv[optind - 1], "--index") == 0)
2974 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
2977 stripe_offset_opt = optarg;
2982 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2986 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2987 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2989 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
2992 stripe_hash_opt = optarg;
2995 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2996 progname, argv[0], argv[optind - 1]);
3001 if (optind == argc) {
3002 fprintf(stderr, "%s %s: DIR must be specified\n",
3007 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
3009 "%s %s: stripe offset and count must be specified\n",
3014 if (stripe_offset_opt != NULL) {
3015 /* get the stripe offset */
3016 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
3019 "%s %s: bad stripe offset '%s'\n",
3020 progname, argv[0], stripe_offset_opt);
3026 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3028 "%s %s: cannot specify -d with -c or -i options\n",
3037 if (mode_opt != NULL) {
3038 mode = strtoul(mode_opt, &end, 8);
3041 "%s %s: bad MODE '%s'\n",
3042 progname, argv[0], mode_opt);
3045 previous_mode = umask(0);
3048 if (stripe_hash_opt == NULL) {
3049 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3051 hash_type = check_hashtype(stripe_hash_opt);
3052 if (hash_type == 0) {
3053 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3054 progname, argv[0], stripe_hash_opt);
3059 /* get the stripe count */
3060 if (stripe_count_opt != NULL) {
3061 stripe_count = strtoul(stripe_count_opt, &end, 0);
3064 "%s %s: bad stripe count '%s'\n",
3065 progname, argv[0], stripe_count_opt);
3070 dname = argv[optind];
3072 if (default_stripe) {
3073 result = llapi_dir_set_default_lmv_stripe(dname,
3074 stripe_offset, stripe_count,
3077 result = llapi_dir_create_pool(dname, mode,
3079 stripe_count, hash_type,
3085 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3086 progname, dname, strerror(-result));
3089 dname = argv[++optind];
3090 } while (dname != NULL);
3092 if (mode_opt != NULL)
3093 umask(previous_mode);
3099 static int lfs_rmentry(int argc, char **argv)
3106 fprintf(stderr, "error: %s: missing dirname\n",
3112 dname = argv[index];
3113 while (dname != NULL) {
3114 result = llapi_direntry_remove(dname);
3116 fprintf(stderr, "error: %s: remove dir entry '%s' "
3117 "failed\n", argv[0], dname);
3120 dname = argv[++index];
3125 static int lfs_mv(int argc, char **argv)
3127 struct find_param param = {
3134 struct option long_opts[] = {
3135 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3136 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3139 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3142 param.fp_mdt_index = strtoul(optarg, &end, 0);
3144 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3151 param.fp_verbose = VERBOSE_DETAIL;
3155 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3156 argv[0], argv[optind - 1]);
3161 if (param.fp_mdt_index == -1) {
3162 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3166 if (optind >= argc) {
3167 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3171 param.fp_migrate = 1;
3172 rc = llapi_migrate_mdt(argv[optind], ¶m);
3174 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3175 argv[0], argv[optind], param.fp_mdt_index,
3180 static int lfs_osts(int argc, char **argv)
3182 return lfs_tgts(argc, argv);
3185 static int lfs_mdts(int argc, char **argv)
3187 return lfs_tgts(argc, argv);
3190 #define COOK(value) \
3193 while (value > 1024) { \
3201 #define CDF "%11llu"
3202 #define HDF "%8.1f%c"
3207 MNTDF_INODES = 0x0001,
3208 MNTDF_COOKED = 0x0002,
3209 MNTDF_LAZY = 0x0004,
3210 MNTDF_VERBOSE = 0x0008,
3213 static int showdf(char *mntdir, struct obd_statfs *stat,
3214 char *uuid, enum mntdf_flags flags,
3215 char *type, int index, int rc)
3217 long long avail, used, total;
3219 char *suffix = "KMGTPEZY";
3220 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3221 char tbuf[3 * sizeof(__u64)];
3222 char ubuf[3 * sizeof(__u64)];
3223 char abuf[3 * sizeof(__u64)];
3224 char rbuf[3 * sizeof(__u64)];
3231 if (flags & MNTDF_INODES) {
3232 avail = stat->os_ffree;
3233 used = stat->os_files - stat->os_ffree;
3234 total = stat->os_files;
3236 int shift = flags & MNTDF_COOKED ? 0 : 10;
3238 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3239 used = ((stat->os_blocks - stat->os_bfree) *
3240 stat->os_bsize) >> shift;
3241 total = (stat->os_blocks * stat->os_bsize) >> shift;
3244 if ((used + avail) > 0)
3245 ratio = (double)used / (double)(used + avail);
3247 if (flags & MNTDF_COOKED) {
3251 cook_val = (double)total;
3254 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3257 snprintf(tbuf, sizeof(tbuf), CDF, total);
3259 cook_val = (double)used;
3262 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3265 snprintf(ubuf, sizeof(ubuf), CDF, used);
3267 cook_val = (double)avail;
3270 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3273 snprintf(abuf, sizeof(abuf), CDF, avail);
3275 snprintf(tbuf, sizeof(tbuf), CDF, total);
3276 snprintf(ubuf, sizeof(tbuf), CDF, used);
3277 snprintf(abuf, sizeof(tbuf), CDF, avail);
3280 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3281 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3282 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3284 printf("[%s:%d]", type, index);
3286 if (stat->os_state) {
3288 * Each character represents the matching
3291 const char state_names[] = "DRSI";
3296 for (i = 0, state = stat->os_state;
3297 state && i < sizeof(state_names); i++) {
3298 if (!(state & (1 << i)))
3300 printf("%c", state_names[i]);
3308 printf(UUF": inactive device\n", uuid);
3311 printf(UUF": %s\n", uuid, strerror(-rc));
3318 struct ll_stat_type {
3323 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3325 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3326 struct obd_uuid uuid_buf;
3327 char *poolname = NULL;
3328 struct ll_stat_type types[] = {
3329 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3330 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3331 { .st_name = NULL } };
3332 struct ll_stat_type *tp;
3333 __u64 ost_ffree = 0;
3341 poolname = strchr(pool, '.');
3342 if (poolname != NULL) {
3343 if (strncmp(fsname, pool, strlen(fsname))) {
3344 fprintf(stderr, "filesystem name incorrect\n");
3352 fd = open(mntdir, O_RDONLY);
3355 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3360 if (flags & MNTDF_INODES)
3361 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3362 "UUID", "Inodes", "IUsed", "IFree",
3363 "IUse%", "Mounted on");
3365 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3366 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3367 "Used", "Available", "Use%", "Mounted on");
3369 for (tp = types; tp->st_name != NULL; tp++) {
3370 for (index = 0; ; index++) {
3371 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3372 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3373 type = flags & MNTDF_LAZY ?
3374 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3375 rc2 = llapi_obd_fstatfs(fd, type, index,
3376 &stat_buf, &uuid_buf);
3381 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3382 if (!(flags & MNTDF_VERBOSE))
3384 } else if (rc2 < 0 && rc == 0) {
3388 if (poolname && tp->st_op == LL_STATFS_LOV &&
3389 llapi_search_ost(fsname, poolname,
3390 obd_uuid2str(&uuid_buf)) != 1)
3393 /* the llapi_obd_statfs() call may have returned with
3394 * an error, but if it filled in uuid_buf we will at
3395 * lease use that to print out a message for that OBD.
3396 * If we didn't get anything in the uuid_buf, then fill
3397 * it in so that we can print an error message. */
3398 if (uuid_buf.uuid[0] == '\0')
3399 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3400 "%s%04x", tp->st_name, index);
3401 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3402 flags, tp->st_name, index, rc2);
3405 if (tp->st_op == LL_STATFS_LMV) {
3406 sum.os_ffree += stat_buf.os_ffree;
3407 sum.os_files += stat_buf.os_files;
3408 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3409 sum.os_blocks += stat_buf.os_blocks *
3411 sum.os_bfree += stat_buf.os_bfree *
3413 sum.os_bavail += stat_buf.os_bavail *
3415 ost_ffree += stat_buf.os_ffree;
3423 /* If we don't have as many objects free on the OST as inodes
3424 * on the MDS, we reduce the total number of inodes to
3425 * compensate, so that the "inodes in use" number is correct.
3426 * Matches ll_statfs_internal() so the results are consistent. */
3427 if (ost_ffree < sum.os_ffree) {
3428 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3429 sum.os_ffree = ost_ffree;
3432 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3438 static int lfs_df(int argc, char **argv)
3440 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3441 enum mntdf_flags flags = 0;
3442 int c, rc = 0, index = 0;
3443 char fsname[PATH_MAX] = "", *pool_name = NULL;
3444 struct option long_opts[] = {
3445 { .val = 'h', .name = "human-readable",
3446 .has_arg = no_argument },
3447 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3448 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3449 { .val = 'p', .name = "pool", .has_arg = required_argument },
3450 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3453 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3456 flags |= MNTDF_COOKED;
3459 flags |= MNTDF_INODES;
3462 flags |= MNTDF_LAZY;
3468 flags |= MNTDF_VERBOSE;
3474 if (optind < argc && !realpath(argv[optind], path)) {
3476 fprintf(stderr, "error: invalid path '%s': %s\n",
3477 argv[optind], strerror(-rc));
3481 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3482 /* Check if we have a mount point */
3483 if (mntdir[0] == '\0')
3486 rc = mntdf(mntdir, fsname, pool_name, flags);
3487 if (rc || path[0] != '\0')
3489 fsname[0] = '\0'; /* avoid matching in next loop */
3490 mntdir[0] = '\0'; /* avoid matching in next loop */
3496 static int lfs_getname(int argc, char **argv)
3498 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3499 int rc = 0, index = 0, c;
3500 char buf[sizeof(struct obd_uuid)];
3502 while ((c = getopt(argc, argv, "h")) != -1)
3505 if (optind == argc) { /* no paths specified, get all paths. */
3506 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3507 rc = llapi_getname(mntdir, buf, sizeof(buf));
3510 "cannot get name for `%s': %s\n",
3511 mntdir, strerror(-rc));
3515 printf("%s %s\n", buf, mntdir);
3517 path[0] = fsname[0] = mntdir[0] = 0;
3519 } else { /* paths specified, only attempt to search these. */
3520 for (; optind < argc; optind++) {
3521 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3524 "cannot get name for `%s': %s\n",
3525 argv[optind], strerror(-rc));
3529 printf("%s %s\n", buf, argv[optind]);
3535 static int lfs_check(int argc, char **argv)
3538 char mntdir[PATH_MAX] = {'\0'};
3547 obd_types[0] = obd_type1;
3548 obd_types[1] = obd_type2;
3550 if (strcmp(argv[1], "osts") == 0) {
3551 strcpy(obd_types[0], "osc");
3552 } else if (strcmp(argv[1], "mds") == 0) {
3553 strcpy(obd_types[0], "mdc");
3554 } else if (strcmp(argv[1], "servers") == 0) {
3556 strcpy(obd_types[0], "osc");
3557 strcpy(obd_types[1], "mdc");
3559 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3564 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3565 if (rc < 0 || mntdir[0] == '\0') {
3566 fprintf(stderr, "No suitable Lustre mount found\n");
3570 rc = llapi_target_check(num_types, obd_types, mntdir);
3572 fprintf(stderr, "error: %s: %s status failed\n",
3579 #ifdef HAVE_SYS_QUOTA_H
3580 #define ARG2INT(nr, str, msg) \
3583 nr = strtol(str, &endp, 0); \
3585 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3590 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3592 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3593 * returns the value or ULONG_MAX on integer overflow or incorrect format
3595 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3596 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3597 * 3. empty integer value is interpreted as 0
3599 static unsigned long str2sec(const char* timestr)
3601 const char spec[] = "smhdw";
3602 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3603 unsigned long val = 0;
3606 if (strpbrk(timestr, spec) == NULL) {
3607 /* no specifiers inside the time string,
3608 should treat it as an integer value */
3609 val = strtoul(timestr, &tail, 10);
3610 return *tail ? ULONG_MAX : val;
3613 /* format string is XXwXXdXXhXXmXXs */
3619 v = strtoul(timestr, &tail, 10);
3620 if (v == ULONG_MAX || *tail == '\0')
3621 /* value too large (ULONG_MAX or more)
3622 or missing specifier */
3625 ptr = strchr(spec, *tail);
3627 /* unknown specifier */
3632 /* check if product will overflow the type */
3633 if (!(v < ULONG_MAX / mult[ind]))
3636 ADD_OVERFLOW(val, mult[ind] * v);
3637 if (val == ULONG_MAX)
3649 #define ARG2ULL(nr, str, def_units) \
3651 unsigned long long limit, units = def_units; \
3654 rc = llapi_parse_size(str, &limit, &units, 1); \
3656 fprintf(stderr, "error: bad limit value %s\n", str); \
3662 static inline int has_times_option(int argc, char **argv)
3666 for (i = 1; i < argc; i++)
3667 if (!strcmp(argv[i], "-t"))
3673 int lfs_setquota_times(int argc, char **argv)
3676 struct if_quotactl qctl;
3677 char *mnt, *obd_type = (char *)qctl.obd_type;
3678 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3679 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3680 struct option long_opts[] = {
3681 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3682 { .val = 'g', .name = "group", .has_arg = no_argument },
3683 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3684 { .val = 'p', .name = "projid", .has_arg = no_argument },
3685 { .val = 't', .name = "times", .has_arg = no_argument },
3686 { .val = 'u', .name = "user", .has_arg = no_argument },
3690 memset(&qctl, 0, sizeof(qctl));
3691 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3692 qctl.qc_type = ALLQUOTA;
3694 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3695 long_opts, NULL)) != -1) {
3706 if (qctl.qc_type != ALLQUOTA) {
3707 fprintf(stderr, "error: -u/g/p can't be used "
3708 "more than once\n");
3711 qctl.qc_type = qtype;
3714 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3715 fprintf(stderr, "error: bad block-grace: %s\n",
3719 dqb->dqb_valid |= QIF_BTIME;
3722 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3723 fprintf(stderr, "error: bad inode-grace: %s\n",
3727 dqb->dqb_valid |= QIF_ITIME;
3729 case 't': /* Yes, of course! */
3731 default: /* getopt prints error message for us when opterr != 0 */
3736 if (qctl.qc_type == ALLQUOTA) {
3737 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3741 if (optind != argc - 1) {
3742 fprintf(stderr, "error: unexpected parameters encountered\n");
3747 rc = llapi_quotactl(mnt, &qctl);
3750 fprintf(stderr, "%s %s ", obd_type,
3751 obd_uuid2str(&qctl.obd_uuid));
3752 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3759 #define BSLIMIT (1 << 0)
3760 #define BHLIMIT (1 << 1)
3761 #define ISLIMIT (1 << 2)
3762 #define IHLIMIT (1 << 3)
3764 int lfs_setquota(int argc, char **argv)
3767 struct if_quotactl qctl;
3768 char *mnt, *obd_type = (char *)qctl.obd_type;
3769 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3770 struct option long_opts[] = {
3771 { .val = 'b', .name = "block-softlimit",
3772 .has_arg = required_argument },
3773 { .val = 'B', .name = "block-hardlimit",
3774 .has_arg = required_argument },
3775 { .val = 'g', .name = "group", .has_arg = required_argument },
3776 { .val = 'i', .name = "inode-softlimit",
3777 .has_arg = required_argument },
3778 { .val = 'I', .name = "inode-hardlimit",
3779 .has_arg = required_argument },
3780 { .val = 'p', .name = "projid", .has_arg = required_argument },
3781 { .val = 'u', .name = "user", .has_arg = required_argument },
3783 unsigned limit_mask = 0;
3787 if (has_times_option(argc, argv))
3788 return lfs_setquota_times(argc, argv);
3790 memset(&qctl, 0, sizeof(qctl));
3791 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3792 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3793 * so it can be used as a marker that qc_type
3794 * isn't reinitialized from command line */
3796 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3797 long_opts, NULL)) != -1) {
3801 rc = name2uid(&qctl.qc_id, optarg);
3805 rc = name2gid(&qctl.qc_id, optarg);
3809 rc = name2projid(&qctl.qc_id, optarg);
3811 if (qctl.qc_type != ALLQUOTA) {
3812 fprintf(stderr, "error: -u and -g can't be used"
3813 " more than once\n");
3816 qctl.qc_type = qtype;
3818 qctl.qc_id = strtoul(optarg, &endptr, 10);
3819 if (*endptr != '\0') {
3820 fprintf(stderr, "error: can't find id "
3821 "for name %s\n", optarg);
3827 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3828 dqb->dqb_bsoftlimit >>= 10;
3829 limit_mask |= BSLIMIT;
3830 if (dqb->dqb_bsoftlimit &&
3831 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3832 fprintf(stderr, "warning: block softlimit is "
3833 "smaller than the miminal qunit size, "
3834 "please see the help of setquota or "
3835 "Lustre manual for details.\n");
3838 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3839 dqb->dqb_bhardlimit >>= 10;
3840 limit_mask |= BHLIMIT;
3841 if (dqb->dqb_bhardlimit &&
3842 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3843 fprintf(stderr, "warning: block hardlimit is "
3844 "smaller than the miminal qunit size, "
3845 "please see the help of setquota or "
3846 "Lustre manual for details.\n");
3849 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3850 limit_mask |= ISLIMIT;
3851 if (dqb->dqb_isoftlimit &&
3852 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3853 fprintf(stderr, "warning: inode softlimit is "
3854 "smaller than the miminal qunit size, "
3855 "please see the help of setquota or "
3856 "Lustre manual for details.\n");
3859 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3860 limit_mask |= IHLIMIT;
3861 if (dqb->dqb_ihardlimit &&
3862 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3863 fprintf(stderr, "warning: inode hardlimit is "
3864 "smaller than the miminal qunit size, "
3865 "please see the help of setquota or "
3866 "Lustre manual for details.\n");
3868 default: /* getopt prints error message for us when opterr != 0 */
3873 if (qctl.qc_type == ALLQUOTA) {
3874 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3878 if (limit_mask == 0) {
3879 fprintf(stderr, "error: at least one limit must be specified\n");
3883 if (optind != argc - 1) {
3884 fprintf(stderr, "error: unexpected parameters encountered\n");
3890 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3891 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3892 /* sigh, we can't just set blimits/ilimits */
3893 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3894 .qc_type = qctl.qc_type,
3895 .qc_id = qctl.qc_id};
3897 rc = llapi_quotactl(mnt, &tmp_qctl);
3899 fprintf(stderr, "error: setquota failed while retrieving"
3900 " current quota settings (%s)\n",
3905 if (!(limit_mask & BHLIMIT))
3906 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3907 if (!(limit_mask & BSLIMIT))
3908 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3909 if (!(limit_mask & IHLIMIT))
3910 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3911 if (!(limit_mask & ISLIMIT))
3912 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3914 /* Keep grace times if we have got no softlimit arguments */
3915 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3916 dqb->dqb_valid |= QIF_BTIME;
3917 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3920 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3921 dqb->dqb_valid |= QIF_ITIME;
3922 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3926 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3927 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3929 rc = llapi_quotactl(mnt, &qctl);
3932 fprintf(stderr, "%s %s ", obd_type,
3933 obd_uuid2str(&qctl.obd_uuid));
3934 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3941 /* Converts seconds value into format string
3942 * result is returned in buf
3944 * 1. result is in descenting order: 1w2d3h4m5s
3945 * 2. zero fields are not filled (except for p. 3): 5d1s
3946 * 3. zero seconds value is presented as "0s"
3948 static char * __sec2str(time_t seconds, char *buf)
3950 const char spec[] = "smhdw";
3951 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3956 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3957 c = seconds / mult[i];
3959 if (c > 0 || (i == 0 && buf == tail))
3960 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3968 static void sec2str(time_t seconds, char *buf, int rc)
3975 tail = __sec2str(seconds, tail);
3977 if (rc && tail - buf < 39) {
3983 static void diff2str(time_t seconds, char *buf, time_t now)
3989 if (seconds <= now) {
3990 strcpy(buf, "none");
3993 __sec2str(seconds - now, buf);
3996 static void print_quota_title(char *name, struct if_quotactl *qctl,
3997 bool human_readable)
3999 printf("Disk quotas for %s %s (%cid %u):\n",
4000 qtype_name(qctl->qc_type), name,
4001 *qtype_name(qctl->qc_type), qctl->qc_id);
4002 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4003 "Filesystem", human_readable ? "used" : "kbytes",
4004 "quota", "limit", "grace",
4005 "files", "quota", "limit", "grace");
4008 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4011 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4014 snprintf(buf, buflen, "%5.4gP",
4015 (double)num / ((__u64)1 << 40));
4017 snprintf(buf, buflen, "%5.4gT",
4018 (double)num / (1 << 30));
4020 snprintf(buf, buflen, "%5.4gG",
4021 (double)num / (1 << 20));
4023 snprintf(buf, buflen, "%5.4gM",
4024 (double)num / (1 << 10));
4026 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4030 #define STRBUF_LEN 32
4031 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4038 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4039 int bover = 0, iover = 0;
4040 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4041 char numbuf[3][STRBUF_LEN];
4043 char strbuf[STRBUF_LEN];
4045 if (dqb->dqb_bhardlimit &&
4046 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4048 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4049 if (dqb->dqb_btime > now) {
4056 if (dqb->dqb_ihardlimit &&
4057 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4059 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4060 if (dqb->dqb_itime > now) {
4068 if (strlen(mnt) > 15)
4069 printf("%s\n%15s", mnt, "");
4071 printf("%15s", mnt);
4074 diff2str(dqb->dqb_btime, timebuf, now);
4076 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4077 strbuf, sizeof(strbuf), h);
4078 if (rc == -EREMOTEIO)
4079 sprintf(numbuf[0], "%s*", strbuf);
4081 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4082 "%s" : "[%s]", strbuf);
4084 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4085 if (type == QC_GENERAL)
4086 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4087 "%s" : "[%s]", strbuf);
4089 sprintf(numbuf[1], "%s", "-");
4091 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4092 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4093 "%s" : "[%s]", strbuf);
4095 printf(" %7s%c %6s %7s %7s",
4096 numbuf[0], bover ? '*' : ' ', numbuf[1],
4097 numbuf[2], bover > 1 ? timebuf : "-");
4100 diff2str(dqb->dqb_itime, timebuf, now);
4102 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4103 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4105 if (type == QC_GENERAL)
4106 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4108 (uintmax_t)dqb->dqb_isoftlimit);
4110 sprintf(numbuf[1], "%s", "-");
4112 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4113 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4115 if (type != QC_OSTIDX)
4116 printf(" %7s%c %6s %7s %7s",
4117 numbuf[0], iover ? '*' : ' ', numbuf[1],
4118 numbuf[2], iover > 1 ? timebuf : "-");
4120 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4123 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4124 qctl->qc_cmd == Q_GETOINFO) {
4128 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4129 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4130 printf("Block grace time: %s; Inode grace time: %s\n",
4131 bgtimebuf, igtimebuf);
4135 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4136 bool h, __u64 *total)
4138 int rc = 0, rc1 = 0, count = 0;
4139 __u32 valid = qctl->qc_valid;
4141 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4143 fprintf(stderr, "can not get %s count: %s\n",
4144 is_mdt ? "mdt": "ost", strerror(-rc));
4148 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4149 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4150 rc = llapi_quotactl(mnt, qctl);
4152 /* It is remote client case. */
4153 if (rc == -EOPNOTSUPP) {
4160 fprintf(stderr, "quotactl %s%d failed.\n",
4161 is_mdt ? "mdt": "ost", qctl->qc_idx);
4165 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4166 qctl->qc_valid, 0, h);
4167 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4168 qctl->qc_dqblk.dqb_bhardlimit;
4171 qctl->qc_valid = valid;
4175 static int lfs_quota(int argc, char **argv)
4178 char *mnt, *name = NULL;
4179 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4180 .qc_type = ALLQUOTA };
4181 char *obd_type = (char *)qctl.obd_type;
4182 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4183 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4184 verbose = 0, pass = 0, quiet = 0, inacc;
4186 __u32 valid = QC_GENERAL, idx = 0;
4187 __u64 total_ialloc = 0, total_balloc = 0;
4188 bool human_readable = false;
4191 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4202 if (qctl.qc_type != ALLQUOTA) {
4203 fprintf(stderr, "error: use either -u or -g\n");
4206 qctl.qc_type = qtype;
4209 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4212 valid = qctl.qc_valid = QC_UUID;
4213 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4216 valid = qctl.qc_valid = QC_MDTIDX;
4217 idx = qctl.qc_idx = atoi(optarg);
4220 valid = qctl.qc_valid = QC_OSTIDX;
4221 idx = qctl.qc_idx = atoi(optarg);
4230 human_readable = true;
4233 fprintf(stderr, "error: %s: option '-%c' "
4234 "unrecognized\n", argv[0], c);
4239 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4240 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4241 optind == argc - 1) {
4243 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4244 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4245 qctl.qc_valid = valid;
4247 qctl.qc_type = pass;
4248 switch (qctl.qc_type) {
4250 qctl.qc_id = geteuid();
4251 rc = uid2name(&name, qctl.qc_id);
4254 qctl.qc_id = getegid();
4255 rc = gid2name(&name, qctl.qc_id);
4264 /* lfs quota -u username /path/to/lustre/mount */
4265 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4266 /* options should be followed by u/g-name and mntpoint */
4267 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4268 fprintf(stderr, "error: missing quota argument(s)\n");
4272 name = argv[optind++];
4273 switch (qctl.qc_type) {
4275 rc = name2uid(&qctl.qc_id, name);
4278 rc = name2gid(&qctl.qc_id, name);
4281 rc = name2projid(&qctl.qc_id, name);
4288 qctl.qc_id = strtoul(name, &endptr, 10);
4289 if (*endptr != '\0') {
4290 fprintf(stderr, "error: can't find id for name: %s\n",
4295 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4296 fprintf(stderr, "error: missing quota info argument(s)\n");
4301 rc1 = llapi_quotactl(mnt, &qctl);
4305 fprintf(stderr, "%s quotas are not enabled.\n",
4306 qtype_name(qctl.qc_type));
4309 fprintf(stderr, "Permission denied.\n");
4312 /* We already got error message. */
4315 fprintf(stderr, "Unexpected quotactl error: %s\n",
4320 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4321 print_quota_title(name, &qctl, human_readable);
4323 if (rc1 && *obd_type)
4324 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4326 if (qctl.qc_valid != QC_GENERAL)
4329 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4330 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4331 (QIF_LIMITS|QIF_USAGE));
4333 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4335 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4337 char strbuf[STRBUF_LEN];
4339 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4341 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4343 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4345 printf("Total allocated inode limit: %ju, total "
4346 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4350 if (rc1 || rc2 || rc3 || inacc)
4351 printf("Some errors happened when getting quota info. "
4352 "Some devices may be not working or deactivated. "
4353 "The data in \"[]\" is inaccurate.\n");
4356 if (pass > 0 && pass < LL_MAXQUOTAS)
4361 #endif /* HAVE_SYS_QUOTA_H! */
4363 static int flushctx_ioctl(char *mp)
4367 fd = open(mp, O_RDONLY);
4369 fprintf(stderr, "flushctx: error open %s: %s\n",
4370 mp, strerror(errno));
4374 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4376 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4377 mp, strerror(errno));
4383 static int lfs_flushctx(int argc, char **argv)
4385 int kdestroy = 0, c;
4386 char mntdir[PATH_MAX] = {'\0'};
4390 while ((c = getopt(argc, argv, "k")) != -1) {
4396 fprintf(stderr, "error: %s: option '-%c' "
4397 "unrecognized\n", argv[0], c);
4403 if ((rc = system("kdestroy > /dev/null")) != 0) {
4404 rc = WEXITSTATUS(rc);
4405 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4409 if (optind >= argc) {
4410 /* flush for all mounted lustre fs. */
4411 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4412 /* Check if we have a mount point */
4413 if (mntdir[0] == '\0')
4416 if (flushctx_ioctl(mntdir))
4419 mntdir[0] = '\0'; /* avoid matching in next loop */
4422 /* flush fs as specified */
4423 while (optind < argc) {
4424 if (flushctx_ioctl(argv[optind++]))
4431 static int lfs_cp(int argc, char **argv)
4433 fprintf(stderr, "remote client copy file(s).\n"
4434 "obsolete, does not support it anymore.\n");
4438 static int lfs_ls(int argc, char **argv)
4440 fprintf(stderr, "remote client lists directory contents.\n"
4441 "obsolete, does not support it anymore.\n");
4445 static int lfs_changelog(int argc, char **argv)
4447 void *changelog_priv;
4448 struct changelog_rec *rec;
4449 long long startrec = 0, endrec = 0;
4451 struct option long_opts[] = {
4452 { .val = 'f', .name = "follow", .has_arg = no_argument },
4454 char short_opts[] = "f";
4457 while ((rc = getopt_long(argc, argv, short_opts,
4458 long_opts, NULL)) != -1) {
4466 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4467 argv[0], argv[optind - 1]);
4474 mdd = argv[optind++];
4476 startrec = strtoll(argv[optind++], NULL, 10);
4478 endrec = strtoll(argv[optind++], NULL, 10);
4480 rc = llapi_changelog_start(&changelog_priv,
4481 CHANGELOG_FLAG_BLOCK |
4482 CHANGELOG_FLAG_JOBID |
4483 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4486 fprintf(stderr, "Can't start changelog: %s\n",
4487 strerror(errno = -rc));
4491 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4495 if (endrec && rec->cr_index > endrec) {
4496 llapi_changelog_free(&rec);
4499 if (rec->cr_index < startrec) {
4500 llapi_changelog_free(&rec);
4504 secs = rec->cr_time >> 30;
4505 gmtime_r(&secs, &ts);
4506 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4507 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4508 changelog_type2str(rec->cr_type),
4509 ts.tm_hour, ts.tm_min, ts.tm_sec,
4510 (int)(rec->cr_time & ((1 << 30) - 1)),
4511 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4512 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4514 if (rec->cr_flags & CLF_JOBID) {
4515 struct changelog_ext_jobid *jid =
4516 changelog_rec_jobid(rec);
4518 if (jid->cr_jobid[0] != '\0')
4519 printf(" j=%s", jid->cr_jobid);
4522 if (rec->cr_namelen)
4523 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4524 rec->cr_namelen, changelog_rec_name(rec));
4526 if (rec->cr_flags & CLF_RENAME) {
4527 struct changelog_ext_rename *rnm =
4528 changelog_rec_rename(rec);
4530 if (!fid_is_zero(&rnm->cr_sfid))
4531 printf(" s="DFID" sp="DFID" %.*s",
4532 PFID(&rnm->cr_sfid),
4533 PFID(&rnm->cr_spfid),
4534 (int)changelog_rec_snamelen(rec),
4535 changelog_rec_sname(rec));
4539 llapi_changelog_free(&rec);
4542 llapi_changelog_fini(&changelog_priv);
4545 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4547 return (rc == 1 ? 0 : rc);
4550 static int lfs_changelog_clear(int argc, char **argv)
4558 endrec = strtoll(argv[3], NULL, 10);
4560 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4563 fprintf(stderr, "%s: record out of range: %llu\n",
4565 else if (rc == -ENOENT)
4566 fprintf(stderr, "%s: no changelog user: %s\n",
4569 fprintf(stderr, "%s error: %s\n", argv[0],
4578 static int lfs_fid2path(int argc, char **argv)
4580 struct option long_opts[] = {
4581 { .val = 'c', .name = "cur", .has_arg = no_argument },
4582 { .val = 'l', .name = "link", .has_arg = required_argument },
4583 { .val = 'r', .name = "rec", .has_arg = required_argument },
4585 char short_opts[] = "cl:r:";
4586 char *device, *fid, *path;
4587 long long recno = -1;
4593 while ((rc = getopt_long(argc, argv, short_opts,
4594 long_opts, NULL)) != -1) {
4600 linkno = strtol(optarg, NULL, 10);
4603 recno = strtoll(optarg, NULL, 10);
4608 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4609 argv[0], argv[optind - 1]);
4617 device = argv[optind++];
4618 path = calloc(1, PATH_MAX);
4620 fprintf(stderr, "error: Not enough memory\n");
4625 while (optind < argc) {
4626 fid = argv[optind++];
4628 lnktmp = (linkno >= 0) ? linkno : 0;
4630 int oldtmp = lnktmp;
4631 long long rectmp = recno;
4633 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4636 fprintf(stderr, "%s: error on FID %s: %s\n",
4637 argv[0], fid, strerror(errno = -rc2));
4644 fprintf(stdout, "%lld ", rectmp);
4645 if (device[0] == '/') {
4646 fprintf(stdout, "%s", device);
4647 if (device[strlen(device) - 1] != '/')
4648 fprintf(stdout, "/");
4649 } else if (path[0] == '\0') {
4650 fprintf(stdout, "/");
4652 fprintf(stdout, "%s\n", path);
4655 /* specified linkno */
4657 if (oldtmp == lnktmp)
4667 static int lfs_path2fid(int argc, char **argv)
4669 struct option long_opts[] = {
4670 { .val = 'p', .name = "parents", .has_arg = no_argument },
4673 const char short_opts[] = "p";
4674 const char *sep = "";
4677 bool show_parents = false;
4679 while ((rc = getopt_long(argc, argv, short_opts,
4680 long_opts, NULL)) != -1) {
4683 show_parents = true;
4686 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4687 argv[0], argv[optind - 1]);
4692 if (optind > argc - 1)
4694 else if (optind < argc - 1)
4698 for (path = argv + optind; *path != NULL; path++) {
4700 if (!show_parents) {
4701 err = llapi_path2fid(*path, &fid);
4703 printf("%s%s"DFID"\n",
4704 *sep != '\0' ? *path : "", sep,
4707 char name[NAME_MAX + 1];
4708 unsigned int linkno = 0;
4710 while ((err = llapi_path2parent(*path, linkno, &fid,
4711 name, sizeof(name))) == 0) {
4712 if (*sep != '\0' && linkno == 0)
4713 printf("%s%s", *path, sep);
4715 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4720 /* err == -ENODATA is end-of-loop */
4721 if (linkno > 0 && err == -ENODATA) {
4728 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4729 argv[0], show_parents ? "parent " : "", *path,
4741 static int lfs_data_version(int argc, char **argv)
4748 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4753 while ((c = getopt(argc, argv, "nrw")) != -1) {
4756 data_version_flags = 0;
4759 data_version_flags |= LL_DV_RD_FLUSH;
4762 data_version_flags |= LL_DV_WR_FLUSH;
4771 path = argv[optind];
4772 fd = open(path, O_RDONLY);
4774 err(errno, "cannot open file %s", path);
4776 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4778 err(errno, "cannot get version for %s", path);
4780 printf("%ju" "\n", (uintmax_t)data_version);
4786 static int lfs_hsm_state(int argc, char **argv)
4791 struct hsm_user_state hus;
4799 rc = llapi_hsm_state_get(path, &hus);
4801 fprintf(stderr, "can't get hsm state for %s: %s\n",
4802 path, strerror(errno = -rc));
4806 /* Display path name and status flags */
4807 printf("%s: (0x%08x)", path, hus.hus_states);
4809 if (hus.hus_states & HS_RELEASED)
4810 printf(" released");
4811 if (hus.hus_states & HS_EXISTS)
4813 if (hus.hus_states & HS_DIRTY)
4815 if (hus.hus_states & HS_ARCHIVED)
4816 printf(" archived");
4817 /* Display user-settable flags */
4818 if (hus.hus_states & HS_NORELEASE)
4819 printf(" never_release");
4820 if (hus.hus_states & HS_NOARCHIVE)
4821 printf(" never_archive");
4822 if (hus.hus_states & HS_LOST)
4823 printf(" lost_from_hsm");
4825 if (hus.hus_archive_id != 0)
4826 printf(", archive_id:%d", hus.hus_archive_id);
4829 } while (++i < argc);
4834 #define LFS_HSM_SET 0
4835 #define LFS_HSM_CLEAR 1
4838 * Generic function to set or clear HSM flags.
4839 * Used by hsm_set and hsm_clear.
4841 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4843 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4845 struct option long_opts[] = {
4846 { .val = 'A', .name = "archived", .has_arg = no_argument },
4847 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4848 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4849 { .val = 'e', .name = "exists", .has_arg = no_argument },
4850 { .val = 'l', .name = "lost", .has_arg = no_argument },
4851 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4853 char short_opts[] = "lraAde";
4861 while ((c = getopt_long(argc, argv, short_opts,
4862 long_opts, NULL)) != -1) {
4868 mask |= HS_NOARCHIVE;
4871 mask |= HS_ARCHIVED;
4874 mask |= HS_NORELEASE;
4885 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4886 argv[0], argv[optind - 1]);
4891 /* User should have specified a flag */
4895 while (optind < argc) {
4897 path = argv[optind];
4899 /* If mode == 0, this means we apply the mask. */
4900 if (mode == LFS_HSM_SET)
4901 rc = llapi_hsm_state_set(path, mask, 0, 0);
4903 rc = llapi_hsm_state_set(path, 0, mask, 0);
4906 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4907 path, strerror(errno = -rc));
4916 static int lfs_hsm_action(int argc, char **argv)
4921 struct hsm_current_action hca;
4922 struct hsm_extent he;
4923 enum hsm_user_action hua;
4924 enum hsm_progress_states hps;
4932 rc = llapi_hsm_current_action(path, &hca);
4934 fprintf(stderr, "can't get hsm action for %s: %s\n",
4935 path, strerror(errno = -rc));
4938 he = hca.hca_location;
4939 hua = hca.hca_action;
4940 hps = hca.hca_state;
4942 printf("%s: %s", path, hsm_user_action2name(hua));
4944 /* Skip file without action */
4945 if (hca.hca_action == HUA_NONE) {
4950 printf(" %s ", hsm_progress_state2name(hps));
4952 if ((hps == HPS_RUNNING) &&
4953 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4954 printf("(%llu bytes moved)\n",
4955 (unsigned long long)he.length);
4956 else if ((he.offset + he.length) == LUSTRE_EOF)
4957 printf("(from %llu to EOF)\n",
4958 (unsigned long long)he.offset);
4960 printf("(from %llu to %llu)\n",
4961 (unsigned long long)he.offset,
4962 (unsigned long long)(he.offset + he.length));
4964 } while (++i < argc);
4969 static int lfs_hsm_set(int argc, char **argv)
4971 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4974 static int lfs_hsm_clear(int argc, char **argv)
4976 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4980 * Check file state and return its fid, to be used by lfs_hsm_request().
4982 * \param[in] file Path to file to check
4983 * \param[in,out] fid Pointer to allocated lu_fid struct.
4984 * \param[in,out] last_dev Pointer to last device id used.
4986 * \return 0 on success.
4988 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4994 rc = lstat(file, &st);
4996 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4999 /* Checking for regular file as archiving as posix copytool
5000 * rejects archiving files other than regular files
5002 if (!S_ISREG(st.st_mode)) {
5003 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5006 /* A request should be ... */
5007 if (*last_dev != st.st_dev && *last_dev != 0) {
5008 fprintf(stderr, "All files should be "
5009 "on the same filesystem: %s\n", file);
5012 *last_dev = st.st_dev;
5014 rc = llapi_path2fid(file, fid);
5016 fprintf(stderr, "Cannot read FID of %s: %s\n",
5017 file, strerror(-rc));
5023 /* Fill an HSM HUR item with a given file name.
5025 * If mntpath is set, then the filename is actually a FID, and no
5026 * lookup on the filesystem will be performed.
5028 * \param[in] hur the user request to fill
5029 * \param[in] idx index of the item inside the HUR to fill
5030 * \param[in] mntpath mountpoint of Lustre
5031 * \param[in] fname filename (if mtnpath is NULL)
5032 * or FID (if mntpath is set)
5033 * \param[in] last_dev pointer to last device id used
5035 * \retval 0 on success
5036 * \retval CMD_HELP or a negative errno on error
5038 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5039 const char *mntpath, const char *fname,
5042 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5045 hui->hui_extent.length = -1;
5047 if (mntpath != NULL) {
5050 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5054 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5059 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5063 hur->hur_request.hr_itemcount++;
5068 static int lfs_hsm_request(int argc, char **argv, int action)
5070 struct option long_opts[] = {
5071 { .val = 'a', .name = "archive", .has_arg = required_argument },
5072 { .val = 'D', .name = "data", .has_arg = required_argument },
5073 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5074 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5077 char short_opts[] = "l:D:a:m:";
5078 struct hsm_user_request *hur, *oldhur;
5083 char *filelist = NULL;
5084 char fullpath[PATH_MAX];
5085 char *opaque = NULL;
5089 int nbfile_alloc = 0;
5090 char *some_file = NULL;
5091 char *mntpath = NULL;
5097 while ((c = getopt_long(argc, argv, short_opts,
5098 long_opts, NULL)) != -1) {
5107 if (action != HUA_ARCHIVE &&
5108 action != HUA_REMOVE) {
5110 "error: -a is supported only "
5111 "when archiving or removing\n");
5114 archive_id = atoi(optarg);
5117 if (some_file == NULL) {
5119 some_file = strdup(optarg);
5125 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5126 argv[0], argv[optind - 1]);
5131 /* All remaining args are files, so we have at least nbfile */
5132 nbfile = argc - optind;
5134 if ((nbfile == 0) && (filelist == NULL))
5138 opaque_len = strlen(opaque);
5140 /* Alloc the request structure with enough place to store all files
5141 * from command line. */
5142 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5144 fprintf(stderr, "Cannot create the request: %s\n",
5148 nbfile_alloc = nbfile;
5150 hur->hur_request.hr_action = action;
5151 hur->hur_request.hr_archive_id = archive_id;
5152 hur->hur_request.hr_flags = 0;
5154 /* All remaining args are files, add them */
5155 if (nbfile != 0 && some_file == NULL)
5156 some_file = strdup(argv[optind]);
5158 for (i = 0; i < nbfile; i++) {
5159 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5165 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5167 /* If a filelist was specified, read the filelist from it. */
5168 if (filelist != NULL) {
5169 fp = fopen(filelist, "r");
5171 fprintf(stderr, "Cannot read the file list %s: %s\n",
5172 filelist, strerror(errno));
5177 while ((rc = getline(&line, &len, fp)) != -1) {
5178 /* If allocated buffer was too small, get something
5180 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5183 nbfile_alloc = nbfile_alloc * 2 + 1;
5185 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5188 fprintf(stderr, "hsm: cannot allocate "
5189 "the request: %s\n",
5196 size = hur_len(oldhur);
5198 fprintf(stderr, "hsm: cannot allocate "
5199 "%u files + %u bytes data\n",
5200 oldhur->hur_request.hr_itemcount,
5201 oldhur->hur_request.hr_data_len);
5208 memcpy(hur, oldhur, size);
5213 if (line[strlen(line) - 1] == '\n')
5214 line[strlen(line) - 1] = '\0';
5216 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5217 mntpath, line, &last_dev);
5223 if (some_file == NULL) {
5233 /* If a --data was used, add it to the request */
5234 hur->hur_request.hr_data_len = opaque_len;
5236 memcpy(hur_data(hur), opaque, opaque_len);
5238 /* Send the HSM request */
5239 if (realpath(some_file, fullpath) == NULL) {
5240 fprintf(stderr, "Could not find path '%s': %s\n",
5241 some_file, strerror(errno));
5243 rc = llapi_hsm_request(fullpath, hur);
5245 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5246 some_file, strerror(-rc));
5256 static int lfs_hsm_archive(int argc, char **argv)
5258 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5261 static int lfs_hsm_restore(int argc, char **argv)
5263 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5266 static int lfs_hsm_release(int argc, char **argv)
5268 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5271 static int lfs_hsm_remove(int argc, char **argv)
5273 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5276 static int lfs_hsm_cancel(int argc, char **argv)
5278 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5281 static int lfs_swap_layouts(int argc, char **argv)
5286 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5287 SWAP_LAYOUTS_KEEP_MTIME |
5288 SWAP_LAYOUTS_KEEP_ATIME);
5291 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5293 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5295 static const char *const lockahead_results[] = {
5296 [LLA_RESULT_SENT] = "Lock request sent",
5297 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5298 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5301 int lfs_get_mode(const char *string)
5303 enum lock_mode_user mode;
5305 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5306 if (lock_mode_names[mode] == NULL)
5308 if (strcmp(string, lock_mode_names[mode]) == 0)
5315 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5317 enum lu_ladvise_type advice;
5320 advice < ARRAY_SIZE(ladvise_names); advice++) {
5321 if (ladvise_names[advice] == NULL)
5323 if (strcmp(string, ladvise_names[advice]) == 0)
5327 return LU_LADVISE_INVALID;
5330 static int lfs_ladvise(int argc, char **argv)
5332 struct option long_opts[] = {
5333 { .val = 'a', .name = "advice", .has_arg = required_argument },
5334 { .val = 'b', .name = "background", .has_arg = no_argument },
5335 { .val = 'e', .name = "end", .has_arg = required_argument },
5336 { .val = 'l', .name = "length", .has_arg = required_argument },
5337 { .val = 'm', .name = "mode", .has_arg = required_argument },
5338 { .val = 's', .name = "start", .has_arg = required_argument },
5339 { .val = 'u', .name = "unset", .has_arg = no_argument },
5341 char short_opts[] = "a:be:l:m:s:u";
5346 struct llapi_lu_ladvise advice;
5347 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5348 unsigned long long start = 0;
5349 unsigned long long end = LUSTRE_EOF;
5350 unsigned long long length = 0;
5351 unsigned long long size_units;
5352 unsigned long long flags = 0;
5356 while ((c = getopt_long(argc, argv, short_opts,
5357 long_opts, NULL)) != -1) {
5360 advice_type = lfs_get_ladvice(optarg);
5361 if (advice_type == LU_LADVISE_INVALID) {
5362 fprintf(stderr, "%s: invalid advice type "
5363 "'%s'\n", argv[0], optarg);
5364 fprintf(stderr, "Valid types:");
5366 for (advice_type = 0;
5367 advice_type < ARRAY_SIZE(ladvise_names);
5369 if (ladvise_names[advice_type] == NULL)
5371 fprintf(stderr, " %s",
5372 ladvise_names[advice_type]);
5374 fprintf(stderr, "\n");
5387 rc = llapi_parse_size(optarg, &end,
5390 fprintf(stderr, "%s: bad end offset '%s'\n",
5397 rc = llapi_parse_size(optarg, &start,
5400 fprintf(stderr, "%s: bad start offset "
5401 "'%s'\n", argv[0], optarg);
5407 rc = llapi_parse_size(optarg, &length,
5410 fprintf(stderr, "%s: bad length '%s'\n",
5416 mode = lfs_get_mode(optarg);
5418 fprintf(stderr, "%s: bad mode '%s', valid "
5419 "modes are READ or WRITE\n",
5427 fprintf(stderr, "%s: option '%s' unrecognized\n",
5428 argv[0], argv[optind - 1]);
5433 if (advice_type == LU_LADVISE_INVALID) {
5434 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5435 fprintf(stderr, "Valid types:");
5436 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5438 if (ladvise_names[advice_type] == NULL)
5440 fprintf(stderr, " %s", ladvise_names[advice_type]);
5442 fprintf(stderr, "\n");
5446 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
5447 fprintf(stderr, "%s: Lock no expand advice is a per file "
5448 "descriptor advice, so when called from lfs, "
5449 "it does nothing.\n", argv[0]);
5453 if (argc <= optind) {
5454 fprintf(stderr, "%s: please give one or more file names\n",
5459 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5460 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5465 if (end == LUSTRE_EOF && length != 0)
5466 end = start + length;
5469 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5470 argv[0], start, end);
5474 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
5475 fprintf(stderr, "%s: mode is only valid with lockahead\n",
5480 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
5481 fprintf(stderr, "%s: mode is required with lockahead\n",
5486 while (optind < argc) {
5489 path = argv[optind++];
5491 fd = open(path, O_RDONLY);
5493 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5494 argv[0], path, strerror(errno));
5499 advice.lla_start = start;
5500 advice.lla_end = end;
5501 advice.lla_advice = advice_type;
5502 advice.lla_value1 = 0;
5503 advice.lla_value2 = 0;
5504 advice.lla_value3 = 0;
5505 advice.lla_value4 = 0;
5506 if (advice_type == LU_LADVISE_LOCKAHEAD) {
5507 advice.lla_lockahead_mode = mode;
5508 advice.lla_peradvice_flags = flags;
5511 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5514 fprintf(stderr, "%s: cannot give advice '%s' to file "
5515 "'%s': %s\n", argv[0],
5516 ladvise_names[advice_type],
5517 path, strerror(errno));
5523 if (rc == 0 && rc2 < 0)
5529 static int lfs_list_commands(int argc, char **argv)
5531 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5533 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5538 int main(int argc, char **argv)
5542 /* Ensure that liblustreapi constructor has run */
5543 if (!liblustreapi_initialized)
5544 fprintf(stderr, "liblustreapi was not properly initialized\n");
5548 Parser_init("lfs > ", cmdlist);
5550 progname = argv[0]; /* Used in error messages */
5552 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5554 rc = Parser_commands();
5557 return rc < 0 ? -rc : rc;
5560 #ifdef _LUSTRE_IDL_H_
5561 /* Everything we need here should be included by lustreapi.h. */
5562 # error "lfs should not depend on lustre_idl.h"
5563 #endif /* _LUSTRE_IDL_H_ */