+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2003-2005 Silicon Graphics, Inc.
* All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <xfs/xfs.h>
-#include <xfs/command.h>
-#include <xfs/input.h>
+#include <pthread.h>
+#include "platform_defs.h"
+#include "command.h"
+#include "input.h"
#include "init.h"
#include "io.h"
char *progname;
int exitcode;
int expert;
+static int idlethread;
size_t pagesize;
struct timeval stopwatch;
-void
+static void
usage(void)
{
fprintf(stderr,
- _("Usage: %s [-adfmnrRstVx] [-p prog] [-c cmd]... file\n"),
+_("Usage: %s [-adfinrRstVx] [-m mode] [-p prog] [[-c|-C] cmd]... file\n"),
progname);
exit(1);
}
{
attr_init();
bmap_init();
+ copy_range_init();
+ cowextsize_init();
+ encrypt_init();
fadvise_init();
+ fiemap_init();
file_init();
+ flink_init();
freeze_init();
+ fsmap_init();
fsync_init();
getrusage_init();
help_init();
imap_init();
inject_init();
- seek_init();
+ label_init();
+ log_writes_init();
madvise_init();
mincore_init();
mmap_init();
parent_init();
pread_init();
prealloc_init();
- fiemap_init();
pwrite_init();
quit_init();
readdir_init();
+ reflink_init();
+ repair_init();
resblks_init();
+ scrub_init();
+ seek_init();
sendfile_init();
shutdown_init();
- truncate_init();
+ stat_init();
+ swapext_init();
+ sync_init();
sync_range_init();
+ truncate_init();
+ utimes_init();
}
+/*
+ * This allows xfs_io commands specified on the command line to be run on every
+ * open file in the file table. Commands that should not be iterated across all
+ * open files need to specify CMD_FLAG_ONESHOT in their command flags.
+ */
static int
-init_args_command(
+filetable_iterator(
int index)
{
if (index >= filecount)
init_check_command(
const cmdinfo_t *ct)
{
- if (ct->flags & CMD_FLAG_GLOBAL)
- return 1;
-
if (!file && !(ct->flags & CMD_NOFILE_OK)) {
fprintf(stderr, _("no files are open, try 'help open'\n"));
return 0;
return 1;
}
-void
+static void
init(
int argc,
char **argv)
char *sp;
mode_t mode = 0600;
xfs_fsop_geom_t geometry = { 0 };
+ struct fs_path fsp;
progname = basename(argv[0]);
setlocale(LC_ALL, "");
pagesize = getpagesize();
gettimeofday(&stopwatch, NULL);
- while ((c = getopt(argc, argv, "ac:dFfmp:nrRstTVx")) != EOF) {
+ fs_table_initialise(0, NULL, 0, NULL);
+ while ((c = getopt(argc, argv, "ac:C:dFfiLm:p:PnrRstTVx")) != EOF) {
switch (c) {
case 'a':
flags |= IO_APPEND;
case 'c':
add_user_command(optarg);
break;
+ case 'C':
+ add_oneshot_user_command(optarg);
+ break;
case 'd':
flags |= IO_DIRECT;
break;
case 'f':
flags |= IO_CREAT;
break;
+ case 'i':
+ idlethread = 1;
+ break;
case 'm':
mode = strtoul(optarg, &sp, 0);
if (!sp || sp == optarg) {
case 't':
flags |= IO_TRUNC;
break;
+ case 'P':
+ flags |= IO_PATH;
+ break;
+ case 'L':
+ flags |= IO_NOFOLLOW;
+ break;
case 'R':
flags |= IO_REALTIME;
break;
}
while (optind < argc) {
- if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
+ c = openfile(argv[optind], &geometry, flags, mode, &fsp);
+ if (c < 0)
exit(1);
if (!platform_test_xfs_fd(c))
flags |= IO_FOREIGN;
- if (addfile(argv[optind], c, &geometry, flags) < 0)
+ if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
exit(1);
optind++;
}
init_commands();
- add_args_command(init_args_command);
+ add_command_iterator(filetable_iterator);
add_check_command(init_check_command);
}
+/*
+ * The purpose of this idle thread is to test io from a multi threaded process.
+ * With single threaded process, the file table is not shared and file structs
+ * are not reference counted. Spawning an idle thread can help detecting file
+ * struct reference leaks.
+ */
+static void *
+idle_loop(void *arg)
+{
+ for (;;)
+ pause();
+ return NULL;
+}
+
+static void
+start_idle_thread(void)
+{
+ pthread_t t;
+
+ if (pthread_create(&t, NULL, idle_loop, NULL)) {
+ fprintf(stderr, "Error creating idle thread\n");
+ exit(1);
+ }
+}
+
int
main(
int argc,
char **argv)
{
init(argc, argv);
+ if (idlethread)
+ start_idle_thread();
command_loop();
return exitcode;
}