From: Nathan Scott Date: Thu, 25 Mar 2004 03:48:10 +0000 (+0000) Subject: xfs_io tweaks - support multiple files and memory mapped IO, amongst others. X-Git-Tag: v2.7.0~119 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=48c46ee3d5d5237b7d4ddafbeac7513e86753396;p=thirdparty%2Fxfsprogs-dev.git xfs_io tweaks - support multiple files and memory mapped IO, amongst others. --- diff --git a/Makefile b/Makefile index 947231421..72a1ddc84 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # -# 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 @@ -44,7 +44,7 @@ LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \ 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) diff --git a/VERSION b/VERSION index da8e5113f..b0079586f 100644 --- a/VERSION +++ b/VERSION @@ -3,5 +3,5 @@ # PKG_MAJOR=2 PKG_MINOR=6 -PKG_REVISION=7 +PKG_REVISION=8 PKG_BUILD=1 diff --git a/debian/changelog b/debian/changelog index 00fce9dcf..843729d8b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -xfsprogs (2.6.7-1) unstable; urgency=low +xfsprogs (2.6.8-1) unstable; urgency=low * New upstream release. - -- Nathan Scott Fri, 19 Mar 2004 13:53:16 +1100 + -- Nathan Scott Thu, 25 Mar 2004 14:29:13 +1100 xfsprogs (2.6.5-1) unstable; urgency=low diff --git a/doc/CHANGES b/doc/CHANGES index a2fde188f..c38f728ff 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,3 +1,12 @@ +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. diff --git a/freeze/xfs_freeze.c b/freeze/xfs_freeze.c deleted file mode 100644 index 63973fa96..000000000 --- a/freeze/xfs_freeze.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 - -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; -} diff --git a/io/Makefile b/io/Makefile index 96251738e..332da52da 100644 --- a/io/Makefile +++ b/io/Makefile @@ -1,5 +1,5 @@ # -# 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 @@ -33,14 +33,20 @@ 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) @@ -60,4 +66,5 @@ install: default $(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: diff --git a/io/bmap.c b/io/bmap.c index 0eef45c87..1fa5060f7 100644 --- a/io/bmap.c +++ b/io/bmap.c @@ -1,5 +1,5 @@ /* - * 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 @@ -33,16 +33,10 @@ #include #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) { @@ -123,24 +117,26 @@ bmap_f( 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; } @@ -199,7 +195,7 @@ bmap_f( 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) { @@ -207,7 +203,7 @@ bmap_f( } 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; @@ -221,12 +217,12 @@ bmap_f( /* 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; @@ -245,12 +241,12 @@ bmap_f( } 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, @@ -430,6 +426,7 @@ bmap_init(void) 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; diff --git a/io/command.c b/io/command.c index 5c1b27e98..2b89807b4 100644 --- a/io/command.c +++ b/io/command.c @@ -33,6 +33,7 @@ #include #include "command.h" #include "init.h" +#include "io.h" cmdinfo_t *cmdtab; int ncmds; @@ -53,6 +54,14 @@ add_command( 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, @@ -67,10 +76,20 @@ command( 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) @@ -109,13 +128,19 @@ void 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(); } diff --git a/io/command.h b/io/command.h index 5c5e60468..7562af1d9 100644 --- a/io/command.h +++ b/io/command.h @@ -35,6 +35,10 @@ 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; @@ -42,7 +46,7 @@ typedef struct cmdinfo { int argmin; int argmax; int canpush; - int foreign; + int flags; const char *args; const char *oneline; helpfunc_t help; @@ -52,27 +56,29 @@ extern cmdinfo_t *cmdtab; 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); diff --git a/io/fadvise.c b/io/fadvise.c new file mode 100644 index 000000000..04508148e --- /dev/null +++ b/io/fadvise.c @@ -0,0 +1,162 @@ +/* + * 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 +#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); +} diff --git a/io/file.c b/io/file.c new file mode 100644 index 000000000..0d5256a83 --- /dev/null +++ b/io/file.c @@ -0,0 +1,124 @@ +/* + * 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 +#include +#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); +} diff --git a/io/freeze.c b/io/freeze.c new file mode 100644 index 000000000..03f300438 --- /dev/null +++ b/io/freeze.c @@ -0,0 +1,97 @@ +/* + * 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 +#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); + } +} diff --git a/io/fsync.c b/io/fsync.c index 9947882ed..ab77bdd79 100644 --- a/io/fsync.c +++ b/io/fsync.c @@ -33,6 +33,7 @@ #include #include "command.h" #include "init.h" +#include "io.h" static cmdinfo_t fsync_cmd; static cmdinfo_t fdatasync_cmd; @@ -42,7 +43,7 @@ fsync_f( int argc, char **argv) { - if (fsync(fdesc) < 0) { + if (fsync(file->fd) < 0) { perror("fsync"); return 0; } @@ -54,7 +55,7 @@ fdatasync_f( int argc, char **argv) { - if (fdatasync(fdesc) < 0) { + if (fdatasync(file->fd) < 0) { perror("fdatasync"); return 0; } @@ -67,14 +68,14 @@ fsync_init(void) 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"); diff --git a/io/help.c b/io/help.c index b62118d2f..68ac15c03 100644 --- a/io/help.c +++ b/io/help.c @@ -32,6 +32,7 @@ #include #include "command.h" +#include "io.h" static cmdinfo_t help_cmd; static void help_onecmd(const char *cmd, const cmdinfo_t *ct); @@ -102,7 +103,7 @@ help_init(void) 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"); diff --git a/io/init.c b/io/init.c index 6eb18877b..3b7db9ca7 100644 --- a/io/init.c +++ b/io/init.c @@ -31,23 +31,14 @@ */ #include -#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; @@ -56,7 +47,7 @@ void 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); } @@ -66,18 +57,21 @@ init( 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++; @@ -88,29 +82,40 @@ init( } 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); @@ -120,14 +125,14 @@ init( } } - 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(); } diff --git a/io/init.h b/io/init.h index 3fe53ffb7..c01975599 100644 --- a/io/init.h +++ b/io/init.h @@ -30,17 +30,7 @@ * 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; diff --git a/io/inject.c b/io/inject.c new file mode 100644 index 000000000..c06515228 --- /dev/null +++ b/io/inject.c @@ -0,0 +1,176 @@ +/* + * 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 +#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); +} diff --git a/io/input.c b/io/input.c index 817b46666..982769220 100644 --- a/io/input.c +++ b/io/input.c @@ -1,5 +1,5 @@ /* - * 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 @@ -33,6 +33,7 @@ #include #include "input.h" #include "init.h" +#include "io.h" #if defined(ENABLE_READLINE) # include @@ -143,6 +144,20 @@ doneline( 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) diff --git a/io/input.h b/io/input.h index d51536217..ad79e0b31 100644 --- a/io/input.h +++ b/io/input.h @@ -1,5 +1,5 @@ /* - * 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 @@ -33,6 +33,7 @@ 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); diff --git a/io/io.h b/io/io.h new file mode 100644 index 000000000..eb1c8516f --- /dev/null +++ b/io/io.h @@ -0,0 +1,86 @@ +/* + * 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); diff --git a/io/mmap.c b/io/mmap.c new file mode 100644 index 000000000..087c89f27 --- /dev/null +++ b/io/mmap.c @@ -0,0 +1,839 @@ +/* + * 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 +#include +#include +#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); +} diff --git a/io/open.c b/io/open.c index fe71b6bba..d27fee20a 100644 --- a/io/open.c +++ b/io/open.c @@ -34,55 +34,172 @@ #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; } @@ -93,7 +210,7 @@ openfile( 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) { @@ -113,10 +230,39 @@ openfile( 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; } @@ -125,24 +271,25 @@ open_help(void) { 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")); } @@ -152,164 +299,103 @@ open_f( 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 @@ -336,8 +422,8 @@ lsattr_f( } } - 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) { @@ -391,7 +477,7 @@ chattr_f( 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; } @@ -430,7 +516,7 @@ chattr_f( 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; } @@ -460,50 +546,6 @@ chattr_help(void) "\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, @@ -511,7 +553,7 @@ setfl_f( { 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; @@ -537,7 +579,7 @@ setfl_f( } } - if (fcntl(fdesc, F_SETFL, flags) < 0) + if (fcntl(file->fd, F_SETFL, flags) < 0) perror("fcntl(F_SETFL)"); return 0; @@ -550,19 +592,21 @@ extsize_f( { 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; } @@ -576,11 +620,9 @@ statfs_f( { 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); @@ -593,10 +635,10 @@ else 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); @@ -622,30 +664,37 @@ open_init(void) 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"); @@ -654,6 +703,7 @@ open_init(void) 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; @@ -663,6 +713,7 @@ open_init(void) 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; @@ -671,14 +722,18 @@ open_init(void) 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); } diff --git a/io/pread.c b/io/pread.c index 4fabb16a3..488b7c2a4 100644 --- a/io/pread.c +++ b/io/pread.c @@ -35,6 +35,7 @@ #include "command.h" #include "input.h" #include "init.h" +#include "io.h" static cmdinfo_t pread_cmd; @@ -46,7 +47,7 @@ pread_help(void) " 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" @@ -61,6 +62,7 @@ ssize_t buffersize; int alloc_buffer( ssize_t bsize, + int uflag, unsigned int seed) { if (bsize > buffersize) { @@ -70,14 +72,15 @@ alloc_buffer( 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) @@ -146,17 +149,11 @@ pread_f( 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); @@ -165,18 +162,19 @@ pread_f( 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]); @@ -189,11 +187,11 @@ pread_f( 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); @@ -203,7 +201,7 @@ pread_f( 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; } @@ -216,7 +214,7 @@ pread_init(void) 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; diff --git a/io/prealloc.c b/io/prealloc.c index 7c0011553..f2fe83b1a 100644 --- a/io/prealloc.c +++ b/io/prealloc.c @@ -1,5 +1,5 @@ /* - * 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 @@ -34,6 +34,7 @@ #include "command.h" #include "input.h" #include "init.h" +#include "io.h" static cmdinfo_t allocsp_cmd; static cmdinfo_t freesp_cmd; @@ -46,14 +47,17 @@ offset_length( 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; @@ -71,8 +75,8 @@ allocsp_f( 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; @@ -88,8 +92,8 @@ freesp_f( 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; @@ -105,8 +109,8 @@ resvsp_f( 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; @@ -122,8 +126,8 @@ unresvsp_f( 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; @@ -136,6 +140,7 @@ prealloc_init(void) 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"); @@ -143,6 +148,7 @@ prealloc_init(void) 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"); @@ -150,6 +156,7 @@ prealloc_init(void) 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"); @@ -159,6 +166,7 @@ prealloc_init(void) 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"); diff --git a/io/pwrite.c b/io/pwrite.c index 657b3ed15..bc8648c04 100644 --- a/io/pwrite.c +++ b/io/pwrite.c @@ -34,6 +34,7 @@ #include "command.h" #include "input.h" #include "init.h" +#include "io.h" static cmdinfo_t pwrite_cmd; @@ -45,7 +46,7 @@ pwrite_help(void) " 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" @@ -78,7 +79,7 @@ write_buffer( 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) { @@ -107,16 +108,10 @@ pwrite_f( 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); @@ -146,15 +141,15 @@ pwrite_f( 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]); @@ -167,11 +162,11 @@ pwrite_f( 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); @@ -188,7 +183,7 @@ pwrite_f( 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; @@ -202,7 +197,7 @@ pwrite_init(void) 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 = diff --git a/io/quit.c b/io/quit.c index 09d6d89ad..a6d5a9f17 100644 --- a/io/quit.c +++ b/io/quit.c @@ -49,8 +49,8 @@ quit_init(void) 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); } diff --git a/io/resblks.c b/io/resblks.c index 060d2ebfb..5d92ba31e 100644 --- a/io/resblks.c +++ b/io/resblks.c @@ -1,5 +1,5 @@ /* - * 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 @@ -34,6 +34,7 @@ #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); @@ -47,18 +48,18 @@ resblks_f( 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"), @@ -75,9 +76,11 @@ resblks_init(void) 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); } diff --git a/io/shutdown.c b/io/shutdown.c new file mode 100644 index 000000000..c9294f339 --- /dev/null +++ b/io/shutdown.c @@ -0,0 +1,79 @@ +/* + * 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 +#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); +} diff --git a/io/truncate.c b/io/truncate.c index 916df94f6..1a9b2be78 100644 --- a/io/truncate.c +++ b/io/truncate.c @@ -34,31 +34,26 @@ #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; } @@ -69,10 +64,11 @@ void 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"); diff --git a/freeze/Makefile b/io/xfs_freeze.sh similarity index 62% rename from freeze/Makefile rename to io/xfs_freeze.sh index 46291d121..98316dbf4 100644 --- a/freeze/Makefile +++ b/io/xfs_freeze.sh @@ -1,5 +1,6 @@ +#!/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 @@ -30,19 +31,45 @@ # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ # -TOPDIR = .. -include $(TOPDIR)/include/builddefs +OPTS="" +USAGE="Usage: xfs_freeze -f | -u " +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 diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 2d6a003c7..78990b6b1 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1,13 +1,13 @@ .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: @@ -17,7 +17,6 @@ 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, @@ -32,45 +31,37 @@ Create \f2file\f1 if it does not already exist. .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 @@ -78,20 +69,30 @@ operated on with a restricted command set. .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 @@ -101,7 +102,10 @@ The default blocksize is 4096 bytes. 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. @@ -109,33 +113,48 @@ 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 @@ -145,25 +164,136 @@ system call described in \f2xfs\f1(5). 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), @@ -171,6 +301,7 @@ fstatfs(2), fsync(2), ftruncate(2), mkfs.xfs(8), +mmap(2), open(2), pread(2), pwrite(2),