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>
63 #include "lfs_project.h"
65 #include <libcfs/util/string.h>
66 #include <libcfs/util/ioctl.h>
67 #include <libcfs/util/parser.h>
68 #include <lustre/lustreapi.h>
69 #include <lustre_ver.h>
70 #include <linux/lustre_param.h>
73 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
74 #endif /* !ARRAY_SIZE */
77 static int lfs_setstripe(int argc, char **argv);
78 static int lfs_find(int argc, char **argv);
79 static int lfs_getstripe(int argc, char **argv);
80 static int lfs_getdirstripe(int argc, char **argv);
81 static int lfs_setdirstripe(int argc, char **argv);
82 static int lfs_rmentry(int argc, char **argv);
83 static int lfs_osts(int argc, char **argv);
84 static int lfs_mdts(int argc, char **argv);
85 static int lfs_df(int argc, char **argv);
86 static int lfs_getname(int argc, char **argv);
87 static int lfs_check(int argc, char **argv);
88 #ifdef HAVE_SYS_QUOTA_H
89 static int lfs_setquota(int argc, char **argv);
90 static int lfs_quota(int argc, char **argv);
91 static int lfs_project(int argc, char **argv);
93 static int lfs_flushctx(int argc, char **argv);
94 static int lfs_cp(int argc, char **argv);
95 static int lfs_ls(int argc, char **argv);
96 static int lfs_poollist(int argc, char **argv);
97 static int lfs_changelog(int argc, char **argv);
98 static int lfs_changelog_clear(int argc, char **argv);
99 static int lfs_fid2path(int argc, char **argv);
100 static int lfs_path2fid(int argc, char **argv);
101 static int lfs_data_version(int argc, char **argv);
102 static int lfs_hsm_state(int argc, char **argv);
103 static int lfs_hsm_set(int argc, char **argv);
104 static int lfs_hsm_clear(int argc, char **argv);
105 static int lfs_hsm_action(int argc, char **argv);
106 static int lfs_hsm_archive(int argc, char **argv);
107 static int lfs_hsm_restore(int argc, char **argv);
108 static int lfs_hsm_release(int argc, char **argv);
109 static int lfs_hsm_remove(int argc, char **argv);
110 static int lfs_hsm_cancel(int argc, char **argv);
111 static int lfs_swap_layouts(int argc, char **argv);
112 static int lfs_mv(int argc, char **argv);
113 static int lfs_ladvise(int argc, char **argv);
114 static int lfs_list_commands(int argc, char **argv);
116 /* Setstripe and migrate share mostly the same parameters */
117 #define SSM_CMD_COMMON(cmd) \
118 "usage: "cmd" [--component-end|-E <comp_end>]\n" \
119 " [--stripe-count|-c <stripe_count>]\n" \
120 " [--stripe-index|-i <start_ost_idx>]\n" \
121 " [--stripe-size|-S <stripe_size>]\n" \
122 " [--pool|-p <pool_name>]\n" \
123 " [--ost|-o <ost_indices>]\n"
125 #define SSM_HELP_COMMON \
126 "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
128 "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \
129 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
130 "\t respectively)\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.\n" \
139 "\tcomp_end: Extent end of component, start after previous end.\n"\
140 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
141 "\t respectively, -1 for EOF). Must be a multiple of\n"\
145 #define MIGRATE_USAGE \
146 SSM_CMD_COMMON("migrate ") \
148 " [--non-block|-n]\n" \
152 "\tblock: Block file access during data migration (default)\n" \
153 "\tnon-block: Abort migrations if concurrent access is detected\n" \
155 #define SETDIRSTRIPE_USAGE \
156 " [--mdt-count|-c stripe_count>\n" \
157 " [--mdt-index|-i mdt_index]\n" \
158 " [--mdt-hash|-H mdt_hash]\n" \
159 " [--default|-D] [--mode|-m mode] <dir>\n" \
160 "\tstripe_count: stripe count of the striped directory\n" \
161 "\tmdt_index: MDT index of first stripe\n" \
162 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
163 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
164 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
165 "\tdefault_stripe: set default dirstripe of the directory\n" \
166 "\tmode: the mode of the directory\n"
168 static bool file_lease_supported = true;
170 /* all available commands */
171 command_t cmdlist[] = {
172 {"setstripe", lfs_setstripe, 0,
173 "To create a file with specified striping/composite layout, or\n"
174 "create/replace the default layout on an existing directory:\n"
175 SSM_CMD_COMMON("setstripe")
176 " <directory|filename>\n"
178 "To add component(s) to an existing composite file:\n"
179 SSM_CMD_COMMON("setstripe --component-add")
181 "To totally delete the default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete the last component(s) from an existing composite file\n"
185 "(note that this will also delete any data in those components):\n"
186 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
187 " [--component-flags|-F <comp_flags>]\n"
189 "\tcomp_id: Unique component ID to delete\n"
190 "\tcomp_flags: 'init' indicating all instantiated components\n"
191 "\t '^init' indicating all uninstantiated components\n"
192 "\t-I and -F cannot be specified at the same time\n"},
193 {"getstripe", lfs_getstripe, 0,
194 "To list the striping info for a given file or files in a\n"
195 "directory or recursively for all files in a directory tree.\n"
196 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
197 " [--stripe-count|-c] [--stripe-index|-i]\n"
198 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
199 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
200 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
201 " [--component-id[=comp_id]|-I[comp_id]]\n"
202 " [--component-flags[=comp_flags]]\n"
203 " [--component-count]\n"
204 " [--component-start[=[+-]comp_start]]\n"
205 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
206 " <directory|filename> ..."},
207 {"setdirstripe", lfs_setdirstripe, 0,
208 "To create a striped directory on a specified MDT. This can only\n"
209 "be done on MDT0 with the right of administrator.\n"
210 "usage: setdirstripe [OPTION] <directory>\n"
212 {"getdirstripe", lfs_getdirstripe, 0,
213 "To list the striping info for a given directory\n"
214 "or recursively for all directories in a directory tree.\n"
215 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
216 " [--mdt-index|-i] [--mdt-hash|-t]\n"
217 " [--recursive|-r] [--yaml|-y]\n"
218 " [--default|-D] <dir> ..."},
219 {"mkdir", lfs_setdirstripe, 0,
220 "To create a striped directory on a specified MDT. This can only\n"
221 "be done on MDT0 with the right of administrator.\n"
222 "usage: mkdir [OPTION] <directory>\n"
224 {"rm_entry", lfs_rmentry, 0,
225 "To remove the name entry of the remote directory. Note: This\n"
226 "command will only delete the name entry, i.e. the remote directory\n"
227 "will become inaccessable after this command. This can only be done\n"
228 "by the administrator\n"
229 "usage: rm_entry <dir>\n"},
230 {"pool_list", lfs_poollist, 0,
231 "List pools or pool OSTs\n"
232 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
233 {"find", lfs_find, 0,
234 "find files matching given attributes recursively in directory tree.\n"
235 "usage: find <directory|filename> ...\n"
236 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
237 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
238 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
239 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
240 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
241 " [[!] --stripe-count|-c [+-]<stripes>]\n"
242 " [[!] --stripe-index|-i <index,...>]\n"
243 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
244 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
245 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
246 " [[!] --projid <projid>]\n"
247 " [[!] --layout|-L released,raid0]\n"
248 " [[!] --component-count [+-]<comp_cnt>]\n"
249 " [[!] --component-start [+-]N[kMGTPE]]\n"
250 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
251 " [[!] --component-flags <comp_flags>]\n"
252 " [[!] --mdt-count|-T [+-]<stripes>]\n"
253 " [[!] --mdt-hash|-H <hashtype>\n"
254 "\t !: used before an option indicates 'NOT' requested attribute\n"
255 "\t -: used before a value indicates less than requested value\n"
256 "\t +: used before a value indicates more than requested value\n"
257 "\tmdt-hash: hash type of the striped directory.\n"
258 "\t fnv_1a_64 FNV-1a hash algorithm\n"
259 "\t all_char sum of characters % MDT_COUNT\n"},
260 {"check", lfs_check, 0,
261 "Display the status of MDS or OSTs (as specified in the command)\n"
262 "or all the servers (MDS and OSTs).\n"
263 "usage: check <osts|mds|servers>"},
264 {"osts", lfs_osts, 0, "list OSTs connected to client "
265 "[for specified path only]\n" "usage: osts [path]"},
266 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
267 "[for specified path only]\n" "usage: mdts [path]"},
269 "report filesystem disk space usage or inodes usage"
270 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
271 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
272 {"getname", lfs_getname, 0, "list instances and specified mount points "
273 "[for specified path only]\n"
274 "Usage: getname [-h]|[path ...] "},
275 #ifdef HAVE_SYS_QUOTA_H
276 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
277 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
278 " -b <block-softlimit> -B <block-hardlimit>\n"
279 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
280 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
281 " [--block-softlimit <block-softlimit>]\n"
282 " [--block-hardlimit <block-hardlimit>]\n"
283 " [--inode-softlimit <inode-softlimit>]\n"
284 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
285 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
286 " [--block-grace <block-grace>]\n"
287 " [--inode-grace <inode-grace>] <filesystem>\n"
288 " -b can be used instead of --block-softlimit/--block-grace\n"
289 " -B can be used instead of --block-hardlimit\n"
290 " -i can be used instead of --inode-softlimit/--inode-grace\n"
291 " -I can be used instead of --inode-hardlimit\n\n"
292 "Note: The total quota space will be split into many qunits and\n"
293 " balanced over all server targets, the minimal qunit size is\n"
294 " 1M bytes for block space and 1K inodes for inode space.\n\n"
295 " Quota space rebalancing process will stop when this mininum\n"
296 " value is reached. As a result, quota exceeded can be returned\n"
297 " while many targets still have 1MB or 1K inodes of spare\n"
299 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
300 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
302 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
303 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
304 {"project", lfs_project, 0,
305 "Change or list project attribute for specified file or directory.\n"
306 "usage: project [-d|-r] <file|directory...>\n"
307 " list project ID and flags on file(s) or directories\n"
308 " project [-p id] [-s] [-r] <file|directory...>\n"
309 " set project ID and/or inherit flag for specified file(s) or directories\n"
310 " project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
311 " check project ID and flags on file(s) or directories, print outliers\n"
312 " project -C [-r] [-k] <file|directory...>\n"
313 " clear the project inherit flag and ID on the file or directory\n"
316 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
317 "usage: flushctx [-k] [mountpoint...]"},
319 "Remote user copy files and directories.\n"
320 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
322 "Remote user list directory contents.\n"
323 "usage: ls [OPTION]... [FILE]..."},
324 {"changelog", lfs_changelog, 0,
325 "Show the metadata changes on an MDT."
326 "\nusage: changelog <mdtname> [startrec [endrec]]"},
327 {"changelog_clear", lfs_changelog_clear, 0,
328 "Indicate that old changelog records up to <endrec> are no longer of "
329 "interest to consumer <id>, allowing the system to free up space.\n"
330 "An <endrec> of 0 means all records.\n"
331 "usage: changelog_clear <mdtname> <id> <endrec>"},
332 {"fid2path", lfs_fid2path, 0,
333 "Resolve the full path(s) for given FID(s). For a specific hardlink "
334 "specify link number <linkno>.\n"
335 /* "For a historical link name, specify changelog record <recno>.\n" */
336 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
337 /* [ --rec <recno> ] */ },
338 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
339 "usage: path2fid [--parents] <path> ..."},
340 {"data_version", lfs_data_version, 0, "Display file data version for "
341 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
342 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
343 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
344 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
345 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
346 "[--archived] [--lost] [--archive-id NUM] <file> ..."},
347 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
349 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
350 "[--archived] [--lost] <file> ..."},
351 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
352 "given files.\n" "usage: hsm_action <file> ..."},
353 {"hsm_archive", lfs_hsm_archive, 0,
354 "Archive file to external storage.\n"
355 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
357 {"hsm_restore", lfs_hsm_restore, 0,
358 "Restore file from external storage.\n"
359 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
360 {"hsm_release", lfs_hsm_release, 0,
361 "Release files from Lustre.\n"
362 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
363 {"hsm_remove", lfs_hsm_remove, 0,
364 "Remove file copy from external storage.\n"
365 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
366 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
368 "Note: To remove files from the archive that have been deleted on\n"
369 "Lustre, set mntpath and optionally archive. In that case, all the\n"
370 "positional arguments and entries in the file list must be FIDs."
372 {"hsm_cancel", lfs_hsm_cancel, 0,
373 "Cancel requests related to specified files.\n"
374 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
375 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
376 "usage: swap_layouts <path1> <path2>"},
377 {"migrate", lfs_setstripe, 0,
378 "migrate a directory between MDTs.\n"
379 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
381 "\tmdt_idx: index of the destination MDT\n"
383 "migrate file objects from one OST "
384 "layout\nto another (may be not safe with concurent writes).\n"
386 "[--stripe-count|-c] <stripe_count>\n"
387 " [--stripe-index|-i] <start_ost_index>\n"
388 " [--stripe-size|-S] <stripe_size>\n"
389 " [--pool|-p] <pool_name>\n"
390 " [--ost-list|-o] <ost_indices>\n"
392 " [--non-block|-n]\n"
393 " <file|directory>\n"
394 "\tstripe_count: number of OSTs to stripe a file over\n"
395 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
396 "\tstripe_size: number of bytes to store before moving to the next OST\n"
397 "\tpool_name: name of the predefined pool of OSTs\n"
398 "\tost_indices: OSTs to stripe over, in order\n"
399 "\tblock: wait for the operation to return before continuing\n"
400 "\tnon-block: do not wait for the operation to return.\n"},
402 "To move directories between MDTs. This command is deprecated, "
403 "use \"migrate\" instead.\n"
404 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
406 {"ladvise", lfs_ladvise, 0,
407 "Provide servers with advice about access patterns for a file.\n"
408 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
409 " [--background|-b]\n"
410 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
412 {"help", Parser_help, 0, "help"},
413 {"exit", Parser_quit, 0, "quit"},
414 {"quit", Parser_quit, 0, "quit"},
415 {"--version", Parser_version, 0,
416 "output build version of the utility and exit"},
417 {"--list-commands", lfs_list_commands, 0,
418 "list commands supported by the utility and exit"},
423 #define MIGRATION_NONBLOCK 1
425 static int check_hashtype(const char *hashtype)
429 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
430 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
437 * Internal helper for migrate_copy_data(). Check lease and report error if
440 * \param[in] fd File descriptor on which to check the lease.
441 * \param[out] lease_broken Set to true if the lease was broken.
442 * \param[in] group_locked Whether a group lock was taken or not.
443 * \param[in] path Name of the file being processed, for error
446 * \retval 0 Migration can keep on going.
447 * \retval -errno Error occurred, abort migration.
449 static int check_lease(int fd, bool *lease_broken, bool group_locked,
454 if (!file_lease_supported)
457 rc = llapi_lease_check(fd);
459 return 0; /* llapi_check_lease returns > 0 on success. */
462 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
464 rc = rc ? rc : -EAGAIN;
466 fprintf(stderr, "%s: external attempt to access file '%s' "
467 "blocked until migration ends.\n", progname, path);
470 *lease_broken = true;
474 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
475 bool group_locked, const char *fname)
484 bool lease_broken = false;
486 /* Use a page-aligned buffer for direct I/O */
487 rc = posix_memalign(&buf, getpagesize(), buf_size);
492 /* read new data only if we have written all
493 * previously read data */
496 rc = check_lease(fd_src, &lease_broken,
497 group_locked, fname);
501 rsize = read(fd_src, buf, buf_size);
504 fprintf(stderr, "%s: %s: read failed: %s\n",
505 progname, fname, strerror(-rc));
515 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
519 "%s: %s: write failed on volatile: %s\n",
520 progname, fname, strerror(-rc));
530 fprintf(stderr, "%s: %s: fsync failed: %s\n",
531 progname, fname, strerror(-rc));
539 static int migrate_copy_timestamps(int fdv, const struct stat *st)
541 struct timeval tv[2] = {
542 {.tv_sec = st->st_atime},
543 {.tv_sec = st->st_mtime}
546 return futimes(fdv, tv);
549 static int migrate_block(int fd, int fdv, const struct stat *st,
550 size_t buf_size, const char *name)
557 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
559 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
560 progname, name, strerror(-rc));
568 /* The grouplock blocks all concurrent accesses to the file.
569 * It has to be taken after llapi_get_data_version as it would
571 rc = llapi_group_lock(fd, gid);
573 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
574 progname, name, strerror(-rc));
578 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
580 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
584 /* Make sure we keep original atime/mtime values */
585 rc = migrate_copy_timestamps(fdv, st);
587 fprintf(stderr, "%s: %s: timestamp copy failed\n",
593 * for a migration we need to check data version on file did
596 * Pass in gid=0 since we already own grouplock. */
597 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
598 SWAP_LAYOUTS_CHECK_DV1);
600 fprintf(stderr, "%s: %s: dataversion changed during copy, "
601 "migration aborted\n", progname, name);
604 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
605 name, strerror(-rc));
610 rc2 = llapi_group_unlock(fd, gid);
611 if (rc2 < 0 && rc == 0) {
612 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
613 progname, name, strerror(-rc2));
620 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
621 size_t buf_size, const char *name)
627 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
629 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
630 progname, name, strerror(-rc));
634 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
636 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
640 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
642 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
643 progname, name, strerror(-rc));
649 fprintf(stderr, "%s: %s: data version changed during "
655 /* Make sure we keep original atime/mtime values */
656 rc = migrate_copy_timestamps(fdv, st);
658 fprintf(stderr, "%s: %s: timestamp copy failed\n",
663 /* Atomically put lease, swap layouts and close.
664 * for a migration we need to check data version on file did
666 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
668 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
669 progname, name, strerror(-rc));
676 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
681 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
685 if (flags != 0 && comp_id != 0)
688 /* LCME_FL_INIT is the only supported flag in PFL */
690 if (flags & ~LCME_KNOWN_FLAGS) {
691 fprintf(stderr, "Invalid component flags %#x\n", flags);
694 } else if (comp_id > LCME_ID_MAX) {
695 fprintf(stderr, "Invalid component id %u\n", comp_id);
699 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
701 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
702 comp_id, fname, strerror(errno));
706 static int lfs_component_add(char *fname, struct llapi_layout *layout)
713 rc = llapi_layout_file_comp_add(fname, layout);
715 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
716 fname, strerror(errno));
720 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
721 struct llapi_layout *layout)
729 fd = lstat(fname, &st);
730 if (fd == 0 && S_ISDIR(st.st_mode))
731 open_flags = O_DIRECTORY | O_RDONLY;
733 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
735 fprintf(stderr, "%s %s failed. %s\n",
736 S_ISDIR(st.st_mode) ?
737 "Set default composite layout to " :
738 "Create composite file",
739 fname, strerror(errno));
743 static int lfs_migrate(char *name, __u64 migration_flags,
744 struct llapi_stripe_param *param,
745 struct llapi_layout *layout)
749 char parent[PATH_MAX];
752 char volatile_file[sizeof(parent) +
753 LUSTRE_VOLATILE_HDR_LEN +
754 2 * sizeof(mdt_index) +
755 2 * sizeof(random_value) + 4];
758 struct lov_user_md *lum = NULL;
760 int buf_size = 1024 * 1024 * 4;
761 bool have_lease_rdlck = false;
765 /* find the right size for the IO and allocate the buffer */
766 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
767 lum = malloc(lum_size);
773 rc = llapi_file_get_stripe(name, lum);
774 /* failure can happen for many reasons and some may be not real errors
776 * in case of a real error, a later call will fail with better
777 * error management */
779 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
780 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
781 lum->lmm_stripe_size != 0)
782 buf_size = lum->lmm_stripe_size;
785 /* open file, direct io */
786 /* even if the file is only read, WR mode is nedeed to allow
787 * layout swap on fd */
788 fd = open(name, O_RDWR | O_DIRECT);
791 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
796 if (file_lease_supported) {
797 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
798 if (rc == -EOPNOTSUPP) {
799 /* Older servers do not support file lease.
800 * Disable related checks. This opens race conditions
801 * as explained in LU-4840 */
802 file_lease_supported = false;
804 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
805 progname, name, strerror(-rc));
808 have_lease_rdlck = true;
812 /* search for file directory pathname */
813 if (strlen(name) > sizeof(parent)-1) {
817 strncpy(parent, name, sizeof(parent));
818 ptr = strrchr(parent, '/');
820 if (getcwd(parent, sizeof(parent)) == NULL) {
831 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
833 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
834 progname, name, strerror(-rc));
839 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
840 mode_t open_mode = S_IRUSR | S_IWUSR;
842 random_value = random();
843 rc = snprintf(volatile_file, sizeof(volatile_file),
844 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
845 mdt_index, random_value);
846 if (rc >= sizeof(volatile_file)) {
851 /* create, open a volatile file, use caching (ie no directio) */
853 fdv = llapi_file_open_param(volatile_file, open_flags,
855 else if (layout != NULL)
856 fdv = lfs_component_create(volatile_file, open_flags,
860 } while (fdv == -EEXIST);
864 fprintf(stderr, "%s: %s: cannot create volatile file in"
866 progname, parent, strerror(-rc));
870 /* In case the MDT does not support creation of volatile files
871 * we should try to unlink it. */
872 (void)unlink(volatile_file);
874 /* Not-owner (root?) special case.
875 * Need to set owner/group of volatile file like original.
876 * This will allow to pass related check during layout_swap.
881 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
885 rc = fstat(fdv, &stv);
888 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
889 volatile_file, strerror(errno));
892 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
893 rc = fchown(fdv, st.st_uid, st.st_gid);
896 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
897 name, strerror(errno));
902 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
903 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
905 have_lease_rdlck = false;
906 fdv = -1; /* The volatile file is closed as we put the
907 * lease in non-blocking mode. */
910 /* Blocking mode (forced if servers do not support file lease).
911 * It is also the default mode, since we cannot distinguish
912 * between a broken lease and a server that does not support
913 * atomic swap/close (LU-6785) */
914 rc = migrate_block(fd, fdv, &st, buf_size, name);
918 if (have_lease_rdlck)
935 * Parse a string containing an OST index list into an array of integers.
937 * The input string contains a comma delimited list of individual
938 * indices and ranges, for example "1,2-4,7". Add the indices into the
939 * \a osts array and remove duplicates.
941 * \param[out] osts array to store indices in
942 * \param[in] size size of \a osts array
943 * \param[in] offset starting index in \a osts
944 * \param[in] arg string containing OST index list
946 * \retval positive number of indices in \a osts
947 * \retval -EINVAL unable to parse \a arg
949 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
953 int slots = size - offset;
961 while (!end_of_loop) {
969 ptr = strchrnul(arg, ',');
971 end_of_loop = *ptr == '\0';
974 start_index = strtol(arg, &endptr, 0);
975 if (endptr == arg) /* no data at all */
977 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
982 end_index = start_index;
983 if (*endptr == '-') {
984 end_index = strtol(endptr + 1, &endptr, 0);
987 if (end_index < start_index)
991 for (i = start_index; i <= end_index && slots > 0; i++) {
994 /* remove duplicate */
995 for (j = 0; j < offset; j++) {
999 if (j == offset) { /* no duplicate */
1004 if (slots == 0 && i < end_index)
1012 if (!end_of_loop && ptr != NULL)
1015 return rc < 0 ? rc : nr;
1018 struct lfs_setstripe_args {
1019 unsigned long long lsa_comp_end;
1020 unsigned long long lsa_stripe_size;
1021 int lsa_stripe_count;
1023 __u32 lsa_comp_flags;
1026 char *lsa_pool_name;
1029 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1031 memset(lsa, 0, sizeof(*lsa));
1032 lsa->lsa_stripe_off = -1;
1035 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1037 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1038 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1039 lsa->lsa_comp_end != 0);
1042 static int comp_args_to_layout(struct llapi_layout **composite,
1043 struct lfs_setstripe_args *lsa)
1045 struct llapi_layout *layout = *composite;
1046 uint64_t prev_end = 0;
1049 if (layout == NULL) {
1050 layout = llapi_layout_alloc();
1051 if (layout == NULL) {
1052 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1056 *composite = layout;
1060 /* Get current component extent, current component
1061 * must be the tail component. */
1062 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1064 fprintf(stderr, "Get comp extent failed. %s\n",
1069 rc = llapi_layout_comp_add(layout);
1071 fprintf(stderr, "Add component failed. %s\n",
1077 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1079 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1080 prev_end, lsa->lsa_comp_end, strerror(errno));
1084 if (lsa->lsa_stripe_size != 0) {
1085 rc = llapi_layout_stripe_size_set(layout,
1086 lsa->lsa_stripe_size);
1088 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1089 lsa->lsa_stripe_size, strerror(errno));
1094 if (lsa->lsa_stripe_count != 0) {
1095 rc = llapi_layout_stripe_count_set(layout,
1096 lsa->lsa_stripe_count == -1 ?
1098 lsa->lsa_stripe_count);
1100 fprintf(stderr, "Set stripe count %d failed. %s\n",
1101 lsa->lsa_stripe_count, strerror(errno));
1106 if (lsa->lsa_pool_name != NULL) {
1107 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1109 fprintf(stderr, "Set pool name: %s failed. %s\n",
1110 lsa->lsa_pool_name, strerror(errno));
1115 if (lsa->lsa_nr_osts > 0) {
1116 if (lsa->lsa_stripe_count > 0 &&
1117 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1118 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1119 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1122 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1123 rc = llapi_layout_ost_index_set(layout, i,
1128 } else if (lsa->lsa_stripe_off != -1) {
1129 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1132 fprintf(stderr, "Set ost index %d failed. %s\n",
1133 i, strerror(errno));
1140 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1141 * end of the last component in the existing file, and adjust the
1142 * first extent start of the components to be added accordingly. */
1143 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1145 struct llapi_layout *head;
1146 uint64_t start, end, stripe_size, prev_end = 0;
1153 head = llapi_layout_get_by_path(fname, 0);
1155 fprintf(stderr, "Read layout from %s failed. %s\n",
1156 fname, strerror(errno));
1158 } else if (errno == ENODATA) {
1159 /* file without LOVEA, this component-add will be turned
1160 * into a component-create. */
1161 llapi_layout_free(head);
1164 /* Current component of 'head' should be tail of component
1165 * list by default, but we do an extra move cursor operation
1166 * here to test if the layout is non-composite. */
1167 rc = llapi_layout_comp_use(head, LLAPI_LAYOUT_COMP_USE_LAST);
1169 fprintf(stderr, "'%s' isn't a composite file?\n",
1171 llapi_layout_free(head);
1176 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1178 fprintf(stderr, "Get prev extent failed. %s\n",
1180 llapi_layout_free(head);
1184 llapi_layout_free(head);
1186 /* Make sure we use the first component of the layout to be added. */
1187 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1189 fprintf(stderr, "Move component cursor failed. %s\n",
1194 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1196 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1200 if (start > prev_end || end <= prev_end) {
1201 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1202 "adjacent with the existing file extent end: %lu\n",
1203 start, end, prev_end);
1207 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1209 fprintf(stderr, "Get stripe size failed. %s\n",
1214 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1215 (prev_end & (stripe_size - 1))) {
1216 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1217 stripe_size, prev_end);
1221 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1223 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1224 prev_end, end, strerror(errno));
1231 static inline bool comp_flags_is_neg(__u32 flags)
1233 return flags & LCME_FL_NEG;
1236 static inline void comp_flags_set_neg(__u32 *flags)
1238 *flags |= LCME_FL_NEG;
1241 static inline void comp_flags_clear_neg(__u32 *flags)
1243 *flags &= ~LCME_FL_NEG;
1246 static int comp_str2flags(__u32 *flags, char *string)
1249 __u32 neg_flags = 0;
1255 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1259 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1260 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1261 const char *comp_name = comp_flags_table[i].cfn_name;
1263 if (strcmp(name, comp_name) == 0) {
1264 *flags |= comp_flag;
1266 } else if (strncmp(name, "^", 1) == 0 &&
1267 strcmp(name + 1, comp_name) == 0) {
1268 neg_flags |= comp_flag;
1273 llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1274 "'%s' is not supported.\n", name);
1279 if (*flags == 0 && neg_flags == 0)
1281 /* don't support mixed flags for now */
1282 if (*flags && neg_flags)
1287 comp_flags_set_neg(flags);
1293 static inline bool arg_is_eof(char *arg)
1295 return !strncmp(arg, "-1", strlen("-1")) ||
1296 !strncmp(arg, "EOF", strlen("EOF")) ||
1297 !strncmp(arg, "eof", strlen("eof"));
1312 static int lfs_setstripe(int argc, char **argv)
1314 struct lfs_setstripe_args lsa;
1315 struct llapi_stripe_param *param = NULL;
1316 struct find_param migrate_mdt_param = {
1326 char *mdt_idx_arg = NULL;
1327 unsigned long long size_units = 1;
1328 bool migrate_mode = false;
1329 bool migration_block = false;
1330 __u64 migration_flags = 0;
1331 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1332 int comp_del = 0, comp_set = 0;
1335 struct llapi_layout *layout = NULL;
1337 struct option long_opts[] = {
1338 /* --block is only valid in migrate mode */
1339 { .val = 'b', .name = "block", .has_arg = no_argument},
1340 { .val = LFS_COMP_ADD_OPT,
1341 .name = "comp-add", .has_arg = no_argument},
1342 { .val = LFS_COMP_ADD_OPT,
1343 .name = "component-add",
1344 .has_arg = no_argument},
1345 { .val = LFS_COMP_DEL_OPT,
1346 .name = "comp-del", .has_arg = no_argument},
1347 { .val = LFS_COMP_DEL_OPT,
1348 .name = "component-del",
1349 .has_arg = no_argument},
1350 { .val = LFS_COMP_FLAGS_OPT,
1351 .name = "comp-flags", .has_arg = required_argument},
1352 { .val = LFS_COMP_FLAGS_OPT,
1353 .name = "component-flags",
1354 .has_arg = required_argument},
1355 { .val = LFS_COMP_SET_OPT,
1356 .name = "comp-set", .has_arg = no_argument},
1357 { .val = LFS_COMP_SET_OPT,
1358 .name = "component-set",
1359 .has_arg = no_argument},
1360 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1361 /* This formerly implied "stripe-count", but was explicitly
1362 * made "stripe-count" for consistency with other options,
1363 * and to separate it from "mdt-count" when DNE arrives. */
1364 { .val = 'c', .name = "count", .has_arg = required_argument },
1366 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1367 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1368 { .val = 'd', .name = "delete", .has_arg = no_argument},
1369 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1370 { .val = 'E', .name = "component-end",
1371 .has_arg = required_argument},
1372 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1373 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1374 /* This formerly implied "stripe-index", but was explicitly
1375 * made "stripe-index" for consistency with other options,
1376 * and to separate it from "mdt-index" when DNE arrives. */
1377 { .val = 'i', .name = "index", .has_arg = required_argument },
1379 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1380 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1381 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1382 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1383 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1384 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1385 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1386 /* --non-block is only valid in migrate mode */
1387 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1388 { .val = 'o', .name = "ost", .has_arg = required_argument},
1389 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1390 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1391 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1393 { .val = 'p', .name = "pool", .has_arg = required_argument },
1394 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1395 /* This formerly implied "--stripe-size", but was confusing
1396 * with "lfs find --size|-s", which means "file size", so use
1397 * the consistent "--stripe-size|-S" for all commands. */
1398 { .val = 's', .name = "size", .has_arg = required_argument },
1400 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1401 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1402 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1403 /* --verbose is only valid in migrate mode */
1404 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1405 { .val = LFS_COMP_ADD_OPT,
1406 .name = "component-add",
1407 .has_arg = no_argument },
1408 { .val = LFS_COMP_DEL_OPT,
1409 .name = "component-del",
1410 .has_arg = no_argument },
1411 { .val = LFS_COMP_FLAGS_OPT,
1412 .name = "component-flags",
1413 .has_arg = required_argument },
1414 { .val = LFS_COMP_SET_OPT,
1415 .name = "component-set",
1416 .has_arg = no_argument },
1419 setstripe_args_init(&lsa);
1421 if (strcmp(argv[0], "migrate") == 0)
1422 migrate_mode = true;
1424 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1425 long_opts, NULL)) >= 0) {
1430 case LFS_COMP_ADD_OPT:
1433 case LFS_COMP_DEL_OPT:
1436 case LFS_COMP_FLAGS_OPT:
1437 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1439 fprintf(stderr, "error: %s: bad comp flags "
1440 "'%s'\n", argv[0], optarg);
1444 case LFS_COMP_SET_OPT:
1448 if (!migrate_mode) {
1449 fprintf(stderr, "--block is valid only for"
1453 migration_block = true;
1456 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1457 if (strcmp(argv[optind - 1], "--count") == 0)
1458 fprintf(stderr, "warning: '--count' deprecated"
1459 ", use '--stripe-count' instead\n");
1461 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1463 fprintf(stderr, "error: %s: bad stripe count "
1464 "'%s'\n", argv[0], optarg);
1469 /* delete the default striping pattern */
1473 if (lsa.lsa_comp_end != 0) {
1474 result = comp_args_to_layout(&layout, &lsa);
1478 setstripe_args_init(&lsa);
1481 if (arg_is_eof(optarg)) {
1482 lsa.lsa_comp_end = LUSTRE_EOF;
1484 result = llapi_parse_size(optarg,
1488 fprintf(stderr, "error: %s: "
1489 "bad component end '%s'\n",
1496 if (strcmp(argv[optind - 1], "--index") == 0)
1497 fprintf(stderr, "warning: '--index' deprecated"
1498 ", use '--stripe-index' instead\n");
1499 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1501 fprintf(stderr, "error: %s: bad stripe offset "
1502 "'%s'\n", argv[0], optarg);
1507 comp_id = strtoul(optarg, &end, 0);
1508 if (*end != '\0' || comp_id == 0 ||
1509 comp_id > LCME_ID_MAX) {
1510 fprintf(stderr, "error: %s: bad comp ID "
1511 "'%s'\n", argv[0], optarg);
1516 if (!migrate_mode) {
1517 fprintf(stderr, "--mdt-index is valid only for"
1521 mdt_idx_arg = optarg;
1524 if (!migrate_mode) {
1525 fprintf(stderr, "--non-block is valid only for"
1529 migration_flags |= MIGRATION_NONBLOCK;
1532 lsa.lsa_nr_osts = parse_targets(osts,
1533 sizeof(osts) / sizeof(__u32),
1534 lsa.lsa_nr_osts, optarg);
1535 if (lsa.lsa_nr_osts < 0) {
1537 "error: %s: bad OST indices '%s'\n",
1542 lsa.lsa_osts = osts;
1543 if (lsa.lsa_stripe_off == -1)
1544 lsa.lsa_stripe_off = osts[0];
1549 lsa.lsa_pool_name = optarg;
1551 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1553 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1554 fprintf(stderr, "warning: '--size|-s' deprecated, "
1555 "use '--stripe-size|-S' instead\n");
1557 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1559 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1562 fprintf(stderr, "error: %s: bad stripe size "
1563 "'%s'\n", argv[0], optarg);
1568 if (!migrate_mode) {
1569 fprintf(stderr, "--verbose is valid only for"
1573 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1580 fname = argv[optind];
1582 if (lsa.lsa_comp_end != 0) {
1583 result = comp_args_to_layout(&layout, &lsa);
1588 if (optind == argc) {
1589 fprintf(stderr, "error: %s: missing filename|dirname\n",
1594 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1595 * altered by user space tool, so we don't need to support the
1596 * --component-set for this moment. */
1597 if (comp_set != 0) {
1598 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1603 if ((delete + comp_set + comp_del + comp_add) > 1) {
1604 fprintf(stderr, "error: %s: can't specify --component-set, "
1605 "--component-del, --component-add or -d together\n",
1610 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1611 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1612 fprintf(stderr, "error: %s: can't specify -d with "
1613 "-s, -c, -o, -p, -I, -F or -E options\n",
1618 if ((comp_set || comp_del) &&
1619 (setstripe_args_specified(&lsa) || layout != NULL)) {
1620 fprintf(stderr, "error: %s: can't specify --component-del or "
1621 "--component-set with -s, -c, -o, -p or -E options.\n",
1626 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1627 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1628 "--component-del option.\n", argv[0]);
1632 if (comp_add || comp_del) {
1635 result = lstat(fname, &st);
1636 if (result == 0 && S_ISDIR(st.st_mode)) {
1637 fprintf(stderr, "error: %s: can't use --component-add "
1638 "or --component-del for directory.\n",
1645 if (layout == NULL) {
1646 fprintf(stderr, "error: %s: -E option must be present"
1647 "in --component-add mode.\n", argv[0]);
1650 result = adjust_first_extent(fname, layout);
1651 if (result == -ENODATA)
1653 else if (result != 0)
1657 if (mdt_idx_arg != NULL && optind > 3) {
1658 fprintf(stderr, "error: %s: cannot specify -m with other "
1659 "options\n", argv[0]);
1663 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1665 "error: %s: cannot specify --non-block and --block\n",
1670 if (!comp_del && !comp_set && comp_id != 0) {
1671 fprintf(stderr, "error: %s: -I can only be used with "
1672 "--component-del.\n", argv[0]);
1676 if (mdt_idx_arg != NULL) {
1677 /* initialize migrate mdt parameters */
1678 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1680 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1681 argv[0], mdt_idx_arg);
1684 migrate_mdt_param.fp_migrate = 1;
1685 } else if (layout == NULL) {
1686 /* initialize stripe parameters */
1687 param = calloc(1, offsetof(typeof(*param),
1688 lsp_osts[lsa.lsa_nr_osts]));
1689 if (param == NULL) {
1690 fprintf(stderr, "error: %s: %s\n", argv[0],
1695 param->lsp_stripe_size = lsa.lsa_stripe_size;
1696 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1697 param->lsp_stripe_count = lsa.lsa_stripe_count;
1698 param->lsp_stripe_pattern = 0;
1699 param->lsp_pool = lsa.lsa_pool_name;
1700 param->lsp_is_specific = false;
1701 if (lsa.lsa_nr_osts > 0) {
1702 if (lsa.lsa_stripe_count > 0 &&
1703 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1704 fprintf(stderr, "error: %s: stripe count '%d' "
1705 "doesn't match the number of OSTs: %d\n"
1706 , argv[0], lsa.lsa_stripe_count,
1712 param->lsp_is_specific = true;
1713 param->lsp_stripe_count = lsa.lsa_nr_osts;
1714 memcpy(param->lsp_osts, osts,
1715 sizeof(*osts) * lsa.lsa_nr_osts);
1719 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1721 if (mdt_idx_arg != NULL) {
1722 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1723 op = "migrate mdt objects of";
1724 } else if (migrate_mode) {
1725 result = lfs_migrate(fname, migration_flags, param,
1727 op = "migrate ost objects of";
1728 } else if (comp_set != 0) {
1729 result = lfs_component_set(fname, comp_id,
1730 lsa.lsa_comp_flags);
1731 op = "modify component flags of";
1732 } else if (comp_del != 0) {
1733 result = lfs_component_del(fname, comp_id,
1734 lsa.lsa_comp_flags);
1735 op = "delete component of";
1736 } else if (comp_add != 0) {
1737 result = lfs_component_add(fname, layout);
1738 op = "add component to";
1739 } else if (layout != NULL) {
1740 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1746 op = "create composite";
1748 result = llapi_file_open_param(fname,
1755 op = "create striped";
1758 /* Save the first error encountered. */
1761 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1763 lsa.lsa_pool_name != NULL && result == EINVAL ?
1764 "OST not in pool?" : strerror(errno));
1770 llapi_layout_free(layout);
1773 llapi_layout_free(layout);
1777 static int lfs_poollist(int argc, char **argv)
1782 return llapi_poollist(argv[1]);
1785 static int set_time(time_t *time, time_t *set, char *str)
1792 else if (str[0] == '-')
1798 t = strtol(str, NULL, 0);
1799 if (*time < t * 24 * 60 * 60) {
1802 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1806 *set = *time - t * 24 * 60 * 60;
1809 static int name2uid(unsigned int *id, const char *name)
1811 struct passwd *passwd;
1813 passwd = getpwnam(name);
1816 *id = passwd->pw_uid;
1821 static int name2gid(unsigned int *id, const char *name)
1823 struct group *group;
1825 group = getgrnam(name);
1828 *id = group->gr_gid;
1833 static inline int name2projid(unsigned int *id, const char *name)
1838 static int uid2name(char **name, unsigned int id)
1840 struct passwd *passwd;
1842 passwd = getpwuid(id);
1845 *name = passwd->pw_name;
1850 static inline int gid2name(char **name, unsigned int id)
1852 struct group *group;
1854 group = getgrgid(id);
1857 *name = group->gr_name;
1862 static int name2layout(__u32 *layout, char *name)
1867 for (ptr = name; ; ptr = NULL) {
1868 lyt = strtok(ptr, ",");
1871 if (strcmp(lyt, "released") == 0)
1872 *layout |= LOV_PATTERN_F_RELEASED;
1873 else if (strcmp(lyt, "raid0") == 0)
1874 *layout |= LOV_PATTERN_RAID0;
1881 static int lfs_find(int argc, char **argv)
1886 struct find_param param = {
1890 struct option long_opts[] = {
1891 {"atime", required_argument, 0, 'A'},
1892 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1893 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1894 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1895 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1896 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1897 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1898 {"stripe-count", required_argument, 0, 'c'},
1899 {"stripe_count", required_argument, 0, 'c'},
1900 {"ctime", required_argument, 0, 'C'},
1901 {"maxdepth", required_argument, 0, 'D'},
1902 {"comp-end", required_argument, 0, 'E'},
1903 {"component-end", required_argument, 0, 'E'},
1904 {"gid", required_argument, 0, 'g'},
1905 {"group", required_argument, 0, 'G'},
1906 {"mdt-hash", required_argument, 0, 'H'},
1907 {"stripe-index", required_argument, 0, 'i'},
1908 {"stripe_index", required_argument, 0, 'i'},
1909 /*{"component-id", required_argument, 0, 'I'},*/
1910 {"layout", required_argument, 0, 'L'},
1911 {"mdt", required_argument, 0, 'm'},
1912 {"mdt-index", required_argument, 0, 'm'},
1913 {"mdt_index", required_argument, 0, 'm'},
1914 {"mtime", required_argument, 0, 'M'},
1915 {"name", required_argument, 0, 'n'},
1916 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1917 {"obd", required_argument, 0, 'O'},
1918 {"ost", required_argument, 0, 'O'},
1919 /* no short option for pool, p/P already used */
1920 {"pool", required_argument, 0, LFS_POOL_OPT},
1921 {"print0", no_argument, 0, 'p'},
1922 {"print", no_argument, 0, 'P'},
1923 {"projid", required_argument, 0, LFS_PROJID_OPT},
1924 {"size", required_argument, 0, 's'},
1925 {"stripe-size", required_argument, 0, 'S'},
1926 {"stripe_size", required_argument, 0, 'S'},
1927 {"type", required_argument, 0, 't'},
1928 {"mdt-count", required_argument, 0, 'T'},
1929 {"uid", required_argument, 0, 'u'},
1930 {"user", required_argument, 0, 'U'},
1943 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1944 while ((c = getopt_long_only(argc, argv,
1945 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1946 long_opts, NULL)) >= 0) {
1951 /* '!' is part of option */
1952 /* when getopt_long_only() finds a string which is not
1953 * an option nor a known option argument it returns 1
1954 * in that case if we already have found pathstart and pathend
1955 * (i.e. we have the list of pathnames),
1956 * the only supported value is "!"
1958 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1959 if (!isoption && pathend != -1) {
1960 fprintf(stderr, "err: %s: filename|dirname must either "
1961 "precede options or follow options\n",
1966 if (!isoption && pathstart == -1)
1967 pathstart = optind - 1;
1968 if (isoption && pathstart != -1 && pathend == -1)
1969 pathend = optind - 2;
1975 /* unknown; opt is "!" or path component,
1976 * checking done above.
1978 if (strcmp(optarg, "!") == 0)
1982 xtime = ¶m.fp_atime;
1983 xsign = ¶m.fp_asign;
1984 param.fp_exclude_atime = !!neg_opt;
1985 /* no break, this falls through to 'C' for ctime */
1988 xtime = ¶m.fp_ctime;
1989 xsign = ¶m.fp_csign;
1990 param.fp_exclude_ctime = !!neg_opt;
1992 /* no break, this falls through to 'M' for mtime */
1995 xtime = ¶m.fp_mtime;
1996 xsign = ¶m.fp_msign;
1997 param.fp_exclude_mtime = !!neg_opt;
1999 rc = set_time(&t, xtime, optarg);
2000 if (rc == INT_MAX) {
2007 case LFS_COMP_COUNT_OPT:
2008 if (optarg[0] == '+') {
2009 param.fp_comp_count_sign = -1;
2011 } else if (optarg[0] == '-') {
2012 param.fp_comp_count_sign = 1;
2016 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2017 if (*endptr != '\0') {
2018 fprintf(stderr, "error: bad component count "
2022 param.fp_check_comp_count = 1;
2023 param.fp_exclude_comp_count = !!neg_opt;
2025 case LFS_COMP_FLAGS_OPT:
2026 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2027 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2028 fprintf(stderr, "error: bad component flags "
2032 param.fp_check_comp_flags = 1;
2033 param.fp_exclude_comp_flags = !!neg_opt;
2035 case LFS_COMP_START_OPT:
2036 if (optarg[0] == '+') {
2037 param.fp_comp_start_sign = -1;
2039 } else if (optarg[0] == '-') {
2040 param.fp_comp_start_sign = 1;
2044 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2045 ¶m.fp_comp_start_units, 0);
2047 fprintf(stderr, "error: bad component start "
2051 param.fp_check_comp_start = 1;
2052 param.fp_exclude_comp_start = !!neg_opt;
2055 if (optarg[0] == '+') {
2056 param.fp_stripe_count_sign = -1;
2058 } else if (optarg[0] == '-') {
2059 param.fp_stripe_count_sign = 1;
2063 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2064 if (*endptr != '\0') {
2065 fprintf(stderr,"error: bad stripe_count '%s'\n",
2070 param.fp_check_stripe_count = 1;
2071 param.fp_exclude_stripe_count = !!neg_opt;
2074 param.fp_max_depth = strtol(optarg, 0, 0);
2077 if (optarg[0] == '+') {
2078 param.fp_comp_end_sign = -1;
2080 } else if (optarg[0] == '-') {
2081 param.fp_comp_end_sign = 1;
2085 if (arg_is_eof(optarg)) {
2086 param.fp_comp_end = LUSTRE_EOF;
2087 param.fp_comp_end_units = 1;
2090 rc = llapi_parse_size(optarg,
2092 ¶m.fp_comp_end_units, 0);
2095 fprintf(stderr, "error: bad component end "
2099 param.fp_check_comp_end = 1;
2100 param.fp_exclude_comp_end = !!neg_opt;
2104 rc = name2gid(¶m.fp_gid, optarg);
2106 param.fp_gid = strtoul(optarg, &endptr, 10);
2107 if (*endptr != '\0') {
2108 fprintf(stderr, "Group/GID: %s cannot "
2109 "be found.\n", optarg);
2114 param.fp_exclude_gid = !!neg_opt;
2115 param.fp_check_gid = 1;
2118 param.fp_hash_type = check_hashtype(optarg);
2119 if (param.fp_hash_type == 0) {
2120 fprintf(stderr, "error: bad hash_type '%s'\n",
2125 param.fp_check_hash_type = 1;
2126 param.fp_exclude_hash_type = !!neg_opt;
2129 ret = name2layout(¶m.fp_layout, optarg);
2132 param.fp_exclude_layout = !!neg_opt;
2133 param.fp_check_layout = 1;
2137 rc = name2uid(¶m.fp_uid, optarg);
2139 param.fp_uid = strtoul(optarg, &endptr, 10);
2140 if (*endptr != '\0') {
2141 fprintf(stderr, "User/UID: %s cannot "
2142 "be found.\n", optarg);
2147 param.fp_exclude_uid = !!neg_opt;
2148 param.fp_check_uid = 1;
2151 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2153 "Pool name %s is too long"
2154 " (max is %d)\n", optarg,
2159 /* we do check for empty pool because empty pool
2160 * is used to find V1 lov attributes */
2161 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2162 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2163 param.fp_exclude_pool = !!neg_opt;
2164 param.fp_check_pool = 1;
2167 param.fp_pattern = (char *)optarg;
2168 param.fp_exclude_pattern = !!neg_opt;
2173 char *buf, *token, *next, *p;
2177 buf = strdup(optarg);
2183 param.fp_exclude_obd = !!neg_opt;
2186 while (token && *token) {
2187 token = strchr(token, ',');
2194 param.fp_exclude_mdt = !!neg_opt;
2195 param.fp_num_alloc_mdts += len;
2196 tmp = realloc(param.fp_mdt_uuid,
2197 param.fp_num_alloc_mdts *
2198 sizeof(*param.fp_mdt_uuid));
2204 param.fp_mdt_uuid = tmp;
2206 param.fp_exclude_obd = !!neg_opt;
2207 param.fp_num_alloc_obds += len;
2208 tmp = realloc(param.fp_obd_uuid,
2209 param.fp_num_alloc_obds *
2210 sizeof(*param.fp_obd_uuid));
2216 param.fp_obd_uuid = tmp;
2218 for (token = buf; token && *token; token = next) {
2219 struct obd_uuid *puuid;
2222 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2225 ¶m.fp_obd_uuid[param.fp_num_obds++];
2227 p = strchr(token, ',');
2234 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2239 strncpy(puuid->uuid, token,
2240 sizeof(puuid->uuid));
2248 param.fp_zero_end = 1;
2252 case LFS_PROJID_OPT:
2253 rc = name2projid(¶m.fp_projid, optarg);
2255 param.fp_projid = strtoul(optarg, &endptr, 10);
2256 if (*endptr != '\0') {
2258 "Invalid project ID: %s",
2264 param.fp_exclude_projid = !!neg_opt;
2265 param.fp_check_projid = 1;
2268 if (optarg[0] == '+') {
2269 param.fp_size_sign = -1;
2271 } else if (optarg[0] == '-') {
2272 param.fp_size_sign = 1;
2276 ret = llapi_parse_size(optarg, ¶m.fp_size,
2277 ¶m.fp_size_units, 0);
2279 fprintf(stderr, "error: bad file size '%s'\n",
2283 param.fp_check_size = 1;
2284 param.fp_exclude_size = !!neg_opt;
2287 if (optarg[0] == '+') {
2288 param.fp_stripe_size_sign = -1;
2290 } else if (optarg[0] == '-') {
2291 param.fp_stripe_size_sign = 1;
2295 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2296 ¶m.fp_stripe_size_units, 0);
2298 fprintf(stderr, "error: bad stripe_size '%s'\n",
2302 param.fp_check_stripe_size = 1;
2303 param.fp_exclude_stripe_size = !!neg_opt;
2306 param.fp_exclude_type = !!neg_opt;
2307 switch (optarg[0]) {
2309 param.fp_type = S_IFBLK;
2312 param.fp_type = S_IFCHR;
2315 param.fp_type = S_IFDIR;
2318 param.fp_type = S_IFREG;
2321 param.fp_type = S_IFLNK;
2324 param.fp_type = S_IFIFO;
2327 param.fp_type = S_IFSOCK;
2330 fprintf(stderr, "error: %s: bad type '%s'\n",
2337 if (optarg[0] == '+') {
2338 param.fp_mdt_count_sign = -1;
2340 } else if (optarg[0] == '-') {
2341 param.fp_mdt_count_sign = 1;
2345 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2346 if (*endptr != '\0') {
2347 fprintf(stderr, "error: bad mdt_count '%s'\n",
2352 param.fp_check_mdt_count = 1;
2353 param.fp_exclude_mdt_count = !!neg_opt;
2361 if (pathstart == -1) {
2362 fprintf(stderr, "error: %s: no filename|pathname\n",
2366 } else if (pathend == -1) {
2372 rc = llapi_find(argv[pathstart], ¶m);
2373 if (rc != 0 && ret == 0)
2375 } while (++pathstart < pathend);
2378 fprintf(stderr, "error: %s failed for %s.\n",
2379 argv[0], argv[optind - 1]);
2381 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2382 free(param.fp_obd_uuid);
2384 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2385 free(param.fp_mdt_uuid);
2390 static int lfs_getstripe_internal(int argc, char **argv,
2391 struct find_param *param)
2393 struct option long_opts[] = {
2394 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2395 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2396 {"comp-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2397 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2398 {"comp-start", optional_argument, 0, LFS_COMP_START_OPT},
2399 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2400 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2401 /* This formerly implied "stripe-count", but was explicitly
2402 * made "stripe-count" for consistency with other options,
2403 * and to separate it from "mdt-count" when DNE arrives. */
2404 {"count", no_argument, 0, 'c'},
2406 {"stripe-count", no_argument, 0, 'c'},
2407 {"stripe_count", no_argument, 0, 'c'},
2408 {"directory", no_argument, 0, 'd'},
2409 {"default", no_argument, 0, 'D'},
2410 {"comp-end", optional_argument, 0, 'E'},
2411 {"component-end", optional_argument, 0, 'E'},
2412 {"fid", no_argument, 0, 'F'},
2413 {"generation", no_argument, 0, 'g'},
2414 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2415 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2416 /* This formerly implied "stripe-index", but was explicitly
2417 * made "stripe-index" for consistency with other options,
2418 * and to separate it from "mdt-index" when DNE arrives. */
2419 {"index", no_argument, 0, 'i'},
2421 {"stripe-index", no_argument, 0, 'i'},
2422 {"stripe_index", no_argument, 0, 'i'},
2423 {"comp-id", optional_argument, 0, 'I'},
2424 {"component-id", optional_argument, 0, 'I'},
2425 {"layout", no_argument, 0, 'L'},
2426 {"mdt", no_argument, 0, 'm'},
2427 {"mdt-index", no_argument, 0, 'm'},
2428 {"mdt_index", no_argument, 0, 'm'},
2429 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2430 {"mdt-index", no_argument, 0, 'M'},
2431 {"mdt_index", no_argument, 0, 'M'},
2433 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2434 /* This formerly implied "stripe-index", but was confusing
2435 * with "file offset" (which will eventually be needed for
2436 * with different layouts by offset), so deprecate it. */
2437 {"offset", no_argument, 0, 'o'},
2439 {"obd", required_argument, 0, 'O'},
2440 {"ost", required_argument, 0, 'O'},
2441 {"pool", no_argument, 0, 'p'},
2442 {"quiet", no_argument, 0, 'q'},
2443 {"recursive", no_argument, 0, 'r'},
2444 {"raw", no_argument, 0, 'R'},
2445 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2446 /* This formerly implied "--stripe-size", but was confusing
2447 * with "lfs find --size|-s", which means "file size", so use
2448 * the consistent "--stripe-size|-S" for all commands. */
2449 {"size", no_argument, 0, 's'},
2451 {"stripe-size", no_argument, 0, 'S'},
2452 {"stripe_size", no_argument, 0, 'S'},
2453 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2454 {"verbose", no_argument, 0, 'v'},
2455 {"yaml", no_argument, 0, 'y'},
2461 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2462 long_opts, NULL)) != -1) {
2465 if (strcmp(argv[optind - 1], "--count") == 0)
2466 fprintf(stderr, "warning: '--count' deprecated,"
2467 " use '--stripe-count' instead\n");
2468 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2469 param->fp_verbose |= VERBOSE_COUNT;
2470 param->fp_max_depth = 0;
2473 case LFS_COMP_COUNT_OPT:
2474 param->fp_verbose |= VERBOSE_COMP_COUNT;
2475 param->fp_max_depth = 0;
2477 case LFS_COMP_FLAGS_OPT:
2478 if (optarg != NULL) {
2479 __u32 *flags = ¶m->fp_comp_flags;
2480 rc = comp_str2flags(flags, optarg);
2482 fprintf(stderr, "error: %s bad "
2483 "component flags '%s'.\n",
2487 param->fp_check_comp_flags = 1;
2488 param->fp_exclude_comp_flags =
2489 comp_flags_is_neg(*flags);
2490 comp_flags_clear_neg(flags);
2493 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2494 param->fp_max_depth = 0;
2497 case LFS_COMP_START_OPT:
2498 if (optarg != NULL) {
2500 if (tmp[0] == '+') {
2501 param->fp_comp_start_sign = -1;
2503 } else if (tmp[0] == '-') {
2504 param->fp_comp_start_sign = 1;
2507 rc = llapi_parse_size(tmp,
2508 ¶m->fp_comp_start,
2509 ¶m->fp_comp_start_units, 0);
2511 fprintf(stderr, "error: %s bad "
2512 "component start '%s'.\n",
2516 param->fp_check_comp_start = 1;
2519 param->fp_verbose |= VERBOSE_COMP_START;
2520 param->fp_max_depth = 0;
2524 param->fp_max_depth = 0;
2527 param->fp_get_default_lmv = 1;
2530 if (optarg != NULL) {
2532 if (tmp[0] == '+') {
2533 param->fp_comp_end_sign = -1;
2535 } else if (tmp[0] == '-') {
2536 param->fp_comp_end_sign = 1;
2540 if (arg_is_eof(tmp)) {
2541 param->fp_comp_end = LUSTRE_EOF;
2542 param->fp_comp_end_units = 1;
2545 rc = llapi_parse_size(tmp,
2546 ¶m->fp_comp_end,
2547 ¶m->fp_comp_end_units, 0);
2550 fprintf(stderr, "error: %s bad "
2551 "component end '%s'.\n",
2555 param->fp_check_comp_end = 1;
2557 param->fp_verbose |= VERBOSE_COMP_END;
2558 param->fp_max_depth = 0;
2562 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2563 param->fp_verbose |= VERBOSE_DFID;
2564 param->fp_max_depth = 0;
2568 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2569 param->fp_verbose |= VERBOSE_GENERATION;
2570 param->fp_max_depth = 0;
2573 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2575 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2576 "use '--stripe-index|-i' instead\n");
2579 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2580 if (strcmp(argv[optind - 1], "--index") == 0)
2581 fprintf(stderr, "warning: '--index' deprecated"
2582 ", use '--stripe-index' instead\n");
2584 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2585 param->fp_verbose |= VERBOSE_OFFSET;
2586 param->fp_max_depth = 0;
2590 if (optarg != NULL) {
2591 param->fp_comp_id = strtoul(optarg, &end, 0);
2592 if (*end != '\0' || param->fp_comp_id == 0 ||
2593 param->fp_comp_id > LCME_ID_MAX) {
2594 fprintf(stderr, "error: %s bad "
2595 "component id '%s'\n",
2599 param->fp_check_comp_id = 1;
2602 param->fp_max_depth = 0;
2603 param->fp_verbose |= VERBOSE_COMP_ID;
2607 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2608 param->fp_verbose |= VERBOSE_LAYOUT;
2609 param->fp_max_depth = 0;
2612 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2614 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2615 fprintf(stderr, "warning: '-M' deprecated"
2616 ", use '-m' instead\n");
2620 if (!(param->fp_verbose & VERBOSE_DETAIL))
2621 param->fp_max_depth = 0;
2622 param->fp_verbose |= VERBOSE_MDTINDEX;
2625 if (param->fp_obd_uuid) {
2627 "error: %s: only one obduuid allowed",
2631 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2634 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2635 param->fp_verbose |= VERBOSE_POOL;
2636 param->fp_max_depth = 0;
2643 param->fp_recursive = 1;
2648 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2650 fprintf(stderr, "warning: '--size|-s' deprecated, "
2651 "use '--stripe-size|-S' instead\n");
2652 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2654 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2655 param->fp_verbose |= VERBOSE_SIZE;
2656 param->fp_max_depth = 0;
2660 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2673 if (param->fp_recursive)
2674 param->fp_max_depth = -1;
2675 else if (param->fp_verbose & VERBOSE_DETAIL)
2676 param->fp_max_depth = 1;
2678 if (!param->fp_verbose)
2679 param->fp_verbose = VERBOSE_DEFAULT;
2680 if (param->fp_quiet)
2681 param->fp_verbose = VERBOSE_OBJID;
2684 rc = llapi_getstripe(argv[optind], param);
2685 } while (++optind < argc && !rc);
2688 fprintf(stderr, "error: %s failed for %s.\n",
2689 argv[0], argv[optind - 1]);
2693 static int lfs_tgts(int argc, char **argv)
2695 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2696 struct find_param param;
2697 int index = 0, rc=0;
2702 if (argc == 2 && !realpath(argv[1], path)) {
2704 fprintf(stderr, "error: invalid path '%s': %s\n",
2705 argv[1], strerror(-rc));
2709 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2710 /* Check if we have a mount point */
2711 if (mntdir[0] == '\0')
2714 memset(¶m, 0, sizeof(param));
2715 if (!strcmp(argv[0], "mdts"))
2716 param.fp_get_lmv = 1;
2718 rc = llapi_ostlist(mntdir, ¶m);
2720 fprintf(stderr, "error: %s: failed on %s\n",
2723 if (path[0] != '\0')
2725 memset(mntdir, 0, PATH_MAX);
2731 static int lfs_getstripe(int argc, char **argv)
2733 struct find_param param = { 0 };
2735 param.fp_max_depth = 1;
2736 return lfs_getstripe_internal(argc, argv, ¶m);
2740 static int lfs_getdirstripe(int argc, char **argv)
2742 struct find_param param = { 0 };
2743 struct option long_opts[] = {
2744 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2745 {"mdt-count", no_argument, 0, 'c'},
2747 {"mdt-hash", no_argument, 0, 'H'},
2748 {"mdt-index", no_argument, 0, 'i'},
2749 {"recursive", no_argument, 0, 'r'},
2750 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2751 {"mdt-hash", no_argument, 0, 't'},
2753 {"default", no_argument, 0, 'D'},
2754 {"obd", required_argument, 0, 'O'},
2755 {"mdt-count", no_argument, 0, 'T'},
2756 {"yaml", no_argument, 0, 'y'},
2761 param.fp_get_lmv = 1;
2763 while ((c = getopt_long(argc, argv,
2764 "cDHiO:rtTy", long_opts, NULL)) != -1)
2768 if (param.fp_obd_uuid) {
2770 "error: %s: only one obduuid allowed",
2774 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2776 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2778 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2779 fprintf(stderr, "warning: '-c' deprecated"
2780 ", use '-T' instead\n");
2784 param.fp_verbose |= VERBOSE_COUNT;
2787 param.fp_verbose |= VERBOSE_OFFSET;
2789 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2793 param.fp_verbose |= VERBOSE_HASH_TYPE;
2796 param.fp_get_default_lmv = 1;
2799 param.fp_recursive = 1;
2812 if (param.fp_recursive)
2813 param.fp_max_depth = -1;
2815 if (!param.fp_verbose)
2816 param.fp_verbose = VERBOSE_DEFAULT;
2819 rc = llapi_getstripe(argv[optind], ¶m);
2820 } while (++optind < argc && !rc);
2823 fprintf(stderr, "error: %s failed for %s.\n",
2824 argv[0], argv[optind - 1]);
2829 static int lfs_setdirstripe(int argc, char **argv)
2833 unsigned int stripe_offset = -1;
2834 unsigned int stripe_count = 1;
2835 enum lmv_hash_type hash_type;
2838 char *stripe_offset_opt = NULL;
2839 char *stripe_count_opt = NULL;
2840 char *stripe_hash_opt = NULL;
2841 char *mode_opt = NULL;
2842 bool default_stripe = false;
2843 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2844 mode_t previous_mode = 0;
2845 bool delete = false;
2847 struct option long_opts[] = {
2848 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2849 { .val = 'c', .name = "count", .has_arg = required_argument },
2851 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2852 { .val = 'd', .name = "delete", .has_arg = no_argument },
2853 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2854 { .val = 'i', .name = "index", .has_arg = required_argument },
2856 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2857 { .val = 'm', .name = "mode", .has_arg = required_argument },
2858 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2859 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2860 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2862 {"mdt-hash", required_argument, 0, 'H'},
2863 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2864 { .val = 'D', .name = "default_stripe",
2865 .has_arg = no_argument },
2867 { .val = 'D', .name = "default", .has_arg = no_argument },
2870 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2877 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2878 if (strcmp(argv[optind - 1], "--count") == 0)
2879 fprintf(stderr, "warning: '--count' deprecated"
2880 ", use '--mdt-count' instead\n");
2882 stripe_count_opt = optarg;
2886 default_stripe = true;
2889 default_stripe = true;
2892 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2893 if (strcmp(argv[optind - 1], "--index") == 0)
2894 fprintf(stderr, "warning: '--index' deprecated"
2895 ", use '--mdt-index' instead\n");
2897 stripe_offset_opt = optarg;
2902 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2906 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2907 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2908 fprintf(stderr, "warning: '--hash-type' "
2909 "deprecated, use '--mdt-hash' "
2912 stripe_hash_opt = optarg;
2915 fprintf(stderr, "error: %s: option '%s' "
2917 argv[0], argv[optind - 1]);
2922 if (optind == argc) {
2923 fprintf(stderr, "error: %s: missing dirname\n",
2928 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2929 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2934 if (stripe_offset_opt != NULL) {
2935 /* get the stripe offset */
2936 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2938 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2939 argv[0], stripe_offset_opt);
2945 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2946 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2947 " or -i options.\n", argv[0]);
2955 if (mode_opt != NULL) {
2956 mode = strtoul(mode_opt, &end, 8);
2958 fprintf(stderr, "error: %s: bad mode '%s'\n",
2962 previous_mode = umask(0);
2965 if (stripe_hash_opt == NULL) {
2966 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2968 hash_type = check_hashtype(stripe_hash_opt);
2969 if (hash_type == 0) {
2971 "error: %s: bad stripe hash type '%s'\n",
2972 argv[0], stripe_hash_opt);
2977 /* get the stripe count */
2978 if (stripe_count_opt != NULL) {
2979 stripe_count = strtoul(stripe_count_opt, &end, 0);
2981 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2982 argv[0], stripe_count_opt);
2987 dname = argv[optind];
2989 if (default_stripe) {
2990 result = llapi_dir_set_default_lmv_stripe(dname,
2991 stripe_offset, stripe_count,
2994 result = llapi_dir_create_pool(dname, mode,
2996 stripe_count, hash_type,
3001 fprintf(stderr, "error: %s: create stripe dir '%s' "
3002 "failed\n", argv[0], dname);
3005 dname = argv[++optind];
3006 } while (dname != NULL);
3008 if (mode_opt != NULL)
3009 umask(previous_mode);
3015 static int lfs_rmentry(int argc, char **argv)
3022 fprintf(stderr, "error: %s: missing dirname\n",
3028 dname = argv[index];
3029 while (dname != NULL) {
3030 result = llapi_direntry_remove(dname);
3032 fprintf(stderr, "error: %s: remove dir entry '%s' "
3033 "failed\n", argv[0], dname);
3036 dname = argv[++index];
3041 static int lfs_mv(int argc, char **argv)
3043 struct find_param param = {
3050 struct option long_opts[] = {
3051 {"mdt-index", required_argument, 0, 'M'},
3052 {"verbose", no_argument, 0, 'v'},
3056 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3059 param.fp_mdt_index = strtoul(optarg, &end, 0);
3061 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3068 param.fp_verbose = VERBOSE_DETAIL;
3072 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3073 argv[0], argv[optind - 1]);
3078 if (param.fp_mdt_index == -1) {
3079 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3083 if (optind >= argc) {
3084 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3088 param.fp_migrate = 1;
3089 rc = llapi_migrate_mdt(argv[optind], ¶m);
3091 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3092 argv[0], argv[optind], param.fp_mdt_index,
3097 static int lfs_osts(int argc, char **argv)
3099 return lfs_tgts(argc, argv);
3102 static int lfs_mdts(int argc, char **argv)
3104 return lfs_tgts(argc, argv);
3107 #define COOK(value) \
3110 while (value > 1024) { \
3118 #define CDF "%11llu"
3119 #define HDF "%8.1f%c"
3124 MNTDF_INODES = 0x0001,
3125 MNTDF_COOKED = 0x0002,
3126 MNTDF_LAZY = 0x0004,
3127 MNTDF_VERBOSE = 0x0008,
3130 static int showdf(char *mntdir, struct obd_statfs *stat,
3131 char *uuid, enum mntdf_flags flags,
3132 char *type, int index, int rc)
3134 long long avail, used, total;
3136 char *suffix = "KMGTPEZY";
3137 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3138 char tbuf[3 * sizeof(__u64)];
3139 char ubuf[3 * sizeof(__u64)];
3140 char abuf[3 * sizeof(__u64)];
3141 char rbuf[3 * sizeof(__u64)];
3148 if (flags & MNTDF_INODES) {
3149 avail = stat->os_ffree;
3150 used = stat->os_files - stat->os_ffree;
3151 total = stat->os_files;
3153 int shift = flags & MNTDF_COOKED ? 0 : 10;
3155 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3156 used = ((stat->os_blocks - stat->os_bfree) *
3157 stat->os_bsize) >> shift;
3158 total = (stat->os_blocks * stat->os_bsize) >> shift;
3161 if ((used + avail) > 0)
3162 ratio = (double)used / (double)(used + avail);
3164 if (flags & MNTDF_COOKED) {
3168 cook_val = (double)total;
3171 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3174 snprintf(tbuf, sizeof(tbuf), CDF, total);
3176 cook_val = (double)used;
3179 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3182 snprintf(ubuf, sizeof(ubuf), CDF, used);
3184 cook_val = (double)avail;
3187 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3190 snprintf(abuf, sizeof(abuf), CDF, avail);
3192 snprintf(tbuf, sizeof(tbuf), CDF, total);
3193 snprintf(ubuf, sizeof(tbuf), CDF, used);
3194 snprintf(abuf, sizeof(tbuf), CDF, avail);
3197 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3198 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3199 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3201 printf("[%s:%d]", type, index);
3203 if (stat->os_state) {
3205 * Each character represents the matching
3208 const char state_names[] = "DRSI";
3213 for (i = 0, state = stat->os_state;
3214 state && i < sizeof(state_names); i++) {
3215 if (!(state & (1 << i)))
3217 printf("%c", state_names[i]);
3225 printf(UUF": inactive device\n", uuid);
3228 printf(UUF": %s\n", uuid, strerror(-rc));
3235 struct ll_stat_type {
3240 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3242 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3243 struct obd_uuid uuid_buf;
3244 char *poolname = NULL;
3245 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3246 { LL_STATFS_LOV, "OST" },
3248 struct ll_stat_type *tp;
3249 __u64 ost_ffree = 0;
3257 poolname = strchr(pool, '.');
3258 if (poolname != NULL) {
3259 if (strncmp(fsname, pool, strlen(fsname))) {
3260 fprintf(stderr, "filesystem name incorrect\n");
3268 fd = open(mntdir, O_RDONLY);
3271 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3276 if (flags & MNTDF_INODES)
3277 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3278 "UUID", "Inodes", "IUsed", "IFree",
3279 "IUse%", "Mounted on");
3281 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3282 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3283 "Used", "Available", "Use%", "Mounted on");
3285 for (tp = types; tp->st_name != NULL; tp++) {
3286 for (index = 0; ; index++) {
3287 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3288 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3289 type = flags & MNTDF_LAZY ?
3290 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3291 rc2 = llapi_obd_fstatfs(fd, type, index,
3292 &stat_buf, &uuid_buf);
3297 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3298 if (!(flags & MNTDF_VERBOSE))
3300 } else if (rc2 < 0 && rc == 0) {
3304 if (poolname && tp->st_op == LL_STATFS_LOV &&
3305 llapi_search_ost(fsname, poolname,
3306 obd_uuid2str(&uuid_buf)) != 1)
3309 /* the llapi_obd_statfs() call may have returned with
3310 * an error, but if it filled in uuid_buf we will at
3311 * lease use that to print out a message for that OBD.
3312 * If we didn't get anything in the uuid_buf, then fill
3313 * it in so that we can print an error message. */
3314 if (uuid_buf.uuid[0] == '\0')
3315 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3316 "%s%04x", tp->st_name, index);
3317 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3318 flags, tp->st_name, index, rc2);
3321 if (tp->st_op == LL_STATFS_LMV) {
3322 sum.os_ffree += stat_buf.os_ffree;
3323 sum.os_files += stat_buf.os_files;
3324 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3325 sum.os_blocks += stat_buf.os_blocks *
3327 sum.os_bfree += stat_buf.os_bfree *
3329 sum.os_bavail += stat_buf.os_bavail *
3331 ost_ffree += stat_buf.os_ffree;
3339 /* If we don't have as many objects free on the OST as inodes
3340 * on the MDS, we reduce the total number of inodes to
3341 * compensate, so that the "inodes in use" number is correct.
3342 * Matches ll_statfs_internal() so the results are consistent. */
3343 if (ost_ffree < sum.os_ffree) {
3344 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3345 sum.os_ffree = ost_ffree;
3348 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3354 static int lfs_df(int argc, char **argv)
3356 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3357 enum mntdf_flags flags = 0;
3358 int c, rc = 0, index = 0;
3359 char fsname[PATH_MAX] = "", *pool_name = NULL;
3360 struct option long_opts[] = {
3361 { .val = 'h', .name = "human-readable",
3362 .has_arg = no_argument },
3363 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3364 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3365 { .val = 'p', .name = "pool", .has_arg = required_argument },
3366 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3369 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3372 flags |= MNTDF_COOKED;
3375 flags |= MNTDF_INODES;
3378 flags |= MNTDF_LAZY;
3384 flags |= MNTDF_VERBOSE;
3390 if (optind < argc && !realpath(argv[optind], path)) {
3392 fprintf(stderr, "error: invalid path '%s': %s\n",
3393 argv[optind], strerror(-rc));
3397 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3398 /* Check if we have a mount point */
3399 if (mntdir[0] == '\0')
3402 rc = mntdf(mntdir, fsname, pool_name, flags);
3403 if (rc || path[0] != '\0')
3405 fsname[0] = '\0'; /* avoid matching in next loop */
3406 mntdir[0] = '\0'; /* avoid matching in next loop */
3412 static int lfs_getname(int argc, char **argv)
3414 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3415 int rc = 0, index = 0, c;
3416 char buf[sizeof(struct obd_uuid)];
3418 while ((c = getopt(argc, argv, "h")) != -1)
3421 if (optind == argc) { /* no paths specified, get all paths. */
3422 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3423 rc = llapi_getname(mntdir, buf, sizeof(buf));
3426 "cannot get name for `%s': %s\n",
3427 mntdir, strerror(-rc));
3431 printf("%s %s\n", buf, mntdir);
3433 path[0] = fsname[0] = mntdir[0] = 0;
3435 } else { /* paths specified, only attempt to search these. */
3436 for (; optind < argc; optind++) {
3437 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3440 "cannot get name for `%s': %s\n",
3441 argv[optind], strerror(-rc));
3445 printf("%s %s\n", buf, argv[optind]);
3451 static int lfs_check(int argc, char **argv)
3454 char mntdir[PATH_MAX] = {'\0'};
3463 obd_types[0] = obd_type1;
3464 obd_types[1] = obd_type2;
3466 if (strcmp(argv[1], "osts") == 0) {
3467 strcpy(obd_types[0], "osc");
3468 } else if (strcmp(argv[1], "mds") == 0) {
3469 strcpy(obd_types[0], "mdc");
3470 } else if (strcmp(argv[1], "servers") == 0) {
3472 strcpy(obd_types[0], "osc");
3473 strcpy(obd_types[1], "mdc");
3475 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3480 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3481 if (rc < 0 || mntdir[0] == '\0') {
3482 fprintf(stderr, "No suitable Lustre mount found\n");
3486 rc = llapi_target_check(num_types, obd_types, mntdir);
3488 fprintf(stderr, "error: %s: %s status failed\n",
3495 #ifdef HAVE_SYS_QUOTA_H
3496 #define ARG2INT(nr, str, msg) \
3499 nr = strtol(str, &endp, 0); \
3501 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3506 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3508 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3509 * returns the value or ULONG_MAX on integer overflow or incorrect format
3511 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3512 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3513 * 3. empty integer value is interpreted as 0
3515 static unsigned long str2sec(const char* timestr)
3517 const char spec[] = "smhdw";
3518 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3519 unsigned long val = 0;
3522 if (strpbrk(timestr, spec) == NULL) {
3523 /* no specifiers inside the time string,
3524 should treat it as an integer value */
3525 val = strtoul(timestr, &tail, 10);
3526 return *tail ? ULONG_MAX : val;
3529 /* format string is XXwXXdXXhXXmXXs */
3535 v = strtoul(timestr, &tail, 10);
3536 if (v == ULONG_MAX || *tail == '\0')
3537 /* value too large (ULONG_MAX or more)
3538 or missing specifier */
3541 ptr = strchr(spec, *tail);
3543 /* unknown specifier */
3548 /* check if product will overflow the type */
3549 if (!(v < ULONG_MAX / mult[ind]))
3552 ADD_OVERFLOW(val, mult[ind] * v);
3553 if (val == ULONG_MAX)
3565 #define ARG2ULL(nr, str, def_units) \
3567 unsigned long long limit, units = def_units; \
3570 rc = llapi_parse_size(str, &limit, &units, 1); \
3572 fprintf(stderr, "error: bad limit value %s\n", str); \
3578 static inline int has_times_option(int argc, char **argv)
3582 for (i = 1; i < argc; i++)
3583 if (!strcmp(argv[i], "-t"))
3589 int lfs_setquota_times(int argc, char **argv)
3592 struct if_quotactl qctl;
3593 char *mnt, *obd_type = (char *)qctl.obd_type;
3594 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3595 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3596 struct option long_opts[] = {
3597 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3598 { .val = 'g', .name = "group", .has_arg = no_argument },
3599 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3600 { .val = 'p', .name = "projid", .has_arg = no_argument },
3601 { .val = 't', .name = "times", .has_arg = no_argument },
3602 { .val = 'u', .name = "user", .has_arg = no_argument },
3606 memset(&qctl, 0, sizeof(qctl));
3607 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3608 qctl.qc_type = ALLQUOTA;
3610 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3611 long_opts, NULL)) != -1) {
3622 if (qctl.qc_type != ALLQUOTA) {
3623 fprintf(stderr, "error: -u/g/p can't be used "
3624 "more than once\n");
3627 qctl.qc_type = qtype;
3630 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3631 fprintf(stderr, "error: bad block-grace: %s\n",
3635 dqb->dqb_valid |= QIF_BTIME;
3638 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3639 fprintf(stderr, "error: bad inode-grace: %s\n",
3643 dqb->dqb_valid |= QIF_ITIME;
3645 case 't': /* Yes, of course! */
3647 default: /* getopt prints error message for us when opterr != 0 */
3652 if (qctl.qc_type == ALLQUOTA) {
3653 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3657 if (optind != argc - 1) {
3658 fprintf(stderr, "error: unexpected parameters encountered\n");
3663 rc = llapi_quotactl(mnt, &qctl);
3666 fprintf(stderr, "%s %s ", obd_type,
3667 obd_uuid2str(&qctl.obd_uuid));
3668 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3675 #define BSLIMIT (1 << 0)
3676 #define BHLIMIT (1 << 1)
3677 #define ISLIMIT (1 << 2)
3678 #define IHLIMIT (1 << 3)
3680 int lfs_setquota(int argc, char **argv)
3683 struct if_quotactl qctl;
3684 char *mnt, *obd_type = (char *)qctl.obd_type;
3685 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3686 struct option long_opts[] = {
3687 {"block-softlimit", required_argument, 0, 'b'},
3688 {"block-hardlimit", required_argument, 0, 'B'},
3689 {"group", required_argument, 0, 'g'},
3690 {"inode-softlimit", required_argument, 0, 'i'},
3691 {"inode-hardlimit", required_argument, 0, 'I'},
3692 {"user", required_argument, 0, 'u'},
3693 {"projid", required_argument, 0, 'p'},
3696 unsigned limit_mask = 0;
3700 if (has_times_option(argc, argv))
3701 return lfs_setquota_times(argc, argv);
3703 memset(&qctl, 0, sizeof(qctl));
3704 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3705 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3706 * so it can be used as a marker that qc_type
3707 * isn't reinitialized from command line */
3709 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3710 long_opts, NULL)) != -1) {
3714 rc = name2uid(&qctl.qc_id, optarg);
3718 rc = name2gid(&qctl.qc_id, optarg);
3722 rc = name2projid(&qctl.qc_id, optarg);
3724 if (qctl.qc_type != ALLQUOTA) {
3725 fprintf(stderr, "error: -u and -g can't be used"
3726 " more than once\n");
3729 qctl.qc_type = qtype;
3731 qctl.qc_id = strtoul(optarg, &endptr, 10);
3732 if (*endptr != '\0') {
3733 fprintf(stderr, "error: can't find id "
3734 "for name %s\n", optarg);
3740 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3741 dqb->dqb_bsoftlimit >>= 10;
3742 limit_mask |= BSLIMIT;
3743 if (dqb->dqb_bsoftlimit &&
3744 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3745 fprintf(stderr, "warning: block softlimit is "
3746 "smaller than the miminal qunit size, "
3747 "please see the help of setquota or "
3748 "Lustre manual for details.\n");
3751 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3752 dqb->dqb_bhardlimit >>= 10;
3753 limit_mask |= BHLIMIT;
3754 if (dqb->dqb_bhardlimit &&
3755 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3756 fprintf(stderr, "warning: block hardlimit is "
3757 "smaller than the miminal qunit size, "
3758 "please see the help of setquota or "
3759 "Lustre manual for details.\n");
3762 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3763 limit_mask |= ISLIMIT;
3764 if (dqb->dqb_isoftlimit &&
3765 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3766 fprintf(stderr, "warning: inode softlimit is "
3767 "smaller than the miminal qunit size, "
3768 "please see the help of setquota or "
3769 "Lustre manual for details.\n");
3772 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3773 limit_mask |= IHLIMIT;
3774 if (dqb->dqb_ihardlimit &&
3775 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3776 fprintf(stderr, "warning: inode hardlimit is "
3777 "smaller than the miminal qunit size, "
3778 "please see the help of setquota or "
3779 "Lustre manual for details.\n");
3781 default: /* getopt prints error message for us when opterr != 0 */
3786 if (qctl.qc_type == ALLQUOTA) {
3787 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3791 if (limit_mask == 0) {
3792 fprintf(stderr, "error: at least one limit must be specified\n");
3796 if (optind != argc - 1) {
3797 fprintf(stderr, "error: unexpected parameters encountered\n");
3803 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3804 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3805 /* sigh, we can't just set blimits/ilimits */
3806 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3807 .qc_type = qctl.qc_type,
3808 .qc_id = qctl.qc_id};
3810 rc = llapi_quotactl(mnt, &tmp_qctl);
3812 fprintf(stderr, "error: setquota failed while retrieving"
3813 " current quota settings (%s)\n",
3818 if (!(limit_mask & BHLIMIT))
3819 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3820 if (!(limit_mask & BSLIMIT))
3821 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3822 if (!(limit_mask & IHLIMIT))
3823 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3824 if (!(limit_mask & ISLIMIT))
3825 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3827 /* Keep grace times if we have got no softlimit arguments */
3828 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3829 dqb->dqb_valid |= QIF_BTIME;
3830 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3833 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3834 dqb->dqb_valid |= QIF_ITIME;
3835 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3839 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3840 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3842 rc = llapi_quotactl(mnt, &qctl);
3845 fprintf(stderr, "%s %s ", obd_type,
3846 obd_uuid2str(&qctl.obd_uuid));
3847 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3854 /* Converts seconds value into format string
3855 * result is returned in buf
3857 * 1. result is in descenting order: 1w2d3h4m5s
3858 * 2. zero fields are not filled (except for p. 3): 5d1s
3859 * 3. zero seconds value is presented as "0s"
3861 static char * __sec2str(time_t seconds, char *buf)
3863 const char spec[] = "smhdw";
3864 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3869 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3870 c = seconds / mult[i];
3872 if (c > 0 || (i == 0 && buf == tail))
3873 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3881 static void sec2str(time_t seconds, char *buf, int rc)
3888 tail = __sec2str(seconds, tail);
3890 if (rc && tail - buf < 39) {
3896 static void diff2str(time_t seconds, char *buf, time_t now)
3902 if (seconds <= now) {
3903 strcpy(buf, "none");
3906 __sec2str(seconds - now, buf);
3909 static void print_quota_title(char *name, struct if_quotactl *qctl,
3910 bool human_readable)
3912 printf("Disk quotas for %s %s (%cid %u):\n",
3913 qtype_name(qctl->qc_type), name,
3914 *qtype_name(qctl->qc_type), qctl->qc_id);
3915 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3916 "Filesystem", human_readable ? "used" : "kbytes",
3917 "quota", "limit", "grace",
3918 "files", "quota", "limit", "grace");
3921 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3924 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3927 snprintf(buf, buflen, "%5.4gP",
3928 (double)num / ((__u64)1 << 40));
3930 snprintf(buf, buflen, "%5.4gT",
3931 (double)num / (1 << 30));
3933 snprintf(buf, buflen, "%5.4gG",
3934 (double)num / (1 << 20));
3936 snprintf(buf, buflen, "%5.4gM",
3937 (double)num / (1 << 10));
3939 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3943 #define STRBUF_LEN 32
3944 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3951 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3952 int bover = 0, iover = 0;
3953 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3954 char numbuf[3][STRBUF_LEN];
3956 char strbuf[STRBUF_LEN];
3958 if (dqb->dqb_bhardlimit &&
3959 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3961 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3962 if (dqb->dqb_btime > now) {
3969 if (dqb->dqb_ihardlimit &&
3970 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3972 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3973 if (dqb->dqb_itime > now) {
3981 if (strlen(mnt) > 15)
3982 printf("%s\n%15s", mnt, "");
3984 printf("%15s", mnt);
3987 diff2str(dqb->dqb_btime, timebuf, now);
3989 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3990 strbuf, sizeof(strbuf), h);
3991 if (rc == -EREMOTEIO)
3992 sprintf(numbuf[0], "%s*", strbuf);
3994 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3995 "%s" : "[%s]", strbuf);
3997 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3998 if (type == QC_GENERAL)
3999 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4000 "%s" : "[%s]", strbuf);
4002 sprintf(numbuf[1], "%s", "-");
4004 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4005 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4006 "%s" : "[%s]", strbuf);
4008 printf(" %7s%c %6s %7s %7s",
4009 numbuf[0], bover ? '*' : ' ', numbuf[1],
4010 numbuf[2], bover > 1 ? timebuf : "-");
4013 diff2str(dqb->dqb_itime, timebuf, now);
4015 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4016 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4018 if (type == QC_GENERAL)
4019 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4021 (uintmax_t)dqb->dqb_isoftlimit);
4023 sprintf(numbuf[1], "%s", "-");
4025 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4026 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4028 if (type != QC_OSTIDX)
4029 printf(" %7s%c %6s %7s %7s",
4030 numbuf[0], iover ? '*' : ' ', numbuf[1],
4031 numbuf[2], iover > 1 ? timebuf : "-");
4033 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4036 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4037 qctl->qc_cmd == Q_GETOINFO) {
4041 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4042 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4043 printf("Block grace time: %s; Inode grace time: %s\n",
4044 bgtimebuf, igtimebuf);
4048 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4049 bool h, __u64 *total)
4051 int rc = 0, rc1 = 0, count = 0;
4052 __u32 valid = qctl->qc_valid;
4054 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4056 fprintf(stderr, "can not get %s count: %s\n",
4057 is_mdt ? "mdt": "ost", strerror(-rc));
4061 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4062 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4063 rc = llapi_quotactl(mnt, qctl);
4065 /* It is remote client case. */
4066 if (rc == -EOPNOTSUPP) {
4073 fprintf(stderr, "quotactl %s%d failed.\n",
4074 is_mdt ? "mdt": "ost", qctl->qc_idx);
4078 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4079 qctl->qc_valid, 0, h);
4080 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4081 qctl->qc_dqblk.dqb_bhardlimit;
4084 qctl->qc_valid = valid;
4088 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
4089 int verbose, int quiet, bool human_readable)
4091 int rc1 = 0, rc2 = 0, rc3 = 0;
4092 char *obd_type = (char *)qctl->obd_type;
4093 char *obd_uuid = (char *)qctl->obd_uuid.uuid;
4094 __u64 total_ialloc = 0, total_balloc = 0;
4097 rc1 = llapi_quotactl(mnt, qctl);
4101 fprintf(stderr, "%s quotas are not enabled.\n",
4102 qtype_name(qctl->qc_type));
4105 fprintf(stderr, "Permission denied.\n");
4108 /* We already got error message. */
4111 fprintf(stderr, "Unexpected quotactl error: %s\n",
4116 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4117 print_quota_title(name, qctl, human_readable);
4119 if (rc1 && *obd_type)
4120 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4122 if (qctl->qc_valid != QC_GENERAL)
4125 inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) &&
4126 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4127 (QIF_LIMITS|QIF_USAGE));
4129 print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable);
4131 if (qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
4133 char strbuf[STRBUF_LEN];
4135 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
4137 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
4139 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4141 printf("Total allocated inode limit: %ju, total "
4142 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4146 if (rc1 || rc2 || rc3 || inacc)
4147 printf("Some errors happened when getting quota info. "
4148 "Some devices may be not working or deactivated. "
4149 "The data in \"[]\" is inaccurate.\n");
4155 static int lfs_project(int argc, char **argv)
4157 int ret = 0, err = 0, c, i;
4158 struct project_handle_control phc = { 0 };
4159 enum lfs_project_ops_t op;
4162 phc.assign_projid = false;
4163 /* default action */
4164 op = LFS_PROJECT_LIST;
4166 while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
4169 if (op != LFS_PROJECT_LIST) {
4171 "%s: cannot specify '-c' '-C' '-s' together\n",
4176 op = LFS_PROJECT_CHECK;
4179 if (op != LFS_PROJECT_LIST) {
4181 "%s: cannot specify '-c' '-C' '-s' together\n",
4186 op = LFS_PROJECT_CLEAR;
4189 if (op != LFS_PROJECT_LIST) {
4191 "%s: cannot specify '-c' '-C' '-s' together\n",
4196 phc.set_inherit = true;
4197 op = LFS_PROJECT_SET;
4203 phc.keep_projid = true;
4206 phc.recursive = true;
4209 phc.projid = strtoul(optarg, NULL, 0);
4210 phc.assign_projid = true;
4214 phc.newline = false;
4217 fprintf(stderr, "%s: invalid option '%c'\n",
4223 if (phc.assign_projid && op == LFS_PROJECT_LIST) {
4224 op = LFS_PROJECT_SET;
4225 phc.set_projid = true;
4226 } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
4227 phc.set_projid = true;
4231 case LFS_PROJECT_CHECK:
4232 if (phc.keep_projid) {
4234 "%s: '-k' is useless together with '-c'\n",
4239 case LFS_PROJECT_CLEAR:
4242 "%s: '-0' is useless together with '-C'\n",
4246 if (phc.assign_projid) {
4248 "%s: '-p' is useless together with '-C'\n",
4253 case LFS_PROJECT_SET:
4256 "%s: '-0' is useless together with '-s'\n",
4260 if (phc.keep_projid) {
4262 "%s: '-k' is useless together with '-s'\n",
4270 "%s: '-0' is useless for list operations\n",
4280 fprintf(stderr, "%s: missing file or directory target(s)\n",
4285 for (i = 0; i < argc; i++) {
4287 case LFS_PROJECT_CHECK:
4288 err = lfs_project_check(argv[i], &phc);
4290 case LFS_PROJECT_LIST:
4291 err = lfs_project_list(argv[i], &phc);
4293 case LFS_PROJECT_CLEAR:
4294 err = lfs_project_clear(argv[i], &phc);
4296 case LFS_PROJECT_SET:
4297 err = lfs_project_set(argv[i], &phc);
4309 static int lfs_quota(int argc, char **argv)
4312 char *mnt, *name = NULL;
4313 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4314 .qc_type = ALLQUOTA };
4315 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4316 int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
4318 __u32 valid = QC_GENERAL, idx = 0;
4319 bool human_readable = false;
4322 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4333 if (qctl.qc_type != ALLQUOTA) {
4334 fprintf(stderr, "error: use either -u or -g\n");
4337 qctl.qc_type = qtype;
4340 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4343 valid = qctl.qc_valid = QC_UUID;
4344 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4347 valid = qctl.qc_valid = QC_MDTIDX;
4348 idx = qctl.qc_idx = atoi(optarg);
4351 valid = qctl.qc_valid = QC_OSTIDX;
4352 idx = qctl.qc_idx = atoi(optarg);
4361 human_readable = true;
4364 fprintf(stderr, "error: %s: option '-%c' "
4365 "unrecognized\n", argv[0], c);
4370 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4371 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4372 optind == argc - 1) {
4374 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4375 qctl.qc_valid = valid;
4378 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
4379 qctl.qc_type = qtype;
4380 if (qtype == USRQUOTA) {
4381 qctl.qc_id = geteuid();
4382 rc = uid2name(&name, qctl.qc_id);
4384 qctl.qc_id = getegid();
4385 rc = gid2name(&name, qctl.qc_id);
4390 rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet,
4396 /* lfs quota -u username /path/to/lustre/mount */
4397 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4398 /* options should be followed by u/g-name and mntpoint */
4399 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4400 fprintf(stderr, "error: missing quota argument(s)\n");
4404 name = argv[optind++];
4405 switch (qctl.qc_type) {
4407 rc = name2uid(&qctl.qc_id, name);
4410 rc = name2gid(&qctl.qc_id, name);
4413 rc = name2projid(&qctl.qc_id, name);
4420 qctl.qc_id = strtoul(name, &endptr, 10);
4421 if (*endptr != '\0') {
4422 fprintf(stderr, "error: can't find id for name: %s\n",
4427 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4428 fprintf(stderr, "error: missing quota info argument(s)\n");
4433 rc = get_print_quota(mnt, name, &qctl, verbose, quiet,
4437 #endif /* HAVE_SYS_QUOTA_H! */
4439 static int flushctx_ioctl(char *mp)
4443 fd = open(mp, O_RDONLY);
4445 fprintf(stderr, "flushctx: error open %s: %s\n",
4446 mp, strerror(errno));
4450 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4452 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4453 mp, strerror(errno));
4459 static int lfs_flushctx(int argc, char **argv)
4461 int kdestroy = 0, c;
4462 char mntdir[PATH_MAX] = {'\0'};
4466 while ((c = getopt(argc, argv, "k")) != -1) {
4472 fprintf(stderr, "error: %s: option '-%c' "
4473 "unrecognized\n", argv[0], c);
4479 if ((rc = system("kdestroy > /dev/null")) != 0) {
4480 rc = WEXITSTATUS(rc);
4481 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4485 if (optind >= argc) {
4486 /* flush for all mounted lustre fs. */
4487 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4488 /* Check if we have a mount point */
4489 if (mntdir[0] == '\0')
4492 if (flushctx_ioctl(mntdir))
4495 mntdir[0] = '\0'; /* avoid matching in next loop */
4498 /* flush fs as specified */
4499 while (optind < argc) {
4500 if (flushctx_ioctl(argv[optind++]))
4507 static int lfs_cp(int argc, char **argv)
4509 fprintf(stderr, "remote client copy file(s).\n"
4510 "obsolete, does not support it anymore.\n");
4514 static int lfs_ls(int argc, char **argv)
4516 fprintf(stderr, "remote client lists directory contents.\n"
4517 "obsolete, does not support it anymore.\n");
4521 static int lfs_changelog(int argc, char **argv)
4523 void *changelog_priv;
4524 struct changelog_rec *rec;
4525 long long startrec = 0, endrec = 0;
4527 struct option long_opts[] = {
4528 {"follow", no_argument, 0, 'f'},
4531 char short_opts[] = "f";
4534 while ((rc = getopt_long(argc, argv, short_opts,
4535 long_opts, NULL)) != -1) {
4543 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4544 argv[0], argv[optind - 1]);
4551 mdd = argv[optind++];
4553 startrec = strtoll(argv[optind++], NULL, 10);
4555 endrec = strtoll(argv[optind++], NULL, 10);
4557 rc = llapi_changelog_start(&changelog_priv,
4558 CHANGELOG_FLAG_BLOCK |
4559 CHANGELOG_FLAG_JOBID |
4560 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4563 fprintf(stderr, "Can't start changelog: %s\n",
4564 strerror(errno = -rc));
4568 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4572 if (endrec && rec->cr_index > endrec) {
4573 llapi_changelog_free(&rec);
4576 if (rec->cr_index < startrec) {
4577 llapi_changelog_free(&rec);
4581 secs = rec->cr_time >> 30;
4582 gmtime_r(&secs, &ts);
4583 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4584 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4585 changelog_type2str(rec->cr_type),
4586 ts.tm_hour, ts.tm_min, ts.tm_sec,
4587 (int)(rec->cr_time & ((1 << 30) - 1)),
4588 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4589 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4591 if (rec->cr_flags & CLF_JOBID) {
4592 struct changelog_ext_jobid *jid =
4593 changelog_rec_jobid(rec);
4595 if (jid->cr_jobid[0] != '\0')
4596 printf(" j=%s", jid->cr_jobid);
4599 if (rec->cr_namelen)
4600 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4601 rec->cr_namelen, changelog_rec_name(rec));
4603 if (rec->cr_flags & CLF_RENAME) {
4604 struct changelog_ext_rename *rnm =
4605 changelog_rec_rename(rec);
4607 if (!fid_is_zero(&rnm->cr_sfid))
4608 printf(" s="DFID" sp="DFID" %.*s",
4609 PFID(&rnm->cr_sfid),
4610 PFID(&rnm->cr_spfid),
4611 (int)changelog_rec_snamelen(rec),
4612 changelog_rec_sname(rec));
4616 llapi_changelog_free(&rec);
4619 llapi_changelog_fini(&changelog_priv);
4622 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4624 return (rc == 1 ? 0 : rc);
4627 static int lfs_changelog_clear(int argc, char **argv)
4635 endrec = strtoll(argv[3], NULL, 10);
4637 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4640 fprintf(stderr, "%s: record out of range: %llu\n",
4642 else if (rc == -ENOENT)
4643 fprintf(stderr, "%s: no changelog user: %s\n",
4646 fprintf(stderr, "%s error: %s\n", argv[0],
4655 static int lfs_fid2path(int argc, char **argv)
4657 struct option long_opts[] = {
4658 { .val = 'c', .name = "cur", .has_arg = no_argument },
4659 { .val = 'l', .name = "link", .has_arg = required_argument },
4660 { .val = 'r', .name = "rec", .has_arg = required_argument },
4662 char short_opts[] = "cl:r:";
4663 char *device, *fid, *path;
4664 long long recno = -1;
4670 while ((rc = getopt_long(argc, argv, short_opts,
4671 long_opts, NULL)) != -1) {
4677 linkno = strtol(optarg, NULL, 10);
4680 recno = strtoll(optarg, NULL, 10);
4685 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4686 argv[0], argv[optind - 1]);
4694 device = argv[optind++];
4695 path = calloc(1, PATH_MAX);
4697 fprintf(stderr, "error: Not enough memory\n");
4702 while (optind < argc) {
4703 fid = argv[optind++];
4705 lnktmp = (linkno >= 0) ? linkno : 0;
4707 int oldtmp = lnktmp;
4708 long long rectmp = recno;
4710 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4713 fprintf(stderr, "%s: error on FID %s: %s\n",
4714 argv[0], fid, strerror(errno = -rc2));
4721 fprintf(stdout, "%lld ", rectmp);
4722 if (device[0] == '/') {
4723 fprintf(stdout, "%s", device);
4724 if (device[strlen(device) - 1] != '/')
4725 fprintf(stdout, "/");
4726 } else if (path[0] == '\0') {
4727 fprintf(stdout, "/");
4729 fprintf(stdout, "%s\n", path);
4732 /* specified linkno */
4734 if (oldtmp == lnktmp)
4744 static int lfs_path2fid(int argc, char **argv)
4746 struct option long_opts[] = {
4747 {"parents", no_argument, 0, 'p'},
4751 const char short_opts[] = "p";
4752 const char *sep = "";
4755 bool show_parents = false;
4757 while ((rc = getopt_long(argc, argv, short_opts,
4758 long_opts, NULL)) != -1) {
4761 show_parents = true;
4764 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4765 argv[0], argv[optind - 1]);
4770 if (optind > argc - 1)
4772 else if (optind < argc - 1)
4776 for (path = argv + optind; *path != NULL; path++) {
4778 if (!show_parents) {
4779 err = llapi_path2fid(*path, &fid);
4781 printf("%s%s"DFID"\n",
4782 *sep != '\0' ? *path : "", sep,
4785 char name[NAME_MAX + 1];
4786 unsigned int linkno = 0;
4788 while ((err = llapi_path2parent(*path, linkno, &fid,
4789 name, sizeof(name))) == 0) {
4790 if (*sep != '\0' && linkno == 0)
4791 printf("%s%s", *path, sep);
4793 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4798 /* err == -ENODATA is end-of-loop */
4799 if (linkno > 0 && err == -ENODATA) {
4806 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4807 argv[0], show_parents ? "parent " : "", *path,
4819 static int lfs_data_version(int argc, char **argv)
4826 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4831 while ((c = getopt(argc, argv, "nrw")) != -1) {
4834 data_version_flags = 0;
4837 data_version_flags |= LL_DV_RD_FLUSH;
4840 data_version_flags |= LL_DV_WR_FLUSH;
4849 path = argv[optind];
4850 fd = open(path, O_RDONLY);
4852 err(errno, "cannot open file %s", path);
4854 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4856 err(errno, "cannot get version for %s", path);
4858 printf("%ju" "\n", (uintmax_t)data_version);
4864 static int lfs_hsm_state(int argc, char **argv)
4869 struct hsm_user_state hus;
4877 rc = llapi_hsm_state_get(path, &hus);
4879 fprintf(stderr, "can't get hsm state for %s: %s\n",
4880 path, strerror(errno = -rc));
4884 /* Display path name and status flags */
4885 printf("%s: (0x%08x)", path, hus.hus_states);
4887 if (hus.hus_states & HS_RELEASED)
4888 printf(" released");
4889 if (hus.hus_states & HS_EXISTS)
4891 if (hus.hus_states & HS_DIRTY)
4893 if (hus.hus_states & HS_ARCHIVED)
4894 printf(" archived");
4895 /* Display user-settable flags */
4896 if (hus.hus_states & HS_NORELEASE)
4897 printf(" never_release");
4898 if (hus.hus_states & HS_NOARCHIVE)
4899 printf(" never_archive");
4900 if (hus.hus_states & HS_LOST)
4901 printf(" lost_from_hsm");
4903 if (hus.hus_archive_id != 0)
4904 printf(", archive_id:%d", hus.hus_archive_id);
4907 } while (++i < argc);
4912 #define LFS_HSM_SET 0
4913 #define LFS_HSM_CLEAR 1
4916 * Generic function to set or clear HSM flags.
4917 * Used by hsm_set and hsm_clear.
4919 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4921 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4923 struct option long_opts[] = {
4924 { .val = 'A', .name = "archived", .has_arg = no_argument },
4925 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4926 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4927 { .val = 'e', .name = "exists", .has_arg = no_argument },
4928 { .val = 'l', .name = "lost", .has_arg = no_argument },
4929 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4930 { .val = 'i', .name = "archive-id", .has_arg = required_argument },
4932 char short_opts[] = "lraAdei:";
4936 __u32 archive_id = 0;
4942 while ((c = getopt_long(argc, argv, short_opts,
4943 long_opts, NULL)) != -1) {
4949 mask |= HS_NOARCHIVE;
4952 mask |= HS_ARCHIVED;
4955 mask |= HS_NORELEASE;
4964 archive_id = strtol(optarg, &end, 10);
4966 fprintf(stderr, "invalid archive_id: '%s'\n",
4974 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4975 argv[0], argv[optind - 1]);
4980 /* User should have specified a flag */
4984 while (optind < argc) {
4986 path = argv[optind];
4988 /* If mode == 0, this means we apply the mask. */
4989 if (mode == LFS_HSM_SET)
4990 rc = llapi_hsm_state_set(path, mask, 0, archive_id);
4992 rc = llapi_hsm_state_set(path, 0, mask, 0);
4995 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4996 path, strerror(errno = -rc));
5005 static int lfs_hsm_action(int argc, char **argv)
5010 struct hsm_current_action hca;
5011 struct hsm_extent he;
5012 enum hsm_user_action hua;
5013 enum hsm_progress_states hps;
5021 rc = llapi_hsm_current_action(path, &hca);
5023 fprintf(stderr, "can't get hsm action for %s: %s\n",
5024 path, strerror(errno = -rc));
5027 he = hca.hca_location;
5028 hua = hca.hca_action;
5029 hps = hca.hca_state;
5031 printf("%s: %s", path, hsm_user_action2name(hua));
5033 /* Skip file without action */
5034 if (hca.hca_action == HUA_NONE) {
5039 printf(" %s ", hsm_progress_state2name(hps));
5041 if ((hps == HPS_RUNNING) &&
5042 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5043 printf("(%llu bytes moved)\n",
5044 (unsigned long long)he.length);
5045 else if ((he.offset + he.length) == LUSTRE_EOF)
5046 printf("(from %llu to EOF)\n",
5047 (unsigned long long)he.offset);
5049 printf("(from %llu to %llu)\n",
5050 (unsigned long long)he.offset,
5051 (unsigned long long)(he.offset + he.length));
5053 } while (++i < argc);
5058 static int lfs_hsm_set(int argc, char **argv)
5060 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5063 static int lfs_hsm_clear(int argc, char **argv)
5065 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5069 * Check file state and return its fid, to be used by lfs_hsm_request().
5071 * \param[in] file Path to file to check
5072 * \param[in,out] fid Pointer to allocated lu_fid struct.
5073 * \param[in,out] last_dev Pointer to last device id used.
5075 * \return 0 on success.
5077 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5083 rc = lstat(file, &st);
5085 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5088 /* Checking for regular file as archiving as posix copytool
5089 * rejects archiving files other than regular files
5091 if (!S_ISREG(st.st_mode)) {
5092 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5095 /* A request should be ... */
5096 if (*last_dev != st.st_dev && *last_dev != 0) {
5097 fprintf(stderr, "All files should be "
5098 "on the same filesystem: %s\n", file);
5101 *last_dev = st.st_dev;
5103 rc = llapi_path2fid(file, fid);
5105 fprintf(stderr, "Cannot read FID of %s: %s\n",
5106 file, strerror(-rc));
5112 /* Fill an HSM HUR item with a given file name.
5114 * If mntpath is set, then the filename is actually a FID, and no
5115 * lookup on the filesystem will be performed.
5117 * \param[in] hur the user request to fill
5118 * \param[in] idx index of the item inside the HUR to fill
5119 * \param[in] mntpath mountpoint of Lustre
5120 * \param[in] fname filename (if mtnpath is NULL)
5121 * or FID (if mntpath is set)
5122 * \param[in] last_dev pointer to last device id used
5124 * \retval 0 on success
5125 * \retval CMD_HELP or a negative errno on error
5127 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5128 const char *mntpath, const char *fname,
5131 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5134 hui->hui_extent.length = -1;
5136 if (mntpath != NULL) {
5139 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5143 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5148 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5152 hur->hur_request.hr_itemcount++;
5157 static int lfs_hsm_request(int argc, char **argv, int action)
5159 struct option long_opts[] = {
5160 {"filelist", 1, 0, 'l'},
5161 {"data", 1, 0, 'D'},
5162 {"archive", 1, 0, 'a'},
5163 {"mntpath", 1, 0, 'm'},
5167 char short_opts[] = "l:D:a:m:";
5168 struct hsm_user_request *hur, *oldhur;
5173 char *filelist = NULL;
5174 char fullpath[PATH_MAX];
5175 char *opaque = NULL;
5179 int nbfile_alloc = 0;
5180 char *some_file = NULL;
5181 char *mntpath = NULL;
5187 while ((c = getopt_long(argc, argv, short_opts,
5188 long_opts, NULL)) != -1) {
5197 if (action != HUA_ARCHIVE &&
5198 action != HUA_REMOVE) {
5200 "error: -a is supported only "
5201 "when archiving or removing\n");
5204 archive_id = atoi(optarg);
5207 if (some_file == NULL) {
5209 some_file = strdup(optarg);
5215 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5216 argv[0], argv[optind - 1]);
5221 /* All remaining args are files, so we have at least nbfile */
5222 nbfile = argc - optind;
5224 if ((nbfile == 0) && (filelist == NULL))
5228 opaque_len = strlen(opaque);
5230 /* Alloc the request structure with enough place to store all files
5231 * from command line. */
5232 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5234 fprintf(stderr, "Cannot create the request: %s\n",
5238 nbfile_alloc = nbfile;
5240 hur->hur_request.hr_action = action;
5241 hur->hur_request.hr_archive_id = archive_id;
5242 hur->hur_request.hr_flags = 0;
5244 /* All remaining args are files, add them */
5245 if (nbfile != 0 && some_file == NULL)
5246 some_file = strdup(argv[optind]);
5248 for (i = 0; i < nbfile; i++) {
5249 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5255 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5257 /* If a filelist was specified, read the filelist from it. */
5258 if (filelist != NULL) {
5259 fp = fopen(filelist, "r");
5261 fprintf(stderr, "Cannot read the file list %s: %s\n",
5262 filelist, strerror(errno));
5267 while ((rc = getline(&line, &len, fp)) != -1) {
5268 /* If allocated buffer was too small, get something
5270 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5273 nbfile_alloc = nbfile_alloc * 2 + 1;
5275 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5278 fprintf(stderr, "hsm: cannot allocate "
5279 "the request: %s\n",
5286 size = hur_len(oldhur);
5288 fprintf(stderr, "hsm: cannot allocate "
5289 "%u files + %u bytes data\n",
5290 oldhur->hur_request.hr_itemcount,
5291 oldhur->hur_request.hr_data_len);
5298 memcpy(hur, oldhur, size);
5303 if (line[strlen(line) - 1] == '\n')
5304 line[strlen(line) - 1] = '\0';
5306 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5307 mntpath, line, &last_dev);
5313 if (some_file == NULL) {
5323 /* If a --data was used, add it to the request */
5324 hur->hur_request.hr_data_len = opaque_len;
5326 memcpy(hur_data(hur), opaque, opaque_len);
5328 /* Send the HSM request */
5329 if (realpath(some_file, fullpath) == NULL) {
5330 fprintf(stderr, "Could not find path '%s': %s\n",
5331 some_file, strerror(errno));
5333 rc = llapi_hsm_request(fullpath, hur);
5335 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5336 some_file, strerror(-rc));
5346 static int lfs_hsm_archive(int argc, char **argv)
5348 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5351 static int lfs_hsm_restore(int argc, char **argv)
5353 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5356 static int lfs_hsm_release(int argc, char **argv)
5358 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5361 static int lfs_hsm_remove(int argc, char **argv)
5363 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5366 static int lfs_hsm_cancel(int argc, char **argv)
5368 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5371 static int lfs_swap_layouts(int argc, char **argv)
5376 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5377 SWAP_LAYOUTS_KEEP_MTIME |
5378 SWAP_LAYOUTS_KEEP_ATIME);
5381 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5383 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5385 enum lu_ladvise_type advice;
5388 advice < ARRAY_SIZE(ladvise_names); advice++) {
5389 if (ladvise_names[advice] == NULL)
5391 if (strcmp(string, ladvise_names[advice]) == 0)
5395 return LU_LADVISE_INVALID;
5398 static int lfs_ladvise(int argc, char **argv)
5400 struct option long_opts[] = {
5401 {"advice", required_argument, 0, 'a'},
5402 {"background", no_argument, 0, 'b'},
5403 {"end", required_argument, 0, 'e'},
5404 {"start", required_argument, 0, 's'},
5405 {"length", required_argument, 0, 'l'},
5408 char short_opts[] = "a:be:l:s:";
5413 struct llapi_lu_ladvise advice;
5414 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5415 unsigned long long start = 0;
5416 unsigned long long end = LUSTRE_EOF;
5417 unsigned long long length = 0;
5418 unsigned long long size_units;
5419 unsigned long long flags = 0;
5422 while ((c = getopt_long(argc, argv, short_opts,
5423 long_opts, NULL)) != -1) {
5426 advice_type = lfs_get_ladvice(optarg);
5427 if (advice_type == LU_LADVISE_INVALID) {
5428 fprintf(stderr, "%s: invalid advice type "
5429 "'%s'\n", argv[0], optarg);
5430 fprintf(stderr, "Valid types:");
5432 for (advice_type = 0;
5433 advice_type < ARRAY_SIZE(ladvise_names);
5435 if (ladvise_names[advice_type] == NULL)
5437 fprintf(stderr, " %s",
5438 ladvise_names[advice_type]);
5440 fprintf(stderr, "\n");
5450 rc = llapi_parse_size(optarg, &end,
5453 fprintf(stderr, "%s: bad end offset '%s'\n",
5460 rc = llapi_parse_size(optarg, &start,
5463 fprintf(stderr, "%s: bad start offset "
5464 "'%s'\n", argv[0], optarg);
5470 rc = llapi_parse_size(optarg, &length,
5473 fprintf(stderr, "%s: bad length '%s'\n",
5481 fprintf(stderr, "%s: option '%s' unrecognized\n",
5482 argv[0], argv[optind - 1]);
5487 if (advice_type == LU_LADVISE_INVALID) {
5488 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5489 fprintf(stderr, "Valid types:");
5490 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5492 if (ladvise_names[advice_type] == NULL)
5494 fprintf(stderr, " %s", ladvise_names[advice_type]);
5496 fprintf(stderr, "\n");
5500 if (argc <= optind) {
5501 fprintf(stderr, "%s: please give one or more file names\n",
5506 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5507 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5512 if (end == LUSTRE_EOF && length != 0)
5513 end = start + length;
5516 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5517 argv[0], start, end);
5521 while (optind < argc) {
5524 path = argv[optind++];
5526 fd = open(path, O_RDONLY);
5528 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5529 argv[0], path, strerror(errno));
5534 advice.lla_start = start;
5535 advice.lla_end = end;
5536 advice.lla_advice = advice_type;
5537 advice.lla_value1 = 0;
5538 advice.lla_value2 = 0;
5539 advice.lla_value3 = 0;
5540 advice.lla_value4 = 0;
5541 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5544 fprintf(stderr, "%s: cannot give advice '%s' to file "
5545 "'%s': %s\n", argv[0],
5546 ladvise_names[advice_type],
5547 path, strerror(errno));
5550 if (rc == 0 && rc2 < 0)
5556 static int lfs_list_commands(int argc, char **argv)
5558 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5560 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5565 int main(int argc, char **argv)
5569 /* Ensure that liblustreapi constructor has run */
5570 if (!liblustreapi_initialized)
5571 fprintf(stderr, "liblustreapi was not properly initialized\n");
5575 Parser_init("lfs > ", cmdlist);
5577 progname = argv[0]; /* Used in error messages */
5579 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5581 rc = Parser_commands();
5584 return rc < 0 ? -rc : rc;
5587 #ifdef _LUSTRE_IDL_H_
5588 /* Everything we need here should be included by lustreapi.h. */
5589 # error "lfs should not depend on lustre_idl.h"
5590 #endif /* _LUSTRE_IDL_H_ */