]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_io tweaks - support multiple files and memory mapped IO, amongst others.
authorNathan Scott <nathans@sgi.com>
Thu, 25 Mar 2004 03:48:10 +0000 (03:48 +0000)
committerNathan Scott <nathans@sgi.com>
Thu, 25 Mar 2004 03:48:10 +0000 (03:48 +0000)
31 files changed:
Makefile
VERSION
debian/changelog
doc/CHANGES
freeze/xfs_freeze.c [deleted file]
io/Makefile
io/bmap.c
io/command.c
io/command.h
io/fadvise.c [new file with mode: 0644]
io/file.c [new file with mode: 0644]
io/freeze.c [new file with mode: 0644]
io/fsync.c
io/help.c
io/init.c
io/init.h
io/inject.c [new file with mode: 0644]
io/input.c
io/input.h
io/io.h [new file with mode: 0644]
io/mmap.c [new file with mode: 0644]
io/open.c
io/pread.c
io/prealloc.c
io/pwrite.c
io/quit.c
io/resblks.c
io/shutdown.c [new file with mode: 0644]
io/truncate.c
io/xfs_freeze.sh [moved from freeze/Makefile with 62% similarity]
man/man8/xfs_io.8

index 94723142156c5e2ad71c3baecf6622fa863d1fea..72a1ddc84a9171df27dfd1c74eac979d143924ff 100644 (file)
--- 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 da8e5113f7c9511d9f4841df8166e453c94ce240..b0079586ff09109ce7715d10c57715c9ee189deb 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -3,5 +3,5 @@
 #
 PKG_MAJOR=2
 PKG_MINOR=6
-PKG_REVISION=7
+PKG_REVISION=8
 PKG_BUILD=1
index 00fce9dcf650a399c883bab97b344c3f5df11c31..843729d8beb54f2708546aba45ce353d1d6e5cf5 100644 (file)
@@ -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 <nathans@debian.org>  Fri, 19 Mar 2004 13:53:16 +1100
+ -- Nathan Scott <nathans@debian.org>  Thu, 25 Mar 2004 14:29:13 +1100
 
 xfsprogs (2.6.5-1) unstable; urgency=low
 
index a2fde188f41a7f78c4c7458323ea44e4f1567213..c38f728ffbd84689f4aa7265aea574aba06db6cc 100644 (file)
@@ -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 (file)
index 63973fa..0000000
+++ /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 <xfs/libxfs.h>
-
-char   *progname;
-
-static void
-usage(void)
-{
-       fprintf(stderr, _(
-"Usage: %s [options] mountpoint\n\n\
-Options:\n\
-       -f          freeze filesystem access\n\
-       -u          unfreeze filesystem access\n"),
-               progname);
-       exit(2);
-}
-
-int
-main(int argc, char **argv)
-{
-       int                     c;      /* current option character */
-       int                     ffd;    /* mount point file descriptor */
-       int                     fflag, uflag;
-       int                     level;
-       char                    *fname;
-
-       fflag = uflag = 0;
-       progname = basename(argv[0]);
-       setlocale(LC_ALL, "");
-       bindtextdomain(PACKAGE, LOCALEDIR);
-       textdomain(PACKAGE);
-
-       while ((c = getopt(argc, argv, "fu")) != EOF) {
-               switch (c) {
-               case 'f':
-                       fflag = 1;
-                       break;
-               case 'u':
-                       uflag = 1;
-                       break;
-               case '?':
-               default:
-                       usage();
-               }
-       }
-       if (argc - optind != 1)
-               usage();
-       if ((fflag + uflag) != 1)
-               usage();
-
-       fname = argv[optind];
-       ffd = open(fname, O_RDONLY);
-       if (ffd < 0) {
-               perror(fname);
-               return 1;
-       }
-
-       if (!platform_test_xfs_fd(ffd)) {
-               fprintf(stderr, _("%s: specified file "
-                       "[\"%s\"] is not on an XFS filesystem\n"),
-                       progname, argv[optind]);
-               exit(1);
-       }
-
-       if (fflag) {
-               level = 1;
-               if (xfsctl(fname, ffd, XFS_IOC_FREEZE, &level) < 0) {
-                       fprintf(stderr, _("%s: cannot freeze filesystem"
-                               " mounted at %s: %s\n"),
-                               progname, argv[optind], strerror(errno));
-                       exit(1);
-               }
-       }
-
-       if (uflag) {
-               if (xfsctl(fname, ffd, XFS_IOC_THAW, &level) < 0) {
-                       fprintf(stderr, _("%s: cannot unfreeze filesystem"
-                               " mounted at %s: %s\n"),
-                               progname, argv[optind], strerror(errno));
-                       exit(1);
-               }
-       }
-
-       close(ffd);
-       return 0;
-}
index 96251738e1c3f209eac37729d9c1e1ef41e4d09a..332da52dadb228a9f643a88c0a53ec4ec9d271cd 100644 (file)
@@ -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
 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:
