aboutsummaryrefslogtreecommitdiff
path: root/sys/gnu/fs/xfs/FreeBSD
diff options
context:
space:
mode:
authorCraig Rodrigues <rodrigc@FreeBSD.org>2005-12-12 01:04:32 +0000
committerCraig Rodrigues <rodrigc@FreeBSD.org>2005-12-12 01:04:32 +0000
commit93d9c69ff4fe2edfb9a52bcb52732ae39a504eeb (patch)
tree8ac52e2fe37d3790aa9ac8fc061d5c395bc1b946 /sys/gnu/fs/xfs/FreeBSD
parentc84b7832a2bf073724a5c7d1ca21cbf5d0d10ad9 (diff)
downloadsrc-93d9c69ff4fe2edfb9a52bcb52732ae39a504eeb.tar.gz
src-93d9c69ff4fe2edfb9a52bcb52732ae39a504eeb.zip
Initial import of read-only support for SGI's XFS filesystem.
Contributed by: XFS for FreeBSD project
Notes
Notes: svn path=/head/; revision=153323
Diffstat (limited to 'sys/gnu/fs/xfs/FreeBSD')
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/atomic.h37
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/debug.c97
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/debug.h77
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/kdb.c63
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/kdb.h44
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/kmem.c3
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/kmem.h65
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/ktrace.c348
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/ktrace.h101
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/move.h48
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/mrlock.c49
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/mrlock.h65
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/mutex.h29
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/rwlock.h22
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/rwsem.h21
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/sema.h53
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/spin.h42
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/support.h49
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/sv.h34
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/time.h37
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/uuid.c165
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/support/uuid.h45
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_buf.c188
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_buf.h304
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_compat.h165
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_config.h38
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_cred.h46
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_dmistubs.c143
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_freebsd.h356
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_frw.c1040
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_frw.h109
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.c131
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.h49
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_globals.c71
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_iget.c973
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c1244
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_iops.h60
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_mountops.c459
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_mountops.h59
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_node.h16
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_stats.c105
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_stats.h161
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_super.c338
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_super.h134
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.c43
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.h118
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_version.h44
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_vfs.c372
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_vfs.h229
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_vnode.c210
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_vnode.h652
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c1431
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfsdmapistubs.c0
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfsquotasstubs.c0
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfsrtstubs.c0
55 files changed, 10782 insertions, 0 deletions
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/atomic.h b/sys/gnu/fs/xfs/FreeBSD/support/atomic.h
new file mode 100644
index 000000000000..f8b6c9171ddc
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/atomic.h
@@ -0,0 +1,37 @@
+#ifndef __XFS_SUPPORT_ATOMIC_H__
+
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+typedef struct {
+ volatile unsigned int val;
+} atomic_t;
+
+#define atomic_read(v) ((v)->val)
+#define atomic_set(v, i) ((v)->val = (i))
+
+#define atomic_add(i, v) atomic_add_int(&(v)->val, (i))
+#define atomic_inc(v) atomic_add_int(&(v)->val, 1)
+#define atomic_dec(v) atomic_subtract_int(&(v)->val, 1)
+#define atomic_sub(i, v) atomic_subtract_int(&(v)->val, (i))
+#define atomic_sub_and_test(i, v) (atomic_fetchadd_int(&(v)->val, (-i) == i)
+#define atomic_dec_and_test(v) (atomic_fetchadd_int(&(v)->val, -1) == 1)
+
+/*
+ * This is used for two variables in XFS, one of which is a debug trace
+ * buffer index.
+ */
+
+static __inline__ int atomicIncWithWrap(volatile unsigned int *ip, int val)
+{
+ unsigned int oldval, newval;
+
+ do {
+ oldval = *ip;
+ newval = (oldval + 1 >= val) ? 0 : oldval + 1;
+ } while (atomic_cmpset_rel_int(ip, oldval, newval) == 0);
+
+ return oldval;
+}
+
+#endif /* __XFS_SUPPORT_ATOMIC_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/debug.c b/sys/gnu/fs/xfs/FreeBSD/support/debug.c
new file mode 100644
index 000000000000..72345f0ef0b3
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/debug.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2000 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 <sys/param.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <machine/stdarg.h>
+
+#include <support/debug.h>
+
+SYSCTL_NODE(_debug, OID_AUTO, xfs, CTLFLAG_RD, 0, "XFS debug options");
+
+static int verbosity = 10;
+SYSCTL_INT(_debug_xfs, OID_AUTO, verbosity, CTLFLAG_RW, &verbosity, 0, "");
+
+#ifdef DEBUG
+
+static int doass = 1;
+SYSCTL_INT(_debug_xfs, OID_AUTO, assert, CTLFLAG_RW, &doass, 0, "");
+
+void
+assfail(char *a, char *f, int l)
+{
+ if (doass == 0) return;
+ panic("XFS assertion failed: %s, file: %s, line: %d\n", a, f, l);
+}
+
+int
+get_thread_id(void)
+{
+ return curthread->td_proc->p_pid;
+}
+
+#endif
+
+void
+cmn_err(register int level, char *fmt, ...)
+{
+ char *fp = fmt;
+ char message[256];
+ va_list ap;
+
+ if (verbosity < level)
+ return;
+
+ va_start(ap, fmt);
+ if (*fmt == '!') fp++;
+ vsprintf(message, fp, ap);
+ printf("%s\n", message);
+ va_end(ap);
+}
+
+
+void
+icmn_err(register int level, char *fmt, va_list ap)
+{
+ char message[256];
+
+ if (verbosity < level)
+ return;
+
+ vsprintf(message, fmt, ap);
+ printf("cmn_err level %d %s\n",level, message);
+}
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/debug.h b/sys/gnu/fs/xfs/FreeBSD/support/debug.h
new file mode 100644
index 000000000000..6c82c84260d2
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/debug.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2000 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/
+ */
+#ifndef __XFS_SUPPORT_DEBUG_H__
+#define __XFS_SUPPORT_DEBUG_H__
+
+#include <machine/stdarg.h>
+
+#define CE_DEBUG 7 /* debug */
+#define CE_CONT 6 /* continuation */
+#define CE_NOTE 5 /* notice */
+#define CE_WARN 4 /* warning */
+#define CE_ALERT 1 /* alert */
+#define CE_PANIC 0 /* panic */
+
+extern void icmn_err(int, char *, va_list);
+extern void cmn_err(int, char *, ...);
+
+#ifndef STATIC
+# define STATIC static
+#endif
+
+#if defined(INVARIANTS)
+# ifndef DEBUG
+# define DEBUG
+# endif
+#endif
+
+#if defined(DEBUG)
+# ifdef lint
+# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */
+# else
+# define ASSERT(EX) ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__))
+# endif /* lint */
+#else /* !DEBUG */
+# define ASSERT(x) ((void)0)
+#endif /* !DEBUG */
+
+#ifdef DEBUG
+extern void assfail(char *, char *, int);
+extern int get_thread_id(void);
+#else
+#define assfail(a, b, c) ((void)0)
+#endif
+
+#define ASSERT_ALWAYS(EX) ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__))
+#define debug_stop_all_cpus(param) /* param is "cpumask_t *" */
+
+#endif /* __XFS_SUPPORT_DEBUG_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/kdb.c b/sys/gnu/fs/xfs/FreeBSD/support/kdb.c
new file mode 100644
index 000000000000..2d3aac6f390b
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/kdb.c
@@ -0,0 +1,63 @@
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <machine/db_machdep.h>
+
+#include "opt_ddb.h"
+#ifdef DDB
+#include <ddb/ddb.h>
+#else
+#error "Must have options for KDB, DDB in kernel config"
+#endif
+
+#include <support/kdb.h>
+
+DB_SET(xfs, xfs_ddb_cmd, db_cmd_set, CS_MORE, NULL)
+{
+ db_error("No commands registered.\n");
+}
+
+
+int
+kdb_register(char *cmd, kdb_func_t func, char *usage, char *help, short minlen)
+{
+ return 0;
+}
+
+int
+kdb_unregister(char *cmd)
+{
+ return 0;
+}
+
+int
+kdbgetaddrarg(int argc, const char **argv, int *nextarg,
+ kdb_machreg_t *value, long *offset, char **name, struct pt_regs *regs)
+{
+ return 0;
+}
+
+int
+kdbnearsym(unsigned long addr, kdb_symtab_t *symtab)
+
+{
+ return 0;
+}
+
+void
+kdb_printf(const char *fmt, ...)
+{
+}
+
+int
+kdb_getarea_size(void *res, unsigned long addr, size_t size)
+{
+ return 0;
+}
+
+int
+db_putarea_size(unsigned long addr, void *res, size_t size)
+{
+ return 0;
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/kdb.h b/sys/gnu/fs/xfs/FreeBSD/support/kdb.h
new file mode 100644
index 000000000000..d85bd6de763c
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/kdb.h
@@ -0,0 +1,44 @@
+#ifndef __XFS_SUPPORT_KGDB_H__
+#define __XFS_SUPPORT_KGDB_H__
+
+#define KDB_ARGCOUNT EINVAL
+
+struct pt_regs
+{
+ int dummy;
+};
+
+#define MODULE_AUTHOR(s) static char __module_author[] = s;
+#define MODULE_DESCRIPTION(s) static char __module_description[] = s;
+#define MODULE_LICENSE(s) static char __module_license[] = s
+
+
+typedef int (*kdb_func_t)(int, const char **, const char **, struct pt_regs *);
+typedef register_t kdb_machreg_t;
+
+/*
+ * Symbol table format.
+ */
+typedef struct __ksymtab {
+ unsigned long value; /* Address of symbol */
+ const char *sym_name; /* Full symbol name, including any version */
+ unsigned long sym_start;
+ unsigned long sym_end;
+} kdb_symtab_t;
+
+extern int kdb_register(char *, kdb_func_t, char *, char *, short);
+extern int kdb_unregister(char *);
+
+extern int kdbgetaddrarg(int, const char**, int*, kdb_machreg_t *,
+ long *, char **, struct pt_regs *);
+extern int kdbnearsym(unsigned long, kdb_symtab_t *);
+extern void kdb_printf(const char *,...)
+ __attribute__ ((format (printf, 1, 2)));
+
+extern int kdb_getarea_size(void *, unsigned long, size_t);
+extern int kdb_putarea_size(unsigned long, void *, size_t);
+
+#define kdb_getarea(x,addr) kdb_getarea_size(&(x), addr, sizeof((x)))
+#define kdb_putarea(addr,x) kdb_putarea_size(addr, &(x), sizeof((x)))
+
+#endif /* __XFS_SUPPORT_KGDB_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/kmem.c b/sys/gnu/fs/xfs/FreeBSD/support/kmem.c
new file mode 100644
index 000000000000..c98e4bcb4d71
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/kmem.c
@@ -0,0 +1,3 @@
+#include <support/kmem.h>
+
+MALLOC_DEFINE(M_XFS, "XFSALLOC", "XFS memory");
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/kmem.h b/sys/gnu/fs/xfs/FreeBSD/support/kmem.h
new file mode 100644
index 000000000000..f457302c062f
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/kmem.h
@@ -0,0 +1,65 @@
+#ifndef __XFS_SUPPORT_KMEM_H__
+#define __XFS_SUPPORT_KMEM_H__
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <vm/uma.h>
+
+typedef unsigned long xfs_pflags_t;
+
+#define PFLAGS_TEST_NOIO() 0
+#define PFLAGS_TEST_FSTRANS() 0
+
+#define PFLAGS_SET_NOIO(STATEP) do { \
+} while (0)
+
+#define PFLAGS_SET_FSTRANS(STATEP) do { \
+} while (0)
+
+#define PFLAGS_RESTORE(STATEP) do { \
+} while (0)
+
+#define PFLAGS_DUP(OSTATEP, NSTATEP) do { \
+} while (0)
+
+/*
+ * memory management routines
+ */
+#define KM_SLEEP M_WAITOK
+#define KM_SLEEP_IO M_WAITOK
+#define KM_NOFS M_WAITOK
+#define KM_NOSLEEP M_NOWAIT
+#define KM_CACHEALIGN 0
+
+#define kmem_zone uma_zone
+
+typedef struct uma_zone kmem_zone_t;
+typedef struct uma_zone xfs_zone_t;
+
+#define kmem_zone_init(len, name) \
+ uma_zcreate(name, len, NULL, NULL, NULL, NULL, 0, 0)
+#define kmem_zone_free(zone, ptr) \
+ uma_zfree(zone, ptr)
+#define kmem_cache_destroy(zone) \
+ uma_zdestroy(zone)
+#define kmem_zone_alloc(zone, flg) \
+ uma_zalloc(zone, flg)
+#define kmem_zone_zalloc(zone, flg) \
+ uma_zalloc(zone, (flg) | M_ZERO)
+
+#define kmem_alloc(len, flg) \
+ malloc(len, M_XFS, flg)
+#define kmem_zalloc(len, flg) \
+ malloc(len, M_XFS, (flg) | M_ZERO)
+#define kmem_free(ptr, size) \
+ free(ptr, M_XFS)
+#define kmem_realloc(ptr, nsize, osize, flg) \
+ realloc(ptr, nsize, M_XFS, flg)
+
+MALLOC_DECLARE(M_XFS);
+
+#endif /* __XFS_SUPPORT_KMEM_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/ktrace.c b/sys/gnu/fs/xfs/FreeBSD/support/ktrace.c
new file mode 100644
index 000000000000..462a66572adc
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/ktrace.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2000-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.h>
+
+static kmem_zone_t *ktrace_hdr_zone;
+static kmem_zone_t *ktrace_ent_zone;
+static int ktrace_zentries;
+static struct mtx wrap_lock;
+
+void
+ktrace_init(int zentries)
+{
+ ktrace_zentries = zentries;
+
+ ktrace_hdr_zone = kmem_zone_init(sizeof(ktrace_t),
+ "ktrace_hdr");
+ ASSERT(ktrace_hdr_zone);
+
+ ktrace_ent_zone = kmem_zone_init(ktrace_zentries
+ * sizeof(ktrace_entry_t),
+ "ktrace_ent");
+ ASSERT(ktrace_ent_zone);
+
+ mtx_init(&wrap_lock, "xfsktr", NULL, MTX_DEF);
+}
+
+void
+ktrace_uninit(void)
+{
+ kmem_cache_destroy(ktrace_hdr_zone);
+ kmem_cache_destroy(ktrace_ent_zone);
+ mtx_destroy(&wrap_lock);
+}
+
+/*
+ * ktrace_alloc()
+ *
+ * Allocate a ktrace header and enough buffering for the given
+ * number of entries.
+ */
+ktrace_t *
+ktrace_alloc(int nentries, int sleep)
+{
+ ktrace_t *ktp;
+ ktrace_entry_t *ktep;
+
+ ktp = (ktrace_t*)kmem_zone_alloc(ktrace_hdr_zone, sleep);
+
+ if (ktp == (ktrace_t*)NULL) {
+ /*
+ * KM_SLEEP callers don't expect failure.
+ */
+ if (sleep & KM_SLEEP)
+ panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
+
+ return NULL;
+ }
+
+ /*
+ * Special treatment for buffers with the ktrace_zentries entries
+ */
+ if (nentries == ktrace_zentries) {
+ ktep = (ktrace_entry_t*)kmem_zone_zalloc(ktrace_ent_zone,
+ sleep);
+ } else {
+ ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)),
+ sleep);
+ }
+
+ if (ktep == NULL) {
+ /*
+ * KM_SLEEP callers don't expect failure.
+ */
+ if (sleep & KM_SLEEP)
+ panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
+
+ kmem_free(ktp, sizeof(*ktp));
+
+ return NULL;
+ }
+
+ spinlock_init(&(ktp->kt_lock), "kt_lock");
+
+ ktp->kt_entries = ktep;
+ ktp->kt_nentries = nentries;
+ ktp->kt_index = 0;
+ ktp->kt_rollover = 0;
+ return ktp;
+}
+
+
+/*
+ * ktrace_free()
+ *
+ * Free up the ktrace header and buffer. It is up to the caller
+ * to ensure that no-one is referencing it.
+ */
+void
+ktrace_free(ktrace_t *ktp)
+{
+ int entries_size;
+
+ if (ktp == (ktrace_t *)NULL)
+ return;
+
+ spinlock_destroy(&ktp->kt_lock);
+
+ /*
+ * Special treatment for the Vnode trace buffer.
+ */
+ if (ktp->kt_nentries == ktrace_zentries) {
+ kmem_zone_free(ktrace_ent_zone, ktp->kt_entries);
+ } else {
+ entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t));
+
+ kmem_free(ktp->kt_entries, entries_size);
+ }
+
+ kmem_zone_free(ktrace_hdr_zone, ktp);
+}
+
+
+/*
+ * Enter the given values into the "next" entry in the trace buffer.
+ * kt_index is always the index of the next entry to be filled.
+ */
+void
+ktrace_enter(
+ ktrace_t *ktp,
+ void *val0,
+ void *val1,
+ void *val2,
+ void *val3,
+ void *val4,
+ void *val5,
+ void *val6,
+ void *val7,
+ void *val8,
+ void *val9,
+ void *val10,
+ void *val11,
+ void *val12,
+ void *val13,
+ void *val14,
+ void *val15)
+{
+ int index;
+ ktrace_entry_t *ktep;
+
+ ASSERT(ktp != NULL);
+
+ /*
+ * Grab an entry by pushing the index up to the next one.
+ */
+ mtx_lock(&wrap_lock);
+ index = ktp->kt_index;
+ if (++ktp->kt_index == ktp->kt_nentries)
+ ktp->kt_index = 0;
+ mtx_unlock(&wrap_lock);
+
+ if (!ktp->kt_rollover && index == ktp->kt_nentries - 1)
+ ktp->kt_rollover = 1;
+
+ ASSERT((index >= 0) && (index < ktp->kt_nentries));
+
+ ktep = &(ktp->kt_entries[index]);
+
+ ktep->val[0] = val0;
+ ktep->val[1] = val1;
+ ktep->val[2] = val2;
+ ktep->val[3] = val3;
+ ktep->val[4] = val4;
+ ktep->val[5] = val5;
+ ktep->val[6] = val6;
+ ktep->val[7] = val7;
+ ktep->val[8] = val8;
+ ktep->val[9] = val9;
+ ktep->val[10] = val10;
+ ktep->val[11] = val11;
+ ktep->val[12] = val12;
+ ktep->val[13] = val13;
+ ktep->val[14] = val14;
+ ktep->val[15] = val15;
+}
+
+/*
+ * Return the number of entries in the trace buffer.
+ */
+int
+ktrace_nentries(
+ ktrace_t *ktp)
+{
+ if (ktp == NULL) {
+ return 0;
+ }
+
+ return (ktp->kt_rollover ? ktp->kt_nentries : ktp->kt_index);
+}
+
+/*
+ * ktrace_first()
+ *
+ * This is used to find the start of the trace buffer.
+ * In conjunction with ktrace_next() it can be used to
+ * iterate through the entire trace buffer. This code does
+ * not do any locking because it is assumed that it is called
+ * from the debugger.
+ *
+ * The caller must pass in a pointer to a ktrace_snap
+ * structure in which we will keep some state used to
+ * iterate through the buffer. This state must not touched
+ * by any code outside of this module.
+ */
+ktrace_entry_t *
+ktrace_first(ktrace_t *ktp, ktrace_snap_t *ktsp)
+{
+ ktrace_entry_t *ktep;
+ int index;
+ int nentries;
+
+ if (ktp->kt_rollover)
+ index = ktp->kt_index;
+ else
+ index = 0;
+
+ ktsp->ks_start = index;
+ ktep = &(ktp->kt_entries[index]);
+
+ nentries = ktrace_nentries(ktp);
+ index++;
+ if (index < nentries) {
+ ktsp->ks_index = index;
+ } else {
+ ktsp->ks_index = 0;
+ if (index > nentries)
+ ktep = NULL;
+ }
+ return ktep;
+}
+
+/*
+ * ktrace_next()
+ *
+ * This is used to iterate through the entries of the given
+ * trace buffer. The caller must pass in the ktrace_snap_t
+ * structure initialized by ktrace_first(). The return value
+ * will be either a pointer to the next ktrace_entry or NULL
+ * if all of the entries have been traversed.
+ */
+ktrace_entry_t *
+ktrace_next(
+ ktrace_t *ktp,
+ ktrace_snap_t *ktsp)
+{
+ int index;
+ ktrace_entry_t *ktep;
+
+ index = ktsp->ks_index;
+ if (index == ktsp->ks_start) {
+ ktep = NULL;
+ } else {
+ ktep = &ktp->kt_entries[index];
+ }
+
+ index++;
+ if (index == ktrace_nentries(ktp)) {
+ ktsp->ks_index = 0;
+ } else {
+ ktsp->ks_index = index;
+ }
+
+ return ktep;
+}
+
+/*
+ * ktrace_skip()
+ *
+ * Skip the next "count" entries and return the entry after that.
+ * Return NULL if this causes us to iterate past the beginning again.
+ */
+ktrace_entry_t *
+ktrace_skip(
+ ktrace_t *ktp,
+ int count,
+ ktrace_snap_t *ktsp)
+{
+ int index;
+ int new_index;
+ ktrace_entry_t *ktep;
+ int nentries = ktrace_nentries(ktp);
+
+ index = ktsp->ks_index;
+ new_index = index + count;
+ while (new_index >= nentries) {
+ new_index -= nentries;
+ }
+ if (index == ktsp->ks_start) {
+ /*
+ * We've iterated around to the start, so we're done.
+ */
+ ktep = NULL;
+ } else if ((new_index < index) && (index < ktsp->ks_index)) {
+ /*
+ * We've skipped past the start again, so we're done.
+ */
+ ktep = NULL;
+ ktsp->ks_index = ktsp->ks_start;
+ } else {
+ ktep = &(ktp->kt_entries[new_index]);
+ new_index++;
+ if (new_index == nentries) {
+ ktsp->ks_index = 0;
+ } else {
+ ktsp->ks_index = new_index;
+ }
+ }
+ return ktep;
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/ktrace.h b/sys/gnu/fs/xfs/FreeBSD/support/ktrace.h
new file mode 100644
index 000000000000..b566ef8fa756
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/ktrace.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_SUPPORT_KTRACE_H__
+#define __XFS_SUPPORT_KTRACE_H__
+
+#include <support/spin.h>
+
+/*
+ * Trace buffer entry structure.
+ */
+typedef struct ktrace_entry {
+ void *val[16];
+} ktrace_entry_t;
+
+/*
+ * Trace buffer header structure.
+ */
+typedef struct ktrace {
+ lock_t kt_lock; /* mutex to guard counters */
+ int kt_nentries; /* number of entries in trace buf */
+ int kt_index; /* current index in entries */
+ int kt_rollover;
+ ktrace_entry_t *kt_entries; /* buffer of entries */
+} ktrace_t;
+
+/*
+ * Trace buffer snapshot structure.
+ */
+typedef struct ktrace_snap {
+ int ks_start; /* kt_index at time of snap */
+ int ks_index; /* current index */
+} ktrace_snap_t;
+
+
+#ifdef CONFIG_XFS_TRACE
+
+extern void ktrace_init(int zentries);
+extern void ktrace_uninit(void);
+
+extern ktrace_t *ktrace_alloc(int, int);
+extern void ktrace_free(ktrace_t *);
+
+extern void ktrace_enter(
+ ktrace_t *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *,
+ void *);
+
+extern ktrace_entry_t *ktrace_first(ktrace_t *, ktrace_snap_t *);
+extern int ktrace_nentries(ktrace_t *);
+extern ktrace_entry_t *ktrace_next(ktrace_t *, ktrace_snap_t *);
+extern ktrace_entry_t *ktrace_skip(ktrace_t *, int, ktrace_snap_t *);
+
+#else
+#define ktrace_init(x) do { } while (0)
+#define ktrace_uninit() do { } while (0)
+#endif /* CONFIG_XFS_TRACE */
+
+#endif /* __XFS_SUPPORT_KTRACE_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/move.h b/sys/gnu/fs/xfs/FreeBSD/support/move.h
new file mode 100644
index 000000000000..856ec03f5ae5
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/move.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2000-2002 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/
+ */
+
+#ifndef __XFS_SUPPORT_MOVE_H__
+#define __XFS_SUPPORT_MOVE_H__
+
+#include <sys/uio.h>
+
+typedef struct iovec iovec_t;
+typedef struct uio uio_t;
+
+static __inline__ int
+uio_read(void *buf, int howmuch, struct uio *uiop)
+{
+ uiop->uio_rw = UIO_READ;
+ return uiomove(buf,howmuch,uiop);
+}
+
+#endif /* __XFS_SUPPORT_MOVE_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/mrlock.c b/sys/gnu/fs/xfs/FreeBSD/support/mrlock.c
new file mode 100644
index 000000000000..950303938a07
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/mrlock.c
@@ -0,0 +1,49 @@
+#include <sys/param.h>
+#include <support/mrlock.h>
+
+void
+_sx_xfs_destroy(struct sx *sx)
+{
+ if (sx->sx_cnt == -1)
+ sx_xunlock(sx);
+ sx_destroy(sx);
+}
+
+void
+_sx_xfs_lock(struct sx *sx, int type, const char *file, int line)
+{
+ if (type == MR_ACCESS)
+ _sx_slock(sx, file, line);
+ else if (type == MR_UPDATE)
+ _sx_sunlock(sx, file, line);
+ else
+ panic("Invalid lock type passed");
+}
+
+
+void
+_sx_xfs_unlock(struct sx *sx, const char *file, int line)
+{
+ if (_sx_xfs_xowned(sx))
+ _sx_xunlock(sx, file, line);
+ else if (_sx_xfs_sowned(sx))
+ _sx_sunlock(sx, file, line);
+ else
+ panic("lock is not locked");
+}
+
+int
+ismrlocked(mrlock_t *mrp, int type)
+{
+ if (type == MR_ACCESS)
+ return _sx_xfs_sowned(mrp); /* Read lock */
+ else if (type == MR_UPDATE)
+ return _sx_xfs_xowned(mrp); /* Write lock */
+ else if (type == (MR_UPDATE | MR_ACCESS))
+ return _sx_xfs_sowned(mrp) ||
+ _sx_xfs_xowned(mrp); /* Any type of lock held */
+ return (mrp->sx_shrd_wcnt > 0 || mrp->sx_excl_wcnt > 0);
+}
+
+
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/mrlock.h b/sys/gnu/fs/xfs/FreeBSD/support/mrlock.h
new file mode 100644
index 000000000000..4e82d4199118
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/mrlock.h
@@ -0,0 +1,65 @@
+#ifndef __XFS_SUPPORT_MRLOCK_H__
+#define __XFS_SUPPORT_MRLOCK_H__
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+
+#include <support/debug.h>
+
+/*
+ * Implement mrlocks on FreeBSD that work for XFS.
+ * Use FreeBSD sx lock and add necessary functions
+ * if additional functionality is requested
+ */
+typedef struct sx mrlock_t;
+
+#define MR_ACCESS 1
+#define MR_UPDATE 2
+
+/*
+ * Compatibility defines, not really used
+ */
+#define MRLOCK_BARRIER 0x1
+#define MRLOCK_ALLOW_EQUAL_PRI 0x8
+
+/*
+ * mraccessf/mrupdatef take flags to be passed in while sleeping;
+ * only PLTWAIT is currently supported.
+ */
+#define mrinit(lock, name) sx_init(lock, name)
+#define mrlock_init(lock, type, name, seq) sx_init(lock, name)
+#define mrfree(lock) _sx_xfs_destroy(lock)
+#define mraccessf(lock, f) sx_slock(lock)
+#define mrupdatef(lock, f) sx_xlock(lock)
+#define mraccunlock(lock) sx_sunlock(lock)
+#define mrtryaccess(lock) sx_try_slock(lock)
+#define mrtryupdate(lock) sx_try_xlock(lock)
+#define mraccess(mrp) mraccessf(mrp, 0)
+#define mrupdate(mrp) mrupdatef(mrp, 0)
+#define mrislocked_access(lock) _sx_xfs_xowned(lock)
+#define mrislocked_update(lock) _sx_xfs_sowned(lock)
+#define mrtrypromote(lock) sx_try_upgrade(lock)
+#define mrdemote(lock) sx_downgrade(lock)
+
+int ismrlocked(mrlock_t *, int);
+void _sx_xfs_lock(struct sx *sx, int type, const char *file, int line);
+void _sx_xfs_unlock(struct sx *sx, const char *file, int line);
+void _sx_xfs_destroy(struct sx *sx);
+#define _sx_xfs_xowned(lock) ((lock)->sx_cnt < 0)
+#define _sx_xfs_sowned(lock) ((lock)->sx_cnt > 0)
+
+/*
+ * Functions, not implemented in FreeBSD
+ */
+#define mrunlock(lock) \
+ _sx_xfs_unlock(lock, __FILE__, __LINE__)
+
+#define mrlock(lock, type, flags) \
+ _sx_xfs_lock(lock, type, __FILE__, __LINE__)
+
+
+
+#endif /* __XFS_SUPPORT_MRLOCK_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/mutex.h b/sys/gnu/fs/xfs/FreeBSD/support/mutex.h
new file mode 100644
index 000000000000..d9b89b3adcf3
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/mutex.h
@@ -0,0 +1,29 @@
+#ifndef __XFS_SUPPORT_MUTEX_H__
+#define __XFS_SUPPORT_MUTEX_H__
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+
+/*
+ * Map the mutex'es from IRIX to FreeBSD. Irix holds mutexes across
+ * sleeps, so on FreeBSD we have a choice of sema, sx or lockmgr
+ * to use as a underlining implemenation. Go with sx always locked
+ * in exclusive mode for now as it gets all the benefits of witness
+ * checking.
+ */
+typedef struct sx mutex_t;
+
+#define mutex_init(lock, type, name) sx_init(lock, name)
+#define mutex_lock(lock, num) sx_xlock(lock)
+#define mutex_trylock(lock) sx_try_xlock(lock)
+#define mutex_unlock(lock) sx_xunlock(lock)
+#define mutex_destroy(lock) sx_destroy(lock)
+
+/*
+ * Type for mutex_init()
+ */
+#define MUTEX_DEFAULT 0
+
+#endif /* __XFS_SUPPORT_MUTEX_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/rwlock.h b/sys/gnu/fs/xfs/FreeBSD/support/rwlock.h
new file mode 100644
index 000000000000..05f489e1e4f6
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/rwlock.h
@@ -0,0 +1,22 @@
+#ifndef __XFS_SUPPORT_RWLOCK_H__
+#define __XFS_SUPPORT_RWLOCK_H__
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+
+typedef struct sx rwlock_t;
+typedef int wait_queue_head_t;
+
+#define rwlock_init(lock) sx_init(lock, "rwlock")
+#define rwlock_destroy(lock) sx_destroy(lock)
+#define read_lock(lock) sx_slock(lock)
+#define read_unlock(lock) sx_sunlock(lock)
+#define write_lock(lock) sx_xlock(lock)
+#define write_unlock(lock) sx_xunlock(lock)
+#define rwlock_trypromote(lock) sx_try_upgrade(lock)
+#define rwlock_demote(lock) sx_downgrade(lock)
+
+
+#endif /* __XFS_SUPPORT_RWLOCK_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/rwsem.h b/sys/gnu/fs/xfs/FreeBSD/support/rwsem.h
new file mode 100644
index 000000000000..bb972327bb78
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/rwsem.h
@@ -0,0 +1,21 @@
+#ifndef __XFS_SUPPORT_RWSEM_H__
+#define __XFS_SUPPORT_RWSEM_H__
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+
+#define rw_semaphore sx
+
+#define init_rwsem(sem) sx_init(sem, "rwsem")
+#define free_rwsem(sem) sx_destroy(sem)
+#define down_read(sem) sx_slock(sem)
+#define down_read_trylock(sem) sx_try_slock(sem)
+#define down_write(sem) sx_xlock(sem)
+#define down_write_trylock(sem) sx_try_xlock(sem)
+#define up_read(sem) sx_sunlock(sem)
+#define up_write(sem) sx_xunlock(sem)
+#define downgrade_write(sem) sx_downgrade(sem)
+
+#endif /* __XFS_SUPPORT_RWSEM_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/sema.h b/sys/gnu/fs/xfs/FreeBSD/support/sema.h
new file mode 100644
index 000000000000..db7795b93d2a
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/sema.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __XFS_SUPPORT_SEMA_H__
+#define __XFS_SUPPORT_SEMA_H__
+
+#include <sys/sema.h>
+
+/*
+ * sema_t structure just maps to struct sema in FreeBSD kernel.
+ */
+
+typedef struct sema sema_t;
+
+#define init_sema(sp, val, c, d) sema_init(sp, val, c)
+#define initnsema(sp, val, name) sema_init(sp, val, name)
+#define psema(sp, b) sema_wait(sp)
+#define vsema(sp) sema_post(sp)
+#define valusema(sp) sema_value(sp)
+#define freesema(sp) sema_destroy(sp)
+#define cpsema(sp) sema_trywait(sp)
+
+#endif /* __XFS_SUPPORT_SEMA_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/spin.h b/sys/gnu/fs/xfs/FreeBSD/support/spin.h
new file mode 100644
index 000000000000..2b09be477959
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/spin.h
@@ -0,0 +1,42 @@
+#ifndef __XFS_SUPPORT_SPIN_H__
+#define __XFS_SUPPORT_SPIN_H__
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#define SPLDECL(s) register_t s
+
+/*
+ * Map the spinlocks from IRIX to FreeBSD
+ */
+#define spinlock_init(lock, name) mtx_init(lock, name, NULL, MTX_DEF)
+#define spinlock_destroy(lock) mtx_destroy(lock)
+
+/*
+ * Map lock_t from IRIX to FreeBSD mutexes
+ */
+typedef struct mtx lock_t;
+
+#define nested_spinunlock(lock) mtx_unlock(lock)
+#define nested_spinlock(lock) mtx_lock(lock)
+#define nested_spintrylock(lock) mtx_trylock(lock)
+
+#define spin_lock(lock) mtx_lock(lock)
+#define spin_unlock(lock) mtx_unlock(lock)
+
+#if LOCK_DEBUG > 0
+#define mutex_spinlock(lock) (spin_lock(lock),0)
+#else
+static __inline register_t
+mutex_spinlock(lock_t *lock) { mtx_lock(lock); return 0; }
+#endif
+
+#define mutex_spinunlock(lock,s) \
+ do { \
+ spin_unlock(lock); \
+ if (&s) {} \
+ } while (0)
+
+#endif /* __XFS_SUPPORT_SPIN_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/support.h b/sys/gnu/fs/xfs/FreeBSD/support/support.h
new file mode 100644
index 000000000000..d7804fa8b265
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/support.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000 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/
+ */
+#ifndef __XFS_SUPPORT_H__
+#define __XFS_SUPPORT_H__
+
+#include <support/types.h>
+#include <support/arch.h>
+#include <support/kmem.h>
+#include <support/mrlock.h>
+#include <support/spin.h>
+#include <support/sv.h>
+#include <support/ktrace.h>
+#include <support/mutex.h>
+#include <support/sema.h>
+#include <support/atomic.h>
+#include <support/debug.h>
+#include <support/uuid.h>
+#include <support/time.h>
+
+#endif /* __XFS_SUPPORT_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/sv.h b/sys/gnu/fs/xfs/FreeBSD/support/sv.h
new file mode 100644
index 000000000000..fa37129c6037
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/sv.h
@@ -0,0 +1,34 @@
+#ifndef __XFS_SUPPORT_SV_H__
+#define __XFS_SUPPORT_SV_H__
+
+#include <sys/condvar.h>
+
+/*
+ * Synchronisation variables
+ *
+ * parameters "pri", "svf" and "rts" are not (yet?) implemented
+ *
+ */
+
+typedef struct cv sv_t;
+
+#define init_sv(sv,type,name,flag) \
+ cv_init(sv, name)
+#define sv_init(sv,flag,name) \
+ cv_init(sv, name)
+#define sv_wait(sv, pri, lock, spl) \
+ cv_wait_unlock(sv, lock)
+#define sv_signal(sv) \
+ cv_signal(sv)
+#define sv_broadcast(sv) \
+ cv_broadcast(sv)
+#define sv_destroy(sv) \
+ cv_destroy(sv)
+
+#define SV_FIFO 0x0 /* sv_t is FIFO type */
+#define SV_LIFO 0x2 /* sv_t is LIFO type */
+#define SV_PRIO 0x4 /* sv_t is PRIO type */
+#define SV_KEYED 0x6 /* sv_t is KEYED type */
+#define SV_DEFAULT SV_FIFO
+
+#endif /* __XFS_SUPPORT_SV_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/time.h b/sys/gnu/fs/xfs/FreeBSD/support/time.h
new file mode 100644
index 000000000000..9b3a974c2431
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/time.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2000 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/
+ */
+#ifndef __XFS_SUPPORT_TIME_H__
+#define __XFS_SUPPORT_TIME_H__
+
+#define delay(ticks) DELAY(ticks)
+
+#endif /* __XFS_SUPPORT_TIME_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/uuid.c b/sys/gnu/fs/xfs/FreeBSD/support/uuid.c
new file mode 100644
index 000000000000..55344c01419c
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/uuid.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2000-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_config.h>
+#include <xfs_compat.h>
+#include <xfs_types.h>
+#include <xfs_arch.h>
+
+#include <support/uuid.h>
+#include <support/kmem.h>
+#include <support/debug.h>
+#include <support/mutex.h>
+
+static mutex_t uuid_monitor;
+static int uuid_table_size;
+static uuid_t *uuid_table;
+
+void
+uuid_init(void)
+{
+ mutex_init(&uuid_monitor, MUTEX_DEFAULT, "uuid_monitor");
+}
+
+void
+uuid_cleanup(void)
+{
+ mutex_destroy(&uuid_monitor);
+}
+
+/*
+ * uuid_getnodeuniq - obtain the node unique fields of a UUID.
+ *
+ * This is not in any way a standard or condoned UUID function;
+ * it just something that's needed for user-level file handles.
+ */
+void
+uuid_getnodeuniq(uuid_t *uuid, int fsid [2])
+{
+ char *uu = (char *)uuid;
+
+ /* on IRIX, this function assumes big-endian fields within
+ * the uuid, so we use INT_GET to get the same result on
+ * little-endian systems
+ */
+
+ fsid[0] = (INT_GET(*(u_int16_t*)(uu+8), ARCH_CONVERT) << 16) +
+ INT_GET(*(u_int16_t*)(uu+4), ARCH_CONVERT);
+ fsid[1] = INT_GET(*(u_int32_t*)(uu ), ARCH_CONVERT);
+}
+
+void
+uuid_create_nil(uuid_t *uuid)
+{
+ memset(uuid, 0, sizeof(*uuid));
+}
+
+int
+uuid_is_nil(uuid_t *uuid)
+{
+ int i;
+ char *cp = (char *)uuid;
+
+ if (uuid == NULL)
+ return 0;
+ /* implied check of version number here... */
+ for (i = 0; i < sizeof *uuid; i++)
+ if (*cp++) return 0; /* not nil */
+ return 1; /* is nil */
+}
+
+int
+uuid_equal(uuid_t *uuid1, uuid_t *uuid2)
+{
+ return memcmp(uuid1, uuid2, sizeof(uuid_t)) ? 0 : 1;
+}
+
+/*
+ * Given a 128-bit uuid, return a 64-bit value by adding the top and bottom
+ * 64-bit words. NOTE: This function can not be changed EVER. Although
+ * brain-dead, some applications depend on this 64-bit value remaining
+ * persistent. Specifically, DMI vendors store the value as a persistent
+ * filehandle.
+ */
+__uint64_t
+uuid_hash64(uuid_t *uuid)
+{
+ __uint64_t *sp = (__uint64_t *)uuid;
+
+ return sp[0] + sp[1];
+}
+
+int
+uuid_table_insert(uuid_t *uuid)
+{
+ int i, hole;
+
+ mutex_lock(&uuid_monitor, PVFS);
+ for (i = 0, hole = -1; i < uuid_table_size; i++) {
+ if (uuid_is_nil(&uuid_table[i])) {
+ hole = i;
+ continue;
+ }
+ if (uuid_equal(uuid, &uuid_table[i])) {
+ mutex_unlock(&uuid_monitor);
+ return 0;
+ }
+ }
+ if (hole < 0) {
+ uuid_table = kmem_realloc(uuid_table,
+ (uuid_table_size + 1) * sizeof(*uuid_table),
+ uuid_table_size * sizeof(*uuid_table),
+ KM_SLEEP);
+ hole = uuid_table_size++;
+ }
+ uuid_table[hole] = *uuid;
+ mutex_unlock(&uuid_monitor);
+ return 1;
+}
+
+void
+uuid_table_remove(uuid_t *uuid)
+{
+ int i;
+
+ mutex_lock(&uuid_monitor, PVFS);
+ for (i = 0; i < uuid_table_size; i++) {
+ if (uuid_is_nil(&uuid_table[i]))
+ continue;
+ if (!uuid_equal(uuid, &uuid_table[i]))
+ continue;
+ uuid_create_nil(&uuid_table[i]);
+ break;
+ }
+ ASSERT(i < uuid_table_size);
+ mutex_unlock(&uuid_monitor);
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/support/uuid.h b/sys/gnu/fs/xfs/FreeBSD/support/uuid.h
new file mode 100644
index 000000000000..d8f389ae5a22
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/support/uuid.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_SUPPORT_UUID_H__
+#define __XFS_SUPPORT_UUID_H__
+
+void uuid_init(void);
+void uuid_cleanup(void);
+void uuid_create_nil(uuid_t *uuid);
+int uuid_is_nil(uuid_t *uuid);
+int uuid_equal(uuid_t *uuid1, uuid_t *uuid2);
+void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]);
+__uint64_t uuid_hash64(uuid_t *uuid);
+int uuid_table_insert(uuid_t *uuid);
+void uuid_table_remove(uuid_t *uuid);
+
+#endif /* __XFS_SUPPORT_UUID_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_buf.c b/sys/gnu/fs/xfs/FreeBSD/xfs_buf.c
new file mode 100644
index 000000000000..ac300dbed01c
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_buf.c
@@ -0,0 +1,188 @@
+/*
+ *
+ *
+ */
+#include "xfs.h"
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_clnt.h"
+#include "xfs_mountops.h"
+#include <geom/geom.h>
+
+xfs_buf_t *
+xfs_buf_read_flags(xfs_buftarg_t *target, xfs_daddr_t blkno, size_t len, int flags)
+{
+ struct buf *bp;
+ struct g_consumer *cp;
+
+ KASSERT((target != NULL), ("got NULL buftarg_t"));
+
+ cp = target->specvp->v_bufobj.bo_private;
+ if (cp == NULL) {
+ bp = NULL;
+ goto done;
+ }
+
+ /* This restriction is in GEOM's g_io_request() */
+ if ((BBTOB(len) % cp->provider->sectorsize) != 0) {
+ printf("Read request %ld does not align with sector size: %d\n",
+ (long)BBTOB(len), cp->provider->sectorsize);
+ bp = NULL;
+ goto done;
+ }
+
+ if (bread(target->specvp, blkno, BBTOB(len), NOCRED, &bp)) {
+ printf("bread failed specvp %p blkno %qd BBTOB(len) %ld\n",
+ target->specvp, blkno, (long)BBTOB(len));
+ bp = NULL;
+ goto done;
+ }
+ if (flags & B_MANAGED)
+ bp->b_flags |= B_MANAGED;
+ xfs_buf_set_target(bp, target);
+
+done:
+ return (bp);
+}
+
+xfs_buf_t *
+xfs_buf_get_flags(xfs_buftarg_t *target, xfs_daddr_t blkno, size_t len, int flags)
+{
+ struct buf *bp = NULL;
+ KASSERT((target != NULL), ("got NULL buftarg_t"));
+ bp = getblk(target->specvp, blkno, BBTOB(len), 0, 0, 0);
+ if (bp != NULL)
+ xfs_buf_set_target(bp, target);
+ return (bp);
+}
+
+xfs_buf_t*
+xfs_buf_get_empty(size_t size, xfs_buftarg_t *target)
+{
+ struct buf *bp;
+
+ bp = geteblk(0);
+ if (bp != NULL) {
+ bp->b_bufsize = size;
+ bp->b_bcount = size;
+
+ KASSERT(BUF_REFCNT(bp) == 1,
+ ("xfs_buf_get_empty: bp %p not locked",bp));
+
+ xfs_buf_set_target(bp, target);
+ }
+ return (bp);
+}
+
+xfs_buf_t*
+xfs_buf_get_noaddr(size_t len, xfs_buftarg_t *target)
+{
+ struct buf *bp;
+ if (len >= MAXPHYS)
+ return (NULL);
+
+ bp = geteblk(len);
+ if (bp != NULL) {
+ KASSERT(BUF_REFCNT(bp) == 1,
+ ("xfs_buf_get_empty: bp %p not locked",bp));
+
+ xfs_buf_set_target(bp, target);
+ }
+
+ return (bp);
+}
+
+void
+xfs_buf_free(xfs_buf_t *bp)
+{
+ bp->b_flags |= B_INVAL;
+ BUF_KERNPROC(bp); /* ugly hack #1 */
+ if (bp->b_kvasize == 0) {
+ bp->b_saveaddr = bp->b_kvabase; /* ugly hack #2 */
+ bp->b_data = bp->b_saveaddr;
+ bp->b_bcount = 0;
+ bp->b_bufsize = 0;
+ }
+ brelse(bp);
+}
+
+void
+xfs_baread(xfs_buftarg_t *targp, xfs_daddr_t ioff, size_t isize)
+{
+ daddr_t rablkno;
+ int rabsize;
+
+ rablkno = ioff;
+ rabsize = BBTOB(isize);
+ breada(targp->specvp, &rablkno, &rabsize, 1, NOCRED);
+}
+
+void
+xfs_buf_set_target(xfs_buf_t *bp, xfs_buftarg_t *targ)
+{
+ bp->b_bufobj = &targ->specvp->v_bufobj;
+ bp->b_caller1 = targ;
+}
+
+xfs_buftarg_t *
+xfs_buf_get_target(xfs_buf_t *bp)
+{
+ return (xfs_buftarg_t *)bp->b_caller1;
+}
+
+int
+XFS_bwrite(xfs_buf_t *bp)
+{
+ int error;
+ if (bp->b_vp == NULL) {
+ error = xfs_buf_iorequest(bp);
+
+ if ((bp->b_flags & B_ASYNC) == 0) {
+ error = bufwait(bp);
+ if (BUF_REFCNT(bp) > 1)
+ BUF_UNLOCK(bp);
+ else
+ brelse(bp);
+ }
+ return (error);
+ }
+ error = bwrite(bp);
+ return (error);
+}
+
+void
+xfs_bpin(xfs_buf_t *bp)
+{
+ printf("xfs_bpin(%p)\n", bp);
+ bpin(bp);
+}
+
+void
+xfs_bunpin(xfs_buf_t *bp)
+{
+ printf("xfs_bunpin(%p)\n", bp);
+ bunpin(bp);
+}
+
+int
+xfs_ispin(xfs_buf_t *bp)
+{
+ printf("xfs_ispin(%p)\n", bp);
+ return bp->b_pin_count;
+}
+
+void
+xfs_bwait_unpin(xfs_buf_t *bp)
+{
+ printf("xfs_bwait_unpin(%p)\n", bp);
+ bunpin_wait(bp);
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_buf.h b/sys/gnu/fs/xfs/FreeBSD/xfs_buf.h
new file mode 100644
index 000000000000..54a7fc656e45
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_buf.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_BUF_H__
+#define __XFS_BUF_H__
+
+#include <sys/bio.h>
+#include <sys/buf.h>
+
+/* XXX: move this into buf.h */
+#ifndef B_MANAGED
+#define B_MANAGED B_08000000
+#endif
+
+struct xfs_buf;
+struct xfs_mount;
+struct vnode;
+
+typedef void (*xfs_buf_iodone_t)(struct xfs_buf *); /* call-back function on I/O completion */
+typedef void (*xfs_buf_relse_t)(struct xfs_buf *); /* call-back function on I/O completion */
+typedef int (*xfs_buf_bdstrat_t)(struct xfs_buf *);
+
+typedef struct xfs_buftarg {
+ struct cdev *dev;
+ struct vnode *specvp;
+} xfs_buftarg_t;
+
+typedef struct buf xfs_buf_t;
+#define xfs_buf buf
+
+/* These are just for xfs_syncsub... it sets an internal variable
+ * then passes it to VOP_FLUSH_PAGES or adds the flags to a newly gotten buf_t
+ */
+
+#define XFS_B_ASYNC B_ASYNC
+#define XFS_B_DELWRI B_DELWRI
+#define XFS_B_READ BIO_READ
+#define XFS_B_WRITE BIO_WRITE
+
+#define XFS_B_STALE B_INVAL
+#define XFS_BUF_LOCK 0
+#define XFS_BUF_TRYLOCK 0
+#define XFS_BUF_MAPPED 0
+#define BUF_BUSY 0
+
+ /* debugging routines might need this */
+#define XFS_BUF_BFLAGS(x) ((x)->b_flags)
+#define XFS_BUF_ZEROFLAGS(x) ((x)->b_flags = 0)
+#define XFS_BUF_STALE(x) ((x)->b_flags |= XFS_B_STALE)
+#define XFS_BUF_UNSTALE(x) ((x)->b_flags &= ~XFS_B_STALE)
+#define XFS_BUF_ISSTALE(x) ((x)->b_flags & XFS_B_STALE)
+#define XFS_BUF_SUPER_STALE(x) {(x)->b_flags |= XFS_B_STALE;\
+ (x)->b_flags &= ~(XFS_B_DELWRI|B_CACHE);}
+
+#define XFS_BUF_MANAGE B_MANAGED
+#define XFS_BUF_UNMANAGE(x) ((x)->b_flags &= ~B_MANAGED)
+
+#define XFS_BUF_DELAYWRITE(x) ((x)->b_flags |= XFS_B_DELWRI)
+#define XFS_BUF_UNDELAYWRITE(x) ((x)->b_flags &= ~XFS_B_DELWRI)
+#define XFS_BUF_ISDELAYWRITE(x) ((x)->b_flags & XFS_B_DELWRI)
+
+#define XFS_BUF_ERROR(x,no) xfs_buf_set_error((x), (no))
+#define XFS_BUF_GETERROR(x) xfs_buf_get_error(x)
+#define XFS_BUF_ISERROR(x) (((x)->b_ioflags & BIO_ERROR) != 0)
+
+void static __inline__
+xfs_buf_set_error(struct buf *bp, int err)
+{
+ bp->b_ioflags |= BIO_ERROR;
+ bp->b_error = err;
+}
+
+int static __inline__
+xfs_buf_get_error(struct buf *bp)
+{
+ return XFS_BUF_ISERROR(bp) ? (bp->b_error ? bp->b_error : EIO) : 0;
+}
+
+#define XFS_BUF_DONE(x) ((x)->b_flags |= B_CACHE)
+#define XFS_BUF_UNDONE(x) ((x)->b_flags &= ~B_CACHE)
+#define XFS_BUF_ISDONE(x) ((x)->b_flags & B_CACHE)
+
+#define XFS_BUF_BUSY(x) ((x)->b_flags |= BUF_BUSY)
+#define XFS_BUF_UNBUSY(x) ((x)->b_flags &= ~BUF_BUSY)
+#define XFS_BUF_ISBUSY(x) (1)
+
+#define XFS_BUF_ASYNC(x) ((x)->b_flags |= B_ASYNC)
+#define XFS_BUF_UNASYNC(x) ((x)->b_flags &= ~B_ASYNC)
+#define XFS_BUF_ISASYNC(x) ((x)->b_flags & B_ASYNC)
+
+#define XFS_BUF_FLUSH(x) ((x)->b_flags |= B_00800000)
+#define XFS_BUF_UNFLUSH(x) ((x)->b_flags &= ~B_00800000)
+#define XFS_BUF_ISFLUSH(x) ((x)->b_flags & B_00800000)
+
+#define XFS_BUF_SHUT(x) printf("XFS_BUF_SHUT not implemented yet\n")
+#define XFS_BUF_UNSHUT(x) printf("XFS_BUF_UNSHUT not implemented yet\n")
+#define XFS_BUF_ISSHUT(x) (0)
+
+#define XFS_BUF_HOLD(x) ((void)0)
+#define XFS_BUF_UNHOLD(x) ((void)0)
+#define XFS_BUF_ISHOLD(x) BUF_REFCNT(x)
+
+#define XFS_BUF_READ(x) ((x)->b_iocmd = BIO_READ)
+#define XFS_BUF_UNREAD(x) ((x)->b_iocmd = 0)
+#define XFS_BUF_ISREAD(x) ((x)->b_iocmd == BIO_READ)
+
+#define XFS_BUF_WRITE(x) ((x)->b_iocmd = BIO_WRITE)
+#define XFS_BUF_UNWRITE(x) ((x)->b_iocmd = 0)
+#define XFS_BUF_ISWRITE(x) ((x)->b_iocmd == BIO_WRITE)
+
+#define XFS_BUF_ISUNINITIAL(x) (0)
+#define XFS_BUF_UNUNINITIAL(x) (0)
+
+#define XFS_BUF_IODONE_FUNC(x) (x)->b_iodone
+#define XFS_BUF_SET_IODONE_FUNC(x, f) (x)->b_iodone = (f)
+#define XFS_BUF_CLR_IODONE_FUNC(x) (x)->b_iodone = NULL
+
+#define XFS_BUF_SET_BDSTRAT_FUNC(x, f) do { if(f != NULL) {} } while(0)
+#define XFS_BUF_CLR_BDSTRAT_FUNC(x) ((void)0)
+
+#define XFS_BUF_BP_ISMAPPED(bp) (1)
+
+#define XFS_BUF_FSPRIVATE(buf, type) \
+ ((type)(buf)->b_fsprivate1)
+#define XFS_BUF_SET_FSPRIVATE(buf, value) \
+ (buf)->b_fsprivate1 = (void *)(value)
+#define XFS_BUF_FSPRIVATE2(buf, type) \
+ ((type)(buf)->b_fsprivate2)
+#define XFS_BUF_SET_FSPRIVATE2(buf, value) \
+ (buf)->b_fsprivate2 = (void *)(value)
+#define XFS_BUF_FSPRIVATE3(buf, type) \
+ ((type)(buf)->b_fsprivate3)
+#define XFS_BUF_SET_FSPRIVATE3(buf, value) \
+ (buf)->b_fsprivate3 = (void *)(value)
+#define XFS_BUF_SET_START(buf) \
+ printf("XFS_BUF_SET_START: %s:%d\n", __FILE__, __LINE__)
+
+#define XFS_BUF_SET_BRELSE_FUNC(buf, value) \
+ do { \
+ printf("XFS_BUF_SET_BRELSE_FUNC: %s:%d\n", \
+ __FILE__, __LINE__); \
+ if (value != NULL ) {} \
+ } while(0)
+
+#define XFS_BUF_PTR(bp) (xfs_caddr_t)((bp)->b_data)
+
+static __inline xfs_caddr_t
+xfs_buf_offset(xfs_buf_t *bp, size_t offset)
+{
+ return XFS_BUF_PTR(bp) + offset;
+}
+
+#define XFS_BUF_SET_PTR(bp, val, count) \
+ do { \
+ (bp)->b_data = (val); \
+ (bp)->b_bcount = (count); \
+ } while(0)
+
+#define XFS_BUF_ADDR(bp) ((bp)->b_blkno)
+#define XFS_BUF_SET_ADDR(bp, blk) \
+ ((bp)->b_blkno = blk)
+#define XFS_BUF_OFFSET(bp) ((bp)->b_offset)
+#define XFS_BUF_SET_OFFSET(bp, off) \
+ ((bp)->b_offset = off)
+#define XFS_BUF_COUNT(bp) ((bp)->b_bcount)
+#define XFS_BUF_SET_COUNT(bp, cnt) \
+ ((bp)->b_bcount = cnt)
+#define XFS_BUF_SIZE(bp) ((bp)->b_bufsize)
+#define XFS_BUF_SET_SIZE(bp, cnt) \
+ ((bp)->b_bufsize = cnt)
+#define XFS_BUF_SET_VTYPE_REF(bp, type, ref)
+#define XFS_BUF_SET_VTYPE(bp, type)
+#define XFS_BUF_SET_REF(bp, ref)
+
+#define XFS_BUF_VALUSEMA(bp) (BUF_REFCNT(bp)? 0 : 1)
+#define XFS_BUF_CPSEMA(bp) \
+ (BUF_LOCK(bp, LK_EXCLUSIVE|LK_CANRECURSE | LK_SLEEPFAIL, NULL) == 0)
+#define XFS_BUF_PSEMA(bp,x) BUF_LOCK(bp, LK_EXCLUSIVE|LK_CANRECURSE, NULL)
+#define XFS_BUF_VSEMA(bp) BUF_UNLOCK(bp)
+#define XFS_BUF_V_IODONESEMA(bp) bdone(bp)
+
+/* setup the buffer target from a buftarg structure */
+#define XFS_BUF_SET_TARGET(bp, target) \
+ xfs_buf_set_target(bp, target)
+
+void xfs_buf_set_target(xfs_buf_t *, xfs_buftarg_t *);
+xfs_buftarg_t *xfs_buf_get_target(xfs_buf_t *);
+
+/* return the dev_t being used */
+#define XFS_BUF_TARGET(bp) xfs_buf_get_target(bp)
+#define XFS_BUFTARG_NAME(targp) devtoname((targp)->dev)
+
+#define XFS_BUF_SET_VTYPE_REF(bp, type, ref)
+#define XFS_BUF_SET_VTYPE(bp, type)
+#define XFS_BUF_SET_REF(bp, ref)
+
+#define XFS_BUF_ISPINNED(bp) xfs_ispin(bp)
+
+xfs_buf_t *
+xfs_buf_read_flags(xfs_buftarg_t *, xfs_daddr_t, size_t, int);
+
+#define xfs_buf_read(target, blkno, len, flags) \
+ xfs_buf_read_flags(target, blkno, len, \
+ XFS_BUF_LOCK | XFS_BUF_MAPPED)
+
+xfs_buf_t *
+xfs_buf_get_flags(xfs_buftarg_t *, xfs_daddr_t, size_t, int);
+
+#define xfs_buf_get(target, blkno, len, flags) \
+ xfs_buf_get_flags(target, blkno, len, \
+ XFS_BUF_LOCK | XFS_BUF_MAPPED)
+
+#define xfs_bdwrite(mp, bp) bdwrite(bp)
+/*
+ { ((bp)->b_vp == NULL) ? (bp)->b_bdstrat = xfs_bdstrat_cb: 0; \
+ (bp)->b_fsprivate3 = (mp); bdwrite(bp);}
+*/
+#define xfs_bawrite(mp, bp) bawrite(bp)
+/*
+ { ((bp)->b_vp == NULL) ? (bp)->b_bdstrat = xfs_bdstrat_cb: 0; \
+ (bp)->b_fsprivate3 = (mp); bawrite(bp);}
+*/
+
+#define xfs_buf_relse(bp) brelse(bp)
+#define xfs_bp_mapin(bp) bp_mapin(bp)
+#define xfs_xfsd_list_evict(x) _xfs_xfsd_list_evict(x)
+#define xfs_buftrace(x,y) CTR2(KTR_BUF, "%s bp %p flags %X", bp, bp->b_flags)
+#define xfs_biodone(bp) bufdone_finish(bp)
+
+#define xfs_incore(xfs_buftarg,blkno,len,lockit) \
+ incore(&xfs_buftarg->specvp->v_bufobj, blkno);
+
+#define xfs_biomove(pb, off, len, data, rw) \
+ panic("%s:%d: xfs_biomove NI", __FILE__, __LINE__)
+
+#define xfs_biozero(pb, off, len) \
+ panic("%s:%d: xfs_biozero NI", __FILE__, __LINE__)
+
+/* already a function xfs_bwrite... fix this */
+#define XFS_bdwrite(bp) bdwrite(bp)
+#define xfs_iowait(bp) bufwait(bp)
+
+#define xfs_binval(buftarg) printf("binval(buftarg.dev) NI\n")
+#define XFS_bflush(buftarg) printf("bflush(buftarg.dev) NI\n")
+
+#define XFS_bdstrat(bp) printf("XFS_bdstrat NI\n")
+
+#define xfs_incore_relse(buftarg,delwri_only,wait) \
+ printf("incore_relse(buftarg.dev,delwri_only,wait) NI\n")
+
+#define xfs_incore_match(buftarg,blkno,len,field,value) \
+ printf("incore_match(buftarg.dev,blkno,len,field,value) NI \n")
+
+void xfs_baread(xfs_buftarg_t *targp, xfs_daddr_t ioff, size_t isize);
+
+extern void pdflush(struct vnode *, uint64_t);
+#define XFS_pdflush(vnode,flags) \
+ pdflush(vnode,flags)
+
+struct xfs_mount;
+
+int XFS_bwrite(xfs_buf_t *bp);
+xfs_buf_t* xfs_buf_get_empty(size_t, xfs_buftarg_t *targ);
+xfs_buf_t* xfs_buf_get_noaddr(size_t, xfs_buftarg_t *targ);
+void xfs_buf_free(xfs_buf_t *);
+int xfs_buf_iorequest(struct xfs_buf *bp);
+
+void XFS_freerbuf(xfs_buf_t *bp);
+void XFS_nfreerbuf(xfs_buf_t *bp);
+
+void xfs_bpin(xfs_buf_t *bp);
+void xfs_bunpin(xfs_buf_t *bp);
+int xfs_ispin(xfs_buf_t *bp);
+void xfs_bwait_unpin(xfs_buf_t *bp);
+
+#endif
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h b/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h
new file mode 100644
index 000000000000..d89e38b1593c
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h
@@ -0,0 +1,165 @@
+#ifndef __XFS_COMPAT_H__
+#define __XFS_COMPAT_H__
+
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <sys/limits.h>
+#include <sys/uuid.h>
+#include <sys/conf.h>
+#include <sys/sbuf.h>
+#include <sys/stat.h>
+#include <sys/ioccom.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+#include <sys/ktr.h>
+#include <sys/kdb.h>
+
+#ifdef _KERNEL
+#define __KERNEL__
+#endif
+
+#define printk printf
+
+#define MAJOR(x) major(x)
+#define MINOR(x) minor(x)
+
+/*
+ * SYSV compatibility types missing in FreeBSD.
+ */
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+
+/*
+ * Additional type declarations for XFS.
+ */
+typedef signed char __s8;
+typedef unsigned char __u8;
+typedef signed short int __s16;
+typedef unsigned short int __u16;
+typedef signed int __s32;
+typedef unsigned int __u32;
+typedef signed long long int __s64;
+typedef unsigned long long int __u64;
+
+/*
+ * Linux types with direct FreeBSD conterparts
+ */
+typedef off_t loff_t;
+typedef struct timespec timespec_t;
+typedef struct uuid uuid_t;
+typedef struct fid fid_t;
+typedef dev_t os_dev_t;
+
+/*
+ * Linux block devices are device vnodes in FreeBSD.
+ */
+#define block_device vnode
+
+/*
+ * Get the current CPU ID.
+ */
+#define smp_processor_id() PCPU_GET(cpuid)
+
+/*
+ * FreeBSD does not have BITS_PER_LONG defined.
+ */
+#if defined(LONG_BIT)
+#define BITS_PER_LONG LONG_BIT
+#elif defined(__i386__)
+#define BITS_PER_LONG 32
+#endif
+
+/*
+ * boolean_t is enum on Linux, int on FreeBSD.
+ * Provide value defines.
+ */
+#define B_FALSE 0
+#define B_TRUE 1
+
+/*
+ * GCC 3.x static branch prediction hints
+ */
+#if __GNUC__ < 3
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#ifndef likely
+#define likely(x) __builtin_expect((x), 1)
+#endif
+
+#ifndef unlikely
+#define unlikely(x) __builtin_expect((x), 0)
+#endif
+
+/*
+ * ANSI and GCC extension keywords compatibity
+ */
+#ifndef inline
+#define inline __inline__
+#endif
+
+#ifndef asm
+#define asm __asm
+#endif
+
+#ifndef typeof
+#define typeof __typeof
+#endif
+
+/*
+ * Miscellaneous limit constants
+ */
+#define MAX_LFS_FILESIZE 0x7fffffffffffffffLL
+
+/*
+ * Map simple functions to their FreeBSD kernel equivalents
+ */
+#ifndef copy_to_user
+#define copy_to_user(dst, src, len) copyout((src), (dst), (len))
+#endif
+
+#ifndef copy_from_user
+#define copy_from_user(dst, src, len) copyin((src), (dst), (len))
+#endif
+
+#ifndef memmove
+#define memmove(dst, src, len) bcopy((src), (dst), (len))
+#endif
+
+#ifndef barrier
+#define barrier() __asm__ __volatile__("": : :"memory")
+#endif
+
+/*
+ * Map simple global vairables to FreeBSD kernel equivalents
+ */
+#if !defined(xfs_physmem)
+#define xfs_physmem physmem
+#endif
+
+#ifndef HZ
+#define HZ hz
+#endif
+
+/*
+ * These should be implemented properly for all architectures
+ * we want to support.
+ */
+#define get_unaligned(ptr) (*(ptr))
+#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+/*
+ * Linux type-safe min/max macros.
+ */
+#define min_t(type,x,y) MIN((x),(y))
+#define max_t(type,x,y) MAX((x),(y))
+
+
+/*
+ * Cedentials manipulation.
+ */
+#define current_fsuid(credp) (credp)->cr_uid
+#define current_fsgid(credp) (credp)->cr_groups[0]
+
+#endif /* __XFS_COMPAT_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_config.h b/sys/gnu/fs/xfs/FreeBSD/xfs_config.h
new file mode 100644
index 000000000000..a115f5438e8a
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_config.h
@@ -0,0 +1,38 @@
+#ifndef __XFS_CONFIG_H__
+#define __XFS_CONFIG_H__
+
+#define HAVE_FID 1
+/*
+ * Linux config variables, harcoded to values desirable for FreeBSD.
+ */
+#define CONFIG_SYSCTL 1
+#define CONFIG_LBD 1
+#define CONFIG_XFS_TRACE 0
+
+/*
+ * Tracing.
+ */
+#if CONFIG_XFS_TRACE == 1
+#define XFS_ALLOC_TRACE 1
+#define XFS_ALLOC_TRACE 1
+#define XFS_ATTR_TRACE 1
+#define XFS_BLI_TRACE 1
+#define XFS_BMAP_TRACE 1
+#define XFS_BMBT_TRACE 1
+#define XFS_DIR_TRACE 1
+#define XFS_DIR2_TRACE 1
+#define XFS_DQUOT_TRACE 1
+#define XFS_ILOCK_TRACE 1
+#define XFS_LOG_TRACE 1
+#define XFS_RW_TRACE 1
+#endif
+
+/*
+ * XFS config defines.
+ */
+#define XFS_BIG_BLKNOS 1
+#define XFS_BIG_INUMS 0
+
+#undef XFS_STATS_OFF
+
+#endif /* __XFS_CONFIG_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_cred.h b/sys/gnu/fs/xfs/FreeBSD/xfs_cred.h
new file mode 100644
index 000000000000..bc599776e66d
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_cred.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2002 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/
+ */
+#ifndef __XFS_CRED_H__
+#define __XFS_CRED_H__
+
+#include <sys/ucred.h>
+/*
+ * struct cred is struct ucred on FreeBSD
+ */
+typedef struct ucred cred_t;
+
+#define cred ucred
+
+#define capable(cap) (1)
+#define capable_cred(cr, cap) (1)
+
+#endif /* __XFS_CRED_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_dmistubs.c b/sys/gnu/fs/xfs/FreeBSD/xfs_dmistubs.c
new file mode 100644
index 000000000000..746747efe7cc
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_dmistubs.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2000 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.
+ *
+ * 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.h"
+
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+
+static int nopkg(void);
+
+static __inline int
+nopkg()
+{
+ return (ENOSYS);
+}
+
+int
+dmapi_init (void)
+{
+ return (0);
+}
+
+void
+dmapi_uninit (void)
+{
+}
+
+int dm_data_event(void);
+int
+dm_data_event (void)
+{
+ return nopkg();
+}
+
+int dm_namesp_event(void);
+int
+dm_namesp_event (void)
+{
+ return nopkg();
+}
+
+/* The following stubs are for routines needed for the X/Open
+ * version of DMAPI.
+ */
+int xfs_dm_mount(xfs_vfs_t *, xfs_vnode_t *, char *, char *);
+int
+xfs_dm_mount(
+ xfs_vfs_t *vfsp,
+ xfs_vnode_t *mvp,
+ char *dir_name,
+ char *fsname)
+{
+ return nopkg();
+}
+
+int
+dm_send_destroy_event(bhv_desc_t *bdp, dm_right_t vp_right);
+int
+dm_send_destroy_event(bhv_desc_t *bdp, dm_right_t vp_right)
+{
+ return nopkg();
+}
+
+int
+dm_send_mount_event(xfs_vfs_t *vfsp, dm_right_t vfsp_right, bhv_desc_t *bdp,
+ dm_right_t vp_right, bhv_desc_t *rootbdp, dm_right_t rootvp_right,
+ char *name1, char *name2);
+int
+dm_send_mount_event(xfs_vfs_t *vfsp, dm_right_t vfsp_right, bhv_desc_t *bdp,
+ dm_right_t vp_right, bhv_desc_t *rootbdp, dm_right_t rootvp_right,
+ char *name1, char *name2)
+{
+ return nopkg();
+}
+
+
+int
+dm_send_namesp_event(dm_eventtype_t event, bhv_desc_t *bdp1,
+ dm_right_t vp1_right, bhv_desc_t *bdp2, dm_right_t vp2_right,
+ char *name1, char *name2, mode_t mode, int retcode, int flags);
+int
+dm_send_namesp_event(dm_eventtype_t event, bhv_desc_t *bdp1,
+ dm_right_t vp1_right, bhv_desc_t *bdp2, dm_right_t vp2_right,
+ char *name1, char *name2, mode_t mode, int retcode, int flags)
+{
+ return nopkg();
+}
+
+
+void
+dm_send_unmount_event(xfs_vfs_t *vfsp, xfs_vnode_t *vp, dm_right_t vfsp_right,
+ mode_t mode, int retcode, int flags);
+void
+dm_send_unmount_event(xfs_vfs_t *vfsp, xfs_vnode_t *vp, dm_right_t vfsp_right,
+ mode_t mode, int retcode, int flags)
+{
+}
+
+
+int
+dm_vp_to_handle (xfs_vnode_t *vp, xfs_handle_t *handlep);
+int
+dm_vp_to_handle (xfs_vnode_t *vp, xfs_handle_t *handlep)
+{
+ return nopkg();
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd.h b/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd.h
new file mode 100644
index 000000000000..d7a30d6ecd0d
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_FREEBSD__
+#define __XFS_FREEBSD__
+
+#include <xfs_config.h>
+#include <xfs_compat.h>
+
+/*
+ * Some types are conditional depending on the target system.
+ * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits.
+ * XFS_BIG_INUMS needs the VFS inode number to be 64 bits, as well
+ * as requiring XFS_BIG_BLKNOS to be set.
+ */
+#define XFS_BIG_BLKNOS 1
+#define XFS_BIG_INUMS 0
+
+#include <xfs_types.h>
+#include <xfs_arch.h>
+
+#include <support/atomic.h>
+#include <support/kmem.h>
+#include <support/mrlock.h>
+#include <support/spin.h>
+#include <support/sv.h>
+#include <support/ktrace.h>
+#include <support/mutex.h>
+#include <support/rwsem.h>
+#include <support/rwlock.h>
+#include <support/sema.h>
+#include <support/debug.h>
+#include <support/move.h>
+#include <support/uuid.h>
+#include <support/time.h>
+
+#include <xfs_behavior.h>
+#include <xfs_cred.h>
+#include <xfs_vfs.h>
+#include <xfs_vnode.h>
+#include <xfs_stats.h>
+#include <xfs_sysctl.h>
+#include <xfs_iops.h>
+#include <xfs_super.h>
+#include <xfs_fs_subr.h>
+#include <xfs_buf.h>
+#include <xfs_frw.h>
+#include <xfs_log.h>
+
+/*
+ * Feature macros (disable/enable)
+ */
+#undef HAVE_REFCACHE /* Do not use refcache. */
+#undef HAVE_SENDFILE /* sendfile(2) is available in FreeBSD. */
+
+#ifndef EVMS_MAJOR
+#define EVMS_MAJOR 117
+#endif
+
+#define xfs_refcache_size xfs_params.refcache_size.val
+#define xfs_refcache_purge_count xfs_params.refcache_purge.val
+#define restricted_chown xfs_params.restrict_chown.val
+#define irix_sgid_inherit xfs_params.sgid_inherit.val
+#define irix_symlink_mode xfs_params.symlink_mode.val
+#define xfs_panic_mask xfs_params.panic_mask.val
+#define xfs_error_level xfs_params.error_level.val
+#define xfs_syncd_interval xfs_params.sync_interval.val
+#define xfs_probe_dmapi xfs_params.probe_dmapi.val
+#define xfs_probe_ioops xfs_params.probe_ioops.val
+#define xfs_probe_quota xfs_params.probe_quota.val
+#define xfs_stats_clear xfs_params.stats_clear.val
+#define xfs_inherit_sync xfs_params.inherit_sync.val
+#define xfs_inherit_nodump xfs_params.inherit_nodump.val
+#define xfs_inherit_noatime xfs_params.inherit_noatim.val
+#define xfs_flush_interval xfs_params.flush_interval.val
+#define xfs_age_buffer xfs_params.age_buffer.val
+#define xfs_io_bypass xfs_params.io_bypass.val
+
+#define current_cpu() smp_processor_id()
+#define current_pid() (curthread->td_proc->p_pid)
+
+#define NBPP PAGE_SIZE
+#define DPPSHFT (PAGE_SHIFT - 9)
+#define NDPP (1 << (PAGE_SHIFT - 9))
+#define dtop(DD) (((DD) + NDPP - 1) >> DPPSHFT)
+#define dtopt(DD) ((DD) >> DPPSHFT)
+#define dpoff(DD) ((DD) & (NDPP-1))
+
+#define NBBY 8 /* number of bits per byte */
+#define NBPC PAGE_SIZE /* Number of bytes per click */
+#define BPCSHIFT PAGE_SHIFT /* LOG2(NBPC) if exact */
+
+/*
+ * Size of block device i/o is parameterized here.
+ * Currently the system supports page-sized i/o.
+ */
+#define BLKDEV_IOSHIFT BPCSHIFT
+#ifndef BLKDEV_IOSIZE
+#define BLKDEV_IOSIZE (1<<BLKDEV_IOSHIFT)
+#else
+# if NBPC != BLKDEV_IOSIZE
+# error Wrong BLKDEV_IOSIZE
+# endif
+#endif
+/* number of BB's per block device block */
+#define BLKDEV_BB BTOBB(BLKDEV_IOSIZE)
+
+/* bytes to clicks */
+#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT)
+#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT)
+#define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT)
+#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))>>IO_BPCSHIFT)
+#define io_btoct(x) ((__psunsigned_t)(x)>>IO_BPCSHIFT)
+
+/* off_t bytes to clicks */
+#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT)
+#define offtoct(x) ((xfs_off_t)(x)>>BPCSHIFT)
+
+/* clicks to off_t bytes */
+#define ctooff(x) ((xfs_off_t)(x)<<BPCSHIFT)
+
+/* clicks to bytes */
+#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT)
+#define ctob64(x) ((__uint64_t)(x)<<BPCSHIFT)
+#define io_ctob(x) ((__psunsigned_t)(x)<<IO_BPCSHIFT)
+
+#ifndef CELL_CAPABLE
+#define FSC_NOTIFY_NAME_CHANGED(vp)
+#endif
+
+#ifndef ENOATTR
+#define ENOATTR ENODATA /* Attribute not found */
+#endif
+
+/* Note: EWRONGFS never visible outside the kernel */
+#define EWRONGFS EINVAL /* Mount with wrong filesystem type */
+
+/*
+ * XXX EFSCORRUPTED needs a real value in errno.h. asm-i386/errno.h won't
+ * return codes out of its known range in errno.
+ * XXX Also note: needs to be < 1000 and fairly unique on Linux (mustn't
+ * conflict with any code we use already or any code a driver may use)
+ * XXX Some options (currently we do #2):
+ * 1/ New error code ["Filesystem is corrupted", _after_ glibc updated]
+ * 2/ 990 ["Unknown error 990"]
+ * 3/ EUCLEAN ["Structure needs cleaning"]
+ * 4/ Convert EFSCORRUPTED to EIO [just prior to return into userspace]
+ */
+#define EFSCORRUPTED 990 /* Filesystem is corrupted */
+
+#define SYNCHRONIZE() barrier()
+#define __return_address __builtin_return_address(0)
+
+/*
+ * IRIX (BSD) quotactl makes use of separate commands for user/group,
+ * whereas on Linux the syscall encodes this information into the cmd
+ * field (see the QCMD macro in quota.h). These macros help keep the
+ * code portable - they are not visible from the syscall interface.
+ */
+#define Q_XSETGQLIM XQM_CMD(0x8) /* set groups disk limits */
+#define Q_XGETGQUOTA XQM_CMD(0x9) /* get groups disk limits */
+
+/* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */
+/* we may well need to fine-tune this if it ever becomes an issue. */
+#define DQUOT_MAX_HEURISTIC 1024 /* NR_DQUOTS */
+#define ndquot DQUOT_MAX_HEURISTIC
+
+/* IRIX uses the current size of the name cache to guess a good value */
+/* - this isn't the same but is a good enough starting point for now. */
+#define DQUOT_HASH_HEURISTIC files_stat.nr_files
+
+/* IRIX inodes maintain the project ID also, zero this field on Linux */
+#define DEFAULT_PROJID 0
+#define dfltprid DEFAULT_PROJID
+
+#define FINVIS 0x0102 /* don't update timestamps - XFS */
+
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/*
+ * Juggle IRIX device numbers - still used in ondisk structures
+ */
+#define XFS_DEV_BITSMAJOR 14
+#define XFS_DEV_BITSMINOR 18
+#define XFS_DEV_MAXMAJ 0x1ff
+#define XFS_DEV_MAXMIN 0x3ffff
+#define XFS_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>XFS_DEV_BITSMINOR) \
+ & XFS_DEV_MAXMAJ))
+#define XFS_DEV_MINOR(dev) ((int)((dev)&XFS_DEV_MAXMIN))
+#define XFS_MKDEV(major,minor) ((xfs_dev_t)(((major)<<XFS_DEV_BITSMINOR) \
+ | (minor&XFS_DEV_MAXMIN)))
+
+#define XFS_DEV_TO_KDEVT(dev) mk_kdev(XFS_DEV_MAJOR(dev),XFS_DEV_MINOR(dev))
+
+
+/* Produce a kernel stack trace */
+
+static inline void xfs_stack_trace(void)
+{
+ kdb_backtrace();
+}
+
+
+/* Move the kernel do_div definition off to one side */
+
+#if defined __i386__
+/* For ia32 we need to pull some tricks to get past various versions
+ * of the compiler which do not like us using do_div in the middle
+ * of large functions.
+ */
+static inline __u32 xfs_do_div(void *a, __u32 b, int n)
+{
+ __u32 mod;
+
+ switch (n) {
+ case 4:
+ mod = *(__u32 *)a % b;
+ *(__u32 *)a = *(__u32 *)a / b;
+ return mod;
+ case 8:
+ {
+ unsigned long __upper, __low, __high, __mod;
+ __u64 c = *(__u64 *)a;
+ __upper = __high = c >> 32;
+ __low = c;
+ if (__high) {
+ __upper = __high % (b);
+ __high = __high / (b);
+ }
+ asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper));
+ asm("":"=A" (c):"a" (__low),"d" (__high));
+ *(__u64 *)a = c;
+ return __mod;
+ }
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+/* Side effect free 64 bit mod operation */
+static inline __u32 xfs_do_mod(void *a, __u32 b, int n)
+{
+ switch (n) {
+ case 4:
+ return *(__u32 *)a % b;
+ case 8:
+ {
+ unsigned long __upper, __low, __high, __mod;
+ __u64 c = *(__u64 *)a;
+ __upper = __high = c >> 32;
+ __low = c;
+ if (__high) {
+ __upper = __high % (b);
+ __high = __high / (b);
+ }
+ asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper));
+ asm("":"=A" (c):"a" (__low),"d" (__high));
+ return __mod;
+ }
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+#else
+
+#define do_div(n, base) ({\
+ int __res; \
+ __res = ((__u64)(n)) % (__u32)(base); \
+ (n) = ((__u64)(n)) / (__u32)(base); \
+ __res; })
+
+static inline __u32 xfs_do_div(void *a, __u32 b, int n)
+{
+ __u32 mod;
+
+ switch (n) {
+ case 4:
+ mod = *(__u32 *)a % b;
+ *(__u32 *)a = *(__u32 *)a / b;
+ return mod;
+ case 8:
+ mod = do_div(*(__u64 *)a, b);
+ return mod;
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+/* Side effect free 64 bit mod operation */
+static inline __u32 xfs_do_mod(void *a, __u32 b, int n)
+{
+ switch (n) {
+ case 4:
+ return *(__u32 *)a % b;
+ case 8:
+ {
+ __u64 c = *(__u64 *)a;
+ return do_div(c, b);
+ }
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+#endif
+
+#undef do_div
+#define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a))
+#define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a))
+
+static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y)
+{
+ x += y - 1;
+ do_div(x, y);
+ return(x * y);
+}
+
+static inline unsigned long ffz(unsigned long val)
+{
+ val = ffsl(~val);
+ return val;
+}
+
+#endif /* __XFS_FREEBSD__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_frw.c b/sys/gnu/fs/xfs/FreeBSD/xfs_frw.c
new file mode 100644
index 000000000000..ac9f2dcada41
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_frw.c
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+/*
+ * fs/xfs/linux/xfs_lrw.c (Linux Read Write stuff)
+ *
+ */
+
+#include "xfs.h"
+
+#include "xfs_fs.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_alloc.h"
+#include "xfs_dmapi.h"
+#include "xfs_quota.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_bmap.h"
+#include "xfs_bit.h"
+#include "xfs_rtalloc.h"
+#include "xfs_error.h"
+#include "xfs_itable.h"
+#include "xfs_rw.h"
+#include "xfs_refcache.h"
+#include "xfs_acl.h"
+#include "xfs_cap.h"
+#include "xfs_mac.h"
+#include "xfs_attr.h"
+#include "xfs_inode_item.h"
+#include "xfs_buf_item.h"
+#include "xfs_utils.h"
+#include "xfs_iomap.h"
+
+#if defined(XFS_RW_TRACE)
+void
+xfs_rw_enter_trace(
+ int tag,
+ xfs_iocore_t *io,
+ const char *buf,
+ size_t size,
+ loff_t offset,
+ int ioflags)
+{
+ xfs_inode_t *ip = XFS_IO_INODE(io);
+
+ if (ip->i_rwtrace == NULL)
+ return;
+ ktrace_enter(ip->i_rwtrace,
+ (void *)(unsigned long)tag,
+ (void *)ip,
+ (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
+ (void *)(__psint_t)buf,
+ (void *)((unsigned long)size),
+ (void *)((unsigned long)((offset >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(offset & 0xffffffff)),
+ (void *)((unsigned long)ioflags),
+ (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(io->io_new_size & 0xffffffff)),
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL);
+}
+
+void
+xfs_inval_cached_trace(
+ xfs_iocore_t *io,
+ xfs_off_t offset,
+ xfs_off_t len,
+ xfs_off_t first,
+ xfs_off_t last)
+{
+ xfs_inode_t *ip = XFS_IO_INODE(io);
+
+ if (ip->i_rwtrace == NULL)
+ return;
+ ktrace_enter(ip->i_rwtrace,
+ (void *)(__psint_t)XFS_INVAL_CACHED,
+ (void *)ip,
+ (void *)((unsigned long)((offset >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(offset & 0xffffffff)),
+ (void *)((unsigned long)((len >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(len & 0xffffffff)),
+ (void *)((unsigned long)((first >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(first & 0xffffffff)),
+ (void *)((unsigned long)((last >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(last & 0xffffffff)),
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL,
+ (void *)NULL);
+}
+#endif
+
+/*
+ * xfs_iozero
+ *
+ * xfs_iozero clears the specified range of buffer supplied,
+ * and marks all the affected blocks as valid and modified. If
+ * an affected block is not allocated, it will be allocated. If
+ * an affected block is not completely overwritten, and is not
+ * valid before the operation, it will be read from disk before
+ * being partially zeroed.
+ */
+STATIC int
+xfs_iozero(
+ xfs_vnode_t *vp, /* vnode */
+ loff_t pos, /* offset in file */
+ size_t count, /* size of data to zero */
+ loff_t end_size) /* max file size to set */
+{
+#if XXXKAN
+ unsigned bytes;
+ struct page *page;
+ struct address_space *mapping;
+ char *kaddr;
+ int status;
+
+ mapping = ip->i_mapping;
+ do {
+ unsigned long index, offset;
+
+ offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
+ index = pos >> PAGE_CACHE_SHIFT;
+ bytes = PAGE_CACHE_SIZE - offset;
+ if (bytes > count)
+ bytes = count;
+
+ status = -ENOMEM;
+ page = grab_cache_page(mapping, index);
+ if (!page)
+ break;
+
+ kaddr = kmap(page);
+ status = mapping->a_ops->prepare_write(NULL, page, offset,
+ offset + bytes);
+ if (status) {
+ goto unlock;
+ }
+
+ memset((void *) (kaddr + offset), 0, bytes);
+ flush_dcache_page(page);
+ status = mapping->a_ops->commit_write(NULL, page, offset,
+ offset + bytes);
+ if (!status) {
+ pos += bytes;
+ count -= bytes;
+ if (pos > i_size_read(ip))
+ i_size_write(ip, pos < end_size ? pos : end_size);
+ }
+
+unlock:
+ kunmap(page);
+ unlock_page(page);
+ page_cache_release(page);
+ if (status)
+ break;
+ } while (count);
+
+ return (-status);
+#endif /* XXXKAN */
+ return (0);
+}
+
+/*
+ * xfs_inval_cached_pages
+ *
+ * This routine is responsible for keeping direct I/O and buffered I/O
+ * somewhat coherent. From here we make sure that we're at least
+ * temporarily holding the inode I/O lock exclusively and then call
+ * the page cache to flush and invalidate any cached pages. If there
+ * are no cached pages this routine will be very quick.
+ */
+void
+xfs_inval_cached_pages(
+ xfs_vnode_t *vp,
+ xfs_iocore_t *io,
+ xfs_off_t offset,
+ int write,
+ int relock)
+{
+ xfs_mount_t *mp;
+
+ if (!VN_CACHED(vp)) {
+ return;
+ }
+
+ mp = io->io_mount;
+
+ /*
+ * We need to get the I/O lock exclusively in order
+ * to safely invalidate pages and mappings.
+ */
+ if (relock) {
+ XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED);
+ XFS_ILOCK(mp, io, XFS_IOLOCK_EXCL);
+ }
+
+ /* Writing beyond EOF creates a hole that must be zeroed */
+ if (write && (offset > XFS_SIZE(mp, io))) {
+ xfs_fsize_t isize;
+
+ XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ isize = XFS_SIZE(mp, io);
+ if (offset > isize) {
+ xfs_zero_eof(vp, io, offset, isize, offset);
+ }
+ XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ }
+
+ xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1);
+ XVOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED);
+ if (relock) {
+ XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL);
+ }
+}
+
+int
+xfs_read_file(xfs_mount_t *mp, xfs_inode_t *ip, struct uio *uio, int ioflag);
+
+ssize_t /* bytes read, or (-) error */
+xfs_read(
+ bhv_desc_t *bdp,
+ uio_t *uio,
+ int ioflags,
+ cred_t *credp)
+{
+ ssize_t ret, size;
+ xfs_fsize_t n;
+ xfs_inode_t *ip;
+ xfs_mount_t *mp;
+
+ ip = XFS_BHVTOI(bdp);
+ mp = ip->i_mount;
+
+ XFS_STATS_INC(xs_read_calls);
+
+ if (unlikely(ioflags & IO_ISDIRECT)) {
+ if (((__psint_t)buf & BBMASK) ||
+ (uio->uio_offset & mp->m_blockmask) ||
+ (uio->uio_resid & mp->m_blockmask)) {
+ if (uio->uio_offset >= ip->i_d.di_size) {
+ return (0);
+ }
+ return EINVAL;
+ }
+ }
+
+ if (uio->uio_resid == 0)
+ return 0;
+ n = XFS_MAXIOFFSET(mp) - uio->uio_offset;
+ if (n <= 0)
+ return EFBIG;
+
+ size = (n < uio->uio_resid)? n : uio->uio_resid;
+
+ if (XFS_FORCED_SHUTDOWN(mp)) {
+ return EIO;
+ }
+
+ if (!(ioflags & IO_ISLOCKED))
+ xfs_ilock(ip, XFS_IOLOCK_SHARED);
+#if XXXKAN
+ if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
+ !(ioflags & IO_INVIS)) {
+ int error;
+ vrwlock_t locktype = VRWLOCK_READ;
+ int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags);
+
+ error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp),
+ uio->uio_offset, size, dmflags, &locktype);
+ if (error) {
+ if (!(ioflags & IO_ISLOCKED))
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ return (error);
+ }
+ }
+
+ if (unlikely(ioflags & IO_ISDIRECT)) {
+ xfs_rw_enter_trace(XFS_DIORD_ENTER, &ip->i_iocore,
+ buf, size, *offset, ioflags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22)
+ xfs_off_t pos = uio->uio_offset;
+
+ ret = generic_file_direct_IO(READ, file, buf, size, pos);
+ if (ret > 0)
+ uio->uio_offset = pos + ret;
+
+ UPDATE_ATIME(file->f_dentry->d_inode);
+#else
+ ret = generic_file_read(file, buf, size, offset);
+#endif
+ } else {
+ xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
+ buf, size, *offset, ioflags);
+ ret = generic_file_read(file, buf, size, offset);
+ }
+#else /* XXXKAN */
+ ret = xfs_read_file(mp, ip, uio, ioflags);
+#endif /* XXXKAN */
+
+ if (!(ioflags & IO_ISLOCKED))
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+
+ XFS_STATS_ADD(xs_read_bytes, ret);
+
+ if (likely((ioflags & IO_INVIS) == 0)) {
+ xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
+ }
+
+ return ret;
+}
+
+/*
+ * This routine is called to handle zeroing any space in the last
+ * block of the file that is beyond the EOF. We do this since the
+ * size is being increased without writing anything to that block
+ * and we don't want anyone to read the garbage on the disk.
+ */
+STATIC int /* error (positive) */
+xfs_zero_last_block(
+ xfs_vnode_t *vp,
+ xfs_iocore_t *io,
+ xfs_off_t offset,
+ xfs_fsize_t isize,
+ xfs_fsize_t end_size)
+{
+ xfs_fileoff_t last_fsb;
+ xfs_mount_t *mp;
+ int nimaps;
+ int zero_offset;
+ int zero_len;
+ int isize_fsb_offset;
+ int error = 0;
+ xfs_bmbt_irec_t imap;
+ loff_t loff;
+ size_t lsize;
+
+ ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
+ ASSERT(offset > isize);
+
+ mp = io->io_mount;
+
+ isize_fsb_offset = XFS_B_FSB_OFFSET(mp, isize);
+ if (isize_fsb_offset == 0) {
+ /*
+ * There are no extra bytes in the last block on disk to
+ * zero, so return.
+ */
+ return 0;
+ }
+
+ last_fsb = XFS_B_TO_FSBT(mp, isize);
+ nimaps = 1;
+ error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap,
+ &nimaps, NULL);
+ if (error) {
+ return error;
+ }
+ ASSERT(nimaps > 0);
+ /*
+ * If the block underlying isize is just a hole, then there
+ * is nothing to zero.
+ */
+ if (imap.br_startblock == HOLESTARTBLOCK) {
+ return 0;
+ }
+ /*
+ * Zero the part of the last block beyond the EOF, and write it
+ * out sync. We need to drop the ilock while we do this so we
+ * don't deadlock when the buffer cache calls back to us.
+ */
+ XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD);
+ loff = XFS_FSB_TO_B(mp, last_fsb);
+ lsize = XFS_FSB_TO_B(mp, 1);
+
+ zero_offset = isize_fsb_offset;
+ zero_len = mp->m_sb.sb_blocksize - isize_fsb_offset;
+
+ error = xfs_iozero(vp, loff + zero_offset, zero_len, end_size);
+
+ XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ ASSERT(error >= 0);
+ return error;
+}
+
+/*
+ * Zero any on disk space between the current EOF and the new,
+ * larger EOF. This handles the normal case of zeroing the remainder
+ * of the last block in the file and the unusual case of zeroing blocks
+ * out beyond the size of the file. This second case only happens
+ * with fixed size extents and when the system crashes before the inode
+ * size was updated but after blocks were allocated. If fill is set,
+ * then any holes in the range are filled and zeroed. If not, the holes
+ * are left alone as holes.
+ */
+
+int /* error (positive) */
+xfs_zero_eof(
+ xfs_vnode_t *vp,
+ xfs_iocore_t *io,
+ xfs_off_t offset, /* starting I/O offset */
+ xfs_fsize_t isize, /* current inode size */
+ xfs_fsize_t end_size) /* terminal inode size */
+{
+ xfs_fileoff_t start_zero_fsb;
+ xfs_fileoff_t end_zero_fsb;
+ xfs_fileoff_t prev_zero_fsb;
+ xfs_fileoff_t zero_count_fsb;
+ xfs_fileoff_t last_fsb;
+ xfs_extlen_t buf_len_fsb;
+ xfs_extlen_t prev_zero_count;
+ xfs_mount_t *mp;
+ int nimaps;
+ int error = 0;
+ xfs_bmbt_irec_t imap;
+ loff_t loff;
+ size_t lsize;
+
+ ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
+ ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
+
+ mp = io->io_mount;
+
+ /*
+ * First handle zeroing the block on which isize resides.
+ * We only zero a part of that block so it is handled specially.
+ */
+ error = xfs_zero_last_block(vp, io, offset, isize, end_size);
+ if (error) {
+ ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
+ ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
+ return error;
+ }
+
+ /*
+ * Calculate the range between the new size and the old
+ * where blocks needing to be zeroed may exist. To get the
+ * block where the last byte in the file currently resides,
+ * we need to subtract one from the size and truncate back
+ * to a block boundary. We subtract 1 in case the size is
+ * exactly on a block boundary.
+ */
+ last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1;
+ start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize);
+ end_zero_fsb = XFS_B_TO_FSBT(mp, offset - 1);
+ ASSERT((xfs_sfiloff_t)last_fsb < (xfs_sfiloff_t)start_zero_fsb);
+ if (last_fsb == end_zero_fsb) {
+ /*
+ * The size was only incremented on its last block.
+ * We took care of that above, so just return.
+ */
+ return 0;
+ }
+
+ ASSERT(start_zero_fsb <= end_zero_fsb);
+ prev_zero_fsb = NULLFILEOFF;
+ prev_zero_count = 0;
+ while (start_zero_fsb <= end_zero_fsb) {
+ nimaps = 1;
+ zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
+ error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb,
+ 0, NULL, 0, &imap, &nimaps, NULL);
+ if (error) {
+ ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
+ ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
+ return error;
+ }
+ ASSERT(nimaps > 0);
+
+ if (imap.br_state == XFS_EXT_UNWRITTEN ||
+ imap.br_startblock == HOLESTARTBLOCK) {
+ /*
+ * This loop handles initializing pages that were
+ * partially initialized by the code below this
+ * loop. It basically zeroes the part of the page
+ * that sits on a hole and sets the page as P_HOLE
+ * and calls remapf if it is a mapped file.
+ */
+ prev_zero_fsb = NULLFILEOFF;
+ prev_zero_count = 0;
+ start_zero_fsb = imap.br_startoff +
+ imap.br_blockcount;
+ ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
+ continue;
+ }
+
+ /*
+ * There are blocks in the range requested.
+ * Zero them a single write at a time. We actually
+ * don't zero the entire range returned if it is
+ * too big and simply loop around to get the rest.
+ * That is not the most efficient thing to do, but it
+ * is simple and this path should not be exercised often.
+ */
+ buf_len_fsb = XFS_FILBLKS_MIN(imap.br_blockcount,
+ mp->m_writeio_blocks << 8);
+ /*
+ * Drop the inode lock while we're doing the I/O.
+ * We'll still have the iolock to protect us.
+ */
+ XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+
+ loff = XFS_FSB_TO_B(mp, start_zero_fsb);
+ lsize = XFS_FSB_TO_B(mp, buf_len_fsb);
+
+ error = xfs_iozero(vp, loff, lsize, end_size);
+
+ if (error) {
+ goto out_lock;
+ }
+
+ prev_zero_fsb = start_zero_fsb;
+ prev_zero_count = buf_len_fsb;
+ start_zero_fsb = imap.br_startoff + buf_len_fsb;
+ ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
+
+ XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ }
+
+ return 0;
+
+out_lock:
+
+ XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ ASSERT(error >= 0);
+ return error;
+}
+
+ssize_t /* bytes written, or (-) error */
+xfs_write(
+ bhv_desc_t *bdp,
+ uio_t *uiop,
+ int ioflags,
+ cred_t *credp)
+{
+#if XXXKAN
+ xfs_inode_t *xip;
+ xfs_mount_t *mp;
+ ssize_t ret;
+ int error = 0;
+ xfs_fsize_t isize, new_size;
+ xfs_fsize_t n, limit;
+ xfs_iocore_t *io;
+ xfs_vnode_t *vp;
+ int iolock;
+ int eventsent = 0;
+ vrwlock_t locktype;
+
+ XFS_STATS_INC(xs_write_calls);
+
+ vp = BHV_TO_VNODE(bdp);
+ xip = XFS_BHVTOI(bdp);
+
+ if (size == 0)
+ return 0;
+
+ io = &xip->i_iocore;
+ mp = io->io_mount;
+
+ xfs_check_frozen(mp, bdp, XFS_FREEZE_WRITE);
+
+ if (XFS_FORCED_SHUTDOWN(xip->i_mount)) {
+ return EIO;
+ }
+
+ if (unlikely(ioflags & IO_ISDIRECT)) {
+ if (((__psint_t)buf & BBMASK) ||
+ (*offset & mp->m_blockmask) ||
+ (size & mp->m_blockmask)) {
+ return EINVAL;
+ }
+ iolock = XFS_IOLOCK_SHARED;
+ locktype = VRWLOCK_WRITE_DIRECT;
+ } else {
+ if (io->io_flags & XFS_IOCORE_RT)
+ return EINVAL;
+ iolock = XFS_IOLOCK_EXCL;
+ locktype = VRWLOCK_WRITE;
+ }
+
+ if (ioflags & IO_ISLOCKED)
+ iolock = 0;
+
+ xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
+
+ isize = xip->i_d.di_size;
+ limit = XFS_MAXIOFFSET(mp);
+
+ if (file->f_flags & O_APPEND)
+ *offset = isize;
+
+start:
+ n = limit - *offset;
+ if (n <= 0) {
+ xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
+ return EFBIG;
+ }
+ if (n < size)
+ size = n;
+
+ new_size = *offset + size;
+ if (new_size > isize) {
+ io->io_new_size = new_size;
+ }
+
+ if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
+ !(ioflags & IO_INVIS) && !eventsent)) {
+ loff_t savedsize = *offset;
+ int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags);
+
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
+ error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
+ *offset, size,
+ dmflags, &locktype);
+ if (error) {
+ if (iolock) xfs_iunlock(xip, iolock);
+ return -error;
+ }
+ xfs_ilock(xip, XFS_ILOCK_EXCL);
+ eventsent = 1;
+
+ /*
+ * The iolock was dropped and reaquired in XFS_SEND_DATA
+ * so we have to recheck the size when appending.
+ * We will only "goto start;" once, since having sent the
+ * event prevents another call to XFS_SEND_DATA, which is
+ * what allows the size to change in the first place.
+ */
+ if ((file->f_flags & O_APPEND) &&
+ savedsize != xip->i_d.di_size) {
+ *offset = isize = xip->i_d.di_size;
+ goto start;
+ }
+ }
+
+ /*
+ * If the offset is beyond the size of the file, we have a couple
+ * of things to do. First, if there is already space allocated
+ * we need to either create holes or zero the disk or ...
+ *
+ * If there is a page where the previous size lands, we need
+ * to zero it out up to the new size.
+ */
+
+ if (!(ioflags & IO_ISDIRECT) && (*offset > isize && isize)) {
+ error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset,
+ isize, *offset + size);
+ if (error) {
+ xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
+ return(-error);
+ }
+ }
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
+
+ /*
+ * If we're writing the file then make sure to clear the
+ * setuid and setgid bits if the process is not being run
+ * by root. This keeps people from modifying setuid and
+ * setgid binaries.
+ */
+
+ if (((xip->i_d.di_mode & S_ISUID) ||
+ ((xip->i_d.di_mode & (S_ISGID | S_IXGRP)) ==
+ (S_ISGID | S_IXGRP))) &&
+ !capable(CAP_FSETID)) {
+ error = xfs_write_clear_setuid(xip);
+ if (error) {
+ xfs_iunlock(xip, iolock);
+ return -error;
+ }
+ }
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22)
+ if ((ssize_t) size < 0) {
+ ret = EINVAL;
+ goto error;
+ }
+
+ if (!access_ok(VERIFY_READ, buf, size)) {
+ ret = EINVAL;
+ goto error;
+ }
+#else
+#define do_generic_direct_write(file, buf, size, offset) \
+ generic_file_write_nolock(file, buf, size, offset)
+#define do_generic_file_write(file, buf, size, offset) \
+ generic_file_write_nolock(file, buf, size, offset)
+#endif
+
+retry:
+ if (unlikely(ioflags & IO_ISDIRECT)) {
+ loff_t pos = *offset;
+ struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+ struct inode *inode = mapping->host;
+
+ ret = precheck_file_write(file, inode, &size, &pos);
+ if (ret || size == 0)
+ goto error;
+
+ xfs_inval_cached_pages(vp, io, pos, 1, 1);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ /* mark_inode_dirty_sync(inode); - we do this later */
+
+ xfs_rw_enter_trace(XFS_DIOWR_ENTER, io, buf, size, pos, ioflags);
+ ret = generic_file_direct_IO(WRITE, file, (char *)buf, size, pos);
+ if (ret > 0)
+ *offset += ret;
+ } else {
+ xfs_rw_enter_trace(XFS_WRITE_ENTER, io, buf, size, *offset, ioflags);
+ ret = do_generic_file_write(file, buf, size, offset);
+ }
+
+ if (unlikely(ioflags & IO_INVIS)) {
+ /* generic_file_write updates the mtime/ctime but we need
+ * to undo that because this I/O was supposed to be
+ * invisible.
+ */
+ struct inode *inode = LINVFS_GET_IP(vp);
+ inode->i_mtime = xip->i_d.di_mtime.t_sec;
+ inode->i_ctime = xip->i_d.di_ctime.t_sec;
+ } else {
+ xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+ }
+
+ if ((ret == -ENOSPC) &&
+ DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
+ !(ioflags & IO_INVIS)) {
+
+ xfs_rwunlock(bdp, locktype);
+ error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
+ DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
+ 0, 0, 0); /* Delay flag intentionally unused */
+ if (error)
+ return -error;
+ xfs_rwlock(bdp, locktype);
+ *offset = xip->i_d.di_size;
+ goto retry;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22)
+error:
+#endif
+ if (ret <= 0) {
+ if (iolock)
+ xfs_rwunlock(bdp, locktype);
+ return ret;
+ }
+
+ XFS_STATS_ADD(xs_write_bytes, ret);
+
+ if (*offset > xip->i_d.di_size) {
+ xfs_ilock(xip, XFS_ILOCK_EXCL);
+ if (*offset > xip->i_d.di_size) {
+ struct inode *inode = LINVFS_GET_IP(vp);
+
+ xip->i_d.di_size = *offset;
+ i_size_write(inode, *offset);
+ xip->i_update_core = 1;
+ xip->i_update_size = 1;
+ mark_inode_dirty_sync(inode);
+ }
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
+ }
+
+ /* Handle various SYNC-type writes */
+ if ((file->f_flags & O_SYNC) || IS_SYNC(file->f_dentry->d_inode)) {
+
+ /*
+ * If we're treating this as O_DSYNC and we have not updated the
+ * size, force the log.
+ */
+
+ if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC)
+ && !(xip->i_update_size)) {
+ /*
+ * If an allocation transaction occurred
+ * without extending the size, then we have to force
+ * the log up the proper point to ensure that the
+ * allocation is permanent. We can't count on
+ * the fact that buffered writes lock out direct I/O
+ * writes - the direct I/O write could have extended
+ * the size nontransactionally, then finished before
+ * we started. xfs_write_file will think that the file
+ * didn't grow but the update isn't safe unless the
+ * size change is logged.
+ *
+ * Force the log if we've committed a transaction
+ * against the inode or if someone else has and
+ * the commit record hasn't gone to disk (e.g.
+ * the inode is pinned). This guarantees that
+ * all changes affecting the inode are permanent
+ * when we return.
+ */
+
+ xfs_inode_log_item_t *iip;
+ xfs_lsn_t lsn;
+
+ iip = xip->i_itemp;
+ if (iip && iip->ili_last_lsn) {
+ lsn = iip->ili_last_lsn;
+ xfs_log_force(mp, lsn,
+ XFS_LOG_FORCE | XFS_LOG_SYNC);
+ } else if (xfs_ipincount(xip) > 0) {
+ xfs_log_force(mp, (xfs_lsn_t)0,
+ XFS_LOG_FORCE | XFS_LOG_SYNC);
+ }
+
+ } else {
+ xfs_trans_t *tp;
+
+ /*
+ * O_SYNC or O_DSYNC _with_ a size update are handled
+ * the same way.
+ *
+ * If the write was synchronous then we need to make
+ * sure that the inode modification time is permanent.
+ * We'll have updated the timestamp above, so here
+ * we use a synchronous transaction to log the inode.
+ * It's not fast, but it's necessary.
+ *
+ * If this a dsync write and the size got changed
+ * non-transactionally, then we need to ensure that
+ * the size change gets logged in a synchronous
+ * transaction.
+ */
+
+ tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC);
+ if ((error = xfs_trans_reserve(tp, 0,
+ XFS_SWRITE_LOG_RES(mp),
+ 0, 0, 0))) {
+ /* Transaction reserve failed */
+ xfs_trans_cancel(tp, 0);
+ } else {
+ /* Transaction reserve successful */
+ xfs_ilock(xip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL);
+ xfs_trans_ihold(tp, xip);
+ xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE);
+ xfs_trans_set_sync(tp);
+ error = xfs_trans_commit(tp, 0, (xfs_lsn_t)0);
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
+ }
+ }
+ } /* (ioflags & O_SYNC) */
+
+ /*
+ * If we are coming from an nfsd thread then insert into the
+ * reference cache.
+ */
+
+ if (!strcmp(current->comm, "nfsd"))
+ xfs_refcache_insert(xip);
+
+ /* Drop lock this way - the old refcache release is in here */
+ if (iolock)
+ xfs_rwunlock(bdp, locktype);
+
+ return(ret);
+#endif /* XXXKAN */
+ return (0);
+}
+
+/*
+ * Initiate IO on given buffer.
+ */
+int
+xfs_buf_iorequest(struct xfs_buf *bp)
+{
+ bp->b_flags &= ~(B_INVAL|B_DONE);
+ bp->b_ioflags &= ~BIO_ERROR;
+
+ if (bp->b_flags & B_ASYNC)
+ BUF_KERNPROC(bp);
+
+ if (bp->b_vp == NULL) {
+ if (bp->b_iocmd == BIO_WRITE) {
+ bp->b_flags &= ~(B_DELWRI | B_DEFERRED);
+ bufobj_wref(bp->b_bufobj);
+ }
+
+ bp->b_iooffset = (bp->b_blkno << BBSHIFT);
+ bstrategy(bp);
+ } else {
+ if (bp->b_iocmd == BIO_WRITE) {
+ /* Mark the buffer clean */
+ bundirty(bp);
+ bufobj_wref(bp->b_bufobj);
+ vfs_busy_pages(bp, 1);
+ } else if (bp->b_iocmd == BIO_READ) {
+ vfs_busy_pages(bp, 0);
+ }
+ bp->b_iooffset = dbtob(bp->b_blkno);
+ bstrategy(bp);
+ }
+ return 0;
+}
+
+/*
+ * All xfs metadata buffers except log state machine buffers
+ * get this attached as their b_bdstrat callback function.
+ * This is so that we can catch a buffer
+ * after prematurely unpinning it to forcibly shutdown the filesystem.
+ */
+int
+xfs_bdstrat_cb(struct xfs_buf *bp)
+{
+ xfs_mount_t *mp;
+
+ mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *);
+ if (!XFS_FORCED_SHUTDOWN(mp)) {
+ xfs_buf_iorequest(bp);
+ return 0;
+ } else {
+ xfs_buftrace("XFS__BDSTRAT IOERROR", bp);
+ /*
+ * Metadata write that didn't get logged but
+ * written delayed anyway. These aren't associated
+ * with a transaction, and can be ignored.
+ */
+ if (XFS_BUF_IODONE_FUNC(bp) == NULL &&
+ (XFS_BUF_ISREAD(bp)) == 0)
+ return (xfs_bioerror_relse(bp));
+ else
+ return (xfs_bioerror(bp));
+ }
+}
+
+
+int
+xfs_bmap(bhv_desc_t *bdp,
+ xfs_off_t offset,
+ ssize_t count,
+ int flags,
+ xfs_iomap_t *iomapp,
+ int *niomaps)
+{
+ xfs_inode_t *ip = XFS_BHVTOI(bdp);
+ xfs_iocore_t *io = &ip->i_iocore;
+
+ ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
+ ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
+ ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
+
+ return xfs_iomap(io, offset, count, flags, iomapp, niomaps);
+}
+
+/*
+ * Wrapper around bdstrat so that we can stop data
+ * from going to disk in case we are shutting down the filesystem.
+ * Typically user data goes thru this path; one of the exceptions
+ * is the superblock.
+ */
+int
+xfsbdstrat(
+ struct xfs_mount *mp,
+ struct xfs_buf *bp)
+{
+ ASSERT(mp);
+ if (!XFS_FORCED_SHUTDOWN(mp)) {
+ /* Grio redirection would go here
+ * if (XFS_BUF_IS_GRIO(bp)) {
+ */
+
+ return xfs_buf_iorequest(bp);
+ return 0;
+ }
+
+ xfs_buftrace("XFSBDSTRAT IOERROR", bp);
+ return (xfs_bioerror_relse(bp));
+}
+
+/*
+ * If the underlying (data/log/rt) device is readonly, there are some
+ * operations that cannot proceed.
+ */
+int
+xfs_dev_is_read_only(
+ xfs_mount_t *mp,
+ char *message)
+{
+ if (xfs_readonly_buftarg(mp->m_ddev_targp) ||
+ xfs_readonly_buftarg(mp->m_logdev_targp) ||
+ (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp))) {
+ cmn_err(CE_NOTE,
+ "XFS: %s required on read-only device.", message);
+ cmn_err(CE_NOTE,
+ "XFS: write access unavailable, cannot proceed.");
+ return EROFS;
+ }
+ return 0;
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_frw.h b/sys/gnu/fs/xfs/FreeBSD/xfs_frw.h
new file mode 100644
index 000000000000..c08abceef176
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_frw.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_FRW_H__
+#define __XFS_FRW_H__
+
+struct xfs_vnode;
+struct bhv_desc;
+struct xfs_mount;
+struct xfs_iocore;
+struct xfs_inode;
+struct xfs_bmbt_irec;
+struct xfs_buf;
+struct xfs_iomap;
+
+#if defined(XFS_RW_TRACE)
+/*
+ * Defines for the trace mechanisms in xfs_lrw.c.
+ */
+#define XFS_RW_KTRACE_SIZE 128
+
+#define XFS_READ_ENTER 1
+#define XFS_WRITE_ENTER 2
+#define XFS_IOMAP_READ_ENTER 3
+#define XFS_IOMAP_WRITE_ENTER 4
+#define XFS_IOMAP_READ_MAP 5
+#define XFS_IOMAP_WRITE_MAP 6
+#define XFS_IOMAP_WRITE_NOSPACE 7
+#define XFS_ITRUNC_START 8
+#define XFS_ITRUNC_FINISH1 9
+#define XFS_ITRUNC_FINISH2 10
+#define XFS_CTRUNC1 11
+#define XFS_CTRUNC2 12
+#define XFS_CTRUNC3 13
+#define XFS_CTRUNC4 14
+#define XFS_CTRUNC5 15
+#define XFS_CTRUNC6 16
+#define XFS_BUNMAPI 17
+#define XFS_INVAL_CACHED 18
+#define XFS_DIORD_ENTER 19
+#define XFS_DIOWR_ENTER 20
+#define XFS_SENDFILE_ENTER 21
+#define XFS_WRITEPAGE_ENTER 22
+#define XFS_RELEASEPAGE_ENTER 23
+#define XFS_IOMAP_ALLOC_ENTER 24
+#define XFS_IOMAP_ALLOC_MAP 25
+#define XFS_IOMAP_UNWRITTEN 26
+extern void xfs_rw_enter_trace(int, struct xfs_iocore *,
+ const char *, size_t, loff_t, int);
+extern void xfs_inval_cached_trace(struct xfs_iocore *,
+ xfs_off_t, xfs_off_t, xfs_off_t, xfs_off_t);
+#else
+#define xfs_rw_enter_trace(tag, io, buf, size, offset, ioflags)
+#define xfs_inval_cached_trace(io, offset, len, first, last)
+#endif
+
+/*
+ * Maximum count of bmaps used by read and write paths.
+ */
+#define XFS_MAX_RW_NBMAPS 4
+
+extern int xfs_bmap(struct bhv_desc *, xfs_off_t, ssize_t, int,
+ struct xfs_iomap *, int *);
+extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
+extern int xfs_bdstrat_cb(struct xfs_buf *);
+
+extern int xfs_zero_eof(struct xfs_vnode *, struct xfs_iocore *, xfs_off_t,
+ xfs_fsize_t, xfs_fsize_t);
+extern void xfs_inval_cached_pages(struct xfs_vnode*, struct xfs_iocore *,
+ xfs_off_t, int, int);
+extern ssize_t xfs_read(bhv_desc_t *, uio_t *, int, cred_t *);
+extern ssize_t xfs_write(bhv_desc_t *, uio_t *, int, cred_t *);
+
+extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
+
+#define XFS_FSB_TO_DB_IO(io,fsb) \
+ (((io)->io_flags & XFS_IOCORE_RT) ? \
+ XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \
+ XFS_FSB_TO_DADDR((io)->io_mount, (fsb)))
+
+#endif /* __XFS_FRW_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.c b/sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.c
new file mode 100644
index 000000000000..5a581ab5ee6e
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2000-2002 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.h"
+
+/*
+ * Stub for no-op vnode operations that return error status.
+ */
+int
+fs_noerr()
+{
+ return 0;
+}
+
+/*
+ * Operation unsupported under this file system.
+ */
+int
+fs_nosys()
+{
+ return ENOSYS;
+}
+
+/*
+ * Stub for inactive, strategy, and read/write lock/unlock. Does nothing.
+ */
+/* ARGSUSED */
+void
+fs_noval()
+{
+}
+
+/*
+ * vnode pcache layer for vnode_tosspages.
+ * 'last' parameter unused but left in for IRIX compatibility
+ */
+void
+fs_tosspages(
+ bhv_desc_t *bdp,
+ xfs_off_t first,
+ xfs_off_t last,
+ int fiopt)
+{
+#if XXXKAN
+ vnode_t *vp = BHV_TO_VNODE(bdp);
+ struct inode *ip = LINVFS_GET_IP(vp);
+
+ if (VN_CACHED(vp))
+ truncate_inode_pages(ip->i_mapping, first);
+#endif
+}
+
+
+/*
+ * vnode pcache layer for vnode_flushinval_pages.
+ * 'last' parameter unused but left in for IRIX compatibility
+ */
+void
+fs_flushinval_pages(
+ bhv_desc_t *bdp,
+ xfs_off_t first,
+ xfs_off_t last,
+ int fiopt)
+{
+#if XXXKAN
+ vnode_t *vp = BHV_TO_VNODE(bdp);
+ struct inode *ip = LINVFS_GET_IP(vp);
+
+ if (VN_CACHED(vp)) {
+ filemap_fdatasync(ip->i_mapping);
+ fsync_inode_data_buffers(ip);
+ filemap_fdatawait(ip->i_mapping);
+
+ truncate_inode_pages(ip->i_mapping, first);
+ }
+#endif
+}
+
+/*
+ * vnode pcache layer for vnode_flush_pages.
+ * 'last' parameter unused but left in for IRIX compatibility
+ */
+int
+fs_flush_pages(
+ bhv_desc_t *bdp,
+ xfs_off_t first,
+ xfs_off_t last,
+ uint64_t flags,
+ int fiopt)
+{
+#if XXXKAN
+ vnode_t *vp = BHV_TO_VNODE(bdp);
+ struct inode *ip = LINVFS_GET_IP(vp);
+
+ if (VN_CACHED(vp)) {
+ filemap_fdatasync(ip->i_mapping);
+ fsync_inode_data_buffers(ip);
+ filemap_fdatawait(ip->i_mapping);
+ }
+#endif
+ return 0;
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.h b/sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.h
new file mode 100644
index 000000000000..198b8dd7818d
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_fs_subr.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000, 2002 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/
+ */
+#ifndef __XFS_SUBR_H__
+#define __XFS_SUBR_H__
+
+/*
+ * Utilities shared among file system implementations.
+ */
+
+struct cred;
+
+extern int fs_noerr(void);
+extern int fs_nosys(void);
+extern int fs_nodev(void);
+extern void fs_noval(void);
+extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int);
+
+#endif /* __XFS_FS_SUBR_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_globals.c b/sys/gnu/fs/xfs/FreeBSD/xfs_globals.c
new file mode 100644
index 000000000000..85f34fc222ce
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_globals.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+
+/*
+ * This file contains globals needed by XFS that were normally defined
+ * somewhere else in IRIX.
+ */
+
+#include "xfs.h"
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_bit.h"
+#include "xfs_refcache.h"
+
+/*
+ * Tunable XFS parameters. xfs_params is required even when CONFIG_SYSCTL=n,
+ * other XFS code uses these values.
+ */
+
+xfs_param_t xfs_params = {
+ /* MIN DFLT MAX */
+#ifdef HAVE_REFCACHE
+ .refcache_size = { 0, 128, XFS_REFCACHE_SIZE_MAX },
+ .refcache_purge = { 0, 32, XFS_REFCACHE_SIZE_MAX },
+#endif
+ .restrict_chown = { 0, 1, 1 },
+ .sgid_inherit = { 0, 0, 1 },
+ .symlink_mode = { 0, 0, 1 },
+ .panic_mask = { 0, 0, 127 },
+ .error_level = { 0, 3, 11 },
+ .sync_interval = { 1, 30, 60 },
+ .stats_clear = { 0, 0, 1 },
+ .inherit_sync = { 0, 1, 1 },
+ .inherit_nodump = { 0, 1, 1 },
+ .inherit_noatim = { 0, 1, 1 },
+};
+
+/*
+ * Global system credential structure.
+ */
+cred_t sys_cred_val, *sys_cred = &sys_cred_val;
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_iget.c b/sys/gnu/fs/xfs/FreeBSD/xfs_iget.c
new file mode 100644
index 000000000000..45485bb361a5
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_iget.c
@@ -0,0 +1,973 @@
+/*
+ * Copyright (c) 2000-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.h"
+
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_quota.h"
+#include "xfs_utils.h"
+#include "xfs_vnode.h"
+
+
+static int xfs_vn_allocate(xfs_mount_t *, xfs_inode_t *, struct xfs_vnode **);
+
+/*
+ * Initialize the inode hash table for the newly mounted file system.
+ *
+ * mp -- this is the mount point structure for the file system being
+ * initialized
+ */
+void
+xfs_ihash_init(xfs_mount_t *mp)
+{
+ int i;
+
+ mp->m_ihsize = XFS_BUCKETS(mp);
+ mp->m_ihash = (xfs_ihash_t *)kmem_zalloc(mp->m_ihsize
+ * sizeof(xfs_ihash_t), KM_SLEEP);
+ ASSERT(mp->m_ihash != NULL);
+ for (i = 0; i < mp->m_ihsize; i++) {
+ rwlock_init(&(mp->m_ihash[i].ih_lock));
+ }
+}
+
+/*
+ * Free up structures allocated by xfs_ihash_init, at unmount time.
+ */
+void
+xfs_ihash_free(xfs_mount_t *mp)
+{
+ int i;
+
+ for (i = 0; i < mp->m_ihsize; i++)
+ rwlock_destroy(&mp->m_ihash[i].ih_lock);
+ kmem_free(mp->m_ihash, mp->m_ihsize*sizeof(xfs_ihash_t));
+ mp->m_ihash = NULL;
+}
+
+/*
+ * Initialize the inode cluster hash table for the newly mounted file system.
+ *
+ * mp -- this is the mount point structure for the file system being
+ * initialized
+ */
+void
+xfs_chash_init(xfs_mount_t *mp)
+{
+ int i;
+
+ /*
+ * m_chash size is based on m_ihash
+ * with a minimum of 37 entries
+ */
+ mp->m_chsize = (XFS_BUCKETS(mp)) /
+ (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
+ if (mp->m_chsize < 37) {
+ mp->m_chsize = 37;
+ }
+ mp->m_chash = (xfs_chash_t *)kmem_zalloc(mp->m_chsize
+ * sizeof(xfs_chash_t),
+ KM_SLEEP);
+ ASSERT(mp->m_chash != NULL);
+
+ for (i = 0; i < mp->m_chsize; i++) {
+ spinlock_init(&mp->m_chash[i].ch_lock,"xfshash");
+ }
+}
+
+/*
+ * Free up structures allocated by xfs_chash_init, at unmount time.
+ */
+void
+xfs_chash_free(xfs_mount_t *mp)
+{
+ int i;
+
+ for (i = 0; i < mp->m_chsize; i++) {
+ spinlock_destroy(&mp->m_chash[i].ch_lock);
+ }
+
+ kmem_free(mp->m_chash, mp->m_chsize*sizeof(xfs_chash_t));
+ mp->m_chash = NULL;
+}
+
+/*
+ * Look up an inode by number in the given file system.
+ * The inode is looked up in the hash table for the file system
+ * represented by the mount point parameter mp. Each bucket of
+ * the hash table is guarded by an individual semaphore.
+ *
+ * If the inode is found in the hash table, its corresponding vnode
+ * is obtained with a call to vn_get(). This call takes care of
+ * coordination with the reclamation of the inode and vnode. Note
+ * that the vmap structure is filled in while holding the hash lock.
+ * This gives us the state of the inode/vnode when we found it and
+ * is used for coordination in vn_get().
+ *
+ * If it is not in core, read it in from the file system's device and
+ * add the inode into the hash table.
+ *
+ * The inode is locked according to the value of the lock_flags parameter.
+ * This flag parameter indicates how and if the inode's IO lock and inode lock
+ * should be taken.
+ *
+ * mp -- the mount point structure for the current file system. It points
+ * to the inode hash table.
+ * tp -- a pointer to the current transaction if there is one. This is
+ * simply passed through to the xfs_iread() call.
+ * ino -- the number of the inode desired. This is the unique identifier
+ * within the file system for the inode being requested.
+ * lock_flags -- flags indicating how to lock the inode. See the comment
+ * for xfs_ilock() for a list of valid values.
+ * bno -- the block number starting the buffer containing the inode,
+ * if known (as by bulkstat), else 0.
+ */
+int
+xfs_iget(
+ xfs_mount_t *mp,
+ xfs_trans_t *tp,
+ xfs_ino_t ino,
+ uint lock_flags,
+ xfs_inode_t **ipp,
+ xfs_daddr_t bno)
+{
+ xfs_ihash_t *ih;
+ xfs_inode_t *ip;
+ xfs_inode_t *iq;
+ xfs_vnode_t *vp;
+ ulong version;
+ int error;
+ /* REFERENCED */
+ int newnode;
+ xfs_chash_t *ch;
+ xfs_chashlist_t *chl, *chlnew;
+ vmap_t vmap;
+ SPLDECL(s);
+
+ XFS_STATS_INC(xs_ig_attempts);
+
+ ih = XFS_IHASH(mp, ino);
+
+again:
+ read_lock(&ih->ih_lock);
+
+ for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) {
+ if (ip->i_ino == ino) {
+ vp = XFS_ITOV(ip);
+ VMAP(vp, vmap);
+ /*
+ * Inode cache hit: if ip is not at the front of
+ * its hash chain, move it there now.
+ * Do this with the lock held for update, but
+ * do statistics after releasing the lock.
+ */
+ if (ip->i_prevp != &ih->ih_next
+ && rwlock_trypromote(&ih->ih_lock)) {
+
+ if ((iq = ip->i_next)) {
+ iq->i_prevp = ip->i_prevp;
+ }
+ *ip->i_prevp = iq;
+ iq = ih->ih_next;
+ iq->i_prevp = &ip->i_next;
+ ip->i_next = iq;
+ ip->i_prevp = &ih->ih_next;
+ ih->ih_next = ip;
+ write_unlock(&ih->ih_lock);
+ } else {
+ read_unlock(&ih->ih_lock);
+ }
+
+ XFS_STATS_INC(xs_ig_found);
+
+ /*
+ * Get a reference to the vnode/inode.
+ * vn_get() takes care of coordination with
+ * the file system inode release and reclaim
+ * functions. If it returns NULL, the inode
+ * has been reclaimed so just start the search
+ * over again. We probably won't find it,
+ * but we could be racing with another cpu
+ * looking for the same inode so we have to at
+ * least look.
+ */
+ if (!(vp = vn_get(vp, &vmap))) {
+ XFS_STATS_INC(xs_ig_frecycle);
+ goto again;
+ }
+
+ if (lock_flags != 0) {
+ ip->i_flags &= ~XFS_IRECLAIM;
+ xfs_ilock(ip, lock_flags);
+ }
+
+ newnode = (ip->i_d.di_mode == 0);
+ if (newnode) {
+ xfs_iocore_inode_reinit(ip);
+ }
+ ip->i_flags &= ~XFS_ISTALE;
+
+ vn_trace_exit(vp, "xfs_iget.found",
+ (inst_t *)__return_address);
+ goto return_ip;
+ }
+ }
+
+ /*
+ * Inode cache miss: save the hash chain version stamp and unlock
+ * the chain, so we don't deadlock in vn_alloc.
+ */
+ XFS_STATS_INC(xs_ig_missed);
+
+ version = ih->ih_version;
+
+ read_unlock(&ih->ih_lock);
+
+ /*
+ * Read the disk inode attributes into a new inode structure and get
+ * a new vnode for it. This should also initialize i_ino and i_mount.
+ */
+ error = xfs_iread(mp, tp, ino, &ip, bno);
+ if (error) {
+ return error;
+ }
+
+ error = xfs_vn_allocate(mp, ip, &vp);
+ if (error) {
+ return error;
+ }
+ vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address);
+
+ xfs_inode_lock_init(ip, vp);
+ xfs_iocore_inode_init(ip);
+
+ if (lock_flags != 0) {
+ xfs_ilock(ip, lock_flags);
+ }
+
+ /*
+ * Put ip on its hash chain, unless someone else hashed a duplicate
+ * after we released the hash lock.
+ */
+ write_lock(&ih->ih_lock);
+
+ if (ih->ih_version != version) {
+ for (iq = ih->ih_next; iq != NULL; iq = iq->i_next) {
+ if (iq->i_ino == ino) {
+ write_unlock(&ih->ih_lock);
+ xfs_idestroy(ip);
+
+ XFS_STATS_INC(xs_ig_dup);
+ goto again;
+ }
+ }
+ }
+
+ /*
+ * These values _must_ be set before releasing ihlock!
+ */
+ ip->i_hash = ih;
+ if ((iq = ih->ih_next)) {
+ iq->i_prevp = &ip->i_next;
+ }
+ ip->i_next = iq;
+ ip->i_prevp = &ih->ih_next;
+ ih->ih_next = ip;
+ ip->i_udquot = ip->i_gdquot = NULL;
+ ih->ih_version++;
+
+ write_unlock(&ih->ih_lock);
+
+ /*
+ * put ip on its cluster's hash chain
+ */
+ ASSERT(ip->i_chash == NULL && ip->i_cprev == NULL &&
+ ip->i_cnext == NULL);
+
+ chlnew = NULL;
+ ch = XFS_CHASH(mp, ip->i_blkno);
+ chlredo:
+ s = mutex_spinlock(&ch->ch_lock);
+ for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) {
+ if (chl->chl_blkno == ip->i_blkno) {
+
+ /* insert this inode into the doubly-linked list
+ * where chl points */
+ if ((iq = chl->chl_ip)) {
+ ip->i_cprev = iq->i_cprev;
+ iq->i_cprev->i_cnext = ip;
+ iq->i_cprev = ip;
+ ip->i_cnext = iq;
+ } else {
+ ip->i_cnext = ip;
+ ip->i_cprev = ip;
+ }
+ chl->chl_ip = ip;
+ ip->i_chash = chl;
+ break;
+ }
+ }
+
+ /* no hash list found for this block; add a new hash list */
+ if (chl == NULL) {
+ if (chlnew == NULL) {
+ mutex_spinunlock(&ch->ch_lock, s);
+ ASSERT(xfs_chashlist_zone != NULL);
+ chlnew = (xfs_chashlist_t *)
+ kmem_zone_alloc(xfs_chashlist_zone,
+ KM_SLEEP);
+ ASSERT(chlnew != NULL);
+ goto chlredo;
+ } else {
+ ip->i_cnext = ip;
+ ip->i_cprev = ip;
+ ip->i_chash = chlnew;
+ chlnew->chl_ip = ip;
+ chlnew->chl_blkno = ip->i_blkno;
+ chlnew->chl_next = ch->ch_list;
+ ch->ch_list = chlnew;
+ chlnew = NULL;
+ }
+ } else {
+ if (chlnew != NULL) {
+ kmem_zone_free(xfs_chashlist_zone, chlnew);
+ }
+ }
+
+ mutex_spinunlock(&ch->ch_lock, s);
+
+
+ /*
+ * Link ip to its mount and thread it on the mount's inode list.
+ */
+ XFS_MOUNT_ILOCK(mp);
+ if ((iq = mp->m_inodes)) {
+ ASSERT(iq->i_mprev->i_mnext == iq);
+ ip->i_mprev = iq->i_mprev;
+ iq->i_mprev->i_mnext = ip;
+ iq->i_mprev = ip;
+ ip->i_mnext = iq;
+ } else {
+ ip->i_mnext = ip;
+ ip->i_mprev = ip;
+ }
+ mp->m_inodes = ip;
+
+ XFS_MOUNT_IUNLOCK(mp);
+
+ newnode = 1;
+
+ return_ip:
+ ASSERT(ip->i_df.if_ext_max ==
+ XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
+
+ ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
+ ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
+
+ *ipp = ip;
+
+ /*
+ * If we have a real type for an on-disk inode, we can set ops(&unlock)
+ * now. If it's a new inode being created, xfs_ialloc will handle it.
+ */
+ XVFS_INIT_VNODE(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1);
+
+ return 0;
+}
+
+/*
+ * Do the setup for the various locks within the incore inode.
+ */
+void
+xfs_inode_lock_init(
+ xfs_inode_t *ip,
+ xfs_vnode_t *vp)
+{
+ mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
+ "xfsino", (long)vp->v_number);
+ mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", vp->v_number);
+#if XXXKAN
+ init_waitqueue_head(&ip->i_ipin_wait);
+#endif
+ atomic_set(&ip->i_pincount, 0);
+ init_sema(&ip->i_flock, 1, "xfsfino", vp->v_number);
+}
+
+/*
+ * Look for the inode corresponding to the given ino in the hash table.
+ * If it is there and its i_transp pointer matches tp, return it.
+ * Otherwise, return NULL.
+ */
+xfs_inode_t *
+xfs_inode_incore(xfs_mount_t *mp,
+ xfs_ino_t ino,
+ xfs_trans_t *tp)
+{
+ xfs_ihash_t *ih;
+ xfs_inode_t *ip;
+
+ ih = XFS_IHASH(mp, ino);
+ read_lock(&ih->ih_lock);
+ for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) {
+ if (ip->i_ino == ino) {
+ /*
+ * If we find it and tp matches, return it.
+ * Otherwise break from the loop and return
+ * NULL.
+ */
+ if (ip->i_transp == tp) {
+ read_unlock(&ih->ih_lock);
+ return (ip);
+ }
+ break;
+ }
+ }
+ read_unlock(&ih->ih_lock);
+ return (NULL);
+}
+
+/*
+ * Decrement reference count of an inode structure and unlock it.
+ *
+ * ip -- the inode being released
+ * lock_flags -- this parameter indicates the inode's locks to be
+ * to be released. See the comment on xfs_iunlock() for a list
+ * of valid values.
+ */
+void
+xfs_iput(xfs_inode_t *ip,
+ uint lock_flags)
+{
+ xfs_vnode_t *vp = XFS_ITOV(ip);
+
+ vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address);
+
+ xfs_iunlock(ip, lock_flags);
+
+ VN_RELE(vp);
+}
+
+/*
+ * Special iput for brand-new inodes that are still locked
+ */
+void
+xfs_iput_new(xfs_inode_t *ip,
+ uint lock_flags)
+{
+ xfs_vnode_t *vp = XFS_ITOV(ip);
+
+ vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address);
+
+ if (lock_flags)
+ xfs_iunlock(ip, lock_flags);
+
+ VN_RELE(vp);
+}
+
+
+/*
+ * This routine embodies the part of the reclaim code that pulls
+ * the inode from the inode hash table and the mount structure's
+ * inode list.
+ * This should only be called from xfs_reclaim().
+ */
+void
+xfs_ireclaim(xfs_inode_t *ip)
+{
+ xfs_vnode_t *vp;
+
+ /*
+ * Remove from old hash list and mount list.
+ */
+ XFS_STATS_INC(xs_ig_reclaims);
+
+ xfs_iextract(ip);
+
+ /*
+ * Here we do a spurious inode lock in order to coordinate with
+ * xfs_sync(). This is because xfs_sync() references the inodes
+ * in the mount list without taking references on the corresponding
+ * vnodes. We make that OK here by ensuring that we wait until
+ * the inode is unlocked in xfs_sync() before we go ahead and
+ * free it. We get both the regular lock and the io lock because
+ * the xfs_sync() code may need to drop the regular one but will
+ * still hold the io lock.
+ */
+ xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+
+ /*
+ * Release dquots (and their references) if any. An inode may escape
+ * xfs_inactive and get here via vn_alloc->vn_reclaim path.
+ */
+ XFS_QM_DQDETACH(ip->i_mount, ip);
+
+ /*
+ * Pull our behavior descriptor from the vnode chain.
+ */
+ vp = XFS_ITOV_NULL(ip);
+ if (vp) {
+ vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
+ }
+
+ /*
+ * Free all memory associated with the inode.
+ */
+ xfs_idestroy(ip);
+}
+
+/*
+ * This routine removes an about-to-be-destroyed inode from
+ * all of the lists in which it is located with the exception
+ * of the behavior chain.
+ */
+void
+xfs_iextract(
+ xfs_inode_t *ip)
+{
+ xfs_ihash_t *ih;
+ xfs_inode_t *iq;
+ xfs_mount_t *mp;
+ xfs_chash_t *ch;
+ xfs_chashlist_t *chl, *chm;
+ SPLDECL(s);
+
+ ih = ip->i_hash;
+ write_lock(&ih->ih_lock);
+ if ((iq = ip->i_next)) {
+ iq->i_prevp = ip->i_prevp;
+ }
+ *ip->i_prevp = iq;
+ write_unlock(&ih->ih_lock);
+
+ /*
+ * Remove from cluster hash list
+ * 1) delete the chashlist if this is the last inode on the chashlist
+ * 2) unchain from list of inodes
+ * 3) point chashlist->chl_ip to 'chl_next' if to this inode.
+ */
+ mp = ip->i_mount;
+ ch = XFS_CHASH(mp, ip->i_blkno);
+ s = mutex_spinlock(&ch->ch_lock);
+
+ if (ip->i_cnext == ip) {
+ /* Last inode on chashlist */
+ ASSERT(ip->i_cnext == ip && ip->i_cprev == ip);
+ ASSERT(ip->i_chash != NULL);
+ chm=NULL;
+ for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) {
+ if (chl->chl_blkno == ip->i_blkno) {
+ if (chm == NULL) {
+ /* first item on the list */
+ ch->ch_list = chl->chl_next;
+ } else {
+ chm->chl_next = chl->chl_next;
+ }
+ kmem_zone_free(xfs_chashlist_zone, chl);
+ break;
+ } else {
+ ASSERT(chl->chl_ip != ip);
+ chm = chl;
+ }
+ }
+ ASSERT_ALWAYS(chl != NULL);
+ } else {
+ /* delete one inode from a non-empty list */
+ iq = ip->i_cnext;
+ iq->i_cprev = ip->i_cprev;
+ ip->i_cprev->i_cnext = iq;
+ if (ip->i_chash->chl_ip == ip) {
+ ip->i_chash->chl_ip = iq;
+ }
+ ip->i_chash = __return_address;
+ ip->i_cprev = __return_address;
+ ip->i_cnext = __return_address;
+ }
+ mutex_spinunlock(&ch->ch_lock, s);
+
+ /*
+ * Remove from mount's inode list.
+ */
+ XFS_MOUNT_ILOCK(mp);
+ ASSERT((ip->i_mnext != NULL) && (ip->i_mprev != NULL));
+ iq = ip->i_mnext;
+ iq->i_mprev = ip->i_mprev;
+ ip->i_mprev->i_mnext = iq;
+
+ /*
+ * Fix up the head pointer if it points to the inode being deleted.
+ */
+ if (mp->m_inodes == ip) {
+ if (ip == iq) {
+ mp->m_inodes = NULL;
+ } else {
+ mp->m_inodes = iq;
+ }
+ }
+
+#if XXXKAN
+ /*
+ * Not sure if while i_reclaim crap is needed on
+ * FreeBSD, will revisit this later.
+ */
+
+ /* Deal with the deleted inodes list */
+ list_del_init(&ip->i_reclaim);
+#endif
+
+ mp->m_ireclaims++;
+ XFS_MOUNT_IUNLOCK(mp);
+}
+
+/*
+ * This is a wrapper routine around the xfs_ilock() routine
+ * used to centralize some grungy code. It is used in places
+ * that wish to lock the inode solely for reading the extents.
+ * The reason these places can't just call xfs_ilock(SHARED)
+ * is that the inode lock also guards to bringing in of the
+ * extents from disk for a file in b-tree format. If the inode
+ * is in b-tree format, then we need to lock the inode exclusively
+ * until the extents are read in. Locking it exclusively all
+ * the time would limit our parallelism unnecessarily, though.
+ * What we do instead is check to see if the extents have been
+ * read in yet, and only lock the inode exclusively if they
+ * have not.
+ *
+ * The function returns a value which should be given to the
+ * corresponding xfs_iunlock_map_shared(). This value is
+ * the mode in which the lock was actually taken.
+ */
+uint
+xfs_ilock_map_shared(
+ xfs_inode_t *ip)
+{
+ uint lock_mode;
+
+ if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) &&
+ ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) {
+ lock_mode = XFS_ILOCK_EXCL;
+ } else {
+ lock_mode = XFS_ILOCK_SHARED;
+ }
+
+ xfs_ilock(ip, lock_mode);
+
+ return lock_mode;
+}
+
+/*
+ * This is simply the unlock routine to go with xfs_ilock_map_shared().
+ * All it does is call xfs_iunlock() with the given lock_mode.
+ */
+void
+xfs_iunlock_map_shared(
+ xfs_inode_t *ip,
+ unsigned int lock_mode)
+{
+ xfs_iunlock(ip, lock_mode);
+}
+
+/*
+ * The xfs inode contains 2 locks: a multi-reader lock called the
+ * i_iolock and a multi-reader lock called the i_lock. This routine
+ * allows either or both of the locks to be obtained.
+ *
+ * The 2 locks should always be ordered so that the IO lock is
+ * obtained first in order to prevent deadlock.
+ *
+ * ip -- the inode being locked
+ * lock_flags -- this parameter indicates the inode's locks
+ * to be locked. It can be:
+ * XFS_IOLOCK_SHARED,
+ * XFS_IOLOCK_EXCL,
+ * XFS_ILOCK_SHARED,
+ * XFS_ILOCK_EXCL,
+ * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED,
+ * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL,
+ * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED,
+ * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL
+ */
+void
+xfs_ilock(xfs_inode_t *ip,
+ uint lock_flags)
+{
+ /*
+ * You can't set both SHARED and EXCL for the same lock,
+ * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
+ * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
+ */
+ ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
+ (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
+ ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
+ (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+ ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+
+ if (lock_flags & XFS_IOLOCK_EXCL) {
+ mrupdate(&ip->i_iolock);
+ } else if (lock_flags & XFS_IOLOCK_SHARED) {
+ mraccess(&ip->i_iolock);
+ }
+ if (lock_flags & XFS_ILOCK_EXCL) {
+ mrupdate(&ip->i_lock);
+ } else if (lock_flags & XFS_ILOCK_SHARED) {
+ mraccess(&ip->i_lock);
+ }
+ xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address);
+}
+
+/*
+ * This is just like xfs_ilock(), except that the caller
+ * is guaranteed not to sleep. It returns 1 if it gets
+ * the requested locks and 0 otherwise. If the IO lock is
+ * obtained but the inode lock cannot be, then the IO lock
+ * is dropped before returning.
+ *
+ * ip -- the inode being locked
+ * lock_flags -- this parameter indicates the inode's locks to be
+ * to be locked. See the comment for xfs_ilock() for a list
+ * of valid values.
+ *
+ */
+int
+xfs_ilock_nowait(xfs_inode_t *ip,
+ uint lock_flags)
+{
+ int iolocked;
+ int ilocked;
+
+ /*
+ * You can't set both SHARED and EXCL for the same lock,
+ * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
+ * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
+ */
+ ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
+ (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
+ ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
+ (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+ ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+
+ iolocked = 0;
+ if (lock_flags & XFS_IOLOCK_EXCL) {
+ iolocked = mrtryupdate(&ip->i_iolock);
+ if (!iolocked) {
+ return 0;
+ }
+ } else if (lock_flags & XFS_IOLOCK_SHARED) {
+ iolocked = mrtryaccess(&ip->i_iolock);
+ if (!iolocked) {
+ return 0;
+ }
+ }
+ if (lock_flags & XFS_ILOCK_EXCL) {
+ ilocked = mrtryupdate(&ip->i_lock);
+ if (!ilocked) {
+ if (iolocked) {
+ mrunlock(&ip->i_iolock);
+ }
+ return 0;
+ }
+ } else if (lock_flags & XFS_ILOCK_SHARED) {
+ ilocked = mrtryaccess(&ip->i_lock);
+ if (!ilocked) {
+ if (iolocked) {
+ mrunlock(&ip->i_iolock);
+ }
+ return 0;
+ }
+ }
+ xfs_ilock_trace(ip, 2, lock_flags, (inst_t *)__return_address);
+ return 1;
+}
+
+/*
+ * xfs_iunlock() is used to drop the inode locks acquired with
+ * xfs_ilock() and xfs_ilock_nowait(). The caller must pass
+ * in the flags given to xfs_ilock() or xfs_ilock_nowait() so
+ * that we know which locks to drop.
+ *
+ * ip -- the inode being unlocked
+ * lock_flags -- this parameter indicates the inode's locks to be
+ * to be unlocked. See the comment for xfs_ilock() for a list
+ * of valid values for this parameter.
+ *
+ */
+void
+xfs_iunlock(xfs_inode_t *ip,
+ uint lock_flags)
+{
+ /*
+ * You can't set both SHARED and EXCL for the same lock,
+ * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
+ * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
+ */
+ ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
+ (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
+ ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
+ (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+ ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY)) == 0);
+ ASSERT(lock_flags != 0);
+
+ if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) {
+ ASSERT(!(lock_flags & XFS_IOLOCK_SHARED) ||
+ (ismrlocked(&ip->i_iolock, MR_ACCESS)));
+ ASSERT(!(lock_flags & XFS_IOLOCK_EXCL) ||
+ (ismrlocked(&ip->i_iolock, MR_UPDATE)));
+ mrunlock(&ip->i_iolock);
+ }
+
+ if (lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) {
+ ASSERT(!(lock_flags & XFS_ILOCK_SHARED) ||
+ (ismrlocked(&ip->i_lock, MR_ACCESS)));
+ ASSERT(!(lock_flags & XFS_ILOCK_EXCL) ||
+ (ismrlocked(&ip->i_lock, MR_UPDATE)));
+ mrunlock(&ip->i_lock);
+
+ /*
+ * Let the AIL know that this item has been unlocked in case
+ * it is in the AIL and anyone is waiting on it. Don't do
+ * this if the caller has asked us not to.
+ */
+ if (!(lock_flags & XFS_IUNLOCK_NONOTIFY) &&
+ ip->i_itemp != NULL) {
+ xfs_trans_unlocked_item(ip->i_mount,
+ (xfs_log_item_t*)(ip->i_itemp));
+ }
+ }
+ xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address);
+}
+
+/*
+ * give up write locks. the i/o lock cannot be held nested
+ * if it is being demoted.
+ */
+void
+xfs_ilock_demote(xfs_inode_t *ip,
+ uint lock_flags)
+{
+ ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL));
+ ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0);
+
+ if (lock_flags & XFS_ILOCK_EXCL) {
+ ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ mrdemote(&ip->i_lock);
+ }
+ if (lock_flags & XFS_IOLOCK_EXCL) {
+ ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE));
+ mrdemote(&ip->i_iolock);
+ }
+}
+
+/*
+ * The following three routines simply manage the i_flock
+ * semaphore embedded in the inode. This semaphore synchronizes
+ * processes attempting to flush the in-core inode back to disk.
+ */
+void
+xfs_iflock(xfs_inode_t *ip)
+{
+ psema(&(ip->i_flock), PINOD|PLTWAIT);
+}
+
+int
+xfs_iflock_nowait(xfs_inode_t *ip)
+{
+ return (cpsema(&(ip->i_flock)));
+}
+
+void
+xfs_ifunlock(xfs_inode_t *ip)
+{
+ ASSERT(valusema(&(ip->i_flock)) <= 0);
+ vsema(&(ip->i_flock));
+}
+
+extern struct vop_vector xfs_vnops;
+
+static int
+xfs_vn_allocate(xfs_mount_t *mp, xfs_inode_t *ip, struct xfs_vnode **vpp)
+{
+ struct vnode *vp;
+ struct xfs_vnode *vdata;
+ int error;
+
+ /* Use zone allocator here? */
+ vdata = kmem_zalloc(sizeof(*vdata), KM_SLEEP);
+
+ error = getnewvnode("xfs", XVFSTOMNT(XFS_MTOVFS(mp)),
+ &xfs_vnops, &vp);
+ if (error) {
+ kmem_free(vdata, sizeof(*vdata));
+ return (error);
+ }
+
+ vp->v_vnlock->lk_flags |= LK_CANRECURSE;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+
+ vp->v_data = (void *)vdata;
+ vdata->v_number= 0;
+ vdata->v_inode = ip;
+ vdata->v_vfsp = XFS_MTOVFS(mp);
+ vdata->v_vnode = vp;
+ vdata->v_type = vp->v_type = VNON;
+
+ vn_bhv_head_init(VN_BHV_HEAD(vdata), "vnode");
+
+#ifdef CONFIG_XFS_VNODE_TRACING
+ vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
+#endif /* CONFIG_XFS_VNODE_TRACING */
+
+ vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address);
+
+ if (error == 0)
+ *vpp = vdata;
+
+ return (error);
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c b/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c
new file mode 100644
index 000000000000..40c3159a6ccd
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c
@@ -0,0 +1,1244 @@
+/*
+ * Copyright (c) 2000-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.h"
+
+#include "xfs_fs.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_alloc.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_bmap.h"
+#include "xfs_bit.h"
+#include "xfs_rtalloc.h"
+#include "xfs_error.h"
+#include "xfs_itable.h"
+#include "xfs_rw.h"
+#include "xfs_acl.h"
+#include "xfs_cap.h"
+#include "xfs_mac.h"
+#include "xfs_attr.h"
+#include "xfs_buf_item.h"
+#include "xfs_utils.h"
+#include "xfs_dfrag.h"
+#include "xfs_fsops.h"
+
+
+#if XXXKAN
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS _IOR('f', 1, long)
+#define XFS_IOC_SETXFLAGS _IOW('f', 2, long)
+#define XFS_IOC_GETVERSION _IOR('v', 1, long)
+
+
+/*
+ * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
+ * a file or fs handle.
+ *
+ * XFS_IOC_PATH_TO_FSHANDLE
+ * returns fs handle for a mount point or path within that mount point
+ * XFS_IOC_FD_TO_HANDLE
+ * returns full handle for a FD opened in user space
+ * XFS_IOC_PATH_TO_HANDLE
+ * returns full handle for a path
+ */
+STATIC int
+xfs_find_handle(
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int hsize;
+ xfs_handle_t handle;
+ xfs_fsop_handlereq_t hreq;
+ struct xfs_vnode *vp;
+ struct thread *td = curthread;
+
+ if (copy_from_user(&hreq, (xfs_fsop_handlereq_t *)arg, sizeof(hreq)))
+ return XFS_ERROR(EFAULT);
+
+ memset((char *)&handle, 0, sizeof(handle));
+
+ switch (cmd) {
+ case XFS_IOC_PATH_TO_FSHANDLE:
+ case XFS_IOC_PATH_TO_HANDLE: {
+ struct nameidata nd;
+ int error;
+
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ,
+ UIO_USERSPACE, hreq.path, td);
+ error = namei(&nd);
+ if (error)
+ return error;
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ break;
+ }
+
+ case XFS_IOC_FD_TO_HANDLE: {
+ struct file *file;
+
+ error = getvnode(td->td_proc->p_fd, hreq.fd, &file);
+ if (error)
+ return error;
+
+ error = vget(vp, LK_EXCLUSIVE, td);
+ if (error) {
+ fdrop(file);
+ return error;
+ }
+ fdrop(file);
+ break;
+ }
+
+ default:
+ ASSERT(0);
+ return XFS_ERROR(EINVAL);
+ }
+
+ if (inode->i_sb->s_magic != XFS_SB_MAGIC) {
+ /* we're not in XFS anymore, Toto */
+ iput(inode);
+ return XFS_ERROR(EINVAL);
+ }
+
+ /* we need the vnode */
+ vp = LINVFS_GET_VP(inode);
+ if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
+ iput(inode);
+ return XFS_ERROR(EBADF);
+ }
+
+ /* now we can grab the fsid */
+ memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));
+ hsize = sizeof(xfs_fsid_t);
+
+ if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {
+ xfs_inode_t *ip;
+ bhv_desc_t *bhv;
+ int lock_mode;
+
+ /* need to get access to the xfs_inode to read the generation */
+ bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);
+ ASSERT(bhv);
+ ip = XFS_BHVTOI(bhv);
+ ASSERT(ip);
+ lock_mode = xfs_ilock_map_shared(ip);
+
+ /* fill in fid section of handle from inode */
+ handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) -
+ sizeof(handle.ha_fid.xfs_fid_len);
+ handle.ha_fid.xfs_fid_pad = 0;
+ handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen;
+ handle.ha_fid.xfs_fid_ino = ip->i_ino;
+
+ xfs_iunlock_map_shared(ip, lock_mode);
+
+ hsize = XFS_HSIZE(handle);
+ }
+
+ /* now copy our handle into the user buffer & write out the size */
+ if (copy_to_user((xfs_handle_t *)hreq.ohandle, &handle, hsize) ||
+ copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {
+ iput(inode);
+ return -XFS_ERROR(EFAULT);
+ }
+
+ iput(inode);
+ return 0;
+}
+
+
+/*
+ * Convert userspace handle data into vnode (and inode).
+ * We [ab]use the fact that all the fsop_handlereq ioctl calls
+ * have a data structure argument whose first component is always
+ * a xfs_fsop_handlereq_t, so we can cast to and from this type.
+ * This allows us to optimise the copy_from_user calls and gives
+ * a handy, shared routine.
+ *
+ * If no error, caller must always VN_RELE the returned vp.
+ */
+STATIC int
+xfs_vget_fsop_handlereq(
+ xfs_mount_t *mp,
+ struct inode *parinode, /* parent inode pointer */
+ int cap, /* capability level for op */
+ unsigned long arg, /* userspace data pointer */
+ unsigned long size, /* size of expected struct */
+ /* output arguments */
+ xfs_fsop_handlereq_t *hreq,
+ vnode_t **vp,
+ struct inode **inode)
+{
+ void *hanp;
+ size_t hlen;
+ xfs_fid_t *xfid;
+ xfs_handle_t *handlep;
+ xfs_handle_t handle;
+ xfs_inode_t *ip;
+ struct inode *inodep;
+ vnode_t *vpp;
+ xfs_ino_t ino;
+ __u32 igen;
+ int error;
+
+ if (!capable(cap))
+ return XFS_ERROR(EPERM);
+
+ /*
+ * Only allow handle opens under a directory.
+ */
+ if (!S_ISDIR(parinode->i_mode))
+ return XFS_ERROR(ENOTDIR);
+
+ /*
+ * Copy the handle down from the user and validate
+ * that it looks to be in the correct format.
+ */
+ if (copy_from_user(hreq, (struct xfs_fsop_handlereq *)arg, size))
+ return XFS_ERROR(EFAULT);
+
+ hanp = hreq->ihandle;
+ hlen = hreq->ihandlen;
+ handlep = &handle;
+
+ if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
+ return XFS_ERROR(EINVAL);
+ if (copy_from_user(handlep, hanp, hlen))
+ return XFS_ERROR(EFAULT);
+ if (hlen < sizeof(*handlep))
+ memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
+ if (hlen > sizeof(handlep->ha_fsid)) {
+ if (handlep->ha_fid.xfs_fid_len !=
+ (hlen - sizeof(handlep->ha_fsid)
+ - sizeof(handlep->ha_fid.xfs_fid_len))
+ || handlep->ha_fid.xfs_fid_pad)
+ return XFS_ERROR(EINVAL);
+ }
+
+ /*
+ * Crack the handle, obtain the inode # & generation #
+ */
+ xfid = (struct xfs_fid *)&handlep->ha_fid;
+ if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
+ ino = xfid->xfs_fid_ino;
+ igen = xfid->xfs_fid_gen;
+ } else {
+ return XFS_ERROR(EINVAL);
+ }
+
+ /*
+ * Get the XFS inode, building a vnode to go with it.
+ */
+ error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0);
+ if (error)
+ return error;
+ if (ip == NULL)
+ return XFS_ERROR(EIO);
+ if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {
+ xfs_iput_new(ip, XFS_ILOCK_SHARED);
+ return XFS_ERROR(ENOENT);
+ }
+
+ vpp = XFS_ITOV(ip);
+ inodep = LINVFS_GET_IP(vpp);
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+
+ *vp = vpp;
+ *inode = inodep;
+ return 0;
+}
+
+STATIC int
+xfs_open_by_handle(
+ xfs_mount_t *mp,
+ unsigned long arg,
+ struct file *parfilp,
+ struct inode *parinode)
+{
+ int error;
+ int new_fd;
+ int permflag;
+ struct file *filp;
+ struct inode *inode;
+ struct dentry *dentry;
+ vnode_t *vp;
+ xfs_fsop_handlereq_t hreq;
+
+ error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
+ sizeof(xfs_fsop_handlereq_t),
+ &hreq, &vp, &inode);
+ if (error)
+ return -error;
+
+ /* Restrict xfs_open_by_handle to directories & regular files. */
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
+ iput(inode);
+ return -XFS_ERROR(EINVAL);
+ }
+
+#if BITS_PER_LONG != 32
+ hreq.oflags |= O_LARGEFILE;
+#endif
+ /* Put open permission in namei format. */
+ permflag = hreq.oflags;
+ if ((permflag+1) & O_ACCMODE)
+ permflag++;
+ if (permflag & O_TRUNC)
+ permflag |= 2;
+
+ if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
+ (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
+ iput(inode);
+ return -XFS_ERROR(EPERM);
+ }
+
+ if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
+ iput(inode);
+ return -XFS_ERROR(EACCES);
+ }
+
+ /* Can't write directories. */
+ if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
+ iput(inode);
+ return -XFS_ERROR(EISDIR);
+ }
+
+ if ((new_fd = get_unused_fd()) < 0) {
+ iput(inode);
+ return new_fd;
+ }
+
+ dentry = d_alloc_anon(inode);
+ if (dentry == NULL) {
+ iput(inode);
+ put_unused_fd(new_fd);
+ return -XFS_ERROR(ENOMEM);
+ }
+
+ /* Ensure umount returns EBUSY on umounts while this file is open. */
+ mntget(parfilp->f_vfsmnt);
+
+ /* Create file pointer. */
+ filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
+ if (IS_ERR(filp)) {
+ put_unused_fd(new_fd);
+ return -XFS_ERROR(-PTR_ERR(filp));
+ }
+ if (inode->i_mode & S_IFREG)
+ filp->f_op = &linvfs_invis_file_operations;
+
+ fd_install(new_fd, filp);
+ return new_fd;
+}
+
+STATIC int
+xfs_readlink_by_handle(
+ xfs_mount_t *mp,
+ unsigned long arg,
+ struct file *parfilp,
+ struct inode *parinode)
+{
+ int error;
+ struct iovec aiov;
+ struct uio auio;
+ struct inode *inode;
+ xfs_fsop_handlereq_t hreq;
+ vnode_t *vp;
+ __u32 olen;
+
+ error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
+ sizeof(xfs_fsop_handlereq_t),
+ &hreq, &vp, &inode);
+ if (error)
+ return -error;
+
+ /* Restrict this handle operation to symlinks only. */
+ if (vp->v_type != VLNK) {
+ VN_RELE(vp);
+ return -XFS_ERROR(EINVAL);
+ }
+
+ if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
+ VN_RELE(vp);
+ return -XFS_ERROR(EFAULT);
+ }
+ aiov.iov_len = olen;
+ aiov.iov_base = hreq.ohandle;
+
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = 0;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_resid = olen;
+
+ VOP_READLINK(vp, &auio, IO_INVIS, NULL, error);
+
+ VN_RELE(vp);
+ return (olen - auio.uio_resid);
+}
+
+STATIC int
+xfs_fssetdm_by_handle(
+ xfs_mount_t *mp,
+ unsigned long arg,
+ struct file *parfilp,
+ struct inode *parinode)
+{
+ int error;
+ struct fsdmidata fsd;
+ xfs_fsop_setdm_handlereq_t dmhreq;
+ struct inode *inode;
+ bhv_desc_t *bdp;
+ vnode_t *vp;
+
+ error = xfs_vget_fsop_handlereq(mp, parinode, CAP_MKNOD, arg,
+ sizeof(xfs_fsop_setdm_handlereq_t),
+ (xfs_fsop_handlereq_t *)&dmhreq,
+ &vp, &inode);
+ if (error)
+ return -error;
+
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ VN_RELE(vp);
+ return -XFS_ERROR(EPERM);
+ }
+
+ if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
+ VN_RELE(vp);
+ return -XFS_ERROR(EFAULT);
+ }
+
+ bdp = bhv_base_unlocked(VN_BHV_HEAD(vp));
+ error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL);
+
+ VN_RELE(vp);
+ if (error)
+ return -error;
+ return 0;
+}
+
+STATIC int
+xfs_attrlist_by_handle(
+ xfs_mount_t *mp,
+ unsigned long arg,
+ struct file *parfilp,
+ struct inode *parinode)
+{
+ int error;
+ attrlist_cursor_kern_t *cursor;
+ xfs_fsop_attrlist_handlereq_t al_hreq;
+ struct inode *inode;
+ vnode_t *vp;
+
+ error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
+ sizeof(xfs_fsop_attrlist_handlereq_t),
+ (xfs_fsop_handlereq_t *)&al_hreq,
+ &vp, &inode);
+ if (error)
+ return -error;
+
+ cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
+ VOP_ATTR_LIST(vp, al_hreq.buffer, al_hreq.buflen, al_hreq.flags,
+ cursor, NULL, error);
+ VN_RELE(vp);
+ if (error)
+ return -error;
+ return 0;
+}
+
+STATIC int
+xfs_attrmulti_by_handle(
+ xfs_mount_t *mp,
+ unsigned long arg,
+ struct file *parfilp,
+ struct inode *parinode)
+{
+ int error;
+ xfs_attr_multiop_t *ops;
+ xfs_fsop_attrmulti_handlereq_t am_hreq;
+ struct inode *inode;
+ vnode_t *vp;
+ int i, size;
+
+ error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
+ sizeof(xfs_fsop_attrmulti_handlereq_t),
+ (xfs_fsop_handlereq_t *)&am_hreq,
+ &vp, &inode);
+ if (error)
+ return -error;
+
+ size = am_hreq.opcount * sizeof(attr_multiop_t);
+ ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL);
+ if (!ops) {
+ VN_RELE(vp);
+ return -XFS_ERROR(ENOMEM);
+ }
+
+ if (copy_from_user(ops, am_hreq.ops, size)) {
+ kfree(ops);
+ VN_RELE(vp);
+ return -XFS_ERROR(EFAULT);
+ }
+
+ for (i = 0; i < am_hreq.opcount; i++) {
+ switch(ops[i].am_opcode) {
+ case ATTR_OP_GET:
+ VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
+ &ops[i].am_length, ops[i].am_flags,
+ NULL, ops[i].am_error);
+ break;
+ case ATTR_OP_SET:
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ ops[i].am_error = EPERM;
+ break;
+ }
+ VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
+ ops[i].am_length, ops[i].am_flags,
+ NULL, ops[i].am_error);
+ break;
+ case ATTR_OP_REMOVE:
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ ops[i].am_error = EPERM;
+ break;
+ }
+ VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
+ NULL, ops[i].am_error);
+ break;
+ default:
+ ops[i].am_error = EINVAL;
+ }
+ }
+
+ if (copy_to_user(am_hreq.ops, ops, size))
+ error = -XFS_ERROR(EFAULT);
+
+ kfree(ops);
+ VN_RELE(vp);
+ return error;
+}
+
+/* prototypes for a few of the stack-hungry cases that have
+ * their own functions. Functions are defined after their use
+ * so gcc doesn't get fancy and inline them with -03 */
+
+STATIC int
+xfs_ioc_space(
+ bhv_desc_t *bdp,
+ vnode_t *vp,
+ struct file *filp,
+ int flags,
+ unsigned int cmd,
+ unsigned long arg);
+
+STATIC int
+xfs_ioc_bulkstat(
+ xfs_mount_t *mp,
+ unsigned int cmd,
+ unsigned long arg);
+
+STATIC int
+xfs_ioc_fsgeometry_v1(
+ xfs_mount_t *mp,
+ unsigned long arg);
+
+STATIC int
+xfs_ioc_fsgeometry(
+ xfs_mount_t *mp,
+ unsigned long arg);
+
+STATIC int
+xfs_ioc_xattr(
+ vnode_t *vp,
+ xfs_inode_t *ip,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg);
+
+STATIC int
+xfs_ioc_getbmap(
+ bhv_desc_t *bdp,
+ struct file *filp,
+ int flags,
+ unsigned int cmd,
+ unsigned long arg);
+
+STATIC int
+xfs_ioc_getbmapx(
+ bhv_desc_t *bdp,
+ unsigned long arg);
+
+int
+xfs_ioctl(
+ bhv_desc_t *bdp,
+ struct inode *inode,
+ struct file *filp,
+ int ioflags,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int error;
+ vnode_t *vp;
+ xfs_inode_t *ip;
+ xfs_mount_t *mp;
+
+ vp = LINVFS_GET_VP(inode);
+
+ vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address);
+
+ ip = XFS_BHVTOI(bdp);
+ mp = ip->i_mount;
+
+ switch (cmd) {
+
+ case XFS_IOC_ALLOCSP:
+ case XFS_IOC_FREESP:
+ case XFS_IOC_RESVSP:
+ case XFS_IOC_UNRESVSP:
+ case XFS_IOC_ALLOCSP64:
+ case XFS_IOC_FREESP64:
+ case XFS_IOC_RESVSP64:
+ case XFS_IOC_UNRESVSP64:
+ /*
+ * Only allow the sys admin to reserve space unless
+ * unwritten extents are enabled.
+ */
+ if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) &&
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
+
+ case XFS_IOC_DIOINFO: {
+ struct dioattr da;
+
+ da.d_miniosz = mp->m_sb.sb_blocksize;
+ da.d_mem = mp->m_sb.sb_blocksize;
+
+ /*
+ * this only really needs to be BBSIZE.
+ * it is set to the file system block size to
+ * avoid having to do block zeroing on short writes.
+ */
+ da.d_maxiosz = XFS_FSB_TO_B(mp,
+ XFS_B_TO_FSBT(mp, KIO_MAX_ATOMIC_IO << 10));
+
+ if (copy_to_user((struct dioattr *)arg, &da, sizeof(da)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_FSBULKSTAT_SINGLE:
+ case XFS_IOC_FSBULKSTAT:
+ case XFS_IOC_FSINUMBERS:
+ return xfs_ioc_bulkstat(mp, cmd, arg);
+
+ case XFS_IOC_FSGEOMETRY_V1:
+ return xfs_ioc_fsgeometry_v1(mp, arg);
+
+ case XFS_IOC_FSGEOMETRY:
+ return xfs_ioc_fsgeometry(mp, arg);
+
+ case XFS_IOC_GETVERSION:
+ case XFS_IOC_GETXFLAGS:
+ case XFS_IOC_SETXFLAGS:
+ case XFS_IOC_FSGETXATTR:
+ case XFS_IOC_FSSETXATTR:
+ case XFS_IOC_FSGETXATTRA:
+ return xfs_ioc_xattr(vp, ip, filp, cmd, arg);
+
+ case XFS_IOC_FSSETDM: {
+ struct fsdmidata dmi;
+
+ if (copy_from_user(&dmi, (struct fsdmidata *)arg, sizeof(dmi)))
+ return -XFS_ERROR(EFAULT);
+
+ error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate,
+ NULL);
+ return -error;
+ }
+
+ case XFS_IOC_GETBMAP:
+ case XFS_IOC_GETBMAPA:
+ return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg);
+
+ case XFS_IOC_GETBMAPX:
+ return xfs_ioc_getbmapx(bdp, arg);
+
+ case XFS_IOC_FD_TO_HANDLE:
+ case XFS_IOC_PATH_TO_HANDLE:
+ case XFS_IOC_PATH_TO_FSHANDLE:
+ return xfs_find_handle(cmd, arg);
+
+ case XFS_IOC_OPEN_BY_HANDLE:
+ return xfs_open_by_handle(mp, arg, filp, inode);
+
+ case XFS_IOC_FSSETDM_BY_HANDLE:
+ return xfs_fssetdm_by_handle(mp, arg, filp, inode);
+
+ case XFS_IOC_READLINK_BY_HANDLE:
+ return xfs_readlink_by_handle(mp, arg, filp, inode);
+
+ case XFS_IOC_ATTRLIST_BY_HANDLE:
+ return xfs_attrlist_by_handle(mp, arg, filp, inode);
+
+ case XFS_IOC_ATTRMULTI_BY_HANDLE:
+ return xfs_attrmulti_by_handle(mp, arg, filp, inode);
+
+ case XFS_IOC_SWAPEXT: {
+ error = xfs_swapext((struct xfs_swapext *)arg);
+ return -error;
+ }
+
+ case XFS_IOC_FSCOUNTS: {
+ xfs_fsop_counts_t out;
+
+ error = xfs_fs_counts(mp, &out);
+ if (error)
+ return -error;
+
+ if (copy_to_user((char *)arg, &out, sizeof(out)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_SET_RESBLKS: {
+ xfs_fsop_resblks_t inout;
+ __uint64_t in;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&inout, (char *)arg, sizeof(inout)))
+ return -XFS_ERROR(EFAULT);
+
+ /* input parameter is passed in resblks field of structure */
+ in = inout.resblks;
+ error = xfs_reserve_blocks(mp, &in, &inout);
+ if (error)
+ return -error;
+
+ if (copy_to_user((char *)arg, &inout, sizeof(inout)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_GET_RESBLKS: {
+ xfs_fsop_resblks_t out;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ error = xfs_reserve_blocks(mp, NULL, &out);
+ if (error)
+ return -error;
+
+ if (copy_to_user((char *)arg, &out, sizeof(out)))
+ return -XFS_ERROR(EFAULT);
+
+ return 0;
+ }
+
+ case XFS_IOC_FSGROWFSDATA: {
+ xfs_growfs_data_t in;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&in, (char *)arg, sizeof(in)))
+ return -XFS_ERROR(EFAULT);
+
+ error = xfs_growfs_data(mp, &in);
+ return -error;
+ }
+
+ case XFS_IOC_FSGROWFSLOG: {
+ xfs_growfs_log_t in;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&in, (char *)arg, sizeof(in)))
+ return -XFS_ERROR(EFAULT);
+
+ error = xfs_growfs_log(mp, &in);
+ return -error;
+ }
+
+ case XFS_IOC_FSGROWFSRT: {
+ xfs_growfs_rt_t in;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&in, (char *)arg, sizeof(in)))
+ return -XFS_ERROR(EFAULT);
+
+ error = xfs_growfs_rt(mp, &in);
+ return -error;
+ }
+
+ case XFS_IOC_FREEZE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ xfs_fs_freeze(mp);
+ return 0;
+
+ case XFS_IOC_THAW:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ xfs_fs_thaw(mp);
+ return 0;
+
+ case XFS_IOC_GOINGDOWN: {
+ __uint32_t in;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (get_user(in, (__uint32_t *)arg))
+ return -XFS_ERROR(EFAULT);
+
+ error = xfs_fs_goingdown(mp, in);
+ return -error;
+ }
+
+ case XFS_IOC_ERROR_INJECTION: {
+ xfs_error_injection_t in;
+
+ if (copy_from_user(&in, (char *)arg, sizeof(in)))
+ return -XFS_ERROR(EFAULT);
+
+ error = xfs_errortag_add(in.errtag, mp);
+ return -error;
+ }
+
+ case XFS_IOC_ERROR_CLEARALL:
+ error = xfs_errortag_clearall(mp);
+ return -error;
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+STATIC int
+xfs_ioc_space(
+ bhv_desc_t *bdp,
+ vnode_t *vp,
+ struct file *filp,
+ int ioflags,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ xfs_flock64_t bf;
+ int attr_flags = 0;
+ int error;
+
+ if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
+ return -XFS_ERROR(EPERM);
+
+ if (filp->f_flags & O_RDONLY)
+ return -XFS_ERROR(EBADF);
+
+ if (vp->v_type != VREG)
+ return -XFS_ERROR(EINVAL);
+
+ if (copy_from_user(&bf, (xfs_flock64_t *)arg, sizeof(bf)))
+ return -XFS_ERROR(EFAULT);
+
+ if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
+ attr_flags |= ATTR_NONBLOCK;
+ if (ioflags & IO_INVIS)
+ attr_flags |= ATTR_DMI;
+
+ error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos,
+ NULL, attr_flags);
+ return -error;
+}
+
+STATIC int
+xfs_ioc_bulkstat(
+ xfs_mount_t *mp,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ xfs_fsop_bulkreq_t bulkreq;
+ int count; /* # of records returned */
+ xfs_ino_t inlast; /* last inode number */
+ int done;
+ int error;
+
+ /* done = 1 if there are more stats to get and if bulkstat */
+ /* should be called again (unused here, but used in dmapi) */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -XFS_ERROR(EIO);
+
+ if (copy_from_user(&bulkreq, (xfs_fsop_bulkreq_t *)arg,
+ sizeof(xfs_fsop_bulkreq_t)))
+ return -XFS_ERROR(EFAULT);
+
+ if (copy_from_user(&inlast, (__s64 *)bulkreq.lastip,
+ sizeof(__s64)))
+ return -XFS_ERROR(EFAULT);
+
+ if ((count = bulkreq.icount) <= 0)
+ return -XFS_ERROR(EINVAL);
+
+ if (cmd == XFS_IOC_FSINUMBERS)
+ error = xfs_inumbers(mp, NULL, &inlast, &count,
+ bulkreq.ubuffer);
+ else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
+ error = xfs_bulkstat_single(mp, &inlast,
+ bulkreq.ubuffer, &done);
+ else { /* XFS_IOC_FSBULKSTAT */
+ if (count == 1 && inlast != 0) {
+ inlast++;
+ error = xfs_bulkstat_single(mp, &inlast,
+ bulkreq.ubuffer, &done);
+ } else {
+ error = xfs_bulkstat(mp, NULL, &inlast, &count,
+ (bulkstat_one_pf)xfs_bulkstat_one, NULL,
+ sizeof(xfs_bstat_t), bulkreq.ubuffer,
+ BULKSTAT_FG_QUICK, &done);
+ }
+ }
+
+ if (error)
+ return -error;
+
+ if (bulkreq.ocount != NULL) {
+ if (copy_to_user((xfs_ino_t *)bulkreq.lastip, &inlast,
+ sizeof(xfs_ino_t)))
+ return -XFS_ERROR(EFAULT);
+
+ if (copy_to_user((__s32 *)bulkreq.ocount, &count,
+ sizeof(count)))
+ return -XFS_ERROR(EFAULT);
+ }
+
+ return 0;
+}
+
+STATIC int
+xfs_ioc_fsgeometry_v1(
+ xfs_mount_t *mp,
+ unsigned long arg)
+{
+ xfs_fsop_geom_v1_t fsgeo;
+ int error;
+
+ error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
+ if (error)
+ return -error;
+
+ if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, sizeof(fsgeo)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+}
+
+STATIC int
+xfs_ioc_fsgeometry(
+ xfs_mount_t *mp,
+ unsigned long arg)
+{
+ xfs_fsop_geom_t fsgeo;
+ int error;
+
+ error = xfs_fs_geometry(mp, &fsgeo, 4);
+ if (error)
+ return -error;
+
+ if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, sizeof(fsgeo)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+}
+
+/*
+ * Linux extended inode flags interface.
+ */
+#define LINUX_XFLAG_SYNC 0x00000008 /* Synchronous updates */
+#define LINUX_XFLAG_IMMUTABLE 0x00000010 /* Immutable file */
+#define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */
+#define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */
+#define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */
+
+STATIC unsigned int
+xfs_merge_ioc_xflags(
+ unsigned int flags,
+ unsigned int start)
+{
+ unsigned int xflags = start;
+
+ if (flags & LINUX_XFLAG_IMMUTABLE)
+ xflags |= XFS_XFLAG_IMMUTABLE;
+ else
+ xflags &= ~XFS_XFLAG_IMMUTABLE;
+ if (flags & LINUX_XFLAG_APPEND)
+ xflags |= XFS_XFLAG_APPEND;
+ else
+ xflags &= ~XFS_XFLAG_APPEND;
+ if (flags & LINUX_XFLAG_SYNC)
+ xflags |= XFS_XFLAG_SYNC;
+ else
+ xflags &= ~XFS_XFLAG_SYNC;
+ if (flags & LINUX_XFLAG_NOATIME)
+ xflags |= XFS_XFLAG_NOATIME;
+ else
+ xflags &= ~XFS_XFLAG_NOATIME;
+ if (flags & LINUX_XFLAG_NODUMP)
+ xflags |= XFS_XFLAG_NODUMP;
+ else
+ xflags &= ~XFS_XFLAG_NODUMP;
+
+ return xflags;
+}
+
+STATIC int
+xfs_ioc_xattr(
+ vnode_t *vp,
+ xfs_inode_t *ip,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct fsxattr fa;
+ vattr_t va;
+ int error;
+ int attr_flags;
+ unsigned int flags;
+
+ switch (cmd) {
+ case XFS_IOC_FSGETXATTR: {
+ va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS;
+ VOP_GETATTR(vp, &va, 0, NULL, error);
+ if (error)
+ return -error;
+
+ fa.fsx_xflags = va.va_xflags;
+ fa.fsx_extsize = va.va_extsize;
+ fa.fsx_nextents = va.va_nextents;
+
+ if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_FSSETXATTR: {
+ if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa)))
+ return -XFS_ERROR(EFAULT);
+
+ attr_flags = 0;
+ if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
+ attr_flags |= ATTR_NONBLOCK;
+
+ va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
+ va.va_xflags = fa.fsx_xflags;
+ va.va_extsize = fa.fsx_extsize;
+
+ VOP_SETATTR(vp, &va, attr_flags, NULL, error);
+ if (!error)
+ vn_revalidate(vp); /* update Linux inode flags */
+ return -error;
+ }
+
+ case XFS_IOC_FSGETXATTRA: {
+ va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS;
+ VOP_GETATTR(vp, &va, 0, NULL, error);
+ if (error)
+ return -error;
+
+ fa.fsx_xflags = va.va_xflags;
+ fa.fsx_extsize = va.va_extsize;
+ fa.fsx_nextents = va.va_anextents;
+
+ if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_GETXFLAGS: {
+ flags = 0;
+ if (ip->i_d.di_flags & XFS_XFLAG_IMMUTABLE)
+ flags |= LINUX_XFLAG_IMMUTABLE;
+ if (ip->i_d.di_flags & XFS_XFLAG_APPEND)
+ flags |= LINUX_XFLAG_APPEND;
+ if (ip->i_d.di_flags & XFS_XFLAG_SYNC)
+ flags |= LINUX_XFLAG_SYNC;
+ if (ip->i_d.di_flags & XFS_XFLAG_NOATIME)
+ flags |= LINUX_XFLAG_NOATIME;
+ if (ip->i_d.di_flags & XFS_XFLAG_NODUMP)
+ flags |= LINUX_XFLAG_NODUMP;
+ if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ case XFS_IOC_SETXFLAGS: {
+ if (copy_from_user(&flags, (unsigned int *)arg, sizeof(flags)))
+ return -XFS_ERROR(EFAULT);
+
+ if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \
+ LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \
+ LINUX_XFLAG_SYNC))
+ return -XFS_ERROR(EOPNOTSUPP);
+
+ attr_flags = 0;
+ if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
+ attr_flags |= ATTR_NONBLOCK;
+
+ va.va_mask = XFS_AT_XFLAGS;
+ va.va_xflags = xfs_merge_ioc_xflags(flags, ip->i_d.di_flags);
+
+ VOP_SETATTR(vp, &va, attr_flags, NULL, error);
+ if (!error)
+ vn_revalidate(vp); /* update Linux inode flags */
+ return -error;
+ }
+
+ case XFS_IOC_GETVERSION: {
+ flags = LINVFS_GET_IP(vp)->i_generation;
+ if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+ }
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+STATIC int
+xfs_ioc_getbmap(
+ bhv_desc_t *bdp,
+ struct file *filp,
+ int ioflags,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct getbmap bm;
+ int iflags;
+ int error;
+
+ if (copy_from_user(&bm, (struct getbmap *)arg, sizeof(bm)))
+ return -XFS_ERROR(EFAULT);
+
+ if (bm.bmv_count < 2)
+ return -XFS_ERROR(EINVAL);
+
+ iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
+ if (ioflags & IO_INVIS)
+ iflags |= BMV_IF_NO_DMAPI_READ;
+
+ error = xfs_getbmap(bdp, &bm, (struct getbmap *)arg+1, iflags);
+ if (error)
+ return -error;
+
+ if (copy_to_user((struct getbmap *)arg, &bm, sizeof(bm)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+}
+
+STATIC int
+xfs_ioc_getbmapx(
+ bhv_desc_t *bdp,
+ unsigned long arg)
+{
+ struct getbmapx bmx;
+ struct getbmap bm;
+ int iflags;
+ int error;
+
+ if (copy_from_user(&bmx, (struct getbmapx *)arg, sizeof(bmx)))
+ return -XFS_ERROR(EFAULT);
+
+ if (bmx.bmv_count < 2)
+ return -XFS_ERROR(EINVAL);
+
+ /*
+ * Map input getbmapx structure to a getbmap
+ * structure for xfs_getbmap.
+ */
+ GETBMAP_CONVERT(bmx, bm);
+
+ iflags = bmx.bmv_iflags;
+
+ if (iflags & (~BMV_IF_VALID))
+ return -XFS_ERROR(EINVAL);
+
+ iflags |= BMV_IF_EXTENDED;
+
+ error = xfs_getbmap(bdp, &bm, (struct getbmapx *)arg+1, iflags);
+ if (error)
+ return -error;
+
+ GETBMAP_CONVERT(bm, bmx);
+
+ if (copy_to_user((struct getbmapx *)arg, &bmx, sizeof(bmx)))
+ return -XFS_ERROR(EFAULT);
+
+ return 0;
+}
+
+#endif
+
+int
+xfs_ioctl(
+ bhv_desc_t *bdp,
+ struct inode *inode,
+ struct file *filp,
+ int ioflags,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ return EINVAL;
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_iops.h b/sys/gnu/fs/xfs/FreeBSD/xfs_iops.h
new file mode 100644
index 000000000000..20549a793ce4
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_iops.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000-2002 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/
+ */
+#ifndef __XFS_IOPS_H__
+#define __XFS_IOPS_H__
+
+/*
+ * Extended system attributes.
+ * So far only POSIX ACLs are supported, but this will need to
+ * grow in time (capabilities, mandatory access control, etc).
+ */
+#define XFS_SYSTEM_NAMESPACE SYSTEM_POSIXACL
+
+/*
+ * Define a table of the namespaces XFS supports
+ */
+typedef int (*xattr_exists_t)(xfs_vnode_t *);
+
+typedef struct xattr_namespace {
+ char *name;
+ unsigned int namelen;
+ xattr_exists_t exists;
+} xattr_namespace_t;
+
+#define SYSTEM_NAMES 0
+#define ROOT_NAMES 1
+#define USER_NAMES 2
+extern struct xattr_namespace *xfs_namespaces;
+
+extern int xfs_ioctl(struct bhv_desc *, struct inode *, struct file *,
+ int, unsigned int, unsigned long);
+#endif /* __XFS_IOPS_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_mountops.c b/sys/gnu/fs/xfs/FreeBSD/xfs_mountops.c
new file mode 100644
index 000000000000..78a091fa4003
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_mountops.c
@@ -0,0 +1,459 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+
+#include <geom/geom.h>
+#include <geom/geom_vfs.h>
+
+#include "xfs.h"
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_alloc.h"
+#include "xfs_rtalloc.h"
+#include "xfs_bmap.h"
+#include "xfs_error.h"
+#include "xfs_bit.h"
+#include "xfs_rw.h"
+#include "xfs_quota.h"
+#include "xfs_fsops.h"
+#include "xfs_clnt.h"
+
+#include <xfs_mountops.h>
+
+MALLOC_DEFINE(M_XFSNODE, "XFS node", "XFS vnode private part");
+
+static vfs_mount_t _xfs_mount;
+static vfs_unmount_t _xfs_unmount;
+static vfs_root_t _xfs_root;
+static vfs_quotactl_t _xfs_quotactl;
+static vfs_statfs_t _xfs_statfs;
+static vfs_sync_t _xfs_sync;
+static vfs_vget_t _xfs_vget;
+static vfs_fhtovp_t _xfs_fhtovp;
+static vfs_checkexp_t _xfs_checkexp;
+static vfs_vptofh_t _xfs_vptofh;
+static vfs_init_t _xfs_init;
+static vfs_uninit_t _xfs_uninit;
+static vfs_extattrctl_t _xfs_extattrctl;
+
+static b_strategy_t xfs_geom_strategy;
+
+static const char *xfs_opts[] =
+ { "from", "flags", "logbufs", "logbufsize",
+ "rtname", "logname", "iosizelog", "sunit",
+ "swidth",
+ NULL };
+
+static void
+parse_int(struct mount *mp, const char *opt, int *val, int *error)
+{
+ char *tmp, *ep;
+
+ tmp = vfs_getopts(mp->mnt_optnew, opt, error);
+ if (*error != 0) {
+ return;
+ }
+ if (tmp != NULL) {
+ *val = (int)strtol(tmp, &ep, 10);
+ if (*ep) {
+ *error = EINVAL;
+ return;
+ }
+ }
+}
+
+static int
+_xfs_param_copyin(struct mount *mp, struct thread *td)
+{
+ struct xfsmount *xmp = MNTTOXFS(mp);
+ struct xfs_mount_args *args = &xmp->m_args;
+ char *path;
+ char *fsname;
+ char *rtname;
+ char *logname;
+ int error;
+
+ path = vfs_getopts(mp->mnt_optnew, "fspath", &error);
+ if (error)
+ return (error);
+
+ bzero(args, sizeof(struct xfs_mount_args));
+ args->logbufs = -1;
+ args->logbufsize = -1;
+
+ parse_int(mp, "flags", &args->flags, &error);
+ if (error != 0)
+ return error;
+
+ args->flags |= XFSMNT_32BITINODES;
+
+ parse_int(mp, "sunit", &args->sunit, &error);
+ if (error != 0)
+ return error;
+
+ parse_int(mp, "swidth", &args->swidth, &error);
+ if (error != 0)
+ return error;
+
+ parse_int(mp, "logbufs", &args->logbufs, &error);
+ if (error != 0)
+ return error;
+
+ parse_int(mp, "logbufsize", &args->logbufsize, &error);
+ if (error != 0)
+ return error;
+
+ fsname = vfs_getopts(mp->mnt_optnew, "from", &error);
+ if (error == 0 && fsname != NULL) {
+ strncpy(args->fsname, fsname, sizeof(args->fsname) - 1);
+ }
+
+ logname = vfs_getopts(mp->mnt_optnew, "logname", &error);
+ if (error == 0 && logname != NULL) {
+ strncpy(args->logname, logname, sizeof(args->logname) - 1);
+ }
+
+ rtname = vfs_getopts(mp->mnt_optnew, "rtname", &error);
+ if (error == 0 && rtname != NULL) {
+ strncpy(args->rtname, rtname, sizeof(args->rtname) - 1);
+ }
+
+ strncpy(args->mtpt, path, sizeof(args->mtpt));
+
+ printf("fsname '%s' logname '%s' rtname '%s'\n"
+ "flags 0x%x sunit %d swidth %d logbufs %d logbufsize %d\n",
+ args->fsname, args->logname, args->rtname, args->flags,
+ args->sunit, args->swidth, args->logbufs, args->logbufsize);
+
+ vfs_mountedfrom(mp, args->fsname);
+
+ return (0);
+}
+
+static int
+_xfs_mount(struct mount *mp,
+ struct thread *td)
+{
+ struct xfsmount *xmp;
+ struct xfs_vnode *rootvp;
+ struct ucred *curcred;
+ struct vnode *rvp;
+ struct cdev *ddev;
+ int error;
+
+ if (vfs_filteropt(mp->mnt_optnew, xfs_opts))
+ return (EINVAL);
+
+ xmp = xfsmount_allocate(mp);
+ if (xmp == NULL)
+ return (ENOMEM);
+
+ if((error = _xfs_param_copyin(mp, td)) != 0)
+ goto fail;
+
+ /* Force read-only mounts in this branch. */
+ XFSTOVFS(xmp)->vfs_flag |= VFS_RDONLY;
+ mp->mnt_flag |= MNT_RDONLY;
+
+ /* XXX: Do not support MNT_UPDATE yet */
+ if (mp->mnt_flag & MNT_UPDATE)
+ return EOPNOTSUPP;
+
+ curcred = td->td_ucred;
+ XVFS_MOUNT(XFSTOVFS(xmp), &xmp->m_args, curcred, error);
+ if (error)
+ goto fail;
+
+ XVFS_ROOT(XFSTOVFS(xmp), &rootvp, error);
+ if (error)
+ goto fail_unmount;
+
+ ddev = XFS_VFSTOM(XFSTOVFS(xmp))->m_dev;
+ if (ddev->si_iosize_max != 0)
+ mp->mnt_iosize_max = ddev->si_iosize_max;
+ if (mp->mnt_iosize_max > MAXPHYS)
+ mp->mnt_iosize_max = MAXPHYS;
+
+ mp->mnt_flag |= MNT_LOCAL | MNT_RDONLY;
+ mp->mnt_stat.f_fsid.val[0] = dev2udev(ddev);
+ mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
+
+ VFS_STATFS(mp, &mp->mnt_stat, td);
+ if (error)
+ goto fail_unmount;
+
+ rvp = rootvp->v_vnode;
+ rvp->v_vflag |= VV_ROOT;
+ VN_RELE(rootvp);
+
+ return (0);
+
+ fail_unmount:
+ XVFS_UNMOUNT(XFSTOVFS(xmp), 0, curcred, error);
+
+ fail:
+ if (xmp != NULL)
+ xfsmount_deallocate(xmp);
+
+ return (error);
+}
+
+/*
+ * Free reference to null layer
+ */
+static int
+_xfs_unmount(mp, mntflags, td)
+ struct mount *mp;
+ int mntflags;
+ struct thread *td;
+{
+ int error;
+
+ XVFS_UNMOUNT(MNTTOVFS(mp), 0, td->td_ucred, error);
+ return (error);
+}
+
+static int
+_xfs_root(mp, flags, vpp, td)
+ struct mount *mp;
+ int flags;
+ struct vnode **vpp;
+ struct thread *td;
+{
+ xfs_vnode_t *vp;
+ int error;
+
+ XVFS_ROOT(MNTTOVFS(mp), &vp, error);
+ if (error == 0) {
+ *vpp = vp->v_vnode;
+ VOP_LOCK(*vpp, flags, curthread);
+ }
+ return (error);
+}
+
+static int
+_xfs_quotactl(mp, cmd, uid, arg, td)
+ struct mount *mp;
+ int cmd;
+ uid_t uid;
+ caddr_t arg;
+ struct thread *td;
+{
+ printf("xfs_quotactl\n");
+ return ENOSYS;
+}
+
+static int
+_xfs_statfs(mp, sbp, td)
+ struct mount *mp;
+ struct statfs *sbp;
+ struct thread *td;
+{
+ int error;
+
+ XVFS_STATVFS(MNTTOVFS(mp), sbp, NULL, error);
+ if (error)
+ return error;
+
+ /* Fix up the values XFS statvfs calls does not know about. */
+ sbp->f_iosize = sbp->f_bsize;
+
+ return (error);
+}
+
+static int
+_xfs_sync(mp, waitfor, td)
+ struct mount *mp;
+ int waitfor;
+ struct thread *td;
+{
+ int error;
+ int flags = SYNC_FSDATA|SYNC_ATTR|SYNC_REFCACHE;
+
+ if (waitfor == MNT_WAIT)
+ flags |= SYNC_WAIT;
+ else if (waitfor == MNT_LAZY)
+ flags |= SYNC_BDFLUSH;
+ XVFS_SYNC(MNTTOVFS(mp), flags, td->td_ucred, error);
+ return (error);
+}
+
+static int
+_xfs_vget(mp, ino, flags, vpp)
+ struct mount *mp;
+ ino_t ino;
+ int flags;
+ struct vnode **vpp;
+{
+ xfs_vnode_t *vp;
+ int error;
+
+ printf("XVFS_GET_VNODE(MNTTOVFS(mp), &vp, ino, error);\n");
+ error = ENOSYS;
+ if (error == 0)
+ *vpp = vp->v_vnode;
+ return (error);
+}
+
+static int
+_xfs_fhtovp(mp, fidp, vpp)
+ struct mount *mp;
+ struct fid *fidp;
+ struct vnode **vpp;
+{
+ printf("xfs_fhtovp\n");
+ return ENOSYS;
+}
+
+static int
+_xfs_checkexp(mp, nam, extflagsp, credanonp)
+ struct mount *mp;
+ struct sockaddr *nam;
+ int *extflagsp;
+ struct ucred **credanonp;
+{
+ printf("xfs_checkexp\n");
+ return ENOSYS;
+}
+
+static int
+_xfs_vptofh(vp, fhp)
+ struct vnode *vp;
+ struct fid *fhp;
+{
+ printf("xfs_vptofh");
+ return ENOSYS;
+}
+
+static int
+_xfs_extattrctl(struct mount *mp, int cm,
+ struct vnode *filename_v,
+ int attrnamespace, const char *attrname,
+ struct thread *td)
+{
+ printf("xfs_extattrctl\n");
+ return ENOSYS;
+}
+
+int
+_xfs_init(vfsp)
+ struct vfsconf *vfsp;
+{
+ int error;
+
+ error = init_xfs_fs();
+
+ return (error);
+}
+
+int
+_xfs_uninit(vfsp)
+ struct vfsconf *vfsp;
+{
+ exit_xfs_fs();
+ return 0;
+}
+
+static struct vfsops xfs_fsops = {
+ .vfs_mount = _xfs_mount,
+ .vfs_unmount = _xfs_unmount,
+ .vfs_root = _xfs_root,
+ .vfs_quotactl = _xfs_quotactl,
+ .vfs_statfs = _xfs_statfs,
+ .vfs_sync = _xfs_sync,
+ .vfs_vget = _xfs_vget,
+ .vfs_fhtovp = _xfs_fhtovp,
+ .vfs_checkexp = _xfs_checkexp,
+ .vfs_vptofh = _xfs_vptofh,
+ .vfs_init = _xfs_init,
+ .vfs_uninit = _xfs_uninit,
+ .vfs_extattrctl = _xfs_extattrctl,
+};
+
+/* XXX: Read-only for now */
+VFS_SET(xfs_fsops, xfs, VFCF_READONLY);
+
+/*
+ * Copy GEOM VFS functions here to provide a conveniet place to
+ * track all XFS-related IO without being distracted by other
+ * filesystems which happen to be mounted on the machine at the
+ * same time.
+ */
+
+static void
+xfs_geom_biodone(struct bio *bip)
+{
+ struct buf *bp;
+
+ if (bip->bio_error) {
+ printf("g_vfs_done():");
+ g_print_bio(bip);
+ printf("error = %d\n", bip->bio_error);
+ }
+ bp = bip->bio_caller2;
+ bp->b_error = bip->bio_error;
+ bp->b_ioflags = bip->bio_flags;
+ if (bip->bio_error)
+ bp->b_ioflags |= BIO_ERROR;
+ bp->b_resid = bp->b_bcount - bip->bio_completed;
+ g_destroy_bio(bip);
+ mtx_lock(&Giant);
+ bufdone(bp);
+ mtx_unlock(&Giant);
+}
+
+static void
+xfs_geom_strategy(struct bufobj *bo, struct buf *bp)
+{
+ struct g_consumer *cp;
+ struct bio *bip;
+
+ cp = bo->bo_private;
+ G_VALID_CONSUMER(cp);
+
+ bip = g_alloc_bio();
+ bip->bio_cmd = bp->b_iocmd;
+ bip->bio_offset = bp->b_iooffset;
+ bip->bio_data = bp->b_data;
+ bip->bio_done = xfs_geom_biodone;
+ bip->bio_caller2 = bp;
+ bip->bio_length = bp->b_bcount;
+ g_io_request(bip, cp);
+}
+
+static int
+xfs_geom_bufwrite(struct buf *bp)
+{
+ return bufwrite(bp);
+}
+
+struct buf_ops xfs_ops = {
+ .bop_name = "XFS",
+ .bop_write = xfs_geom_bufwrite,
+ .bop_strategy = xfs_geom_strategy,
+ .bop_sync = bufsync,
+};
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_mountops.h b/sys/gnu/fs/xfs/FreeBSD/xfs_mountops.h
new file mode 100644
index 000000000000..c8a766d5155f
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_mountops.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2001 Alexander Kabaev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _XFS_XFS_H_
+#define _XFS_XFS_H_
+
+#define XFSFS_VMAJOR 0
+#define XFS_VMINOR 1
+#define XFS_VERSION ((XFS_VMAJOR << 16) | XFS_VMINOR)
+#define XFS_NAME "xfs"
+
+#ifdef _KERNEL
+
+struct xfsmount {
+ struct xfs_mount_args m_args; /* Mount parameters */
+ struct mount * m_mp; /* Back pointer */
+ xfs_vfs_t m_vfs; /* SHOULD BE FIRST */
+};
+
+#define XFSTOMNT(xmp) ((xmp)->m_mp)
+#define XFSTOVFS(xmp) (&(xmp)->m_vfs)
+
+#define MNTTOXFS(mp) ((struct xfsmount *)((mp)->mnt_data))
+#define MNTTOVFS(mp) XFSTOVFS(MNTTOXFS(mp))
+
+#define VFSTOMNT(vfsp) (vfsp)->vfs_mp
+#define VFSTOXFS(vfsp) MNTTOXFS(VFSTOMNT(vfsp))
+
+struct xfsmount *xfsmount_allocate(struct mount *mp);
+void xfsmount_deallocate(struct xfsmount *xmp);
+
+#endif /* _KERNEL */
+
+#endif /* _XFS_XFS_H*/
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_node.h b/sys/gnu/fs/xfs/FreeBSD/xfs_node.h
new file mode 100644
index 000000000000..d8b613c3c50a
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_node.h
@@ -0,0 +1,16 @@
+#ifndef __XFS_NODE_H__
+#define __XFS_NODE_H__
+
+/*
+ * Save one allocation on FreeBSD and always allocate both inode and
+ * xfs_vnode struct as a single memory block.
+ */
+struct xfs_node
+{
+ struct xfs_inode n_inode;
+ struct xfs_vnode n_vnode;
+};
+
+#define XFS_CAST_IP2VP(ip) (&((struct xfs_node *)(ip))->n_vnode)
+
+#endif /* __XFS_NODE_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_stats.c b/sys/gnu/fs/xfs/FreeBSD/xfs_stats.c
new file mode 100644
index 000000000000..04582ee77d1e
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_stats.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2000-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.h"
+
+struct xfsstats xfsstats;
+
+STATIC int
+xfs_read_xfsstats(
+ char *buffer,
+ char **start,
+ off_t offset,
+ int count,
+ int *eof,
+ void *data)
+{
+ int i, j, len;
+ static struct xstats_entry {
+ char *desc;
+ int endpoint;
+ } xstats[] = {
+ { "extent_alloc", XFSSTAT_END_EXTENT_ALLOC },
+ { "abt", XFSSTAT_END_ALLOC_BTREE },
+ { "blk_map", XFSSTAT_END_BLOCK_MAPPING },
+ { "bmbt", XFSSTAT_END_BLOCK_MAP_BTREE },
+ { "dir", XFSSTAT_END_DIRECTORY_OPS },
+ { "trans", XFSSTAT_END_TRANSACTIONS },
+ { "ig", XFSSTAT_END_INODE_OPS },
+ { "log", XFSSTAT_END_LOG_OPS },
+ { "push_ail", XFSSTAT_END_TAIL_PUSHING },
+ { "xstrat", XFSSTAT_END_WRITE_CONVERT },
+ { "rw", XFSSTAT_END_READ_WRITE_OPS },
+ { "attr", XFSSTAT_END_ATTRIBUTE_OPS },
+ { "icluster", XFSSTAT_END_INODE_CLUSTER },
+ { "vnodes", XFSSTAT_END_VNODE_OPS },
+ };
+
+ for (i=j=len = 0; i < sizeof(xstats)/sizeof(struct xstats_entry); i++) {
+ len += sprintf(buffer + len, xstats[i].desc);
+ /* inner loop does each group */
+ while (j < xstats[i].endpoint) {
+ len += sprintf(buffer + len, " %u",
+ *(((__u32*)&xfsstats) + j));
+ j++;
+ }
+ buffer[len++] = '\n';
+ }
+ /* extra precision counters */
+ len += sprintf(buffer + len, "xpc %ju %ju %ju\n",
+ (uintmax_t)xfsstats.xs_xstrat_bytes,
+ (uintmax_t)xfsstats.xs_write_bytes,
+ (uintmax_t)xfsstats.xs_read_bytes);
+
+ if (offset >= len) {
+ *start = buffer;
+ *eof = 1;
+ return 0;
+ }
+ *start = buffer + offset;
+ if ((len -= offset) > count)
+ return count;
+ *eof = 1;
+
+ return len;
+}
+
+void
+xfs_init_procfs(void)
+{
+ if (&xfs_read_xfsstats != NULL);
+}
+
+void
+xfs_cleanup_procfs(void)
+{
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_stats.h b/sys/gnu/fs/xfs/FreeBSD/xfs_stats.h
new file mode 100644
index 000000000000..04ddc95d46f4
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_stats.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2000 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/
+ */
+#ifndef __XFS_STATS_H__
+#define __XFS_STATS_H__
+
+
+#if !defined(XFS_STATS_OFF)
+
+/*
+ * XFS global statistics
+ */
+struct xfsstats {
+# define XFSSTAT_END_EXTENT_ALLOC 4
+ __uint32_t xs_allocx;
+ __uint32_t xs_allocb;
+ __uint32_t xs_freex;
+ __uint32_t xs_freeb;
+# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4)
+ __uint32_t xs_abt_lookup;
+ __uint32_t xs_abt_compare;
+ __uint32_t xs_abt_insrec;
+ __uint32_t xs_abt_delrec;
+# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7)
+ __uint32_t xs_blk_mapr;
+ __uint32_t xs_blk_mapw;
+ __uint32_t xs_blk_unmap;
+ __uint32_t xs_add_exlist;
+ __uint32_t xs_del_exlist;
+ __uint32_t xs_look_exlist;
+ __uint32_t xs_cmp_exlist;
+# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4)
+ __uint32_t xs_bmbt_lookup;
+ __uint32_t xs_bmbt_compare;
+ __uint32_t xs_bmbt_insrec;
+ __uint32_t xs_bmbt_delrec;
+# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4)
+ __uint32_t xs_dir_lookup;
+ __uint32_t xs_dir_create;
+ __uint32_t xs_dir_remove;
+ __uint32_t xs_dir_getdents;
+# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3)
+ __uint32_t xs_trans_sync;
+ __uint32_t xs_trans_async;
+ __uint32_t xs_trans_empty;
+# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7)
+ __uint32_t xs_ig_attempts;
+ __uint32_t xs_ig_found;
+ __uint32_t xs_ig_frecycle;
+ __uint32_t xs_ig_missed;
+ __uint32_t xs_ig_dup;
+ __uint32_t xs_ig_reclaims;
+ __uint32_t xs_ig_attrchg;
+# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5)
+ __uint32_t xs_log_writes;
+ __uint32_t xs_log_blocks;
+ __uint32_t xs_log_noiclogs;
+ __uint32_t xs_log_force;
+ __uint32_t xs_log_force_sleep;
+# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10)
+ __uint32_t xs_try_logspace;
+ __uint32_t xs_sleep_logspace;
+ __uint32_t xs_push_ail;
+ __uint32_t xs_push_ail_success;
+ __uint32_t xs_push_ail_pushbuf;
+ __uint32_t xs_push_ail_pinned;
+ __uint32_t xs_push_ail_locked;
+ __uint32_t xs_push_ail_flushing;
+ __uint32_t xs_push_ail_restarts;
+ __uint32_t xs_push_ail_flush;
+# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2)
+ __uint32_t xs_xstrat_quick;
+ __uint32_t xs_xstrat_split;
+# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2)
+ __uint32_t xs_write_calls;
+ __uint32_t xs_read_calls;
+# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4)
+ __uint32_t xs_attr_get;
+ __uint32_t xs_attr_set;
+ __uint32_t xs_attr_remove;
+ __uint32_t xs_attr_list;
+# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_ATTRIBUTE_OPS+3)
+ __uint32_t xs_iflush_count;
+ __uint32_t xs_icluster_flushcnt;
+ __uint32_t xs_icluster_flushinode;
+# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8)
+ __uint32_t vn_active; /* # vnodes not on free lists */
+ __uint32_t vn_alloc; /* # times vn_alloc called */
+ __uint32_t vn_get; /* # times vn_get called */
+ __uint32_t vn_hold; /* # times vn_hold called */
+ __uint32_t vn_rele; /* # times vn_rele called */
+ __uint32_t vn_reclaim; /* # times vn_reclaim called */
+ __uint32_t vn_remove; /* # times vn_remove called */
+ __uint32_t vn_free; /* # times vn_free called */
+#define XFSSTAT_END_BUF (XFSSTAT_END_VNODE_OPS+9)
+ __uint32_t pb_get;
+ __uint32_t pb_create;
+ __uint32_t pb_get_locked;
+ __uint32_t pb_get_locked_waited;
+ __uint32_t pb_busy_locked;
+ __uint32_t pb_miss_locked;
+ __uint32_t pb_page_retries;
+ __uint32_t pb_page_found;
+ __uint32_t pb_get_read;
+/* Extra precision counters */
+ __uint64_t xs_xstrat_bytes;
+ __uint64_t xs_write_bytes;
+ __uint64_t xs_read_bytes;
+};
+
+extern struct xfsstats xfsstats;
+
+# define XFS_STATS_INC(count) ( xfsstats.count++ )
+# define XFS_STATS_DEC(count) ( xfsstats.count-- )
+# define XFS_STATS_ADD(count, inc) ( xfsstats.count += (inc) )
+
+extern void xfs_init_procfs(void);
+extern void xfs_cleanup_procfs(void);
+
+
+#else /* !CONFIG_PROC_FS */
+
+# define XFS_STATS_INC(count)
+# define XFS_STATS_DEC(count)
+# define XFS_STATS_ADD(count, inc)
+
+static __inline void xfs_init_procfs(void) { };
+static __inline void xfs_cleanup_procfs(void) { };
+
+#endif /* !CONFIG_PROC_FS */
+
+#endif /* __XFS_STATS_H__ */
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_super.c b/sys/gnu/fs/xfs/FreeBSD/xfs_super.c
new file mode 100644
index 000000000000..7f23f42b9d72
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_super.c
@@ -0,0 +1,338 @@
+/*
+ * 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
+ * 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.h"
+
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_clnt.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_alloc.h"
+#include "xfs_dmapi.h"
+#include "xfs_quota.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_bmap.h"
+#include "xfs_bit.h"
+#include "xfs_rtalloc.h"
+#include "xfs_error.h"
+#include "xfs_itable.h"
+#include "xfs_rw.h"
+#include "xfs_acl.h"
+#include "xfs_cap.h"
+#include "xfs_mac.h"
+#include "xfs_attr.h"
+#include "xfs_buf_item.h"
+#include "xfs_utils.h"
+#include "xfs_version.h"
+
+#include <geom/geom.h>
+#include <geom/geom_vfs.h>
+
+extern struct vop_vector xfs_fifoops;
+extern struct buf_ops xfs_ops;
+
+__uint64_t
+xfs_max_file_offset(
+ unsigned int blockshift)
+{
+
+ return (OFF_MAX);
+}
+
+void
+xfs_initialize_vnode(
+ bhv_desc_t *bdp,
+ xfs_vnode_t *vp,
+ bhv_desc_t *inode_bhv,
+ int unlock)
+{
+ xfs_inode_t *ip = XFS_BHVTOI(inode_bhv);
+
+ if (!inode_bhv->bd_vobj) {
+ vp->v_vfsp = bhvtovfs(bdp);
+ bhv_desc_init(inode_bhv, ip, vp, &xfs_vnodeops);
+ bhv_insert(VN_BHV_HEAD(vp), inode_bhv);
+ }
+
+ /*
+ * XXX: Use VNON as an indication of freshly allocated vnode
+ * which need to be initialized and unlocked.
+ * This is _not_ like the same place in Linux version of
+ * routine.
+ */
+ if (vp->v_type != VNON)
+ return;
+
+ vp->v_type = IFTOVT(ip->i_d.di_mode);
+ vp->v_vnode->v_type = vp->v_type;
+
+ if (vp->v_type == VFIFO)
+ vp->v_vnode->v_op = &xfs_fifoops;
+
+ ASSERT_VOP_LOCKED(vp->v_vnode, "xfs_initialize_vnode");
+
+ /* For new inodes we need to set the ops vectors,
+ * and unlock the inode.
+ */
+ if (unlock)
+ VOP_UNLOCK(vp->v_vnode, 0, curthread);
+}
+
+struct vnode *
+xfs_get_inode(
+ bhv_desc_t *bdp,
+ xfs_ino_t ino,
+ int flags)
+{
+ return NULL;
+}
+
+void
+xfs_flush_inode(
+ xfs_inode_t *ip)
+{
+ printf("xfs_flush_inode NI\n");
+}
+
+void
+xfs_flush_device(
+ xfs_inode_t *ip)
+{
+ printf("xfs_flush_device NI\n");
+ xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
+}
+
+/*ARGSUSED*/
+int
+xfs_blkdev_get(
+ xfs_mount_t *mp,
+ const char *name,
+ struct vnode **bdevp)
+{
+ struct nameidata nd;
+ struct nameidata *ndp = &nd;
+ int error, ronly;
+ struct thread *td;
+ struct vnode *devvp;
+ struct g_consumer *cp;
+ struct g_provider *pp;
+ mode_t accessmode;
+
+ td = curthread;
+
+ NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, name, td);
+ if ((error = namei(ndp)) != 0)
+ return (error);
+ NDFREE(ndp, NDF_ONLY_PNBUF);
+ devvp = ndp->ni_vp;
+
+ if (!vn_isdisk(devvp, &error)) {
+ vrele(devvp);
+ return (error);
+ }
+
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+
+ ronly = ((XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) != 0);
+ if (suser(td)) {
+ accessmode = VREAD;
+ if (!ronly)
+ accessmode |= VWRITE;
+ if ((error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td))!= 0){
+ vput(devvp);
+ return (error);
+ }
+ }
+
+ DROP_GIANT();
+ g_topology_lock();
+
+ /*
+ * XXX: Do not allow more than one consumer to open a device
+ * associated with a particular GEOM provider.
+ * This disables multiple read-only mounts of a device,
+ * but it gets rid of panics in bmemfree() when you try to
+ * mount the same device more than once.
+ * During mounting, XFS does a bread() of the superblock, but does
+ * not brelse() it. A subsequent mount of the same device
+ * will try to bread() the superblock, resulting in a panic in
+ * bremfree(), "buffer not on queue".
+ */
+ pp = g_dev_getprovider(devvp->v_rdev);
+ if ((pp != NULL) && ((pp->acr | pp->acw | pp->ace ) != 0))
+ error = EPERM;
+ else
+ error = g_vfs_open(devvp, &cp, "xfs", ronly ? 0 : 1);
+
+ g_topology_unlock();
+ PICKUP_GIANT();
+
+ VOP_UNLOCK(devvp, 0, td);
+ if (error) {
+ vput(devvp);
+ return (error);
+ }
+
+ devvp->v_bufobj.bo_private = cp;
+ devvp->v_bufobj.bo_ops = &xfs_ops;
+
+ *bdevp = devvp;
+ return (0);
+}
+
+void
+xfs_blkdev_put(
+ struct vnode *devvp)
+{
+ struct g_consumer *cp;
+
+ if (devvp == NULL)
+ return;
+
+ vinvalbuf(devvp, V_SAVE, curthread, 0, 0);
+
+ cp = devvp->v_bufobj.bo_private;
+ DROP_GIANT();
+ g_topology_lock();
+ g_wither_geom_close(cp->geom, ENXIO);
+ g_topology_unlock();
+ PICKUP_GIANT();
+
+ vrele(devvp);
+}
+
+void
+xfs_flush_buftarg(
+ xfs_buftarg_t *btp)
+{
+ printf("xfs_flush_buftarg NI %p\n",btp);
+}
+
+void
+xfs_free_buftarg(
+ xfs_buftarg_t *btp)
+{
+ xfs_flush_buftarg(btp);
+ kmem_free(btp, sizeof(*btp));
+}
+
+int
+xfs_readonly_buftarg(
+ xfs_buftarg_t *btp)
+{
+ struct g_consumer *cp;
+
+ KASSERT(btp->specvp->v_bufobj.bo_ops == &xfs_ops,
+ ("Bogus xfs_buftarg_t pointer"));
+ cp = btp->specvp->v_bufobj.bo_private;
+
+ return (cp->acw == 0);
+}
+
+void
+xfs_relse_buftarg(
+ xfs_buftarg_t *btp)
+{
+ printf("xfs_readonly_buftarg NI %p\n",btp);
+}
+
+unsigned int
+xfs_getsize_buftarg(
+ xfs_buftarg_t *btp)
+{
+ struct g_consumer *cp;
+ cp = btp->specvp->v_bufobj.bo_private;
+ return (cp->provider->sectorsize);
+}
+
+void
+xfs_setsize_buftarg(
+ xfs_buftarg_t *btp,
+ unsigned int blocksize,
+ unsigned int sectorsize)
+{
+ printf("xfs_setsize_buftarg NI %p\n",btp);
+}
+
+xfs_buftarg_t *
+xfs_alloc_buftarg(
+ struct vnode *bdev)
+{
+ xfs_buftarg_t *btp;
+
+ btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
+
+ btp->dev = bdev->v_rdev;
+ btp->specvp = bdev;
+
+ return btp;
+}
+
+int
+init_xfs_fs( void )
+{
+ static char message[] =
+ XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled\n";
+
+ printf(message);
+
+ vn_init();
+ xfs_init();
+ uuid_init();
+ vfs_initdmapi();
+ vfs_initquota();
+
+ return 0;
+}
+
+void
+exit_xfs_fs(void)
+{
+ xfs_cleanup();
+ vfs_exitquota();
+ vfs_exitdmapi();
+ uuid_cleanup();
+}
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_super.h b/sys/gnu/fs/xfs/FreeBSD/xfs_super.h
new file mode 100644
index 000000000000..2665806ed943
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_super.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_SUPER_H__
+#define __XFS_SUPER_H__
+
+#ifdef CONFIG_XFS_DMAPI
+# define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops)
+# define vfs_initdmapi() dmapi_init()
+# define vfs_exitdmapi() dmapi_uninit()
+#else
+# define vfs_insertdmapi(vfs) do { } while (0)
+# define vfs_initdmapi() do { } while (0)
+# define vfs_exitdmapi() do { } while (0)
+#endif
+
+#ifdef CONFIG_XFS_QUOTA
+# define vfs_insertquota(vfs) vfs_insertops(vfsp, &xfs_qmops)
+# define vfs_initquota() xfs_qm_init()
+# define vfs_exitquota() xfs_qm_exit()
+#else
+# define vfs_insertquota(vfs) do { } while (0)
+# define vfs_initquota() do { } while (0)
+# define vfs_exitquota() do { } while (0)
+#endif
+
+#ifdef CONFIG_XFS_POSIX_ACL
+# define XFS_ACL_STRING "ACLs, "
+# define set_posix_acl_flag(sb) ((sb)->s_flags |= MS_POSIXACL)
+#else
+# define XFS_ACL_STRING
+# define set_posix_acl_flag(sb) do { } while (0)
+#endif
+
+#ifdef CONFIG_XFS_SECURITY
+# define XFS_SECURITY_STRING "security attributes, "
+# define ENOSECURITY 0
+#else
+# define XFS_SECURITY_STRING
+# define ENOSECURITY EOPNOTSUPP
+#endif
+
+#ifdef CONFIG_XFS_RT
+# define XFS_REALTIME_STRING "realtime, "
+#else
+# define XFS_REALTIME_STRING
+#endif
+
+#if XFS_BIG_BLKNOS
+# if XFS_BIG_INUMS
+# define XFS_BIGFS_STRING "large block/inode numbers, "
+# else
+# define XFS_BIGFS_STRING "large block numbers, "
+# endif
+#else
+# define XFS_BIGFS_STRING
+#endif
+
+#ifdef CONFIG_XFS_TRACE
+# define XFS_TRACE_STRING "tracing, "
+#else
+# define XFS_TRACE_STRING
+#endif
+
+#ifdef XFSDEBUG
+# define XFS_DBG_STRING "debug"
+#else
+# define XFS_DBG_STRING "no debug"
+#endif
+
+#define XFS_BUILD_OPTIONS XFS_ACL_STRING \
+ XFS_SECURITY_STRING \
+ XFS_REALTIME_STRING \
+ XFS_BIGFS_STRING \
+ XFS_TRACE_STRING \
+ XFS_DBG_STRING /* DBG must be last */
+
+struct xfs_inode;
+struct xfs_mount;
+struct xfs_buftarg;
+
+extern __uint64_t xfs_max_file_offset(unsigned int);
+
+extern void xfs_initialize_vnode(bhv_desc_t *, xfs_vnode_t *, bhv_desc_t *, int);
+
+extern struct vnode * xfs_get_inode( bhv_desc_t *, xfs_ino_t, int);
+extern void xfs_flush_inode(struct xfs_inode *);
+extern void xfs_flush_device(struct xfs_inode *);
+
+extern int xfs_blkdev_get(struct xfs_mount *, const char *,
+ struct block_device **);
+extern void xfs_blkdev_put(struct block_device *);
+
+extern struct xfs_buftarg *xfs_alloc_buftarg(struct vnode *);
+extern void xfs_relse_buftarg(struct xfs_buftarg *);
+extern void xfs_free_buftarg(struct xfs_buftarg *);
+extern void xfs_flush_buftarg(struct xfs_buftarg *);
+extern int xfs_readonly_buftarg(struct xfs_buftarg *);
+extern void xfs_setsize_buftarg(struct xfs_buftarg *, unsigned int, unsigned int);
+extern unsigned int xfs_getsize_buftarg(struct xfs_buftarg *);
+
+extern int init_xfs_fs(void);
+extern void exit_xfs_fs(void);
+
+#endif /* __XFS_SUPER_H__ */
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.c b/sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.c
new file mode 100644
index 000000000000..9ba2d45b33c1
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2001-2002 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.h"
+
+void
+xfs_sysctl_register(void)
+{
+}
+
+void
+xfs_sysctl_unregister(void)
+{
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.h b/sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.h
new file mode 100644
index 000000000000..b4b58b487c45
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_sysctl.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2001-2002 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/
+ */
+
+#ifndef __XFS_SYSCTL_H__
+#define __XFS_SYSCTL_H__
+
+/*
+ * Tunable xfs parameters
+ */
+
+typedef struct xfs_sysctl_val {
+ int min;
+ int val;
+ int max;
+} xfs_sysctl_val_t;
+
+typedef struct xfs_param {
+ xfs_sysctl_val_t refcache_size; /* Size of NFS reference cache. */
+ xfs_sysctl_val_t refcache_purge;/* # of entries to purge each time. */
+ xfs_sysctl_val_t restrict_chown;/* Root/non-root can give away files.*/
+ xfs_sysctl_val_t sgid_inherit; /* Inherit S_ISGID bit if process' GID
+ * is not a member of the parent dir
+ * GID */
+ xfs_sysctl_val_t symlink_mode; /* Link creat mode affected by umask */
+ xfs_sysctl_val_t panic_mask; /* bitmask to cause panic on errors. */
+ xfs_sysctl_val_t error_level; /* Degree of reporting for problems */
+ xfs_sysctl_val_t sync_interval; /* time between sync calls */
+ xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */
+ xfs_sysctl_val_t probe_dmapi; /* probe for DMAPI module on mount. */
+ xfs_sysctl_val_t probe_ioops; /* probe for an IO module on mount. */
+ xfs_sysctl_val_t probe_quota; /* probe for quota module on mount. */
+ xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */
+ xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */
+ xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */
+ xfs_sysctl_val_t flush_interval;/* interval between runs of the
+ * delwri flush daemon. */
+ xfs_sysctl_val_t age_buffer; /* time for buffer to age before
+ * we flush it. */
+ xfs_sysctl_val_t io_bypass; /* toggle for directio io bypass */
+} xfs_param_t;
+
+/*
+ * xfs_error_level:
+ *
+ * How much error reporting will be done when internal problems are
+ * encountered. These problems normally return an EFSCORRUPTED to their
+ * caller, with no other information reported.
+ *
+ * 0 No error reports
+ * 1 Report EFSCORRUPTED errors that will cause a filesystem shutdown
+ * 5 Report all EFSCORRUPTED errors (all of the above errors, plus any
+ * additional errors that are known to not cause shutdowns)
+ *
+ * xfs_panic_mask bit 0x8 turns the error reports into panics
+ */
+
+enum {
+ XFS_REFCACHE_SIZE = 1,
+ XFS_REFCACHE_PURGE = 2,
+ XFS_RESTRICT_CHOWN = 3,
+ XFS_SGID_INHERIT = 4,
+ XFS_SYMLINK_MODE = 5,
+ XFS_PANIC_MASK = 6,
+ XFS_ERRLEVEL = 7,
+ XFS_SYNC_INTERVAL = 8,
+ XFS_PROBE_DMAPI = 9,
+ XFS_PROBE_IOOPS = 10,
+ XFS_PROBE_QUOTA = 11,
+ XFS_STATS_CLEAR = 12,
+ XFS_INHERIT_SYNC = 13,
+ XFS_INHERIT_NODUMP = 14,
+ XFS_INHERIT_NOATIME = 15,
+ XFS_FLUSH_INTERVAL = 16,
+ XFS_AGE_BUFFER = 17,
+ XFS_IO_BYPASS = 18,
+};
+
+extern xfs_param_t xfs_params;
+
+#ifdef CONFIG_SYSCTL
+extern void xfs_sysctl_register(void);
+extern void xfs_sysctl_unregister(void);
+#else
+# define xfs_sysctl_register() do { } while (0)
+# define xfs_sysctl_unregister() do { } while (0)
+#endif /* CONFIG_SYSCTL */
+
+#endif /* __XFS_SYSCTL_H__ */
+
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_version.h b/sys/gnu/fs/xfs/FreeBSD/xfs_version.h
new file mode 100644
index 000000000000..96f96394417e
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_version.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2001-2002 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/
+ */
+
+/*
+ * Dummy file that can contain a timestamp to put into the
+ * XFS init string, to help users keep track of what they're
+ * running
+ */
+
+#ifndef __XFS_VERSION_H__
+#define __XFS_VERSION_H__
+
+#define XFS_VERSION_STRING "SGI XFS"
+
+#endif /* __XFS_VERSION_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_vfs.c b/sys/gnu/fs/xfs/FreeBSD/xfs_vfs.c
new file mode 100644
index 000000000000..a621e200ba95
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_vfs.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2000-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.h"
+#include "xfs_fs.h"
+#include "xfs_macros.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_clnt.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_imap.h"
+#include "xfs_alloc.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_quota.h"
+
+#include "xfs_mountops.h"
+
+int
+xvfs_mount(
+ struct bhv_desc *bdp,
+ struct xfs_mount_args *args,
+ struct cred *cr)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_mount)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_mount)(next, args, cr));
+}
+
+int
+xvfs_parseargs(
+ struct bhv_desc *bdp,
+ char *s,
+ struct xfs_mount_args *args,
+ int f)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_parseargs)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_parseargs)(next, s, args, f));
+}
+
+int
+xvfs_showargs(
+ struct bhv_desc *bdp,
+ struct sbuf *m)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_showargs)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_showargs)(next, m));
+}
+
+int
+xvfs_unmount(
+ struct bhv_desc *bdp,
+ int fl,
+ struct cred *cr)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_unmount)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_unmount)(next, fl, cr));
+}
+
+int
+xvfs_mntupdate(
+ struct bhv_desc *bdp,
+ int *fl,
+ struct xfs_mount_args *args)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_mntupdate)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_mntupdate)(next, fl, args));
+}
+
+int
+xvfs_root(
+ struct bhv_desc *bdp,
+ struct xfs_vnode **vpp)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_root)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_root)(next, vpp));
+}
+
+int
+xvfs_statvfs(
+ struct bhv_desc *bdp,
+ struct statfs *sp,
+ struct xfs_vnode *vp)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_statvfs)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_statvfs)(next, sp, vp));
+}
+
+int
+xvfs_sync(
+ struct bhv_desc *bdp,
+ int fl,
+ struct cred *cr)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_sync)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_sync)(next, fl, cr));
+}
+
+int
+xvfs_vget(
+ struct bhv_desc *bdp,
+ struct xfs_vnode **vpp,
+ struct fid *fidp)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_vget)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_vget)(next, vpp, fidp));
+}
+
+int
+xvfs_dmapiops(
+ struct bhv_desc *bdp,
+ caddr_t addr)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_dmapiops)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_dmapiops)(next, addr));
+}
+
+int
+xvfs_quotactl(
+ struct bhv_desc *bdp,
+ int cmd,
+ int id,
+ caddr_t addr)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_quotactl)
+ next = BHV_NEXT(next);
+ return ((*bhvtovfsops(next)->xvfs_quotactl)(next, cmd, id, addr));
+}
+
+struct inode *
+xvfs_get_inode(
+ struct bhv_desc *bdp,
+ xfs_ino_t ino,
+ int fl)
+{
+ struct bhv_desc *next = bdp;
+
+ while (! (bhvtovfsops(next))->xvfs_get_inode)
+ next = BHV_NEXTNULL(next);
+ return ((*bhvtovfsops(next)->xvfs_get_inode)(next, ino, fl));
+}
+
+void
+xvfs_init_vnode(
+ struct bhv_desc *bdp,
+ struct xfs_vnode *vp,
+ struct bhv_desc *bp,
+ int unlock)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_init_vnode)
+ next = BHV_NEXT(next);
+ ((*bhvtovfsops(next)->xvfs_init_vnode)(next, vp, bp, unlock));
+}
+
+void
+xvfs_force_shutdown(
+ struct bhv_desc *bdp,
+ int fl,
+ char *file,
+ int line)
+{
+ struct bhv_desc *next = bdp;
+
+ ASSERT(next);
+ while (! (bhvtovfsops(next))->xvfs_force_shutdown)
+ next = BHV_NEXT(next);
+ ((*bhvtovfsops(next)->xvfs_force_shutdown)(next, fl, file, line));
+}
+
+xfs_vfs_t *
+vfs_allocate(struct mount *mp)
+{
+ struct xfs_vfs *vfsp;
+ struct xfsmount *xmp;
+
+ xmp = kmem_zalloc(sizeof(*xmp), KM_SLEEP);
+ vfsp = XFSTOVFS(xmp);
+
+ bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
+
+ xmp->m_mp = mp;
+ mp->mnt_data = (qaddr_t)xmp;
+ vfsp->vfs_mp = mp;
+
+ return vfsp;
+}
+
+void
+vfs_deallocate(
+ struct xfs_vfs *vfsp)
+{
+ struct xfsmount *xmp;
+
+ bhv_head_destroy(VFS_BHVHEAD(vfsp));
+
+ xmp = VFSTOXFS(vfsp);
+ kmem_free(xmp, sizeof(*xmp));
+}
+
+/*
+ * Allocate and initialize a new XFS mount structure
+ */
+struct xfsmount *
+xfsmount_allocate(struct mount *mp)
+{
+ xfs_vfs_t *vfsp;
+
+ vfsp = vfs_allocate(mp);
+
+ ASSERT(vfsp);
+
+ if (mp->mnt_flag & MNT_RDONLY)
+ vfsp->vfs_flag |= VFS_RDONLY;
+
+ bhv_insert_all_vfsops(vfsp);
+ return (VFSTOXFS(vfsp));
+}
+
+void
+xfsmount_deallocate(struct xfsmount *xmp)
+{
+ xfs_vfs_t *vfsp;
+
+ vfsp = XFSTOVFS(xmp);
+ bhv_remove_all_vfsops(vfsp, 1);
+ vfs_deallocate(vfsp);
+}
+
+
+void
+vfs_insertops(
+ struct xfs_vfs *vfsp,
+ struct bhv_vfsops *vfsops)
+{
+ struct bhv_desc *bdp;
+
+ bdp = kmem_alloc(sizeof(struct bhv_desc), KM_SLEEP);
+ bhv_desc_init(bdp, NULL, vfsp, vfsops);
+ bhv_insert(&vfsp->vfs_bh, bdp);
+}
+
+void
+vfs_insertbhv(
+ struct xfs_vfs *vfsp,
+ struct bhv_desc *bdp,
+ struct xvfsops *vfsops,
+ void *mount)
+{
+ bhv_desc_init(bdp, mount, vfsp, vfsops);
+ bhv_insert_initial(&vfsp->vfs_bh, bdp);
+}
+
+void
+bhv_remove_vfsops(
+ struct xfs_vfs *vfsp,
+ int pos)
+{
+ struct bhv_desc *bhv;
+
+ bhv = bhv_lookup_range(&vfsp->vfs_bh, pos, pos);
+ if (bhv) {
+ bhv_remove(&vfsp->vfs_bh, bhv);
+ kmem_free(bhv, sizeof(*bhv));
+ }
+}
+
+void
+bhv_remove_all_vfsops(
+ struct xfs_vfs *vfsp,
+ int freebase)
+{
+ struct xfs_mount *mp;
+
+ bhv_remove_vfsops(vfsp, VFS_POSITION_QM);
+ bhv_remove_vfsops(vfsp, VFS_POSITION_DM);
+ bhv_remove_vfsops(vfsp, VFS_POSITION_IO);
+ if (!freebase)
+ return;
+ mp = XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfsp), &xfs_vfsops));
+ VFS_REMOVEBHV(vfsp, &mp->m_bhv);
+ xfs_mount_free(mp, 0);
+}
+
+void
+bhv_insert_all_vfsops(
+ struct xfs_vfs *vfsp)
+{
+ struct xfs_mount *mp;
+
+ mp = xfs_mount_init();
+ vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
+ vfs_insertdmapi(vfsp);
+ vfs_insertquota(vfsp);
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_vfs.h b/sys/gnu/fs/xfs/FreeBSD/xfs_vfs.h
new file mode 100644
index 000000000000..c16ddcd0310c
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_vfs.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2000-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/
+ */
+#ifndef __XFS_VFS_H__
+#define __XFS_VFS_H__
+
+#include <sys/mount.h>
+#include "xfs_fs.h"
+
+struct fid;
+struct cred;
+struct xfs_vnode;
+struct statfs;
+struct sbuf;
+struct xfs_mount_args;
+struct mount;
+
+typedef struct statfs xfs_statfs_t;
+
+typedef struct xfs_vfs {
+ u_int vfs_flag; /* flags */
+ xfs_fsid_t vfs_fsid; /* file system ID */
+ xfs_fsid_t *vfs_altfsid; /* An ID fixed for life of FS */
+ bhv_head_t vfs_bh; /* head of vfs behavior chain */
+ struct mount *vfs_mp; /* FreeBSD mount struct */
+} xfs_vfs_t;
+
+#define MNTTOXVFS(mp) ((struct xfs_vfs*)(mp)->mnt_data)
+#define XVFSTOMNT(vfs) ((vfs)->vfs_mp)
+
+#define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */
+
+#define bhvtovfs(bdp) ( (struct xfs_vfs *)BHV_VOBJ(bdp) )
+#define bhvtovfsops(bdp) ( (struct xvfsops *)BHV_OPS(bdp) )
+#define VFS_BHVHEAD(vfs) ( &(vfs)->vfs_bh )
+#define VFS_REMOVEBHV(vfs, bdp) ( bhv_remove(VFS_BHVHEAD(vfs), bdp) )
+
+#define VFS_POSITION_BASE BHV_POSITION_BASE /* chain bottom */
+#define VFS_POSITION_TOP BHV_POSITION_TOP /* chain top */
+#define VFS_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */
+
+typedef enum {
+ VFS_BHV_UNKNOWN, /* not specified */
+ VFS_BHV_XFS, /* xfs */
+ VFS_BHV_DM, /* data migration */
+ VFS_BHV_QM, /* quota manager */
+ VFS_BHV_IO, /* IO path */
+ VFS_BHV_END /* housekeeping end-of-range */
+} vfs_bhv_t;
+
+#define VFS_POSITION_XFS (BHV_POSITION_BASE)
+#define VFS_POSITION_DM (VFS_POSITION_BASE+10)
+#define VFS_POSITION_QM (VFS_POSITION_BASE+20)
+#define VFS_POSITION_IO (VFS_POSITION_BASE+30)
+
+#define VFS_RDONLY 0x0001 /* read-only vfs */
+#define VFS_GRPID 0x0002 /* group-ID assigned from directory */
+#define VFS_DMI 0x0004 /* filesystem has the DMI enabled */
+#define VFS_UMOUNT 0x0008 /* unmount in progress */
+#define VFS_END 0x0008 /* max flag */
+
+#define SYNC_ATTR 0x0001 /* sync attributes */
+#define SYNC_CLOSE 0x0002 /* close file system down */
+#define SYNC_DELWRI 0x0004 /* look at delayed writes */
+#define SYNC_WAIT 0x0008 /* wait for i/o to complete */
+#define SYNC_BDFLUSH 0x0010 /* BDFLUSH is calling -- don't block */
+#define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */
+#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */
+#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */
+
+#define IGET_NOALLOC 0x0001 /* vfs_get_inode may return NULL */
+
+typedef int (*xvfs_mount_t)(bhv_desc_t *,
+ struct xfs_mount_args *, struct cred *);
+typedef int (*xvfs_parseargs_t)(bhv_desc_t *, char *,
+ struct xfs_mount_args *, int);
+typedef int (*xvfs_showargs_t)(bhv_desc_t *, struct sbuf *);
+typedef int (*xvfs_unmount_t)(bhv_desc_t *, int, struct cred *);
+typedef int (*xvfs_mntupdate_t)(bhv_desc_t *, int *,
+ struct xfs_mount_args *);
+typedef int (*xvfs_root_t)(bhv_desc_t *, struct xfs_vnode **);
+typedef int (*xvfs_statvfs_t)(bhv_desc_t *, xfs_statfs_t *, struct xfs_vnode *);
+typedef int (*xvfs_sync_t)(bhv_desc_t *, int, struct cred *);
+typedef int (*xvfs_vget_t)(bhv_desc_t *, struct xfs_vnode **, struct fid *);
+typedef int (*xvfs_dmapiops_t)(bhv_desc_t *, caddr_t);
+typedef int (*xvfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t);
+typedef void (*xvfs_init_vnode_t)(bhv_desc_t *,
+ struct xfs_vnode *, bhv_desc_t *, int);
+typedef void (*xvfs_force_shutdown_t)(bhv_desc_t *, int, char *, int);
+typedef struct inode * (*xvfs_get_inode_t)(bhv_desc_t *, xfs_ino_t, int);
+
+typedef struct xvfsops {
+ bhv_position_t xvfs_position; /* behavior chain position */
+ xvfs_mount_t xvfs_mount; /* mount file system */
+ xvfs_parseargs_t xvfs_parseargs; /* parse mount options */
+ xvfs_showargs_t xvfs_showargs; /* unparse mount options */
+ xvfs_unmount_t xvfs_unmount; /* unmount file system */
+ xvfs_mntupdate_t xvfs_mntupdate; /* update file system options */
+ xvfs_root_t xvfs_root; /* get root vnode */
+ xvfs_statvfs_t xvfs_statvfs; /* file system statistics */
+ xvfs_sync_t xvfs_sync; /* flush files */
+ xvfs_vget_t xvfs_vget; /* get vnode from fid */
+ xvfs_dmapiops_t xvfs_dmapiops; /* data migration */
+ xvfs_quotactl_t xvfs_quotactl; /* disk quota */
+ xvfs_get_inode_t xvfs_get_inode; /* bhv specific iget */
+ xvfs_init_vnode_t xvfs_init_vnode; /* initialize a new vnode */
+ xvfs_force_shutdown_t xvfs_force_shutdown; /* crash and burn */
+} xvfsops_t;
+
+/*
+ * VFS's. Operates on vfs structure pointers (starts at bhv head).
+ */
+#define VHEAD(v) ((v)->vfs_fbhv)
+#define XVFS_MOUNT(v, ma,cr, rv) ((rv) = xvfs_mount(VHEAD(v), ma,cr))
+#define XVFS_PARSEARGS(v, o,ma,f, rv) ((rv) = xvfs_parseargs(VHEAD(v), o,ma,f))
+#define XVFS_SHOWARGS(v, m, rv) ((rv) = xvfs_showargs(VHEAD(v), m))
+#define XVFS_UNMOUNT(v, f, cr, rv) ((rv) = xvfs_unmount(VHEAD(v), f,cr))
+#define XVFS_MNTUPDATE(v, fl, args, rv) ((rv) = xvfs_mntupdate(VHEAD(v), fl, args))
+#define XVFS_ROOT(v, vpp, rv) ((rv) = xvfs_root(VHEAD(v), vpp))
+#define XVFS_STATVFS(v, sp,vp, rv) ((rv) = xvfs_statvfs(VHEAD(v), sp,vp))
+#define XVFS_SYNC(v, flag,cr, rv) ((rv) = xvfs_sync(VHEAD(v), flag,cr))
+#define XVFS_VGET(v, vpp,fidp, rv) ((rv) = xvfs_vget(VHEAD(v), vpp,fidp))
+#define XVFS_DMAPIOPS(v, p, rv) ((rv) = xvfs_dmapiops(VHEAD(v), p))
+#define XVFS_QUOTACTL(v, c,id,p, rv) ((rv) = xvfs_quotactl(VHEAD(v), c,id,p))
+#define XVFS_GET_INODE(v, ino, fl) ( xvfs_get_inode(VHEAD(v), ino,fl) )
+#define XVFS_INIT_VNODE(v, vp,b,ul) ( xvfs_init_vnode(VHEAD(v), vp,b,ul) )
+#define XVFS_FORCE_SHUTDOWN(v, fl,f,l) ( xvfs_force_shutdown(VHEAD(v), fl,f,l) )
+
+/*
+ * PVFS's. Operates on behavior descriptor pointers.
+ */
+#define PVFS_MOUNT(b, ma,cr, rv) ((rv) = xvfs_mount(b, ma,cr))
+#define PVFS_PARSEARGS(b, o,ma,f, rv) ((rv) = xvfs_parseargs(b, o,ma,f))
+#define PVFS_SHOWARGS(b, m, rv) ((rv) = xvfs_showargs(b, m))
+#define PVFS_UNMOUNT(b, f,cr, rv) ((rv) = xvfs_unmount(b, f,cr))
+#define PVFS_MNTUPDATE(b, fl, args, rv) ((rv) = xvfs_mntupdate(b, fl, args))
+#define PVFS_ROOT(b, vpp, rv) ((rv) = xvfs_root(b, vpp))
+#define PVFS_STATVFS(b, sp,vp, rv) ((rv) = xvfs_statvfs(b, sp,vp))
+#define PVFS_SYNC(b, flag,cr, rv) ((rv) = xvfs_sync(b, flag,cr))
+#define PVFS_VGET(b, vpp,fidp, rv) ((rv) = xvfs_vget(b, vpp,fidp))
+#define PVFS_DMAPIOPS(b, p, rv) ((rv) = xvfs_dmapiops(b, p))
+#define PVFS_QUOTACTL(b, c,id,p, rv) ((rv) = xvfs_quotactl(b, c,id,p))
+#define PVFS_GET_INODE(b, ino,fl) ( xvfs_get_inode(b, ino,fl) )
+#define PVFS_INIT_VNODE(b, vp,b2,ul) ( xvfs_init_vnode(b, vp,b2,ul) )
+#define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( xvfs_force_shutdown(b, fl,f,l) )
+
+extern int xvfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *);
+extern int xvfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int);
+extern int xvfs_showargs(bhv_desc_t *, struct sbuf *);
+extern int xvfs_unmount(bhv_desc_t *, int, struct cred *);
+extern int xvfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *);
+extern int xvfs_root(bhv_desc_t *, struct xfs_vnode **);
+extern int xvfs_statvfs(bhv_desc_t *, xfs_statfs_t *, struct xfs_vnode *);
+extern int xvfs_sync(bhv_desc_t *, int, struct cred *);
+extern int xvfs_vget(bhv_desc_t *, struct xfs_vnode **, struct fid *);
+extern int xvfs_dmapiops(bhv_desc_t *, caddr_t);
+extern int xvfs_quotactl(bhv_desc_t *, int, int, caddr_t);
+extern struct inode *xvfs_get_inode(bhv_desc_t *, xfs_ino_t, int);
+extern void xvfs_init_vnode(bhv_desc_t *, struct xfs_vnode *, bhv_desc_t *, int);
+extern void xvfs_force_shutdown(bhv_desc_t *, int, char *, int);
+
+#define XFS_DMOPS "xfs_dm_operations" /* Data Migration */
+#define XFS_QMOPS "xfs_qm_operations" /* Quota Manager */
+#define XFS_IOOPS "xfs_io_operations" /* I/O subsystem */
+#define XFS_DM_MODULE "xfs_dmapi"
+#define XFS_QM_MODULE "xfs_quota"
+#define XFS_IO_MODULE "xfs_ioops"
+
+typedef struct bhv_vfsops {
+ struct xvfsops bhv_common;
+ void * bhv_custom;
+} bhv_vfsops_t;
+
+typedef struct bhv_module {
+ bhv_desc_t bm_desc;
+ const char * bm_name;
+ bhv_vfsops_t * bm_ops;
+} bhv_module_t;
+
+#define vfs_bhv_lookup(v, id) ( bhv_lookup_range(&(v)->vfs_bh, (id), (id)) )
+#define vfs_bhv_custom(b) ( ((bhv_vfsops_t *)BHV_OPS(b))->bhv_custom )
+#define vfs_bhv_set_custom(b,o) ( (b)->bhv_custom = (void *)(o))
+#define vfs_bhv_clr_custom(b) ( (b)->bhv_custom = NULL )
+
+extern xfs_vfs_t *vfs_allocate(struct mount *);
+extern void vfs_deallocate(xfs_vfs_t *);
+extern void vfs_insertops(xfs_vfs_t *, bhv_vfsops_t *);
+extern void vfs_insertbhv(xfs_vfs_t *, bhv_desc_t *, xvfsops_t *, void *);
+
+#define bhv_lookup_module(n,m) ( (m) ? \
+ inter_module_get_request(n, m) : \
+ inter_module_get(n) )
+#define bhv_remove_module(n) inter_module_put(n)
+#define bhv_module_init(n,m,op) inter_module_register(n,m,op)
+#define bhv_module_exit(n) inter_module_unregister(n)
+
+extern void bhv_insert_all_vfsops(struct xfs_vfs *);
+extern void bhv_remove_all_vfsops(struct xfs_vfs *, int);
+extern void bhv_remove_vfsops(struct xfs_vfs *, int);
+
+#endif /* __XFS_VFS_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_vnode.c b/sys/gnu/fs/xfs/FreeBSD/xfs_vnode.c
new file mode 100644
index 000000000000..ac85f877f093
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_vnode.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2000-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.h"
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_imap.h"
+#include "xfs_alloc.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode_item.h"
+#include "xfs_inode.h"
+
+void
+vn_init(void)
+{
+}
+
+struct xfs_vnode *
+vn_initialize(
+ xfs_vnode_t *vp)
+{
+ XFS_STATS_INC(vn_active);
+ XFS_STATS_INC(vn_alloc);
+
+ /* Initialize the first behavior and the behavior chain head. */
+ vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode");
+
+#ifdef CONFIG_XFS_VNODE_TRACING
+ vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
+#endif /* CONFIG_XFS_VNODE_TRACING */
+
+ vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address);
+ return vp;
+}
+
+/*
+ * Get a reference on a vnode. Need to drop vnode reference
+ * to accomodate for vhold by VMAP regardless of whether or
+ * not we were able to successfully grab the vnode.
+ */
+xfs_vnode_t *
+vn_get(
+ struct xfs_vnode *xfs_vp,
+ vmap_t *vmap)
+{
+ struct vnode *vp;
+ int error;
+
+ XFS_STATS_INC(vn_get);
+
+ vp = vmap->v_vp;
+
+ error = vget(vp, 0, curthread);
+ if (error) {
+ vdrop(vp);
+ return (NULL);
+ }
+
+ vdrop(vp);
+ if (vp->v_data != xfs_vp) {
+ vput(vp);
+ return (NULL);
+ }
+
+ vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
+ return xfs_vp;
+}
+
+/*
+ * purge a vnode from the cache
+ * At this point the vnode is guaranteed to have no references (vn_count == 0)
+ * The caller has to make sure that there are no ways someone could
+ * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock).
+ */
+void
+vn_purge(
+ struct xfs_vnode *xfs_vp,
+ vmap_t *vmap)
+{
+ struct vnode *vp;
+
+ vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
+
+ vp = vmap->v_vp;
+
+ vn_lock(vp, LK_EXCLUSIVE, curthread);
+ vgone(vp);
+ VOP_UNLOCK(vp, 0, curthread);
+ vdrop(vp);
+}
+
+/*
+ * Finish the removal of a vnode.
+ */
+void
+vn_remove(
+ struct xfs_vnode *vp)
+{
+ vmap_t vmap;
+
+ /* Make sure we don't do this to the same vnode twice */
+ if (!(vp->v_fbhv))
+ return;
+
+ XFS_STATS_INC(vn_remove);
+ vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address);
+ /*
+ * After the following purge the vnode
+ * will no longer exist.
+ */
+ VMAP(vp, vmap);
+ vn_purge(vp, &vmap);
+}
+
+
+#ifdef CONFIG_XFS_VNODE_TRACING
+
+#define KTRACE_ENTER(vp, vk, s, line, ra) \
+ ktrace_enter( (vp)->v_trace, \
+/* 0 */ (void *)(__psint_t)(vk), \
+/* 1 */ (void *)(s), \
+/* 2 */ (void *)(__psint_t) line, \
+/* 3 */ (void *)(vn_count(vp)), \
+/* 4 */ (void *)(ra), \
+/* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \
+/* 6 */ (void *)(__psint_t)smp_processor_id(), \
+/* 7 */ (void *)(__psint_t)(current->pid), \
+/* 8 */ (void *)__return_address, \
+/* 9 */ 0, 0, 0, 0, 0, 0, 0)
+
+/*
+ * Vnode tracing code.
+ */
+void
+vn_trace_entry(xfs_vnode_t *vp, char *func, inst_t *ra)
+{
+ KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra);
+}
+
+void
+vn_trace_exit(xfs_vnode_t *vp, char *func, inst_t *ra)
+{
+ KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra);
+}
+
+void
+vn_trace_hold(xfs_vnode_t *vp, char *file, int line, inst_t *ra)
+{
+ KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra);
+}
+
+void
+vn_trace_ref(xfs_vnode_t *vp, char *file, int line, inst_t *ra)
+{
+ KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra);
+}
+
+void
+vn_trace_rele(xfs_vnode_t *vp, char *file, int line, inst_t *ra)
+{
+ KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra);
+}
+#endif /* CONFIG_XFS_VNODE_TRACING */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_vnode.h b/sys/gnu/fs/xfs/FreeBSD/xfs_vnode.h
new file mode 100644
index 000000000000..d224cb86a0c0
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_vnode.h
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2000-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/
+ *
+ * Portions Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef __XFS_VNODE_H__
+#define __XFS_VNODE_H__
+
+#include <sys/vnode.h>
+#include <sys/namei.h>
+
+struct xfs_iomap;
+typedef xfs_ino_t vnumber_t;
+typedef struct componentname vname_t;
+typedef bhv_head_t vn_bhv_head_t;
+
+/*
+ * MP locking protocols:
+ * v_flag, v_vfsp VN_LOCK/VN_UNLOCK
+ * v_type read-only or fs-dependent
+ */
+typedef struct xfs_vnode {
+ __u32 v_flag; /* vnode flags (see below) */
+ enum vtype v_type; /* vnode type */
+ struct xfs_vfs *v_vfsp; /* ptr to containing VFS */
+ vnumber_t v_number; /* in-core vnode number */
+ vn_bhv_head_t v_bh; /* behavior head */
+ struct vnode *v_vnode; /* FreeBSD vnode */
+ struct xfs_inode *v_inode; /* XFS inode */
+#ifdef XFS_VNODE_TRACE
+ struct ktrace *v_trace; /* trace header structure */
+#endif
+} xfs_vnode_t;
+
+#define v_fbhv v_bh.bh_first /* first behavior */
+#define v_fops v_bh.bh_first->bd_ops /* first behavior ops */
+
+#define VNODE_POSITION_BASE BHV_POSITION_BASE /* chain bottom */
+#define VNODE_POSITION_TOP BHV_POSITION_TOP /* chain top */
+#define VNODE_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */
+
+typedef enum {
+ VN_BHV_UNKNOWN, /* not specified */
+ VN_BHV_XFS, /* xfs */
+ VN_BHV_DM, /* data migration */
+ VN_BHV_QM, /* quota manager */
+ VN_BHV_IO, /* IO path */
+ VN_BHV_END /* housekeeping end-of-range */
+} vn_bhv_t;
+
+#define VNODE_POSITION_XFS (VNODE_POSITION_BASE)
+#define VNODE_POSITION_DM (VNODE_POSITION_BASE+10)
+#define VNODE_POSITION_QM (VNODE_POSITION_BASE+20)
+#define VNODE_POSITION_IO (VNODE_POSITION_BASE+30)
+
+#define VPTOXFSVP(vp) ((struct xfs_vnode *)(vp)->v_data)
+
+/*
+ * Macros for dealing with the behavior descriptor inside of the vnode.
+ */
+#define BHV_TO_VNODE(bdp) ((xfs_vnode_t *)BHV_VOBJ(bdp))
+#define BHV_TO_VNODE_NULL(bdp) ((xfs_vnode_t *)BHV_VOBJNULL(bdp))
+
+#define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh)))
+#define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name)
+#define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp)
+#define vn_bhv_lookup(bhp,ops) bhv_lookup(bhp,ops)
+#define vn_bhv_lookup_unlocked(bhp,ops) bhv_lookup_unlocked(bhp,ops)
+
+/*
+ * Vnode to Linux inode mapping.
+ */
+#define LINVFS_GET_VP(inode) ((xfs_vnode_t *)NULL)
+#define LINVFS_GET_IP(vp) ((xfs_inode_t *)NULL)
+
+#ifndef __FreeBSD__
+/*
+ * Convert between vnode types and inode formats (since POSIX.1
+ * defines mode word of stat structure in terms of inode formats).
+ */
+extern enum vtype iftovt_tab[];
+extern u_short vttoif_tab[];
+#define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
+#define VTTOIF(indx) (vttoif_tab[(int)(indx)])
+#define MAKEIMODE(indx, mode) (int)(VTTOIF(indx) | (mode))
+#endif
+
+
+/*
+ * Vnode flags.
+ */
+#define VINACT 0x1 /* vnode is being inactivated */
+#define VRECLM 0x2 /* vnode is being reclaimed */
+#define VWAIT 0x4 /* waiting for VINACT/VRECLM to end */
+#define VMODIFIED 0x8 /* XFS inode state possibly differs */
+ /* to the Linux inode state. */
+
+/*
+ * Values for the VOP_RWLOCK and VOP_RWUNLOCK flags parameter.
+ */
+typedef enum vrwlock {
+ VRWLOCK_NONE,
+ VRWLOCK_READ,
+ VRWLOCK_WRITE,
+ VRWLOCK_WRITE_DIRECT,
+ VRWLOCK_TRY_READ,
+ VRWLOCK_TRY_WRITE
+} vrwlock_t;
+
+/*
+ * Return values for VOP_INACTIVE. A return value of
+ * VN_INACTIVE_NOCACHE implies that the file system behavior
+ * has disassociated its state and bhv_desc_t from the vnode.
+ */
+#define VN_INACTIVE_CACHE 0
+#define VN_INACTIVE_NOCACHE 1
+
+/*
+ * Values for the cmd code given to VOP_VNODE_CHANGE.
+ */
+typedef enum vchange {
+ VCHANGE_FLAGS_FRLOCKS = 0,
+ VCHANGE_FLAGS_ENF_LOCKING = 1,
+ VCHANGE_FLAGS_TRUNCATED = 2,
+ VCHANGE_FLAGS_PAGE_DIRTY = 3,
+ VCHANGE_FLAGS_IOEXCL_COUNT = 4
+} vchange_t;
+
+struct file_lock;
+struct xfs_iomap_s;
+struct xfs_vattr;
+struct attrlist_cursor_kern;
+
+typedef int (*xfs_vop_open_t)(bhv_desc_t *, struct cred *);
+typedef ssize_t (*xfs_vop_read_t)(bhv_desc_t *, uio_t *, int, struct cred *);
+typedef ssize_t (*xfs_vop_write_t)(bhv_desc_t *, uio_t *, int, struct cred *);
+typedef int (*xfs_vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *,
+ int, unsigned int, unsigned long);
+typedef int (*xfs_vop_getattr_t)(bhv_desc_t *, struct xfs_vattr *, int,
+ struct cred *);
+typedef int (*xfs_vop_setattr_t)(bhv_desc_t *, struct xfs_vattr *, int,
+ struct cred *);
+typedef int (*xfs_vop_access_t)(bhv_desc_t *, int, struct cred *);
+typedef int (*xfs_vop_lookup_t)(bhv_desc_t *, vname_t *, xfs_vnode_t **,
+ int, xfs_vnode_t *, struct cred *);
+typedef int (*xfs_vop_create_t)(bhv_desc_t *, vname_t *, struct xfs_vattr *,
+ xfs_vnode_t **, struct cred *);
+typedef int (*xfs_vop_remove_t)(bhv_desc_t *, vname_t *, struct cred *);
+typedef int (*xfs_vop_link_t)(bhv_desc_t *, xfs_vnode_t *, vname_t *,
+ struct cred *);
+typedef int (*xfs_vop_rename_t)(bhv_desc_t *, vname_t *, xfs_vnode_t *, vname_t *,
+ struct cred *);
+typedef int (*xfs_vop_mkdir_t)(bhv_desc_t *, vname_t *, struct xfs_vattr *,
+ xfs_vnode_t **, struct cred *);
+typedef int (*xfs_vop_rmdir_t)(bhv_desc_t *, vname_t *, struct cred *);
+typedef int (*xfs_vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *,
+ int *);
+typedef int (*xfs_vop_symlink_t)(bhv_desc_t *, vname_t *, struct xfs_vattr *,
+ char *, xfs_vnode_t **, struct cred *);
+
+typedef int (*xfs_vop_readlink_t)(bhv_desc_t *, struct uio *, int,
+ struct cred *);
+typedef int (*xfs_vop_fsync_t)(bhv_desc_t *, int, struct cred *,
+ xfs_off_t, xfs_off_t);
+typedef int (*xfs_vop_inactive_t)(bhv_desc_t *, struct cred *);
+typedef int (*xfs_vop_fid2_t)(bhv_desc_t *, struct fid *);
+typedef int (*xfs_vop_release_t)(bhv_desc_t *);
+typedef int (*xfs_vop_rwlock_t)(bhv_desc_t *, vrwlock_t);
+typedef void (*xfs_vop_rwunlock_t)(bhv_desc_t *, vrwlock_t);
+typedef int (*xfs_vop_frlock_t)(bhv_desc_t *, int, struct file_lock *,int,
+ xfs_off_t, struct cred *);
+typedef int (*xfs_vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int,
+ struct xfs_iomap *, int *);
+typedef int (*xfs_vop_reclaim_t)(bhv_desc_t *);
+typedef int (*xfs_vop_attr_get_t)(bhv_desc_t *, const char *, char *, int *, int,
+ struct cred *);
+typedef int (*xfs_vop_attr_set_t)(bhv_desc_t *, const char *, char *, int, int,
+ struct cred *);
+typedef int (*xfs_vop_attr_remove_t)(bhv_desc_t *, const char *, int, struct cred *);
+typedef int (*xfs_vop_attr_list_t)(bhv_desc_t *, char *, int, int,
+ struct attrlist_cursor_kern *, struct cred *);
+typedef void (*xfs_vop_link_removed_t)(bhv_desc_t *, xfs_vnode_t *, int);
+typedef void (*xfs_vop_vnode_change_t)(bhv_desc_t *, vchange_t, __psint_t);
+typedef void (*xfs_vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+typedef void (*xfs_vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+typedef int (*xfs_vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t,
+ uint64_t, int);
+typedef int (*xfs_vop_iflush_t)(bhv_desc_t *, int);
+
+
+typedef struct xfs_vnodeops {
+ bhv_position_t vn_position; /* position within behavior chain */
+ xfs_vop_open_t vop_open;
+ xfs_vop_read_t vop_read;
+ xfs_vop_write_t vop_write;
+ xfs_vop_ioctl_t vop_ioctl;
+ xfs_vop_getattr_t vop_getattr;
+ xfs_vop_setattr_t vop_setattr;
+ xfs_vop_access_t vop_access;
+ xfs_vop_lookup_t vop_lookup;
+ xfs_vop_create_t vop_create;
+ xfs_vop_remove_t vop_remove;
+ xfs_vop_link_t vop_link;
+ xfs_vop_rename_t vop_rename;
+ xfs_vop_mkdir_t vop_mkdir;
+ xfs_vop_rmdir_t vop_rmdir;
+ xfs_vop_readdir_t vop_readdir;
+ xfs_vop_symlink_t vop_symlink;
+ xfs_vop_readlink_t vop_readlink;
+ xfs_vop_fsync_t vop_fsync;
+ xfs_vop_inactive_t vop_inactive;
+ xfs_vop_fid2_t vop_fid2;
+ xfs_vop_rwlock_t vop_rwlock;
+ xfs_vop_rwunlock_t vop_rwunlock;
+ xfs_vop_frlock_t vop_frlock;
+ xfs_vop_bmap_t vop_bmap;
+ xfs_vop_reclaim_t vop_reclaim;
+ xfs_vop_attr_get_t vop_attr_get;
+ xfs_vop_attr_set_t vop_attr_set;
+ xfs_vop_attr_remove_t vop_attr_remove;
+ xfs_vop_attr_list_t vop_attr_list;
+ xfs_vop_link_removed_t vop_link_removed;
+ xfs_vop_vnode_change_t vop_vnode_change;
+ xfs_vop_ptossvp_t vop_tosspages;
+ xfs_vop_pflushinvalvp_t vop_flushinval_pages;
+ xfs_vop_pflushvp_t vop_flush_pages;
+ xfs_vop_release_t vop_release;
+ xfs_vop_iflush_t vop_iflush;
+} xfs_vnodeops_t;
+
+/*
+ * VOP's.
+ */
+#define _VOP_(op, vp) (*((xfs_vnodeops_t *)(vp)->v_fops)->op)
+
+#define XVOP_READ(vp,uio,ioflags,cr,rv) \
+ rv = _VOP_(vop_read, vp)((vp)->v_fbhv,uio,ioflags,cr)
+#define XVOP_WRITE(vp,file,uio,ioflags,cr,rv) \
+ rv = _VOP_(vop_write, vp)((vp)->v_fbhv,uio,ioflags,cr)
+#define XVOP_BMAP(vp,of,sz,rw,b,n,rv) \
+ rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n)
+#define XVOP_OPEN(vp, cr, rv) \
+ rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr)
+#define XVOP_GETATTR(vp, vap, f, cr, rv) \
+ rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr)
+#define XVOP_SETATTR(vp, vap, f, cr, rv) \
+ rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr)
+#define XVOP_ACCESS(vp, mode, cr, rv) \
+ rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr)
+#define XVOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv) \
+ rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr)
+#define XVOP_CREATE(dvp,d,vap,vpp,cr,rv) \
+ rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr)
+#define XVOP_REMOVE(dvp,d,cr,rv) \
+ rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr)
+#define XVOP_LINK(tdvp,fvp,d,cr,rv) \
+ rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr)
+#define XVOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv) \
+ rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr)
+#define XVOP_MKDIR(dp,d,vap,vpp,cr,rv) \
+ rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr)
+#define XVOP_RMDIR(dp,d,cr,rv) \
+ rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr)
+#define XVOP_READDIR(vp,uiop,cr,eofp,rv) \
+ rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp)
+#define XVOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv) \
+ rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr)
+#define XVOP_READLINK(vp,uiop,fl,cr,rv) \
+ rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,fl,cr)
+
+#define XVOP_FSYNC(vp,f,cr,b,e,rv) \
+ rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e)
+#define XVOP_INACTIVE(vp, cr, rv) \
+ rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr)
+#define XVOP_RELEASE(vp, rv) \
+ rv = _VOP_(vop_release, vp)((vp)->v_fbhv)
+#define XVOP_FID2(vp, fidp, rv) \
+ rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp)
+#define XVOP_RWLOCK(vp,i) \
+ (void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
+#define XVOP_RWLOCK_TRY(vp,i) \
+ _VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
+#define XVOP_RWUNLOCK(vp,i) \
+ (void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i)
+#define XVOP_FRLOCK(vp,c,fl,flags,offset,fr,rv) \
+ rv = _VOP_(vop_frlock, vp)((vp)->v_fbhv,c,fl,flags,offset,fr)
+#define XVOP_RECLAIM(vp, rv) \
+ rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv)
+#define XVOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv) \
+ rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred)
+#define XVOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv) \
+ rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred)
+#define XVOP_ATTR_REMOVE(vp, name, flags, cred, rv) \
+ rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred)
+#define XVOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv) \
+ rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred)
+#define XVOP_LINK_REMOVED(vp, dvp, linkzero) \
+ (void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero)
+#define XVOP_VNODE_CHANGE(vp, cmd, val) \
+ (void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val)
+/*
+ * These are page cache functions that now go thru VOPs.
+ * 'last' parameter is unused and left in for IRIX compatibility
+ */
+#define XVOP_TOSS_PAGES(vp, first, last, fiopt) \
+ _VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt)
+/*
+ * 'last' parameter is unused and left in for IRIX compatibility
+ */
+#define XVOP_FLUSHINVAL_PAGES(vp, first, last, fiopt) \
+ _VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt)
+/*
+ * 'last' parameter is unused and left in for IRIX compatibility
+ */
+#define XVOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv) \
+ rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt)
+#define XVOP_IOCTL(vp, inode, filp, fl, cmd, arg, rv) \
+ rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,fl,cmd,arg)
+#define XVOP_IFLUSH(vp, flags, rv) \
+ rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags)
+
+/*
+ * Flags for read/write calls - select values from FreeBSD IO_ flags
+ * or non-conflicting bits.
+ */
+#define IO_ISDIRECT IO_DIRECT /* bypass page cache */
+#define IO_INVIS 0x02000 /* don't update inode timestamps */
+#define IO_ISLOCKED 0x04000 /* don't do inode locking */
+
+/*
+ * Flags for VOP_IFLUSH call
+ */
+#define FLUSH_SYNC 1 /* wait for flush to complete */
+#define FLUSH_INODE 2 /* flush the inode itself */
+#define FLUSH_LOG 4 /* force the last log entry for
+ * this inode out to disk */
+
+/*
+ * Flush/Invalidate options for VOP_TOSS_PAGES, VOP_FLUSHINVAL_PAGES and
+ * VOP_FLUSH_PAGES.
+ */
+#define FI_NONE 0 /* none */
+#define FI_REMAPF 1 /* Do a remapf prior to the operation */
+#define FI_REMAPF_LOCKED 2 /* Do a remapf prior to the operation.
+ Prevent VM access to the pages until
+ the operation completes. */
+
+/*
+ * Vnode attributes. va_mask indicates those attributes the caller
+ * wants to set or extract.
+ */
+typedef struct xfs_vattr {
+ int va_mask; /* bit-mask of attributes present */
+ enum vtype va_type; /* vnode type (for create) */
+ mode_t va_mode; /* file access mode and type */
+ nlink_t va_nlink; /* number of references to file */
+ uid_t va_uid; /* owner user id */
+ gid_t va_gid; /* owner group id */
+ xfs_ino_t va_nodeid; /* file id */
+ xfs_off_t va_size; /* file size in bytes */
+ u_long va_blocksize; /* blocksize preferred for i/o */
+ struct timespec va_atime; /* time of last access */
+ struct timespec va_mtime; /* time of last modification */
+ struct timespec va_ctime; /* time file changed */
+ u_int va_gen; /* generation number of file */
+ xfs_dev_t va_rdev; /* device the special file represents */
+ __int64_t va_nblocks; /* number of blocks allocated */
+ u_long va_xflags; /* random extended file flags */
+ u_long va_extsize; /* file extent size */
+ u_long va_nextents; /* number of extents in file */
+ u_long va_anextents; /* number of attr extents in file */
+ int va_projid; /* project id */
+} xfs_vattr_t;
+
+/*
+ * setattr or getattr attributes
+ */
+#define XFS_AT_TYPE 0x00000001
+#define XFS_AT_MODE 0x00000002
+#define XFS_AT_UID 0x00000004
+#define XFS_AT_GID 0x00000008
+#define XFS_AT_FSID 0x00000010
+#define XFS_AT_NODEID 0x00000020
+#define XFS_AT_NLINK 0x00000040
+#define XFS_AT_SIZE 0x00000080
+#define XFS_AT_ATIME 0x00000100
+#define XFS_AT_MTIME 0x00000200
+#define XFS_AT_CTIME 0x00000400
+#define XFS_AT_RDEV 0x00000800
+#define XFS_AT_BLKSIZE 0x00001000
+#define XFS_AT_NBLOCKS 0x00002000
+#define XFS_AT_VCODE 0x00004000
+#define XFS_AT_MAC 0x00008000
+#define XFS_AT_UPDATIME 0x00010000
+#define XFS_AT_UPDMTIME 0x00020000
+#define XFS_AT_UPDCTIME 0x00040000
+#define XFS_AT_ACL 0x00080000
+#define XFS_AT_CAP 0x00100000
+#define XFS_AT_INF 0x00200000
+#define XFS_AT_XFLAGS 0x00400000
+#define XFS_AT_EXTSIZE 0x00800000
+#define XFS_AT_NEXTENTS 0x01000000
+#define XFS_AT_ANEXTENTS 0x02000000
+#define XFS_AT_PROJID 0x04000000
+#define XFS_AT_SIZE_NOPERM 0x08000000
+#define XFS_AT_GENCOUNT 0x10000000
+
+#define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
+ XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
+ XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
+ XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\
+ XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\
+ XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT)
+
+#define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
+ XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
+ XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
+ XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID)
+
+#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME)
+
+#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME)
+
+#define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\
+ XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\
+ XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT)
+
+#ifndef __FreeBSD__
+/*
+ * Modes.
+ */
+#define VSUID S_ISUID /* set user id on execution */
+#define VSGID S_ISGID /* set group id on execution */
+#define VSVTX S_ISVTX /* save swapped text even after use */
+#define VREAD S_IRUSR /* read, write, execute permissions */
+#define VWRITE S_IWUSR
+#define VEXEC S_IXUSR
+#endif /* __FreeBSD__ */
+
+#define MODEMASK ALLPERMS /* mode bits plus permission bits */
+
+/*
+ * Check whether mandatory file locking is enabled.
+ */
+#define MANDLOCK(vp, mode) \
+ ((vp)->v_type == VREG && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
+
+extern void vn_init(void);
+extern int vn_wait(struct xfs_vnode *);
+extern xfs_vnode_t *vn_initialize(struct xfs_vnode *);
+
+/*
+ * Acquiring and invalidating vnodes:
+ *
+ * if (vn_get(vp, version, 0))
+ * ...;
+ * vn_purge(vp, version);
+ *
+ * vn_get and vn_purge must be called with vmap_t arguments, sampled
+ * while a lock that the vnode's VOP_RECLAIM function acquires is
+ * held, to ensure that the vnode sampled with the lock held isn't
+ * recycled (VOP_RECLAIMed) or deallocated between the release of the lock
+ * and the subsequent vn_get or vn_purge.
+ */
+
+/*
+ * vnode_map structures _must_ match vn_epoch and vnode structure sizes.
+ */
+typedef struct vnode_map {
+ xfs_vfs_t *v_vfsp;
+ xfs_ino_t v_ino;
+ struct vnode *v_vp;
+} vmap_t;
+
+#define VMAP(vp, vmap) {(vmap).v_vfsp = (vp)->v_vfsp; \
+ (vmap).v_vp = (vp)->v_vnode; \
+ (vmap).v_ino = (vp)->v_inode->i_ino;\
+ vhold((vp)->v_vnode); \
+ }
+
+extern void vn_purge(struct xfs_vnode *, vmap_t *);
+extern xfs_vnode_t *vn_get(struct xfs_vnode *, vmap_t *);
+extern int vn_revalidate(struct xfs_vnode *);
+extern void vn_remove(struct xfs_vnode *);
+
+static inline int vn_count(struct xfs_vnode *vp)
+{
+ return vp->v_vnode->v_usecount;
+}
+
+/*
+ * Vnode reference counting functions (and macros for compatibility).
+ */
+extern xfs_vnode_t *vn_hold(struct xfs_vnode *);
+extern void vn_rele(struct xfs_vnode *);
+
+#if defined(XFS_VNODE_TRACE)
+#define VN_HOLD(vp) \
+ ((void)vref((vp)->v_vnode), \
+ vn_trace_hold(vp, __FILE__, __LINE__, (inst_t *)__return_address))
+#define VN_RELE(vp) \
+ (vn_trace_rele(vp, __FILE__, __LINE__, (inst_t *)__return_address), \
+ vrele((vp)->v_vnode))
+#else
+#define VN_HOLD(vp) vref((vp)->v_vnode)
+#define VN_RELE(vp) vrele((vp)->v_vnode)
+#endif
+
+/*
+ * Vname handling macros.
+ */
+#define VNAME(cnp) ((cnp)->cn_nameptr)
+#define VNAMELEN(cnp) ((cnp)->cn_namelen)
+#define VNAME_TO_VNODE(dentry) (printf("VNAME_TO_VNODE NI"), (xfs_vnode_t *)0)
+
+/*
+ * Vnode spinlock manipulation.
+ */
+#define VN_LOCK(vp) VI_LOCK(vp->v_vnode)
+#define VN_UNLOCK(vp, s) VI_UNLOCK(vp->v_vnode)
+#define VN_FLAGSET(vp,b) vn_flagset(vp,b)
+#define VN_FLAGCLR(vp,b) vn_flagclr(vp,b)
+
+static __inline__ void vn_flagset(struct xfs_vnode *vp, __u32 flag)
+{
+ VN_LOCK(vp);
+ vp->v_flag |= flag;
+ VN_UNLOCK(vp, 0);
+}
+
+static __inline__ void vn_flagclr(struct xfs_vnode *vp, __u32 flag)
+{
+ VN_LOCK(vp);
+ vp->v_flag &= ~flag;
+ VN_UNLOCK(vp, 0);
+}
+
+/*
+ * Update modify/access/change times on the vnode
+ */
+#define VN_MTIMESET(vp, tvp)
+#define VN_ATIMESET(vp, tvp)
+#define VN_CTIMESET(vp, tvp)
+
+/*
+ * Some useful predicates.
+ */
+#define VN_MAPPED(vp) 0
+#define VN_CACHED(vp) 0
+#define VN_DIRTY(vp) 0
+#define VMODIFY(vp) VN_FLAGSET(vp, VMODIFIED)
+#define VUNMODIFY(vp) VN_FLAGCLR(vp, VMODIFIED)
+
+/*
+ * Flags to VOP_SETATTR/VOP_GETATTR.
+ */
+#define ATTR_UTIME 0x01 /* non-default utime(2) request */
+#define ATTR_DMI 0x08 /* invocation from a DMI function */
+#define ATTR_LAZY 0x80 /* set/get attributes lazily */
+#define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */
+
+/*
+ * Flags to VOP_FSYNC and VOP_RECLAIM.
+ */
+#define FSYNC_NOWAIT 0 /* asynchronous flush */
+#define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */
+#define FSYNC_INVAL 0x2 /* flush and invalidate cached data */
+#define FSYNC_DATA 0x4 /* synchronous fsync of data only */
+
+/*
+ * Tracking vnode activity.
+ */
+#if defined(XFS_VNODE_TRACE)
+
+#define VNODE_TRACE_SIZE 16 /* number of trace entries */
+#define VNODE_KTRACE_ENTRY 1
+#define VNODE_KTRACE_EXIT 2
+#define VNODE_KTRACE_HOLD 3
+#define VNODE_KTRACE_REF 4
+#define VNODE_KTRACE_RELE 5
+
+extern void vn_trace_entry(struct xfs_vnode *, char *, inst_t *);
+extern void vn_trace_exit(struct xfs_vnode *, char *, inst_t *);
+extern void vn_trace_hold(struct xfs_vnode *, char *, int, inst_t *);
+extern void vn_trace_ref(struct xfs_vnode *, char *, int, inst_t *);
+extern void vn_trace_rele(struct xfs_vnode *, char *, int, inst_t *);
+
+#define VN_TRACE(vp) \
+ vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address)
+#else
+#define vn_trace_entry(a,b,c)
+#define vn_trace_exit(a,b,c)
+#define vn_trace_hold(a,b,c,d)
+#define vn_trace_ref(a,b,c,d)
+#define vn_trace_rele(a,b,c,d)
+#define VN_TRACE(vp)
+#endif
+
+#endif /* __XFS_VNODE_H__ */
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c b/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c
new file mode 100644
index 000000000000..dc9f6f698834
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c
@@ -0,0 +1,1431 @@
+/*
+ * Copyright (c) 2001, Alexander Kabaev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/kernel.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/dirent.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/extattr.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+
+#include <fs/fifofs/fifo.h>
+
+#define NO_VFS_MACROS
+#include "xfs.h"
+#include "xfs_macros.h"
+#include "xfs_types.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_imap.h"
+#include "xfs_alloc.h"
+#include "xfs_ialloc.h"
+#include "xfs_attr.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir_sf.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode_item.h"
+#include "xfs_inode.h"
+#include "xfs_acl.h"
+#include "xfs_cap.h"
+#include "xfs_mac.h"
+#include "xfs_iomap.h"
+#include "xfs_clnt.h"
+#include "xfs_mountops.h"
+
+/*
+ * Prototypes for XFS vnode operations.
+ */
+static vop_access_t _xfs_access;
+static vop_advlock_t _xfs_advlock;
+static vop_bmap_t _xfs_bmap;
+static vop_cachedlookup_t _xfs_cachedlookup;
+static vop_close_t _xfs_close;
+static vop_create_t _xfs_create;
+static vop_fsync_t _xfs_fsync;
+static vop_getattr_t _xfs_getattr;
+static vop_getextattr_t _xfs_getextattr;
+static vop_inactive_t _xfs_inactive;
+static vop_ioctl_t _xfs_ioctl;
+static vop_link_t _xfs_link;
+static vop_listextattr_t _xfs_listextattr;
+static vop_mkdir_t _xfs_mkdir;
+static vop_mknod_t _xfs_mknod;
+static vop_open_t _xfs_open;
+static vop_read_t _xfs_read;
+static vop_readdir_t _xfs_readdir;
+static vop_readlink_t _xfs_readlink;
+static vop_reclaim_t _xfs_reclaim;
+static vop_remove_t _xfs_remove;
+static vop_rename_t _xfs_rename;
+static vop_rmdir_t _xfs_rmdir;
+static vop_setattr_t _xfs_setattr;
+static vop_strategy_t _xfs_strategy;
+static vop_symlink_t _xfs_symlink;
+static vop_write_t _xfs_write;
+
+struct vop_vector xfs_vnops = {
+ .vop_default = &default_vnodeops,
+ .vop_access = _xfs_access,
+ .vop_advlock = _xfs_advlock,
+ .vop_bmap = _xfs_bmap,
+ .vop_cachedlookup = _xfs_cachedlookup,
+ .vop_close = _xfs_close,
+ .vop_create = _xfs_create,
+ .vop_fsync = _xfs_fsync,
+ .vop_getattr = _xfs_getattr,
+ .vop_getextattr = _xfs_getextattr,
+ .vop_inactive = _xfs_inactive,
+ .vop_ioctl = _xfs_ioctl,
+ .vop_link = _xfs_link,
+ .vop_listextattr = _xfs_listextattr,
+ .vop_lookup = vfs_cache_lookup,
+ .vop_mkdir = _xfs_mkdir,
+ .vop_mknod = _xfs_mknod,
+ .vop_open = _xfs_open,
+ .vop_read = _xfs_read,
+ .vop_readdir = _xfs_readdir,
+ .vop_readlink = _xfs_readlink,
+ .vop_reclaim = _xfs_reclaim,
+ .vop_remove = _xfs_remove,
+ .vop_rename = _xfs_rename,
+ .vop_rmdir = _xfs_rmdir,
+ .vop_setattr = _xfs_setattr,
+ .vop_strategy = _xfs_strategy,
+ .vop_symlink = _xfs_symlink,
+ .vop_write = _xfs_write,
+};
+
+/*
+ * FIFO's specific operations.
+ */
+
+static vop_close_t _xfsfifo_close;
+static vop_read_t _xfsfifo_read;
+static vop_kqfilter_t _xfsfifo_kqfilter;
+static vop_write_t _xfsfifo_write;
+
+struct vop_vector xfs_fifoops = {
+ .vop_default = &fifo_specops,
+ .vop_access = _xfs_access,
+ .vop_close = _xfsfifo_close,
+ .vop_fsync = _xfs_fsync,
+ .vop_getattr = _xfs_getattr,
+ .vop_inactive = _xfs_inactive,
+ .vop_kqfilter = _xfsfifo_kqfilter,
+ .vop_read = _xfsfifo_read,
+ .vop_reclaim = _xfs_reclaim,
+ .vop_setattr = _xfs_setattr,
+ .vop_write = _xfsfifo_write,
+};
+
+static int
+_xfs_access(
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+ int error;
+
+ XVOP_ACCESS(VPTOXFSVP(ap->a_vp), ap->a_mode, ap->a_cred, error);
+ return (error);
+}
+
+static int
+_xfs_open(
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ int a_fdidx;
+ } */ *ap)
+{
+ int error;
+
+ XVOP_OPEN(VPTOXFSVP(ap->a_vp), ap->a_cred, error);
+ if (error == 0)
+ vnode_create_vobject(ap->a_vp, 0, ap->a_td);
+ return (error);
+}
+
+static int
+_xfs_close(
+ struct vop_close_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+ int error = 0;
+ /* XVOP_CLOSE(VPTOXFSVP(ap->a_vp), NULL, error); */
+ return (error);
+}
+
+static int
+_xfs_getattr(
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+ struct mount *mp;
+ xfs_vattr_t va;
+ int error;
+
+
+ VATTR_NULL(vap);
+ memset(&va,0,sizeof(xfs_vattr_t));
+ va.va_mask = XFS_AT_STAT|XFS_AT_GENCOUNT|XFS_AT_XFLAGS;
+
+ XVOP_GETATTR(VPTOXFSVP(vp), &va, 0, ap->a_cred, error);
+ if (error) return (error);
+
+ mp = vp->v_mount;
+
+ vap->va_type = va.va_type;
+ vap->va_mode = va.va_mode;
+ vap->va_nlink = va.va_nlink;
+ vap->va_uid = va.va_uid;
+ vap->va_gid = va.va_gid;
+ vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
+ vap->va_fileid = va.va_nodeid;
+ vap->va_size = va.va_size;
+ vap->va_blocksize = va.va_blocksize;
+ vap->va_atime = va.va_atime;
+ vap->va_mtime = va.va_mtime;
+ vap->va_ctime = va.va_ctime;
+ vap->va_gen = va.va_gen;
+ vap->va_rdev = va.va_rdev;
+ vap->va_bytes = (va.va_nblocks << BBSHIFT);
+
+ /* XFS now supports devices that have block sizes
+ * other than 512 so BBSHIFT will work for now
+ * but need to get this value from the super block
+ */
+
+ /*
+ * Fields with no direct equivalent in XFS
+ * leave initialized by VATTR_NULL
+ */
+#if 0
+ vap->va_filerev = 0;
+ vap->va_birthtime = va.va_ctime;
+ vap->va_vaflags = 0;
+ vap->va_flags = 0;
+ vap->va_spare = 0;
+#endif
+
+ return (0);
+}
+
+static int
+_xfs_setattr(
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+ xfs_vattr_t va;
+ int error;
+
+ /*
+ * Check for unsettable attributes.
+ */
+ if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+ (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+ (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+ ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
+ return (EINVAL);
+
+ memset(&va, 0, sizeof(va));
+
+ if (vap->va_uid != (uid_t)VNOVAL) {
+ va.va_mask |= XFS_AT_UID;
+ va.va_uid = vap->va_uid;
+ }
+ if (vap->va_gid != (gid_t)VNOVAL) {
+ va.va_mask |= XFS_AT_GID;
+ va.va_gid = vap->va_gid;
+ }
+ if (vap->va_size != VNOVAL) {
+ va.va_mask |= XFS_AT_SIZE;
+ va.va_size = vap->va_size;
+ }
+ if (vap->va_atime.tv_sec != VNOVAL) {
+ va.va_mask |= XFS_AT_ATIME;
+ va.va_atime = vap->va_atime;
+ }
+ if (vap->va_mtime.tv_sec != VNOVAL) {
+ va.va_mask |= XFS_AT_MTIME;
+ va.va_mtime = vap->va_mtime;
+ }
+ if (vap->va_ctime.tv_sec != VNOVAL) {
+ va.va_mask |= XFS_AT_CTIME;
+ va.va_ctime = vap->va_ctime;
+ }
+ if (vap->va_mode != (mode_t)VNOVAL) {
+ va.va_mask |= XFS_AT_MODE;
+ va.va_mode = vap->va_mode;
+ }
+
+ XVOP_SETATTR(VPTOXFSVP(vp), &va, 0, ap->a_cred, error);
+ return (error);
+}
+
+static int
+_xfs_inactive(
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct thread *a_td;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct thread *td = ap->a_td;
+ int error;
+
+ XVOP_INACTIVE(VPTOXFSVP(vp), td->td_ucred, error);
+ return (error);
+}
+
+static int
+_xfs_read(
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ int error;
+
+ switch (vp->v_type) {
+ case VREG:
+ break;
+ case VDIR:
+ return (EISDIR);
+ default:
+ return (EPERM);
+ };
+
+ XVOP_READ(VPTOXFSVP(vp), uio, ap->a_ioflag, ap->a_cred, error);
+ return error;
+}
+
+int
+xfs_read_file(xfs_mount_t *mp, xfs_inode_t *ip, struct uio *uio, int ioflag);
+
+int
+xfs_read_file(xfs_mount_t *mp, xfs_inode_t *ip, struct uio *uio, int ioflag)
+{
+ xfs_fileoff_t lbn, nextlbn;
+ xfs_fsize_t bytesinfile;
+ long size, xfersize, blkoffset;
+ struct buf *bp;
+ struct vnode *vp;
+ int error, orig_resid;
+ int seqcount;
+
+ seqcount = ioflag >> IO_SEQSHIFT;
+
+ orig_resid = uio->uio_resid;
+ if (orig_resid <= 0)
+ return (0);
+
+ vp = XFS_ITOV(ip)->v_vnode;
+
+ /*
+ * Ok so we couldn't do it all in one vm trick...
+ * so cycle around trying smaller bites..
+ */
+ for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
+ if ((bytesinfile = ip->i_d.di_size - uio->uio_offset) <= 0)
+ break;
+
+ lbn = XFS_B_TO_FSBT(mp, uio->uio_offset);
+ nextlbn = lbn + 1;
+
+ /*
+ * size of buffer. The buffer representing the
+ * end of the file is rounded up to the size of
+ * the block type ( fragment or full block,
+ * depending ).
+ */
+ size = mp->m_sb.sb_blocksize;
+ blkoffset = XFS_B_FSB_OFFSET(mp, uio->uio_offset);
+
+ /*
+ * The amount we want to transfer in this iteration is
+ * one FS block less the amount of the data before
+ * our startpoint (duh!)
+ */
+ xfersize = mp->m_sb.sb_blocksize - blkoffset;
+
+ /*
+ * But if we actually want less than the block,
+ * or the file doesn't have a whole block more of data,
+ * then use the lesser number.
+ */
+ if (uio->uio_resid < xfersize)
+ xfersize = uio->uio_resid;
+ if (bytesinfile < xfersize)
+ xfersize = bytesinfile;
+
+ if (XFS_FSB_TO_B(mp, nextlbn) >= ip->i_d.di_size ) {
+ /*
+ * Don't do readahead if this is the end of the file.
+ */
+ error = bread(vp, lbn, size, NOCRED, &bp);
+ } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
+ /*
+ * Otherwise if we are allowed to cluster,
+ * grab as much as we can.
+ *
+ * XXX This may not be a win if we are not
+ * doing sequential access.
+ */
+ error = cluster_read(vp, ip->i_d.di_size, lbn,
+ size, NOCRED, uio->uio_resid, seqcount, &bp);
+ } else if (seqcount > 1) {
+ /*
+ * If we are NOT allowed to cluster, then
+ * if we appear to be acting sequentially,
+ * fire off a request for a readahead
+ * as well as a read. Note that the 4th and 5th
+ * arguments point to arrays of the size specified in
+ * the 6th argument.
+ */
+ int nextsize = mp->m_sb.sb_blocksize;
+ error = breadn(vp, lbn,
+ size, &nextlbn, &nextsize, 1, NOCRED, &bp);
+ } else {
+ /*
+ * Failing all of the above, just read what the
+ * user asked for. Interestingly, the same as
+ * the first option above.
+ */
+ error = bread(vp, lbn, size, NOCRED, &bp);
+ }
+ if (error) {
+ brelse(bp);
+ bp = NULL;
+ break;
+ }
+
+ /*
+ * If IO_DIRECT then set B_DIRECT for the buffer. This
+ * will cause us to attempt to release the buffer later on
+ * and will cause the buffer cache to attempt to free the
+ * underlying pages.
+ */
+ if (ioflag & IO_DIRECT)
+ bp->b_flags |= B_DIRECT;
+
+ /*
+ * We should only get non-zero b_resid when an I/O error
+ * has occurred, which should cause us to break above.
+ * However, if the short read did not cause an error,
+ * then we want to ensure that we do not uiomove bad
+ * or uninitialized data.
+ */
+ size -= bp->b_resid;
+ if (size < xfersize) {
+ if (size == 0)
+ break;
+ xfersize = size;
+ }
+
+ /*
+ * otherwise use the general form
+ */
+ error = uiomove((char *)bp->b_data + blkoffset,
+ (int)xfersize, uio);
+
+ if (error)
+ break;
+
+ if (ioflag & (IO_VMIO|IO_DIRECT) ) {
+ /*
+ * If there are no dependencies, and it's VMIO,
+ * then we don't need the buf, mark it available
+ * for freeing. The VM has the data.
+ */
+ bp->b_flags |= B_RELBUF;
+ brelse(bp);
+ } else {
+ /*
+ * Otherwise let whoever
+ * made the request take care of
+ * freeing it. We just queue
+ * it onto another list.
+ */
+ bqrelse(bp);
+ }
+ }
+
+ /*
+ * This can only happen in the case of an error
+ * because the loop above resets bp to NULL on each iteration
+ * and on normal completion has not set a new value into it.
+ * so it must have come from a 'break' statement
+ */
+ if (bp != NULL) {
+ if (ioflag & (IO_VMIO|IO_DIRECT)) {
+ bp->b_flags |= B_RELBUF;
+ brelse(bp);
+ } else
+ bqrelse(bp);
+ }
+
+ return (error);
+}
+
+static int
+_xfs_write(struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+/* struct uio *uio = ap->a_uio; */
+
+ if (vp->v_type != VREG)
+ return (EPERM);
+ return (EPERM);
+}
+
+static int
+_xfs_create(
+ struct vop_create_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap)
+{
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
+ struct thread *td = curthread;
+ struct ucred *credp = td->td_ucred;
+ struct componentname *cnp = ap->a_cnp;
+ xfs_vnode_t *xvp;
+ xfs_vattr_t va;
+ int error;
+
+ memset(&va, 0, sizeof (va));
+ va.va_mask |= XFS_AT_MODE;
+ va.va_mode = vap->va_mode;
+ va.va_mask |= XFS_AT_TYPE;
+ va.va_type = vap->va_type;
+
+ xvp = NULL;
+ XVOP_CREATE(VPTOXFSVP(dvp), cnp, &va, &xvp, credp, error);
+
+ if (error == 0) {
+ *ap->a_vpp = xvp->v_vnode;
+ VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE, td);
+ }
+
+ return (error);
+}
+
+static int
+_xfs_remove(
+ struct vop_remove_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_dvp;
+ struct vnode * a_vp;
+ struct componentname * a_cnp;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ /*
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ */
+ int error;
+
+ if (vp->v_type == VDIR || vp->v_usecount != 1)
+ return (EPERM);
+
+ error = 0;
+ cache_purge(vp);
+ return (error);
+}
+
+static int
+_xfs_rename(
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap)
+{
+ struct vnode *fvp = ap->a_fvp;
+ struct vnode *tvp = ap->a_tvp;
+ struct vnode *fdvp = ap->a_fdvp;
+ struct vnode *tdvp = ap->a_tdvp;
+/* struct componentname *tcnp = ap->a_tcnp; */
+/* struct componentname *fcnp = ap->a_fcnp;*/
+ int error = EPERM;
+
+ if (error)
+ goto out;
+
+ /* Check for cross-device rename */
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+ goto out;
+ }
+
+ if (tvp && tvp->v_usecount > 1) {
+ error = EBUSY;
+ goto out;
+ }
+
+ if (fvp->v_type == VDIR) {
+ if (tvp != NULL && tvp->v_type == VDIR)
+ cache_purge(tdvp);
+ cache_purge(fdvp);
+ }
+out:
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ vrele(fdvp);
+ vrele(fvp);
+ vgone(fvp);
+ if (tvp)
+ vgone(tvp);
+ return (error);
+}
+
+static int
+_xfs_link(
+ struct vop_link_args /* {
+ struct vnode *a_tdvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap)
+{
+ xfs_vnode_t *tdvp, *vp;
+ int error;
+
+ tdvp = VPTOXFSVP(ap->a_tdvp);
+ vp = VPTOXFSVP(ap->a_vp);
+ XVOP_LINK(tdvp, vp, ap->a_cnp, NULL, error);
+ return (error);
+}
+
+static int
+_xfs_symlink(
+ struct vop_symlink_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ char *a_target;
+ } */ *ap)
+{
+ struct thread *td = curthread;
+ struct ucred *credp = td->td_ucred;
+ xfs_vnode_t *xvp;
+ xfs_vattr_t va;
+ int error;
+
+ memset(&va, 0, sizeof (va));
+
+ va.va_mask |= XFS_AT_MODE;
+ va.va_mode = ap->a_vap->va_mode;
+ va.va_mask |= XFS_AT_TYPE;
+ va.va_type = ap->a_vap->va_type;
+
+ XVOP_SYMLINK(VPTOXFSVP(ap->a_dvp), ap->a_cnp, &va, ap->a_target,
+ &xvp, credp, error);
+
+ if (error == 0) {
+ *ap->a_vpp = xvp->v_vnode;
+ VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE, td);
+ }
+
+ return (error);
+}
+
+static int
+_xfs_mknod(
+ struct vop_mknod_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap)
+{
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
+ struct thread *td = curthread;
+ struct ucred *credp = td->td_ucred;
+ struct componentname *cnp = ap->a_cnp;
+ xfs_vnode_t *xvp;
+ xfs_vattr_t va;
+ int error;
+
+ memset(&va, 0, sizeof (va));
+ va.va_mask |= XFS_AT_MODE;
+ va.va_mode = vap->va_mode;
+ va.va_mask |= XFS_AT_TYPE;
+ va.va_type = vap->va_type;
+ va.va_mask |= XFS_AT_RDEV;
+ va.va_rdev = vap->va_rdev;
+
+ xvp = NULL;
+ XVOP_CREATE(VPTOXFSVP(dvp), cnp, &va, &xvp, credp, error);
+
+ if (error == 0) {
+ *ap->a_vpp = xvp->v_vnode;
+ VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE, td);
+ }
+
+ return (error);
+}
+
+static int
+_xfs_mkdir(
+ struct vop_mkdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap)
+{
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
+ struct thread *td = curthread;
+ struct ucred *credp = td->td_ucred;
+ struct componentname *cnp = ap->a_cnp;
+ xfs_vnode_t *xvp;
+ xfs_vattr_t va;
+ int error;
+
+ memset(&va, 0, sizeof (va));
+ va.va_mask |= XFS_AT_MODE;
+ va.va_mode = vap->va_mode;
+ va.va_mask |= XFS_AT_TYPE;
+ va.va_type = vap->va_type;
+
+ xvp = NULL;
+ XVOP_MKDIR(VPTOXFSVP(dvp), cnp, &va, &xvp, credp, error);
+
+ if (error == 0) {
+ *ap->a_vpp = xvp->v_vnode;
+ VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE, td);
+ }
+
+ return (error);
+}
+
+static int
+_xfs_rmdir(
+ struct vop_rmdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+/* struct componentname *cnp = ap->a_cnp; */
+ int error;
+
+ if (dvp == vp)
+ return (EINVAL);
+
+ error = EPERM;
+
+ return (error);
+}
+
+static int
+_xfs_readdir(
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ int *a_ncookies;
+ u_long **a_cookies;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ int error;
+ off_t off;
+ int eof = 0;
+
+ if (vp->v_type != VDIR)
+ return (EPERM);
+ if (ap->a_ncookies) {
+ return (EOPNOTSUPP);
+ }
+
+ error = 0;
+ while (!eof){
+ off = (int)uio->uio_offset;
+
+ XVOP_READDIR(VPTOXFSVP(vp), uio, NULL, &eof, error);
+ if ((uio->uio_offset == off) || error) {
+ break;
+ }
+ }
+
+ if (ap->a_eofflag)
+ *ap->a_eofflag = (eof != 0);
+
+ return (error);
+}
+
+
+static int
+_xfs_readlink(
+ struct vop_readlink_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct ucred *cred = ap->a_cred;
+ int error;
+
+ XVOP_READLINK(VPTOXFSVP(vp), uio, 0, cred, error);
+ return (error);
+}
+
+static int
+_xfs_fsync(
+ struct vop_fsync_args /* {
+ struct vnode * a_vp;
+ int a_waitfor;
+ struct thread * a_td;
+ } */ *ap)
+{
+ xfs_vnode_t *vp = VPTOXFSVP(ap->a_vp);
+ int flags = FSYNC_DATA;
+ int error;
+
+ if (ap->a_waitfor == MNT_WAIT)
+ flags |= FSYNC_WAIT;
+ XVOP_FSYNC(vp, flags, ap->a_td->td_ucred, (xfs_off_t)-1, (xfs_off_t)-1,
+ error);
+
+ return (error);
+}
+
+static int
+_xfs_bmap(
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct bufobj **a_bop;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap)
+{
+ xfs_iomap_t iomap;
+ xfs_off_t offset;
+ ssize_t size;
+ struct mount *mp;
+ struct xfs_mount *xmp;
+ struct xfs_vnode *xvp;
+ int error, maxrun, retbm;
+
+ mp = ap->a_vp->v_mount;
+ xmp = XFS_VFSTOM(MNTTOVFS(mp));
+ if (ap->a_bop != NULL)
+ *ap->a_bop = &xmp->m_ddev_targp->specvp->v_bufobj;
+ if (ap->a_bnp == NULL)
+ return (0);
+
+ xvp = VPTOXFSVP(ap->a_vp);
+ retbm = 1;
+
+ offset = XFS_FSB_TO_B(xmp, ap->a_bn);
+ size = XFS_FSB_TO_B(xmp, 1);
+ XVOP_BMAP(xvp, offset, size, BMAPI_READ, &iomap, &retbm, error);
+ if (error)
+ return (error);
+ if (retbm == 0 || iomap.iomap_bn == IOMAP_DADDR_NULL) {
+ *ap->a_bnp = (daddr_t)-1;
+ if (ap->a_runb)
+ *ap->a_runb = 0;
+ if (ap->a_runp)
+ *ap->a_runp = 0;
+ } else {
+ *ap->a_bnp = iomap.iomap_bn + btodb(iomap.iomap_delta);
+ maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
+ if (ap->a_runb) {
+ *ap->a_runb = XFS_B_TO_FSB(xmp, iomap.iomap_delta);
+ if (*ap->a_runb > maxrun)
+ *ap->a_runb = maxrun;
+ }
+ if (ap->a_runp) {
+ *ap->a_runp =
+ XFS_B_TO_FSB(xmp, iomap.iomap_bsize
+ - iomap.iomap_delta - size);
+ if (*ap->a_runp > maxrun)
+ *ap->a_runp = maxrun;
+ }
+ }
+ return (0);
+}
+
+static int
+_xfs_strategy(
+ struct vop_strategy_args /* {
+ struct vnode *a_vp;
+ struct buf *a_bp;
+ } */ *ap)
+{
+ daddr_t blkno;
+ struct buf *bp;;
+ struct bufobj *bo;
+ struct vnode *vp;
+ struct xfs_mount *xmp;
+ int error;
+
+ bp = ap->a_bp;
+ vp = ap->a_vp;
+
+ KASSERT(ap->a_vp == ap->a_bp->b_vp, ("%s(%p != %p)",
+ __func__, ap->a_vp, ap->a_bp->b_vp));
+ if (bp->b_blkno == bp->b_lblkno) {
+ error = VOP_BMAP(vp, bp->b_lblkno, NULL, &blkno, NULL, NULL);
+ bp->b_blkno = blkno;
+ bp->b_iooffset = (blkno << BBSHIFT);
+ if (error) {
+ bp->b_error = error;
+ bp->b_ioflags |= BIO_ERROR;
+ bufdone(bp);
+ return (error);
+ }
+ if ((long)bp->b_blkno == -1)
+ vfs_bio_clrbuf(bp);
+ }
+ if ((long)bp->b_blkno == -1) {
+ bufdone(bp);
+ return (0);
+ }
+
+ xmp = XFS_VFSTOM(MNTTOVFS(vp->v_mount));
+ bo = &xmp->m_ddev_targp->specvp->v_bufobj;
+ bo->bo_ops->bop_strategy(bo, bp);
+ return (0);
+}
+
+int
+_xfs_ioctl(
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ u_long a_command;
+ caddr_t a_data;
+ int fflag;
+ struct ucred *cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+/* struct vnode *vp = ap->a_vp; */
+/* struct thread *p = ap->a_td; */
+/* struct file *fp; */
+ int error;
+
+ switch (ap->a_command) {
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+int
+_xfs_advlock(
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ } */ *ap)
+{
+/* struct vnode *vp = ap->a_vp;*/
+ struct flock *fl = ap->a_fl;
+/* caddr_t id = (caddr_t)1 */ /* ap->a_id */;
+/* int flags = ap->a_flags; */
+ off_t start, end, size;
+ int error/* , lkop */;
+
+ /*KAN: temp */
+ return (EOPNOTSUPP);
+
+ size = 0;
+ error = 0;
+ switch (fl->l_whence) {
+ case SEEK_SET:
+ case SEEK_CUR:
+ start = fl->l_start;
+ break;
+ case SEEK_END:
+ start = fl->l_start + size;
+ default:
+ return (EINVAL);
+ }
+ if (start < 0)
+ return (EINVAL);
+ if (fl->l_len == 0)
+ end = -1;
+ else {
+ end = start + fl->l_len - 1;
+ if (end < start)
+ return (EINVAL);
+ }
+#ifdef notyet
+ switch (ap->a_op) {
+ case F_SETLK:
+ error = lf_advlock(ap, &np->n_lockf, size);
+ break;
+ case F_UNLCK:
+ lf_advlock(ap, &np->n_lockf, size);
+ break;
+ case F_GETLK:
+ error = lf_advlock(ap, &np->n_lockf, size);
+ break;
+ default:
+ return (EINVAL);
+ }
+#endif
+ return (error);
+}
+
+static int
+_xfs_cachedlookup(
+ struct vop_cachedlookup_args /* {
+ struct vnode * a_dvp;
+ struct vnode ** a_vpp;
+ struct componentname * a_cnp;
+ } */ *ap)
+{
+ struct vnode *dvp, *tvp;
+ struct xfs_vnode *cvp;
+ int islastcn;
+ int error;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct ucred *cred = cnp->cn_cred;
+ int flags = cnp->cn_flags;
+ int nameiop = cnp->cn_nameiop;
+ struct thread *td = cnp->cn_thread;
+
+ char *pname = cnp->cn_nameptr;
+ int namelen = cnp->cn_namelen;
+
+ *vpp = NULL;
+ dvp = ap->a_dvp;
+ islastcn = flags & ISLASTCN;
+
+ XVOP_LOOKUP(VPTOXFSVP(dvp), cnp, &cvp, 0, NULL, cred, error);
+
+ if (error == ENOENT) {
+ if ((nameiop == CREATE || nameiop == RENAME ||
+ nameiop == DELETE) && islastcn)
+ {
+ error = VOP_ACCESS(dvp, VWRITE, cred, td);
+ if (error)
+ return (error);
+ cnp->cn_flags |= SAVENAME;
+ return (EJUSTRETURN);
+ }
+ if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
+ cache_enter(dvp, *vpp, cnp);
+ return (error);
+ }
+ if (error)
+ return (error);
+
+ tvp = cvp->v_vnode;
+
+ if (nameiop == DELETE && islastcn) {
+ if ((error = vn_lock(tvp, LK_EXCLUSIVE, td))) {
+ vrele(tvp);
+ goto err_out;
+ }
+ *vpp = tvp;
+
+ /* Directory should be writable for deletes. */
+ error = VOP_ACCESS(dvp, VWRITE, cred, td);
+ if (error)
+ goto err_out;
+
+ /* XXXKAN: Permission checks for sticky dirs? */
+ return (0);
+ }
+
+ if (nameiop == RENAME && islastcn) {
+ if ((error = vn_lock(tvp, LK_EXCLUSIVE, td))) {
+ vrele(tvp);
+ goto err_out;
+ }
+ *vpp = tvp;
+
+ if ((error = VOP_ACCESS(dvp, VWRITE, cred, td)))
+ goto err_out;
+ return (0);
+ }
+
+ if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, td);
+ error = vn_lock(tvp, cnp->cn_lkflags, td);
+ if (error) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
+ vrele(tvp);
+ goto err_out;
+ }
+ *vpp = tvp;
+ } else if (namelen == 1 && pname[0] == '.') {
+ *vpp = tvp;
+ KASSERT(tvp == dvp, ("not same directory"));
+ } else {
+ if ((error = vn_lock(tvp, cnp->cn_lkflags, td))) {
+ vrele(tvp);
+ goto err_out;
+ }
+ *vpp = tvp;
+ }
+
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, *vpp, cnp);
+ return (0);
+
+err_out:
+ if (*vpp != 0)
+ vput(*vpp);
+ return (error);
+}
+
+static int
+_xfs_reclaim(
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ struct thread *a_td;
+ } */ *ap)
+{
+
+ struct vnode *vp = ap->a_vp;
+ struct xfs_vnode *xfs_vp = VPTOXFSVP(vp);
+ int error;
+
+ XVOP_RECLAIM(xfs_vp, error);
+ kmem_free(xfs_vp, sizeof(*xfs_vp));
+ vp->v_data = NULL;
+ return (error);
+}
+
+static int
+_xfs_kqfilter(
+ struct vop_kqfilter_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ struct knote *a_kn;
+ } */ *ap)
+{
+ return (0);
+}
+
+static __inline
+struct xfs_inode *
+xfs_vtoi(struct vnode *vp)
+{
+ if (VPTOXFSVP(vp) != 0)
+ return (XFS_BHVTOI(VPTOXFSVP(vp)->v_fbhv));
+ return (NULL);
+}
+
+/*
+ * Read wrapper for fifos.
+ */
+static int
+_xfsfifo_read(
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap)
+{
+ int error, resid;
+ struct xfs_inode *ip;
+ struct uio *uio;
+
+ uio = ap->a_uio;
+ resid = uio->uio_resid;
+ error = fifo_specops.vop_read(ap);
+ ip = xfs_vtoi(ap->a_vp);
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
+ (uio->uio_resid != resid || (error == 0 && resid != 0)))
+ xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
+ return (error);
+}
+
+/*
+ * Write wrapper for fifos.
+ */
+static int
+_xfsfifo_write(
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap)
+{
+ int error, resid;
+ struct uio *uio;
+ struct xfs_inode *ip;
+
+ uio = ap->a_uio;
+ resid = uio->uio_resid;
+ error = fifo_specops.vop_write(ap);
+ ip = xfs_vtoi(ap->a_vp);
+ if (ip != NULL && (uio->uio_resid != resid ||
+ (error == 0 && resid != 0)))
+ xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+ return (error);
+}
+
+/*
+ * Close wrapper for fifos.
+ *
+ * Update the times on the inode then do device close.
+ */
+static int
+_xfsfifo_close(
+ struct vop_close_args /* {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+
+ return (fifo_specops.vop_close(ap));
+}
+
+/*
+ * Kqfilter wrapper for fifos.
+ *
+ * Fall through to ufs kqfilter routines if needed
+ */
+static int
+_xfsfifo_kqfilter(
+ struct vop_kqfilter_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ struct knote *a_kn;
+ } */ *ap)
+{
+ int error;
+
+ error = fifo_specops.vop_kqfilter(ap);
+ if (error)
+ error = _xfs_kqfilter(ap);
+ return (error);
+}
+
+static int
+_xfs_getextattr(
+ struct vop_getextattr_args /* {
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ const char *a_name;
+ struct uio *a_uio;
+ size_t *a_size;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+ int error;
+ char *value;
+ int size;
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VREAD);
+ if (error)
+ return (error);
+
+ size = ATTR_MAX_VALUELEN;
+ value = (char *)kmem_zalloc(size, KM_SLEEP);
+ if (value == NULL)
+ return (ENOMEM);
+
+ XVOP_ATTR_GET(VPTOXFSVP(ap->a_vp), ap->a_name, value, &size, 1,
+ ap->a_cred, error);
+
+ if (ap->a_uio != NULL) {
+ if (ap->a_uio->uio_iov->iov_len < size)
+ error = ERANGE;
+ else
+ uiomove(value, size, ap->a_uio);
+ }
+
+ if (ap->a_size != NULL)
+ *ap->a_size = size;
+
+ kmem_free(value, ATTR_MAX_VALUELEN);
+ return (error);
+}
+
+static int
+_xfs_listextattr(
+ struct vop_listextattr_args /* {
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ struct uio *a_uio;
+ size_t *a_size;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap)
+{
+ int error;
+ char *buf = NULL;
+ int buf_len = 0;
+ attrlist_cursor_kern_t cursor = { 0 };
+ int i;
+ char name_len;
+ int attrnames_len = 0;
+ int xfs_flags = ATTR_KERNAMELS;
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VREAD);
+ if (error)
+ return (error);
+
+ if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
+ xfs_flags |= ATTR_KERNORMALS;
+
+ if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
+ xfs_flags |= ATTR_KERNROOTLS;
+
+ if (ap->a_uio == NULL || ap->a_uio->uio_iov[0].iov_base == NULL) {
+ xfs_flags |= ATTR_KERNOVAL;
+ buf_len = 0;
+ } else {
+ buf = ap->a_uio->uio_iov[0].iov_base;
+ buf_len = ap->a_uio->uio_iov[0].iov_len;
+ }
+
+ XVOP_ATTR_LIST(VPTOXFSVP(ap->a_vp), buf, buf_len, xfs_flags,
+ &cursor, ap->a_cred, error);
+ if (error < 0) {
+ attrnames_len = -error;
+ error = 0;
+ }
+ if (buf == NULL)
+ goto done;
+
+ /*
+ * extattr_list expects a list of names. Each list
+ * entry consists of one byte for the name length, followed
+ * by the name (not null terminated)
+ */
+ name_len=0;
+ for(i=attrnames_len-1; i > 0 ; --i) {
+ buf[i] = buf[i-1];
+ if (buf[i])
+ ++name_len;
+ else {
+ buf[i] = name_len;
+ name_len = 0;
+ }
+ }
+ buf[0] = name_len;
+
+ if (ap->a_uio != NULL)
+ ap->a_uio->uio_resid -= attrnames_len;
+
+done:
+ if (ap->a_size != NULL)
+ *ap->a_size = attrnames_len;
+
+ return (error);
+}
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfsdmapistubs.c b/sys/gnu/fs/xfs/FreeBSD/xfsdmapistubs.c
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfsdmapistubs.c
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfsquotasstubs.c b/sys/gnu/fs/xfs/FreeBSD/xfsquotasstubs.c
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfsquotasstubs.c
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfsrtstubs.c b/sys/gnu/fs/xfs/FreeBSD/xfsrtstubs.c
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/gnu/fs/xfs/FreeBSD/xfsrtstubs.c