#
-# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2000-2004 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
Logs/* built .census install.* install-dev.* *.gz
SUBDIRS = include libxfs libxlog libhandle libdisk \
- copy db freeze fsck growfs io imap logprint mkfile mkfs repair rtcp \
+ copy db fsck growfs io imap logprint mkfile mkfs repair rtcp \
m4 man doc po debian build
default: $(CONFIGURE)
#
PKG_MAJOR=2
PKG_MINOR=6
-PKG_REVISION=7
+PKG_REVISION=8
PKG_BUILD=1
-xfsprogs (2.6.7-1) unstable; urgency=low
+xfsprogs (2.6.8-1) unstable; urgency=low
* New upstream release.
- -- Nathan Scott <nathans@debian.org> Fri, 19 Mar 2004 13:53:16 +1100
+ -- Nathan Scott <nathans@debian.org> Thu, 25 Mar 2004 14:29:13 +1100
xfsprogs (2.6.5-1) unstable; urgency=low
+xfsprogs-2.6.8 (25 March 2003)
+ - Fix xfs_db when dumping v2 dirs larger than the fsb size.
+ - Several xfs_io additions - support for memory mapped areas,
+ multiple open files, expert mode (freeze, shutdown, error
+ injection, etc), fadvise (Linux-specific), allow user to
+ specify a create mode to open(2).
+ - Fix xfs_bmap verbose mode stripe alignment information.
+ - Fix typo on xfs(5) man page.
+
xfsprogs-2.6.7 (19 March 2003)
- Fix up UUID library checks again, previous fix didn't work
for older versions of autconf.
+++ /dev/null
-/*
- * Copyright (c) 2001-2003 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/
- */
-
-#include <xfs/libxfs.h>
-
-char *progname;
-
-static void
-usage(void)
-{
- fprintf(stderr, _(
-"Usage: %s [options] mountpoint\n\n\
-Options:\n\
- -f freeze filesystem access\n\
- -u unfreeze filesystem access\n"),
- progname);
- exit(2);
-}
-
-int
-main(int argc, char **argv)
-{
- int c; /* current option character */
- int ffd; /* mount point file descriptor */
- int fflag, uflag;
- int level;
- char *fname;
-
- fflag = uflag = 0;
- progname = basename(argv[0]);
- setlocale(LC_ALL, "");
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-
- while ((c = getopt(argc, argv, "fu")) != EOF) {
- switch (c) {
- case 'f':
- fflag = 1;
- break;
- case 'u':
- uflag = 1;
- break;
- case '?':
- default:
- usage();
- }
- }
- if (argc - optind != 1)
- usage();
- if ((fflag + uflag) != 1)
- usage();
-
- fname = argv[optind];
- ffd = open(fname, O_RDONLY);
- if (ffd < 0) {
- perror(fname);
- return 1;
- }
-
- if (!platform_test_xfs_fd(ffd)) {
- fprintf(stderr, _("%s: specified file "
- "[\"%s\"] is not on an XFS filesystem\n"),
- progname, argv[optind]);
- exit(1);
- }
-
- if (fflag) {
- level = 1;
- if (xfsctl(fname, ffd, XFS_IOC_FREEZE, &level) < 0) {
- fprintf(stderr, _("%s: cannot freeze filesystem"
- " mounted at %s: %s\n"),
- progname, argv[optind], strerror(errno));
- exit(1);
- }
- }
-
- if (uflag) {
- if (xfsctl(fname, ffd, XFS_IOC_THAW, &level) < 0) {
- fprintf(stderr, _("%s: cannot unfreeze filesystem"
- " mounted at %s: %s\n"),
- progname, argv[optind], strerror(errno));
- exit(1);
- }
- }
-
- close(ffd);
- return 0;
-}
#
-# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2000-2004 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
TOPDIR = ..
include $(TOPDIR)/include/builddefs
-# TODO: mmap, file locking, fadvise
-
LTCOMMAND = xfs_io
+LSRCFILES = xfs_bmap.sh xfs_freeze.sh
HFILES = command.h input.h init.h
CFILES = command.c input.c init.c \
- bmap.c fsync.c help.c open.c pread.c prealloc.c pwrite.c \
- quit.c resblks.c truncate.c
-LSRCFILES = xfs_bmap.sh
+ bmap.c file.c freeze.c fsync.c help.c inject.c \
+ mmap.c open.c pread.c prealloc.c pwrite.c quit.c \
+ resblks.c shutdown.c truncate.c
+
+ifeq ($(PKG_PLATFORM),linux)
+CFILES += fadvise.c
+LCFLAGS += -DHAVE_FADVISE
+else
+LSRCFILES += fadvise.c
+endif
ifeq ($(ENABLE_READLINE),yes)
LLDLIBS += $(LIBREADLINE)
$(INSTALL) -m 755 -d $(PKG_BIN_DIR)
$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR)
$(LTINSTALL) -m 755 xfs_bmap.sh $(PKG_BIN_DIR)/xfs_bmap
+ $(LTINSTALL) -m 755 xfs_freeze.sh $(PKG_BIN_DIR)/xfs_freeze
install-dev:
/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2004 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
#include <xfs/libxfs.h>
#include "command.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t bmap_cmd;
-static int
-usage(void)
-{
- printf("%s %s\n", bmap_cmd.name, bmap_cmd.oneline);
- return 0;
-}
-
static void
bmap_help(void)
{
vflag++;
break;
default:
- return usage();
+ return command_usage(&bmap_cmd);
}
}
if (aflag)
bmv_iflags &= ~(BMV_IF_PREALLOC|BMV_IF_NO_DMAPI_READ);
if (vflag) {
- if (xfsctl(fname, fdesc, XFS_IOC_FSGEOMETRY_V1, &fsgeo) < 0) {
+ c = xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo);
+ if (c < 0) {
fprintf(stderr,
_("%s: can't get geometry [\"%s\"]: %s\n"),
- progname, fname, strerror(errno));
+ progname, file->name, strerror(errno));
exitcode = 1;
return 0;
}
- if ((xfsctl(fname, fdesc, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
+ c = xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx);
+ if (c < 0) {
fprintf(stderr,
_("%s: cannot read attrs on \"%s\": %s\n"),
- progname, fname, strerror(errno));
+ progname, file->name, strerror(errno));
exitcode = 1;
return 0;
}
map->bmv_count = map_size;
map->bmv_iflags = bmv_iflags;
- i = xfsctl(fname, fdesc, XFS_IOC_GETBMAPX, map);
+ i = xfsctl(file->name, file->fd, XFS_IOC_GETBMAPX, map);
if (i < 0) {
if ( errno == EINVAL
&& !aflag && filesize() == 0) {
} else {
fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETBMAPX)"
" iflags=0x%x [\"%s\"]: %s\n"),
- progname, map->bmv_iflags, fname,
+ progname, map->bmv_iflags, file->name,
strerror(errno));
free(map);
exitcode = 1;
/* Get number of extents from xfsctl XFS_IOC_FSGETXATTR[A]
* syscall.
*/
- i = xfsctl(fname, fdesc, aflag ?
+ i = xfsctl(file->name, file->fd, aflag ?
XFS_IOC_FSGETXATTRA : XFS_IOC_FSGETXATTR, &fsx);
if (i < 0) {
fprintf(stderr, "%s: xfsctl(XFS_IOC_FSGETXATTR%s) "
"[\"%s\"]: %s\n", progname, aflag ? "A" : "",
- fname, strerror(errno));
+ file->name, strerror(errno));
free(map);
exitcode = 1;
return 0;
} while (++loop < 2);
if (!nflag) {
if (map->bmv_entries <= 0) {
- printf(_("%s: no extents\n"), fname);
+ printf(_("%s: no extents\n"), file->name);
free(map);
return 0;
}
}
- printf("%s:\n", fname);
+ printf("%s:\n", file->name);
if (!vflag) {
for (i = 0; i < map->bmv_entries; i++) {
printf("\t%d: [%lld..%lld]: ", i,
bmap_cmd.cfunc = bmap_f;
bmap_cmd.argmin = 0;
bmap_cmd.argmax = -1;
+ bmap_cmd.flags = CMD_NOMAP_OK;
bmap_cmd.args = _("[-adlpv] [-n nx]");
bmap_cmd.oneline = _("print block mapping for an XFS file");
bmap_cmd.help = bmap_help;
#include <xfs/libxfs.h>
#include "command.h"
#include "init.h"
+#include "io.h"
cmdinfo_t *cmdtab;
int ncmds;
qsort(cmdtab, ncmds, sizeof(*cmdtab), cmd_compare);
}
+int
+command_usage(
+ const cmdinfo_t *ci)
+{
+ printf("%s %s\n", ci->name, ci->oneline);
+ return 0;
+}
+
int
command(
int argc,
fprintf(stderr, _("command \"%s\" not found\n"), cmd);
return 0;
}
- if (foreign && !ct->foreign) {
+ if (!file && !(ct->flags & CMD_NOFILE_OK)) {
+ fprintf(stderr, _("no files are open, try 'help open'\n"));
+ return 0;
+ }
+ if (!mapping && !(ct->flags & CMD_NOMAP_OK)) {
+ fprintf(stderr, _("no mapped regions, try 'help mmap'\n"));
+ return 0;
+ }
+ if (file && !(ct->flags & CMD_FOREIGN_OK) &&
+ (file->flags & IO_FOREIGN)) {
fprintf(stderr,
- _("foreign file is open, %s command is for XFS filesystems only\n"),
+ _("foreign file active, %s command is for XFS filesystems only\n"),
cmd);
+ return 0;
}
if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
if (ct->argmax == -1)
init_commands(void)
{
bmap_init();
+ fadvise_init();
+ file_init();
+ freeze_init();
+ fsync_init();
help_init();
+ inject_init();
+ mmap_init();
open_init();
pread_init();
prealloc_init();
pwrite_init();
quit_init();
resblks_init();
- fsync_init();
+ shutdown_init();
truncate_init();
}
typedef int (*cfunc_t)(int argc, char **argv);
typedef void (*helpfunc_t)(void);
+#define CMD_NOFILE_OK (1<<0) /* command doesn't need an open file */
+#define CMD_NOMAP_OK (1<<1) /* command doesn't need a mapped region */
+#define CMD_FOREIGN_OK (1<<2) /* command not restricted to XFS files */
+
typedef struct cmdinfo {
const char *name;
const char *altname;
int argmin;
int argmax;
int canpush;
- int foreign;
+ int flags;
const char *args;
const char *oneline;
helpfunc_t help;
extern int ncmds;
extern void add_command(const cmdinfo_t *ci);
+extern int command_usage(const cmdinfo_t *ci);
extern int command(int argc, char **argv);
extern const cmdinfo_t *find_command(const char *cmd);
extern void init_commands(void);
extern void bmap_init(void);
+#ifdef HAVE_FADVISE
+extern void fadvise_init(void);
+#else
+# define fadvise_init() do { } while (0)
+#endif
+extern void file_init(void);
+extern void freeze_init(void);
+extern void fsync_init(void);
extern void help_init(void);
+extern void inject_init(void);
+extern void mmap_init(void);
extern void open_init(void);
extern void pread_init(void);
extern void prealloc_init(void);
extern void pwrite_init(void);
extern void quit_init(void);
extern void resblks_init(void);
-extern void fsync_init(void);
+extern void shutdown_init(void);
extern void truncate_init(void);
-extern off64_t filesize(void);
-extern int openfile(char *, xfs_fsop_geom_t *,
- int, int, int, int, int, int, int);
-
-extern void *buffer;
-extern ssize_t buffersize;
-extern int alloc_buffer(ssize_t, unsigned int);
-extern int read_buffer(int, off64_t, long long, long long *,
- int, int);
--- /dev/null
+/*
+ * Copyright (c) 2004 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/
+ */
+
+#include <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t fadvise_cmd;
+
+#if !defined(__NR_fadvise64)
+# if defined(__i386__)
+# define __NR_fadvise64 250
+# elif defined(__ia64__)
+# define __NR_fadvise64 1234
+# elif defined(__powerpc__)
+# define __NR_fadvise64 233
+# endif
+#endif
+
+static int
+fadvise64(int fd, off64_t offset, size_t len, int advise)
+{
+#ifdef __NR_fadvise64
+ return syscall(__NR_fadvise64, fd, offset, len, advise);
+#else
+ errno = ENOSYS; return -1;
+#endif
+}
+
+static void
+fadvise_help(void)
+{
+ printf(_(
+"\n"
+" advise the page cache about expected I/O patterns on the current file\n"
+"\n"
+" Modifies kernel page cache behaviour when operating on the current file.\n"
+" The range arguments are required by some advise commands ([*] below).\n"
+" With no arguments, the POSIX_FADV_NORMAL advice is implied.\n"
+" -d -- don't need these pages (POSIX_FADV_DONTNEED) [*]\n"
+" -n -- data will be accessed once (POSIX_FADV_NOREUSE) [*]\n"
+" -r -- expect random page references (POSIX_FADV_RANDOM)\n"
+" -s -- expect sequential page references (POSIX_FADV_SEQUENTIAL)\n"
+" -w -- will need these pages (POSIX_FADV_WILLNEED) [*]\n"
+" Notes: these interfaces are not supported in Linux kernels before 2.6.\n"
+" NORMAL sets the default readahead setting on the file.\n"
+" RANDOM sets the readahead setting on the file to zero.\n"
+" SEQUENTIAL sets double the default readahead setting on the file.\n"
+" WILLNEED and NOREUSE are equivalent, and force the maximum readahead.\n"
+"\n"));
+}
+
+static int
+fadvise_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset = 0;
+ size_t length = 0;
+ int c, range = 0, advise = POSIX_FADV_NORMAL;
+
+ while ((c = getopt(argc, argv, "dnrsw")) != EOF) {
+ switch (c) {
+ case 'd': /* Don't need these pages */
+ advise = POSIX_FADV_DONTNEED;
+ range = 1;
+ break;
+ case 'n': /* Data will be accessed once */
+ advise = POSIX_FADV_NOREUSE;
+ range = 1;
+ break;
+ case 'r': /* Expect random page references */
+ advise = POSIX_FADV_RANDOM;
+ range = 0;
+ break;
+ case 's': /* Expect sequential page references */
+ advise = POSIX_FADV_SEQUENTIAL;
+ range = 0;
+ break;
+ case 'w': /* Will need these pages */
+ advise = POSIX_FADV_WILLNEED;
+ range = 1;
+ break;
+ default:
+ return command_usage(&fadvise_cmd);
+ }
+ }
+ if (range) {
+ unsigned int blocksize, sectsize;
+
+ if (optind != argc - 2)
+ return command_usage(&fadvise_cmd);
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ length = cvtnum(blocksize, sectsize, argv[optind]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ } else if (optind != argc) {
+ return command_usage(&fadvise_cmd);
+ }
+
+ if (fadvise64(file->fd, offset, length, advise) < 0) {
+ perror("fadvise");
+ return 0;
+ }
+ return 0;
+}
+
+void
+fadvise_init(void)
+{
+ fadvise_cmd.name = _("fadvise");
+ fadvise_cmd.cfunc = fadvise_f;
+ fadvise_cmd.argmin = 0;
+ fadvise_cmd.argmax = -1;
+ fadvise_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+ fadvise_cmd.args = _("[-dnrsw] [off len]");
+ fadvise_cmd.oneline = _("advisory commands for sections of a file");
+ fadvise_cmd.help = fadvise_help;
+
+ add_command(&fadvise_cmd);
+}
--- /dev/null
+/*
+ * Copyright (c) 2004 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/
+ */
+
+#include <xfs/libxfs.h>
+#include <sys/mman.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t file_cmd;
+static cmdinfo_t print_cmd;
+
+fileio_t *filetable;
+int filecount;
+fileio_t *file;
+
+static void
+print_fileio(
+ fileio_t *file,
+ int index,
+ int braces)
+{
+ printf(_("%c%d%c %-14s (%s,%s,%s,%s%s%s)\n"),
+ braces? '[' : ' ', index, braces? ']' : ' ', file->name,
+ file->flags & IO_FOREIGN ? _("foreign") : _("xfs"),
+ file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
+ file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
+ file->flags & IO_READONLY ? _("read-only") : _("read-write"),
+ file->flags & IO_REALTIME ? _(",real-time") : "",
+ file->flags & IO_APPEND ? _(",append-only") : "");
+}
+
+int
+filelist_f(void)
+{
+ int i;
+
+ for (i = 0; i < filecount; i++)
+ print_fileio(&filetable[i], i, &filetable[i] == file);
+ return 0;
+}
+
+static int
+print_f(
+ int argc,
+ char **argv)
+{
+ filelist_f();
+ maplist_f();
+ return 0;
+}
+
+static int
+file_f(
+ int argc,
+ char **argv)
+{
+ int i;
+
+ if (argc <= 1)
+ return filelist_f();
+ i = atoi(argv[1]);
+ if (i < 0 || i >= filecount) {
+ printf("value %d is out of range (0-%d)\n", i, filecount);
+ } else {
+ file = &filetable[i];
+ filelist_f();
+ }
+ return 0;
+}
+
+void
+file_init(void)
+{
+ file_cmd.name = _("file");
+ file_cmd.altname = _("f");
+ file_cmd.args = _("[N]");
+ file_cmd.cfunc = file_f;
+ file_cmd.argmin = 0;
+ file_cmd.argmax = 1;
+ file_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+ file_cmd.oneline = _("set the current file");
+
+ print_cmd.name = _("print");
+ print_cmd.altname = _("p");
+ print_cmd.cfunc = print_f;
+ print_cmd.argmin = 0;
+ print_cmd.argmax = 0;
+ print_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ print_cmd.oneline = _("list current open files and memory mappings");
+
+ add_command(&file_cmd);
+ add_command(&print_cmd);
+}
--- /dev/null
+/*
+ * Copyright (c) 2001-2004 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/
+ */
+
+#include <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t freeze_cmd;
+static cmdinfo_t thaw_cmd;
+
+int
+freeze_f(
+ int argc,
+ char **argv)
+{
+ int level = 1;
+
+ if (xfsctl(file->name, file->fd, XFS_IOC_FREEZE, &level) < 0) {
+ fprintf(stderr,
+ _("%s: cannot freeze filesystem at %s: %s\n"),
+ progname, file->name, strerror(errno));
+ exitcode = 1;
+ return 0;
+ }
+ return 0;
+}
+
+int
+thaw_f(
+ int argc,
+ char **argv)
+{
+ int level = 1;
+
+ if (xfsctl(file->name, file->fd, XFS_IOC_THAW, &level) < 0) {
+ fprintf(stderr,
+ _("%s: cannot unfreeze filesystem mounted at %s: %s\n"),
+ progname, file->name, strerror(errno));
+ exitcode = 1;
+ return 0;
+ }
+ return 0;
+}
+
+void
+freeze_init(void)
+{
+ freeze_cmd.name = _("freeze");
+ freeze_cmd.cfunc = freeze_f;
+ freeze_cmd.argmin = 0;
+ freeze_cmd.argmax = 0;
+ freeze_cmd.flags = CMD_NOMAP_OK;
+ freeze_cmd.oneline = _("freeze filesystem of current file");
+
+ thaw_cmd.name = _("thaw");
+ thaw_cmd.cfunc = thaw_f;
+ thaw_cmd.argmin = 0;
+ thaw_cmd.argmax = 0;
+ thaw_cmd.flags = CMD_NOMAP_OK;
+ thaw_cmd.oneline = _("unfreeze filesystem of current file");
+
+ if (expert) {
+ add_command(&freeze_cmd);
+ add_command(&thaw_cmd);
+ }
+}
#include <xfs/libxfs.h>
#include "command.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t fsync_cmd;
static cmdinfo_t fdatasync_cmd;
int argc,
char **argv)
{
- if (fsync(fdesc) < 0) {
+ if (fsync(file->fd) < 0) {
perror("fsync");
return 0;
}
int argc,
char **argv)
{
- if (fdatasync(fdesc) < 0) {
+ if (fdatasync(file->fd) < 0) {
perror("fdatasync");
return 0;
}
fsync_cmd.name = _("fsync");
fsync_cmd.altname = _("s");
fsync_cmd.cfunc = fsync_f;
- fsync_cmd.foreign = 1;
+ fsync_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
fsync_cmd.oneline =
_("calls fsync(2) to flush all in-core file state to disk");
fdatasync_cmd.name = _("fdatasync");
fdatasync_cmd.altname = _("ds");
fdatasync_cmd.cfunc = fdatasync_f;
- fdatasync_cmd.foreign = 1;
+ fdatasync_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
fdatasync_cmd.oneline =
_("calls fdatasync(2) to flush the files in-core data to disk");
#include <xfs/libxfs.h>
#include "command.h"
+#include "io.h"
static cmdinfo_t help_cmd;
static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
help_cmd.cfunc = help_f;
help_cmd.argmin = 0;
help_cmd.argmax = 1;
- help_cmd.foreign = 1;
+ help_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
help_cmd.args = _("[command]");
help_cmd.oneline = _("help for one or all commands");
*/
#include <xfs/libxfs.h>
-#include "input.h"
#include "command.h"
+#include "input.h"
+#include "io.h"
char *progname;
int exitcode;
-
-int fdesc;
-char *fname;
-xfs_fsop_geom_t fgeom;
-
-int readonly;
-int directio;
-int realtime;
-int foreign;
-int append;
-int osync;
-int trunc;
+int expert;
+size_t pagesize;
static int ncmdline;
static char **cmdline;
usage(void)
{
fprintf(stderr,
- _("Usage: %s [-adFfrstx] [-p prog] [-c cmd]... file\n"),
+ _("Usage: %s [-adFfmrRstx] [-p prog] [-c cmd]... file\n"),
progname);
exit(1);
}
int argc,
char **argv)
{
- int fflag = 0;
- int c;
+ int c, flags = 0;
+ char *sp;
+ mode_t mode = 0600;
+ xfs_fsop_geom_t geometry = { 0 };
progname = basename(argv[0]);
+ pagesize = getpagesize();
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- while ((c = getopt(argc, argv, "ac:dFfp:rstVx")) != EOF) {
+ while ((c = getopt(argc, argv, "ac:dFfmp:rRstVx")) != EOF) {
switch (c) {
case 'a': /* append */
- append = 1;
+ flags |= IO_APPEND;
break;
case 'c': /* commands */
ncmdline++;
}
cmdline[ncmdline-1] = optarg;
break;
- case 'd': /* directIO */
- directio = 1;
+ case 'd':
+ flags |= IO_DIRECT;
+ break;
+ case 'F':
+ flags |= IO_FOREIGN;
break;
- case 'F': /* foreign */
- foreign = 1;
+ case 'f':
+ flags |= IO_CREAT;
break;
- case 'f': /* create */
- fflag = 1;
+ case 'm':
+ mode = strtoul(optarg, &sp, 0);
+ if (!sp || sp == optarg) {
+ fprintf(stderr, _("non-numeric mode -- %s\n"),
+ optarg);
+ exit(1);
+ }
break;
- case 'p': /* progname */
+ case 'p':
progname = optarg;
break;
- case 'r': /* readonly */
- readonly = 1;
+ case 'r':
+ flags |= IO_READONLY;
+ break;
+ case 's':
+ flags |= IO_OSYNC;
break;
- case 's': /* sync */
- osync = 1;
+ case 't':
+ flags |= IO_TRUNC;
break;
- case 't': /* truncate */
- trunc = 1;
+ case 'R':
+ flags |= IO_REALTIME;
break;
- case 'x': /* realtime */
- realtime = 1;
+ case 'x':
+ expert = 1;
break;
case 'V':
printf(_("%s version %s\n"), progname, VERSION);
}
}
- if (optind != argc - 1)
- usage();
-
- fname = strdup(argv[optind]);
- if ((fdesc = openfile(fname, foreign ? NULL : &fgeom,
- append, fflag, directio,
- readonly, osync, trunc, realtime)) < 0)
- exit(1);
+ while (optind < argc) {
+ if ((c = openfile(argv[optind], flags & IO_FOREIGN ?
+ NULL : &geometry, flags, mode)) < 0)
+ exit(1);
+ if (addfile(argv[optind], c, &geometry, flags) < 0)
+ exit(1);
+ optind++;
+ }
init_commands();
}
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
-extern int exitcode;
extern char *progname;
-
-extern int fdesc;
-extern char *fname;
-extern struct xfs_fsop_geom fgeom;
-
-extern int readonly;
-extern int directio;
-extern int realtime;
-extern int foreign;
-extern int append;
-extern int osync;
-extern int trunc;
+extern int exitcode;
+extern int expert;
+extern size_t pagesize;
--- /dev/null
+/*
+ * Copyright (c) 2004 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/
+ */
+
+#include <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t inject_cmd;
+
+static int
+error_tag(char *name)
+{
+ static struct {
+ int tag;
+ char *name;
+ } *e, eflags[] = {
+#define XFS_ERRTAG_NOERROR 0
+ { XFS_ERRTAG_NOERROR, "noerror" },
+#define XFS_ERRTAG_IFLUSH_1 1
+ { XFS_ERRTAG_IFLUSH_1, "iflush1" },
+#define XFS_ERRTAG_IFLUSH_2 2
+ { XFS_ERRTAG_IFLUSH_2, "iflush2" },
+#define XFS_ERRTAG_IFLUSH_3 3
+ { XFS_ERRTAG_IFLUSH_3, "iflush3" },
+#define XFS_ERRTAG_IFLUSH_4 4
+ { XFS_ERRTAG_IFLUSH_4, "iflush4" },
+#define XFS_ERRTAG_IFLUSH_5 5
+ { XFS_ERRTAG_IFLUSH_5, "iflush5" },
+#define XFS_ERRTAG_IFLUSH_6 6
+ { XFS_ERRTAG_IFLUSH_6, "iflush6" },
+#define XFS_ERRTAG_DA_READ_BUF 7
+ { XFS_ERRTAG_DA_READ_BUF, "dareadbuf" },
+#define XFS_ERRTAG_BTREE_CHECK_LBLOCK 8
+ { XFS_ERRTAG_BTREE_CHECK_LBLOCK, "btree_chk_lblk" },
+#define XFS_ERRTAG_BTREE_CHECK_SBLOCK 9
+ { XFS_ERRTAG_BTREE_CHECK_SBLOCK, "btree_chk_sblk" },
+#define XFS_ERRTAG_ALLOC_READ_AGF 10
+ { XFS_ERRTAG_ALLOC_READ_AGF, "readagf" },
+#define XFS_ERRTAG_IALLOC_READ_AGI 11
+ { XFS_ERRTAG_IALLOC_READ_AGI, "readagi" },
+#define XFS_ERRTAG_ITOBP_INOTOBP 12
+ { XFS_ERRTAG_ITOBP_INOTOBP, "itobp" },
+#define XFS_ERRTAG_IUNLINK 13
+ { XFS_ERRTAG_IUNLINK, "iunlink" },
+#define XFS_ERRTAG_IUNLINK_REMOVE 14
+ { XFS_ERRTAG_IUNLINK_REMOVE, "iunlinkrm" },
+#define XFS_ERRTAG_DIR_INO_VALIDATE 15
+ { XFS_ERRTAG_DIR_INO_VALIDATE, "dirinovalid" },
+#define XFS_ERRTAG_BULKSTAT_READ_CHUNK 16
+ { XFS_ERRTAG_BULKSTAT_READ_CHUNK, "bulkstat" },
+#define XFS_ERRTAG_IODONE_IOERR 17
+ { XFS_ERRTAG_IODONE_IOERR, "logiodone" },
+#define XFS_ERRTAG_STRATREAD_IOERR 18
+ { XFS_ERRTAG_STRATREAD_IOERR, "stratread" },
+#define XFS_ERRTAG_STRATCMPL_IOERR 19
+ { XFS_ERRTAG_STRATCMPL_IOERR, "stratcmpl" },
+#define XFS_ERRTAG_DIOWRITE_IOERR 20
+ { XFS_ERRTAG_DIOWRITE_IOERR, "diowrite" },
+#define XFS_ERRTAG_BMAPIFORMAT 21
+ { XFS_ERRTAG_BMAPIFORMAT, "bmapifmt" },
+#define XFS_ERRTAG_MAX 22
+ { XFS_ERRTAG_MAX, NULL }
+ };
+ int count;
+
+ /* Search for a name */
+ if (name) {
+ for (e = eflags; e->name; e++)
+ if (strcmp(name, e->name) == 0)
+ return e->tag;
+ return -1;
+ }
+
+ /* Dump all the names */
+ fputs("tags: [ ", stdout);
+ for (count = 0, e = eflags; e->name; e++, count++) {
+ if (count) {
+ fputs(", ", stdout);
+ if (!(count % 5))
+ fputs("\n\t", stdout);
+ }
+ fputs(e->name, stdout);
+ }
+ fputs(" ]\n", stdout);
+ return 0;
+}
+
+static void
+inject_help(void)
+{
+ printf(_(
+"\n"
+" inject errors into the filesystem of the currently open file\n"
+"\n"
+" Example:\n"
+" 'inject readagf' - cause errors on allocation group freespace reads\n"
+"\n"
+" Causes the kernel to generate and react to errors within XFS, provided\n"
+" the XFS kernel code has been built with debugging features enabled.\n"
+" With no arguments, displays the list of error injection tags.\n"
+"\n"));
+}
+
+static int
+inject_f(
+ int argc,
+ char **argv)
+{
+ xfs_error_injection_t error;
+ int command = XFS_IOC_ERROR_INJECTION;
+
+ if (argc == 1)
+ return error_tag(NULL);
+
+ while (--argc > 0) {
+ error.fd = file->fd;
+ if ((error.errtag = error_tag(argv[argc])) < 0) {
+ fprintf(stderr, _("no such tag -- %s\n"), argv[1]);
+ continue;
+ }
+ if (error.errtag == XFS_ERRTAG_NOERROR)
+ command = XFS_IOC_ERROR_CLEARALL;
+ if ((xfsctl(file->name, file->fd, command, &error)) < 0) {
+ perror("XFS_IOC_ERROR_INJECTION");
+ continue;
+ }
+ }
+ return 0;
+}
+
+void
+inject_init(void)
+{
+ inject_cmd.name = _("inject");
+ inject_cmd.cfunc = inject_f;
+ inject_cmd.argmin = 0;
+ inject_cmd.argmax = -1;
+ inject_cmd.flags = CMD_NOMAP_OK;
+ inject_cmd.args = _("[tag ...]");
+ inject_cmd.oneline = _("inject errors into a filesystem");
+ inject_cmd.help = inject_help;
+
+ if (expert)
+ add_command(&inject_cmd);
+}
/*
- * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2003-2004 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
#include <xfs/libxfs.h>
#include "input.h"
#include "init.h"
+#include "io.h"
#if defined(ENABLE_READLINE)
# include <readline/history.h>
free(vec);
}
+void
+init_cvtnum(
+ int *blocksize,
+ int *sectsize)
+{
+ if (!file || (file->flags & IO_FOREIGN)) {
+ *blocksize = 4096;
+ *sectsize = 512;
+ } else {
+ *blocksize = file->geom.blocksize;
+ *sectsize = file->geom.sectsize;
+ }
+}
+
#define EXABYTES(x) ((long long)(x) << 60)
#define PETABYTES(x) ((long long)(x) << 50)
#define TERABYTES(x) ((long long)(x) << 40)
/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2004 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
extern char **breakline(char *input, int *count);
extern void doneline(char *input, char **vec);
extern char *fetchline(void);
+extern void init_cvtnum(int *blocksize, int *sectorsize);
extern long long cvtnum(int blocksize, int sectorsize, char *s);
extern void cvtstr(double value, char *str, size_t sz);
extern struct timeval tsub(struct timeval t1, struct timeval t2);
--- /dev/null
+/*
+ * Copyright (c) 2003-2004 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/
+ */
+
+#define IO_READONLY (1<<0)
+#define IO_DIRECT (1<<1)
+#define IO_REALTIME (1<<2)
+#define IO_APPEND (1<<3)
+#define IO_OSYNC (1<<4)
+#define IO_CREAT (1<<5)
+#define IO_TRUNC (1<<6)
+#define IO_FOREIGN (1<<7)
+
+/*
+ * Regular file I/O control
+ */
+typedef struct fileio {
+ int fd; /* open file descriptor */
+ int flags; /* flags describing file state */
+ char *name; /* file name at time of open */
+ xfs_fsop_geom_t geom; /* XFS filesystem geometry */
+} fileio_t;
+
+extern fileio_t *filetable; /* open file table */
+extern int filecount; /* number of open files */
+extern fileio_t *file; /* active file in file table */
+extern int filelist_f(void);
+
+/*
+ * Memory mapped file regions
+ */
+typedef struct mmap_region {
+ void *addr; /* address of start of mapping */
+ size_t length; /* length of mapping */
+ off64_t offset; /* start offset into backing file */
+ int prot; /* protection mode of the mapping */
+ char *name; /* name of backing file */
+} mmap_region_t;
+
+extern mmap_region_t *maptable; /* mmap'd region array */
+extern int mapcount; /* #entries in the mapping table */
+extern mmap_region_t *mapping; /* active mapping table entry */
+extern int maplist_f(void);
+
+/*
+ * Various xfs_io helper routines/globals
+ */
+
+extern off64_t filesize(void);
+extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
+extern int addfile(char *, int , xfs_fsop_geom_t *, int);
+
+extern void *buffer;
+extern ssize_t buffersize;
+extern int alloc_buffer(ssize_t, int, unsigned int);
+extern int read_buffer(int, off64_t, long long, long long *,
+ int, int);
+extern void dump_buffer(off64_t, ssize_t);
--- /dev/null
+/*
+ * Copyright (c) 2004 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/
+ */
+
+#include <xfs/libxfs.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t mmap_cmd;
+static cmdinfo_t mread_cmd;
+static cmdinfo_t msync_cmd;
+static cmdinfo_t munmap_cmd;
+static cmdinfo_t mwrite_cmd;
+static cmdinfo_t madvise_cmd;
+static cmdinfo_t mincore_cmd;
+
+mmap_region_t *maptable;
+int mapcount;
+mmap_region_t *mapping;
+
+static void
+print_mapping(
+ mmap_region_t *map,
+ int index,
+ int braces)
+{
+ unsigned char buffer[8] = { 0 };
+ int i;
+
+ static struct {
+ int prot;
+ int mode;
+ } *p, pflags[] = {
+ { PROT_READ, 'r' },
+ { PROT_WRITE, 'w' },
+ { PROT_EXEC, 'x' },
+ { PROT_NONE, 0 }
+ };
+
+ for (i = 0, p = pflags; p->prot != PROT_NONE; i++, p++)
+ buffer[i] = (map->prot & p->prot) ? p->mode : '-';
+ printf("%c%d%c 0x%lx - 0x%lx %s %14s (%lld : %ld)\n",
+ braces? '[' : ' ', index, braces? ']' : ' ',
+ (unsigned long)map->addr,
+ (unsigned long)(map->addr + map->length),
+ buffer, map->name ? map->name : "???",
+ (long long)map->offset, (long)map->length);
+}
+
+static void *
+check_mapping_range(
+ mmap_region_t *map,
+ off64_t offset,
+ size_t length,
+ int pagealign)
+{
+ off64_t relative;
+
+ if (offset < mapping->offset) {
+ printf(_("offset (%lld) is before start of mapping (%lld)\n"),
+ (long long)offset, (long long)mapping->offset);
+ return NULL;
+ }
+ relative = offset - mapping->offset;
+ if (relative > mapping->length) {
+ printf(_("offset (%lld) is beyond end of mapping (%lld)\n"),
+ (long long)relative, (long long)mapping->offset);
+ return NULL;
+ }
+ if ((relative + length) > (mapping->offset + mapping->length)) {
+ printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"),
+ (long long)offset, (long long)relative,
+ (long long)mapping->offset, (long)mapping->length);
+ return NULL;
+ }
+ if (pagealign && (long)(mapping->addr + relative) % pagesize) {
+ printf(_("offset address (%p) is not page aligned\n"),
+ mapping->addr + relative);
+ return NULL;
+ }
+
+ return mapping->addr + relative;
+}
+
+int
+maplist_f(void)
+{
+ int i;
+
+ for (i = 0; i < mapcount; i++)
+ print_mapping(&maptable[i], i, &maptable[i] == mapping);
+ return 0;
+}
+
+static int
+mapset_f(
+ int argc,
+ char **argv)
+{
+ int i;
+
+ ASSERT(argc == 2);
+ i = atoi(argv[1]);
+ if (i < 0 || i >= mapcount) {
+ printf("value %d is out of range (0-%d)\n", i, mapcount);
+ } else {
+ mapping = &maptable[i];
+ maplist_f();
+ }
+ return 0;
+}
+
+static void
+mmap_help(void)
+{
+ printf(_(
+"\n"
+" maps a range within the current file into memory\n"
+"\n"
+" Example:\n"
+" 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n"
+"\n"
+" Memory maps a range of a file for subsequent use by other xfs_io commands.\n"
+" With no arguments, mmap shows the current mappings. The current mapping\n"
+" can be set by using the single argument form (mapping number or address).\n"
+" If two arguments are specified (a range), a new mapping is created and the\n"
+" following options are available:\n"
+" -r -- map with PROT_READ protection\n"
+" -w -- map with PROT_WRITE protection\n"
+" -x -- map with PROT_EXEC protection\n"
+" If no protection mode is specified, all are used by default.\n"
+"\n"));
+}
+
+static int
+mmap_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset;
+ size_t length;
+ void *address;
+ char *filename;
+ int blocksize, sectsize;
+ int c, prot = 0;
+
+ if (argc == 1) {
+ if (mapping)
+ return maplist_f();
+ fprintf(stderr, file ?
+ _("no mapped regions, try 'help mmap'\n") :
+ _("no files are open, try 'help open'\n"));
+ return 0;
+ } else if (argc == 2) {
+ if (mapping)
+ return mapset_f(argc, argv);
+ fprintf(stderr, file ?
+ _("no mapped regions, try 'help mmap'\n") :
+ _("no files are open, try 'help open'\n"));
+ return 0;
+ } else if (!file) {
+ fprintf(stderr, _("no files are open, try 'help open'\n"));
+ return 0;
+ }
+
+ while ((c = getopt(argc, argv, "rwx")) != EOF) {
+ switch (c) {
+ case 'r':
+ prot |= PROT_READ;
+ break;
+ case 'w':
+ prot |= PROT_WRITE;
+ break;
+ case 'x':
+ prot |= PROT_EXEC;
+ break;
+ default:
+ return command_usage(&mmap_cmd);
+ }
+ }
+ if (!prot)
+ prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+ if (optind != argc - 2)
+ return command_usage(&mmap_cmd);
+
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"), argv[optind]);
+ return 0;
+ }
+ optind++;
+ length = cvtnum(blocksize, sectsize, argv[optind]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"), argv[optind]);
+ return 0;
+ }
+
+ filename = strdup(file->name);
+ if (!filename) {
+ perror("strdup");
+ return 0;
+ }
+
+ address = mmap(NULL, length, prot, MAP_SHARED, file->fd, offset);
+ if (address == MAP_FAILED) {
+ perror("mmap");
+ free(filename);
+ return 0;
+ }
+
+ /* Extend the control array of mmap'd regions */
+ maptable = (mmap_region_t *)realloc(maptable, /* growing */
+ ++mapcount * sizeof(mmap_region_t));
+ if (!maptable) {
+ perror("realloc");
+ mapcount = 0;
+ munmap(address, length);
+ free(filename);
+ return 0;
+ }
+
+ /* Finally, make this the new active mapping */
+ mapping = &maptable[mapcount - 1];
+ mapping->addr = address;
+ mapping->length = length;
+ mapping->offset = offset;
+ mapping->name = filename;
+ mapping->prot = prot;
+ return 0;
+}
+
+static void
+msync_help(void)
+{
+ printf(_(
+"\n"
+" flushes a range of bytes in the current memory mapping\n"
+"\n"
+" Writes all modified copies of pages over the specified range (or entire\n"
+" mapping if no range specified) to their backing storage locations. Also,\n"
+" optionally invalidates so that subsequent references to the pages will be\n"
+" obtained from their backing storage locations (instead of cached copies).\n"
+" -a -- perform asynchronous writes (MS_ASYNC)\n"
+" -i -- invalidate mapped pages (MS_INVALIDATE)\n"
+" -s -- perform synchronous writes (MS_SYNC)\n"
+"\n"));
+}
+
+int
+msync_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset;
+ size_t length;
+ void *start;
+ int c, flags = 0, blocksize, sectsize;
+
+ while ((c = getopt(argc, argv, "ais")) != EOF) {
+ switch (c) {
+ case 'a':
+ flags |= MS_ASYNC;
+ break;
+ case 'i':
+ flags |= MS_INVALIDATE;
+ break;
+ case 's':
+ flags |= MS_SYNC;
+ break;
+ default:
+ return command_usage(&msync_cmd);
+ }
+ }
+
+ if (optind == argc) {
+ offset = mapping->offset;
+ length = mapping->length;
+ } else if (optind == argc - 2) {
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ length = cvtnum(blocksize, sectsize, argv[optind]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ } else {
+ return command_usage(&msync_cmd);
+ }
+
+ start = check_mapping_range(mapping, offset, length, 1);
+ if (!start)
+ return 0;
+
+ if (msync(start, length, flags) < 0)
+ perror("msync");
+
+ return 0;
+}
+
+static int
+read_mapping(
+ char *dest,
+ off64_t offset,
+ int dump,
+ off64_t dumpoffset,
+ size_t dumplength)
+{
+ *dest = *(((char *)mapping->addr) + offset);
+
+ if (offset % pagesize == 0) {
+ if (dump == 2)
+ dumpoffset += mapping->offset;
+ if (dump)
+ dump_buffer(dumpoffset, dumplength);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+mread_help(void)
+{
+ printf(_(
+"\n"
+" reads a range of bytes in the current memory mapping\n"
+"\n"
+" Example:\n"
+" 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n"
+"\n"
+" Accesses a range of the current memory mapping, optionally dumping it to\n"
+" the standard output stream (with -v option) for subsequent inspection.\n"
+" -f -- verbose mode, dump bytes with offsets relative to start of file.\n"
+" -r -- reverse order; start accessing fom the end of range, moving backward\n"
+" -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n"
+" The accesses are performed sequentially from the start offset by default.\n"
+" Notes:\n"
+" References to whole pages following the end of the backing file results\n"
+" in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n"
+" on various filesystem conditions, including quota exceeded errors, and\n"
+" for physical device errors (such as unreadable disk blocks). No attempt\n"
+" has been made to catch signals at this stage...\n"
+"\n"));
+}
+
+int
+mread_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset, tmp;
+ size_t length, dumplen;
+ char *bp;
+ void *start;
+ int dump = 0, rflag = 0;
+ int c, blocksize, sectsize;
+
+ while ((c = getopt(argc, argv, "frv")) != EOF) {
+ switch (c) {
+ case 'f':
+ dump = 2; /* file offset dump */
+ break;
+ case 'r':
+ rflag = 1; /* read in reverse */
+ break;
+ case 'v':
+ dump = 1; /* mapping offset dump */
+ break;
+ default:
+ return command_usage(&mread_cmd);
+ }
+ }
+
+ if (optind == argc) {
+ offset = mapping->offset;
+ length = mapping->length;
+ } else if (optind == argc - 2) {
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ length = cvtnum(blocksize, sectsize, argv[optind]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ } else {
+ return command_usage(&mread_cmd);
+ }
+
+ start = check_mapping_range(mapping, offset, length, 0);
+ if (!start)
+ return 0;
+
+ if (alloc_buffer(pagesize, 0, 0) < 0)
+ return 0;
+ bp = (char *)buffer;
+
+ dumplen = length % pagesize;
+ if (!dumplen)
+ dumplen = pagesize;
+
+ if (rflag) {
+ for (tmp = length, c = 0; tmp > 0; tmp--, bp++, c = 1)
+ if (read_mapping(bp, tmp, c? dump:0, offset, dumplen)) {
+ bp = (char *)buffer;
+ dumplen = pagesize;
+ }
+ } else {
+ for (tmp = 0, c = 0; tmp < length; tmp++, bp++, c = 1)
+ if (read_mapping(bp, tmp, c? dump:0, offset, dumplen)) {
+ bp = (char *)buffer;
+ dumplen = pagesize;
+ }
+ }
+ /* dump the remaining (partial page) part of the read buffer */
+ if (dump) {
+ if (rflag)
+ dumplen = length % pagesize;
+ else
+ dumplen = tmp % pagesize;
+ if (dumplen) {
+ if (dump == 2)
+ tmp += mapping->offset;
+ dump_buffer(tmp, dumplen);
+ }
+ }
+ return 0;
+}
+
+int
+munmap_f(
+ int argc,
+ char **argv)
+{
+ size_t length;
+ unsigned int offset;
+
+ if (munmap(mapping->addr, mapping->length) < 0) {
+ perror("munmap");
+ return 0;
+ }
+ free(mapping->name);
+
+ /* Shuffle the mapping table entries down over the removed entry */
+ offset = mapping - &maptable[0];
+ length = mapcount * sizeof(mmap_region_t);
+ length -= (offset + 1) * sizeof(mmap_region_t);
+ if (length)
+ memmove(mapping, mapping + 1, length);
+
+ /* Resize the memory allocated for the table, possibly freeing */
+ if (--mapcount) {
+ maptable = (mmap_region_t *)realloc(maptable, /* shrinking */
+ mapcount * sizeof(mmap_region_t));
+ if (offset == mapcount)
+ offset--;
+ mapping = maptable + offset;
+ } else {
+ free(maptable);
+ mapping = maptable = NULL;
+ }
+ maplist_f();
+ return 0;
+}
+
+static void
+mwrite_help(void)
+{
+ printf(_(
+"\n"
+" dirties a range of bytes in the current memory mapping\n"
+"\n"
+" Example:\n"
+" 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n"
+"\n"
+" Stores a byte into memory for a range within a mapping.\n"
+" The default stored value is 'X', repeated to fill the range specified.\n"
+" -S -- use an alternate seed character\n"
+" -r -- reverse order; start storing fom the end of range, moving backward\n"
+" The stores are performed sequentially from the start offset by default.\n"
+"\n"));
+}
+
+int
+mwrite_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset, tmp;
+ size_t length;
+ void *start;
+ char *sp;
+ int seed = 'X';
+ int rflag = 0;
+ int c, blocksize, sectsize;
+
+ while ((c = getopt(argc, argv, "rS:")) != EOF) {
+ switch (c) {
+ case 'r':
+ rflag = 1;
+ break;
+ case 'S':
+ seed = (int)strtol(optarg, &sp, 0);
+ if (!sp || sp == optarg) {
+ printf(_("non-numeric seed -- %s\n"), optarg);
+ return 0;
+ }
+ break;
+ default:
+ return command_usage(&mwrite_cmd);
+ }
+ }
+
+ if (optind == argc) {
+ offset = mapping->offset;
+ length = mapping->length;
+ } else if (optind == argc - 2) {
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ length = cvtnum(blocksize, sectsize, argv[optind]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ } else {
+ return command_usage(&mwrite_cmd);
+ }
+
+ start = check_mapping_range(mapping, offset, length, 0);
+ if (!start)
+ return 0;
+
+ if (rflag) {
+ for (tmp = offset + length; tmp > offset; tmp--)
+ ((char *)mapping->addr)[tmp] = seed;
+ } else {
+ for (tmp = offset; tmp < offset + length; tmp++)
+ ((char *)mapping->addr)[tmp] = seed;
+ }
+
+ return 0;
+}
+
+static void
+madvise_help(void)
+{
+ printf(_(
+"\n"
+" advise the page cache about access patterns expected for a mapping\n"
+"\n"
+" Modifies page cache behavior when operating on the current mapping.\n"
+" The range arguments are required by some advise commands ([*] below).\n"
+" With no arguments, the POSIX_MADV_NORMAL advice is implied.\n"
+" -d -- don't need these pages (POSIX_MADV_DONTNEED) [*]\n"
+" -r -- expect random page references (POSIX_MADV_RANDOM)\n"
+" -s -- expect sequential page references (POSIX_MADV_SEQUENTIAL)\n"
+" -w -- will need these pages (POSIX_MADV_WILLNEED) [*]\n"
+" Notes:\n"
+" NORMAL sets the default readahead setting on the file.\n"
+" RANDOM sets the readahead setting on the file to zero.\n"
+" SEQUENTIAL sets double the default readahead setting on the file.\n"
+" WILLNEED forces the maximum readahead.\n"
+"\n"));
+}
+
+int
+madvise_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset;
+ size_t length;
+ void *start;
+ int advise = MADV_NORMAL;
+ int c, blocksize, sectsize;
+
+ while ((c = getopt(argc, argv, "drsw")) != EOF) {
+ switch (c) {
+ case 'd': /* Don't need these pages */
+ advise = MADV_DONTNEED;
+ break;
+ case 'r': /* Expect random page references */
+ advise = MADV_RANDOM;
+ break;
+ case 's': /* Expect sequential page references */
+ advise = MADV_SEQUENTIAL;
+ break;
+ case 'w': /* Will need these pages */
+ advise = MADV_WILLNEED;
+ break;
+ default:
+ return command_usage(&madvise_cmd);
+ }
+ }
+
+ if (optind == argc) {
+ offset = mapping->offset;
+ length = mapping->length;
+ } else if (optind == argc - 2) {
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ length = cvtnum(blocksize, sectsize, argv[optind]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"),
+ argv[optind]);
+ return 0;
+ }
+ } else {
+ return command_usage(&madvise_cmd);
+ }
+
+ start = check_mapping_range(mapping, offset, length, 1);
+ if (!start)
+ return 0;
+
+ if (madvise(start, length, advise) < 0) {
+ perror("madvise");
+ return 0;
+ }
+ return 0;
+}
+
+int
+mincore_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset;
+ size_t length;
+ void *start;
+ void *current, *previous;
+ unsigned char *vec;
+ int i, blocksize, sectsize;
+
+ if (argc == 1) {
+ offset = mapping->offset;
+ length = mapping->length;
+ } else if (argc == 3) {
+ init_cvtnum(&blocksize, §size);
+ offset = cvtnum(blocksize, sectsize, argv[1]);
+ if (offset < 0) {
+ printf(_("non-numeric offset argument -- %s\n"),
+ argv[1]);
+ return 0;
+ }
+ length = cvtnum(blocksize, sectsize, argv[2]);
+ if (length < 0) {
+ printf(_("non-numeric length argument -- %s\n"),
+ argv[2]);
+ return 0;
+ }
+ } else {
+ return command_usage(&mincore_cmd);
+ }
+
+ start = check_mapping_range(mapping, offset, length, 1);
+ if (!start)
+ return 0;
+
+ vec = calloc(length/pagesize, sizeof(unsigned char));
+ if (!vec) {
+ perror("calloc");
+ return 0;
+ }
+
+ if (mincore(start, length, vec) < 0) {
+ perror("mincore");
+ free(vec);
+ return 0;
+ }
+
+ previous = NULL;
+ current = start;
+ for (i = 0; i < length/pagesize; i++, current += pagesize) {
+ if (vec[i]) {
+ if (!previous) { /* print start address */
+ printf("0x%lx - ", (unsigned long)current);
+ previous = start + (i * pagesize);
+ }
+ } else if (previous) { /* print end and page count */
+ printf(_("0x%lx %u pages (%llu : %lu)\n"),
+ (unsigned long)current,
+ (current - previous) / pagesize,
+ (unsigned long long)offset + (previous - start),
+ (unsigned long)(current - previous));
+ previous = NULL;
+ }
+ }
+ if (previous)
+ printf(_("0x%lx %u pages (%llu : %lu)\n"),
+ (unsigned long)current,
+ (current - previous) / pagesize,
+ (unsigned long long)offset + (previous - start),
+ (unsigned long)(current - previous));
+
+ free(vec);
+ return 0;
+}
+
+void
+mmap_init(void)
+{
+ mmap_cmd.name = _("mmap");
+ mmap_cmd.altname = _("mm");
+ mmap_cmd.cfunc = mmap_f;
+ mmap_cmd.argmin = 0;
+ mmap_cmd.argmax = -1;
+ mmap_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ mmap_cmd.args = _("[N] | [-rwx] [off len]");
+ mmap_cmd.oneline =
+ _("mmap a range in the current file, show mappings");
+ mmap_cmd.help = mmap_help;
+
+ mread_cmd.name = _("mread");
+ mread_cmd.altname = _("mr");
+ mread_cmd.cfunc = mread_f;
+ mread_cmd.argmin = 0;
+ mread_cmd.argmax = -1;
+ mread_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ mread_cmd.args = _("[-r] [off len]");
+ mread_cmd.oneline =
+ _("reads data from a region in the current memory mapping");
+ mread_cmd.help = mread_help;
+
+ msync_cmd.name = _("msync");
+ msync_cmd.altname = _("ms");
+ msync_cmd.cfunc = msync_f;
+ msync_cmd.argmin = 0;
+ msync_cmd.argmax = -1;
+ msync_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ msync_cmd.args = _("[-ais] [off len]");
+ msync_cmd.oneline = _("flush a region in the current memory mapping");
+ msync_cmd.help = msync_help;
+
+ munmap_cmd.name = _("munmap");
+ munmap_cmd.altname = _("mu");
+ munmap_cmd.cfunc = munmap_f;
+ munmap_cmd.argmin = 0;
+ munmap_cmd.argmax = 0;
+ munmap_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ munmap_cmd.oneline = _("unmaps the current memory mapping");
+
+ mwrite_cmd.name = _("mwrite");
+ mwrite_cmd.altname = _("mw");
+ mwrite_cmd.cfunc = mwrite_f;
+ mwrite_cmd.argmin = 0;
+ mwrite_cmd.argmax = -1;
+ mwrite_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ mwrite_cmd.args = _("[-r] [-S seed] [off len]");
+ mwrite_cmd.oneline =
+ _("writes data into a region in the current memory mapping");
+ mwrite_cmd.help = mwrite_help;
+
+ madvise_cmd.name = _("madvise");
+ madvise_cmd.altname = _("ma");
+ madvise_cmd.cfunc = madvise_f;
+ madvise_cmd.argmin = 0;
+ madvise_cmd.argmax = -1;
+ madvise_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ madvise_cmd.args = _("[-drsw] [off len]");
+ madvise_cmd.oneline = _("give advice about use of memory");
+ madvise_cmd.help = madvise_help;
+
+ mincore_cmd.name = _("mincore");
+ mincore_cmd.altname = _("mi");
+ mincore_cmd.cfunc = mincore_f;
+ mincore_cmd.argmin = 0;
+ mincore_cmd.argmax = 2;
+ mincore_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ mincore_cmd.args = _("[off len]");
+ mincore_cmd.oneline = _("find mapping pages that are memory resident");
+
+ add_command(&mmap_cmd);
+ add_command(&mread_cmd);
+ add_command(&msync_cmd);
+ add_command(&munmap_cmd);
+ add_command(&mwrite_cmd);
+ add_command(&madvise_cmd);
+ add_command(&mincore_cmd);
+}
#include "command.h"
#include "input.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t open_cmd;
static cmdinfo_t stat_cmd;
+static cmdinfo_t close_cmd;
static cmdinfo_t setfl_cmd;
static cmdinfo_t statfs_cmd;
static cmdinfo_t chattr_cmd;
static cmdinfo_t lsattr_cmd;
static cmdinfo_t extsize_cmd;
-static int stat_f(int, char **);
+
+off64_t
+filesize(void)
+{
+ struct stat64 st;
+
+ if (fstat64(file->fd, &st) < 0) {
+ perror("fstat64");
+ return -1;
+ }
+ return st.st_size;
+}
+
+static char *
+filetype(mode_t mode)
+{
+ switch (mode & S_IFMT) {
+ case S_IFSOCK:
+ return _("socket");
+ case S_IFDIR:
+ return _("directory");
+ case S_IFCHR:
+ return _("char device");
+ case S_IFBLK:
+ return _("block device");
+ case S_IFREG:
+ return _("regular file");
+ case S_IFLNK:
+ return _("symbolic link");
+ case S_IFIFO:
+ return _("fifo");
+ }
+ return NULL;
+}
+
+static void
+printxattr(int flags, int verbose, int dofname, int dobraces, int doeol)
+{
+ static struct {
+ int flag;
+ char *shortname;
+ char *longname;
+ } *p, xflags[] = {
+ { XFS_XFLAG_REALTIME, "r", "realtime" },
+ { XFS_XFLAG_PREALLOC, "p", "prealloc" },
+ { XFS_XFLAG_IMMUTABLE, "i", "immutable" },
+ { XFS_XFLAG_APPEND, "a", "append-only" },
+ { XFS_XFLAG_SYNC, "s", "sync" },
+ { XFS_XFLAG_NOATIME, "A", "no-atime" },
+ { XFS_XFLAG_NODUMP, "d", "no-dump" },
+ { 0, NULL, NULL }
+ };
+ int first = 1;
+
+ if (dobraces)
+ fputs("[", stdout);
+ for (p = xflags; p->flag; p++) {
+ if (flags & p->flag) {
+ if (verbose) {
+ if (first)
+ first = 0;
+ else
+ fputs(", ", stdout);
+ fputs(p->longname, stdout);
+ } else {
+ fputs(p->shortname, stdout);
+ }
+ } else if (!verbose) {
+ fputs("-", stdout);
+ }
+ }
+ if (dobraces)
+ fputs("]", stdout);
+ if (dofname)
+ printf(" %s ", file->name);
+ if (doeol)
+ fputs("\n", stdout);
+}
+
+static int
+stat_f(
+ int argc,
+ char **argv)
+{
+ struct fsxattr fsx;
+ struct stat64 st;
+ int verbose = (argc == 2 && !strcmp(argv[1], "-v"));
+
+ printf(_("fd.path = \"%s\"\n"), file->name);
+ printf(_("fd.flags = %s,%s,%s%s%s\n"),
+ file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
+ file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
+ file->flags & IO_READONLY ? _("read-only") : _("read-write"),
+ file->flags & IO_REALTIME ? _(",real-time") : "",
+ file->flags & IO_APPEND ? _(",append-only") : "");
+ if (fstat64(file->fd, &st) < 0) {
+ perror("fstat64");
+ } else {
+ printf(_("stat.ino = %lld\n"), (long long)st.st_ino);
+ printf(_("stat.type = %s\n"), filetype(st.st_mode));
+ printf(_("stat.size = %lld\n"), (long long)st.st_size);
+ printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks);
+ if (verbose) {
+ printf(_("stat.atime = %s"), ctime(&st.st_atime));
+ printf(_("stat.mtime = %s"), ctime(&st.st_mtime));
+ printf(_("stat.ctime = %s"), ctime(&st.st_ctime));
+ }
+ }
+ if (file->flags & IO_FOREIGN)
+ return 0;
+ if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
+ perror("XFS_IOC_FSGETXATTR");
+ } else {
+ printf(_("xattr.xflags = 0x%x "), fsx.fsx_xflags);
+ printxattr(fsx.fsx_xflags, verbose, 0, 1, 1);
+ printf(_("xattr.extsize = %u\n"), fsx.fsx_extsize);
+ printf(_("xattr.nextents = %u\n"), fsx.fsx_nextents);
+ }
+ return 0;
+}
int
openfile(
char *path,
xfs_fsop_geom_t *geom,
- int aflag,
- int cflag,
- int dflag,
- int rflag,
- int sflag,
- int tflag,
- int xflag)
+ int flags,
+ mode_t mode)
{
int fd;
int oflags;
- oflags = (rflag ? O_RDONLY : O_RDWR);
- if (aflag)
+ oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
+ if (flags & IO_APPEND)
oflags |= O_APPEND;
- if (cflag)
+ if (flags & IO_CREAT)
oflags |= O_CREAT;
- if (dflag)
+ if (flags & IO_DIRECT)
oflags |= O_DIRECT;
- if (sflag)
+ if (flags & IO_OSYNC)
oflags |= O_SYNC;
- if (tflag)
+ if (flags & IO_TRUNC)
oflags |= O_TRUNC;
- fd = open(path, oflags, 0644);
+ fd = open(path, oflags, mode);
if (fd < 0) {
perror(path);
return -1;
}
+
if (!geom)
return fd;
if (!platform_test_xfs_fd(fd)) {
fprintf(stderr, _("%s: specified file "
"[\"%s\"] is not on an XFS filesystem\n"),
- progname, fname);
+ progname, file->name);
close(fd);
return -1;
}
return -1;
}
- if (!readonly && xflag) { /* read/write and realtime */
+ if (!(flags & IO_READONLY) && (flags & IO_REALTIME)) {
struct fsxattr attr;
if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &attr) < 0) {
return fd;
}
-static int
-usage(void)
+int
+addfile(
+ char *name,
+ int fd,
+ xfs_fsop_geom_t *geometry,
+ int flags)
{
- printf("%s %s\n", open_cmd.name, open_cmd.oneline);
+ char *filename;
+
+ filename = strdup(name);
+ if (!filename) {
+ perror("strdup");
+ close(fd);
+ return -1;
+ }
+
+ /* Extend the table of currently open files */
+ filetable = (fileio_t *)realloc(filetable, /* growing */
+ ++filecount * sizeof(fileio_t));
+ if (!filetable) {
+ perror("realloc");
+ filecount = 0;
+ free(filename);
+ close(fd);
+ return -1;
+ }
+
+ /* Finally, make this the new active open file */
+ file = &filetable[filecount - 1];
+ file->fd = fd;
+ file->flags = flags;
+ file->name = filename;
+ file->geom = *geometry;
return 0;
}
{
printf(_(
"\n"
-" opens a new file in the requested mode, after closing the current file\n"
+" opens a new file in the requested mode\n"
"\n"
" Example:\n"
-" 'open -d /tmp/data' - opens data file read-write for direct IO\n"
+" 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
"\n"
" Opens a file for subsequent use by all of the other xfs_io commands.\n"
" With no arguments, open uses the stat command to show the current file.\n"
" -F -- foreign filesystem file, disallow XFS-specific commands\n"
" -a -- open with the O_APPEND flag (append-only mode)\n"
-" -c -- open with O_CREAT (create the file if it doesn't exist)\n"
" -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n"
+" -f -- open with O_CREAT (create the file if it doesn't exist)\n"
+" -m -- permissions to use in case a new file is created (default 0600)\n"
" -r -- open with O_RDONLY, the default is O_RDWR\n"
" -s -- open with O_SYNC\n"
" -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n"
" -x -- mark the file as a realtime XFS file immediately after opening it\n"
-" Note1: usually read/write direct IO requests must be blocksize aligned.\n"
-" Note2: some kernels, however, allow sectorsize alignment for direct IO.\n"
-" Note3: the bmap for non-regular files can be obtained provided the file\n"
+" Note1: usually read/write direct IO requests must be blocksize aligned;\n"
+" some kernels, however, allow sectorsize alignment for direct IO.\n"
+" Note2: the bmap for non-regular files can be obtained provided the file\n"
" was opened correctly (in particular, must be opened read-only).\n"
"\n"));
}
int argc,
char **argv)
{
- int Fflag = 0;
- int aflag = 0;
- int cflag = 0;
- int dflag = 0;
- int rflag = 0;
- int sflag = 0;
- int tflag = 0;
- int xflag = 0;
- char *filename;
+ int c, fd, flags = 0;
+ char *sp;
+ mode_t mode = 0600;
xfs_fsop_geom_t geometry = { 0 };
- int fd;
- int c;
- if (argc == 1)
- return stat_f(argc, argv);
+ if (argc == 1) {
+ if (file)
+ return stat_f(argc, argv);
+ fprintf(stderr, _("no files are open, try 'help open'\n"));
+ return 0;
+ }
- while ((c = getopt(argc, argv, "Facdrstx")) != EOF) {
+ while ((c = getopt(argc, argv, "Facdfm:rstx")) != EOF) {
switch (c) {
case 'F':
- Fflag = 1;
+ flags |= IO_FOREIGN;
break;
case 'a':
- aflag = 1;
+ flags |= IO_APPEND;
break;
case 'c':
- cflag = 1;
+ case 'f':
+ flags |= IO_CREAT;
break;
case 'd':
- dflag = 1;
+ flags |= IO_DIRECT;
+ break;
+ case 'm':
+ mode = strtoul(optarg, &sp, 0);
+ if (!sp || sp == optarg) {
+ printf(_("non-numeric mode -- %s\n"), optarg);
+ return 0;
+ }
break;
case 'r':
- rflag = 1;
+ flags |= IO_READONLY;
break;
case 's':
- sflag = 1;
+ flags |= IO_OSYNC;
break;
case 't':
- tflag = 1;
+ flags |= IO_TRUNC;
break;
case 'x':
- xflag = 1;
+ flags |= IO_REALTIME;
break;
default:
- return usage();
+ return command_usage(&open_cmd);
}
}
if (optind != argc - 1)
- return usage();
+ return command_usage(&open_cmd);
- fd = openfile(argv[optind], Fflag ? NULL : &geometry,
- aflag, cflag, dflag, rflag, sflag, tflag, xflag);
+ fd = openfile(argv[optind], flags & IO_FOREIGN ?
+ NULL : &geometry, flags, mode);
if (fd < 0)
return 0;
- filename = strdup(argv[optind]);
- if (!filename) {
- perror("strdup");
- close(fd);
- return 0;
- }
-
- /*
- * All OK, proceed to make this the new global open file
- */
- osync = sflag;
- trunc = tflag;
- append = aflag;
- foreign = Fflag;
- directio = dflag;
- readonly = rflag;
- realtime = xflag;
- if (fname) {
- close(fdesc);
- free(fname);
- }
- fgeom = geometry;
- fname = filename;
- fdesc = fd;
+ addfile(argv[optind], fd, &geometry, flags);
return 0;
}
-off64_t
-filesize(void)
+static int
+close_f(
+ int argc,
+ char **argv)
{
- struct stat64 st;
-
- if (fstat64(fdesc, &st) < 0) {
- perror("fstat64");
- return -1;
- }
- return st.st_size;
-}
+ size_t length;
+ unsigned int offset;
-static char *
-filetype(mode_t mode)
-{
- switch (mode & S_IFMT) {
- case S_IFSOCK:
- return _("socket");
- case S_IFDIR:
- return _("directory");
- case S_IFCHR:
- return _("char device");
- case S_IFBLK:
- return _("block device");
- case S_IFREG:
- return _("regular file");
- case S_IFLNK:
- return _("symbolic link");
- case S_IFIFO:
- return _("fifo");
+ if (close(file->fd) < 0) {
+ perror("close");
+ return 0;
}
- return NULL;
-}
-
-static void
-printxattr(int flags, int verbose, int dofname, int dobraces, int doeol)
-{
- static struct {
- int flag;
- char *shortname;
- char *longname;
- } *p, xflags[] = {
- { XFS_XFLAG_REALTIME, "r", "realtime" },
- { XFS_XFLAG_PREALLOC, "p", "prealloc" },
- { XFS_XFLAG_IMMUTABLE, "i", "immutable" },
- { XFS_XFLAG_APPEND, "a", "append-only" },
- { XFS_XFLAG_SYNC, "s", "sync" },
- { XFS_XFLAG_NOATIME, "A", "no-atime" },
- { XFS_XFLAG_NODUMP, "d", "no-dump" },
- { 0, NULL, NULL }
- };
- int first = 1;
-
- if (dobraces)
- fputs("[", stdout);
- for (p = xflags; p->flag; p++) {
- if (flags & p->flag) {
- if (verbose) {
- if (first)
- first = 0;
- else
- fputs(", ", stdout);
- fputs(p->longname, stdout);
- } else {
- fputs(p->shortname, stdout);
- }
- } else if (!verbose) {
- fputs("-", stdout);
- }
+ free(file->name);
+
+ /* Shuffle the file table entries down over the removed entry */
+ offset = file - &filetable[0];
+ length = filecount * sizeof(fileio_t);
+ length -= (offset + 1) * sizeof(fileio_t);
+ if (length)
+ memmove(file, file + 1, length);
+
+ /* Resize the memory allocated for the table, possibly freeing */
+ if (--filecount) {
+ filetable = (fileio_t *)realloc(filetable, /* shrinking */
+ filecount * sizeof(fileio_t));
+ if (offset == filecount)
+ offset--;
+ file = filetable + offset;
+ } else {
+ free(filetable);
+ file = filetable = NULL;
}
- if (dobraces)
- fputs("]", stdout);
- if (dofname)
- printf(" %s ", fname);
- if (doeol)
- fputs("\n", stdout);
+ filelist_f();
+ return 0;
}
static int
}
}
- if ((xfsctl(fname, fdesc, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
- perror("xfsctl(XFS_IOC_FSGETXATTR)");
+ if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
+ perror("XFS_IOC_FSGETXATTR");
} else {
printxattr(fsx.fsx_xflags, vflag, !aflag, vflag, !aflag);
if (aflag) {
unsigned int i = 0;
char *c;
- if (xfsctl(fname, fdesc, XFS_IOC_FSGETXATTR, &attr) < 0) {
+ if (xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &attr) < 0) {
perror("XFS_IOC_FSGETXATTR");
return 0;
}
return 0;
}
}
- if (xfsctl(fname, fdesc, XFS_IOC_FSSETXATTR, &attr) < 0)
+ if (xfsctl(file->name, file->fd, XFS_IOC_FSSETXATTR, &attr) < 0)
perror("XFS_IOC_FSSETXATTR");
return 0;
}
"\n"));
}
-static int
-stat_f(
- int argc,
- char **argv)
-{
- struct fsxattr fsx;
- struct stat64 st;
- char fullname[PATH_MAX + 1];
- int verbose = (argc == 2 && !strcmp(argv[1], "-v"));
-
- printf(_("fd.path = \"%s\"\n"),
- realpath(fname, fullname) ? fullname : fname);
- printf(_("fd.flags = %s,%s,%s%s%s\n"),
- osync ? _("sync") : _("non-sync"),
- directio ? _("direct") : _("non-direct"),
- readonly ? _("read-only") : _("read-write"),
- realtime ? _(",real-time") : "",
- append ? _(",append-only") : "");
- if (fstat64(fdesc, &st) < 0) {
- perror("fstat64");
- } else {
- printf(_("stat.ino = %lld\n"), (long long)st.st_ino);
- printf(_("stat.type = %s\n"), filetype(st.st_mode));
- printf(_("stat.size = %lld\n"), (long long)st.st_size);
- printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks);
- if (verbose) {
- printf(_("stat.atime = %s"), ctime(&st.st_atime));
- printf(_("stat.mtime = %s"), ctime(&st.st_mtime));
- printf(_("stat.ctime = %s"), ctime(&st.st_ctime));
- }
- }
- if (foreign)
- return 0;
- if ((xfsctl(fname, fdesc, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
- perror("xfsctl(XFS_IOC_FSGETXATTR)");
- } else {
- printf(_("xattr.xflags = 0x%x "), fsx.fsx_xflags);
- printxattr(fsx.fsx_xflags, verbose, 0, 1, 1);
- printf(_("xattr.extsize = %u\n"), fsx.fsx_extsize);
- printf(_("xattr.nextents = %u\n"), fsx.fsx_nextents);
- }
- return 0;
-}
-
static int
setfl_f(
int argc,
{
int c, flags;
- flags = fcntl(fdesc, F_GETFL, 0);
+ flags = fcntl(file->fd, F_GETFL, 0);
if (flags < 0) {
perror("fcntl(F_GETFL)");
return 0;
}
}
- if (fcntl(fdesc, F_SETFL, flags) < 0)
+ if (fcntl(file->fd, F_SETFL, flags) < 0)
perror("fcntl(F_SETFL)");
return 0;
{
struct fsxattr fsx;
long extsize;
+ int blocksize, sectsize;
- extsize = (long)cvtnum(fgeom.blocksize, fgeom.sectsize, argv[1]);
+ init_cvtnum(&blocksize, §size);
+ extsize = (long)cvtnum(blocksize, sectsize, argv[1]);
if (extsize < 0) {
printf(_("non-numeric extsize argument -- %s\n"), argv[1]);
return 0;
}
- if ((xfsctl(fname, fdesc, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
- perror("xfsctl(XFS_IOC_FSGETXATTR)");
+ if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
+ perror("XFS_IOC_FSGETXATTR");
return 0;
}
fsx.fsx_extsize = extsize;
- if ((xfsctl(fname, fdesc, XFS_IOC_FSSETXATTR, &fsx)) < 0) {
- perror("xfsctl(XFS_IOC_FSSETXATTR)");
+ if ((xfsctl(file->name, file->fd, XFS_IOC_FSSETXATTR, &fsx)) < 0) {
+ perror("XFS_IOC_FSSETXATTR");
return 0;
}
{
struct xfs_fsop_geom_v1 fsgeo;
struct statfs st;
- char fullname[PATH_MAX + 1];
- printf(_("fd.path = \"%s\"\n"),
- realpath(fname, fullname) ? fullname : fname);
- if (platform_fstatfs(fdesc, &st) < 0) {
+ printf(_("fd.path = \"%s\"\n"), file->name);
+ if (platform_fstatfs(file->fd, &st) < 0) {
perror("fstatfs");
} else {
printf(_("statfs.f_bsize = %lld\n"), (long long) st.f_bsize);
printf(_("statfs.f_files = %lld\n"), (long long) st.f_files);
printf(_("statfs.f_ffree = %lld\n"), (long long) st.f_ffree);
}
- if (foreign)
+ if (file->flags & IO_FOREIGN)
return 0;
- if ((xfsctl(fname, fdesc, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
- perror("xfsctl(XFS_IOC_FSGEOMETRY_V1)");
+ if ((xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
+ perror("XFS_IOC_FSGEOMETRY_V1");
} else {
printf(_("geom.bsize = %u\n"), fsgeo.blocksize);
printf(_("geom.agcount = %u\n"), fsgeo.agcount);
open_cmd.cfunc = open_f;
open_cmd.argmin = 0;
open_cmd.argmax = -1;
- open_cmd.foreign = 1;
+ open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
open_cmd.args = _("[-acdrstx] [path]");
- open_cmd.oneline =
- _("close the current file, open file specified by path");
+ open_cmd.oneline = _("open the file specified by path");
open_cmd.help = open_help;
stat_cmd.name = _("stat");
stat_cmd.cfunc = stat_f;
stat_cmd.argmin = 0;
stat_cmd.argmax = 1;
- stat_cmd.foreign = 1;
+ stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
stat_cmd.args = _("[-v]");
- stat_cmd.oneline =
- _("statistics on the currently open file");
+ stat_cmd.oneline = _("statistics on the currently open file");
+
+ close_cmd.name = _("close");
+ close_cmd.altname = _("c");
+ close_cmd.cfunc = close_f;
+ close_cmd.argmin = 0;
+ close_cmd.argmax = 0;
+ close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+ close_cmd.oneline = _("close the current open file");
setfl_cmd.name = _("setfl");
setfl_cmd.cfunc = setfl_f;
setfl_cmd.args = _("[-adx]");
+ setfl_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
setfl_cmd.oneline =
_("set/clear append/direct flags on the open file");
statfs_cmd.name = _("statfs");
statfs_cmd.cfunc = statfs_f;
- statfs_cmd.foreign = 1;
+ statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
statfs_cmd.oneline =
_("statistics on the filesystem of the currently open file");
chattr_cmd.args = _("[+/-riasAd]");
chattr_cmd.argmin = 1;
chattr_cmd.argmax = 1;
+ chattr_cmd.flags = CMD_NOMAP_OK;
chattr_cmd.oneline =
_("change extended inode flags on the currently open file");
chattr_cmd.help = chattr_help;
lsattr_cmd.args = _("[-a | -v]");
lsattr_cmd.argmin = 0;
lsattr_cmd.argmax = 2;
+ lsattr_cmd.flags = CMD_NOMAP_OK;
lsattr_cmd.oneline =
_("list extended inode flags set on the currently open file");
lsattr_cmd.help = lsattr_help;
extsize_cmd.cfunc = extsize_f;
extsize_cmd.argmin = 1;
extsize_cmd.argmax = 1;
+ extsize_cmd.flags = CMD_NOMAP_OK;
extsize_cmd.oneline =
_("set prefered extent size (in bytes) for the open file");
add_command(&open_cmd);
add_command(&stat_cmd);
+ add_command(&close_cmd);
add_command(&setfl_cmd);
add_command(&statfs_cmd);
add_command(&chattr_cmd);
add_command(&lsattr_cmd);
- add_command(&extsize_cmd);
+
+ if (expert)
+ add_command(&extsize_cmd);
}
#include "command.h"
#include "input.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t pread_cmd;
" reads a range of bytes in a specified block size from the given offset\n"
"\n"
" Example:\n"
-" 'read -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n"
+" 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n"
"\n"
" Reads a segment of the currently open file, optionally dumping it to the\n"
" standard output stream (with -v option) for subsequent inspection.\n"
int
alloc_buffer(
ssize_t bsize,
+ int uflag,
unsigned int seed)
{
if (bsize > buffersize) {
if (!buffer) {
perror("memalign");
buffersize = 0;
- return 0;
+ return -1;
}
}
- memset(buffer, seed, buffersize);
- return 1;
+ if (!uflag)
+ memset(buffer, seed, buffersize);
+ return 0;
}
-static void
+void
dump_buffer(
off64_t offset,
ssize_t len)
unsigned int blocksize, sectsize;
struct timeval t1, t2;
char s1[64], s2[64], ts[64];
- int vflag = 0;
+ int uflag = 0, vflag = 0;
int c;
- if (foreign) {
- blocksize = 4096;
- sectsize = 512;
- } else {
- blocksize = fgeom.blocksize;
- sectsize = fgeom.sectsize;
- }
- while ((c = getopt(argc, argv, "b:v")) != EOF) {
+ init_cvtnum(&blocksize, §size);
+ while ((c = getopt(argc, argv, "b:uv")) != EOF) {
switch (c) {
case 'b':
blocksize = cvtnum(blocksize, sectsize, optarg);
return 0;
}
break;
+ case 'u':
+ uflag = 1;
+ break;
case 'v':
vflag = 1;
break;
default:
- printf("%s %s\n", pread_cmd.name, pread_cmd.oneline);
- return 0;
+ return command_usage(&pread_cmd);
}
}
- if (optind != argc - 2) {
- printf("%s %s\n", pread_cmd.name, pread_cmd.oneline);
- return 0;
- }
+ if (optind != argc - 2)
+ return command_usage(&pread_cmd);
+
offset = cvtnum(blocksize, sectsize, argv[optind]);
if (offset < 0) {
printf(_("non-numeric offset argument -- %s\n"), argv[optind]);
return 0;
}
- if (!alloc_buffer(blocksize, 0xabababab))
+ if (alloc_buffer(blocksize, uflag, 0xabababab) < 0)
return 0;
gettimeofday(&t1, NULL);
- if ((c = read_buffer(fdesc, offset, count, &total, vflag, 0)) < 0)
+ if ((c = read_buffer(file->fd, offset, count, &total, vflag, 0)) < 0)
return 0;
gettimeofday(&t2, NULL);
t2 = tsub(t2, t1);
cvtstr((double)total, s1, sizeof(s1));
cvtstr(tdiv((double)total, t2), s2, sizeof(s2));
timestr(&t2, ts, sizeof(ts));
- printf(_("---- %s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
+ printf(_("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
s1, c, ts, s2, tdiv((double)c, t2));
return 0;
}
pread_cmd.cfunc = pread_f;
pread_cmd.argmin = 2;
pread_cmd.argmax = -1;
- pread_cmd.foreign = 1;
+ pread_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
pread_cmd.args = _("[-b bs] [-v] off len");
pread_cmd.oneline = _("reads a number of bytes at a specified offset");
pread_cmd.help = pread_help;
/*
- * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2003-2004 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
#include "command.h"
#include "input.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t allocsp_cmd;
static cmdinfo_t freesp_cmd;
char *length,
xfs_flock64_t *segment)
{
+ int blocksize, sectsize;
+
+ init_cvtnum(&blocksize, §size);
memset(segment, 0, sizeof(*segment));
segment->l_whence = SEEK_SET;
- segment->l_start = cvtnum(fgeom.blocksize, fgeom.sectsize, offset);
+ segment->l_start = cvtnum(blocksize, sectsize, offset);
if (segment->l_start < 0) {
printf(_("non-numeric offset argument -- %s\n"), offset);
return 0;
}
- segment->l_len = cvtnum(fgeom.blocksize, fgeom.sectsize, length);
+ segment->l_len = cvtnum(blocksize, sectsize, length);
if (segment->l_len < 0) {
printf(_("non-numeric length argument -- %s\n"), length);
return 0;
if (!offset_length(argv[1], argv[2], &segment))
return 0;
- if (xfsctl(fname, fdesc, XFS_IOC_ALLOCSP64, &segment) < 0) {
- perror("xfsctl(XFS_IOC_ALLOCSP64)");
+ if (xfsctl(file->name, file->fd, XFS_IOC_ALLOCSP64, &segment) < 0) {
+ perror("XFS_IOC_ALLOCSP64");
return 0;
}
return 0;
if (!offset_length(argv[1], argv[2], &segment))
return 0;
- if (xfsctl(fname, fdesc, XFS_IOC_FREESP64, &segment) < 0) {
- perror("xfsctl(XFS_IOC_FREESP64)");
+ if (xfsctl(file->name, file->fd, XFS_IOC_FREESP64, &segment) < 0) {
+ perror("XFS_IOC_FREESP64");
return 0;
}
return 0;
if (!offset_length(argv[1], argv[2], &segment))
return 0;
- if (xfsctl(fname, fdesc, XFS_IOC_RESVSP64, &segment) < 0) {
- perror("xfsctl(XFS_IOC_RESVSP64)");
+ if (xfsctl(file->name, file->fd, XFS_IOC_RESVSP64, &segment) < 0) {
+ perror("XFS_IOC_RESVSP64");
return 0;
}
return 0;
if (!offset_length(argv[1], argv[2], &segment))
return 0;
- if (xfsctl(fname, fdesc, XFS_IOC_UNRESVSP64, &segment) < 0) {
- perror("xfsctl(XFS_IOC_UNRESVSP64)");
+ if (xfsctl(file->name, file->fd, XFS_IOC_UNRESVSP64, &segment) < 0) {
+ perror("XFS_IOC_UNRESVSP64");
return 0;
}
return 0;
allocsp_cmd.cfunc = allocsp_f;
allocsp_cmd.argmin = 2;
allocsp_cmd.argmax = 2;
+ allocsp_cmd.flags = CMD_NOMAP_OK;
allocsp_cmd.args = _("off len");
allocsp_cmd.oneline = _("allocates zeroed space for part of a file");
freesp_cmd.cfunc = freesp_f;
freesp_cmd.argmin = 2;
freesp_cmd.argmax = 2;
+ freesp_cmd.flags = CMD_NOMAP_OK;
freesp_cmd.args = _("off len");
freesp_cmd.oneline = _("frees space associated with part of a file");
resvsp_cmd.cfunc = resvsp_f;
resvsp_cmd.argmin = 2;
resvsp_cmd.argmax = 2;
+ resvsp_cmd.flags = CMD_NOMAP_OK;
resvsp_cmd.args = _("off len");
resvsp_cmd.oneline =
_("reserves space associated with part of a file");
unresvsp_cmd.argmin = 2;
unresvsp_cmd.argmax = 2;
unresvsp_cmd.args = _("off len");
+ unresvsp_cmd.flags = CMD_NOMAP_OK;
unresvsp_cmd.oneline =
_("frees reserved space associated with part of a file");
#include "command.h"
#include "input.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t pwrite_cmd;
" writes a range of bytes (in block size increments) from the given offset\n"
"\n"
" Example:\n"
-" 'write 512 20' - writes 20 bytes at 512 bytes into the open file\n"
+" 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n"
"\n"
" Writes into a segment of the currently open file, using either a buffer\n"
" filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n"
break;
}
bytes_requested = min(bar, count);
- bytes = pwrite64(fdesc, buffer, bytes_requested, offset);
+ bytes = pwrite64(file->fd, buffer, bytes_requested, offset);
if (bytes == 0)
break;
if (bytes < 0) {
struct timeval t1, t2;
char s1[64], s2[64], ts[64];
char *sp, *infile = NULL;
- int c, fd = -1, dflag = 0;
+ int c, fd = -1, uflag = 0, dflag = 0;
- if (foreign) {
- blocksize = 4096;
- sectsize = 512;
- } else {
- blocksize = fgeom.blocksize;
- sectsize = fgeom.sectsize;
- }
- while ((c = getopt(argc, argv, "b:df:i:s:S:")) != EOF) {
+ init_cvtnum(&blocksize, §size);
+ while ((c = getopt(argc, argv, "b:df:i:s:S:u")) != EOF) {
switch (c) {
case 'b':
blocksize = cvtnum(blocksize, sectsize, optarg);
return 0;
}
break;
+ case 'u':
+ uflag = 1;
+ break;
default:
- printf("%s %s\n", pwrite_cmd.name, pwrite_cmd.oneline);
- return 0;
+ return command_usage(&pwrite_cmd);
}
}
- if ( ((skip || dflag) && !infile) || (optind != argc - 2)) {
- printf("%s %s\n", pwrite_cmd.name, pwrite_cmd.oneline);
- return 0;
- }
+ if ( ((skip || dflag) && !infile) || (optind != argc - 2))
+ return command_usage(&pwrite_cmd);
offset = cvtnum(blocksize, sectsize, argv[optind]);
if (offset < 0) {
printf(_("non-numeric offset argument -- %s\n"), argv[optind]);
return 0;
}
- if (!alloc_buffer(blocksize, seed))
+ if (alloc_buffer(blocksize, uflag, seed) < 0)
return 0;
- if (infile &&
- ((fd = openfile(infile, NULL, 0, 0, dflag, 1, 0, 0, 0)) < 0))
+ c = O_RDONLY | (dflag ? IO_DIRECT : 0);
+ if (infile && ((fd = openfile(infile, NULL, c, 0)) < 0))
return 0;
gettimeofday(&t1, NULL);
cvtstr((double)total, s1, sizeof(s1));
cvtstr(tdiv((double)total, t2), s2, sizeof(s2));
timestr(&t2, ts, sizeof(ts));
- printf(_("----- %s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
+ printf(_("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
s1, c, ts, s2, tdiv((double)c, t2));
close(fd);
return 0;
pwrite_cmd.cfunc = pwrite_f;
pwrite_cmd.argmin = 2;
pwrite_cmd.argmax = -1;
- pwrite_cmd.foreign = 1;
+ pwrite_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
pwrite_cmd.args =
_("[-i infile [-d] [-s skip]] [-b bs] [-S seed] off len");
pwrite_cmd.oneline =
quit_cmd.name = _("quit");
quit_cmd.altname = _("q");
quit_cmd.cfunc = quit_f;
- quit_cmd.foreign = 1;
- quit_cmd.oneline = _("exit xfs_io");
+ quit_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
+ quit_cmd.oneline = _("exit the program");
add_command(&quit_cmd);
}
/*
- * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2003-2004 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
#include "command.h"
#include "input.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t resblks_cmd;
static int resblks_f(int argc, char **argv);
long long blks;
if (argc == 2) {
- blks = cvtnum(fgeom.blocksize, fgeom.sectsize, argv[1]);
+ blks = cvtnum(file->geom.blocksize, file->geom.sectsize, argv[1]);
if (blks < 0) {
printf(_("non-numeric argument -- %s\n"), argv[1]);
return 0;
}
res.resblks = blks;
- if (xfsctl(fname, fdesc, XFS_IOC_SET_RESBLKS, &res) < 0) {
- perror("xfsctl(XFS_IOC_SET_RESBLKS)");
+ if (xfsctl(file->name, file->fd, XFS_IOC_SET_RESBLKS, &res) < 0) {
+ perror("XFS_IOC_SET_RESBLKS");
return 0;
}
- } else if (xfsctl(fname, fdesc, XFS_IOC_GET_RESBLKS, &res) < 0) {
- perror("xfsctl(XFS_IOC_GET_RESBLKS)");
+ } else if (xfsctl(file->name, file->fd, XFS_IOC_GET_RESBLKS, &res) < 0) {
+ perror("XFS_IOC_GET_RESBLKS");
return 0;
}
printf(_("reserved blocks = %llu\n"),
resblks_cmd.cfunc = resblks_f;
resblks_cmd.argmin = 0;
resblks_cmd.argmax = 1;
+ resblks_cmd.flags = CMD_NOMAP_OK;
resblks_cmd.args = _("[blocks]");
resblks_cmd.oneline =
_("get and/or set count of reserved filesystem blocks");
- add_command(&resblks_cmd);
+ if (expert)
+ add_command(&resblks_cmd);
}
--- /dev/null
+/*
+ * Copyright (c) 2004 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/
+ */
+
+#include <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t shutdown_cmd;
+
+static int
+shutdown_f(
+ int argc,
+ char **argv)
+{
+ int c, flag = XFS_FSOP_GOING_FLAGS_NOLOGFLUSH;
+
+ while ((c = getopt(argc, argv, "fv")) != -1) {
+ switch (c) {
+ case 'f':
+ flag = XFS_FSOP_GOING_FLAGS_LOGFLUSH;
+ break;
+ default:
+ return command_usage(&shutdown_cmd);
+ }
+ }
+
+ if ((xfsctl(file->name, file->fd, XFS_IOC_GOINGDOWN, &flag)) < 0) {
+ perror("XFS_IOC_GOINGDOWN");
+ return 0;
+ }
+ return 0;
+}
+
+void
+shutdown_init(void)
+{
+ shutdown_cmd.name = _("shutdown");
+ shutdown_cmd.cfunc = shutdown_f;
+ shutdown_cmd.argmin = 0;
+ shutdown_cmd.argmax = 1;
+ shutdown_cmd.flags = CMD_NOMAP_OK;
+ shutdown_cmd.args = _("[-f]");
+ shutdown_cmd.oneline =
+ _("shuts down the filesystem where the current file resides");
+
+ if (expert)
+ add_command(&shutdown_cmd);
+}
#include "command.h"
#include "input.h"
#include "init.h"
+#include "io.h"
static cmdinfo_t truncate_cmd;
static int
truncate_f(
- int argc,
- char **argv)
+ int argc,
+ char **argv)
{
- off64_t offset;
- unsigned int blocksize, sectsize;
+ off64_t offset;
+ int blocksize, sectsize;
- if (foreign) {
- blocksize = 4096;
- sectsize = 512;
- } else {
- blocksize = fgeom.blocksize;
- sectsize = fgeom.sectsize;
- }
+ init_cvtnum(&blocksize, §size);
offset = cvtnum(blocksize, sectsize, argv[1]);
if (offset < 0) {
printf(_("non-numeric truncate argument -- %s\n"), argv[1]);
return 0;
}
- if (ftruncate64(fdesc, offset) < 0) {
+ if (ftruncate64(file->fd, offset) < 0) {
perror("ftruncate");
return 0;
}
truncate_init(void)
{
truncate_cmd.name = _("truncate");
+ truncate_cmd.altname = _("t");
truncate_cmd.cfunc = truncate_f;
truncate_cmd.argmin = 1;
truncate_cmd.argmax = 1;
- truncate_cmd.foreign = 1;
+ truncate_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
truncate_cmd.args = _("off");
truncate_cmd.oneline =
_("truncates the current file at the given offset");
+#!/bin/sh -f
#
-# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2004 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
# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
#
-TOPDIR = ..
-include $(TOPDIR)/include/builddefs
+OPTS=""
+USAGE="Usage: xfs_freeze -f | -u <mountpoint>"
+DIRNAME=`dirname $0`
+VERSION=false
+FREEZE=false
+THAW=false
-LTCOMMAND = xfs_freeze
+while getopts "fuV" c
+do
+ case $c in
+ f) FREEZE=true;;
+ u) THAW=true;;
+ V) VERSION=true;;
+ \?) echo $USAGE 1>&2
+ exit 2
+ ;;
+ esac
+done
+if $VERSION ; then
+ $DIRNAME/xfs_io -p xfs_freeze -V
+ exit 0
+fi
-CFILES = xfs_freeze.c
-LLDFLAGS += -static
+shift `expr $OPTIND - 1`
+if [ "$1" = "" ]; then
+ echo $USAGE 1>&2
+ exit 2
+fi
-default: $(LTCOMMAND)
-
-include $(BUILDRULES)
-
-install: default
- $(INSTALL) -m 755 -d $(PKG_BIN_DIR)
- $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR)
-install-dev:
+if $FREEZE ; then
+ $DIRNAME/xfs_io -r -p xfs_freeze -x -c "freeze" "$1"
+ status=$?
+ [ $status -ne 0 ] && exit $status
+elif $THAW ; then
+ $DIRNAME/xfs_io -r -p xfs_freeze -x -c "thaw" "$1"
+ status=$?
+ [ $status -ne 0 ] && exit $status
+else
+ echo $USAGE 1>&2
+ exit 2
+fi
+exit 0
.TH xfs_io 8
.SH NAME
-xfs_io \- debug the IO path of an XFS filesystem
+xfs_io \- debug the I/O path of an XFS filesystem
.SH SYNOPSIS
.nf
-\f3xfs_io\f1 [ \f3\-c\f1 cmd ] ... [ \f3\-p\f1 prog ] [ \f3\-Ffr\f1 ] file
+\f3xfs_io\f1 [ \f3\-c\f1 cmd ] ... [ \f3\-p\f1 prog ] [ \f3\-adFfmrRstx\f1 ] file
.fi
.SH DESCRIPTION
\f2xfs_io\f1 is a debugging tool like \f2xfs_db\f1(8), but is aimed
-at examining the regular file IO path rather than the raw XFS volume
+at examining the regular file I/O path rather than the raw XFS volume
itself.
.PP
The options to \f2xfs_io\f1 are:
or as arguments on the command line.
Multiple \f3\-c\f1 arguments may be given.
The commands are run in the sequence given, then the program exits.
-This is the mechanism used to implement \f2xfs_bmap\f1(8).
.TP
\f3\-p\f1 \f2prog\f1
Set the program name for prompts and some error messages,
.TP
\f3\-r\f1
Open \f2file\f1 read-only, initially.
+.TP
+\f3\-x\f1
+Expert mode.
+Dangerous commands are only available in this mode.
+These commands also tend to require additional privileges.
+.PP
+The other \f2open\f1(2) options described below are also available
+from the command line.
.SH CONCEPTS
-\f2xfs_io\f1 always maintains one current open file in the filesystem.
-This is initially specified on the command line, but alternate files
-can be specified later (one at a time \- see the ``open'' command).
+\f2xfs_io\f1 maintains a number of open files and memory mappings.
+Files can be initially opened on the command line (optionally),
+and additional files can also be opened later.
+.PP
+\f2xfs_io\f1 commands can be broken up into three groups.
+Some commands are aimed at doing regular file I/O - read, write,
+sync, space preallocation, etc.
+.PP
+The second set of commands exist for manipulating memory mapped regions
+of a file - mapping, accessing, storing, unmapping, flushing, etc.
.PP
-\f2xfs_io\f1 commands can be broken up into two distinct classes.
-Most commands are for doing IO to the file in some way - reads, writes,
-or space preallocation.
-Other commands are for the navigation and display of data structures
-relating to the open file or the filesystem it resides in.
-.SH COMMANDS
+The remaining commands are for the navigation and display of data
+structures relating to the open files, mappings, and the filesystems
+where they reside.
.PP
Many commands have extensive online help.
Use the \f3help\f1 command for more details on any command.
+.SH FILE I/O COMMANDS
.TP 10
-\f3allocsp\f1 \f2offset\f1 \f2length\f1
-Allocates zeroed space for part of a file using the XFS_IOC_ALLOCSP
-system call described in \f2xfs\f1(5).
-.TP
-\f3freesp\f1 \f2offset\f1 \f2length\f1
-Frees space for part of a file using the XFS_IOC_FREESP
-system call described in \f2xfs\f1(5).
-.TP
-\f3bmap\f1 [ \f2-adlpv\f1 ] [ \f2-n nx\f1 ]
-Prints the block mapping for the open file.
-Refer to \f2xfs_bmap\f1(8) for complete documentation.
-.TP
-\f3fdatasync\f1
-Calls \f2fdatasync\f1(2) to flush the open file's in-core data to disk.
-.TP
-\f3fsync\f1
-Calls \f2fsync\f1(2) to flush all in-core file state to disk.
-.TP
-\f3o\f1
-See the \f3open\f1 command.
-.TP
-\f3open\f1 [ \f2-Facdrstx\f1 ] [ \f2path\f1 ]
+\f3open\f1 [ \f2\-FacdfrstR\f1 ] [ \f2path\f1 ]
Closes the current file, and opens the file specified by \f2path\f1 instead.
-Without any arguments, displays statistics about the currently open file \-
+Without any arguments, displays statistics about the current file \-
see the \f3stat\f1 command.
.br
The \f3\-F\f1 option allows non-XFS (foreign) files to be opened and
.br
The \f3\-a\f1 option opens append-only (O_APPEND).
.br
-The \f3\-c\f1 option creates the file if it doesn't already exist (O_CREAT).
+The \f3\-d\f1 option opens for direct I/O (O_DIRECT).
.br
-The \f3\-d\f1 option opens for direct IO (O_DIRECT).
+The \f3\-f\f1 option creates the file if it doesn't already exist (O_CREAT).
.br
The \f3\-r\f1 option opens read-only (O_RDONLY).
.br
-The \f3\-s\f1 option opens for synchronous IO (O_SYNC).
+The \f3\-s\f1 option opens for synchronous I/O (O_SYNC).
.br
The \f3\-t\f1 option truncates on open (O_TRUNC).
.br
-The \f3\-x\f1 option marks the file as a realtime XFS file after
+The \f3\-R\f1 option marks the file as a realtime XFS file after
opening it, if it is not already marked as such.
.TP
-\f3pread\f1
+\f3o\f1
+See the \f3open\f1 command.
+.TP
+\f3close\f1
+Closes the current open file, marking the next open file as current
+(if one exists).
+.TP
+\f3c\f1
+See the \f3close\f1 command.
+.TP
+\f3pread\f1 [ \f2\-b bsize\f1 ] [ \f2\-v\f1 ]
Reads a range of bytes in a specified blocksize from the given offset.
.br
The \f3\-b\f1 option can be used to set the blocksize into which the
The \f3\-v\f1 option will dump the contents of the buffer after reading,
by default only the count of bytes actually read is dumped.
.TP
-\f3pwrite\f1
+\f3r\f1
+See the \f3pread\f1 command.
+.TP
+\f3pwrite\f1 [ \f2\-i file\f1 ] [ \f2\-d\f1 ] [ \f2\-s skip\f1 ] [ \f2\-b size\f1 ] [ \f2\-S seed\f1 ]
Writes a range of bytes in a specified blocksize from the given offset.
The bytes written can be either a set pattern or read in from another
file before writing.
The \f3\-i\f1 option allows an input file to be specified as the source
of the data to be written.
.br
-The \f3\-d\f1 option will cause direct IO, rather than the usual buffered
-IO, to be used when reading the input file.
+The \f3\-d\f1 option will cause direct I/O, rather than the usual buffered
+I/O, to be used when reading the input file.
.br
The \f3\-s\f1 options specifies the number of bytes to skip from the
start of the input file before starting to read.
.br
The \f3\-b\f1 option can be used to set the blocksize into which the
-\f2read\f1(2) requests will be split.
+\f2write\f1(2) requests will be split.
The default blocksize is 4096 bytes.
The \f3\-S\f1 option is used to set the (repeated) fill pattern which
is used when the data to write is not coming from a file.
The default buffer fill pattern value is 0xcdcdcdcd.
.TP
-\f3q\f1
-See the \f3quit\f1 command.
+\f3w\f1
+See the \f3pwrite\f1 command.
.TP
-\f3quit\f1
-Exit \f2xfs_io\f1.
+\f3bmap\f1 [ \f2\-adlpv\f1 ] [ \f2\-n nx\f1 ]
+Prints the block mapping for the current open file.
+Refer to \f2xfs_bmap\f1(8) for complete documentation.
.TP
-\f3r\f1
-See the \f3pread\f1 command.
+\f3allocsp\f1 \f2offset\f1 \f2length\f1
+Allocates zeroed space for part of a file using the XFS_IOC_ALLOCSP
+system call described in \f2xfs\f1(5).
.TP
-\f3resblks\f1 [ \f2blocks\f1 ]
-Get and/or set count of reserved filesystem blocks using the
-XFS_IOC_GET_RESBLKS or XFS_IOC_SET_RESBLKS system calls, as
-described in \f2xfs\f1(5).
-Note \-\- this can be useful for exercising out of space behavior.
+\f3freesp\f1 \f2offset\f1 \f2length\f1
+Frees space for part of a file using the XFS_IOC_FREESP
+system call described in \f2xfs\f1(5).
+.TP
+\f3fadvise\f1 [ \f2\-dnrsw\f1 ]
+On platforms which support it, allows hints be given to the system
+regarding the expected I/O patterns on the file.
+The hints are similar to those of the \f3madvise\f1 command,
+discussed later.
+.TP
+\f3fdatasync\f1
+Calls \f2fdatasync\f1(2) to flush the file's in-core data to disk.
+.TP
+\f3fsync\f1
+Calls \f2fsync\f1(2) to flush all in-core file state to disk.
+.TP
+\f3s\f1
+See the \f3fsync\f1 command.
.TP
\f3resvsp\f1 \f2offset\f1 \f2length\f1
Allocates reserved, unwritten space for part of a file using the XFS_IOC_RESVSP
Frees reserved space for part of a file using the XFS_IOC_UNRESVSP
system call described in \f2xfs\f1(5).
.TP
-\f3s\f1
-See the \f3fsync\f1 command.
+\f3truncate\f1 \f2offset\f1
+Truncates the current file at the given offset using \f2ftruncate\f1(2).
+
+.SH MEMORY MAPPED I/O COMMANDS
+.TP
+\f3mmap\f1 [ \f2-rwx\f1 ] [ \f2offset\f1 \f2length\f1 ]
+With no arguments, \f3mmap\f1 shows the current mappings.
+Specifying a single numeric argument sets the current mapping.
+If two arguments are specified (a range), a new mapping is created
+spanning the range, and the protection mode can be given as a combination of
+PROT_READ (\f2-r\f1), PROT_WRITE (\f2-w\f1), and PROT_EXEC (\f2-x\f1).
+.TP
+\f3mm\f1
+See the \f3mmap\f1 command.
+.TP
+\f3munmap\f1
+Unmaps the current memory mapping.
+.TP
+\f3mu\f1
+See the \f3munmap\f1 command.
+.TP
+\f3mread\f1 [ \-\f2frv\f1 ]
+Accesses a segment of the current memory mapping, optionally dumping it to
+the standard output stream (with \f2-v\f1 or \f2-f\f1 option) for inspection.
+The accesses are performed sequentially from the start offset by default,
+but can also be done from the end backwards through the mapping if
+the \f2-r\f1 option in specified.
+The two verbose modes differ only in the relative offsets they display,
+the \f2-f\f1 option is relative to file start, whereas \f2-v\f1 shows
+offsets relative to the start of the mapping.
+.TP
+\f3mr\f1
+See the \f3mread\f1 command.
+.TP
+\f3mwrite\f1 [ \f2-r\f1 ] [ \f2-S seed\f1 ]
+Stores a byte into memory for a range within a mapping.
+The default stored value is 'X', repeated to fill the range specified,
+but this can be changed using the \f2-S\f1 option.
+The memory stores are performed sequentially from the start offset by default,
+but can also be done from the end backwards through the mapping if the \-\f2r\f1
+option in specified.
+.TP
+\f3mw\f1
+See the \f3mwrite\f1 command.
+.TP
+\f3msync\f1
+Writes all modified copies of pages over the specified range (or entire
+mapping if no range specified) to their backing storage locations.
+Also, optionally invalidates (\f2-i\f1) so that subsequent references to
+the pages will be obtained from their backing storage locations (instead
+of cached copies).
+The flush can be done synchronously (\f2-s\f1) or asynchronously (\f2-a\f1).
+.TP
+\f3ms\f1
+See the \f3msync\f1 command.
+.TP
+\f3madvise\f1 [ \-\f2drwsw\f1 ] [ \f2offset\f1 \f2length\f1 ]
+Modifies page cache behavior when operating on the current mapping.
+The range arguments are required by some advise commands ([*] below).
+With no arguments, the POSIX_MADV_NORMAL advice is implied (default readahead).
+The \f2-d\f1 option says the pages will not be needed (POSIX_MADV_DONTNEED[*]).
+The \f2-r\f1 option says to expect random page references (POSIX_MADV_RANDOM),
+which sets readahead to zero.
+The \f2-s\f1 option says to expect sequential page references
+(POSIX_MADV_SEQUENTIAL), which doubles the default readahead on the file.
+The \f2-w\f1 option advises the specified pages will be needed
+again (POSIX_MADV_WILLNEED[*]) which forces the maximum readahead.
+.TP
+\f3mincore\f1
+Dumps a list of pages or ranges of pages that are currently in core,
+for the current memory mapping.
+
+.SH OTHER COMMANDS
.TP
-\f3stat\f1 [ \f2-v\f1 ]
+\f3print\f1
+Display a list of all open files and memory mapped regions.
+The current file and current mapping are distinguishable from
+any others.
+.TP
+\f3p\f1
+See the \f3print\f1 command.
+.TP
+\f3quit\f1
+Exit \f2xfs_io\f1.
+.TP
+\f3q\f1
+See the \f3quit\f1 command.
+.TP
+\f3lsattr\f1
+List extended inode flags on the currently open file.
+.TP
+\f3chattr\f1 [ \f2+/\-riasAd\f1 ]
+Change extended inode flags on the currently open file.
+.TP
+\f3freeze\f1
+Suspend all write I/O requests to the filesystem of the current file.
+Only available in expert mode and requires privileges.
+.TP
+\f3thaw\f1
+Undo the effects of a filesystem freeze operation.
+Only available in expert mode and requires privileges.
+.TP
+\f3inject\f1 [ \f2tag\f1 ]
+Inject errors into a filesystem to observe filesystem behavior at
+specific points under adverse conditions.
+Without an argument, displays the list of error tags available.
+Only available in expert mode and requires privileges.
+.TP
+\f3resblks\f1 [ \f2blocks\f1 ]
+Get and/or set count of reserved filesystem blocks using the
+XFS_IOC_GET_RESBLKS or XFS_IOC_SET_RESBLKS system calls,
+as described in \f2xfs\f1(5).
+Note \-\- this can be useful for exercising out of space behavior.
+Only available in expert mode and requires privileges.
+.TP
+\f3shutdown\f1 [ \f2\-f\f1 ]
+Force the filesystem to shutdown (with or without flushing the log).
+Only available in expert mode and requires privileges.
+.TP
+\f3stat\f1 [ \f2\-v\f1 ]
Selected statistics from \f2stat\f1(2) and the XFS_IOC_GETXATTR
-system call from \f2xfs\f1(5) on the currently open file.
+system call from \f2xfs\f1(5) on the current file.
If the \f2-v\f1 option is specified, the atime (last access), mtime
(last modify), and ctime (last change) timestamps are also displayed.
.TP
\f3statfs\f1
Selected statistics from \f2statfs\f1(2) and the XFS_IOC_FSGEOMETRY
-system call from \f2xfs\f1(5) on the filesystem where the currently
-open file resides.
-.TP
-\f3truncate\f1 \f2offset\f1
-Truncates the current file at the given offset using \f2ftruncate\f1(2).
-.TP
-\f3w\f1
-See the \f3pwrite\f1 command.
+system call from \f2xfs\f1(5) on the filesystem where the current
+file resides.
+
.SH SEE ALSO
fdatasync(2),
fstat(2),
fsync(2),
ftruncate(2),
mkfs.xfs(8),
+mmap(2),
open(2),
pread(2),
pwrite(2),