index 0eef45c877b0cb4aa118b6a12c378dac70f673f4..1fa5060f7104f0a4b4fe8b641ef0e7b1db9b36d1 100644 (file)
--- 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
 #include <xfs/libxfs.h>
 #include "command.h"
 #include "init.h"
+#include "io.h"
 
 static cmdinfo_t bmap_cmd;
 
-static int
-usage(void)
-{
-       printf("%s %s\n", bmap_cmd.name, bmap_cmd.oneline);
-       return 0;
-}
-
 static void
 bmap_help(void)
 {
@@ -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;
index 5c1b27e98b482d6f0b2f22a7a6ae3150af7713fe..2b89807b4dab99894dd862b55405e6466f594c5d 100644 (file)
@@ -33,6 +33,7 @@
 #include <xfs/libxfs.h>
 #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();
 }
index 5c5e6046815b33e34258d609eab3f0357d75fd72..7562af1d9a53cb334254e0c704e4773c26a23e4a 100644 (file)
 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 (file)
index 0000000..0450814
--- /dev/null
@@ -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 <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t fadvise_cmd;
+
+#if !defined(__NR_fadvise64)
+# if defined(__i386__)
+#   define __NR_fadvise64 250
+# elif defined(__ia64__)
+#   define __NR_fadvise64 1234
+# elif defined(__powerpc__)
+#   define __NR_fadvise64 233
+# endif
+#endif
+
+static int
+fadvise64(int fd, off64_t offset, size_t len, int advise)
+{
+#ifdef __NR_fadvise64
+       return syscall(__NR_fadvise64, fd, offset, len, advise);
+#else
+       errno = ENOSYS; return -1;
+#endif
+}
+
+static void
+fadvise_help(void)
+{
+       printf(_(
+"\n"
+" advise the page cache about expected I/O patterns on the current file\n"
+"\n"
+" Modifies kernel page cache behaviour when operating on the current file.\n"
+" The range arguments are required by some advise commands ([*] below).\n"
+" With no arguments, the POSIX_FADV_NORMAL advice is implied.\n"
+" -d -- don't need these pages (POSIX_FADV_DONTNEED) [*]\n"
+" -n -- data will be accessed once (POSIX_FADV_NOREUSE) [*]\n"
+" -r -- expect random page references (POSIX_FADV_RANDOM)\n"
+" -s -- expect sequential page references (POSIX_FADV_SEQUENTIAL)\n"
+" -w -- will need these pages (POSIX_FADV_WILLNEED) [*]\n"
+" Notes: these interfaces are not supported in Linux kernels before 2.6.\n"
+"   NORMAL sets the default readahead setting on the file.\n"
+"   RANDOM sets the readahead setting on the file to zero.\n"
+"   SEQUENTIAL sets double the default readahead setting on the file.\n"
+"   WILLNEED and NOREUSE are equivalent, and force the maximum readahead.\n"
+"\n"));
+}
+
+static int
+fadvise_f(
+       int             argc,
+       char            **argv)
+{
+       off64_t         offset = 0;
+       size_t          length = 0;
+       int             c, range = 0, advise = POSIX_FADV_NORMAL;
+
+       while ((c = getopt(argc, argv, "dnrsw")) != EOF) {
+               switch (c) {
+               case 'd':       /* Don't need these pages */
+                       advise = POSIX_FADV_DONTNEED;
+                       range = 1;
+                       break;
+               case 'n':       /* Data will be accessed once */
+                       advise = POSIX_FADV_NOREUSE;
+                       range = 1;
+                       break;
+               case 'r':       /* Expect random page references */
+                       advise = POSIX_FADV_RANDOM;
+                       range = 0;
+                       break;
+               case 's':       /* Expect sequential page references */
+                       advise = POSIX_FADV_SEQUENTIAL;
+                       range = 0;
+                       break;
+               case 'w':       /* Will need these pages */
+                       advise = POSIX_FADV_WILLNEED;
+                       range = 1;
+                       break;
+               default:
+                       return command_usage(&fadvise_cmd);
+               }
+       }
+       if (range) {
+               unsigned int    blocksize, sectsize;
+
+               if (optind != argc - 2)
+                       return command_usage(&fadvise_cmd);
+               init_cvtnum(&blocksize, &sectsize);
+               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 (file)
index 0000000..0d5256a
--- /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 <xfs/libxfs.h>
+#include <sys/mman.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t file_cmd;
+static cmdinfo_t print_cmd;
+
+fileio_t       *filetable;
+int            filecount;
+fileio_t       *file;
+
+static void
+print_fileio(
+       fileio_t        *file,
+       int             index,
+       int             braces)
+{
+       printf(_("%c%d%c %-14s (%s,%s,%s,%s%s%s)\n"),
+               braces? '[' : ' ', index, braces? ']' : ' ', file->name,
+               file->flags & IO_FOREIGN ? _("foreign") : _("xfs"),
+               file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
+               file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
+               file->flags & IO_READONLY ? _("read-only") : _("read-write"),
+               file->flags & IO_REALTIME ? _(",real-time") : "",
+               file->flags & IO_APPEND ? _(",append-only") : "");
+}
+
+int
+filelist_f(void)
+{
+       int             i;
+
+       for (i = 0; i < filecount; i++)
+               print_fileio(&filetable[i], i, &filetable[i] == file);
+       return 0;
+}
+
+static int
+print_f(
+       int             argc,
+       char            **argv)
+{
+       filelist_f();
+       maplist_f();
+       return 0;
+}
+
+static int
+file_f(
+       int             argc,
+       char            **argv)
+{
+       int             i;
+
+       if (argc <= 1)
+               return filelist_f();
+       i = atoi(argv[1]);
+       if (i < 0 || i >= filecount) {
+               printf("value %d is out of range (0-%d)\n", i, filecount);
+       } else {
+               file = &filetable[i];
+               filelist_f();
+       }
+       return 0;
+}
+
+void
+file_init(void)
+{
+       file_cmd.name = _("file");
+       file_cmd.altname = _("f");
+       file_cmd.args = _("[N]");
+       file_cmd.cfunc = file_f;
+       file_cmd.argmin = 0;
+       file_cmd.argmax = 1;
+       file_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+       file_cmd.oneline = _("set the current file");
+
+       print_cmd.name = _("print");
+       print_cmd.altname = _("p");
+       print_cmd.cfunc = print_f;
+       print_cmd.argmin = 0;
+       print_cmd.argmax = 0;
+       print_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
+       print_cmd.oneline = _("list current open files and memory mappings");
+
+       add_command(&file_cmd);
+       add_command(&print_cmd);
+}
diff --git a/io/freeze.c b/io/freeze.c
new file mode 100644 (file)
index 0000000..03f3004
--- /dev/null
@@ -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 <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t freeze_cmd;
+static cmdinfo_t thaw_cmd;
+
+int
+freeze_f(
+       int             argc,
+       char            **argv)
+{
+       int             level = 1;
+
+       if (xfsctl(file->name, file->fd, XFS_IOC_FREEZE, &level) < 0) {
+               fprintf(stderr,
+                       _("%s: cannot freeze filesystem at %s: %s\n"),
+                       progname, file->name, strerror(errno));
+               exitcode = 1;
+               return 0;
+       }
+       return 0;
+}
+
+int
+thaw_f(
+       int             argc,
+       char            **argv)
+{
+       int             level = 1;
+
+       if (xfsctl(file->name, file->fd, XFS_IOC_THAW, &level) < 0) {
+               fprintf(stderr,
+                       _("%s: cannot unfreeze filesystem mounted at %s: %s\n"),
+                       progname, file->name, strerror(errno));
+               exitcode = 1;
+               return 0;
+       }
+       return 0;
+}
+
+void
+freeze_init(void)
+{
+       freeze_cmd.name = _("freeze");
+       freeze_cmd.cfunc = freeze_f;
+       freeze_cmd.argmin = 0;
+       freeze_cmd.argmax = 0;
+       freeze_cmd.flags = CMD_NOMAP_OK;
+       freeze_cmd.oneline = _("freeze filesystem of current file");
+
+       thaw_cmd.name = _("thaw");
+       thaw_cmd.cfunc = thaw_f;
+       thaw_cmd.argmin = 0;
+       thaw_cmd.argmax = 0;
+       thaw_cmd.flags = CMD_NOMAP_OK;
+       thaw_cmd.oneline = _("unfreeze filesystem of current file");
+
+       if (expert) {
+               add_command(&freeze_cmd);
+               add_command(&thaw_cmd);
+       }
+}
index 9947882ed5a13e9dda3eccc4e6e9b989ddf172d6..ab77bdd7915a695561f562a22324f3744411e918 100644 (file)
@@ -33,6 +33,7 @@
 #include <xfs/libxfs.h>
 #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");
 
index b62118d2fd35f9132b072d0d31dda8d53f4bd871..68ac15c03a5e185dff86bccaf034d818f406712d 100644 (file)
--- a/io/help.c
+++ b/io/help.c
@@ -32,6 +32,7 @@
 
 #include <xfs/libxfs.h>
 #include "command.h"
+#include "io.h"
 
 static cmdinfo_t help_cmd;
 static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
@@ -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");
 
index 6eb18877b438be4140332cb1497c7a45105254ca..3b7db9ca78c3ddba581111b2a4541182bb2e125b 100644 (file)
--- a/io/init.c
+++ b/io/init.c
  */
 
 #include <xfs/libxfs.h>
-#include "input.h"
 #include "command.h"
+#include "input.h"
+#include "io.h"
 
 char   *progname;
 int    exitcode;
-
-int    fdesc;
-char   *fname;
-xfs_fsop_geom_t        fgeom;
-
-int    readonly;
-int    directio;
-int    realtime;
-int    foreign;
-int    append;
-int    osync;
-int    trunc;
+int    expert;
+size_t pagesize;
 
 static int     ncmdline;
 static char    **cmdline;
@@ -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();
 }
index 3fe53ffb7b5a28210622c7378d53224ec1bfe57b..c01975599779a7e9c5b65b592eec595c06d7babf 100644 (file)
--- a/io/init.h
+++ b/io/init.h
  * 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 (file)
index 0000000..c065152
--- /dev/null
@@ -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 <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t inject_cmd;
+
+static int
+error_tag(char *name)
+{
+       static struct {
+               int     tag;
+               char    *name;
+       } *e, eflags[] = {
+#define XFS_ERRTAG_NOERROR                              0
+               { XFS_ERRTAG_NOERROR,                   "noerror" },
+#define XFS_ERRTAG_IFLUSH_1                             1
+               { XFS_ERRTAG_IFLUSH_1,                  "iflush1" },
+#define XFS_ERRTAG_IFLUSH_2                             2
+               { XFS_ERRTAG_IFLUSH_2,                  "iflush2" },
+#define XFS_ERRTAG_IFLUSH_3                             3
+               { XFS_ERRTAG_IFLUSH_3,                  "iflush3" },
+#define XFS_ERRTAG_IFLUSH_4                             4
+               { XFS_ERRTAG_IFLUSH_4,                  "iflush4" },
+#define XFS_ERRTAG_IFLUSH_5                             5
+               { XFS_ERRTAG_IFLUSH_5,                  "iflush5" },
+#define XFS_ERRTAG_IFLUSH_6                             6
+               { XFS_ERRTAG_IFLUSH_6,                  "iflush6" },
+#define XFS_ERRTAG_DA_READ_BUF                          7
+               { XFS_ERRTAG_DA_READ_BUF,               "dareadbuf" },
+#define XFS_ERRTAG_BTREE_CHECK_LBLOCK                   8
+               { XFS_ERRTAG_BTREE_CHECK_LBLOCK,        "btree_chk_lblk" },
+#define XFS_ERRTAG_BTREE_CHECK_SBLOCK                   9
+               { XFS_ERRTAG_BTREE_CHECK_SBLOCK,        "btree_chk_sblk" },
+#define XFS_ERRTAG_ALLOC_READ_AGF                       10
+               { XFS_ERRTAG_ALLOC_READ_AGF,            "readagf" },
+#define XFS_ERRTAG_IALLOC_READ_AGI                      11
+               { XFS_ERRTAG_IALLOC_READ_AGI,           "readagi" },
+#define XFS_ERRTAG_ITOBP_INOTOBP                        12
+               { XFS_ERRTAG_ITOBP_INOTOBP,             "itobp" },
+#define XFS_ERRTAG_IUNLINK                              13
+               { XFS_ERRTAG_IUNLINK,                   "iunlink" },
+#define XFS_ERRTAG_IUNLINK_REMOVE                       14
+               { XFS_ERRTAG_IUNLINK_REMOVE,            "iunlinkrm" },
+#define XFS_ERRTAG_DIR_INO_VALIDATE                     15
+               { XFS_ERRTAG_DIR_INO_VALIDATE,          "dirinovalid" },
+#define XFS_ERRTAG_BULKSTAT_READ_CHUNK                  16
+               { XFS_ERRTAG_BULKSTAT_READ_CHUNK,       "bulkstat" },
+#define XFS_ERRTAG_IODONE_IOERR                         17
+               { XFS_ERRTAG_IODONE_IOERR,              "logiodone" },
+#define XFS_ERRTAG_STRATREAD_IOERR                      18
+               { XFS_ERRTAG_STRATREAD_IOERR,           "stratread" },
+#define XFS_ERRTAG_STRATCMPL_IOERR                      19
+               { XFS_ERRTAG_STRATCMPL_IOERR,           "stratcmpl" },
+#define XFS_ERRTAG_DIOWRITE_IOERR                       20
+               { XFS_ERRTAG_DIOWRITE_IOERR,            "diowrite" },
+#define XFS_ERRTAG_BMAPIFORMAT                          21
+               { XFS_ERRTAG_BMAPIFORMAT,               "bmapifmt" },
+#define XFS_ERRTAG_MAX                                  22
+               { XFS_ERRTAG_MAX,                       NULL }
+       };
+       int     count;
+
+       /* Search for a name */
+       if (name) {
+               for (e = eflags; e->name; e++)
+                       if (strcmp(name, e->name) == 0)
+                               return e->tag;
+               return -1;
+       }
+
+       /* Dump all the names */
+       fputs("tags: [ ", stdout);
+       for (count = 0, e = eflags; e->name; e++, count++) {
+               if (count) {
+                       fputs(", ", stdout);
+                       if (!(count % 5))
+                               fputs("\n\t", stdout);
+               }
+               fputs(e->name, stdout);
+       }
+       fputs(" ]\n", stdout);
+       return 0;
+}
+
+static void
+inject_help(void)
+{
+       printf(_(
+"\n"
+" inject errors into the filesystem of the currently open file\n"
+"\n"
+" Example:\n"
+" 'inject readagf' - cause errors on allocation group freespace reads\n"
+"\n"
+" Causes the kernel to generate and react to errors within XFS, provided\n"
+" the XFS kernel code has been built with debugging features enabled.\n"
+" With no arguments, displays the list of error injection tags.\n"
+"\n"));
+}
+
+static int
+inject_f(
+       int                     argc,
+       char                    **argv)
+{
+       xfs_error_injection_t   error;
+       int                     command = XFS_IOC_ERROR_INJECTION;
+
+       if (argc == 1)
+               return error_tag(NULL);
+
+       while (--argc > 0) {
+               error.fd = file->fd;
+               if ((error.errtag = error_tag(argv[argc])) < 0) {
+                       fprintf(stderr, _("no such tag -- %s\n"), argv[1]);
+                       continue;
+               }
+               if (error.errtag == XFS_ERRTAG_NOERROR)
+                       command = XFS_IOC_ERROR_CLEARALL;
+               if ((xfsctl(file->name, file->fd, command, &error)) < 0) {
+                       perror("XFS_IOC_ERROR_INJECTION");
+                       continue;
+               }
+       }
+       return 0;
+}
+
+void
+inject_init(void)
+{
+       inject_cmd.name = _("inject");
+       inject_cmd.cfunc = inject_f;
+       inject_cmd.argmin = 0;
+       inject_cmd.argmax = -1;
+       inject_cmd.flags = CMD_NOMAP_OK;
+       inject_cmd.args = _("[tag ...]");
+       inject_cmd.oneline = _("inject errors into a filesystem");
+       inject_cmd.help = inject_help;
+
+       if (expert)
+               add_command(&inject_cmd);
+}
index 817b46666e628010f6a4025c8eecdfaf786e5cf8..9827692205606d1a445d01cb73d32e4aa3ede88b 100644 (file)
@@ -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 <xfs/libxfs.h>
 #include "input.h"
 #include "init.h"
+#include "io.h"
 
 #if defined(ENABLE_READLINE)
 # include <readline/history.h>
@@ -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)
index d5153621737d54736f794e5c399363184193a257..ad79e0b31e468af9eb8d2dedd89625d2f4c30c12 100644 (file)
@@ -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 (file)
index 0000000..eb1c851
--- /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 (file)
index 0000000..087c89f
--- /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 <xfs/libxfs.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t mmap_cmd;
+static cmdinfo_t mread_cmd;
+static cmdinfo_t msync_cmd;
+static cmdinfo_t munmap_cmd;
+static cmdinfo_t mwrite_cmd;
+static cmdinfo_t madvise_cmd;
+static cmdinfo_t mincore_cmd;
+
+mmap_region_t  *maptable;
+int            mapcount;
+mmap_region_t  *mapping;
+
+static void
+print_mapping(
+       mmap_region_t   *map,
+       int             index,
+       int             braces)
+{
+       unsigned char   buffer[8] = { 0 };
+       int             i;
+
+       static struct {
+               int     prot;
+               int     mode;
+       } *p, pflags[] = {
+               { PROT_READ,    'r' },
+               { PROT_WRITE,   'w' },
+               { PROT_EXEC,    'x' },
+               { PROT_NONE,    0 }
+       };
+
+       for (i = 0, p = pflags; p->prot != PROT_NONE; i++, p++)
+               buffer[i] = (map->prot & p->prot) ? p->mode : '-';
+       printf("%c%d%c 0x%lx - 0x%lx %s  %14s (%lld : %ld)\n",
+               braces? '[' : ' ', index, braces? ']' : ' ',
+               (unsigned long)map->addr,
+               (unsigned long)(map->addr + map->length),
+               buffer, map->name ? map->name : "???",
+               (long long)map->offset, (long)map->length);
+}
+
+static void *
+check_mapping_range(
+       mmap_region_t   *map,
+       off64_t         offset,
+       size_t          length,
+       int             pagealign)
+{
+       off64_t         relative;
+
+       if (offset < mapping->offset) {
+               printf(_("offset (%lld) is before start of mapping (%lld)\n"),
+                       (long long)offset, (long long)mapping->offset);
+               return NULL;
+       }
+       relative = offset - mapping->offset;
+       if (relative > mapping->length) {
+               printf(_("offset (%lld) is beyond end of mapping (%lld)\n"),
+                       (long long)relative, (long long)mapping->offset);
+               return NULL;
+       }
+       if ((relative + length) > (mapping->offset + mapping->length)) {
+               printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"),
+                       (long long)offset, (long long)relative,
+                       (long long)mapping->offset, (long)mapping->length);
+               return NULL;
+       }
+       if (pagealign && (long)(mapping->addr + relative) % pagesize) {
+               printf(_("offset address (%p) is not page aligned\n"),
+                       mapping->addr + relative);
+               return NULL;
+       }
+
+       return mapping->addr + relative;
+}
+
+int
+maplist_f(void)
+{
+       int             i;
+
+       for (i = 0; i < mapcount; i++)
+               print_mapping(&maptable[i], i, &maptable[i] == mapping);
+       return 0;
+}
+
+static int
+mapset_f(
+       int             argc,
+       char            **argv)
+{
+       int             i;
+
+       ASSERT(argc == 2);
+       i = atoi(argv[1]);
+       if (i < 0 || i >= mapcount) {
+               printf("value %d is out of range (0-%d)\n", i, mapcount);
+       } else {
+               mapping = &maptable[i];
+               maplist_f();
+       }
+       return 0;
+}
+
+static void
+mmap_help(void)
+{
+       printf(_(
+"\n"
+" maps a range within the current file into memory\n"
+"\n"
+" Example:\n"
+" 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n"
+"\n"
+" Memory maps a range of a file for subsequent use by other xfs_io commands.\n"
+" With no arguments, mmap shows the current mappings.  The current mapping\n"
+" can be set by using the single argument form (mapping number or address).\n"
+" If two arguments are specified (a range), a new mapping is created and the\n"
+" following options are available:\n"
+" -r -- map with PROT_READ protection\n"
+" -w -- map with PROT_WRITE protection\n"
+" -x -- map with PROT_EXEC protection\n"
+" If no protection mode is specified, all are used by default.\n"
+"\n"));
+}
+
+static int
+mmap_f(
+       int             argc,
+       char            **argv)
+{
+       off64_t         offset;
+       size_t          length;
+       void            *address;
+       char            *filename;
+       int             blocksize, sectsize;
+       int             c, prot = 0;
+
+       if (argc == 1) {
+               if (mapping)
+                       return maplist_f();
+               fprintf(stderr, file ?
+                       _("no mapped regions, try 'help mmap'\n") : 
+                       _("no files are open, try 'help open'\n"));
+               return 0;
+       } else if (argc == 2) {
+               if (mapping)
+                       return mapset_f(argc, argv);
+               fprintf(stderr, file ?
+                       _("no mapped regions, try 'help mmap'\n") :
+                       _("no files are open, try 'help open'\n"));
+               return 0;
+       } else if (!file) {
+               fprintf(stderr, _("no files are open, try 'help open'\n"));
+               return 0;
+       }
+
+       while ((c = getopt(argc, argv, "rwx")) != EOF) {
+               switch (c) {
+               case 'r':
+                       prot |= PROT_READ;
+                       break;
+               case 'w':
+                       prot |= PROT_WRITE;
+                       break;
+               case 'x':
+                       prot |= PROT_EXEC;
+                       break;
+               default:
+                       return command_usage(&mmap_cmd);
+               }
+       }
+       if (!prot)
+               prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+       if (optind != argc - 2)
+               return command_usage(&mmap_cmd);
+
+       init_cvtnum(&blocksize, &sectsize);
+       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, &sectsize);
+               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, &sectsize);
+               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, &sectsize);
+               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, &sectsize);
+               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, &sectsize);
+               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);
+}
index fe71b6bba44a49a8cda634484c0b4ac5748079a0..d27fee20aa47db5395185b06e46043de4032aa0a 100644 (file)
--- a/io/open.c
+++ b/io/open.c
 #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, &sectsize);
