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) {
1678 "error: %s: Directory migration unsafe in Lustre 2.10. "
1679 "See https://jira.whamcloud.com/browse/LU-11481\n",
1683 /* initialize migrate mdt parameters */
1684 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1686 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1687 argv[0], mdt_idx_arg);
1690 migrate_mdt_param.fp_migrate = 1;
1691 } else if (layout == NULL) {
1692 /* initialize stripe parameters */
1693 param = calloc(1, offsetof(typeof(*param),
1694 lsp_osts[lsa.lsa_nr_osts]));
1695 if (param == NULL) {
1696 fprintf(stderr, "error: %s: %s\n", argv[0],
1701 param->lsp_stripe_size = lsa.lsa_stripe_size;
1702 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1703 param->lsp_stripe_count = lsa.lsa_stripe_count;
1704 param->lsp_stripe_pattern = 0;
1705 param->lsp_pool = lsa.lsa_pool_name;
1706 param->lsp_is_specific = false;
1707 if (lsa.lsa_nr_osts > 0) {
1708 if (lsa.lsa_stripe_count > 0 &&
1709 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1710 fprintf(stderr, "error: %s: stripe count '%d' "
1711 "doesn't match the number of OSTs: %d\n"
1712 , argv[0], lsa.lsa_stripe_count,
1718 param->lsp_is_specific = true;
1719 param->lsp_stripe_count = lsa.lsa_nr_osts;
1720 memcpy(param->lsp_osts, osts,
1721 sizeof(*osts) * lsa.lsa_nr_osts);
1725 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1727 if (mdt_idx_arg != NULL) {
1728 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1729 op = "migrate mdt objects of";
1730 } else if (migrate_mode) {
1731 result = lfs_migrate(fname, migration_flags, param,
1733 op = "migrate ost objects of";
1734 } else if (comp_set != 0) {
1735 result = lfs_component_set(fname, comp_id,
1736 lsa.lsa_comp_flags);
1737 op = "modify component flags of";
1738 } else if (comp_del != 0) {
1739 result = lfs_component_del(fname, comp_id,
1740 lsa.lsa_comp_flags);
1741 op = "delete component of";
1742 } else if (comp_add != 0) {
1743 result = lfs_component_add(fname, layout);
1744 op = "add component to";
1745 } else if (layout != NULL) {
1746 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1752 op = "create composite";
1754 result = llapi_file_open_param(fname,
1761 op = "create striped";
1764 /* Save the first error encountered. */
1767 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1769 lsa.lsa_pool_name != NULL && result == EINVAL ?
1770 "OST not in pool?" : strerror(errno));
1776 llapi_layout_free(layout);
1779 llapi_layout_free(layout);
1783 static int lfs_poollist(int argc, char **argv)
1788 return llapi_poollist(argv[1]);
1791 static int set_time(time_t *time, time_t *set, char *str)
1798 else if (str[0] == '-')
1804 t = strtol(str, NULL, 0);
1805 if (*time < t * 24 * 60 * 60) {
1808 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1812 *set = *time - t * 24 * 60 * 60;
1815 static int name2uid(unsigned int *id, const char *name)
1817 struct passwd *passwd;
1819 passwd = getpwnam(name);
1822 *id = passwd->pw_uid;
1827 static int name2gid(unsigned int *id, const char *name)
1829 struct group *group;
1831 group = getgrnam(name);
1834 *id = group->gr_gid;
1839 static inline int name2projid(unsigned int *id, const char *name)
1844 static int uid2name(char **name, unsigned int id)
1846 struct passwd *passwd;
1848 passwd = getpwuid(id);
1851 *name = passwd->pw_name;
1856 static inline int gid2name(char **name, unsigned int id)
1858 struct group *group;
1860 group = getgrgid(id);
1863 *name = group->gr_name;
1868 static int name2layout(__u32 *layout, char *name)
1873 for (ptr = name; ; ptr = NULL) {
1874 lyt = strtok(ptr, ",");
1877 if (strcmp(lyt, "released") == 0)
1878 *layout |= LOV_PATTERN_F_RELEASED;
1879 else if (strcmp(lyt, "raid0") == 0)
1880 *layout |= LOV_PATTERN_RAID0;
1887 static int lfs_find(int argc, char **argv)
1892 struct find_param param = {
1896 struct option long_opts[] = {
1897 {"atime", required_argument, 0, 'A'},
1898 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1899 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1900 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1901 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1902 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1903 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1904 {"stripe-count", required_argument, 0, 'c'},
1905 {"stripe_count", required_argument, 0, 'c'},
1906 {"ctime", required_argument, 0, 'C'},
1907 {"maxdepth", required_argument, 0, 'D'},
1908 {"comp-end", required_argument, 0, 'E'},
1909 {"component-end", required_argument, 0, 'E'},
1910 {"gid", required_argument, 0, 'g'},
1911 {"group", required_argument, 0, 'G'},
1912 {"mdt-hash", required_argument, 0, 'H'},
1913 {"stripe-index", required_argument, 0, 'i'},
1914 {"stripe_index", required_argument, 0, 'i'},
1915 /*{"component-id", required_argument, 0, 'I'},*/
1916 {"layout", required_argument, 0, 'L'},
1917 {"mdt", required_argument, 0, 'm'},
1918 {"mdt-index", required_argument, 0, 'm'},
1919 {"mdt_index", required_argument, 0, 'm'},
1920 {"mtime", required_argument, 0, 'M'},
1921 {"name", required_argument, 0, 'n'},
1922 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1923 {"obd", required_argument, 0, 'O'},
1924 {"ost", required_argument, 0, 'O'},
1925 /* no short option for pool, p/P already used */
1926 {"pool", required_argument, 0, LFS_POOL_OPT},
1927 {"print0", no_argument, 0, 'p'},
1928 {"print", no_argument, 0, 'P'},
1929 {"projid", required_argument, 0, LFS_PROJID_OPT},
1930 {"size", required_argument, 0, 's'},
1931 {"stripe-size", required_argument, 0, 'S'},
1932 {"stripe_size", required_argument, 0, 'S'},
1933 {"type", required_argument, 0, 't'},
1934 {"mdt-count", required_argument, 0, 'T'},
1935 {"uid", required_argument, 0, 'u'},
1936 {"user", required_argument, 0, 'U'},
1949 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1950 while ((c = getopt_long_only(argc, argv,
1951 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1952 long_opts, NULL)) >= 0) {
1957 /* '!' is part of option */
1958 /* when getopt_long_only() finds a string which is not
1959 * an option nor a known option argument it returns 1
1960 * in that case if we already have found pathstart and pathend
1961 * (i.e. we have the list of pathnames),
1962 * the only supported value is "!"
1964 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1965 if (!isoption && pathend != -1) {
1966 fprintf(stderr, "err: %s: filename|dirname must either "
1967 "precede options or follow options\n",
1972 if (!isoption && pathstart == -1)
1973 pathstart = optind - 1;
1974 if (isoption && pathstart != -1 && pathend == -1)
1975 pathend = optind - 2;
1981 /* unknown; opt is "!" or path component,
1982 * checking done above.
1984 if (strcmp(optarg, "!") == 0)
1988 xtime = ¶m.fp_atime;
1989 xsign = ¶m.fp_asign;
1990 param.fp_exclude_atime = !!neg_opt;
1991 /* no break, this falls through to 'C' for ctime */
1994 xtime = ¶m.fp_ctime;
1995 xsign = ¶m.fp_csign;
1996 param.fp_exclude_ctime = !!neg_opt;
1998 /* no break, this falls through to 'M' for mtime */
2001 xtime = ¶m.fp_mtime;
2002 xsign = ¶m.fp_msign;
2003 param.fp_exclude_mtime = !!neg_opt;
2005 rc = set_time(&t, xtime, optarg);
2006 if (rc == INT_MAX) {
2013 case LFS_COMP_COUNT_OPT:
2014 if (optarg[0] == '+') {
2015 param.fp_comp_count_sign = -1;
2017 } else if (optarg[0] == '-') {
2018 param.fp_comp_count_sign = 1;
2022 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2023 if (*endptr != '\0') {
2024 fprintf(stderr, "error: bad component count "
2028 param.fp_check_comp_count = 1;
2029 param.fp_exclude_comp_count = !!neg_opt;
2031 case LFS_COMP_FLAGS_OPT:
2032 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2033 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2034 fprintf(stderr, "error: bad component flags "
2038 param.fp_check_comp_flags = 1;
2039 param.fp_exclude_comp_flags = !!neg_opt;
2041 case LFS_COMP_START_OPT:
2042 if (optarg[0] == '+') {
2043 param.fp_comp_start_sign = -1;
2045 } else if (optarg[0] == '-') {
2046 param.fp_comp_start_sign = 1;
2050 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2051 ¶m.fp_comp_start_units, 0);
2053 fprintf(stderr, "error: bad component start "
2057 param.fp_check_comp_start = 1;
2058 param.fp_exclude_comp_start = !!neg_opt;
2061 if (optarg[0] == '+') {
2062 param.fp_stripe_count_sign = -1;
2064 } else if (optarg[0] == '-') {
2065 param.fp_stripe_count_sign = 1;
2069 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2070 if (*endptr != '\0') {
2071 fprintf(stderr,"error: bad stripe_count '%s'\n",
2076 param.fp_check_stripe_count = 1;
2077 param.fp_exclude_stripe_count = !!neg_opt;
2080 param.fp_max_depth = strtol(optarg, 0, 0);
2083 if (optarg[0] == '+') {
2084 param.fp_comp_end_sign = -1;
2086 } else if (optarg[0] == '-') {
2087 param.fp_comp_end_sign = 1;
2091 if (arg_is_eof(optarg)) {
2092 param.fp_comp_end = LUSTRE_EOF;
2093 param.fp_comp_end_units = 1;
2096 rc = llapi_parse_size(optarg,
2098 ¶m.fp_comp_end_units, 0);
2101 fprintf(stderr, "error: bad component end "
2105 param.fp_check_comp_end = 1;
2106 param.fp_exclude_comp_end = !!neg_opt;
2110 rc = name2gid(¶m.fp_gid, optarg);
2112 param.fp_gid = strtoul(optarg, &endptr, 10);
2113 if (*endptr != '\0') {
2114 fprintf(stderr, "Group/GID: %s cannot "
2115 "be found.\n", optarg);
2120 param.fp_exclude_gid = !!neg_opt;
2121 param.fp_check_gid = 1;
2124 param.fp_hash_type = check_hashtype(optarg);
2125 if (param.fp_hash_type == 0) {
2126 fprintf(stderr, "error: bad hash_type '%s'\n",
2131 param.fp_check_hash_type = 1;
2132 param.fp_exclude_hash_type = !!neg_opt;
2135 ret = name2layout(¶m.fp_layout, optarg);
2138 param.fp_exclude_layout = !!neg_opt;
2139 param.fp_check_layout = 1;
2143 rc = name2uid(¶m.fp_uid, optarg);
2145 param.fp_uid = strtoul(optarg, &endptr, 10);
2146 if (*endptr != '\0') {
2147 fprintf(stderr, "User/UID: %s cannot "
2148 "be found.\n", optarg);
2153 param.fp_exclude_uid = !!neg_opt;
2154 param.fp_check_uid = 1;
2157 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2159 "Pool name %s is too long"
2160 " (max is %d)\n", optarg,
2165 /* we do check for empty pool because empty pool
2166 * is used to find V1 lov attributes */
2167 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2168 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2169 param.fp_exclude_pool = !!neg_opt;
2170 param.fp_check_pool = 1;
2173 param.fp_pattern = (char *)optarg;
2174 param.fp_exclude_pattern = !!neg_opt;
2179 char *buf, *token, *next, *p;
2183 buf = strdup(optarg);
2189 param.fp_exclude_obd = !!neg_opt;
2192 while (token && *token) {
2193 token = strchr(token, ',');
2200 param.fp_exclude_mdt = !!neg_opt;
2201 param.fp_num_alloc_mdts += len;
2202 tmp = realloc(param.fp_mdt_uuid,
2203 param.fp_num_alloc_mdts *
2204 sizeof(*param.fp_mdt_uuid));
2210 param.fp_mdt_uuid = tmp;
2212 param.fp_exclude_obd = !!neg_opt;
2213 param.fp_num_alloc_obds += len;
2214 tmp = realloc(param.fp_obd_uuid,
2215 param.fp_num_alloc_obds *
2216 sizeof(*param.fp_obd_uuid));
2222 param.fp_obd_uuid = tmp;
2224 for (token = buf; token && *token; token = next) {
2225 struct obd_uuid *puuid;
2228 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2231 ¶m.fp_obd_uuid[param.fp_num_obds++];
2233 p = strchr(token, ',');
2240 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2245 strncpy(puuid->uuid, token,
2246 sizeof(puuid->uuid));
2254 param.fp_zero_end = 1;
2258 case LFS_PROJID_OPT:
2259 rc = name2projid(¶m.fp_projid, optarg);
2261 param.fp_projid = strtoul(optarg, &endptr, 10);
2262 if (*endptr != '\0') {
2264 "Invalid project ID: %s",
2270 param.fp_exclude_projid = !!neg_opt;
2271 param.fp_check_projid = 1;
2274 if (optarg[0] == '+') {
2275 param.fp_size_sign = -1;
2277 } else if (optarg[0] == '-') {
2278 param.fp_size_sign = 1;
2282 ret = llapi_parse_size(optarg, ¶m.fp_size,
2283 ¶m.fp_size_units, 0);
2285 fprintf(stderr, "error: bad file size '%s'\n",
2289 param.fp_check_size = 1;
2290 param.fp_exclude_size = !!neg_opt;
2293 if (optarg[0] == '+') {
2294 param.fp_stripe_size_sign = -1;
2296 } else if (optarg[0] == '-') {
2297 param.fp_stripe_size_sign = 1;
2301 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2302 ¶m.fp_stripe_size_units, 0);
2304 fprintf(stderr, "error: bad stripe_size '%s'\n",
2308 param.fp_check_stripe_size = 1;
2309 param.fp_exclude_stripe_size = !!neg_opt;
2312 param.fp_exclude_type = !!neg_opt;
2313 switch (optarg[0]) {
2315 param.fp_type = S_IFBLK;
2318 param.fp_type = S_IFCHR;
2321 param.fp_type = S_IFDIR;
2324 param.fp_type = S_IFREG;
2327 param.fp_type = S_IFLNK;
2330 param.fp_type = S_IFIFO;
2333 param.fp_type = S_IFSOCK;
2336 fprintf(stderr, "error: %s: bad type '%s'\n",
2343 if (optarg[0] == '+') {
2344 param.fp_mdt_count_sign = -1;
2346 } else if (optarg[0] == '-') {
2347 param.fp_mdt_count_sign = 1;
2351 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2352 if (*endptr != '\0') {
2353 fprintf(stderr, "error: bad mdt_count '%s'\n",
2358 param.fp_check_mdt_count = 1;
2359 param.fp_exclude_mdt_count = !!neg_opt;
2367 if (pathstart == -1) {
2368 fprintf(stderr, "error: %s: no filename|pathname\n",
2372 } else if (pathend == -1) {
2378 rc = llapi_find(argv[pathstart], ¶m);
2379 if (rc != 0 && ret == 0)
2381 } while (++pathstart < pathend);
2384 fprintf(stderr, "error: %s failed for %s.\n",
2385 argv[0], argv[optind - 1]);
2387 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2388 free(param.fp_obd_uuid);
2390 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2391 free(param.fp_mdt_uuid);
2396 static int lfs_getstripe_internal(int argc, char **argv,
2397 struct find_param *param)
2399 struct option long_opts[] = {
2400 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2401 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2402 {"comp-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2403 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2404 {"comp-start", optional_argument, 0, LFS_COMP_START_OPT},
2405 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2406 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2407 /* This formerly implied "stripe-count", but was explicitly
2408 * made "stripe-count" for consistency with other options,
2409 * and to separate it from "mdt-count" when DNE arrives. */
2410 {"count", no_argument, 0, 'c'},
2412 {"stripe-count", no_argument, 0, 'c'},
2413 {"stripe_count", no_argument, 0, 'c'},
2414 {"directory", no_argument, 0, 'd'},
2415 {"default", no_argument, 0, 'D'},
2416 {"comp-end", optional_argument, 0, 'E'},
2417 {"component-end", optional_argument, 0, 'E'},
2418 {"fid", no_argument, 0, 'F'},
2419 {"generation", no_argument, 0, 'g'},
2420 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2421 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2422 /* This formerly implied "stripe-index", but was explicitly
2423 * made "stripe-index" for consistency with other options,
2424 * and to separate it from "mdt-index" when DNE arrives. */
2425 {"index", no_argument, 0, 'i'},
2427 {"stripe-index", no_argument, 0, 'i'},
2428 {"stripe_index", no_argument, 0, 'i'},
2429 {"comp-id", optional_argument, 0, 'I'},
2430 {"component-id", optional_argument, 0, 'I'},
2431 {"layout", no_argument, 0, 'L'},
2432 {"mdt", no_argument, 0, 'm'},
2433 {"mdt-index", no_argument, 0, 'm'},
2434 {"mdt_index", no_argument, 0, 'm'},
2435 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2436 {"mdt-index", no_argument, 0, 'M'},
2437 {"mdt_index", no_argument, 0, 'M'},
2439 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2440 /* This formerly implied "stripe-index", but was confusing
2441 * with "file offset" (which will eventually be needed for
2442 * with different layouts by offset), so deprecate it. */
2443 {"offset", no_argument, 0, 'o'},
2445 {"obd", required_argument, 0, 'O'},
2446 {"ost", required_argument, 0, 'O'},
2447 {"pool", no_argument, 0, 'p'},
2448 {"quiet", no_argument, 0, 'q'},
2449 {"recursive", no_argument, 0, 'r'},
2450 {"raw", no_argument, 0, 'R'},
2451 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2452 /* This formerly implied "--stripe-size", but was confusing
2453 * with "lfs find --size|-s", which means "file size", so use
2454 * the consistent "--stripe-size|-S" for all commands. */
2455 {"size", no_argument, 0, 's'},
2457 {"stripe-size", no_argument, 0, 'S'},
2458 {"stripe_size", no_argument, 0, 'S'},
2459 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2460 {"verbose", no_argument, 0, 'v'},
2461 {"yaml", no_argument, 0, 'y'},
2467 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2468 long_opts, NULL)) != -1) {
2471 if (strcmp(argv[optind - 1], "--count") == 0)
2472 fprintf(stderr, "warning: '--count' deprecated,"
2473 " use '--stripe-count' instead\n");
2474 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2475 param->fp_verbose |= VERBOSE_COUNT;
2476 param->fp_max_depth = 0;
2479 case LFS_COMP_COUNT_OPT:
2480 param->fp_verbose |= VERBOSE_COMP_COUNT;
2481 param->fp_max_depth = 0;
2483 case LFS_COMP_FLAGS_OPT:
2484 if (optarg != NULL) {
2485 __u32 *flags = ¶m->fp_comp_flags;
2486 rc = comp_str2flags(flags, optarg);
2488 fprintf(stderr, "error: %s bad "
2489 "component flags '%s'.\n",
2493 param->fp_check_comp_flags = 1;
2494 param->fp_exclude_comp_flags =
2495 comp_flags_is_neg(*flags);
2496 comp_flags_clear_neg(flags);
2499 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2500 param->fp_max_depth = 0;
2503 case LFS_COMP_START_OPT:
2504 if (optarg != NULL) {
2506 if (tmp[0] == '+') {
2507 param->fp_comp_start_sign = -1;
2509 } else if (tmp[0] == '-') {
2510 param->fp_comp_start_sign = 1;
2513 rc = llapi_parse_size(tmp,
2514 ¶m->fp_comp_start,
2515 ¶m->fp_comp_start_units, 0);
2517 fprintf(stderr, "error: %s bad "
2518 "component start '%s'.\n",
2522 param->fp_check_comp_start = 1;
2525 param->fp_verbose |= VERBOSE_COMP_START;
2526 param->fp_max_depth = 0;
2530 param->fp_max_depth = 0;
2533 param->fp_get_default_lmv = 1;
2536 if (optarg != NULL) {
2538 if (tmp[0] == '+') {
2539 param->fp_comp_end_sign = -1;
2541 } else if (tmp[0] == '-') {
2542 param->fp_comp_end_sign = 1;
2546 if (arg_is_eof(tmp)) {
2547 param->fp_comp_end = LUSTRE_EOF;
2548 param->fp_comp_end_units = 1;
2551 rc = llapi_parse_size(tmp,
2552 ¶m->fp_comp_end,
2553 ¶m->fp_comp_end_units, 0);
2556 fprintf(stderr, "error: %s bad "
2557 "component end '%s'.\n",
2561 param->fp_check_comp_end = 1;
2563 param->fp_verbose |= VERBOSE_COMP_END;
2564 param->fp_max_depth = 0;
2568 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2569 param->fp_verbose |= VERBOSE_DFID;
2570 param->fp_max_depth = 0;
2574 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2575 param->fp_verbose |= VERBOSE_GENERATION;
2576 param->fp_max_depth = 0;
2579 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2581 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2582 "use '--stripe-index|-i' instead\n");
2585 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2586 if (strcmp(argv[optind - 1], "--index") == 0)
2587 fprintf(stderr, "warning: '--index' deprecated"
2588 ", use '--stripe-index' instead\n");
2590 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2591 param->fp_verbose |= VERBOSE_OFFSET;
2592 param->fp_max_depth = 0;
2596 if (optarg != NULL) {
2597 param->fp_comp_id = strtoul(optarg, &end, 0);
2598 if (*end != '\0' || param->fp_comp_id == 0 ||
2599 param->fp_comp_id > LCME_ID_MAX) {
2600 fprintf(stderr, "error: %s bad "
2601 "component id '%s'\n",
2605 param->fp_check_comp_id = 1;
2608 param->fp_max_depth = 0;
2609 param->fp_verbose |= VERBOSE_COMP_ID;
2613 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2614 param->fp_verbose |= VERBOSE_LAYOUT;
2615 param->fp_max_depth = 0;
2618 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2620 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2621 fprintf(stderr, "warning: '-M' deprecated"
2622 ", use '-m' instead\n");
2626 if (!(param->fp_verbose & VERBOSE_DETAIL))
2627 param->fp_max_depth = 0;
2628 param->fp_verbose |= VERBOSE_MDTINDEX;
2631 if (param->fp_obd_uuid) {
2633 "error: %s: only one obduuid allowed",
2637 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2640 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2641 param->fp_verbose |= VERBOSE_POOL;
2642 param->fp_max_depth = 0;
2649 param->fp_recursive = 1;
2654 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2656 fprintf(stderr, "warning: '--size|-s' deprecated, "
2657 "use '--stripe-size|-S' instead\n");
2658 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2660 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2661 param->fp_verbose |= VERBOSE_SIZE;
2662 param->fp_max_depth = 0;
2666 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2679 if (param->fp_recursive)
2680 param->fp_max_depth = -1;
2681 else if (param->fp_verbose & VERBOSE_DETAIL)
2682 param->fp_max_depth = 1;
2684 if (!param->fp_verbose)
2685 param->fp_verbose = VERBOSE_DEFAULT;
2686 if (param->fp_quiet)
2687 param->fp_verbose = VERBOSE_OBJID;
2690 rc = llapi_getstripe(argv[optind], param);
2691 } while (++optind < argc && !rc);
2694 fprintf(stderr, "error: %s failed for %s.\n",
2695 argv[0], argv[optind - 1]);
2699 static int lfs_tgts(int argc, char **argv)
2701 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2702 struct find_param param;
2703 int index = 0, rc=0;
2708 if (argc == 2 && !realpath(argv[1], path)) {
2710 fprintf(stderr, "error: invalid path '%s': %s\n",
2711 argv[1], strerror(-rc));
2715 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2716 /* Check if we have a mount point */
2717 if (mntdir[0] == '\0')
2720 memset(¶m, 0, sizeof(param));
2721 if (!strcmp(argv[0], "mdts"))
2722 param.fp_get_lmv = 1;
2724 rc = llapi_ostlist(mntdir, ¶m);
2726 fprintf(stderr, "error: %s: failed on %s\n",
2729 if (path[0] != '\0')
2731 memset(mntdir, 0, PATH_MAX);
2737 static int lfs_getstripe(int argc, char **argv)
2739 struct find_param param = { 0 };
2741 param.fp_max_depth = 1;
2742 return lfs_getstripe_internal(argc, argv, ¶m);
2746 static int lfs_getdirstripe(int argc, char **argv)
2748 struct find_param param = { 0 };
2749 struct option long_opts[] = {
2750 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2751 {"mdt-count", no_argument, 0, 'c'},
2753 {"mdt-hash", no_argument, 0, 'H'},
2754 {"mdt-index", no_argument, 0, 'i'},
2755 {"recursive", no_argument, 0, 'r'},
2756 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2757 {"mdt-hash", no_argument, 0, 't'},
2759 {"default", no_argument, 0, 'D'},
2760 {"obd", required_argument, 0, 'O'},
2761 {"mdt-count", no_argument, 0, 'T'},
2762 {"yaml", no_argument, 0, 'y'},
2767 param.fp_get_lmv = 1;
2769 while ((c = getopt_long(argc, argv,
2770 "cDHiO:rtTy", long_opts, NULL)) != -1)
2774 if (param.fp_obd_uuid) {
2776 "error: %s: only one obduuid allowed",
2780 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2782 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2784 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2785 fprintf(stderr, "warning: '-c' deprecated"
2786 ", use '-T' instead\n");
2790 param.fp_verbose |= VERBOSE_COUNT;
2793 param.fp_verbose |= VERBOSE_OFFSET;
2795 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2799 param.fp_verbose |= VERBOSE_HASH_TYPE;
2802 param.fp_get_default_lmv = 1;
2805 param.fp_recursive = 1;
2818 if (param.fp_recursive)
2819 param.fp_max_depth = -1;
2821 if (!param.fp_verbose)
2822 param.fp_verbose = VERBOSE_DEFAULT;
2825 rc = llapi_getstripe(argv[optind], ¶m);
2826 } while (++optind < argc && !rc);
2829 fprintf(stderr, "error: %s failed for %s.\n",
2830 argv[0], argv[optind - 1]);
2835 static int lfs_setdirstripe(int argc, char **argv)
2839 unsigned int stripe_offset = -1;
2840 unsigned int stripe_count = 1;
2841 enum lmv_hash_type hash_type;
2844 char *stripe_offset_opt = NULL;
2845 char *stripe_count_opt = NULL;
2846 char *stripe_hash_opt = NULL;
2847 char *mode_opt = NULL;
2848 bool default_stripe = false;
2849 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2850 mode_t previous_mode = 0;
2851 bool delete = false;
2853 struct option long_opts[] = {
2854 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2855 { .val = 'c', .name = "count", .has_arg = required_argument },
2857 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2858 { .val = 'd', .name = "delete", .has_arg = no_argument },
2859 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2860 { .val = 'i', .name = "index", .has_arg = required_argument },
2862 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2863 { .val = 'm', .name = "mode", .has_arg = required_argument },
2864 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2865 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2866 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2868 {"mdt-hash", required_argument, 0, 'H'},
2869 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2870 { .val = 'D', .name = "default_stripe",
2871 .has_arg = no_argument },
2873 { .val = 'D', .name = "default", .has_arg = no_argument },
2876 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2883 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2884 if (strcmp(argv[optind - 1], "--count") == 0)
2885 fprintf(stderr, "warning: '--count' deprecated"
2886 ", use '--mdt-count' instead\n");
2888 stripe_count_opt = optarg;
2892 default_stripe = true;
2895 default_stripe = true;
2898 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2899 if (strcmp(argv[optind - 1], "--index") == 0)
2900 fprintf(stderr, "warning: '--index' deprecated"
2901 ", use '--mdt-index' instead\n");
2903 stripe_offset_opt = optarg;
2908 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2912 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2913 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2914 fprintf(stderr, "warning: '--hash-type' "
2915 "deprecated, use '--mdt-hash' "
2918 stripe_hash_opt = optarg;
2921 fprintf(stderr, "error: %s: option '%s' "
2923 argv[0], argv[optind - 1]);
2928 if (optind == argc) {
2929 fprintf(stderr, "error: %s: missing dirname\n",
2934 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2935 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2940 if (stripe_offset_opt != NULL) {
2941 /* get the stripe offset */
2942 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2944 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2945 argv[0], stripe_offset_opt);
2951 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2952 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2953 " or -i options.\n", argv[0]);
2961 if (mode_opt != NULL) {
2962 mode = strtoul(mode_opt, &end, 8);
2964 fprintf(stderr, "error: %s: bad mode '%s'\n",
2968 previous_mode = umask(0);
2971 if (stripe_hash_opt == NULL) {
2972 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2974 hash_type = check_hashtype(stripe_hash_opt);
2975 if (hash_type == 0) {
2977 "error: %s: bad stripe hash type '%s'\n",
2978 argv[0], stripe_hash_opt);
2983 /* get the stripe count */
2984 if (stripe_count_opt != NULL) {
2985 stripe_count = strtoul(stripe_count_opt, &end, 0);
2987 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2988 argv[0], stripe_count_opt);
2993 dname = argv[optind];
2995 if (default_stripe) {
2996 result = llapi_dir_set_default_lmv_stripe(dname,
2997 stripe_offset, stripe_count,
3000 result = llapi_dir_create_pool(dname, mode,
3002 stripe_count, hash_type,
3007 fprintf(stderr, "error: %s: create stripe dir '%s' "
3008 "failed\n", argv[0], dname);
3011 dname = argv[++optind];
3012 } while (dname != NULL);
3014 if (mode_opt != NULL)
3015 umask(previous_mode);
3021 static int lfs_rmentry(int argc, char **argv)
3028 fprintf(stderr, "error: %s: missing dirname\n",
3034 dname = argv[index];
3035 while (dname != NULL) {
3036 result = llapi_direntry_remove(dname);
3038 fprintf(stderr, "error: %s: remove dir entry '%s' "
3039 "failed\n", argv[0], dname);
3042 dname = argv[++index];
3047 static int lfs_mv(int argc, char **argv)
3049 struct find_param param = {
3056 struct option long_opts[] = {
3057 {"mdt-index", required_argument, 0, 'M'},
3058 {"verbose", no_argument, 0, 'v'},
3062 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3065 param.fp_mdt_index = strtoul(optarg, &end, 0);
3067 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3074 param.fp_verbose = VERBOSE_DETAIL;
3078 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3079 argv[0], argv[optind - 1]);
3084 if (param.fp_mdt_index == -1) {
3085 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3089 if (optind >= argc) {
3090 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3094 param.fp_migrate = 1;
3095 rc = llapi_migrate_mdt(argv[optind], ¶m);
3097 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3098 argv[0], argv[optind], param.fp_mdt_index,
3103 static int lfs_osts(int argc, char **argv)
3105 return lfs_tgts(argc, argv);
3108 static int lfs_mdts(int argc, char **argv)
3110 return lfs_tgts(argc, argv);
3113 #define COOK(value) \
3116 while (value > 1024) { \
3124 #define CDF "%11llu"
3125 #define HDF "%8.1f%c"
3130 MNTDF_INODES = 0x0001,
3131 MNTDF_COOKED = 0x0002,
3132 MNTDF_LAZY = 0x0004,
3133 MNTDF_VERBOSE = 0x0008,
3136 static int showdf(char *mntdir, struct obd_statfs *stat,
3137 char *uuid, enum mntdf_flags flags,
3138 char *type, int index, int rc)
3140 long long avail, used, total;
3142 char *suffix = "KMGTPEZY";
3143 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3144 char tbuf[3 * sizeof(__u64)];
3145 char ubuf[3 * sizeof(__u64)];
3146 char abuf[3 * sizeof(__u64)];
3147 char rbuf[3 * sizeof(__u64)];
3154 if (flags & MNTDF_INODES) {
3155 avail = stat->os_ffree;
3156 used = stat->os_files - stat->os_ffree;
3157 total = stat->os_files;
3159 int shift = flags & MNTDF_COOKED ? 0 : 10;
3161 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3162 used = ((stat->os_blocks - stat->os_bfree) *
3163 stat->os_bsize) >> shift;
3164 total = (stat->os_blocks * stat->os_bsize) >> shift;
3167 if ((used + avail) > 0)
3168 ratio = (double)used / (double)(used + avail);
3170 if (flags & MNTDF_COOKED) {
3174 cook_val = (double)total;
3177 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3180 snprintf(tbuf, sizeof(tbuf), CDF, total);
3182 cook_val = (double)used;
3185 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3188 snprintf(ubuf, sizeof(ubuf), CDF, used);
3190 cook_val = (double)avail;
3193 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3196 snprintf(abuf, sizeof(abuf), CDF, avail);
3198 snprintf(tbuf, sizeof(tbuf), CDF, total);
3199 snprintf(ubuf, sizeof(tbuf), CDF, used);
3200 snprintf(abuf, sizeof(tbuf), CDF, avail);
3203 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3204 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3205 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3207 printf("[%s:%d]", type, index);
3209 if (stat->os_state) {
3211 * Each character represents the matching
3214 const char state_names[] = "DRSI";
3219 for (i = 0, state = stat->os_state;
3220 state && i < sizeof(state_names); i++) {
3221 if (!(state & (1 << i)))
3223 printf("%c", state_names[i]);
3231 printf(UUF": inactive device\n", uuid);
3234 printf(UUF": %s\n", uuid, strerror(-rc));
3241 struct ll_stat_type {
3246 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3248 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3249 struct obd_uuid uuid_buf;
3250 char *poolname = NULL;
3251 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3252 { LL_STATFS_LOV, "OST" },
3254 struct ll_stat_type *tp;
3255 __u64 ost_ffree = 0;
3263 poolname = strchr(pool, '.');
3264 if (poolname != NULL) {
3265 if (strncmp(fsname, pool, strlen(fsname))) {
3266 fprintf(stderr, "filesystem name incorrect\n");
3274 fd = open(mntdir, O_RDONLY);
3277 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3282 if (flags & MNTDF_INODES)
3283 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3284 "UUID", "Inodes", "IUsed", "IFree",
3285 "IUse%", "Mounted on");
3287 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3288 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3289 "Used", "Available", "Use%", "Mounted on");
3291 for (tp = types; tp->st_name != NULL; tp++) {
3292 for (index = 0; ; index++) {
3293 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3294 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3295 type = flags & MNTDF_LAZY ?
3296 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3297 rc2 = llapi_obd_fstatfs(fd, type, index,
3298 &stat_buf, &uuid_buf);
3303 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3304 if (!(flags & MNTDF_VERBOSE))
3306 } else if (rc2 < 0 && rc == 0) {
3310 if (poolname && tp->st_op == LL_STATFS_LOV &&
3311 llapi_search_ost(fsname, poolname,
3312 obd_uuid2str(&uuid_buf)) != 1)
3315 /* the llapi_obd_statfs() call may have returned with
3316 * an error, but if it filled in uuid_buf we will at
3317 * lease use that to print out a message for that OBD.
3318 * If we didn't get anything in the uuid_buf, then fill
3319 * it in so that we can print an error message. */
3320 if (uuid_buf.uuid[0] == '\0')
3321 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3322 "%s%04x", tp->st_name, index);
3323 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3324 flags, tp->st_name, index, rc2);
3327 if (tp->st_op == LL_STATFS_LMV) {
3328 sum.os_ffree += stat_buf.os_ffree;
3329 sum.os_files += stat_buf.os_files;
3330 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3331 sum.os_blocks += stat_buf.os_blocks *
3333 sum.os_bfree += stat_buf.os_bfree *
3335 sum.os_bavail += stat_buf.os_bavail *
3337 ost_ffree += stat_buf.os_ffree;
3345 /* If we don't have as many objects free on the OST as inodes
3346 * on the MDS, we reduce the total number of inodes to
3347 * compensate, so that the "inodes in use" number is correct.
3348 * Matches ll_statfs_internal() so the results are consistent. */
3349 if (ost_ffree < sum.os_ffree) {
3350 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3351 sum.os_ffree = ost_ffree;
3354 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3360 static int lfs_df(int argc, char **argv)
3362 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3363 enum mntdf_flags flags = 0;
3364 int c, rc = 0, index = 0;
3365 char fsname[PATH_MAX] = "", *pool_name = NULL;
3366 struct option long_opts[] = {
3367 { .val = 'h', .name = "human-readable",
3368 .has_arg = no_argument },
3369 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3370 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3371 { .val = 'p', .name = "pool", .has_arg = required_argument },
3372 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3375 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3378 flags |= MNTDF_COOKED;
3381 flags |= MNTDF_INODES;
3384 flags |= MNTDF_LAZY;
3390 flags |= MNTDF_VERBOSE;
3396 if (optind < argc && !realpath(argv[optind], path)) {
3398 fprintf(stderr, "error: invalid path '%s': %s\n",
3399 argv[optind], strerror(-rc));
3403 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3404 /* Check if we have a mount point */
3405 if (mntdir[0] == '\0')
3408 rc = mntdf(mntdir, fsname, pool_name, flags);
3409 if (rc || path[0] != '\0')
3411 fsname[0] = '\0'; /* avoid matching in next loop */
3412 mntdir[0] = '\0'; /* avoid matching in next loop */
3418 static int lfs_getname(int argc, char **argv)
3420 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3421 int rc = 0, index = 0, c;
3422 char buf[sizeof(struct obd_uuid)];
3424 while ((c = getopt(argc, argv, "h")) != -1)
3427 if (optind == argc) { /* no paths specified, get all paths. */
3428 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3429 rc = llapi_getname(mntdir, buf, sizeof(buf));
3432 "cannot get name for `%s': %s\n",
3433 mntdir, strerror(-rc));
3437 printf("%s %s\n", buf, mntdir);
3439 path[0] = fsname[0] = mntdir[0] = 0;
3441 } else { /* paths specified, only attempt to search these. */
3442 for (; optind < argc; optind++) {
3443 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3446 "cannot get name for `%s': %s\n",
3447 argv[optind], strerror(-rc));
3451 printf("%s %s\n", buf, argv[optind]);
3457 static int lfs_check(int argc, char **argv)
3460 char mntdir[PATH_MAX] = {'\0'};
3469 obd_types[0] = obd_type1;
3470 obd_types[1] = obd_type2;
3472 if (strcmp(argv[1], "osts") == 0) {
3473 strcpy(obd_types[0], "osc");
3474 } else if (strcmp(argv[1], "mds") == 0) {
3475 strcpy(obd_types[0], "mdc");
3476 } else if (strcmp(argv[1], "servers") == 0) {
3478 strcpy(obd_types[0], "osc");
3479 strcpy(obd_types[1], "mdc");
3481 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3486 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3487 if (rc < 0 || mntdir[0] == '\0') {
3488 fprintf(stderr, "No suitable Lustre mount found\n");
3492 rc = llapi_target_check(num_types, obd_types, mntdir);
3494 fprintf(stderr, "error: %s: %s status failed\n",
3501 #ifdef HAVE_SYS_QUOTA_H
3502 #define ARG2INT(nr, str, msg) \
3505 nr = strtol(str, &endp, 0); \
3507 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3512 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3514 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3515 * returns the value or ULONG_MAX on integer overflow or incorrect format
3517 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3518 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3519 * 3. empty integer value is interpreted as 0
3521 static unsigned long str2sec(const char* timestr)
3523 const char spec[] = "smhdw";
3524 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3525 unsigned long val = 0;
3528 if (strpbrk(timestr, spec) == NULL) {
3529 /* no specifiers inside the time string,
3530 should treat it as an integer value */
3531 val = strtoul(timestr, &tail, 10);
3532 return *tail ? ULONG_MAX : val;
3535 /* format string is XXwXXdXXhXXmXXs */
3541 v = strtoul(timestr, &tail, 10);
3542 if (v == ULONG_MAX || *tail == '\0')
3543 /* value too large (ULONG_MAX or more)
3544 or missing specifier */
3547 ptr = strchr(spec, *tail);
3549 /* unknown specifier */
3554 /* check if product will overflow the type */
3555 if (!(v < ULONG_MAX / mult[ind]))
3558 ADD_OVERFLOW(val, mult[ind] * v);
3559 if (val == ULONG_MAX)
3571 #define ARG2ULL(nr, str, def_units) \
3573 unsigned long long limit, units = def_units; \
3576 rc = llapi_parse_size(str, &limit, &units, 1); \
3578 fprintf(stderr, "error: bad limit value %s\n", str); \
3584 static inline int has_times_option(int argc, char **argv)
3588 for (i = 1; i < argc; i++)
3589 if (!strcmp(argv[i], "-t"))
3595 int lfs_setquota_times(int argc, char **argv)
3598 struct if_quotactl qctl;
3599 char *mnt, *obd_type = (char *)qctl.obd_type;
3600 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3601 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3602 struct option long_opts[] = {
3603 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3604 { .val = 'g', .name = "group", .has_arg = no_argument },
3605 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3606 { .val = 'p', .name = "projid", .has_arg = no_argument },
3607 { .val = 't', .name = "times", .has_arg = no_argument },
3608 { .val = 'u', .name = "user", .has_arg = no_argument },
3612 memset(&qctl, 0, sizeof(qctl));
3613 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3614 qctl.qc_type = ALLQUOTA;
3616 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3617 long_opts, NULL)) != -1) {
3628 if (qctl.qc_type != ALLQUOTA) {
3629 fprintf(stderr, "error: -u/g/p can't be used "
3630 "more than once\n");
3633 qctl.qc_type = qtype;
3636 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3637 fprintf(stderr, "error: bad block-grace: %s\n",
3641 dqb->dqb_valid |= QIF_BTIME;
3644 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3645 fprintf(stderr, "error: bad inode-grace: %s\n",
3649 dqb->dqb_valid |= QIF_ITIME;
3651 case 't': /* Yes, of course! */
3653 default: /* getopt prints error message for us when opterr != 0 */
3658 if (qctl.qc_type == ALLQUOTA) {
3659 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3663 if (optind != argc - 1) {
3664 fprintf(stderr, "error: unexpected parameters encountered\n");
3669 rc = llapi_quotactl(mnt, &qctl);
3672 fprintf(stderr, "%s %s ", obd_type,
3673 obd_uuid2str(&qctl.obd_uuid));
3674 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3681 #define BSLIMIT (1 << 0)
3682 #define BHLIMIT (1 << 1)
3683 #define ISLIMIT (1 << 2)
3684 #define IHLIMIT (1 << 3)
3686 int lfs_setquota(int argc, char **argv)
3689 struct if_quotactl qctl;
3690 char *mnt, *obd_type = (char *)qctl.obd_type;
3691 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3692 struct option long_opts[] = {
3693 {"block-softlimit", required_argument, 0, 'b'},
3694 {"block-hardlimit", required_argument, 0, 'B'},
3695 {"group", required_argument, 0, 'g'},
3696 {"inode-softlimit", required_argument, 0, 'i'},
3697 {"inode-hardlimit", required_argument, 0, 'I'},
3698 {"user", required_argument, 0, 'u'},
3699 {"projid", required_argument, 0, 'p'},
3702 unsigned limit_mask = 0;
3706 if (has_times_option(argc, argv))
3707 return lfs_setquota_times(argc, argv);
3709 memset(&qctl, 0, sizeof(qctl));
3710 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3711 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3712 * so it can be used as a marker that qc_type
3713 * isn't reinitialized from command line */
3715 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3716 long_opts, NULL)) != -1) {
3720 rc = name2uid(&qctl.qc_id, optarg);
3724 rc = name2gid(&qctl.qc_id, optarg);
3728 rc = name2projid(&qctl.qc_id, optarg);
3730 if (qctl.qc_type != ALLQUOTA) {
3731 fprintf(stderr, "error: -u and -g can't be used"
3732 " more than once\n");
3735 qctl.qc_type = qtype;
3737 qctl.qc_id = strtoul(optarg, &endptr, 10);
3738 if (*endptr != '\0') {
3739 fprintf(stderr, "error: can't find id "
3740 "for name %s\n", optarg);
3746 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3747 dqb->dqb_bsoftlimit >>= 10;
3748 limit_mask |= BSLIMIT;
3749 if (dqb->dqb_bsoftlimit &&
3750 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3751 fprintf(stderr, "warning: block softlimit is "
3752 "smaller than the miminal qunit size, "
3753 "please see the help of setquota or "
3754 "Lustre manual for details.\n");
3757 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3758 dqb->dqb_bhardlimit >>= 10;
3759 limit_mask |= BHLIMIT;
3760 if (dqb->dqb_bhardlimit &&
3761 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3762 fprintf(stderr, "warning: block hardlimit is "
3763 "smaller than the miminal qunit size, "
3764 "please see the help of setquota or "
3765 "Lustre manual for details.\n");
3768 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3769 limit_mask |= ISLIMIT;
3770 if (dqb->dqb_isoftlimit &&
3771 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3772 fprintf(stderr, "warning: inode softlimit is "
3773 "smaller than the miminal qunit size, "
3774 "please see the help of setquota or "
3775 "Lustre manual for details.\n");
3778 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3779 limit_mask |= IHLIMIT;
3780 if (dqb->dqb_ihardlimit &&
3781 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3782 fprintf(stderr, "warning: inode hardlimit is "
3783 "smaller than the miminal qunit size, "
3784 "please see the help of setquota or "
3785 "Lustre manual for details.\n");
3787 default: /* getopt prints error message for us when opterr != 0 */
3792 if (qctl.qc_type == ALLQUOTA) {
3793 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3797 if (limit_mask == 0) {
3798 fprintf(stderr, "error: at least one limit must be specified\n");
3802 if (optind != argc - 1) {
3803 fprintf(stderr, "error: unexpected parameters encountered\n");
3809 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3810 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3811 /* sigh, we can't just set blimits/ilimits */
3812 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3813 .qc_type = qctl.qc_type,
3814 .qc_id = qctl.qc_id};
3816 rc = llapi_quotactl(mnt, &tmp_qctl);
3818 fprintf(stderr, "error: setquota failed while retrieving"
3819 " current quota settings (%s)\n",
3824 if (!(limit_mask & BHLIMIT))
3825 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3826 if (!(limit_mask & BSLIMIT))
3827 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3828 if (!(limit_mask & IHLIMIT))
3829 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3830 if (!(limit_mask & ISLIMIT))
3831 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3833 /* Keep grace times if we have got no softlimit arguments */
3834 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3835 dqb->dqb_valid |= QIF_BTIME;
3836 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3839 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3840 dqb->dqb_valid |= QIF_ITIME;
3841 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3845 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3846 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3848 rc = llapi_quotactl(mnt, &qctl);
3851 fprintf(stderr, "%s %s ", obd_type,
3852 obd_uuid2str(&qctl.obd_uuid));
3853 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3860 /* Converts seconds value into format string
3861 * result is returned in buf
3863 * 1. result is in descenting order: 1w2d3h4m5s
3864 * 2. zero fields are not filled (except for p. 3): 5d1s
3865 * 3. zero seconds value is presented as "0s"
3867 static char * __sec2str(time_t seconds, char *buf)
3869 const char spec[] = "smhdw";
3870 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3875 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3876 c = seconds / mult[i];
3878 if (c > 0 || (i == 0 && buf == tail))
3879 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3887 static void sec2str(time_t seconds, char *buf, int rc)
3894 tail = __sec2str(seconds, tail);
3896 if (rc && tail - buf < 39) {
3902 static void diff2str(time_t seconds, char *buf, time_t now)
3908 if (seconds <= now) {
3909 strcpy(buf, "none");
3912 __sec2str(seconds - now, buf);
3915 static void print_quota_title(char *name, struct if_quotactl *qctl,
3916 bool human_readable)
3918 printf("Disk quotas for %s %s (%cid %u):\n",
3919 qtype_name(qctl->qc_type), name,
3920 *qtype_name(qctl->qc_type), qctl->qc_id);
3921 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3922 "Filesystem", human_readable ? "used" : "kbytes",
3923 "quota", "limit", "grace",
3924 "files", "quota", "limit", "grace");
3927 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3930 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3933 snprintf(buf, buflen, "%5.4gP",
3934 (double)num / ((__u64)1 << 40));
3936 snprintf(buf, buflen, "%5.4gT",
3937 (double)num / (1 << 30));
3939 snprintf(buf, buflen, "%5.4gG",
3940 (double)num / (1 << 20));
3942 snprintf(buf, buflen, "%5.4gM",
3943 (double)num / (1 << 10));
3945 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3949 #define STRBUF_LEN 32
3950 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3957 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3958 int bover = 0, iover = 0;
3959 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3960 char numbuf[3][STRBUF_LEN];
3962 char strbuf[STRBUF_LEN];
3964 if (dqb->dqb_bhardlimit &&
3965 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3967 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3968 if (dqb->dqb_btime > now) {
3975 if (dqb->dqb_ihardlimit &&
3976 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3978 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3979 if (dqb->dqb_itime > now) {
3987 if (strlen(mnt) > 15)
3988 printf("%s\n%15s", mnt, "");
3990 printf("%15s", mnt);
3993 diff2str(dqb->dqb_btime, timebuf, now);
3995 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3996 strbuf, sizeof(strbuf), h);
3997 if (rc == -EREMOTEIO)
3998 sprintf(numbuf[0], "%s*", strbuf);
4000 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4001 "%s" : "[%s]", strbuf);
4003 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4004 if (type == QC_GENERAL)
4005 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4006 "%s" : "[%s]", strbuf);
4008 sprintf(numbuf[1], "%s", "-");
4010 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4011 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4012 "%s" : "[%s]", strbuf);
4014 printf(" %7s%c %6s %7s %7s",
4015 numbuf[0], bover ? '*' : ' ', numbuf[1],
4016 numbuf[2], bover > 1 ? timebuf : "-");
4019 diff2str(dqb->dqb_itime, timebuf, now);
4021 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4022 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4024 if (type == QC_GENERAL)
4025 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4027 (uintmax_t)dqb->dqb_isoftlimit);
4029 sprintf(numbuf[1], "%s", "-");
4031 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4032 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4034 if (type != QC_OSTIDX)
4035 printf(" %7s%c %6s %7s %7s",
4036 numbuf[0], iover ? '*' : ' ', numbuf[1],
4037 numbuf[2], iover > 1 ? timebuf : "-");
4039 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4042 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4043 qctl->qc_cmd == Q_GETOINFO) {
4047 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4048 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4049 printf("Block grace time: %s; Inode grace time: %s\n",
4050 bgtimebuf, igtimebuf);
4054 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4055 bool h, __u64 *total)
4057 int rc = 0, rc1 = 0, count = 0;
4058 __u32 valid = qctl->qc_valid;
4060 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4062 fprintf(stderr, "can not get %s count: %s\n",
4063 is_mdt ? "mdt": "ost", strerror(-rc));
4067 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4068 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4069 rc = llapi_quotactl(mnt, qctl);
4071 /* It is remote client case. */
4072 if (rc == -EOPNOTSUPP) {
4079 fprintf(stderr, "quotactl %s%d failed.\n",
4080 is_mdt ? "mdt": "ost", qctl->qc_idx);
4084 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4085 qctl->qc_valid, 0, h);
4086 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4087 qctl->qc_dqblk.dqb_bhardlimit;
4090 qctl->qc_valid = valid;
4094 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
4095 int verbose, int quiet, bool human_readable)
4097 int rc1 = 0, rc2 = 0, rc3 = 0;
4098 char *obd_type = (char *)qctl->obd_type;
4099 char *obd_uuid = (char *)qctl->obd_uuid.uuid;
4100 __u64 total_ialloc = 0, total_balloc = 0;
4103 rc1 = llapi_quotactl(mnt, qctl);
4107 fprintf(stderr, "%s quotas are not enabled.\n",
4108 qtype_name(qctl->qc_type));
4111 fprintf(stderr, "Permission denied.\n");
4114 /* We already got error message. */
4117 fprintf(stderr, "Unexpected quotactl error: %s\n",
4122 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4123 print_quota_title(name, qctl, human_readable);
4125 if (rc1 && *obd_type)
4126 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4128 if (qctl->qc_valid != QC_GENERAL)
4131 inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) &&
4132 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4133 (QIF_LIMITS|QIF_USAGE));
4135 print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable);
4137 if (qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
4139 char strbuf[STRBUF_LEN];
4141 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
4143 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
4145 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4147 printf("Total allocated inode limit: %ju, total "
4148 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4152 if (rc1 || rc2 || rc3 || inacc)
4153 printf("Some errors happened when getting quota info. "
4154 "Some devices may be not working or deactivated. "
4155 "The data in \"[]\" is inaccurate.\n");
4161 static int lfs_project(int argc, char **argv)
4163 int ret = 0, err = 0, c, i;
4164 struct project_handle_control phc = { 0 };
4165 enum lfs_project_ops_t op;
4168 phc.assign_projid = false;
4169 /* default action */
4170 op = LFS_PROJECT_LIST;
4172 while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
4175 if (op != LFS_PROJECT_LIST) {
4177 "%s: cannot specify '-c' '-C' '-s' together\n",
4182 op = LFS_PROJECT_CHECK;
4185 if (op != LFS_PROJECT_LIST) {
4187 "%s: cannot specify '-c' '-C' '-s' together\n",
4192 op = LFS_PROJECT_CLEAR;
4195 if (op != LFS_PROJECT_LIST) {
4197 "%s: cannot specify '-c' '-C' '-s' together\n",
4202 phc.set_inherit = true;
4203 op = LFS_PROJECT_SET;
4209 phc.keep_projid = true;
4212 phc.recursive = true;
4215 phc.projid = strtoul(optarg, NULL, 0);
4216 phc.assign_projid = true;
4220 phc.newline = false;
4223 fprintf(stderr, "%s: invalid option '%c'\n",
4229 if (phc.assign_projid && op == LFS_PROJECT_LIST) {
4230 op = LFS_PROJECT_SET;
4231 phc.set_projid = true;
4232 } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
4233 phc.set_projid = true;
4237 case LFS_PROJECT_CHECK:
4238 if (phc.keep_projid) {
4240 "%s: '-k' is useless together with '-c'\n",
4245 case LFS_PROJECT_CLEAR:
4248 "%s: '-0' is useless together with '-C'\n",
4252 if (phc.assign_projid) {
4254 "%s: '-p' is useless together with '-C'\n",
4259 case LFS_PROJECT_SET:
4262 "%s: '-0' is useless together with '-s'\n",
4266 if (phc.keep_projid) {
4268 "%s: '-k' is useless together with '-s'\n",
4276 "%s: '-0' is useless for list operations\n",
4286 fprintf(stderr, "%s: missing file or directory target(s)\n",
4291 for (i = 0; i < argc; i++) {
4293 case LFS_PROJECT_CHECK:
4294 err = lfs_project_check(argv[i], &phc);
4296 case LFS_PROJECT_LIST:
4297 err = lfs_project_list(argv[i], &phc);
4299 case LFS_PROJECT_CLEAR:
4300 err = lfs_project_clear(argv[i], &phc);
4302 case LFS_PROJECT_SET:
4303 err = lfs_project_set(argv[i], &phc);
4315 static int lfs_quota(int argc, char **argv)
4318 char *mnt, *name = NULL;
4319 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4320 .qc_type = ALLQUOTA };
4321 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4322 int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
4324 __u32 valid = QC_GENERAL, idx = 0;
4325 bool human_readable = false;
4328 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4339 if (qctl.qc_type != ALLQUOTA) {
4340 fprintf(stderr, "error: use either -u or -g\n");
4343 qctl.qc_type = qtype;
4346 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4349 valid = qctl.qc_valid = QC_UUID;
4350 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4353 valid = qctl.qc_valid = QC_MDTIDX;
4354 idx = qctl.qc_idx = atoi(optarg);
4357 valid = qctl.qc_valid = QC_OSTIDX;
4358 idx = qctl.qc_idx = atoi(optarg);
4367 human_readable = true;
4370 fprintf(stderr, "error: %s: option '-%c' "
4371 "unrecognized\n", argv[0], c);
4376 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4377 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4378 optind == argc - 1) {
4380 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4381 qctl.qc_valid = valid;
4384 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
4385 qctl.qc_type = qtype;
4386 if (qtype == USRQUOTA) {
4387 qctl.qc_id = geteuid();
4388 rc = uid2name(&name, qctl.qc_id);
4390 qctl.qc_id = getegid();
4391 rc = gid2name(&name, qctl.qc_id);
4396 rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet,
4402 /* lfs quota -u username /path/to/lustre/mount */
4403 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4404 /* options should be followed by u/g-name and mntpoint */
4405 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4406 fprintf(stderr, "error: missing quota argument(s)\n");
4410 name = argv[optind++];
4411 switch (qctl.qc_type) {
4413 rc = name2uid(&qctl.qc_id, name);
4416 rc = name2gid(&qctl.qc_id, name);
4419 rc = name2projid(&qctl.qc_id, name);
4426 qctl.qc_id = strtoul(name, &endptr, 10);
4427 if (*endptr != '\0') {
4428 fprintf(stderr, "error: can't find id for name: %s\n",
4433 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4434 fprintf(stderr, "error: missing quota info argument(s)\n");
4439 rc = get_print_quota(mnt, name, &qctl, verbose, quiet,
4443 #endif /* HAVE_SYS_QUOTA_H! */
4445 static int flushctx_ioctl(char *mp)
4449 fd = open(mp, O_RDONLY);
4451 fprintf(stderr, "flushctx: error open %s: %s\n",
4452 mp, strerror(errno));
4456 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4458 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4459 mp, strerror(errno));
4465 static int lfs_flushctx(int argc, char **argv)
4467 int kdestroy = 0, c;
4468 char mntdir[PATH_MAX] = {'\0'};
4472 while ((c = getopt(argc, argv, "k")) != -1) {
4478 fprintf(stderr, "error: %s: option '-%c' "
4479 "unrecognized\n", argv[0], c);
4485 if ((rc = system("kdestroy > /dev/null")) != 0) {
4486 rc = WEXITSTATUS(rc);
4487 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4491 if (optind >= argc) {
4492 /* flush for all mounted lustre fs. */
4493 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4494 /* Check if we have a mount point */
4495 if (mntdir[0] == '\0')
4498 if (flushctx_ioctl(mntdir))
4501 mntdir[0] = '\0'; /* avoid matching in next loop */
4504 /* flush fs as specified */
4505 while (optind < argc) {
4506 if (flushctx_ioctl(argv[optind++]))
4513 static int lfs_cp(int argc, char **argv)
4515 fprintf(stderr, "remote client copy file(s).\n"
4516 "obsolete, does not support it anymore.\n");
4520 static int lfs_ls(int argc, char **argv)
4522 fprintf(stderr, "remote client lists directory contents.\n"
4523 "obsolete, does not support it anymore.\n");
4527 static int lfs_changelog(int argc, char **argv)
4529 void *changelog_priv;
4530 struct changelog_rec *rec;
4531 long long startrec = 0, endrec = 0;
4533 struct option long_opts[] = {
4534 {"follow", no_argument, 0, 'f'},
4537 char short_opts[] = "f";
4540 while ((rc = getopt_long(argc, argv, short_opts,
4541 long_opts, NULL)) != -1) {
4549 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4550 argv[0], argv[optind - 1]);
4557 mdd = argv[optind++];
4559 startrec = strtoll(argv[optind++], NULL, 10);
4561 endrec = strtoll(argv[optind++], NULL, 10);
4563 rc = llapi_changelog_start(&changelog_priv,
4564 CHANGELOG_FLAG_BLOCK |
4565 CHANGELOG_FLAG_JOBID |
4566 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4569 fprintf(stderr, "Can't start changelog: %s\n",
4570 strerror(errno = -rc));
4574 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4578 if (endrec && rec->cr_index > endrec) {
4579 llapi_changelog_free(&rec);
4582 if (rec->cr_index < startrec) {
4583 llapi_changelog_free(&rec);
4587 secs = rec->cr_time >> 30;
4588 gmtime_r(&secs, &ts);
4589 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4590 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4591 changelog_type2str(rec->cr_type),
4592 ts.tm_hour, ts.tm_min, ts.tm_sec,
4593 (int)(rec->cr_time & ((1 << 30) - 1)),
4594 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4595 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4597 if (rec->cr_flags & CLF_JOBID) {
4598 struct changelog_ext_jobid *jid =
4599 changelog_rec_jobid(rec);
4601 if (jid->cr_jobid[0] != '\0')
4602 printf(" j=%s", jid->cr_jobid);
4605 if (rec->cr_namelen)
4606 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4607 rec->cr_namelen, changelog_rec_name(rec));
4609 if (rec->cr_flags & CLF_RENAME) {
4610 struct changelog_ext_rename *rnm =
4611 changelog_rec_rename(rec);
4613 if (!fid_is_zero(&rnm->cr_sfid))
4614 printf(" s="DFID" sp="DFID" %.*s",
4615 PFID(&rnm->cr_sfid),
4616 PFID(&rnm->cr_spfid),
4617 (int)changelog_rec_snamelen(rec),
4618 changelog_rec_sname(rec));
4622 llapi_changelog_free(&rec);
4625 llapi_changelog_fini(&changelog_priv);
4628 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4630 return (rc == 1 ? 0 : rc);
4633 static int lfs_changelog_clear(int argc, char **argv)
4641 endrec = strtoll(argv[3], NULL, 10);
4643 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4646 fprintf(stderr, "%s: record out of range: %llu\n",
4648 else if (rc == -ENOENT)
4649 fprintf(stderr, "%s: no changelog user: %s\n",
4652 fprintf(stderr, "%s error: %s\n", argv[0],
4661 static int lfs_fid2path(int argc, char **argv)
4663 struct option long_opts[] = {
4664 { .val = 'c', .name = "cur", .has_arg = no_argument },
4665 { .val = 'l', .name = "link", .has_arg = required_argument },
4666 { .val = 'r', .name = "rec", .has_arg = required_argument },
4668 char short_opts[] = "cl:r:";
4669 char *device, *fid, *path;
4670 long long recno = -1;
4676 while ((rc = getopt_long(argc, argv, short_opts,
4677 long_opts, NULL)) != -1) {
4683 linkno = strtol(optarg, NULL, 10);
4686 recno = strtoll(optarg, NULL, 10);
4691 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4692 argv[0], argv[optind - 1]);
4700 device = argv[optind++];
4701 path = calloc(1, PATH_MAX);
4703 fprintf(stderr, "error: Not enough memory\n");
4708 while (optind < argc) {
4709 fid = argv[optind++];
4711 lnktmp = (linkno >= 0) ? linkno : 0;
4713 int oldtmp = lnktmp;
4714 long long rectmp = recno;
4716 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4719 fprintf(stderr, "%s: error on FID %s: %s\n",
4720 argv[0], fid, strerror(errno = -rc2));
4727 fprintf(stdout, "%lld ", rectmp);
4728 if (device[0] == '/') {
4729 fprintf(stdout, "%s", device);
4730 if (device[strlen(device) - 1] != '/')
4731 fprintf(stdout, "/");
4732 } else if (path[0] == '\0') {
4733 fprintf(stdout, "/");
4735 fprintf(stdout, "%s\n", path);
4738 /* specified linkno */
4740 if (oldtmp == lnktmp)
4750 static int lfs_path2fid(int argc, char **argv)
4752 struct option long_opts[] = {
4753 {"parents", no_argument, 0, 'p'},
4757 const char short_opts[] = "p";
4758 const char *sep = "";
4761 bool show_parents = false;
4763 while ((rc = getopt_long(argc, argv, short_opts,
4764 long_opts, NULL)) != -1) {
4767 show_parents = true;
4770 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4771 argv[0], argv[optind - 1]);
4776 if (optind > argc - 1)
4778 else if (optind < argc - 1)
4782 for (path = argv + optind; *path != NULL; path++) {
4784 if (!show_parents) {
4785 err = llapi_path2fid(*path, &fid);
4787 printf("%s%s"DFID"\n",
4788 *sep != '\0' ? *path : "", sep,
4791 char name[NAME_MAX + 1];
4792 unsigned int linkno = 0;
4794 while ((err = llapi_path2parent(*path, linkno, &fid,
4795 name, sizeof(name))) == 0) {
4796 if (*sep != '\0' && linkno == 0)
4797 printf("%s%s", *path, sep);
4799 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4804 /* err == -ENODATA is end-of-loop */
4805 if (linkno > 0 && err == -ENODATA) {
4812 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4813 argv[0], show_parents ? "parent " : "", *path,
4825 static int lfs_data_version(int argc, char **argv)
4832 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4837 while ((c = getopt(argc, argv, "nrw")) != -1) {
4840 data_version_flags = 0;
4843 data_version_flags |= LL_DV_RD_FLUSH;
4846 data_version_flags |= LL_DV_WR_FLUSH;
4855 path = argv[optind];
4856 fd = open(path, O_RDONLY);
4858 err(errno, "cannot open file %s", path);
4860 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4862 err(errno, "cannot get version for %s", path);
4864 printf("%ju" "\n", (uintmax_t)data_version);
4870 static int lfs_hsm_state(int argc, char **argv)
4875 struct hsm_user_state hus;
4883 rc = llapi_hsm_state_get(path, &hus);
4885 fprintf(stderr, "can't get hsm state for %s: %s\n",
4886 path, strerror(errno = -rc));
4890 /* Display path name and status flags */
4891 printf("%s: (0x%08x)", path, hus.hus_states);
4893 if (hus.hus_states & HS_RELEASED)
4894 printf(" released");
4895 if (hus.hus_states & HS_EXISTS)
4897 if (hus.hus_states & HS_DIRTY)
4899 if (hus.hus_states & HS_ARCHIVED)
4900 printf(" archived");
4901 /* Display user-settable flags */
4902 if (hus.hus_states & HS_NORELEASE)
4903 printf(" never_release");
4904 if (hus.hus_states & HS_NOARCHIVE)
4905 printf(" never_archive");
4906 if (hus.hus_states & HS_LOST)
4907 printf(" lost_from_hsm");
4909 if (hus.hus_archive_id != 0)
4910 printf(", archive_id:%d", hus.hus_archive_id);
4913 } while (++i < argc);
4918 #define LFS_HSM_SET 0
4919 #define LFS_HSM_CLEAR 1
4922 * Generic function to set or clear HSM flags.
4923 * Used by hsm_set and hsm_clear.
4925 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4927 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4929 struct option long_opts[] = {
4930 { .val = 'A', .name = "archived", .has_arg = no_argument },
4931 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4932 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4933 { .val = 'e', .name = "exists", .has_arg = no_argument },
4934 { .val = 'l', .name = "lost", .has_arg = no_argument },
4935 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4936 { .val = 'i', .name = "archive-id", .has_arg = required_argument },
4938 char short_opts[] = "lraAdei:";
4942 __u32 archive_id = 0;
4948 while ((c = getopt_long(argc, argv, short_opts,
4949 long_opts, NULL)) != -1) {
4955 mask |= HS_NOARCHIVE;
4958 mask |= HS_ARCHIVED;
4961 mask |= HS_NORELEASE;
4970 archive_id = strtol(optarg, &end, 10);
4972 fprintf(stderr, "invalid archive_id: '%s'\n",
4980 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4981 argv[0], argv[optind - 1]);
4986 /* User should have specified a flag */
4990 while (optind < argc) {
4992 path = argv[optind];
4994 /* If mode == 0, this means we apply the mask. */
4995 if (mode == LFS_HSM_SET)
4996 rc = llapi_hsm_state_set(path, mask, 0, archive_id);
4998 rc = llapi_hsm_state_set(path, 0, mask, 0);
5001 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
5002 path, strerror(errno = -rc));
5011 static int lfs_hsm_action(int argc, char **argv)
5016 struct hsm_current_action hca;
5017 struct hsm_extent he;
5018 enum hsm_user_action hua;
5019 enum hsm_progress_states hps;
5027 rc = llapi_hsm_current_action(path, &hca);
5029 fprintf(stderr, "can't get hsm action for %s: %s\n",
5030 path, strerror(errno = -rc));
5033 he = hca.hca_location;
5034 hua = hca.hca_action;
5035 hps = hca.hca_state;
5037 printf("%s: %s", path, hsm_user_action2name(hua));
5039 /* Skip file without action */
5040 if (hca.hca_action == HUA_NONE) {
5045 printf(" %s ", hsm_progress_state2name(hps));
5047 if ((hps == HPS_RUNNING) &&
5048 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5049 printf("(%llu bytes moved)\n",
5050 (unsigned long long)he.length);
5051 else if ((he.offset + he.length) == LUSTRE_EOF)
5052 printf("(from %llu to EOF)\n",
5053 (unsigned long long)he.offset);
5055 printf("(from %llu to %llu)\n",
5056 (unsigned long long)he.offset,
5057 (unsigned long long)(he.offset + he.length));
5059 } while (++i < argc);
5064 static int lfs_hsm_set(int argc, char **argv)
5066 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5069 static int lfs_hsm_clear(int argc, char **argv)
5071 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5075 * Check file state and return its fid, to be used by lfs_hsm_request().
5077 * \param[in] file Path to file to check
5078 * \param[in,out] fid Pointer to allocated lu_fid struct.
5079 * \param[in,out] last_dev Pointer to last device id used.
5081 * \return 0 on success.
5083 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5089 rc = lstat(file, &st);
5091 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5094 /* Checking for regular file as archiving as posix copytool
5095 * rejects archiving files other than regular files
5097 if (!S_ISREG(st.st_mode)) {
5098 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5101 /* A request should be ... */
5102 if (*last_dev != st.st_dev && *last_dev != 0) {
5103 fprintf(stderr, "All files should be "
5104 "on the same filesystem: %s\n", file);
5107 *last_dev = st.st_dev;
5109 rc = llapi_path2fid(file, fid);
5111 fprintf(stderr, "Cannot read FID of %s: %s\n",
5112 file, strerror(-rc));
5118 /* Fill an HSM HUR item with a given file name.
5120 * If mntpath is set, then the filename is actually a FID, and no
5121 * lookup on the filesystem will be performed.
5123 * \param[in] hur the user request to fill
5124 * \param[in] idx index of the item inside the HUR to fill
5125 * \param[in] mntpath mountpoint of Lustre
5126 * \param[in] fname filename (if mtnpath is NULL)
5127 * or FID (if mntpath is set)
5128 * \param[in] last_dev pointer to last device id used
5130 * \retval 0 on success
5131 * \retval CMD_HELP or a negative errno on error
5133 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5134 const char *mntpath, const char *fname,
5137 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5140 hui->hui_extent.length = -1;
5142 if (mntpath != NULL) {
5145 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5149 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5154 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5158 hur->hur_request.hr_itemcount++;
5163 static int lfs_hsm_request(int argc, char **argv, int action)
5165 struct option long_opts[] = {
5166 {"filelist", 1, 0, 'l'},
5167 {"data", 1, 0, 'D'},
5168 {"archive", 1, 0, 'a'},
5169 {"mntpath", 1, 0, 'm'},
5173 char short_opts[] = "l:D:a:m:";
5174 struct hsm_user_request *hur, *oldhur;
5179 char *filelist = NULL;
5180 char fullpath[PATH_MAX];
5181 char *opaque = NULL;
5185 int nbfile_alloc = 0;
5186 char *some_file = NULL;
5187 char *mntpath = NULL;
5193 while ((c = getopt_long(argc, argv, short_opts,
5194 long_opts, NULL)) != -1) {
5203 if (action != HUA_ARCHIVE &&
5204 action != HUA_REMOVE) {
5206 "error: -a is supported only "
5207 "when archiving or removing\n");
5210 archive_id = atoi(optarg);
5213 if (some_file == NULL) {
5215 some_file = strdup(optarg);
5221 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5222 argv[0], argv[optind - 1]);
5227 /* All remaining args are files, so we have at least nbfile */
5228 nbfile = argc - optind;
5230 if ((nbfile == 0) && (filelist == NULL))
5234 opaque_len = strlen(opaque);
5236 /* Alloc the request structure with enough place to store all files
5237 * from command line. */
5238 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5240 fprintf(stderr, "Cannot create the request: %s\n",
5244 nbfile_alloc = nbfile;
5246 hur->hur_request.hr_action = action;
5247 hur->hur_request.hr_archive_id = archive_id;
5248 hur->hur_request.hr_flags = 0;
5250 /* All remaining args are files, add them */
5251 if (nbfile != 0 && some_file == NULL)
5252 some_file = strdup(argv[optind]);
5254 for (i = 0; i < nbfile; i++) {
5255 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5261 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5263 /* If a filelist was specified, read the filelist from it. */
5264 if (filelist != NULL) {
5265 fp = fopen(filelist, "r");
5267 fprintf(stderr, "Cannot read the file list %s: %s\n",
5268 filelist, strerror(errno));
5273 while ((rc = getline(&line, &len, fp)) != -1) {
5274 /* If allocated buffer was too small, get something
5276 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5279 nbfile_alloc = nbfile_alloc * 2 + 1;
5281 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5284 fprintf(stderr, "hsm: cannot allocate "
5285 "the request: %s\n",
5292 size = hur_len(oldhur);
5294 fprintf(stderr, "hsm: cannot allocate "
5295 "%u files + %u bytes data\n",
5296 oldhur->hur_request.hr_itemcount,
5297 oldhur->hur_request.hr_data_len);
5304 memcpy(hur, oldhur, size);
5309 if (line[strlen(line) - 1] == '\n')
5310 line[strlen(line) - 1] = '\0';
5312 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5313 mntpath, line, &last_dev);
5319 if (some_file == NULL) {
5329 /* If a --data was used, add it to the request */
5330 hur->hur_request.hr_data_len = opaque_len;
5332 memcpy(hur_data(hur), opaque, opaque_len);
5334 /* Send the HSM request */
5335 if (realpath(some_file, fullpath) == NULL) {
5336 fprintf(stderr, "Could not find path '%s': %s\n",
5337 some_file, strerror(errno));
5339 rc = llapi_hsm_request(fullpath, hur);
5341 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5342 some_file, strerror(-rc));
5352 static int lfs_hsm_archive(int argc, char **argv)
5354 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5357 static int lfs_hsm_restore(int argc, char **argv)
5359 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5362 static int lfs_hsm_release(int argc, char **argv)
5364 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5367 static int lfs_hsm_remove(int argc, char **argv)
5369 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5372 static int lfs_hsm_cancel(int argc, char **argv)
5374 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5377 static int lfs_swap_layouts(int argc, char **argv)
5382 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5383 SWAP_LAYOUTS_KEEP_MTIME |
5384 SWAP_LAYOUTS_KEEP_ATIME);
5387 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5389 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5391 enum lu_ladvise_type advice;
5394 advice < ARRAY_SIZE(ladvise_names); advice++) {
5395 if (ladvise_names[advice] == NULL)
5397 if (strcmp(string, ladvise_names[advice]) == 0)
5401 return LU_LADVISE_INVALID;
5404 static int lfs_ladvise(int argc, char **argv)
5406 struct option long_opts[] = {
5407 {"advice", required_argument, 0, 'a'},
5408 {"background", no_argument, 0, 'b'},
5409 {"end", required_argument, 0, 'e'},
5410 {"start", required_argument, 0, 's'},
5411 {"length", required_argument, 0, 'l'},
5414 char short_opts[] = "a:be:l:s:";
5419 struct llapi_lu_ladvise advice;
5420 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5421 unsigned long long start = 0;
5422 unsigned long long end = LUSTRE_EOF;
5423 unsigned long long length = 0;
5424 unsigned long long size_units;
5425 unsigned long long flags = 0;
5428 while ((c = getopt_long(argc, argv, short_opts,
5429 long_opts, NULL)) != -1) {
5432 advice_type = lfs_get_ladvice(optarg);
5433 if (advice_type == LU_LADVISE_INVALID) {
5434 fprintf(stderr, "%s: invalid advice type "
5435 "'%s'\n", argv[0], optarg);
5436 fprintf(stderr, "Valid types:");
5438 for (advice_type = 0;
5439 advice_type < ARRAY_SIZE(ladvise_names);
5441 if (ladvise_names[advice_type] == NULL)
5443 fprintf(stderr, " %s",
5444 ladvise_names[advice_type]);
5446 fprintf(stderr, "\n");
5456 rc = llapi_parse_size(optarg, &end,
5459 fprintf(stderr, "%s: bad end offset '%s'\n",
5466 rc = llapi_parse_size(optarg, &start,
5469 fprintf(stderr, "%s: bad start offset "
5470 "'%s'\n", argv[0], optarg);
5476 rc = llapi_parse_size(optarg, &length,
5479 fprintf(stderr, "%s: bad length '%s'\n",
5487 fprintf(stderr, "%s: option '%s' unrecognized\n",
5488 argv[0], argv[optind - 1]);
5493 if (advice_type == LU_LADVISE_INVALID) {
5494 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5495 fprintf(stderr, "Valid types:");
5496 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5498 if (ladvise_names[advice_type] == NULL)
5500 fprintf(stderr, " %s", ladvise_names[advice_type]);
5502 fprintf(stderr, "\n");
5506 if (argc <= optind) {
5507 fprintf(stderr, "%s: please give one or more file names\n",
5512 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5513 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5518 if (end == LUSTRE_EOF && length != 0)
5519 end = start + length;
5522 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5523 argv[0], start, end);
5527 while (optind < argc) {
5530 path = argv[optind++];
5532 fd = open(path, O_RDONLY);
5534 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5535 argv[0], path, strerror(errno));
5540 advice.lla_start = start;
5541 advice.lla_end = end;
5542 advice.lla_advice = advice_type;
5543 advice.lla_value1 = 0;
5544 advice.lla_value2 = 0;
5545 advice.lla_value3 = 0;
5546 advice.lla_value4 = 0;
5547 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5550 fprintf(stderr, "%s: cannot give advice '%s' to file "
5551 "'%s': %s\n", argv[0],
5552 ladvise_names[advice_type],
5553 path, strerror(errno));
5556 if (rc == 0 && rc2 < 0)
5562 static int lfs_list_commands(int argc, char **argv)
5564 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5566 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5571 int main(int argc, char **argv)
5575 /* Ensure that liblustreapi constructor has run */
5576 if (!liblustreapi_initialized)
5577 fprintf(stderr, "liblustreapi was not properly initialized\n");
5581 Parser_init("lfs > ", cmdlist);
5583 progname = argv[0]; /* Used in error messages */
5585 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5587 rc = Parser_commands();
5590 return rc < 0 ? -rc : rc;
5593 #ifdef _LUSTRE_IDL_H_
5594 /* Everything we need here should be included by lustreapi.h. */
5595 # error "lfs should not depend on lustre_idl.h"
5596 #endif /* _LUSTRE_IDL_H_ */