+// 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 version 2 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.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
*/
-#include <xfs/libxfs.h>
+#include <pthread.h>
+#include "platform_defs.h"
#include "command.h"
#include "input.h"
#include "init.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 [-adFfmrRstx] [-p prog] [-c cmd]... file\n"),
+_("Usage: %s [-adfinrRstVx] [-m mode] [-p prog] [[-c|-C] cmd]... file\n"),
progname);
exit(1);
}
void
init_cvtnum(
- unsigned int *blocksize,
- unsigned int *sectsize)
+ size_t *blocksize,
+ size_t *sectsize)
{
if (!file || (file->flags & IO_FOREIGN)) {
*blocksize = 4096;
{
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();
+ label_init();
+ log_writes_init();
+ madvise_init();
+ mincore_init();
mmap_init();
open_init();
+ parent_init();
pread_init();
prealloc_init();
pwrite_init();
quit_init();
+ readdir_init();
+ reflink_init();
+ repair_init();
resblks_init();
+ scrub_init();
+ seek_init();
sendfile_init();
shutdown_init();
+ stat_init();
+ swapext_init();
+ sync_init();
+ sync_range_init();
truncate_init();
+ utimes_init();
+ crc32cselftest_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)
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:rRstVx")) != EOF) {
+ fs_table_initialise(0, NULL, 0, NULL);
+ while ((c = getopt(argc, argv, "ac:C:dFfiLm:p:PnrRstTVx")) != EOF) {
switch (c) {
- case 'a': /* append */
+ case 'a':
flags |= IO_APPEND;
break;
- case 'c': /* commands */
+ 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_FOREIGN;
+ /* Ignored / deprecated now, handled automatically */
break;
case 'f':
flags |= IO_CREAT;
break;
+ case 'i':
+ idlethread = 1;
+ break;
case 'm':
mode = strtoul(optarg, &sp, 0);
if (!sp || sp == optarg) {
exit(1);
}
break;
+ case 'n':
+ flags |= IO_NONBLOCK;
+ break;
case 'p':
progname = optarg;
break;
case 't':
flags |= IO_TRUNC;
break;
+ case 'P':
+ flags |= IO_PATH;
+ break;
+ case 'L':
+ flags |= IO_NOFOLLOW;
+ break;
case 'R':
flags |= IO_REALTIME;
break;
+ case 'T':
+ flags |= IO_TMPFILE;
+ break;
case 'x':
expert = 1;
break;
}
while (optind < argc) {
- if ((c = openfile(argv[optind], flags & IO_FOREIGN ?
- NULL : &geometry, flags, mode)) < 0)
+ c = openfile(argv[optind], &geometry, flags, mode, &fsp);
+ if (c < 0)
exit(1);
- if (addfile(argv[optind], c, &geometry, flags) < 0)
+ if (!platform_test_xfs_fd(c))
+ flags |= IO_FOREIGN;
+ 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;
}