+       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);
 }
index 4fabb16a31776f9f60f85057484f91c75d561f94..488b7c2a47ad46c0daf33609041108618818e002 100644 (file)
@@ -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, &sectsize);
+       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;
index 7c0011553ca581a1f68d026382b4604719464ab1..f2fe83b1ab3179c4d284d4df8047230ceaa3e1d6 100644 (file)
@@ -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, &sectsize);
        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");
 
index 657b3ed15422200edd8d104f4eda4f6a38ed0bca..bc8648c049fc655992e09b45a85b16873ae084bb 100644 (file)
@@ -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, &sectsize);
+       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 =
index 09d6d89adc2839cba8a006d848752e8d89dd0b83..a6d5a9f175d02a3ee3e33708d36ab284f24dcc57 100644 (file)
--- 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);
 }
index 060d2ebfb57b3a0bffe629c00a835f743d496300..5d92ba31eb10301862b462a02f8424c7ffe0379b 100644 (file)
@@ -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 (file)
index 0000000..c9294f3
--- /dev/null
@@ -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 <xfs/libxfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t shutdown_cmd;
+
+static int
+shutdown_f(
+       int             argc,
+       char            **argv)
+{
+       int             c, flag = XFS_FSOP_GOING_FLAGS_NOLOGFLUSH;
+
+       while ((c = getopt(argc, argv, "fv")) != -1) {
+               switch (c) {
+               case 'f':
+                       flag = XFS_FSOP_GOING_FLAGS_LOGFLUSH;
+                       break;
+               default:
+                       return command_usage(&shutdown_cmd);
+               }
+       }
+
+       if ((xfsctl(file->name, file->fd, XFS_IOC_GOINGDOWN, &flag)) < 0) {
+               perror("XFS_IOC_GOINGDOWN");
+               return 0;
+       }
+       return 0;
+}
+
+void
+shutdown_init(void)
+{
+       shutdown_cmd.name = _("shutdown");
+       shutdown_cmd.cfunc = shutdown_f;
+       shutdown_cmd.argmin = 0;
+       shutdown_cmd.argmax = 1;
+       shutdown_cmd.flags = CMD_NOMAP_OK;
+       shutdown_cmd.args = _("[-f]");
+       shutdown_cmd.oneline =
+               _("shuts down the filesystem where the current file resides");
+
+       if (expert)
+               add_command(&shutdown_cmd);
+}
index 916df94f6fcf33cc5149805bb314ff3ea50aed8a..1a9b2be78e4f709ed604e02a94d08fa4d3f177f6 100644 (file)
 #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, &sectsize);
        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");
similarity index 62%
rename from freeze/Makefile
rename to io/xfs_freeze.sh
index 46291d121d847a0883fbfadf9b7675fcec93bd6c..98316dbf496807b5a21bfa18883fe1d84c4dc405 100644 (file)
@@ -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
 # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 #
 
-TOPDIR = ..
-include $(TOPDIR)/include/builddefs
+OPTS=""
+USAGE="Usage: xfs_freeze -f | -u <mountpoint>"
+DIRNAME=`dirname $0`
+VERSION=false
+FREEZE=false
+THAW=false
 
-LTCOMMAND = xfs_freeze
+while getopts "fuV" c
+do
+       case $c in
+       f)      FREEZE=true;;
+       u)      THAW=true;;
+       V)      VERSION=true;;
+       \?)     echo $USAGE 1>&2
+               exit 2
+               ;;
+       esac
+done
+if $VERSION ; then
+       $DIRNAME/xfs_io -p xfs_freeze -V
+       exit 0
+fi
 
-CFILES = xfs_freeze.c
-LLDFLAGS += -static
+shift `expr $OPTIND - 1`
+if [ "$1" = "" ]; then
+       echo $USAGE 1>&2
+       exit 2
+fi
 
-default: $(LTCOMMAND)
-
-include $(BUILDRULES)
-
-install: default
-       $(INSTALL) -m 755 -d $(PKG_BIN_DIR)
-       $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR)
-install-dev:
+if $FREEZE ; then
+       $DIRNAME/xfs_io -r -p xfs_freeze -x -c "freeze" "$1"
+       status=$?
+       [ $status -ne 0 ] && exit $status
+elif $THAW ; then
+       $DIRNAME/xfs_io -r -p xfs_freeze -x -c "thaw" "$1"
+       status=$?
+       [ $status -ne 0 ] && exit $status
+else
+       echo $USAGE 1>&2
+       exit 2
+fi
+exit 0
index 2d6a003c71f4a635b46ab86a64f1dcd7bf3f5513..78990b6b12783f9c891209cb01a2533a0ead4f3f 100644 (file)
@@ -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),