Garbage collect XFS bits which are now already completely disconnected
from the tree since few months. This is not targeted for MFC.
This commit is contained in:
parent
258bee160c
commit
67f1f66fc7
@ -38,6 +38,8 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20130302: XFS support removed
|
||||
OLD_FILES+=usr/share/man/man5/xfs.5.gz
|
||||
# 20130116: removed long unused directories for .1aout section manpages
|
||||
OLD_FILES+=usr/share/man/en.ISO8859-1/man1aout
|
||||
OLD_FILES+=usr/share/man/en.UTF-8/man1aout
|
||||
|
@ -1,108 +0,0 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Craig Rodrigues
|
||||
.\" 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 ``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 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$
|
||||
.\"
|
||||
.Dd January 16, 2011
|
||||
.Dt XFS 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm xfs
|
||||
.Nd "XFS file system"
|
||||
.Sh SYNOPSIS
|
||||
To link into the kernel:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "options XFS"
|
||||
.Ed
|
||||
.Pp
|
||||
To load as a kernel loadable module:
|
||||
.Pp
|
||||
.Dl "kldload xfs"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver will permit the
|
||||
.Fx
|
||||
kernel to access
|
||||
.Tn XFS
|
||||
file systems.
|
||||
.Sh EXAMPLES
|
||||
To mount a
|
||||
.Nm
|
||||
volume located on
|
||||
.Pa /dev/ad1s1 :
|
||||
.Pp
|
||||
.Dl "mount -t xfs -o ro /dev/ad1s1 /mnt"
|
||||
.Sh SEE ALSO
|
||||
.Xr nmount 2 ,
|
||||
.Xr unmount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount 8
|
||||
.Sh NOTES
|
||||
The
|
||||
.Pa sysutils/xfsprogs
|
||||
port contains the
|
||||
.Cm mkfs.xfs
|
||||
utility for
|
||||
creating XFS file systems, and also other utilities for analyzing,
|
||||
and repairing XFS file systems.
|
||||
.Sh HISTORY
|
||||
XFS was originally written by SGI for the IRIX operating system.
|
||||
SGI ported XFS to Linux, and released the source code under the GNU
|
||||
Public License. For more details, see:
|
||||
.Pa http://oss.sgi.com/projects/xfs
|
||||
.Pp
|
||||
The port to
|
||||
.Fx
|
||||
was based on the Linux port, and started by
|
||||
.An -nosplit
|
||||
.An Russell Cattelan Aq cattelan@xfs.org ,
|
||||
.An Alexander Kabaev Aq kan@FreeBSD.org ,
|
||||
and
|
||||
.An Craig Rodrigues Aq rodrigc@FreeBSD.org .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
file system support
|
||||
first appeared in
|
||||
.Fx 7.0 .
|
||||
.Sh AUTHORS
|
||||
This manual page was written by
|
||||
.An Craig Rodrigues Aq rodrigc@FreeBSD.org .
|
||||
.Sh CAVEATS
|
||||
The port of XFS to
|
||||
.Fx
|
||||
is currently incomplete.
|
||||
Only read-only access is supported for XFS volumes.
|
||||
Writing to a volume is not supported.
|
||||
.Pp
|
||||
The
|
||||
.Fl p
|
||||
flag to
|
||||
.Cm mkfs.xfs
|
||||
can be used to create an XFS file system which is populated with files
|
||||
and other metadata.
|
||||
This can be used to quickly create a read-only file system which
|
||||
can be tested on
|
||||
.Fx .
|
@ -1,36 +0,0 @@
|
||||
#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_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__ */
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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 *, ...);
|
||||
|
||||
#define prdev(fmt,targ,args...) \
|
||||
printf("Device %s - " fmt "\n", XFS_BUFTARG_NAME(targ), ## args)
|
||||
|
||||
#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__))
|
||||
|
||||
#endif /* __XFS_SUPPORT_DEBUG_H__ */
|
@ -1,62 +0,0 @@
|
||||
#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>
|
||||
#endif
|
||||
|
||||
#include <support/kdb.h>
|
||||
|
||||
#ifdef DDB
|
||||
DB_FUNC(xfs, xfs_ddb_cmd, db_cmd_table, CS_MORE, NULL)
|
||||
{
|
||||
db_error("No commands registered.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
kdb_putarea_size(unsigned long addr, void *res, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
#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__ */
|
@ -1,3 +0,0 @@
|
||||
#include <support/kmem.h>
|
||||
|
||||
MALLOC_DEFINE(M_XFS, "XFSALLOC", "XFS memory");
|
@ -1,86 +0,0 @@
|
||||
#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)
|
||||
|
||||
/* Restore the PF_FSTRANS state to what was saved in STATEP */
|
||||
#define PFLAGS_RESTORE_FSTRANS(STATEP) do { \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* memory management routines
|
||||
*/
|
||||
#define KM_SLEEP M_WAITOK
|
||||
#define KM_NOSLEEP M_NOWAIT
|
||||
#define KM_NOFS M_WAITOK
|
||||
#define KM_MAYFAIL 0
|
||||
|
||||
#define kmem_zone uma_zone
|
||||
|
||||
typedef struct uma_zone kmem_zone_t;
|
||||
typedef struct uma_zone xfs_zone_t;
|
||||
|
||||
|
||||
#define KM_ZONE_HWALIGN 0
|
||||
#define KM_ZONE_RECLAIM 0
|
||||
#define KM_ZONE_SPREAD 0
|
||||
|
||||
#define kmem_zone_init(len, name) \
|
||||
uma_zcreate(name, len, NULL, NULL, NULL, NULL, 0, 0)
|
||||
|
||||
static inline kmem_zone_t *
|
||||
kmem_zone_init_flags(int size, char *zone_name, unsigned long flags,
|
||||
void (*construct)(void *, kmem_zone_t *, unsigned long))
|
||||
{
|
||||
return uma_zcreate(zone_name, size, NULL, NULL, NULL, NULL, 0, 0);
|
||||
}
|
||||
|
||||
#define kmem_zone_free(zone, ptr) \
|
||||
uma_zfree(zone, ptr)
|
||||
|
||||
static inline void
|
||||
kmem_zone_destroy(kmem_zone_t *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__ */
|
@ -1,334 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#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_zone_destroy(ktrace_hdr_zone);
|
||||
kmem_zone_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;
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,14 +0,0 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <support/debug.h>
|
||||
#include <support/mrlock.h>
|
||||
|
||||
int
|
||||
ismrlocked(mrlock_t *mrp, int type)
|
||||
{
|
||||
|
||||
sx_assert(mrp, SX_LOCKED);
|
||||
if (type == MR_UPDATE)
|
||||
return sx_xlocked(mrp);
|
||||
return 1;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef __XFS_SUPPORT_MRLOCK_H__
|
||||
#define __XFS_SUPPORT_MRLOCK_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/sx.h>
|
||||
|
||||
/*
|
||||
* Implement mrlocks on FreeBSD that work for XFS.
|
||||
* Map mrlock functions to corresponding equivalents in
|
||||
* sx.
|
||||
*/
|
||||
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
|
||||
|
||||
#define mrlock_init(lock, type, name, seq) sx_init(lock, name)
|
||||
#define mrtryaccess(lock) sx_try_slock(lock)
|
||||
#define mrtryupdate(lock) sx_try_xlock(lock)
|
||||
#define mraccess(lock) sx_slock(lock)
|
||||
#define mrupdate(lock) sx_xlock(lock)
|
||||
#define mrdemote(lock) sx_downgrade(lock)
|
||||
#define mrunlock(lock) sx_unlock(lock)
|
||||
|
||||
#define mrfree(lock) do { \
|
||||
if (sx_xlocked(lock)) \
|
||||
sx_xunlock(lock); \
|
||||
sx_destroy(lock); \
|
||||
} while (0)
|
||||
|
||||
int ismrlocked(mrlock_t *mrp, int type);
|
||||
|
||||
#endif /* __XFS_SUPPORT_MRLOCK_H__ */
|
@ -1,29 +0,0 @@
|
||||
#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__ */
|
@ -1,23 +0,0 @@
|
||||
#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_trylock(lock) sx_try_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__ */
|
@ -1,21 +0,0 @@
|
||||
#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__ */
|
@ -1,53 +0,0 @@
|
||||
/*-
|
||||
* 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__ */
|
@ -1,42 +0,0 @@
|
||||
#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 != 0) {} \
|
||||
} while (0)
|
||||
|
||||
#endif /* __XFS_SUPPORT_SPIN_H__ */
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,30 +0,0 @@
|
||||
#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)
|
||||
/* sv_wait should exit with lock unlocked */
|
||||
#define sv_wait(sv, pri, lock, spl) cv_wait_unlock(sv, lock)
|
||||
#define sv_wait_sig(sv, pri, lock, spl) cv_wait_sig_nolock(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__ */
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,165 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,334 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001,2005 Russell Cattelan
|
||||
* 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 "xfs.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>
|
||||
#include <geom/geom_vfs.h>
|
||||
|
||||
xfs_buf_t *
|
||||
xfs_buf_read_flags(xfs_buftarg_t *target, xfs_daddr_t blkno, size_t len, int flags)
|
||||
{
|
||||
struct buf *bp;
|
||||
KASSERT((target != NULL), ("got NULL buftarg_t"));
|
||||
|
||||
if (bread(target->specvp, blkno, BBTOB(len), NOCRED, &bp)) {
|
||||
printf("bread failed specvp %p blkno %jd BBTOB(len) %ld\n",
|
||||
target->specvp, (intmax_t)blkno, (long)BBTOB(len));
|
||||
bp = NULL;
|
||||
}
|
||||
|
||||
/* not really sure what B_MANAGED really does for us
|
||||
* maybe we should drop this and just stick with a locked buf
|
||||
*/
|
||||
|
||||
if (flags & B_MANAGED)
|
||||
bp->b_flags |= B_MANAGED;
|
||||
xfs_buf_set_target(bp, target);
|
||||
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, 0);
|
||||
if (bp != NULL) {
|
||||
bp->b_bufsize = size;
|
||||
bp->b_bcount = size;
|
||||
|
||||
BUF_ASSERT_HELD(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, 0);
|
||||
if (bp != NULL) {
|
||||
BUF_ASSERT_HELD(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_buf_readahead(
|
||||
xfs_buftarg_t *target,
|
||||
xfs_daddr_t ioff,
|
||||
size_t isize,
|
||||
xfs_buf_flags_t flags)
|
||||
{
|
||||
daddr_t rablkno;
|
||||
int rabsize;
|
||||
|
||||
rablkno = ioff;
|
||||
rabsize = BBTOB(isize);
|
||||
breada(target->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 0
|
||||
if (BUF_LOCKRECURSED(bp))
|
||||
BUF_UNLOCK(bp);
|
||||
else
|
||||
brelse(bp);
|
||||
#endif
|
||||
brelse(bp);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
error = bwrite(bp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
xfs_buf_pin(xfs_buf_t *bp)
|
||||
{
|
||||
bpin(bp);
|
||||
}
|
||||
|
||||
void
|
||||
xfs_buf_unpin(xfs_buf_t *bp)
|
||||
{
|
||||
bunpin(bp);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_buf_ispin(xfs_buf_t *bp)
|
||||
{
|
||||
return bp->b_pin_count;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
xfs_buf_wait_unpin(
|
||||
xfs_buf_t *bp)
|
||||
{
|
||||
bunpin_wait(bp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Move data into or out of a buffer.
|
||||
*/
|
||||
void
|
||||
xfs_buf_iomove(
|
||||
xfs_buf_t *bp, /* buffer to process */
|
||||
size_t boff, /* starting buffer offset */
|
||||
size_t bsize, /* length to copy */
|
||||
caddr_t data, /* data address */
|
||||
xfs_buf_rw_t mode) /* read/write/zero flag */
|
||||
{
|
||||
|
||||
printf("xfs_buf_iomove NI\n");
|
||||
#ifdef RMC
|
||||
size_t bend, cpoff, csize;
|
||||
struct page *page;
|
||||
|
||||
bend = boff + bsize;
|
||||
while (boff < bend) {
|
||||
page = bp->b_pages[xfs_buf_btoct(boff + bp->b_offset)];
|
||||
cpoff = xfs_buf_poff(boff + bp->b_offset);
|
||||
csize = min_t(size_t,
|
||||
PAGE_CACHE_SIZE-cpoff, bp->b_count_desired-boff);
|
||||
|
||||
ASSERT(((csize + cpoff) <= PAGE_CACHE_SIZE));
|
||||
|
||||
switch (mode) {
|
||||
case XBRW_ZERO:
|
||||
memset(page_address(page) + cpoff, 0, csize);
|
||||
break;
|
||||
case XBRW_READ:
|
||||
memcpy(data, page_address(page) + cpoff, csize);
|
||||
break;
|
||||
case XBRW_WRITE:
|
||||
memcpy(page_address(page) + cpoff, data, csize);
|
||||
}
|
||||
|
||||
boff += csize;
|
||||
data += csize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handling of buffer targets (buftargs).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Wait for any bufs with callbacks that have been submitted but
|
||||
* have not yet returned... walk the hash list for the target.
|
||||
*/
|
||||
void
|
||||
xfs_wait_buftarg(
|
||||
xfs_buftarg_t *bp)
|
||||
{
|
||||
printf("xfs_wait_buftarg(%p) NI\n", bp);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_flush_buftarg(
|
||||
xfs_buftarg_t *btp,
|
||||
int wait)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
error = vinvalbuf(btp->specvp, V_SAVE | V_NORMAL, 0, 0);
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
xfs_free_buftarg(
|
||||
xfs_buftarg_t *btp,
|
||||
int external)
|
||||
{
|
||||
xfs_flush_buftarg(btp, /* wait */ 0);
|
||||
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_bo_ops,
|
||||
("Bogus xfs_buftarg_t pointer"));
|
||||
cp = btp->specvp->v_bufobj.bo_private;
|
||||
return (cp->acw == 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
xfs_relse_buftarg(
|
||||
xfs_buftarg_t *btp)
|
||||
{
|
||||
printf("xfs_relse_buftargNI %p\n",btp);
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int
|
||||
xfs_getsize_buftarg(
|
||||
xfs_buftarg_t *btp)
|
||||
{
|
||||
struct g_consumer *cp;
|
||||
cp = btp->specvp->v_bufobj.bo_private;
|
||||
return (cp->provider->sectorsize);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_setsize_buftarg(
|
||||
xfs_buftarg_t *btp,
|
||||
unsigned int blocksize,
|
||||
unsigned int sectorsize)
|
||||
{
|
||||
printf("xfs_setsize_buftarg NI %p\n",btp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xfs_buftarg_t *
|
||||
xfs_alloc_buftarg(
|
||||
struct vnode *bdev,
|
||||
int external)
|
||||
{
|
||||
xfs_buftarg_t *btp;
|
||||
|
||||
btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
|
||||
|
||||
btp->dev = bdev->v_rdev;
|
||||
btp->specvp = bdev;
|
||||
return btp;
|
||||
}
|
@ -1,348 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_mount;
|
||||
struct vnode;
|
||||
typedef struct buf xfs_buf_t;
|
||||
typedef uint32_t xfs_buf_flags_t;
|
||||
#define xfs_buf buf
|
||||
|
||||
extern struct buf_ops xfs_bo_ops;
|
||||
|
||||
typedef enum {
|
||||
XBRW_READ = 1, /* transfer into target memory */
|
||||
XBRW_WRITE = 2, /* transfer from target memory */
|
||||
XBRW_ZERO = 3, /* Zero target memory */
|
||||
} xfs_buf_rw_t;
|
||||
|
||||
/* Buffer Read and Write Routines */
|
||||
extern void xfs_buf_ioend(xfs_buf_t *, int);
|
||||
extern void xfs_buf_ioerror(xfs_buf_t *, int);
|
||||
extern int xfs_buf_iostart(xfs_buf_t *, xfs_buf_flags_t);
|
||||
extern int xfs_buf_iorequest(xfs_buf_t *);
|
||||
extern int xfs_buf_iowait(xfs_buf_t *);
|
||||
extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, xfs_caddr_t, xfs_buf_rw_t);
|
||||
|
||||
/* Pinning Buffer Storage in Memory */
|
||||
extern void xfs_buf_pin(xfs_buf_t *);
|
||||
extern void xfs_buf_unpin(xfs_buf_t *);
|
||||
extern int xfs_buf_ispin(xfs_buf_t *);
|
||||
|
||||
|
||||
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 {
|
||||
/* this probaby redundant info, but stick with linux conventions for now */
|
||||
unsigned int bt_bsize;
|
||||
unsigned int bt_sshift;
|
||||
size_t bt_smask;
|
||||
struct cdev *dev;
|
||||
struct vnode *specvp;
|
||||
} xfs_buftarg_t;
|
||||
|
||||
|
||||
/* Finding and Reading Buffers */
|
||||
extern void xfs_buf_readahead(xfs_buftarg_t *, xfs_off_t, size_t, xfs_buf_flags_t);
|
||||
/* Misc buffer rountines */
|
||||
extern int xfs_readonly_buftarg(xfs_buftarg_t *);
|
||||
|
||||
/* 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 XBF_DONT_BLOCK 0
|
||||
|
||||
#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
|
||||
|
||||
#define XBF_ORDERED 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|B_NOCACHE))
|
||||
#define XFS_BUF_UNSTALE(x) ((x)->b_flags &= ~(XFS_B_STALE|B_NOCACHE))
|
||||
#define XFS_BUF_ISSTALE(x) ((x)->b_flags & (XFS_B_STALE|B_NOCACHE))
|
||||
#define XFS_BUF_SUPER_STALE(x) {(x)->b_flags |= (XFS_B_STALE|B_NOCACHE); \
|
||||
(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_ORDERED(bp) ((bp)->b_flags |= XBF_ORDERED)
|
||||
#define XFS_BUF_UNORDERED(bp) ((bp)->b_flags &= ~XBF_ORDERED)
|
||||
#define XFS_BUF_ISORDERED(bp) ((bp)->b_flags & XBF_ORDERED)
|
||||
|
||||
#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_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_ISLOCKED(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_buf_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)
|
||||
|
||||
/* the return value is never used ... why does linux define this functions this way? */
|
||||
static inline int xfs_bawrite(void *mp, xfs_buf_t *bp)
|
||||
{
|
||||
/* Ditto for xfs_bawrite
|
||||
bp->b_fspriv3 = mp;
|
||||
bp->b_strat = xfs_bdstrat_cb;
|
||||
xfs_buf_delwri_dequeue(bp);
|
||||
return xfs_buf_iostart(bp, XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES);
|
||||
*/
|
||||
bawrite(bp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int xfs_bdwrite(void *mp, xfs_buf_t *bp)
|
||||
{
|
||||
/* this is for io shutdown checking need to do this at some point RMC */
|
||||
/* probably should just change xfs to call a buf write function */
|
||||
#if 0 /* RMC */
|
||||
bp->b_strat = xfs_bdstrat_cb;
|
||||
bp->b_fspriv3 = mp;
|
||||
return xfs_buf_iostart(bp, XBF_DELWRI | XBF_ASYNC);
|
||||
#endif
|
||||
bdwrite(bp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define xfs_bpin(bp) xfs_buf_pin(bp)
|
||||
#define xfs_bunpin(bp) xfs_buf_unpin(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(bp, off, len, data, rw) \
|
||||
xfs_buf_iomove((bp), (off), (len), (data), \
|
||||
((rw) == XFS_B_WRITE) ? XBRW_WRITE : XBRW_READ)
|
||||
|
||||
#define xfs_biozero(bp, off, len) \
|
||||
xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO)
|
||||
|
||||
/* already a function xfs_bwrite... fix this */
|
||||
#define XFS_bdwrite(bp) bdwrite(bp)
|
||||
#define xfs_iowait(bp) bufwait(bp)
|
||||
|
||||
#define XFS_bdstrat(bp) xfs_buf_iorequest(bp)
|
||||
|
||||
#define xfs_baread(target, rablkno, ralen) \
|
||||
xfs_buf_readahead((target), (rablkno), (ralen), XBF_DONT_BLOCK)
|
||||
|
||||
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 *);
|
||||
|
||||
extern void xfs_bwait_unpin(xfs_buf_t *bp);
|
||||
extern xfs_buftarg_t *xfs_alloc_buftarg(struct vnode *, int);
|
||||
extern void xfs_free_buftarg(xfs_buftarg_t *, int);
|
||||
extern void xfs_wait_buftarg(xfs_buftarg_t *);
|
||||
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
|
||||
extern unsigned int xfs_getsize_buftarg(struct xfs_buftarg *);
|
||||
extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
|
||||
|
||||
#define xfs_binval(buftarg) xfs_flush_buftarg(buftarg, 1)
|
||||
#define XFS_bflush(buftarg) xfs_flush_buftarg(buftarg, 1)
|
||||
|
||||
#endif
|
@ -1,173 +0,0 @@
|
||||
#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;
|
||||
|
||||
/* linus now has sparse which expects big endian or little endian */
|
||||
typedef __u16 __be16;
|
||||
typedef __u32 __be32;
|
||||
typedef __u64 __be64;
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
#define rol32(x, y) (((x)<<(y))|((x)>>(32-(y))))
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* 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))
|
||||
|
||||
|
||||
typedef struct mtx xfs_mutex_t;
|
||||
/*
|
||||
* Cedentials manipulation.
|
||||
*/
|
||||
#define current_fsuid(credp) (credp)->cr_uid
|
||||
#define current_fsgid(credp) (credp)->cr_groups[0]
|
||||
|
||||
#define PAGE_CACHE_SIZE PAGE_SIZE
|
||||
|
||||
#define IS_ERR(err) (err)
|
||||
|
||||
static inline unsigned long ffz(unsigned long val)
|
||||
{
|
||||
return ffsl(~val);
|
||||
}
|
||||
|
||||
#endif /* __XFS_COMPAT_H__ */
|
@ -1,38 +0,0 @@
|
||||
#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__ */
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* 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_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);
|
||||
int
|
||||
dmapi_init (void)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
void dmapi_uninit(void);
|
||||
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();
|
||||
}
|
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
/*
|
||||
* 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 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_centisecs xfs_params.syncd_timer.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_buf_timer_centisecs xfs_params.xfs_buf_timer.val
|
||||
#define xfs_buf_age_centisecs xfs_params.xfs_buf_age.val
|
||||
#define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
|
||||
#define xfs_rotorstep xfs_params.rotorstep.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 */
|
||||
|
||||
/* 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() __compiler_membar()
|
||||
#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))
|
||||
|
||||
#define xfs_sort(a,n,s,fn) qsort(a,n,s,fn)
|
||||
|
||||
|
||||
static inline int xfs_itruncate_data(void *ip, xfs_off_t off) {
|
||||
printf ("xfs_itruncate_data NI\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
#define xfs_statvfs_fsid(statp, mp) \
|
||||
({ \
|
||||
(statp)->f_fsid.val[0] = /*dev2udev(mp->m_dev) */ 1; \
|
||||
(statp)->f_fsid.val[1] = 0; \
|
||||
})
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
#endif /* __XFS_FREEBSD__ */
|
@ -1,419 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2006 Russell Cattelan Digital Elves, 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_types.h"
|
||||
#include "xfs_bit.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_attr_sf.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_ialloc.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 **);
|
||||
|
||||
/*
|
||||
* 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 flags,
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
printf("xfs_iput_new: ip %p\n",ip);
|
||||
|
||||
if ((ip->i_d.di_mode == 0)) {
|
||||
ASSERT(!(ip->i_flags & XFS_IRECLAIMABLE));
|
||||
//vn_mark_bad(vp);
|
||||
printf("xfs_iput_new: ip %p di_mode == 0\n",ip);
|
||||
/* mabe call vgone here? RMC */
|
||||
}
|
||||
if (lock_flags)
|
||||
xfs_iunlock(ip, lock_flags);
|
||||
|
||||
ASSERT_VOP_LOCKED(vp->v_vnode, "xfs_iput_new");
|
||||
vput(vp->v_vnode);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||
VN_LOCK_AREC(vp);
|
||||
error = insmntque(vp, XVFSTOMNT(XFS_MTOVFS(mp)));
|
||||
if (error != 0) {
|
||||
kmem_free(vdata, sizeof(*vdata));
|
||||
return (error);
|
||||
}
|
||||
|
||||
vp->v_data = (void *)vdata;
|
||||
vdata->v_number= 0;
|
||||
vdata->v_inode = ip;
|
||||
vdata->v_vfsp = XFS_MTOVFS(mp);
|
||||
vdata->v_vnode = vp;
|
||||
|
||||
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);
|
||||
}
|
@ -1,891 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_inum.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_bmap_btree.h"
|
||||
#include "xfs_alloc_btree.h"
|
||||
#include "xfs_ialloc_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_bmap.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_ialloc.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_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 */
|
||||
xfs_off_t pos, /* offset in file */
|
||||
size_t count, /* size of data to zero */
|
||||
xfs_off_t end_size) /* max file size to set */
|
||||
{
|
||||
int status;
|
||||
status = 0; /* XXXKAN: */
|
||||
#ifdef XXXKAN
|
||||
unsigned bytes;
|
||||
struct page *page;
|
||||
struct address_space *mapping;
|
||||
char *kaddr;
|
||||
|
||||
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);
|
||||
#endif
|
||||
return (-status);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
xfs_ilock(ip, XFS_IOLOCK_SHARED);
|
||||
|
||||
#ifdef XXX
|
||||
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) {
|
||||
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = xfs_read_file(mp, ip, uio, ioflags);
|
||||
|
||||
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_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 error = 0;
|
||||
xfs_bmbt_irec_t imap;
|
||||
xfs_off_t loff;
|
||||
|
||||
ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
|
||||
|
||||
mp = io->io_mount;
|
||||
|
||||
zero_offset = XFS_B_FSB_OFFSET(mp, isize);
|
||||
if (zero_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, 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);
|
||||
|
||||
zero_len = mp->m_sb.sb_blocksize - zero_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 zero_count_fsb;
|
||||
xfs_fileoff_t last_fsb;
|
||||
xfs_extlen_t buf_len_fsb;
|
||||
xfs_mount_t *mp;
|
||||
int nimaps;
|
||||
int error = 0;
|
||||
xfs_bmbt_irec_t imap;
|
||||
|
||||
ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
|
||||
ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
|
||||
ASSERT(offset > isize);
|
||||
|
||||
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, 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);
|
||||
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, 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
error = xfs_iozero(vp,
|
||||
XFS_FSB_TO_B(mp, start_zero_fsb),
|
||||
XFS_FSB_TO_B(mp, buf_len_fsb),
|
||||
end_size);
|
||||
|
||||
if (error) {
|
||||
goto out_lock;
|
||||
}
|
||||
|
||||
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 *uio,
|
||||
int ioflag,
|
||||
cred_t *credp)
|
||||
{
|
||||
xfs_inode_t *xip;
|
||||
xfs_mount_t *mp;
|
||||
ssize_t ret = 0;
|
||||
int error = 0;
|
||||
xfs_fsize_t isize, new_size;
|
||||
xfs_fsize_t n, limit;
|
||||
xfs_fsize_t size;
|
||||
xfs_iocore_t *io;
|
||||
xfs_vnode_t *vp;
|
||||
int iolock;
|
||||
//int eventsent = 0;
|
||||
vrwlock_t locktype;
|
||||
xfs_off_t offset_c;
|
||||
xfs_off_t *offset;
|
||||
xfs_off_t pos;
|
||||
|
||||
XFS_STATS_INC(xs_write_calls);
|
||||
|
||||
vp = BHV_TO_VNODE(bdp);
|
||||
xip = XFS_BHVTOI(bdp);
|
||||
|
||||
io = &xip->i_iocore;
|
||||
mp = io->io_mount;
|
||||
|
||||
if (XFS_FORCED_SHUTDOWN(xip->i_mount)) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
size = uio->uio_resid;
|
||||
pos = offset_c = uio->uio_offset;
|
||||
offset = &offset_c;
|
||||
|
||||
if (unlikely(ioflag & 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;
|
||||
}
|
||||
|
||||
iolock = XFS_IOLOCK_EXCL;
|
||||
locktype = VRWLOCK_WRITE;
|
||||
|
||||
xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
|
||||
|
||||
isize = xip->i_d.di_size;
|
||||
limit = XFS_MAXIOFFSET(mp);
|
||||
|
||||
if (ioflag & 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;
|
||||
}
|
||||
|
||||
#ifdef RMC
|
||||
/* probably be a long time before if ever that we do dmapi */
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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 (!(ioflag & 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 0
|
||||
/*
|
||||
* 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 (likely(!error))
|
||||
error = -remove_suid(file->f_dentry);
|
||||
if (unlikely(error)) {
|
||||
xfs_iunlock(xip, iolock);
|
||||
goto out_unlock_mutex;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//retry:
|
||||
if (unlikely(ioflag & IO_ISDIRECT)) {
|
||||
|
||||
#ifdef RMC
|
||||
xfs_off_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);
|
||||
xfs_inval_cached_pages(vp, io, pos, 1, 1);
|
||||
if (ret > 0)
|
||||
*offset += ret;
|
||||
#endif
|
||||
} else {
|
||||
xfs_rw_enter_trace(XFS_WRITE_ENTER, io, buf, size, *offset, ioflags);
|
||||
ret = xfs_write_file(xip,uio,ioflag);
|
||||
}
|
||||
|
||||
xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
|
||||
|
||||
|
||||
//error:
|
||||
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) {
|
||||
printf("xfs_write look at doing more here %s:%d\n",__FILE__,__LINE__);
|
||||
#ifdef RMC
|
||||
struct inode *inode = LINVFS_GET_IP(vp);
|
||||
i_size_write(inode, *offset);
|
||||
mark_inode_dirty_sync(inode);
|
||||
#endif
|
||||
|
||||
xip->i_d.di_size = *offset;
|
||||
xip->i_update_core = 1;
|
||||
xip->i_update_size = 1;
|
||||
}
|
||||
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
||||
}
|
||||
|
||||
/* Handle various SYNC-type writes */
|
||||
#if 0
|
||||
// if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
|
||||
#endif
|
||||
if (ioflag & IO_SYNC) {
|
||||
/*
|
||||
* 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)) {
|
||||
xfs_inode_log_item_t *iip = xip->i_itemp;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (iip && iip->ili_last_lsn) {
|
||||
xfs_log_force(mp, iip->ili_last_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, NULL);
|
||||
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
||||
}
|
||||
if (error)
|
||||
goto out_unlock_internal;
|
||||
}
|
||||
|
||||
xfs_rwunlock(bdp, locktype);
|
||||
return ret;
|
||||
|
||||
} /* (ioflags & O_SYNC) */
|
||||
|
||||
out_unlock_internal:
|
||||
xfs_rwunlock(bdp, locktype);
|
||||
#if 0
|
||||
out_unlock_mutex:
|
||||
if (need_i_mutex)
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
#endif
|
||||
//out_nounlocks:
|
||||
return -error;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
|
||||
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;
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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 *);
|
||||
|
||||
extern int xfs_read_file(struct xfs_mount *mp, struct xfs_inode *ip, struct uio *uio,
|
||||
int ioflag);
|
||||
extern int xfs_write_file(struct xfs_inode *, struct uio *, int);
|
||||
#endif /* __XFS_FRW_H__ */
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
#ifdef 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)
|
||||
{
|
||||
#ifdef 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)
|
||||
{
|
||||
#ifdef 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;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* 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_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 },
|
||||
.syncd_timer = { 1*100, 30*100, 7200*100},
|
||||
.probe_dmapi = { 0, 0, 1 },
|
||||
.probe_ioops = { 0, 0, 1 },
|
||||
.probe_quota = { 0, 1, 1 },
|
||||
.stats_clear = { 0, 0, 1 },
|
||||
.inherit_sync = { 0, 1, 1 },
|
||||
.inherit_nodump = { 0, 1, 1 },
|
||||
.inherit_noatim = { 0, 1, 1 },
|
||||
.xfs_buf_timer = { 100/2, 1*100, 30*100 },
|
||||
.xfs_buf_age = { 1*100, 15*100, 7200*100},
|
||||
.inherit_nosym = { 0, 0, 1 },
|
||||
.rotorstep = { 1, 1, 255 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Global system credential structure.
|
||||
*/
|
||||
cred_t sys_cred_val, *sys_cred = &sys_cred_val;
|
File diff suppressed because it is too large
Load Diff
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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, u_long, void *);
|
||||
|
||||
#endif /* __XFS_IOPS_H__ */
|
@ -1,500 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001,2006 Alexander Kabaev, Russell Cattelan Digital Elves Inc.
|
||||
* 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/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_types.h"
|
||||
#include "xfs_bit.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_attr_sf.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_ialloc.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_alloc.h"
|
||||
#include "xfs_rtalloc.h"
|
||||
#include "xfs_bmap.h"
|
||||
#include "xfs_error.h"
|
||||
#include "xfs_rw.h"
|
||||
#include "xfs_quota.h"
|
||||
#include "xfs_fsops.h"
|
||||
#include "xfs_clnt.h"
|
||||
|
||||
#include <xfs_mountops.h>
|
||||
|
||||
static 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_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", "export",
|
||||
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 && error != ENOENT)
|
||||
return error;
|
||||
|
||||
args->flags |= XFSMNT_32BITINODES;
|
||||
|
||||
parse_int(mp, "sunit", &args->sunit, &error);
|
||||
if (error != 0 && error != ENOENT)
|
||||
return error;
|
||||
|
||||
parse_int(mp, "swidth", &args->swidth, &error);
|
||||
if (error != 0 && error != ENOENT)
|
||||
return error;
|
||||
|
||||
parse_int(mp, "logbufs", &args->logbufs, &error);
|
||||
if (error != 0 && error != ENOENT)
|
||||
return error;
|
||||
|
||||
parse_int(mp, "logbufsize", &args->logbufsize, &error);
|
||||
if (error != 0 && error != ENOENT)
|
||||
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 xfsmount *xmp;
|
||||
struct xfs_vnode *rootvp;
|
||||
struct ucred *curcred;
|
||||
struct vnode *rvp, *devvp;
|
||||
struct cdev *ddev;
|
||||
struct g_consumer *cp;
|
||||
struct thread *td;
|
||||
int error;
|
||||
|
||||
td = curthread;
|
||||
ddev = NULL;
|
||||
cp = NULL;
|
||||
|
||||
if (vfs_filteropt(mp->mnt_optnew, xfs_opts))
|
||||
return (EINVAL);
|
||||
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (0);
|
||||
if ((mp->mnt_flag & MNT_RDONLY) == 0)
|
||||
return (EPERM);
|
||||
|
||||
xmp = xfsmount_allocate(mp);
|
||||
if (xmp == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
if((error = _xfs_param_copyin(mp, td)) != 0)
|
||||
goto fail;
|
||||
|
||||
curcred = td->td_ucred;
|
||||
XVFS_MOUNT(XFSTOVFS(xmp), &xmp->m_args, curcred, error);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
XVFS_ROOT(XFSTOVFS(xmp), &rootvp, error);
|
||||
ddev = XFS_VFSTOM(XFSTOVFS(xmp))->m_ddev_targp->dev;
|
||||
devvp = XFS_VFSTOM(XFSTOVFS(xmp))->m_ddev_targp->specvp;
|
||||
if (error)
|
||||
goto fail_unmount;
|
||||
|
||||
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;
|
||||
mp->mnt_stat.f_fsid.val[0] = dev2udev(ddev);
|
||||
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
|
||||
|
||||
if ((error = VFS_STATFS(mp, &mp->mnt_stat)) != 0)
|
||||
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);
|
||||
|
||||
if (devvp != NULL) {
|
||||
cp = devvp->v_bufobj.bo_private;
|
||||
if (cp != NULL) {
|
||||
DROP_GIANT();
|
||||
g_topology_lock();
|
||||
g_vfs_close(cp);
|
||||
g_topology_unlock();
|
||||
PICKUP_GIANT();
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
if (xmp != NULL)
|
||||
xfsmount_deallocate(xmp);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to null layer
|
||||
*/
|
||||
static int
|
||||
_xfs_unmount(mp, mntflags)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
{
|
||||
struct vnode *devvp;
|
||||
struct g_consumer *cp;
|
||||
int error;
|
||||
cp = NULL;
|
||||
devvp = NULL;
|
||||
|
||||
devvp = XFS_VFSTOM((MNTTOVFS(mp)))->m_ddev_targp->specvp;
|
||||
if (devvp != NULL)
|
||||
cp = devvp->v_bufobj.bo_private;
|
||||
|
||||
XVFS_UNMOUNT(MNTTOVFS(mp), 0, curthread->td_ucred, error);
|
||||
if (error == 0) {
|
||||
if (cp != NULL) {
|
||||
DROP_GIANT();
|
||||
g_topology_lock();
|
||||
g_vfs_close(cp);
|
||||
g_topology_unlock();
|
||||
PICKUP_GIANT();
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
_xfs_root(mp, flags, vpp)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
xfs_vnode_t *vp;
|
||||
int error;
|
||||
|
||||
XVFS_ROOT(MNTTOVFS(mp), &vp, error);
|
||||
if (error == 0) {
|
||||
*vpp = vp->v_vnode;
|
||||
VOP_LOCK(*vpp, flags);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
_xfs_quotactl(mp, cmd, uid, arg)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
uid_t uid;
|
||||
void *arg;
|
||||
{
|
||||
printf("xfs_quotactl\n");
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
_xfs_statfs(mp, sbp)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
{
|
||||
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)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
{
|
||||
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, curthread->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 = NULL;
|
||||
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, flags, vpp)
|
||||
struct mount *mp;
|
||||
struct fid *fidp;
|
||||
int flags;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
printf("xfs_fhtovp\n");
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
static int
|
||||
_xfs_extattrctl(struct mount *mp, int cm,
|
||||
struct vnode *filename_v,
|
||||
int attrnamespace, const char *attrname)
|
||||
{
|
||||
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_init = _xfs_init,
|
||||
.vfs_uninit = _xfs_uninit,
|
||||
.vfs_extattrctl = _xfs_extattrctl,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_geom_bufsync(struct bufobj *bo, int waitfor)
|
||||
{
|
||||
|
||||
return (bufsync(bo, waitfor));
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_geom_bufbdflush(struct bufobj *bo, struct buf *bp)
|
||||
{
|
||||
bufbdflush(bo, bp);
|
||||
}
|
||||
|
||||
struct buf_ops xfs_bo_ops = {
|
||||
.bop_name = "XFS",
|
||||
.bop_write = xfs_geom_bufwrite,
|
||||
.bop_strategy = xfs_geom_strategy,
|
||||
.bop_sync = xfs_geom_bufsync,
|
||||
.bop_bdflush = xfs_geom_bufbdflush,
|
||||
};
|
@ -1,59 +0,0 @@
|
||||
/*-
|
||||
* 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*/
|
||||
|
@ -1,16 +0,0 @@
|
||||
#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__ */
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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, "%s", 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)
|
||||
{
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
||||
|
@ -1,279 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_clnt.h"
|
||||
#include "xfs_inum.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_bmap_btree.h"
|
||||
#include "xfs_alloc_btree.h"
|
||||
#include "xfs_ialloc_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_ialloc.h"
|
||||
#include "xfs_bmap.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 "xfs_buf.h"
|
||||
|
||||
#include <sys/priv.h>
|
||||
|
||||
#include <geom/geom.h>
|
||||
#include <geom/geom_vfs.h>
|
||||
|
||||
extern struct vop_vector xfs_fifoops;
|
||||
extern struct xfs_vnodeops xfs_vnodeops;
|
||||
|
||||
__uint64_t
|
||||
xfs_max_file_offset(
|
||||
unsigned int blockshift)
|
||||
{
|
||||
|
||||
return (OFF_MAX);
|
||||
}
|
||||
|
||||
void
|
||||
xfs_initialize_vnode(
|
||||
bhv_desc_t *bdp,
|
||||
xfs_vnode_t *xvp,
|
||||
bhv_desc_t *inode_bhv,
|
||||
int unlock)
|
||||
{
|
||||
xfs_inode_t *ip = XFS_BHVTOI(inode_bhv);
|
||||
|
||||
if (!inode_bhv->bd_vobj) {
|
||||
xvp->v_vfsp = bhvtovfs(bdp);
|
||||
bhv_desc_init(inode_bhv, ip, xvp, &xfs_vnodeops);
|
||||
bhv_insert(VN_BHV_HEAD(xvp), 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 (xvp->v_vnode->v_type != VNON)
|
||||
return;
|
||||
|
||||
xvp->v_vnode->v_type = IFTOVT(ip->i_d.di_mode);
|
||||
|
||||
if (xvp->v_vnode->v_type == VFIFO)
|
||||
xvp->v_vnode->v_op = &xfs_fifoops;
|
||||
|
||||
ASSERT_VOP_LOCKED(xvp->v_vnode, "xfs_initialize_vnode");
|
||||
|
||||
/* For new inodes we need to set the ops vectors,
|
||||
* and unlock the inode.
|
||||
*/
|
||||
if (ip->i_d.di_mode != 0 && unlock)
|
||||
VOP_UNLOCK(xvp->v_vnode, 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct vnode *
|
||||
xfs_get_inode(
|
||||
bhv_desc_t *bdp,
|
||||
xfs_ino_t ino,
|
||||
int flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*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;
|
||||
accmode_t accmode;
|
||||
|
||||
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);
|
||||
|
||||
ronly = ((XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) != 0);
|
||||
accmode = VREAD;
|
||||
if (!ronly)
|
||||
accmode |= VWRITE;
|
||||
error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
|
||||
if (error)
|
||||
error = priv_check(td, PRIV_VFS_MOUNT_PERM);
|
||||
if (error) {
|
||||
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();
|
||||
|
||||
if (error) {
|
||||
vput(devvp);
|
||||
return (error);
|
||||
}
|
||||
VOP_UNLOCK(devvp, 0);
|
||||
|
||||
devvp->v_bufobj.bo_private = cp;
|
||||
devvp->v_bufobj.bo_ops = &xfs_bo_ops;
|
||||
|
||||
*bdevp = devvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
xfs_blkdev_put(
|
||||
struct vnode *devvp)
|
||||
{
|
||||
struct g_consumer *cp;
|
||||
|
||||
if (devvp == NULL)
|
||||
return;
|
||||
|
||||
vinvalbuf(devvp, V_SAVE, 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_mountfs_check_barriers(xfs_mount_t *mp)
|
||||
{
|
||||
printf("xfs_mountfs_check_barriers NI\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xfs_blkdev_issue_flush(
|
||||
xfs_buftarg_t *buftarg)
|
||||
{
|
||||
printf("xfs_blkdev_issue_flush NI\n");
|
||||
}
|
||||
|
||||
int
|
||||
init_xfs_fs( void )
|
||||
{
|
||||
static const char message[] =
|
||||
XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled\n";
|
||||
|
||||
printf(message);
|
||||
|
||||
vn_init();
|
||||
xfs_init();
|
||||
uuid_init();
|
||||
#ifdef RMC
|
||||
vfs_initdmapi();
|
||||
#endif
|
||||
vfs_initquota();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
exit_xfs_fs(void)
|
||||
{
|
||||
xfs_cleanup();
|
||||
vfs_exitquota();
|
||||
#ifdef RMC
|
||||
vfs_exitdmapi();
|
||||
#endif
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#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 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 void xfs_blkdev_issue_flush(struct xfs_buftarg *);
|
||||
|
||||
extern struct export_operations xfs_export_operations;
|
||||
|
||||
extern int init_xfs_fs(void);
|
||||
extern void exit_xfs_fs(void);
|
||||
|
||||
#endif /* __XFS_SUPER_H__ */
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#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 if process' GID is
|
||||
* not a member of 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 syncd_timer; /* Interval between xfssyncd wakeups */
|
||||
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 xfs_buf_timer; /* Interval between xfsbufd wakeups. */
|
||||
xfs_sysctl_val_t xfs_buf_age; /* Metadata buffer age before flush. */
|
||||
xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */
|
||||
xfs_sysctl_val_t rotorstep; /* inode32 AG rotoring control knob */
|
||||
} 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_SYNCD_TIMER = 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_BUF_TIMER = 16,
|
||||
XFS_BUF_AGE = 17,
|
||||
/* XFS_IO_BYPASS = 18 */
|
||||
XFS_INHERIT_NOSYM = 19,
|
||||
XFS_ROTORSTEP = 20,
|
||||
};
|
||||
|
||||
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__ */
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,356 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.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 = 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);
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
/*
|
||||
* 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_32BITINODES 0x0008 /* do not use inums above 32 bits */
|
||||
#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 SYNC_QUIESCE 0x0100 /* quiesce filesystem for a snapshot */
|
||||
|
||||
#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 void (*xvfs_freeze_t)(bhv_desc_t *);
|
||||
|
||||
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 */
|
||||
xvfs_freeze_t xvfs_freeze; /* freeze fs for snapshot */
|
||||
} 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__ */
|
@ -1,272 +0,0 @@
|
||||
/*
|
||||
* 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_types.h"
|
||||
#include "xfs_bit.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_attr_sf.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_ialloc.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_inode_item.h"
|
||||
|
||||
void
|
||||
vn_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
vn_iowait(
|
||||
struct xfs_vnode *vp)
|
||||
{
|
||||
printf("vn_iowait doing nothing on FreeBSD?\n");
|
||||
}
|
||||
|
||||
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, LK_EXCLUSIVE, curthread);
|
||||
vdrop(vp);
|
||||
if (error)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Drop the vnode returned by vget here.
|
||||
* VOP_RECLAIM(9) should block on internal XFS locks so that
|
||||
* the reclaiming scheme still remains consistent even if the
|
||||
* vp is not locked.
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0);
|
||||
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)
|
||||
{
|
||||
struct vnode *vp;
|
||||
|
||||
vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
|
||||
|
||||
vp = xfs_vp->v_vnode;
|
||||
|
||||
vn_lock(vp, LK_EXCLUSIVE);
|
||||
if (vp->v_holdcnt == 0)
|
||||
vhold(vp);
|
||||
vgone(vp);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
}
|
||||
|
||||
void xfs_ichgtime(
|
||||
xfs_inode_t *ip,
|
||||
int flags)
|
||||
{
|
||||
timespec_t tv;
|
||||
|
||||
vfs_timestamp(&tv);
|
||||
if (flags & XFS_ICHGTIME_MOD) {
|
||||
ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
|
||||
ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
|
||||
}
|
||||
if (flags & XFS_ICHGTIME_ACC) {
|
||||
ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
|
||||
ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
|
||||
}
|
||||
if (flags & XFS_ICHGTIME_CHG) {
|
||||
ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
|
||||
ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
|
||||
}
|
||||
|
||||
//printf ("xfs_ichgtime NI\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Bring the atime in the XFS inode uptodate.
|
||||
* Used before logging the inode to disk or when the Linux inode goes away.
|
||||
*/
|
||||
|
||||
/*
|
||||
* It's unclear if we need this since this is for syncing the linux inode's atime
|
||||
* to the xfs inode's atime.
|
||||
* Since FreeBSD doesn't have atime in the vnode is there anything to really
|
||||
* sync over?
|
||||
* For now just make this a update atime call
|
||||
*/
|
||||
|
||||
void
|
||||
xfs_synchronize_atime(
|
||||
xfs_inode_t *ip)
|
||||
{
|
||||
#if 0
|
||||
xfs_vnode_t *vp;
|
||||
#endif
|
||||
|
||||
timespec_t tv;
|
||||
|
||||
/* vfs_timestamp looks at the system time accuracy variable */
|
||||
vfs_timestamp(&tv);
|
||||
#if 0
|
||||
printf("xfs_synchronize_atime old (%d,%d) new (%d,%ld)\n",
|
||||
ip->i_d.di_atime.t_sec,
|
||||
ip->i_d.di_atime.t_nsec,
|
||||
tv.tv_sec,
|
||||
tv.tv_nsec);
|
||||
#endif
|
||||
|
||||
ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
|
||||
ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
|
||||
}
|
||||
|
||||
#ifdef RMC
|
||||
/*
|
||||
* Extracting atime values in various formats
|
||||
*/
|
||||
void vn_atime_to_bstime(struct xfs_vnode *vp, xfs_bstime_t *bs_atime)
|
||||
{
|
||||
bs_atime->tv_sec = vp->v_inode.i_atime.tv_sec;
|
||||
bs_atime->tv_nsec = vp->v_inode.i_atime.tv_nsec;
|
||||
printf("vn_atime_to_bstime NI\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#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 */
|
@ -1,673 +0,0 @@
|
||||
/*
|
||||
* 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 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) */
|
||||
struct xfs_vfs *v_vfsp; /* ptr to containing VFS */
|
||||
xfs_ino_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;
|
||||
|
||||
|
||||
/* vnode types */
|
||||
#define VN_ISLNK(vp) ((vp)->v_vnode->v_type & VLNK)
|
||||
#define VN_ISREG(vp) ((vp)->v_vnode->v_type & VREG)
|
||||
#define VN_ISDIR(vp) ((vp)->v_vnode->v_type & VDIR)
|
||||
#define VN_ISCHR(vp) ((vp)->v_vnode->v_type & VCHR)
|
||||
#define VN_ISBLK(vp) ((vp)->v_vnode->v_type & VBLK)
|
||||
#define VN_BAD(vp) ((vp)->v_vnode->v_type & VBAD)
|
||||
|
||||
#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)
|
||||
|
||||
/*
|
||||
* 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, u_long, void *);
|
||||
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 *, 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, accmode, cr, rv) \
|
||||
rv = _VOP_(vop_access, vp)((vp)->v_fbhv, accmode, 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, strictly a CXFS thing */
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
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_vnode->v_type == VREG && ((mode) & (S_ISGID|(VEXEC>>3))) == S_ISGID)
|
||||
|
||||
extern void vn_init(void);
|
||||
extern int vn_wait(struct xfs_vnode *);
|
||||
extern void vn_iowait(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;
|
||||
|
||||
#if 1
|
||||
#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); \
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void vn_purge(struct xfs_vnode *);
|
||||
extern xfs_vnode_t *vn_get(struct xfs_vnode *, vmap_t *);
|
||||
extern int vn_revalidate(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 */
|
||||
#define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */
|
||||
#define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
|
||||
static inline struct xfs_vnode *vn_grab(struct xfs_vnode *vp)
|
||||
{
|
||||
printf("vn_grab NI\n");
|
||||
// struct inode *inode = igrab(vn_to_inode(vp));
|
||||
// return inode ? vn_from_inode(inode) : NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void vn_atime_to_bstime(struct xfs_vnode *vp, xfs_bstime_t *bs_atime)
|
||||
{
|
||||
printf("%s NI\n", __func__);
|
||||
// bs_atime->tv_sec = vp->v_inode.i_atime.tv_sec;
|
||||
// bs_atime->tv_nsec = vp->v_inode.i_atime.tv_nsec;
|
||||
}
|
||||
|
||||
static inline void vn_atime_to_timespec(struct xfs_vnode *vp, struct timespec *ts)
|
||||
{
|
||||
// *ts = vp->v_vnode->va_atime;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_H__
|
||||
#define __XFS_H__
|
||||
|
||||
#include <xfs_freebsd.h>
|
||||
#endif /* __XFS_H__ */
|
@ -1,928 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_types.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_inum.h"
|
||||
#include "xfs_ag.h"
|
||||
#include "xfs_dir.h"
|
||||
#include "xfs_dir2.h"
|
||||
#include "xfs_bmap_btree.h"
|
||||
#include "xfs_alloc_btree.h"
|
||||
#include "xfs_ialloc_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_acl.h"
|
||||
#include "xfs_mac.h"
|
||||
#include "xfs_attr.h"
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
|
||||
STATIC int xfs_acl_setmode(xfs_vnode_t *, xfs_acl_t *, int *);
|
||||
STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *);
|
||||
STATIC void xfs_acl_get_endian(xfs_acl_t *);
|
||||
STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
|
||||
STATIC int xfs_acl_invalid(xfs_acl_t *);
|
||||
STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *);
|
||||
STATIC void xfs_acl_get_attr(xfs_vnode_t *, xfs_acl_t *, int, int, int *);
|
||||
STATIC void xfs_acl_set_attr(xfs_vnode_t *, xfs_acl_t *, int, int *);
|
||||
STATIC int xfs_acl_allow_set(xfs_vnode_t *, int);
|
||||
|
||||
kmem_zone_t *xfs_acl_zone;
|
||||
|
||||
|
||||
/*
|
||||
* Test for existence of access ACL attribute as efficiently as possible.
|
||||
*/
|
||||
int
|
||||
xfs_acl_vhasacl_access(
|
||||
xfs_vnode_t *vp)
|
||||
{
|
||||
int error;
|
||||
|
||||
xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error);
|
||||
return (error == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for existence of default ACL attribute as efficiently as possible.
|
||||
*/
|
||||
int
|
||||
xfs_acl_vhasacl_default(
|
||||
xfs_vnode_t *vp)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!VN_ISDIR(vp))
|
||||
return 0;
|
||||
xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
|
||||
return (error == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from extended attribute representation to in-memory for XFS.
|
||||
*/
|
||||
STATIC int
|
||||
posix_acl_xattr_to_xfs(
|
||||
posix_acl_xattr_header *src,
|
||||
size_t size,
|
||||
xfs_acl_t *dest)
|
||||
{
|
||||
posix_acl_xattr_entry *src_entry;
|
||||
xfs_acl_entry_t *dest_entry;
|
||||
int n;
|
||||
|
||||
if (!src || !dest)
|
||||
return EINVAL;
|
||||
|
||||
if (size < sizeof(posix_acl_xattr_header))
|
||||
return EINVAL;
|
||||
|
||||
if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
|
||||
return EOPNOTSUPP;
|
||||
|
||||
memset(dest, 0, sizeof(xfs_acl_t));
|
||||
dest->acl_cnt = posix_acl_xattr_count(size);
|
||||
if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES)
|
||||
return EINVAL;
|
||||
|
||||
/*
|
||||
* acl_set_file(3) may request that we set default ACLs with
|
||||
* zero length -- defend (gracefully) against that here.
|
||||
*/
|
||||
if (!dest->acl_cnt)
|
||||
return 0;
|
||||
|
||||
src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src));
|
||||
dest_entry = &dest->acl_entry[0];
|
||||
|
||||
for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) {
|
||||
dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm);
|
||||
if (_ACL_PERM_INVALID(dest_entry->ae_perm))
|
||||
return EINVAL;
|
||||
dest_entry->ae_tag = le16_to_cpu(src_entry->e_tag);
|
||||
switch(dest_entry->ae_tag) {
|
||||
case ACL_USER:
|
||||
case ACL_GROUP:
|
||||
dest_entry->ae_id = le32_to_cpu(src_entry->e_id);
|
||||
break;
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
dest_entry->ae_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
if (xfs_acl_invalid(dest))
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison function called from xfs_sort().
|
||||
* Primary key is ae_tag, secondary key is ae_id.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_acl_entry_compare(
|
||||
const void *va,
|
||||
const void *vb)
|
||||
{
|
||||
xfs_acl_entry_t *a = (xfs_acl_entry_t *)va,
|
||||
*b = (xfs_acl_entry_t *)vb;
|
||||
|
||||
if (a->ae_tag == b->ae_tag)
|
||||
return (a->ae_id - b->ae_id);
|
||||
return (a->ae_tag - b->ae_tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from in-memory XFS to extended attribute representation.
|
||||
*/
|
||||
STATIC int
|
||||
posix_acl_xfs_to_xattr(
|
||||
xfs_acl_t *src,
|
||||
posix_acl_xattr_header *dest,
|
||||
size_t size)
|
||||
{
|
||||
int n;
|
||||
size_t new_size = posix_acl_xattr_size(src->acl_cnt);
|
||||
posix_acl_xattr_entry *dest_entry;
|
||||
xfs_acl_entry_t *src_entry;
|
||||
|
||||
if (size < new_size)
|
||||
return -ERANGE;
|
||||
|
||||
/* Need to sort src XFS ACL by <ae_tag,ae_id> */
|
||||
xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]),
|
||||
xfs_acl_entry_compare);
|
||||
|
||||
dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
|
||||
dest_entry = &dest->a_entries[0];
|
||||
src_entry = &src->acl_entry[0];
|
||||
for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) {
|
||||
dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm);
|
||||
if (_ACL_PERM_INVALID(src_entry->ae_perm))
|
||||
return -EINVAL;
|
||||
dest_entry->e_tag = cpu_to_le16(src_entry->ae_tag);
|
||||
switch (src_entry->ae_tag) {
|
||||
case ACL_USER:
|
||||
case ACL_GROUP:
|
||||
dest_entry->e_id = cpu_to_le32(src_entry->ae_id);
|
||||
break;
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return new_size;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_acl_vget(
|
||||
xfs_vnode_t *vp,
|
||||
void *acl,
|
||||
size_t size,
|
||||
int kind)
|
||||
{
|
||||
int error;
|
||||
xfs_acl_t *xfs_acl = NULL;
|
||||
posix_acl_xattr_header *ext_acl = acl;
|
||||
int flags = 0;
|
||||
|
||||
VN_HOLD(vp);
|
||||
if(size) {
|
||||
if (!(_ACL_ALLOC(xfs_acl))) {
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memset(xfs_acl, 0, sizeof(xfs_acl_t));
|
||||
} else
|
||||
flags = ATTR_KERNOVAL;
|
||||
|
||||
xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (!size) {
|
||||
error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES);
|
||||
} else {
|
||||
if (xfs_acl_invalid(xfs_acl)) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (kind == _ACL_TYPE_ACCESS) {
|
||||
xfs_vattr_t va;
|
||||
|
||||
va.va_mask = XFS_AT_MODE;
|
||||
XVOP_GETATTR(vp, &va, 0, sys_cred, error);
|
||||
if (error)
|
||||
goto out;
|
||||
xfs_acl_sync_mode(va.va_mode, xfs_acl);
|
||||
}
|
||||
error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);
|
||||
}
|
||||
out:
|
||||
VN_RELE(vp);
|
||||
if(xfs_acl)
|
||||
_ACL_FREE(xfs_acl);
|
||||
return -error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_acl_vremove(
|
||||
xfs_vnode_t *vp,
|
||||
int kind)
|
||||
{
|
||||
int error;
|
||||
|
||||
VN_HOLD(vp);
|
||||
error = xfs_acl_allow_set(vp, kind);
|
||||
if (!error) {
|
||||
XVOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT?
|
||||
SGI_ACL_DEFAULT: SGI_ACL_FILE,
|
||||
ATTR_ROOT, sys_cred, error);
|
||||
if (error == ENOATTR)
|
||||
error = 0; /* 'scool */
|
||||
}
|
||||
VN_RELE(vp);
|
||||
return -error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_acl_vset(
|
||||
xfs_vnode_t *vp,
|
||||
void *acl,
|
||||
size_t size,
|
||||
int kind)
|
||||
{
|
||||
posix_acl_xattr_header *ext_acl = acl;
|
||||
xfs_acl_t *xfs_acl;
|
||||
int error;
|
||||
int basicperms = 0; /* more than std unix perms? */
|
||||
|
||||
if (!acl)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(_ACL_ALLOC(xfs_acl)))
|
||||
return -ENOMEM;
|
||||
|
||||
error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl);
|
||||
if (error) {
|
||||
_ACL_FREE(xfs_acl);
|
||||
return -error;
|
||||
}
|
||||
if (!xfs_acl->acl_cnt) {
|
||||
_ACL_FREE(xfs_acl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VN_HOLD(vp);
|
||||
error = xfs_acl_allow_set(vp, kind);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* Incoming ACL exists, set file mode based on its value */
|
||||
if (kind == _ACL_TYPE_ACCESS)
|
||||
xfs_acl_setmode(vp, xfs_acl, &basicperms);
|
||||
|
||||
/*
|
||||
* If we have more than std unix permissions, set up the actual attr.
|
||||
* Otherwise, delete any existing attr. This prevents us from
|
||||
* having actual attrs for permissions that can be stored in the
|
||||
* standard permission bits.
|
||||
*/
|
||||
if (!basicperms) {
|
||||
xfs_acl_set_attr(vp, xfs_acl, kind, &error);
|
||||
} else {
|
||||
xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
|
||||
}
|
||||
|
||||
out:
|
||||
VN_RELE(vp);
|
||||
_ACL_FREE(xfs_acl);
|
||||
return -error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_acl_iaccess(
|
||||
xfs_inode_t *ip,
|
||||
mode_t mode,
|
||||
cred_t *cr)
|
||||
{
|
||||
xfs_acl_t *acl;
|
||||
int rval;
|
||||
|
||||
if (!(_ACL_ALLOC(acl)))
|
||||
return -1;
|
||||
|
||||
/* If the file has no ACL return -1. */
|
||||
rval = sizeof(xfs_acl_t);
|
||||
if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE,
|
||||
(char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) {
|
||||
_ACL_FREE(acl);
|
||||
return -1;
|
||||
}
|
||||
xfs_acl_get_endian(acl);
|
||||
|
||||
/* If the file has an empty ACL return -1. */
|
||||
if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) {
|
||||
_ACL_FREE(acl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Synchronize ACL with mode bits */
|
||||
xfs_acl_sync_mode(ip->i_d.di_mode, acl);
|
||||
|
||||
rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
|
||||
_ACL_FREE(acl);
|
||||
return rval;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_acl_allow_set(
|
||||
xfs_vnode_t *vp,
|
||||
int kind)
|
||||
{
|
||||
xfs_vattr_t va;
|
||||
int error;
|
||||
|
||||
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
|
||||
return EPERM;
|
||||
if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp))
|
||||
return ENOTDIR;
|
||||
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
|
||||
return EROFS;
|
||||
va.va_mask = XFS_AT_UID;
|
||||
XVOP_GETATTR(vp, &va, 0, NULL, error);
|
||||
if (error)
|
||||
return error;
|
||||
if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
|
||||
return EPERM;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* The access control process to determine the access permission:
|
||||
* if uid == file owner id, use the file owner bits.
|
||||
* if gid == file owner group id, use the file group bits.
|
||||
* scan ACL for a matching user or group, and use matched entry
|
||||
* permission. Use total permissions of all matching group entries,
|
||||
* until all acl entries are exhausted. The final permission produced
|
||||
* by matching acl entry or entries needs to be & with group permission.
|
||||
* if not owner, owning group, or matching entry in ACL, use file
|
||||
* other bits.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_acl_capability_check(
|
||||
mode_t mode,
|
||||
cred_t *cr)
|
||||
{
|
||||
if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH))
|
||||
return EACCES;
|
||||
if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
|
||||
return EACCES;
|
||||
if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
|
||||
return EACCES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: cr is only used here for the capability check if the ACL test fails.
|
||||
* It is not used to find out the credentials uid or groups etc, as was
|
||||
* done in IRIX. It is assumed that the uid and groups for the current
|
||||
* thread are taken from "current" instead of the cr parameter.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_acl_access(
|
||||
uid_t fuid,
|
||||
gid_t fgid,
|
||||
xfs_acl_t *fap,
|
||||
mode_t md,
|
||||
cred_t *cr)
|
||||
{
|
||||
xfs_acl_entry_t matched;
|
||||
int i, allows;
|
||||
int maskallows = -1; /* true, but not 1, either */
|
||||
int seen_userobj = 0;
|
||||
|
||||
matched.ae_tag = 0; /* Invalid type */
|
||||
matched.ae_perm = 0;
|
||||
md >>= 6; /* Normalize the bits for comparison */
|
||||
|
||||
for (i = 0; i < fap->acl_cnt; i++) {
|
||||
/*
|
||||
* Break out if we've got a user_obj entry or
|
||||
* a user entry and the mask (and have processed USER_OBJ)
|
||||
*/
|
||||
if (matched.ae_tag == ACL_USER_OBJ)
|
||||
break;
|
||||
if (matched.ae_tag == ACL_USER) {
|
||||
if (maskallows != -1 && seen_userobj)
|
||||
break;
|
||||
if (fap->acl_entry[i].ae_tag != ACL_MASK &&
|
||||
fap->acl_entry[i].ae_tag != ACL_USER_OBJ)
|
||||
continue;
|
||||
}
|
||||
/* True if this entry allows the requested access */
|
||||
allows = ((fap->acl_entry[i].ae_perm & md) == md);
|
||||
|
||||
switch (fap->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
seen_userobj = 1;
|
||||
if (fuid != current->fsuid)
|
||||
continue;
|
||||
matched.ae_tag = ACL_USER_OBJ;
|
||||
matched.ae_perm = allows;
|
||||
break;
|
||||
case ACL_USER:
|
||||
if (fap->acl_entry[i].ae_id != current->fsuid)
|
||||
continue;
|
||||
matched.ae_tag = ACL_USER;
|
||||
matched.ae_perm = allows;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
if ((matched.ae_tag == ACL_GROUP_OBJ ||
|
||||
matched.ae_tag == ACL_GROUP) && !allows)
|
||||
continue;
|
||||
if (!in_group_p(fgid))
|
||||
continue;
|
||||
matched.ae_tag = ACL_GROUP_OBJ;
|
||||
matched.ae_perm = allows;
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
if ((matched.ae_tag == ACL_GROUP_OBJ ||
|
||||
matched.ae_tag == ACL_GROUP) && !allows)
|
||||
continue;
|
||||
if (!in_group_p(fap->acl_entry[i].ae_id))
|
||||
continue;
|
||||
matched.ae_tag = ACL_GROUP;
|
||||
matched.ae_perm = allows;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
maskallows = allows;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
if (matched.ae_tag != 0)
|
||||
continue;
|
||||
matched.ae_tag = ACL_OTHER;
|
||||
matched.ae_perm = allows;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* First possibility is that no matched entry allows access.
|
||||
* The capability to override DAC may exist, so check for it.
|
||||
*/
|
||||
switch (matched.ae_tag) {
|
||||
case ACL_OTHER:
|
||||
case ACL_USER_OBJ:
|
||||
if (matched.ae_perm)
|
||||
return 0;
|
||||
break;
|
||||
case ACL_USER:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_GROUP:
|
||||
if (maskallows && matched.ae_perm)
|
||||
return 0;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
|
||||
return xfs_acl_capability_check(md, cr);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACL validity checker.
|
||||
* This acl validation routine checks each ACL entry read in makes sense.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_acl_invalid(
|
||||
xfs_acl_t *aclp)
|
||||
{
|
||||
xfs_acl_entry_t *entry, *e;
|
||||
int user = 0, group = 0, other = 0, mask = 0;
|
||||
int mask_required = 0;
|
||||
int i, j;
|
||||
|
||||
if (!aclp)
|
||||
goto acl_invalid;
|
||||
|
||||
if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
|
||||
goto acl_invalid;
|
||||
|
||||
for (i = 0; i < aclp->acl_cnt; i++) {
|
||||
entry = &aclp->acl_entry[i];
|
||||
switch (entry->ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
if (user++)
|
||||
goto acl_invalid;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
if (group++)
|
||||
goto acl_invalid;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
if (other++)
|
||||
goto acl_invalid;
|
||||
break;
|
||||
case ACL_USER:
|
||||
case ACL_GROUP:
|
||||
for (j = i + 1; j < aclp->acl_cnt; j++) {
|
||||
e = &aclp->acl_entry[j];
|
||||
if (e->ae_id == entry->ae_id &&
|
||||
e->ae_tag == entry->ae_tag)
|
||||
goto acl_invalid;
|
||||
}
|
||||
mask_required++;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
if (mask++)
|
||||
goto acl_invalid;
|
||||
break;
|
||||
default:
|
||||
goto acl_invalid;
|
||||
}
|
||||
}
|
||||
if (!user || !group || !other || (mask_required && !mask))
|
||||
goto acl_invalid;
|
||||
else
|
||||
return 0;
|
||||
acl_invalid:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do ACL endian conversion.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_acl_get_endian(
|
||||
xfs_acl_t *aclp)
|
||||
{
|
||||
xfs_acl_entry_t *ace, *end;
|
||||
|
||||
INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
|
||||
end = &aclp->acl_entry[0]+aclp->acl_cnt;
|
||||
for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
|
||||
INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
|
||||
INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
|
||||
INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the ACL from the EA and do endian conversion.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_acl_get_attr(
|
||||
xfs_vnode_t *vp,
|
||||
xfs_acl_t *aclp,
|
||||
int kind,
|
||||
int flags,
|
||||
int *error)
|
||||
{
|
||||
int len = sizeof(xfs_acl_t);
|
||||
|
||||
ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
|
||||
flags |= ATTR_ROOT;
|
||||
XVOP_ATTR_GET(vp,
|
||||
kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT,
|
||||
(char *)aclp, &len, flags, sys_cred, *error);
|
||||
if (*error || (flags & ATTR_KERNOVAL))
|
||||
return;
|
||||
xfs_acl_get_endian(aclp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the EA with the ACL and do endian conversion.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_acl_set_attr(
|
||||
xfs_vnode_t *vp,
|
||||
xfs_acl_t *aclp,
|
||||
int kind,
|
||||
int *error)
|
||||
{
|
||||
xfs_acl_entry_t *ace, *newace, *end;
|
||||
xfs_acl_t *newacl;
|
||||
int len;
|
||||
|
||||
if (!(_ACL_ALLOC(newacl))) {
|
||||
*error = ENOMEM;
|
||||
return;
|
||||
}
|
||||
|
||||
len = sizeof(xfs_acl_t) -
|
||||
(sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt));
|
||||
end = &aclp->acl_entry[0]+aclp->acl_cnt;
|
||||
for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0];
|
||||
ace < end;
|
||||
ace++, newace++) {
|
||||
INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag);
|
||||
INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id);
|
||||
INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
|
||||
}
|
||||
INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
|
||||
XVOP_ATTR_SET(vp,
|
||||
kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT,
|
||||
(char *)newacl, len, ATTR_ROOT, sys_cred, *error);
|
||||
_ACL_FREE(newacl);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_acl_vtoacl(
|
||||
xfs_vnode_t *vp,
|
||||
xfs_acl_t *access_acl,
|
||||
xfs_acl_t *default_acl)
|
||||
{
|
||||
xfs_vattr_t va;
|
||||
int error = 0;
|
||||
|
||||
if (access_acl) {
|
||||
/*
|
||||
* Get the Access ACL and the mode. If either cannot
|
||||
* be obtained for some reason, invalidate the access ACL.
|
||||
*/
|
||||
xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error);
|
||||
if (!error) {
|
||||
/* Got the ACL, need the mode... */
|
||||
va.va_mask = XFS_AT_MODE;
|
||||
XVOP_GETATTR(vp, &va, 0, sys_cred, error);
|
||||
}
|
||||
|
||||
if (error)
|
||||
access_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
|
||||
else /* We have a good ACL and the file mode, synchronize. */
|
||||
xfs_acl_sync_mode(va.va_mode, access_acl);
|
||||
}
|
||||
|
||||
if (default_acl) {
|
||||
xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error);
|
||||
if (error)
|
||||
default_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function retrieves the parent directory's acl, processes it
|
||||
* and lets the child inherit the acl(s) that it should.
|
||||
*/
|
||||
int
|
||||
xfs_acl_inherit(
|
||||
xfs_vnode_t *vp,
|
||||
xfs_vattr_t *vap,
|
||||
xfs_acl_t *pdaclp)
|
||||
{
|
||||
xfs_acl_t *cacl;
|
||||
int error = 0;
|
||||
int basicperms = 0;
|
||||
|
||||
/*
|
||||
* If the parent does not have a default ACL, or it's an
|
||||
* invalid ACL, we're done.
|
||||
*/
|
||||
if (!vp)
|
||||
return 0;
|
||||
if (!pdaclp || xfs_acl_invalid(pdaclp))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Copy the default ACL of the containing directory to
|
||||
* the access ACL of the new file and use the mode that
|
||||
* was passed in to set up the correct initial values for
|
||||
* the u::,g::[m::], and o:: entries. This is what makes
|
||||
* umask() "work" with ACL's.
|
||||
*/
|
||||
|
||||
if (!(_ACL_ALLOC(cacl)))
|
||||
return ENOMEM;
|
||||
|
||||
memcpy(cacl, pdaclp, sizeof(xfs_acl_t));
|
||||
xfs_acl_filter_mode(vap->va_mode, cacl);
|
||||
xfs_acl_setmode(vp, cacl, &basicperms);
|
||||
|
||||
/*
|
||||
* Set the Default and Access ACL on the file. The mode is already
|
||||
* set on the file, so we don't need to worry about that.
|
||||
*
|
||||
* If the new file is a directory, its default ACL is a copy of
|
||||
* the containing directory's default ACL.
|
||||
*/
|
||||
if (VN_ISDIR(vp))
|
||||
xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
|
||||
if (!error && !basicperms)
|
||||
xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
|
||||
_ACL_FREE(cacl);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the correct mode on the file based on the supplied ACL. This
|
||||
* makes sure that the mode on the file reflects the state of the
|
||||
* u::,g::[m::], and o:: entries in the ACL. Since the mode is where
|
||||
* the ACL is going to get the permissions for these entries, we must
|
||||
* synchronize the mode whenever we set the ACL on a file.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_acl_setmode(
|
||||
xfs_vnode_t *vp,
|
||||
xfs_acl_t *acl,
|
||||
int *basicperms)
|
||||
{
|
||||
xfs_vattr_t va;
|
||||
xfs_acl_entry_t *ap;
|
||||
xfs_acl_entry_t *gap = NULL;
|
||||
int i, error, nomask = 1;
|
||||
|
||||
*basicperms = 1;
|
||||
|
||||
if (acl->acl_cnt == XFS_ACL_NOT_PRESENT)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Copy the u::, g::, o::, and m:: bits from the ACL into the
|
||||
* mode. The m:: bits take precedence over the g:: bits.
|
||||
*/
|
||||
va.va_mask = XFS_AT_MODE;
|
||||
XVOP_GETATTR(vp, &va, 0, sys_cred, error);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
va.va_mask = XFS_AT_MODE;
|
||||
va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
ap = acl->acl_entry;
|
||||
for (i = 0; i < acl->acl_cnt; ++i) {
|
||||
switch (ap->ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
va.va_mode |= ap->ae_perm << 6;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
gap = ap;
|
||||
break;
|
||||
case ACL_MASK: /* more than just standard modes */
|
||||
nomask = 0;
|
||||
va.va_mode |= ap->ae_perm << 3;
|
||||
*basicperms = 0;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
va.va_mode |= ap->ae_perm;
|
||||
break;
|
||||
default: /* more than just standard modes */
|
||||
*basicperms = 0;
|
||||
break;
|
||||
}
|
||||
ap++;
|
||||
}
|
||||
|
||||
/* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
|
||||
if (gap && nomask)
|
||||
va.va_mode |= gap->ae_perm << 3;
|
||||
|
||||
XVOP_SETATTR(vp, &va, 0, sys_cred, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* The permissions for the special ACL entries (u::, g::[m::], o::) are
|
||||
* actually stored in the file mode (if there is both a group and a mask,
|
||||
* the group is stored in the ACL entry and the mask is stored on the file).
|
||||
* This allows the mode to remain automatically in sync with the ACL without
|
||||
* the need for a call-back to the ACL system at every point where the mode
|
||||
* could change. This function takes the permissions from the specified mode
|
||||
* and places it in the supplied ACL.
|
||||
*
|
||||
* This implementation draws its validity from the fact that, when the ACL
|
||||
* was assigned, the mode was copied from the ACL.
|
||||
* If the mode did not change, therefore, the mode remains exactly what was
|
||||
* taken from the special ACL entries at assignment.
|
||||
* If a subsequent chmod() was done, the POSIX spec says that the change in
|
||||
* mode must cause an update to the ACL seen at user level and used for
|
||||
* access checks. Before and after a mode change, therefore, the file mode
|
||||
* most accurately reflects what the special ACL entries should permit/deny.
|
||||
*
|
||||
* CAVEAT: If someone sets the SGI_ACL_FILE attribute directly,
|
||||
* the existing mode bits will override whatever is in the
|
||||
* ACL. Similarly, if there is a pre-existing ACL that was
|
||||
* never in sync with its mode (owing to a bug in 6.5 and
|
||||
* before), it will now magically (or mystically) be
|
||||
* synchronized. This could cause slight astonishment, but
|
||||
* it is better than inconsistent permissions.
|
||||
*
|
||||
* The supplied ACL is a template that may contain any combination
|
||||
* of special entries. These are treated as place holders when we fill
|
||||
* out the ACL. This routine does not add or remove special entries, it
|
||||
* simply unites each special entry with its associated set of permissions.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_acl_sync_mode(
|
||||
mode_t mode,
|
||||
xfs_acl_t *acl)
|
||||
{
|
||||
int i, nomask = 1;
|
||||
xfs_acl_entry_t *ap;
|
||||
xfs_acl_entry_t *gap = NULL;
|
||||
|
||||
/*
|
||||
* Set ACL entries. POSIX1003.1eD16 requires that the MASK
|
||||
* be set instead of the GROUP entry, if there is a MASK.
|
||||
*/
|
||||
for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
|
||||
switch (ap->ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
ap->ae_perm = (mode >> 6) & 0x7;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
gap = ap;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
nomask = 0;
|
||||
ap->ae_perm = (mode >> 3) & 0x7;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
ap->ae_perm = mode & 0x7;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
|
||||
if (gap && nomask)
|
||||
gap->ae_perm = (mode >> 3) & 0x7;
|
||||
}
|
||||
|
||||
/*
|
||||
* When inheriting an Access ACL from a directory Default ACL,
|
||||
* the ACL bits are set to the intersection of the ACL default
|
||||
* permission bits and the file permission bits in mode. If there
|
||||
* are no permission bits on the file then we must not give them
|
||||
* the ACL. This is what what makes umask() work with ACLs.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_acl_filter_mode(
|
||||
mode_t mode,
|
||||
xfs_acl_t *acl)
|
||||
{
|
||||
int i, nomask = 1;
|
||||
xfs_acl_entry_t *ap;
|
||||
xfs_acl_entry_t *gap = NULL;
|
||||
|
||||
/*
|
||||
* Set ACL entries. POSIX1003.1eD16 requires that the MASK
|
||||
* be merged with GROUP entry, if there is a MASK.
|
||||
*/
|
||||
for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
|
||||
switch (ap->ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
ap->ae_perm &= (mode >> 6) & 0x7;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
gap = ap;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
nomask = 0;
|
||||
ap->ae_perm &= (mode >> 3) & 0x7;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
ap->ae_perm &= mode & 0x7;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
|
||||
if (gap && nomask)
|
||||
gap->ae_perm &= (mode >> 3) & 0x7;
|
||||
}
|
||||
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ACL_H__
|
||||
#define __XFS_ACL_H__
|
||||
|
||||
/*
|
||||
* Access Control Lists
|
||||
*/
|
||||
typedef __uint16_t xfs_acl_perm_t;
|
||||
typedef __int32_t xfs_acl_type_t;
|
||||
typedef __int32_t xfs_acl_tag_t;
|
||||
typedef __int32_t xfs_acl_id_t;
|
||||
|
||||
#define XFS_ACL_MAX_ENTRIES 25
|
||||
#define XFS_ACL_NOT_PRESENT (-1)
|
||||
|
||||
typedef struct xfs_acl_entry {
|
||||
xfs_acl_tag_t ae_tag;
|
||||
xfs_acl_id_t ae_id;
|
||||
xfs_acl_perm_t ae_perm;
|
||||
} xfs_acl_entry_t;
|
||||
|
||||
typedef struct xfs_acl {
|
||||
__int32_t acl_cnt;
|
||||
xfs_acl_entry_t acl_entry[XFS_ACL_MAX_ENTRIES];
|
||||
} xfs_acl_t;
|
||||
|
||||
/* On-disk XFS extended attribute names */
|
||||
#define SGI_ACL_FILE "SGI_ACL_FILE"
|
||||
#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT"
|
||||
#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1)
|
||||
#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1)
|
||||
|
||||
|
||||
#ifdef CONFIG_XFS_POSIX_ACL
|
||||
|
||||
struct vattr;
|
||||
struct vnode;
|
||||
struct xfs_inode;
|
||||
|
||||
extern struct kmem_zone *xfs_acl_zone;
|
||||
#define xfs_acl_zone_init(zone, name) \
|
||||
(zone) = kmem_zone_init(sizeof(xfs_acl_t), (name))
|
||||
#define xfs_acl_zone_destroy(zone) kmem_zone_destroy(zone)
|
||||
|
||||
extern int xfs_acl_inherit(struct vnode *, struct vattr *, xfs_acl_t *);
|
||||
extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
|
||||
extern int xfs_acl_vtoacl(struct vnode *, xfs_acl_t *, xfs_acl_t *);
|
||||
extern int xfs_acl_vhasacl_access(struct vnode *);
|
||||
extern int xfs_acl_vhasacl_default(struct vnode *);
|
||||
extern int xfs_acl_vset(struct vnode *, void *, size_t, int);
|
||||
extern int xfs_acl_vget(struct vnode *, void *, size_t, int);
|
||||
extern int xfs_acl_vremove(struct vnode *vp, int);
|
||||
|
||||
#define _ACL_TYPE_ACCESS 1
|
||||
#define _ACL_TYPE_DEFAULT 2
|
||||
#define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
|
||||
|
||||
#define _ACL_INHERIT(c,v,d) (xfs_acl_inherit(c,v,d))
|
||||
#define _ACL_GET_ACCESS(pv,pa) (xfs_acl_vtoacl(pv,pa,NULL) == 0)
|
||||
#define _ACL_GET_DEFAULT(pv,pd) (xfs_acl_vtoacl(pv,NULL,pd) == 0)
|
||||
#define _ACL_ACCESS_EXISTS xfs_acl_vhasacl_access
|
||||
#define _ACL_DEFAULT_EXISTS xfs_acl_vhasacl_default
|
||||
#define _ACL_XFS_IACCESS(i,m,c) (XFS_IFORK_Q(i) ? xfs_acl_iaccess(i,m,c) : -1)
|
||||
|
||||
#define _ACL_ALLOC(a) ((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP))
|
||||
#define _ACL_FREE(a) ((a)? kmem_zone_free(xfs_acl_zone, (a)):(void)0)
|
||||
|
||||
#else
|
||||
#define xfs_acl_zone_init(zone,name)
|
||||
#define xfs_acl_zone_destroy(zone)
|
||||
#define xfs_acl_vset(v,p,sz,t) (-EOPNOTSUPP)
|
||||
#define xfs_acl_vget(v,p,sz,t) (-EOPNOTSUPP)
|
||||
#define xfs_acl_vremove(v,t) (-EOPNOTSUPP)
|
||||
#define xfs_acl_vhasacl_access(v) (0)
|
||||
#define xfs_acl_vhasacl_default(v) (0)
|
||||
#define _ACL_ALLOC(a) (1) /* successfully allocate nothing */
|
||||
#define _ACL_FREE(a) ((void)0)
|
||||
#define _ACL_INHERIT(c,v,d) (0)
|
||||
#define _ACL_GET_ACCESS(pv,pa) (0)
|
||||
#define _ACL_GET_DEFAULT(pv,pd) (0)
|
||||
#define _ACL_ACCESS_EXISTS (NULL)
|
||||
#define _ACL_DEFAULT_EXISTS (NULL)
|
||||
#define _ACL_XFS_IACCESS(i,m,c) (-1)
|
||||
#endif
|
||||
|
||||
#endif /* __XFS_ACL_H__ */
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_AG_H__
|
||||
#define __XFS_AG_H__
|
||||
|
||||
/*
|
||||
* Allocation group header
|
||||
* This is divided into three structures, placed in sequential 512-byte
|
||||
* buffers after a copy of the superblock (also in a 512-byte buffer).
|
||||
*/
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
|
||||
#define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */
|
||||
#define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */
|
||||
#define XFS_AGF_VERSION 1
|
||||
#define XFS_AGI_VERSION 1
|
||||
|
||||
#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION)
|
||||
#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION)
|
||||
|
||||
/*
|
||||
* Btree number 0 is bno, 1 is cnt. This value gives the size of the
|
||||
* arrays below.
|
||||
*/
|
||||
#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1)
|
||||
|
||||
/*
|
||||
* The second word of agf_levels in the first a.g. overlaps the EFS
|
||||
* superblock's magic number. Since the magic numbers valid for EFS
|
||||
* are > 64k, our value cannot be confused for an EFS superblock's.
|
||||
*/
|
||||
|
||||
typedef struct xfs_agf {
|
||||
/*
|
||||
* Common allocation group header information
|
||||
*/
|
||||
__be32 agf_magicnum; /* magic number == XFS_AGF_MAGIC */
|
||||
__be32 agf_versionnum; /* header version == XFS_AGF_VERSION */
|
||||
__be32 agf_seqno; /* sequence # starting from 0 */
|
||||
__be32 agf_length; /* size in blocks of a.g. */
|
||||
/*
|
||||
* Freespace information
|
||||
*/
|
||||
__be32 agf_roots[XFS_BTNUM_AGF]; /* root blocks */
|
||||
__be32 agf_spare0; /* spare field */
|
||||
__be32 agf_levels[XFS_BTNUM_AGF]; /* btree levels */
|
||||
__be32 agf_spare1; /* spare field */
|
||||
__be32 agf_flfirst; /* first freelist block's index */
|
||||
__be32 agf_fllast; /* last freelist block's index */
|
||||
__be32 agf_flcount; /* count of blocks in freelist */
|
||||
__be32 agf_freeblks; /* total free blocks */
|
||||
__be32 agf_longest; /* longest free space */
|
||||
} xfs_agf_t;
|
||||
|
||||
#define XFS_AGF_MAGICNUM 0x00000001
|
||||
#define XFS_AGF_VERSIONNUM 0x00000002
|
||||
#define XFS_AGF_SEQNO 0x00000004
|
||||
#define XFS_AGF_LENGTH 0x00000008
|
||||
#define XFS_AGF_ROOTS 0x00000010
|
||||
#define XFS_AGF_LEVELS 0x00000020
|
||||
#define XFS_AGF_FLFIRST 0x00000040
|
||||
#define XFS_AGF_FLLAST 0x00000080
|
||||
#define XFS_AGF_FLCOUNT 0x00000100
|
||||
#define XFS_AGF_FREEBLKS 0x00000200
|
||||
#define XFS_AGF_LONGEST 0x00000400
|
||||
#define XFS_AGF_NUM_BITS 11
|
||||
#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
|
||||
|
||||
/* disk block (xfs_daddr_t) in the AG */
|
||||
#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
|
||||
#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
|
||||
#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
|
||||
/*
|
||||
* Size of the unlinked inode hash table in the agi.
|
||||
*/
|
||||
#define XFS_AGI_UNLINKED_BUCKETS 64
|
||||
|
||||
typedef struct xfs_agi {
|
||||
/*
|
||||
* Common allocation group header information
|
||||
*/
|
||||
__be32 agi_magicnum; /* magic number == XFS_AGI_MAGIC */
|
||||
__be32 agi_versionnum; /* header version == XFS_AGI_VERSION */
|
||||
__be32 agi_seqno; /* sequence # starting from 0 */
|
||||
__be32 agi_length; /* size in blocks of a.g. */
|
||||
/*
|
||||
* Inode information
|
||||
* Inodes are mapped by interpreting the inode number, so no
|
||||
* mapping data is needed here.
|
||||
*/
|
||||
__be32 agi_count; /* count of allocated inodes */
|
||||
__be32 agi_root; /* root of inode btree */
|
||||
__be32 agi_level; /* levels in inode btree */
|
||||
__be32 agi_freecount; /* number of free inodes */
|
||||
__be32 agi_newino; /* new inode just allocated */
|
||||
__be32 agi_dirino; /* last directory inode chunk */
|
||||
/*
|
||||
* Hash table of inodes which have been unlinked but are
|
||||
* still being referenced.
|
||||
*/
|
||||
__be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
|
||||
} xfs_agi_t;
|
||||
|
||||
#define XFS_AGI_MAGICNUM 0x00000001
|
||||
#define XFS_AGI_VERSIONNUM 0x00000002
|
||||
#define XFS_AGI_SEQNO 0x00000004
|
||||
#define XFS_AGI_LENGTH 0x00000008
|
||||
#define XFS_AGI_COUNT 0x00000010
|
||||
#define XFS_AGI_ROOT 0x00000020
|
||||
#define XFS_AGI_LEVEL 0x00000040
|
||||
#define XFS_AGI_FREECOUNT 0x00000080
|
||||
#define XFS_AGI_NEWINO 0x00000100
|
||||
#define XFS_AGI_DIRINO 0x00000200
|
||||
#define XFS_AGI_UNLINKED 0x00000400
|
||||
#define XFS_AGI_NUM_BITS 11
|
||||
#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1)
|
||||
|
||||
/* disk block (xfs_daddr_t) in the AG */
|
||||
#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
|
||||
#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
|
||||
#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
/*
|
||||
* The third a.g. block contains the a.g. freelist, an array
|
||||
* of block pointers to blocks owned by the allocation btree code.
|
||||
*/
|
||||
#define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
|
||||
#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
|
||||
#define XFS_AGFL_SIZE(mp) ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
|
||||
#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
typedef struct xfs_agfl {
|
||||
xfs_agblock_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
|
||||
} xfs_agfl_t;
|
||||
|
||||
/*
|
||||
* Busy block/extent entry. Used in perag to mark blocks that have been freed
|
||||
* but whose transactions aren't committed to disk yet.
|
||||
*/
|
||||
typedef struct xfs_perag_busy {
|
||||
xfs_agblock_t busy_start;
|
||||
xfs_extlen_t busy_length;
|
||||
struct xfs_trans *busy_tp; /* transaction that did the free */
|
||||
} xfs_perag_busy_t;
|
||||
|
||||
/*
|
||||
* Per-ag incore structure, copies of information in agf and agi,
|
||||
* to improve the performance of allocation group selection.
|
||||
*
|
||||
* pick sizes which fit in allocation buckets well
|
||||
*/
|
||||
#if (BITS_PER_LONG == 32)
|
||||
#define XFS_PAGB_NUM_SLOTS 84
|
||||
#elif (BITS_PER_LONG == 64)
|
||||
#define XFS_PAGB_NUM_SLOTS 128
|
||||
#endif
|
||||
|
||||
typedef struct xfs_perag
|
||||
{
|
||||
char pagf_init; /* this agf's entry is initialized */
|
||||
char pagi_init; /* this agi's entry is initialized */
|
||||
char pagf_metadata; /* the agf is preferred to be metadata */
|
||||
char pagi_inodeok; /* The agi is ok for inodes */
|
||||
__uint8_t pagf_levels[XFS_BTNUM_AGF];
|
||||
/* # of levels in bno & cnt btree */
|
||||
__uint32_t pagf_flcount; /* count of blocks in freelist */
|
||||
xfs_extlen_t pagf_freeblks; /* total free blocks */
|
||||
xfs_extlen_t pagf_longest; /* longest free space */
|
||||
xfs_agino_t pagi_freecount; /* number of free inodes */
|
||||
#ifdef __KERNEL__
|
||||
lock_t pagb_lock; /* lock for pagb_list */
|
||||
#endif
|
||||
int pagb_count; /* pagb slots in use */
|
||||
xfs_perag_busy_t *pagb_list; /* unstable blocks */
|
||||
} xfs_perag_t;
|
||||
|
||||
#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
|
||||
#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \
|
||||
(MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + MIN(cl + 1, XFS_AG_MAXLEVELS(mp)))
|
||||
#define XFS_MIN_FREELIST(a,mp) \
|
||||
(XFS_MIN_FREELIST_RAW( \
|
||||
be32_to_cpu((a)->agf_levels[XFS_BTNUM_BNOi]), \
|
||||
be32_to_cpu((a)->agf_levels[XFS_BTNUM_CNTi]), mp))
|
||||
#define XFS_MIN_FREELIST_PAG(pag,mp) \
|
||||
(XFS_MIN_FREELIST_RAW( \
|
||||
(uint_t)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
|
||||
(uint_t)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
|
||||
|
||||
#define XFS_AGB_TO_FSB(mp,agno,agbno) \
|
||||
(((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno))
|
||||
#define XFS_FSB_TO_AGNO(mp,fsbno) \
|
||||
((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog))
|
||||
#define XFS_FSB_TO_AGBNO(mp,fsbno) \
|
||||
((xfs_agblock_t)((fsbno) & XFS_MASK32LO((mp)->m_sb.sb_agblklog)))
|
||||
#define XFS_AGB_TO_DADDR(mp,agno,agbno) \
|
||||
((xfs_daddr_t)XFS_FSB_TO_BB(mp, \
|
||||
(xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno)))
|
||||
#define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d))
|
||||
|
||||
/*
|
||||
* For checking for bad ranges of xfs_daddr_t's, covering multiple
|
||||
* allocation groups or a single xfs_daddr_t that's a superblock copy.
|
||||
*/
|
||||
#define XFS_AG_CHECK_DADDR(mp,d,len) \
|
||||
((len) == 1 ? \
|
||||
ASSERT((d) == XFS_SB_DADDR || \
|
||||
XFS_DADDR_TO_AGBNO(mp, d) != XFS_SB_DADDR) : \
|
||||
ASSERT(XFS_DADDR_TO_AGNO(mp, d) == \
|
||||
XFS_DADDR_TO_AGNO(mp, (d) + (len) - 1)))
|
||||
|
||||
#endif /* __XFS_AG_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ALLOC_H__
|
||||
#define __XFS_ALLOC_H__
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_mount;
|
||||
struct xfs_perag;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* Freespace allocation types. Argument to xfs_alloc_[v]extent.
|
||||
*/
|
||||
typedef enum xfs_alloctype
|
||||
{
|
||||
XFS_ALLOCTYPE_ANY_AG, /* allocate anywhere, use rotor */
|
||||
XFS_ALLOCTYPE_FIRST_AG, /* ... start at ag 0 */
|
||||
XFS_ALLOCTYPE_START_AG, /* anywhere, start in this a.g. */
|
||||
XFS_ALLOCTYPE_THIS_AG, /* anywhere in this a.g. */
|
||||
XFS_ALLOCTYPE_START_BNO, /* near this block else anywhere */
|
||||
XFS_ALLOCTYPE_NEAR_BNO, /* in this a.g. and near this block */
|
||||
XFS_ALLOCTYPE_THIS_BNO /* at exactly this block */
|
||||
} xfs_alloctype_t;
|
||||
|
||||
/*
|
||||
* Flags for xfs_alloc_fix_freelist.
|
||||
*/
|
||||
#define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */
|
||||
|
||||
/*
|
||||
* Argument structure for xfs_alloc routines.
|
||||
* This is turned into a structure to avoid having 20 arguments passed
|
||||
* down several levels of the stack.
|
||||
*/
|
||||
typedef struct xfs_alloc_arg {
|
||||
struct xfs_trans *tp; /* transaction pointer */
|
||||
struct xfs_mount *mp; /* file system mount point */
|
||||
struct xfs_buf *agbp; /* buffer for a.g. freelist header */
|
||||
struct xfs_perag *pag; /* per-ag struct for this agno */
|
||||
xfs_fsblock_t fsbno; /* file system block number */
|
||||
xfs_agnumber_t agno; /* allocation group number */
|
||||
xfs_agblock_t agbno; /* allocation group-relative block # */
|
||||
xfs_extlen_t minlen; /* minimum size of extent */
|
||||
xfs_extlen_t maxlen; /* maximum size of extent */
|
||||
xfs_extlen_t mod; /* mod value for extent size */
|
||||
xfs_extlen_t prod; /* prod value for extent size */
|
||||
xfs_extlen_t minleft; /* min blocks must be left after us */
|
||||
xfs_extlen_t total; /* total blocks needed in xaction */
|
||||
xfs_extlen_t alignment; /* align answer to multiple of this */
|
||||
xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */
|
||||
xfs_extlen_t len; /* output: actual size of extent */
|
||||
xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */
|
||||
xfs_alloctype_t otype; /* original allocation type */
|
||||
char wasdel; /* set if allocation was prev delayed */
|
||||
char wasfromfl; /* set if allocation is from freelist */
|
||||
char isfl; /* set if is freelist blocks - !acctg */
|
||||
char userdata; /* set if this is user data */
|
||||
} xfs_alloc_arg_t;
|
||||
|
||||
/*
|
||||
* Defines for userdata
|
||||
*/
|
||||
#define XFS_ALLOC_USERDATA 1 /* allocation is for user data*/
|
||||
#define XFS_ALLOC_INITIAL_USER_DATA 2 /* special case start of file */
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#if defined(XFS_ALLOC_TRACE)
|
||||
/*
|
||||
* Allocation tracing buffer size.
|
||||
*/
|
||||
#define XFS_ALLOC_TRACE_SIZE 4096
|
||||
extern ktrace_t *xfs_alloc_trace_buf;
|
||||
|
||||
/*
|
||||
* Types for alloc tracing.
|
||||
*/
|
||||
#define XFS_ALLOC_KTRACE_ALLOC 1
|
||||
#define XFS_ALLOC_KTRACE_FREE 2
|
||||
#define XFS_ALLOC_KTRACE_MODAGF 3
|
||||
#define XFS_ALLOC_KTRACE_BUSY 4
|
||||
#define XFS_ALLOC_KTRACE_UNBUSY 5
|
||||
#define XFS_ALLOC_KTRACE_BUSYSEARCH 6
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compute and fill in value of m_ag_maxlevels.
|
||||
*/
|
||||
void
|
||||
xfs_alloc_compute_maxlevels(
|
||||
struct xfs_mount *mp); /* file system mount structure */
|
||||
|
||||
/*
|
||||
* Get a block from the freelist.
|
||||
* Returns with the buffer for the block gotten.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_alloc_get_freelist(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_buf *agbp, /* buffer containing the agf structure */
|
||||
xfs_agblock_t *bnop); /* block address retrieved from freelist */
|
||||
|
||||
/*
|
||||
* Log the given fields from the agf structure.
|
||||
*/
|
||||
void
|
||||
xfs_alloc_log_agf(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_buf *bp, /* buffer for a.g. freelist header */
|
||||
int fields);/* mask of fields to be logged (XFS_AGF_...) */
|
||||
|
||||
/*
|
||||
* Interface for inode allocation to force the pag data to be initialized.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_alloc_pagf_init(
|
||||
struct xfs_mount *mp, /* file system mount structure */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
int flags); /* XFS_ALLOC_FLAGS_... */
|
||||
|
||||
/*
|
||||
* Put the block on the freelist for the allocation group.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_alloc_put_freelist(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_buf *agbp, /* buffer for a.g. freelist header */
|
||||
struct xfs_buf *agflbp,/* buffer for a.g. free block array */
|
||||
xfs_agblock_t bno); /* block being freed */
|
||||
|
||||
/*
|
||||
* Read in the allocation group header (free/alloc section).
|
||||
*/
|
||||
int /* error */
|
||||
xfs_alloc_read_agf(
|
||||
struct xfs_mount *mp, /* mount point structure */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
int flags, /* XFS_ALLOC_FLAG_... */
|
||||
struct xfs_buf **bpp); /* buffer for the ag freelist header */
|
||||
|
||||
/*
|
||||
* Allocate an extent (variable-size).
|
||||
*/
|
||||
int /* error */
|
||||
xfs_alloc_vextent(
|
||||
xfs_alloc_arg_t *args); /* allocation argument structure */
|
||||
|
||||
/*
|
||||
* Free an extent.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_free_extent(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_fsblock_t bno, /* starting block number of extent */
|
||||
xfs_extlen_t len); /* length of extent */
|
||||
|
||||
void
|
||||
xfs_alloc_mark_busy(xfs_trans_t *tp,
|
||||
xfs_agnumber_t agno,
|
||||
xfs_agblock_t bno,
|
||||
xfs_extlen_t len);
|
||||
|
||||
void
|
||||
xfs_alloc_clear_busy(xfs_trans_t *tp,
|
||||
xfs_agnumber_t ag,
|
||||
int idx);
|
||||
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_ALLOC_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ALLOC_BTREE_H__
|
||||
#define __XFS_ALLOC_BTREE_H__
|
||||
|
||||
/*
|
||||
* Freespace on-disk structures
|
||||
*/
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_btree_cur;
|
||||
struct xfs_btree_sblock;
|
||||
struct xfs_mount;
|
||||
|
||||
/*
|
||||
* There are two on-disk btrees, one sorted by blockno and one sorted
|
||||
* by blockcount and blockno. All blocks look the same to make the code
|
||||
* simpler; if we have time later, we'll make the optimizations.
|
||||
*/
|
||||
#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */
|
||||
#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */
|
||||
|
||||
/*
|
||||
* Data record/key structure
|
||||
*/
|
||||
typedef struct xfs_alloc_rec {
|
||||
__be32 ar_startblock; /* starting block number */
|
||||
__be32 ar_blockcount; /* count of free blocks */
|
||||
} xfs_alloc_rec_t, xfs_alloc_key_t;
|
||||
|
||||
typedef struct xfs_alloc_rec_incore {
|
||||
xfs_agblock_t ar_startblock; /* starting block number */
|
||||
xfs_extlen_t ar_blockcount; /* count of free blocks */
|
||||
} xfs_alloc_rec_incore_t;
|
||||
|
||||
/* btree pointer type */
|
||||
typedef __be32 xfs_alloc_ptr_t;
|
||||
/* btree block header type */
|
||||
typedef struct xfs_btree_sblock xfs_alloc_block_t;
|
||||
|
||||
#define XFS_BUF_TO_ALLOC_BLOCK(bp) ((xfs_alloc_block_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
/*
|
||||
* Real block structures have a size equal to the disk block size.
|
||||
*/
|
||||
#define XFS_ALLOC_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog)
|
||||
#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) ((cur)->bc_mp->m_alloc_mxr[lev != 0])
|
||||
#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) ((cur)->bc_mp->m_alloc_mnr[lev != 0])
|
||||
|
||||
/*
|
||||
* Minimum and maximum blocksize and sectorsize.
|
||||
* The blocksize upper limit is pretty much arbitrary.
|
||||
* The sectorsize upper limit is due to sizeof(sb_sectsize).
|
||||
*/
|
||||
#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */
|
||||
#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */
|
||||
#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG)
|
||||
#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG)
|
||||
#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */
|
||||
#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */
|
||||
#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG)
|
||||
#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG)
|
||||
|
||||
/*
|
||||
* Block numbers in the AG:
|
||||
* SB is sector 0, AGF is sector 1, AGI is sector 2, AGFL is sector 3.
|
||||
*/
|
||||
#define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1))
|
||||
#define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1))
|
||||
|
||||
/*
|
||||
* Record, key, and pointer address macros for btree blocks.
|
||||
*/
|
||||
#define XFS_ALLOC_REC_ADDR(bb,i,cur) \
|
||||
XFS_BTREE_REC_ADDR(XFS_ALLOC_BLOCK_SIZE(0,cur), xfs_alloc, \
|
||||
bb, i, XFS_ALLOC_BLOCK_MAXRECS(0, cur))
|
||||
|
||||
#define XFS_ALLOC_KEY_ADDR(bb,i,cur) \
|
||||
XFS_BTREE_KEY_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, \
|
||||
bb, i, XFS_ALLOC_BLOCK_MAXRECS(1, cur))
|
||||
|
||||
#define XFS_ALLOC_PTR_ADDR(bb,i,cur) \
|
||||
XFS_BTREE_PTR_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, \
|
||||
bb, i, XFS_ALLOC_BLOCK_MAXRECS(1, cur))
|
||||
|
||||
/*
|
||||
* Decrement cursor by one record at the level.
|
||||
* For nonzero levels the leaf-ward information is untouched.
|
||||
*/
|
||||
extern int xfs_alloc_decrement(struct xfs_btree_cur *cur, int level, int *stat);
|
||||
|
||||
/*
|
||||
* Delete the record pointed to by cur.
|
||||
* The cursor refers to the place where the record was (could be inserted)
|
||||
* when the operation returns.
|
||||
*/
|
||||
extern int xfs_alloc_delete(struct xfs_btree_cur *cur, int *stat);
|
||||
|
||||
/*
|
||||
* Get the data from the pointed-to record.
|
||||
*/
|
||||
extern int xfs_alloc_get_rec(struct xfs_btree_cur *cur, xfs_agblock_t *bno,
|
||||
xfs_extlen_t *len, int *stat);
|
||||
|
||||
/*
|
||||
* Increment cursor by one record at the level.
|
||||
* For nonzero levels the leaf-ward information is untouched.
|
||||
*/
|
||||
extern int xfs_alloc_increment(struct xfs_btree_cur *cur, int level, int *stat);
|
||||
|
||||
/*
|
||||
* Insert the current record at the point referenced by cur.
|
||||
* The cursor may be inconsistent on return if splits have been done.
|
||||
*/
|
||||
extern int xfs_alloc_insert(struct xfs_btree_cur *cur, int *stat);
|
||||
|
||||
/*
|
||||
* Lookup the record equal to [bno, len] in the btree given by cur.
|
||||
*/
|
||||
extern int xfs_alloc_lookup_eq(struct xfs_btree_cur *cur, xfs_agblock_t bno,
|
||||
xfs_extlen_t len, int *stat);
|
||||
|
||||
/*
|
||||
* Lookup the first record greater than or equal to [bno, len]
|
||||
* in the btree given by cur.
|
||||
*/
|
||||
extern int xfs_alloc_lookup_ge(struct xfs_btree_cur *cur, xfs_agblock_t bno,
|
||||
xfs_extlen_t len, int *stat);
|
||||
|
||||
/*
|
||||
* Lookup the first record less than or equal to [bno, len]
|
||||
* in the btree given by cur.
|
||||
*/
|
||||
extern int xfs_alloc_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
|
||||
xfs_extlen_t len, int *stat);
|
||||
|
||||
/*
|
||||
* Update the record referred to by cur, to the value given by [bno, len].
|
||||
* This either works (return 0) or gets an EFSCORRUPTED error.
|
||||
*/
|
||||
extern int xfs_alloc_update(struct xfs_btree_cur *cur, xfs_agblock_t bno,
|
||||
xfs_extlen_t len);
|
||||
|
||||
#endif /* __XFS_ALLOC_BTREE_H__ */
|
@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ARCH_H__
|
||||
#define __XFS_ARCH_H__
|
||||
|
||||
#ifndef XFS_BIG_INUMS
|
||||
# error XFS_BIG_INUMS must be defined true or false
|
||||
#endif
|
||||
|
||||
#include <sys/endian.h>
|
||||
|
||||
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define __BIG_ENDIAN _BIG_ENDIAN
|
||||
#define __BYTE_ORDER _BYTE_ORDER
|
||||
#define __user
|
||||
/* Compatibiliy defines */
|
||||
#define __swab16 __bswap16
|
||||
#define __swab32 __bswap32
|
||||
#define __swab64 __bswap64
|
||||
|
||||
#define ARCH_NOCONVERT 1
|
||||
#if _BYTE_ORDER != _LITTLE_ENDIAN
|
||||
#define XFS_NATIVE_HOST 1
|
||||
# define ARCH_CONVERT ARCH_NOCONVERT
|
||||
#else
|
||||
#undef XFS_NATIVE_HOST
|
||||
#define ARCH_CONVERT 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XFS_NATIVE_HOST
|
||||
#define cpu_to_be16(val) ((__be16)(val))
|
||||
#define cpu_to_be32(val) ((__be32)(val))
|
||||
#define cpu_to_be64(val) ((__be64)(val))
|
||||
#define be16_to_cpu(val) ((__uint16_t)(val))
|
||||
#define be32_to_cpu(val) ((__uint32_t)(val))
|
||||
#define be64_to_cpu(val) ((__uint64_t)(val))
|
||||
#else
|
||||
#define cpu_to_be16(val) (__swab16((__uint16_t)(val)))
|
||||
#define cpu_to_be32(val) (__swab32((__uint32_t)(val)))
|
||||
#define cpu_to_be64(val) (__swab64((__uint64_t)(val)))
|
||||
#define be16_to_cpu(val) (__swab16((__be16)(val)))
|
||||
#define be32_to_cpu(val) (__swab32((__be32)(val)))
|
||||
#define be64_to_cpu(val) (__swab64((__be64)(val)))
|
||||
#endif
|
||||
|
||||
//#endif /* __KERNEL__ */
|
||||
|
||||
/* do we need conversion? */
|
||||
//#define ARCH_NOCONVERT 1
|
||||
//#ifdef XFS_NATIVE_HOST
|
||||
//# define ARCH_CONVERT ARCH_NOCONVERT
|
||||
//#else
|
||||
//# define ARCH_CONVERT 0
|
||||
//#endif
|
||||
|
||||
/* generic swapping macros */
|
||||
|
||||
#ifndef HAVE_SWABMACROS
|
||||
#define INT_SWAP16(type,var) ((typeof(type))(__swab16((__u16)(var))))
|
||||
#define INT_SWAP32(type,var) ((typeof(type))(__swab32((__u32)(var))))
|
||||
#define INT_SWAP64(type,var) ((typeof(type))(__swab64((__u64)(var))))
|
||||
#endif
|
||||
|
||||
#define INT_SWAP(type, var) \
|
||||
((sizeof(type) == 8) ? INT_SWAP64(type,var) : \
|
||||
((sizeof(type) == 4) ? INT_SWAP32(type,var) : \
|
||||
((sizeof(type) == 2) ? INT_SWAP16(type,var) : \
|
||||
(var))))
|
||||
|
||||
/*
|
||||
* get and set integers from potentially unaligned locations
|
||||
*/
|
||||
|
||||
#define INT_GET_UNALIGNED_16_BE(pointer) \
|
||||
((__u16)((((__u8*)(pointer))[0] << 8) | (((__u8*)(pointer))[1])))
|
||||
#define INT_SET_UNALIGNED_16_BE(pointer,value) \
|
||||
{ \
|
||||
((__u8*)(pointer))[0] = (((value) >> 8) & 0xff); \
|
||||
((__u8*)(pointer))[1] = (((value) ) & 0xff); \
|
||||
}
|
||||
|
||||
/* define generic INT_ macros */
|
||||
|
||||
#define INT_GET(reference,arch) \
|
||||
(((arch) == ARCH_NOCONVERT) \
|
||||
? \
|
||||
(reference) \
|
||||
: \
|
||||
INT_SWAP((reference),(reference)) \
|
||||
)
|
||||
|
||||
/* does not return a value */
|
||||
#define INT_SET(reference,arch,valueref) \
|
||||
(__builtin_constant_p(valueref) ? \
|
||||
(void)( (reference) = ( ((arch) != ARCH_NOCONVERT) ? (INT_SWAP((reference),(valueref))) : (valueref)) ) : \
|
||||
(void)( \
|
||||
((reference) = (valueref)), \
|
||||
( ((arch) != ARCH_NOCONVERT) ? (reference) = INT_SWAP((reference),(reference)) : 0 ) \
|
||||
) \
|
||||
)
|
||||
|
||||
/* does not return a value */
|
||||
#define INT_MOD_EXPR(reference,arch,code) \
|
||||
(((arch) == ARCH_NOCONVERT) \
|
||||
? \
|
||||
(void)((reference) code) \
|
||||
: \
|
||||
(void)( \
|
||||
(reference) = INT_GET((reference),arch) , \
|
||||
((reference) code), \
|
||||
INT_SET(reference, arch, reference) \
|
||||
) \
|
||||
)
|
||||
|
||||
/* does not return a value */
|
||||
#define INT_MOD(reference,arch,delta) \
|
||||
(void)( \
|
||||
INT_MOD_EXPR(reference,arch,+=(delta)) \
|
||||
)
|
||||
|
||||
/*
|
||||
* INT_COPY - copy a value between two locations with the
|
||||
* _same architecture_ but _potentially different sizes_
|
||||
*
|
||||
* if the types of the two parameters are equal or they are
|
||||
* in native architecture, a simple copy is done
|
||||
*
|
||||
* otherwise, architecture conversions are done
|
||||
*
|
||||
*/
|
||||
|
||||
/* does not return a value */
|
||||
#define INT_COPY(dst,src,arch) \
|
||||
( \
|
||||
((sizeof(dst) == sizeof(src)) || ((arch) == ARCH_NOCONVERT)) \
|
||||
? \
|
||||
(void)((dst) = (src)) \
|
||||
: \
|
||||
INT_SET(dst, arch, INT_GET(src, arch)) \
|
||||
)
|
||||
|
||||
/*
|
||||
* INT_XLATE - copy a value in either direction between two locations
|
||||
* with different architectures
|
||||
*
|
||||
* dir < 0 - copy from memory to buffer (native to arch)
|
||||
* dir > 0 - copy from buffer to memory (arch to native)
|
||||
*/
|
||||
|
||||
/* does not return a value */
|
||||
#define INT_XLATE(buf,mem,dir,arch) {\
|
||||
ASSERT(dir); \
|
||||
if (dir>0) { \
|
||||
(mem)=INT_GET(buf, arch); \
|
||||
} else { \
|
||||
INT_SET(buf, arch, mem); \
|
||||
} \
|
||||
}
|
||||
|
||||
static inline void be16_add(__be16 *a, __s16 b)
|
||||
{
|
||||
*a = cpu_to_be16(be16_to_cpu(*a) + b);
|
||||
}
|
||||
|
||||
static inline void be32_add(__be32 *a, __s32 b)
|
||||
{
|
||||
*a = cpu_to_be32(be32_to_cpu(*a) + b);
|
||||
}
|
||||
|
||||
static inline void be64_add(__be64 *a, __s64 b)
|
||||
{
|
||||
*a = cpu_to_be64(be64_to_cpu(*a) + b);
|
||||
}
|
||||
|
||||
/*
|
||||
* In directories inode numbers are stored as unaligned arrays of unsigned
|
||||
* 8bit integers on disk.
|
||||
*
|
||||
* For v1 directories or v2 directories that contain inode numbers that
|
||||
* do not fit into 32bit the array has eight members, but the first member
|
||||
* is always zero:
|
||||
*
|
||||
* |unused|48-55|40-47|32-39|24-31|16-23| 8-15| 0- 7|
|
||||
*
|
||||
* For v2 directories that only contain entries with inode numbers that fit
|
||||
* into 32bits a four-member array is used:
|
||||
*
|
||||
* |24-31|16-23| 8-15| 0- 7|
|
||||
*/
|
||||
|
||||
#define XFS_GET_DIR_INO4(di) \
|
||||
(((__u32)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
|
||||
|
||||
#define XFS_PUT_DIR_INO4(from, di) \
|
||||
do { \
|
||||
(di).i[0] = (((from) & 0xff000000ULL) >> 24); \
|
||||
(di).i[1] = (((from) & 0x00ff0000ULL) >> 16); \
|
||||
(di).i[2] = (((from) & 0x0000ff00ULL) >> 8); \
|
||||
(di).i[3] = ((from) & 0x000000ffULL); \
|
||||
} while (0)
|
||||
|
||||
#define XFS_DI_HI(di) \
|
||||
(((__u32)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
|
||||
#define XFS_DI_LO(di) \
|
||||
(((__u32)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6] << 8) | ((di).i[7]))
|
||||
|
||||
#define XFS_GET_DIR_INO8(di) \
|
||||
(((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
|
||||
((xfs_ino_t)XFS_DI_HI(di) << 32))
|
||||
|
||||
#define XFS_PUT_DIR_INO8(from, di) \
|
||||
do { \
|
||||
(di).i[0] = 0; \
|
||||
(di).i[1] = (((from) & 0x00ff000000000000ULL) >> 48); \
|
||||
(di).i[2] = (((from) & 0x0000ff0000000000ULL) >> 40); \
|
||||
(di).i[3] = (((from) & 0x000000ff00000000ULL) >> 32); \
|
||||
(di).i[4] = (((from) & 0x00000000ff000000ULL) >> 24); \
|
||||
(di).i[5] = (((from) & 0x0000000000ff0000ULL) >> 16); \
|
||||
(di).i[6] = (((from) & 0x000000000000ff00ULL) >> 8); \
|
||||
(di).i[7] = ((from) & 0x00000000000000ffULL); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __XFS_ARCH_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ATTR_H__
|
||||
#define __XFS_ATTR_H__
|
||||
|
||||
/*
|
||||
* xfs_attr.h
|
||||
*
|
||||
* Large attribute lists are structured around Btrees where all the data
|
||||
* elements are in the leaf nodes. Attribute names are hashed into an int,
|
||||
* then that int is used as the index into the Btree. Since the hashval
|
||||
* of an attribute name may not be unique, we may have duplicate keys.
|
||||
* The internal links in the Btree are logical block offsets into the file.
|
||||
*
|
||||
* Small attribute lists use a different format and are packed as tightly
|
||||
* as possible so as to fit into the literal area of the inode.
|
||||
*/
|
||||
|
||||
/*========================================================================
|
||||
* External interfaces
|
||||
*========================================================================*/
|
||||
|
||||
struct cred;
|
||||
struct xfs_vnode;
|
||||
|
||||
typedef int (*attrset_t)(struct xfs_vnode *, char *, void *, size_t, int);
|
||||
typedef int (*attrget_t)(struct xfs_vnode *, char *, void *, size_t, int);
|
||||
typedef int (*attrremove_t)(struct xfs_vnode *, char *, int);
|
||||
typedef int (*attrexists_t)(struct xfs_vnode *);
|
||||
typedef int (*attrcapable_t)(struct xfs_vnode *, struct cred *);
|
||||
|
||||
typedef struct attrnames {
|
||||
char * attr_name;
|
||||
unsigned int attr_namelen;
|
||||
unsigned int attr_flag;
|
||||
attrget_t attr_get;
|
||||
attrset_t attr_set;
|
||||
attrremove_t attr_remove;
|
||||
attrexists_t attr_exists;
|
||||
attrcapable_t attr_capable;
|
||||
} attrnames_t;
|
||||
|
||||
#define ATTR_NAMECOUNT 4
|
||||
extern struct attrnames attr_user;
|
||||
extern struct attrnames attr_secure;
|
||||
extern struct attrnames attr_system;
|
||||
extern struct attrnames attr_trusted;
|
||||
extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
|
||||
|
||||
extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
|
||||
extern int attr_generic_list(struct xfs_vnode *, void *, size_t, int, ssize_t *);
|
||||
|
||||
#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
|
||||
#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
|
||||
#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
|
||||
#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
|
||||
#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
|
||||
#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
|
||||
#define ATTR_SYSTEM 0x0100 /* use attrs in system (pseudo) namespace */
|
||||
|
||||
#define ATTR_KERNACCESS 0x0400 /* [kernel] iaccess, inode held io-locked */
|
||||
#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
|
||||
#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
|
||||
#define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list) */
|
||||
|
||||
#define ATTR_KERNORMALS 0x0800 /* [kernel] normal attr list: user+secure */
|
||||
#define ATTR_KERNROOTLS 0x8000 /* [kernel] include root in the attr list */
|
||||
#define ATTR_KERNFULLS (ATTR_KERNORMALS|ATTR_KERNROOTLS)
|
||||
|
||||
/*
|
||||
* The maximum size (into the kernel or returned from the kernel) of an
|
||||
* attribute value or the buffer used for an attr_list() call. Larger
|
||||
* sizes will result in an ERANGE return code.
|
||||
*/
|
||||
#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
|
||||
|
||||
/*
|
||||
* Define how lists of attribute names are returned to the user from
|
||||
* the attr_list() call. A large, 32bit aligned, buffer is passed in
|
||||
* along with its size. We put an array of offsets at the top that each
|
||||
* reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
|
||||
*/
|
||||
typedef struct attrlist {
|
||||
__s32 al_count; /* number of entries in attrlist */
|
||||
__s32 al_more; /* T/F: more attrs (do call again) */
|
||||
__s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
|
||||
} attrlist_t;
|
||||
|
||||
/*
|
||||
* Show the interesting info about one attribute. This is what the
|
||||
* al_offset[i] entry points to.
|
||||
*/
|
||||
typedef struct attrlist_ent { /* data from attr_list() */
|
||||
__u32 a_valuelen; /* number bytes in value of attr */
|
||||
char a_name[1]; /* attr name (NULL terminated) */
|
||||
} attrlist_ent_t;
|
||||
|
||||
/*
|
||||
* Given a pointer to the (char*) buffer containing the attr_list() result,
|
||||
* and an index, return a pointer to the indicated attribute in the buffer.
|
||||
*/
|
||||
#define ATTR_ENTRY(buffer, index) \
|
||||
((attrlist_ent_t *) \
|
||||
&((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
|
||||
|
||||
/*
|
||||
* Multi-attribute operation vector.
|
||||
*/
|
||||
typedef struct attr_multiop {
|
||||
int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */
|
||||
int am_error; /* [out arg] result of this sub-op (an errno) */
|
||||
char *am_attrname; /* attribute name to work with */
|
||||
char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */
|
||||
int am_length; /* [in/out arg] length of value */
|
||||
int am_flags; /* bitwise OR of attr API flags defined above */
|
||||
} attr_multiop_t;
|
||||
|
||||
#define ATTR_OP_GET 1 /* return the indicated attr's value */
|
||||
#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
|
||||
#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
|
||||
|
||||
/*
|
||||
* Kernel-internal version of the attrlist cursor.
|
||||
*/
|
||||
typedef struct attrlist_cursor_kern {
|
||||
__u32 hashval; /* hash value of next entry to add */
|
||||
__u32 blkno; /* block containing entry (suggestion) */
|
||||
__u32 offset; /* offset in list of equal-hashvals */
|
||||
__u16 pad1; /* padding to match user-level */
|
||||
__u8 pad2; /* padding to match user-level */
|
||||
__u8 initted; /* T/F: cursor has been initialized */
|
||||
} attrlist_cursor_kern_t;
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Function prototypes for the kernel.
|
||||
*========================================================================*/
|
||||
|
||||
struct xfs_inode;
|
||||
struct attrlist_cursor_kern;
|
||||
struct xfs_da_args;
|
||||
|
||||
/*
|
||||
* Overall external interface routines.
|
||||
*/
|
||||
int xfs_attr_get(bhv_desc_t *, const char *, char *, int *, int, struct cred *);
|
||||
int xfs_attr_set(bhv_desc_t *, const char *, char *, int, int, struct cred *);
|
||||
int xfs_attr_remove(bhv_desc_t *, const char *, int, struct cred *);
|
||||
int xfs_attr_list(bhv_desc_t *, char *, int, int,
|
||||
struct attrlist_cursor_kern *, struct cred *);
|
||||
int xfs_attr_inactive(struct xfs_inode *dp);
|
||||
|
||||
int xfs_attr_shortform_getvalue(struct xfs_da_args *);
|
||||
int xfs_attr_fetch(struct xfs_inode *, const char *, int,
|
||||
char *, int *, int, struct cred *);
|
||||
|
||||
#endif /* __XFS_ATTR_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,282 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ATTR_LEAF_H__
|
||||
#define __XFS_ATTR_LEAF_H__
|
||||
|
||||
/*
|
||||
* Attribute storage layout, internal structure, access macros, etc.
|
||||
*
|
||||
* Attribute lists are structured around Btrees where all the data
|
||||
* elements are in the leaf nodes. Attribute names are hashed into an int,
|
||||
* then that int is used as the index into the Btree. Since the hashval
|
||||
* of an attribute name may not be unique, we may have duplicate keys. The
|
||||
* internal links in the Btree are logical block offsets into the file.
|
||||
*/
|
||||
|
||||
struct attrlist;
|
||||
struct attrlist_cursor_kern;
|
||||
struct attrnames;
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_da_state;
|
||||
struct xfs_da_state_blk;
|
||||
struct xfs_inode;
|
||||
struct xfs_trans;
|
||||
|
||||
/*========================================================================
|
||||
* Attribute structure when equal to XFS_LBSIZE(mp) bytes.
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* This is the structure of the leaf nodes in the Btree.
|
||||
*
|
||||
* Struct leaf_entry's are packed from the top. Name/values grow from the
|
||||
* bottom but are not packed. The freemap contains run-length-encoded entries
|
||||
* for the free bytes after the leaf_entry's, but only the N largest such,
|
||||
* smaller runs are dropped. When the freemap doesn't show enough space
|
||||
* for an allocation, we compact the name/value area and try again. If we
|
||||
* still don't have enough space, then we have to split the block. The
|
||||
* name/value structs (both local and remote versions) must be 32bit aligned.
|
||||
*
|
||||
* Since we have duplicate hash keys, for each key that matches, compare
|
||||
* the actual name string. The root and intermediate node search always
|
||||
* takes the first-in-the-block key match found, so we should only have
|
||||
* to work "forw"ard. If none matches, continue with the "forw"ard leaf
|
||||
* nodes until the hash key changes or the attribute name is found.
|
||||
*
|
||||
* We store the fact that an attribute is a ROOT/USER/SECURE attribute in
|
||||
* the leaf_entry. The namespaces are independent only because we also look
|
||||
* at the namespace bit when we are looking for a matching attribute name.
|
||||
*
|
||||
* We also store an "incomplete" bit in the leaf_entry. It shows that an
|
||||
* attribute is in the middle of being created and should not be shown to
|
||||
* the user if we crash during the time that the bit is set. We clear the
|
||||
* bit when we have finished setting up the attribute. We do this because
|
||||
* we cannot create some large attributes inside a single transaction, and we
|
||||
* need some indication that we weren't finished if we crash in the middle.
|
||||
*/
|
||||
#define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */
|
||||
|
||||
typedef struct xfs_attr_leaf_map { /* RLE map of free bytes */
|
||||
__be16 base; /* base of free region */
|
||||
__be16 size; /* length of free region */
|
||||
} xfs_attr_leaf_map_t;
|
||||
|
||||
typedef struct xfs_attr_leaf_hdr { /* constant-structure header block */
|
||||
xfs_da_blkinfo_t info; /* block type, links, etc. */
|
||||
__be16 count; /* count of active leaf_entry's */
|
||||
__be16 usedbytes; /* num bytes of names/values stored */
|
||||
__be16 firstused; /* first used byte in name area */
|
||||
__u8 holes; /* != 0 if blk needs compaction */
|
||||
__u8 pad1;
|
||||
xfs_attr_leaf_map_t freemap[XFS_ATTR_LEAF_MAPSIZE];
|
||||
/* N largest free regions */
|
||||
} xfs_attr_leaf_hdr_t;
|
||||
|
||||
typedef struct xfs_attr_leaf_entry { /* sorted on key, not name */
|
||||
__be32 hashval; /* hash value of name */
|
||||
__be16 nameidx; /* index into buffer of name/value */
|
||||
__u8 flags; /* LOCAL/ROOT/SECURE/INCOMPLETE flag */
|
||||
__u8 pad2; /* unused pad byte */
|
||||
} xfs_attr_leaf_entry_t;
|
||||
|
||||
typedef struct xfs_attr_leaf_name_local {
|
||||
__be16 valuelen; /* number of bytes in value */
|
||||
__u8 namelen; /* length of name bytes */
|
||||
__u8 nameval[1]; /* name/value bytes */
|
||||
} xfs_attr_leaf_name_local_t;
|
||||
|
||||
typedef struct xfs_attr_leaf_name_remote {
|
||||
__be32 valueblk; /* block number of value bytes */
|
||||
__be32 valuelen; /* number of bytes in value */
|
||||
__u8 namelen; /* length of name bytes */
|
||||
__u8 name[1]; /* name bytes */
|
||||
} xfs_attr_leaf_name_remote_t;
|
||||
|
||||
typedef struct xfs_attr_leafblock {
|
||||
xfs_attr_leaf_hdr_t hdr; /* constant-structure header block */
|
||||
xfs_attr_leaf_entry_t entries[1]; /* sorted on key, not name */
|
||||
xfs_attr_leaf_name_local_t namelist; /* grows from bottom of buf */
|
||||
xfs_attr_leaf_name_remote_t valuelist; /* grows from bottom of buf */
|
||||
} xfs_attr_leafblock_t;
|
||||
|
||||
/*
|
||||
* Flags used in the leaf_entry[i].flags field.
|
||||
* NOTE: the INCOMPLETE bit must not collide with the flags bits specified
|
||||
* on the system call, they are "or"ed together for various operations.
|
||||
*/
|
||||
#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */
|
||||
#define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */
|
||||
#define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */
|
||||
#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */
|
||||
#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT)
|
||||
#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT)
|
||||
#define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT)
|
||||
#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT)
|
||||
|
||||
/*
|
||||
* Alignment for namelist and valuelist entries (since they are mixed
|
||||
* there can be only one alignment value)
|
||||
*/
|
||||
#define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t))
|
||||
|
||||
/*
|
||||
* Cast typed pointers for "local" and "remote" name/value structs.
|
||||
*/
|
||||
#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) \
|
||||
xfs_attr_leaf_name_remote(leafp,idx)
|
||||
static inline xfs_attr_leaf_name_remote_t *
|
||||
xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx)
|
||||
{
|
||||
return (xfs_attr_leaf_name_remote_t *)
|
||||
&((char *)leafp)[be16_to_cpu(leafp->entries[idx].nameidx)];
|
||||
}
|
||||
|
||||
#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) \
|
||||
xfs_attr_leaf_name_local(leafp,idx)
|
||||
static inline xfs_attr_leaf_name_local_t *
|
||||
xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx)
|
||||
{
|
||||
return (xfs_attr_leaf_name_local_t *)
|
||||
&((char *)leafp)[be16_to_cpu(leafp->entries[idx].nameidx)];
|
||||
}
|
||||
|
||||
#define XFS_ATTR_LEAF_NAME(leafp,idx) \
|
||||
xfs_attr_leaf_name(leafp,idx)
|
||||
static inline char *xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx)
|
||||
{
|
||||
return &((char *)leafp)[be16_to_cpu(leafp->entries[idx].nameidx)];
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate total bytes used (including trailing pad for alignment) for
|
||||
* a "local" name/value structure, a "remote" name/value structure, and
|
||||
* a pointer which might be either.
|
||||
*/
|
||||
#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) \
|
||||
xfs_attr_leaf_entsize_remote(nlen)
|
||||
static inline int xfs_attr_leaf_entsize_remote(int nlen)
|
||||
{
|
||||
return ((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \
|
||||
XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1);
|
||||
}
|
||||
|
||||
#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) \
|
||||
xfs_attr_leaf_entsize_local(nlen,vlen)
|
||||
static inline int xfs_attr_leaf_entsize_local(int nlen, int vlen)
|
||||
{
|
||||
return ((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) +
|
||||
XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1);
|
||||
}
|
||||
|
||||
#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) \
|
||||
xfs_attr_leaf_entsize_local_max(bsize)
|
||||
static inline int xfs_attr_leaf_entsize_local_max(int bsize)
|
||||
{
|
||||
return (((bsize) >> 1) + ((bsize) >> 2));
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Structure used to pass context around among the routines.
|
||||
*========================================================================*/
|
||||
|
||||
typedef struct xfs_attr_list_context {
|
||||
struct xfs_inode *dp; /* inode */
|
||||
struct attrlist_cursor_kern *cursor;/* position in list */
|
||||
struct attrlist *alist; /* output buffer */
|
||||
int count; /* num used entries */
|
||||
int dupcnt; /* count dup hashvals seen */
|
||||
int bufsize;/* total buffer size */
|
||||
int firstu; /* first used byte in buffer */
|
||||
int flags; /* from VOP call */
|
||||
int resynch;/* T/F: resynch with cursor */
|
||||
} xfs_attr_list_context_t;
|
||||
|
||||
/*
|
||||
* Used to keep a list of "remote value" extents when unlinking an inode.
|
||||
*/
|
||||
typedef struct xfs_attr_inactive_list {
|
||||
xfs_dablk_t valueblk; /* block number of value bytes */
|
||||
int valuelen; /* number of bytes in value */
|
||||
} xfs_attr_inactive_list_t;
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Function prototypes for the kernel.
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* Internal routines when attribute fork size < XFS_LITINO(mp).
|
||||
*/
|
||||
void xfs_attr_shortform_create(struct xfs_da_args *args);
|
||||
void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
|
||||
int xfs_attr_shortform_lookup(struct xfs_da_args *args);
|
||||
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
|
||||
int xfs_attr_shortform_remove(struct xfs_da_args *args);
|
||||
int xfs_attr_shortform_list(struct xfs_attr_list_context *context);
|
||||
int xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp);
|
||||
int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes);
|
||||
|
||||
|
||||
/*
|
||||
* Internal routines when attribute fork size == XFS_LBSIZE(mp).
|
||||
*/
|
||||
int xfs_attr_leaf_to_node(struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_to_shortform(struct xfs_dabuf *bp,
|
||||
struct xfs_da_args *args, int forkoff);
|
||||
int xfs_attr_leaf_clearflag(struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_setflag(struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_flipflags(xfs_da_args_t *args);
|
||||
|
||||
/*
|
||||
* Routines used for growing the Btree.
|
||||
*/
|
||||
int xfs_attr_leaf_split(struct xfs_da_state *state,
|
||||
struct xfs_da_state_blk *oldblk,
|
||||
struct xfs_da_state_blk *newblk);
|
||||
int xfs_attr_leaf_lookup_int(struct xfs_dabuf *leaf,
|
||||
struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_getvalue(struct xfs_dabuf *bp, struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_add(struct xfs_dabuf *leaf_buffer,
|
||||
struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_remove(struct xfs_dabuf *leaf_buffer,
|
||||
struct xfs_da_args *args);
|
||||
int xfs_attr_leaf_list_int(struct xfs_dabuf *bp,
|
||||
struct xfs_attr_list_context *context);
|
||||
|
||||
/*
|
||||
* Routines used for shrinking the Btree.
|
||||
*/
|
||||
int xfs_attr_leaf_toosmall(struct xfs_da_state *state, int *retval);
|
||||
void xfs_attr_leaf_unbalance(struct xfs_da_state *state,
|
||||
struct xfs_da_state_blk *drop_blk,
|
||||
struct xfs_da_state_blk *save_blk);
|
||||
int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp);
|
||||
|
||||
/*
|
||||
* Utility routines.
|
||||
*/
|
||||
xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_dabuf *bp, int *count);
|
||||
int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp,
|
||||
struct xfs_dabuf *leaf2_bp);
|
||||
int xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize,
|
||||
int *local);
|
||||
int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp);
|
||||
|
||||
#endif /* __XFS_ATTR_LEAF_H__ */
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_ATTR_SF_H__
|
||||
#define __XFS_ATTR_SF_H__
|
||||
|
||||
/*
|
||||
* Attribute storage when stored inside the inode.
|
||||
*
|
||||
* Small attribute lists are packed as tightly as possible so as
|
||||
* to fit into the literal area of the inode.
|
||||
*/
|
||||
|
||||
struct xfs_inode;
|
||||
|
||||
/*
|
||||
* Entries are packed toward the top as tight as possible.
|
||||
*/
|
||||
typedef struct xfs_attr_shortform {
|
||||
struct xfs_attr_sf_hdr { /* constant-structure header block */
|
||||
__be16 totsize; /* total bytes in shortform list */
|
||||
__u8 count; /* count of active entries */
|
||||
} hdr;
|
||||
struct xfs_attr_sf_entry {
|
||||
__uint8_t namelen; /* actual length of name (no NULL) */
|
||||
__uint8_t valuelen; /* actual length of value (no NULL) */
|
||||
__uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */
|
||||
__uint8_t nameval[1]; /* name & value bytes concatenated */
|
||||
} list[1]; /* variable sized array */
|
||||
} xfs_attr_shortform_t;
|
||||
typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t;
|
||||
typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t;
|
||||
|
||||
/*
|
||||
* We generate this then sort it, attr_list() must return things in hash-order.
|
||||
*/
|
||||
typedef struct xfs_attr_sf_sort {
|
||||
__uint8_t entno; /* entry number in original list */
|
||||
__uint8_t namelen; /* length of name value (no null) */
|
||||
__uint8_t valuelen; /* length of value */
|
||||
__uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */
|
||||
xfs_dahash_t hash; /* this entry's hash value */
|
||||
char *name; /* name value, pointer into buffer */
|
||||
} xfs_attr_sf_sort_t;
|
||||
|
||||
#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \
|
||||
(((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen)))
|
||||
#define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \
|
||||
((1 << (NBBY*(int)sizeof(__uint8_t))) - 1)
|
||||
#define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \
|
||||
((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen)
|
||||
#define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \
|
||||
((xfs_attr_sf_entry_t *)((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep)))
|
||||
#define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \
|
||||
(be16_to_cpu(((xfs_attr_shortform_t *) \
|
||||
((dp)->i_afp->if_u1.if_data))->hdr.totsize))
|
||||
|
||||
#if defined(XFS_ATTR_TRACE)
|
||||
/*
|
||||
* Kernel tracing support for attribute lists
|
||||
*/
|
||||
struct xfs_attr_list_context;
|
||||
struct xfs_da_intnode;
|
||||
struct xfs_da_node_entry;
|
||||
struct xfs_attr_leafblock;
|
||||
|
||||
#define XFS_ATTR_TRACE_SIZE 4096 /* size of global trace buffer */
|
||||
extern ktrace_t *xfs_attr_trace_buf;
|
||||
|
||||
/*
|
||||
* Trace record types.
|
||||
*/
|
||||
#define XFS_ATTR_KTRACE_L_C 1 /* context */
|
||||
#define XFS_ATTR_KTRACE_L_CN 2 /* context, node */
|
||||
#define XFS_ATTR_KTRACE_L_CB 3 /* context, btree */
|
||||
#define XFS_ATTR_KTRACE_L_CL 4 /* context, leaf */
|
||||
|
||||
void xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context);
|
||||
void xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context,
|
||||
struct xfs_da_intnode *node);
|
||||
void xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
|
||||
struct xfs_da_node_entry *btree);
|
||||
void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
|
||||
struct xfs_attr_leafblock *leaf);
|
||||
void xfs_attr_trace_enter(int type, char *where,
|
||||
__psunsigned_t a2, __psunsigned_t a3,
|
||||
__psunsigned_t a4, __psunsigned_t a5,
|
||||
__psunsigned_t a6, __psunsigned_t a7,
|
||||
__psunsigned_t a8, __psunsigned_t a9,
|
||||
__psunsigned_t a10, __psunsigned_t a11,
|
||||
__psunsigned_t a12, __psunsigned_t a13,
|
||||
__psunsigned_t a14, __psunsigned_t a15);
|
||||
#else
|
||||
#define xfs_attr_trace_l_c(w,c)
|
||||
#define xfs_attr_trace_l_cn(w,c,n)
|
||||
#define xfs_attr_trace_l_cb(w,c,b)
|
||||
#define xfs_attr_trace_l_cl(w,c,l)
|
||||
#endif /* XFS_ATTR_TRACE */
|
||||
|
||||
#endif /* __XFS_ATTR_SF_H__ */
|
@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
|
||||
/*
|
||||
* Source file used to associate/disassociate behaviors with virtualized
|
||||
* objects. See xfs_behavior.h for more information about behaviors, etc.
|
||||
*
|
||||
* The implementation is split between functions in this file and macros
|
||||
* in xfs_behavior.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Insert a new behavior descriptor into a behavior chain.
|
||||
*
|
||||
* The behavior chain is ordered based on the 'position' number which
|
||||
* lives in the first field of the ops vector (higher numbers first).
|
||||
*
|
||||
* Attempts to insert duplicate ops result in an EINVAL return code.
|
||||
* Otherwise, return 0 to indicate success.
|
||||
*/
|
||||
int
|
||||
bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp)
|
||||
{
|
||||
bhv_desc_t *curdesc, *prev;
|
||||
int position;
|
||||
|
||||
/*
|
||||
* Validate the position value of the new behavior.
|
||||
*/
|
||||
position = BHV_POSITION(bdp);
|
||||
ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP);
|
||||
|
||||
/*
|
||||
* Find location to insert behavior. Check for duplicates.
|
||||
*/
|
||||
prev = NULL;
|
||||
for (curdesc = bhp->bh_first;
|
||||
curdesc != NULL;
|
||||
curdesc = curdesc->bd_next) {
|
||||
|
||||
/* Check for duplication. */
|
||||
if (curdesc->bd_ops == bdp->bd_ops) {
|
||||
ASSERT(0);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Find correct position */
|
||||
if (position >= BHV_POSITION(curdesc)) {
|
||||
ASSERT(position != BHV_POSITION(curdesc));
|
||||
break; /* found it */
|
||||
}
|
||||
|
||||
prev = curdesc;
|
||||
}
|
||||
|
||||
if (prev == NULL) {
|
||||
/* insert at front of chain */
|
||||
bdp->bd_next = bhp->bh_first;
|
||||
bhp->bh_first = bdp;
|
||||
} else {
|
||||
/* insert after prev */
|
||||
bdp->bd_next = prev->bd_next;
|
||||
prev->bd_next = bdp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a behavior descriptor from a position in a behavior chain;
|
||||
* the position is guaranteed not to be the first position.
|
||||
* Should only be called by the bhv_remove() macro.
|
||||
*/
|
||||
void
|
||||
bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
|
||||
{
|
||||
bhv_desc_t *curdesc, *prev;
|
||||
|
||||
ASSERT(bhp->bh_first != NULL);
|
||||
ASSERT(bhp->bh_first->bd_next != NULL);
|
||||
|
||||
prev = bhp->bh_first;
|
||||
for (curdesc = bhp->bh_first->bd_next;
|
||||
curdesc != NULL;
|
||||
curdesc = curdesc->bd_next) {
|
||||
|
||||
if (curdesc == bdp)
|
||||
break; /* found it */
|
||||
prev = curdesc;
|
||||
}
|
||||
|
||||
ASSERT(curdesc == bdp);
|
||||
prev->bd_next = bdp->bd_next; /* remove from after prev */
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a specific ops vector on the specified behavior chain.
|
||||
* Return the associated behavior descriptor. Or NULL, if not found.
|
||||
*/
|
||||
bhv_desc_t *
|
||||
bhv_lookup(bhv_head_t *bhp, void *ops)
|
||||
{
|
||||
bhv_desc_t *curdesc;
|
||||
|
||||
for (curdesc = bhp->bh_first;
|
||||
curdesc != NULL;
|
||||
curdesc = curdesc->bd_next) {
|
||||
|
||||
if (curdesc->bd_ops == ops)
|
||||
return curdesc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks for the first behavior within a specified range of positions.
|
||||
* Return the associated behavior descriptor. Or NULL, if none found.
|
||||
*/
|
||||
bhv_desc_t *
|
||||
bhv_lookup_range(bhv_head_t *bhp, int low, int high)
|
||||
{
|
||||
bhv_desc_t *curdesc;
|
||||
|
||||
for (curdesc = bhp->bh_first;
|
||||
curdesc != NULL;
|
||||
curdesc = curdesc->bd_next) {
|
||||
|
||||
int position = BHV_POSITION(curdesc);
|
||||
|
||||
if (position <= high) {
|
||||
if (position >= low)
|
||||
return curdesc;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the base behavior in the chain, or NULL if the chain
|
||||
* is empty.
|
||||
*
|
||||
* The caller has not read locked the behavior chain, so acquire the
|
||||
* lock before traversing the chain.
|
||||
*/
|
||||
bhv_desc_t *
|
||||
bhv_base(bhv_head_t *bhp)
|
||||
{
|
||||
bhv_desc_t *curdesc;
|
||||
|
||||
for (curdesc = bhp->bh_first;
|
||||
curdesc != NULL;
|
||||
curdesc = curdesc->bd_next) {
|
||||
|
||||
if (curdesc->bd_next == NULL) {
|
||||
return curdesc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
bhv_head_init(
|
||||
bhv_head_t *bhp,
|
||||
char *name)
|
||||
{
|
||||
bhp->bh_first = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
bhv_insert_initial(
|
||||
bhv_head_t *bhp,
|
||||
bhv_desc_t *bdp)
|
||||
{
|
||||
ASSERT(bhp->bh_first == NULL);
|
||||
(bhp)->bh_first = bdp;
|
||||
}
|
||||
|
||||
void
|
||||
bhv_head_destroy(
|
||||
bhv_head_t *bhp)
|
||||
{
|
||||
ASSERT(bhp->bh_first == NULL);
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_BEHAVIOR_H__
|
||||
#define __XFS_BEHAVIOR_H__
|
||||
|
||||
/*
|
||||
* Header file used to associate behaviors with virtualized objects.
|
||||
*
|
||||
* A virtualized object is an internal, virtualized representation of
|
||||
* OS entities such as persistent files, processes, or sockets. Examples
|
||||
* of virtualized objects include vnodes, vprocs, and vsockets. Often
|
||||
* a virtualized object is referred to simply as an "object."
|
||||
*
|
||||
* A behavior is essentially an implementation layer associated with
|
||||
* an object. Multiple behaviors for an object are chained together,
|
||||
* the order of chaining determining the order of invocation. Each
|
||||
* behavior of a given object implements the same set of interfaces
|
||||
* (e.g., the VOP interfaces).
|
||||
*
|
||||
* Behaviors may be dynamically inserted into an object's behavior chain,
|
||||
* such that the addition is transparent to consumers that already have
|
||||
* references to the object. Typically, a given behavior will be inserted
|
||||
* at a particular location in the behavior chain. Insertion of new
|
||||
* behaviors is synchronized with operations-in-progress (oip's) so that
|
||||
* the oip's always see a consistent view of the chain.
|
||||
*
|
||||
* The term "interposition" is used to refer to the act of inserting
|
||||
* a behavior such that it interposes on (i.e., is inserted in front
|
||||
* of) a particular other behavior. A key example of this is when a
|
||||
* system implementing distributed single system image wishes to
|
||||
* interpose a distribution layer (providing distributed coherency)
|
||||
* in front of an object that is otherwise only accessed locally.
|
||||
*
|
||||
* Note that the traditional vnode/inode combination is simply a virtualized
|
||||
* object that has exactly one associated behavior.
|
||||
*
|
||||
* Behavior synchronization is logic which is necessary under certain
|
||||
* circumstances that there is no conflict between ongoing operations
|
||||
* traversing the behavior chain and those dynamically modifying the
|
||||
* behavior chain. Because behavior synchronization adds extra overhead
|
||||
* to virtual operation invocation, we want to restrict, as much as
|
||||
* we can, the requirement for this extra code, to those situations
|
||||
* in which it is truly necessary.
|
||||
*
|
||||
* Behavior synchronization is needed whenever there's at least one class
|
||||
* of object in the system for which:
|
||||
* 1) multiple behaviors for a given object are supported,
|
||||
* -- AND --
|
||||
* 2a) insertion of a new behavior can happen dynamically at any time during
|
||||
* the life of an active object,
|
||||
* -- AND --
|
||||
* 3a) insertion of a new behavior needs to synchronize with existing
|
||||
* ops-in-progress.
|
||||
* -- OR --
|
||||
* 3b) multiple different behaviors can be dynamically inserted at
|
||||
* any time during the life of an active object
|
||||
* -- OR --
|
||||
* 3c) removal of a behavior can occur at any time during the life of
|
||||
* an active object.
|
||||
* -- OR --
|
||||
* 2b) removal of a behavior can occur at any time during the life of an
|
||||
* active object
|
||||
*
|
||||
*/
|
||||
|
||||
struct bhv_head_lock;
|
||||
|
||||
/*
|
||||
* Behavior head. Head of the chain of behaviors.
|
||||
* Contained within each virtualized object data structure.
|
||||
*/
|
||||
typedef struct bhv_head {
|
||||
struct bhv_desc *bh_first; /* first behavior in chain */
|
||||
struct bhv_head_lock *bh_lockp; /* pointer to lock info struct */
|
||||
} bhv_head_t;
|
||||
|
||||
/*
|
||||
* Behavior descriptor. Descriptor associated with each behavior.
|
||||
* Contained within the behavior's private data structure.
|
||||
*/
|
||||
typedef struct bhv_desc {
|
||||
void *bd_pdata; /* private data for this behavior */
|
||||
void *bd_vobj; /* virtual object associated with */
|
||||
void *bd_ops; /* ops for this behavior */
|
||||
struct bhv_desc *bd_next; /* next behavior in chain */
|
||||
} bhv_desc_t;
|
||||
|
||||
/*
|
||||
* Behavior identity field. A behavior's identity determines the position
|
||||
* where it lives within a behavior chain, and it's always the first field
|
||||
* of the behavior's ops vector. The optional id field further identifies the
|
||||
* subsystem responsible for the behavior.
|
||||
*/
|
||||
typedef struct bhv_identity {
|
||||
__u16 bi_id; /* owning subsystem id */
|
||||
__u16 bi_position; /* position in chain */
|
||||
} bhv_identity_t;
|
||||
|
||||
typedef bhv_identity_t bhv_position_t;
|
||||
|
||||
#define BHV_IDENTITY_INIT(id,pos) {id, pos}
|
||||
#define BHV_IDENTITY_INIT_POSITION(pos) BHV_IDENTITY_INIT(0, pos)
|
||||
|
||||
/*
|
||||
* Define boundaries of position values.
|
||||
*/
|
||||
#define BHV_POSITION_INVALID 0 /* invalid position number */
|
||||
#define BHV_POSITION_BASE 1 /* base (last) implementation layer */
|
||||
#define BHV_POSITION_TOP 63 /* top (first) implementation layer */
|
||||
|
||||
/*
|
||||
* Plumbing macros.
|
||||
*/
|
||||
#define BHV_HEAD_FIRST(bhp) (ASSERT((bhp)->bh_first), (bhp)->bh_first)
|
||||
#define BHV_NEXT(bdp) (ASSERT((bdp)->bd_next), (bdp)->bd_next)
|
||||
#define BHV_NEXTNULL(bdp) ((bdp)->bd_next)
|
||||
#define BHV_VOBJ(bdp) (ASSERT((bdp)->bd_vobj), (bdp)->bd_vobj)
|
||||
#define BHV_VOBJNULL(bdp) ((bdp)->bd_vobj)
|
||||
#define BHV_PDATA(bdp) (bdp)->bd_pdata
|
||||
#define BHV_OPS(bdp) (bdp)->bd_ops
|
||||
#define BHV_IDENTITY(bdp) ((bhv_identity_t *)(bdp)->bd_ops)
|
||||
#define BHV_POSITION(bdp) (BHV_IDENTITY(bdp)->bi_position)
|
||||
|
||||
extern void bhv_head_init(bhv_head_t *, char *);
|
||||
extern void bhv_head_destroy(bhv_head_t *);
|
||||
extern int bhv_insert(bhv_head_t *, bhv_desc_t *);
|
||||
extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *);
|
||||
|
||||
/*
|
||||
* Initialize a new behavior descriptor.
|
||||
* Arguments:
|
||||
* bdp - pointer to behavior descriptor
|
||||
* pdata - pointer to behavior's private data
|
||||
* vobj - pointer to associated virtual object
|
||||
* ops - pointer to ops for this behavior
|
||||
*/
|
||||
#define bhv_desc_init(bdp, pdata, vobj, ops) \
|
||||
{ \
|
||||
(bdp)->bd_pdata = pdata; \
|
||||
(bdp)->bd_vobj = vobj; \
|
||||
(bdp)->bd_ops = ops; \
|
||||
(bdp)->bd_next = NULL; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a behavior descriptor from a behavior chain.
|
||||
*/
|
||||
#define bhv_remove(bhp, bdp) \
|
||||
{ \
|
||||
if ((bhp)->bh_first == (bdp)) { \
|
||||
/* \
|
||||
* Remove from front of chain. \
|
||||
* Atomic wrt oip's. \
|
||||
*/ \
|
||||
(bhp)->bh_first = (bdp)->bd_next; \
|
||||
} else { \
|
||||
/* remove from non-front of chain */ \
|
||||
bhv_remove_not_first(bhp, bdp); \
|
||||
} \
|
||||
(bdp)->bd_vobj = NULL; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Behavior module prototypes.
|
||||
*/
|
||||
extern void bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp);
|
||||
extern bhv_desc_t * bhv_lookup(bhv_head_t *bhp, void *ops);
|
||||
extern bhv_desc_t * bhv_lookup_range(bhv_head_t *bhp, int low, int high);
|
||||
extern bhv_desc_t * bhv_base(bhv_head_t *bhp);
|
||||
|
||||
/* No bhv locking on Linux */
|
||||
#define bhv_lookup_unlocked bhv_lookup
|
||||
#define bhv_base_unlocked bhv_base
|
||||
|
||||
#endif /* __XFS_BEHAVIOR_H__ */
|
@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_trans.h"
|
||||
#include "xfs_buf_item.h"
|
||||
|
||||
/*
|
||||
* XFS bit manipulation routines, used in non-realtime code.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_ARCH_HIGHBIT
|
||||
/*
|
||||
* Index of high bit number in byte, -1 for none set, 0..7 otherwise.
|
||||
*/
|
||||
STATIC const char xfs_highbit[256] = {
|
||||
-1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */
|
||||
3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */
|
||||
4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */
|
||||
4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */
|
||||
5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */
|
||||
5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */
|
||||
5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */
|
||||
5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */
|
||||
6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */
|
||||
7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Count of bits set in byte, 0..8.
|
||||
*/
|
||||
static const char xfs_countbit[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, /* 00 .. 07 */
|
||||
1, 2, 2, 3, 2, 3, 3, 4, /* 08 .. 0f */
|
||||
1, 2, 2, 3, 2, 3, 3, 4, /* 10 .. 17 */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 18 .. 1f */
|
||||
1, 2, 2, 3, 2, 3, 3, 4, /* 20 .. 27 */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 28 .. 2f */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 30 .. 37 */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* 38 .. 3f */
|
||||
1, 2, 2, 3, 2, 3, 3, 4, /* 40 .. 47 */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 48 .. 4f */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 50 .. 57 */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* 58 .. 5f */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 60 .. 67 */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* 68 .. 6f */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* 70 .. 77 */
|
||||
4, 5, 5, 6, 5, 6, 6, 7, /* 78 .. 7f */
|
||||
1, 2, 2, 3, 2, 3, 3, 4, /* 80 .. 87 */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 88 .. 8f */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* 90 .. 97 */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* 98 .. 9f */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* a0 .. a7 */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* a8 .. af */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* b0 .. b7 */
|
||||
4, 5, 5, 6, 5, 6, 6, 7, /* b8 .. bf */
|
||||
2, 3, 3, 4, 3, 4, 4, 5, /* c0 .. c7 */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* c8 .. cf */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* d0 .. d7 */
|
||||
4, 5, 5, 6, 5, 6, 6, 7, /* d8 .. df */
|
||||
3, 4, 4, 5, 4, 5, 5, 6, /* e0 .. e7 */
|
||||
4, 5, 5, 6, 5, 6, 6, 7, /* e8 .. ef */
|
||||
4, 5, 5, 6, 5, 6, 6, 7, /* f0 .. f7 */
|
||||
5, 6, 6, 7, 6, 7, 7, 8, /* f8 .. ff */
|
||||
};
|
||||
|
||||
/*
|
||||
* xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set.
|
||||
*/
|
||||
int
|
||||
xfs_highbit32(
|
||||
__uint32_t v)
|
||||
{
|
||||
#ifdef HAVE_ARCH_HIGHBIT
|
||||
return highbit32(v);
|
||||
#else
|
||||
int i;
|
||||
|
||||
if (v & 0xffff0000)
|
||||
if (v & 0xff000000)
|
||||
i = 24;
|
||||
else
|
||||
i = 16;
|
||||
else if (v & 0x0000ffff)
|
||||
if (v & 0x0000ff00)
|
||||
i = 8;
|
||||
else
|
||||
i = 0;
|
||||
else
|
||||
return -1;
|
||||
return i + xfs_highbit[(v >> i) & 0xff];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set.
|
||||
*/
|
||||
int
|
||||
xfs_lowbit64(
|
||||
__uint64_t v)
|
||||
{
|
||||
__uint32_t w = (__uint32_t)v;
|
||||
int n = 0;
|
||||
|
||||
if (w) { /* lower bits */
|
||||
n = ffs(w);
|
||||
} else { /* upper bits */
|
||||
w = (__uint32_t)(v >> 32);
|
||||
if (w && (n = ffs(w)))
|
||||
n += 32;
|
||||
}
|
||||
return n - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set.
|
||||
*/
|
||||
int
|
||||
xfs_highbit64(
|
||||
__uint64_t v)
|
||||
{
|
||||
__uint32_t h = (__uint32_t)(v >> 32);
|
||||
|
||||
if (h)
|
||||
return xfs_highbit32(h) + 32;
|
||||
return xfs_highbit32((__uint32_t)v);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Count the number of bits set in the bitmap starting with bit
|
||||
* start_bit. Size is the size of the bitmap in words.
|
||||
*
|
||||
* Do the counting by mapping a byte value to the number of set
|
||||
* bits for that value using the xfs_countbit array, i.e.
|
||||
* xfs_countbit[0] == 0, xfs_countbit[1] == 1, xfs_countbit[2] == 1,
|
||||
* xfs_countbit[3] == 2, etc.
|
||||
*/
|
||||
int
|
||||
xfs_count_bits(uint *map, uint size, uint start_bit)
|
||||
{
|
||||
register int bits;
|
||||
register unsigned char *bytep;
|
||||
register unsigned char *end_map;
|
||||
int byte_bit;
|
||||
|
||||
bits = 0;
|
||||
end_map = (char*)(map + size);
|
||||
bytep = (char*)(map + (start_bit & ~0x7));
|
||||
byte_bit = start_bit & 0x7;
|
||||
|
||||
/*
|
||||
* If the caller fell off the end of the map, return 0.
|
||||
*/
|
||||
if (bytep >= end_map) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If start_bit is not byte aligned, then process the
|
||||
* first byte separately.
|
||||
*/
|
||||
if (byte_bit != 0) {
|
||||
/*
|
||||
* Shift off the bits we don't want to look at,
|
||||
* before indexing into xfs_countbit.
|
||||
*/
|
||||
bits += xfs_countbit[(*bytep >> byte_bit)];
|
||||
bytep++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the bits in each byte until the end of the bitmap.
|
||||
*/
|
||||
while (bytep < end_map) {
|
||||
bits += xfs_countbit[*bytep];
|
||||
bytep++;
|
||||
}
|
||||
|
||||
return (bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of contiguous bits set in the bitmap starting with bit
|
||||
* start_bit. Size is the size of the bitmap in words.
|
||||
*/
|
||||
int
|
||||
xfs_contig_bits(uint *map, uint size, uint start_bit)
|
||||
{
|
||||
uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT);
|
||||
uint result = 0;
|
||||
uint tmp;
|
||||
|
||||
size <<= BIT_TO_WORD_SHIFT;
|
||||
|
||||
ASSERT(start_bit < size);
|
||||
size -= start_bit & ~(NBWORD - 1);
|
||||
start_bit &= (NBWORD - 1);
|
||||
if (start_bit) {
|
||||
tmp = *p++;
|
||||
/* set to one first offset bits prior to start */
|
||||
tmp |= (~0U >> (NBWORD-start_bit));
|
||||
if (tmp != ~0U)
|
||||
goto found;
|
||||
result += NBWORD;
|
||||
size -= NBWORD;
|
||||
}
|
||||
while (size) {
|
||||
if ((tmp = *p++) != ~0U)
|
||||
goto found;
|
||||
result += NBWORD;
|
||||
size -= NBWORD;
|
||||
}
|
||||
return result - start_bit;
|
||||
found:
|
||||
return result + ffz(tmp) - start_bit;
|
||||
}
|
||||
|
||||
/*
|
||||
* This takes the bit number to start looking from and
|
||||
* returns the next set bit from there. It returns -1
|
||||
* if there are no more bits set or the start bit is
|
||||
* beyond the end of the bitmap.
|
||||
*
|
||||
* Size is the number of words, not bytes, in the bitmap.
|
||||
*/
|
||||
int xfs_next_bit(uint *map, uint size, uint start_bit)
|
||||
{
|
||||
uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT);
|
||||
uint result = start_bit & ~(NBWORD - 1);
|
||||
uint tmp;
|
||||
|
||||
size <<= BIT_TO_WORD_SHIFT;
|
||||
|
||||
if (start_bit >= size)
|
||||
return -1;
|
||||
size -= result;
|
||||
start_bit &= (NBWORD - 1);
|
||||
if (start_bit) {
|
||||
tmp = *p++;
|
||||
/* set to zero first offset bits prior to start */
|
||||
tmp &= (~0U << start_bit);
|
||||
if (tmp != 0U)
|
||||
goto found;
|
||||
result += NBWORD;
|
||||
size -= NBWORD;
|
||||
}
|
||||
while (size) {
|
||||
if ((tmp = *p++) != 0U)
|
||||
goto found;
|
||||
result += NBWORD;
|
||||
size -= NBWORD;
|
||||
}
|
||||
return -1;
|
||||
found:
|
||||
return result + ffs(tmp) - 1;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_BIT_H__
|
||||
#define __XFS_BIT_H__
|
||||
|
||||
/*
|
||||
* XFS bit manipulation routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* masks with n high/low bits set, 32-bit values & 64-bit values
|
||||
*/
|
||||
#define XFS_MASK32HI(n) xfs_mask32hi(n)
|
||||
static inline __uint32_t xfs_mask32hi(int n)
|
||||
{
|
||||
return (__uint32_t)-1 << (32 - (n));
|
||||
}
|
||||
#define XFS_MASK64HI(n) xfs_mask64hi(n)
|
||||
static inline __uint64_t xfs_mask64hi(int n)
|
||||
{
|
||||
return (__uint64_t)-1 << (64 - (n));
|
||||
}
|
||||
#define XFS_MASK32LO(n) xfs_mask32lo(n)
|
||||
static inline __uint32_t xfs_mask32lo(int n)
|
||||
{
|
||||
return ((__uint32_t)1 << (n)) - 1;
|
||||
}
|
||||
#define XFS_MASK64LO(n) xfs_mask64lo(n)
|
||||
static inline __uint64_t xfs_mask64lo(int n)
|
||||
{
|
||||
return ((__uint64_t)1 << (n)) - 1;
|
||||
}
|
||||
|
||||
/* Get high bit set out of 32-bit argument, -1 if none set */
|
||||
extern int xfs_highbit32(__uint32_t v);
|
||||
|
||||
/* Get low bit set out of 64-bit argument, -1 if none set */
|
||||
extern int xfs_lowbit64(__uint64_t v);
|
||||
|
||||
/* Get high bit set out of 64-bit argument, -1 if none set */
|
||||
extern int xfs_highbit64(__uint64_t);
|
||||
|
||||
/* Count set bits in map starting with start_bit */
|
||||
extern int xfs_count_bits(uint *map, uint size, uint start_bit);
|
||||
|
||||
/* Count continuous one bits in map starting with start_bit */
|
||||
extern int xfs_contig_bits(uint *map, uint size, uint start_bit);
|
||||
|
||||
/* Find next set bit in map */
|
||||
extern int xfs_next_bit(uint *map, uint size, uint start_bit);
|
||||
|
||||
#endif /* __XFS_BIT_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,386 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2006 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_BMAP_H__
|
||||
#define __XFS_BMAP_H__
|
||||
|
||||
struct getbmap;
|
||||
struct xfs_bmbt_irec;
|
||||
struct xfs_ifork;
|
||||
struct xfs_inode;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* DELTA: describe a change to the in-core extent list.
|
||||
*
|
||||
* Internally the use of xed_blockount is somewhat funky.
|
||||
* xed_blockcount contains an offset much of the time because this
|
||||
* makes merging changes easier. (xfs_fileoff_t and xfs_filblks_t are
|
||||
* the same underlying type).
|
||||
*/
|
||||
typedef struct xfs_extdelta
|
||||
{
|
||||
xfs_fileoff_t xed_startoff; /* offset of range */
|
||||
xfs_filblks_t xed_blockcount; /* blocks in range */
|
||||
} xfs_extdelta_t;
|
||||
|
||||
/*
|
||||
* List of extents to be free "later".
|
||||
* The list is kept sorted on xbf_startblock.
|
||||
*/
|
||||
typedef struct xfs_bmap_free_item
|
||||
{
|
||||
xfs_fsblock_t xbfi_startblock;/* starting fs block number */
|
||||
xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */
|
||||
struct xfs_bmap_free_item *xbfi_next; /* link to next entry */
|
||||
} xfs_bmap_free_item_t;
|
||||
|
||||
/*
|
||||
* Header for free extent list.
|
||||
*/
|
||||
typedef struct xfs_bmap_free
|
||||
{
|
||||
xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */
|
||||
int xbf_count; /* count of items on list */
|
||||
int xbf_low; /* kludge: alloc in low mode */
|
||||
} xfs_bmap_free_t;
|
||||
|
||||
#define XFS_BMAP_MAX_NMAP 4
|
||||
|
||||
/*
|
||||
* Flags for xfs_bmapi
|
||||
*/
|
||||
#define XFS_BMAPI_WRITE 0x001 /* write operation: allocate space */
|
||||
#define XFS_BMAPI_DELAY 0x002 /* delayed write operation */
|
||||
#define XFS_BMAPI_ENTIRE 0x004 /* return entire extent, not trimmed */
|
||||
#define XFS_BMAPI_METADATA 0x008 /* mapping metadata not user data */
|
||||
#define XFS_BMAPI_EXACT 0x010 /* allocate only to spec'd bounds */
|
||||
#define XFS_BMAPI_ATTRFORK 0x020 /* use attribute fork not data */
|
||||
#define XFS_BMAPI_ASYNC 0x040 /* bunmapi xactions can be async */
|
||||
#define XFS_BMAPI_RSVBLOCKS 0x080 /* OK to alloc. reserved data blocks */
|
||||
#define XFS_BMAPI_PREALLOC 0x100 /* preallocation op: unwritten space */
|
||||
#define XFS_BMAPI_IGSTATE 0x200 /* Ignore state - */
|
||||
/* combine contig. space */
|
||||
#define XFS_BMAPI_CONTIG 0x400 /* must allocate only one extent */
|
||||
/* XFS_BMAPI_DIRECT_IO 0x800 */
|
||||
#define XFS_BMAPI_CONVERT 0x1000 /* unwritten extent conversion - */
|
||||
/* need write cache flushing and no */
|
||||
/* additional allocation alignments */
|
||||
|
||||
#define XFS_BMAPI_AFLAG(w) xfs_bmapi_aflag(w)
|
||||
static inline int xfs_bmapi_aflag(int w)
|
||||
{
|
||||
return (w == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special values for xfs_bmbt_irec_t br_startblock field.
|
||||
*/
|
||||
#define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL)
|
||||
#define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL)
|
||||
|
||||
#define XFS_BMAP_INIT(flp,fbp) xfs_bmap_init(flp,fbp)
|
||||
static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp)
|
||||
{
|
||||
((flp)->xbf_first = NULL, (flp)->xbf_count = 0, \
|
||||
(flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Argument structure for xfs_bmap_alloc.
|
||||
*/
|
||||
typedef struct xfs_bmalloca {
|
||||
xfs_fsblock_t firstblock; /* i/o first block allocated */
|
||||
xfs_fsblock_t rval; /* starting block of new extent */
|
||||
xfs_fileoff_t off; /* offset in file filling in */
|
||||
struct xfs_trans *tp; /* transaction pointer */
|
||||
struct xfs_inode *ip; /* incore inode pointer */
|
||||
struct xfs_bmbt_irec *prevp; /* extent before the new one */
|
||||
struct xfs_bmbt_irec *gotp; /* extent after, or delayed */
|
||||
xfs_extlen_t alen; /* i/o length asked/allocated */
|
||||
xfs_extlen_t total; /* total blocks needed for xaction */
|
||||
xfs_extlen_t minlen; /* mininum allocation size (blocks) */
|
||||
xfs_extlen_t minleft; /* amount must be left after alloc */
|
||||
char eof; /* set if allocating past last extent */
|
||||
char wasdel; /* replacing a delayed allocation */
|
||||
char userdata;/* set if is user data */
|
||||
char low; /* low on space, using seq'l ags */
|
||||
char aeof; /* allocated space at eof */
|
||||
char conv; /* overwriting unwritten extents */
|
||||
} xfs_bmalloca_t;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#if defined(XFS_BMAP_TRACE)
|
||||
/*
|
||||
* Trace operations for bmap extent tracing
|
||||
*/
|
||||
#define XFS_BMAP_KTRACE_DELETE 1
|
||||
#define XFS_BMAP_KTRACE_INSERT 2
|
||||
#define XFS_BMAP_KTRACE_PRE_UP 3
|
||||
#define XFS_BMAP_KTRACE_POST_UP 4
|
||||
|
||||
#define XFS_BMAP_TRACE_SIZE 4096 /* size of global trace buffer */
|
||||
#define XFS_BMAP_KTRACE_SIZE 32 /* size of per-inode trace buffer */
|
||||
extern ktrace_t *xfs_bmap_trace_buf;
|
||||
|
||||
/*
|
||||
* Add bmap trace insert entries for all the contents of the extent list.
|
||||
*/
|
||||
void
|
||||
xfs_bmap_trace_exlist(
|
||||
char *fname, /* function name */
|
||||
struct xfs_inode *ip, /* incore inode pointer */
|
||||
xfs_extnum_t cnt, /* count of entries in list */
|
||||
int whichfork); /* data or attr fork */
|
||||
#else
|
||||
#define xfs_bmap_trace_exlist(f,ip,c,w)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convert inode from non-attributed to attributed.
|
||||
* Must not be in a transaction, ip must not be locked.
|
||||
*/
|
||||
int /* error code */
|
||||
xfs_bmap_add_attrfork(
|
||||
struct xfs_inode *ip, /* incore inode pointer */
|
||||
int size, /* space needed for new attribute */
|
||||
int rsvd); /* flag for reserved block allocation */
|
||||
|
||||
/*
|
||||
* Add the extent to the list of extents to be free at transaction end.
|
||||
* The list is maintained sorted (by block number).
|
||||
*/
|
||||
void
|
||||
xfs_bmap_add_free(
|
||||
xfs_fsblock_t bno, /* fs block number of extent */
|
||||
xfs_filblks_t len, /* length of extent */
|
||||
xfs_bmap_free_t *flist, /* list of extents */
|
||||
struct xfs_mount *mp); /* mount point structure */
|
||||
|
||||
/*
|
||||
* Routine to clean up the free list data structure when
|
||||
* an error occurs during a transaction.
|
||||
*/
|
||||
void
|
||||
xfs_bmap_cancel(
|
||||
xfs_bmap_free_t *flist); /* free list to clean up */
|
||||
|
||||
/*
|
||||
* Compute and fill in the value of the maximum depth of a bmap btree
|
||||
* in this filesystem. Done once, during mount.
|
||||
*/
|
||||
void
|
||||
xfs_bmap_compute_maxlevels(
|
||||
struct xfs_mount *mp, /* file system mount structure */
|
||||
int whichfork); /* data or attr fork */
|
||||
|
||||
/*
|
||||
* Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
|
||||
* caller. Frees all the extents that need freeing, which must be done
|
||||
* last due to locking considerations.
|
||||
*
|
||||
* Return 1 if the given transaction was committed and a new one allocated,
|
||||
* and 0 otherwise.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmap_finish(
|
||||
struct xfs_trans **tp, /* transaction pointer addr */
|
||||
xfs_bmap_free_t *flist, /* i/o: list extents to free */
|
||||
xfs_fsblock_t firstblock, /* controlled a.g. for allocs */
|
||||
int *committed); /* xact committed or not */
|
||||
|
||||
/*
|
||||
* Returns the file-relative block number of the first unused block in the file.
|
||||
* This is the lowest-address hole if the file has holes, else the first block
|
||||
* past the end of file.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmap_first_unused(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
xfs_extlen_t len, /* size of hole to find */
|
||||
xfs_fileoff_t *unused, /* unused block num */
|
||||
int whichfork); /* data or attr fork */
|
||||
|
||||
/*
|
||||
* Returns the file-relative block number of the last block + 1 before
|
||||
* last_block (input value) in the file.
|
||||
* This is not based on i_size, it is based on the extent list.
|
||||
* Returns 0 for local files, as they do not have an extent list.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmap_last_before(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
xfs_fileoff_t *last_block, /* last block */
|
||||
int whichfork); /* data or attr fork */
|
||||
|
||||
/*
|
||||
* Returns the file-relative block number of the first block past eof in
|
||||
* the file. This is not based on i_size, it is based on the extent list.
|
||||
* Returns 0 for local files, as they do not have an extent list.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmap_last_offset(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
xfs_fileoff_t *unused, /* last block num */
|
||||
int whichfork); /* data or attr fork */
|
||||
|
||||
/*
|
||||
* Returns whether the selected fork of the inode has exactly one
|
||||
* block or not. For the data fork we check this matches di_size,
|
||||
* implying the file's range is 0..bsize-1.
|
||||
*/
|
||||
int
|
||||
xfs_bmap_one_block(
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
int whichfork); /* data or attr fork */
|
||||
|
||||
/*
|
||||
* Read in the extents to iu_extents.
|
||||
* All inode fields are set up by caller, we just traverse the btree
|
||||
* and copy the records in.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmap_read_extents(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
int whichfork); /* data or attr fork */
|
||||
|
||||
/*
|
||||
* Map file blocks to filesystem blocks.
|
||||
* File range is given by the bno/len pair.
|
||||
* Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set)
|
||||
* into a hole or past eof.
|
||||
* Only allocates blocks from a single allocation group,
|
||||
* to avoid locking problems.
|
||||
* The returned value in "firstblock" from the first call in a transaction
|
||||
* must be remembered and presented to subsequent calls in "firstblock".
|
||||
* An upper bound for the number of blocks to be allocated is supplied to
|
||||
* the first call in "total"; if no allocation group has that many free
|
||||
* blocks then the call will fail (return NULLFSBLOCK in "firstblock").
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmapi(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
xfs_fileoff_t bno, /* starting file offs. mapped */
|
||||
xfs_filblks_t len, /* length to map in file */
|
||||
int flags, /* XFS_BMAPI_... */
|
||||
xfs_fsblock_t *firstblock, /* first allocated block
|
||||
controls a.g. for allocs */
|
||||
xfs_extlen_t total, /* total blocks needed */
|
||||
struct xfs_bmbt_irec *mval, /* output: map values */
|
||||
int *nmap, /* i/o: mval size/count */
|
||||
xfs_bmap_free_t *flist, /* i/o: list extents to free */
|
||||
xfs_extdelta_t *delta); /* o: change made to incore
|
||||
extents */
|
||||
|
||||
/*
|
||||
* Map file blocks to filesystem blocks, simple version.
|
||||
* One block only, read-only.
|
||||
* For flags, only the XFS_BMAPI_ATTRFORK flag is examined.
|
||||
* For the other flag values, the effect is as if XFS_BMAPI_METADATA
|
||||
* was set and all the others were clear.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmapi_single(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
int whichfork, /* data or attr fork */
|
||||
xfs_fsblock_t *fsb, /* output: mapped block */
|
||||
xfs_fileoff_t bno); /* starting file offs. mapped */
|
||||
|
||||
/*
|
||||
* Unmap (remove) blocks from a file.
|
||||
* If nexts is nonzero then the number of extents to remove is limited to
|
||||
* that value. If not all extents in the block range can be removed then
|
||||
* *done is set.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bunmapi(
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_inode *ip, /* incore inode */
|
||||
xfs_fileoff_t bno, /* starting offset to unmap */
|
||||
xfs_filblks_t len, /* length to unmap in file */
|
||||
int flags, /* XFS_BMAPI_... */
|
||||
xfs_extnum_t nexts, /* number of extents max */
|
||||
xfs_fsblock_t *firstblock, /* first allocated block
|
||||
controls a.g. for allocs */
|
||||
xfs_bmap_free_t *flist, /* i/o: list extents to free */
|
||||
xfs_extdelta_t *delta, /* o: change made to incore
|
||||
extents */
|
||||
int *done); /* set if not done yet */
|
||||
|
||||
/*
|
||||
* Fcntl interface to xfs_bmapi.
|
||||
*/
|
||||
int /* error code */
|
||||
xfs_getbmap(
|
||||
bhv_desc_t *bdp, /* XFS behavior descriptor*/
|
||||
struct getbmap *bmv, /* user bmap structure */
|
||||
void __user *ap, /* pointer to user's array */
|
||||
int iflags); /* interface flags */
|
||||
|
||||
/*
|
||||
* Check if the endoff is outside the last extent. If so the caller will grow
|
||||
* the allocation to a stripe unit boundary
|
||||
*/
|
||||
int
|
||||
xfs_bmap_eof(
|
||||
struct xfs_inode *ip,
|
||||
xfs_fileoff_t endoff,
|
||||
int whichfork,
|
||||
int *eof);
|
||||
|
||||
/*
|
||||
* Count fsblocks of the given fork.
|
||||
*/
|
||||
int
|
||||
xfs_bmap_count_blocks(
|
||||
xfs_trans_t *tp,
|
||||
struct xfs_inode *ip,
|
||||
int whichfork,
|
||||
int *count);
|
||||
|
||||
/*
|
||||
* Check an extent list, which has just been read, for
|
||||
* any bit in the extent flag field.
|
||||
*/
|
||||
int
|
||||
xfs_check_nostate_extents(
|
||||
struct xfs_ifork *ifp,
|
||||
xfs_extnum_t idx,
|
||||
xfs_extnum_t num);
|
||||
|
||||
/*
|
||||
* Search the extent records for the entry containing block bno.
|
||||
* If bno lies in a hole, point to the next entry. If bno lies
|
||||
* past eof, *eofp will be set, and *prevp will contain the last
|
||||
* entry (null if none). Else, *lastxp will be set to the index
|
||||
* of the found entry; *gotp will contain the entry.
|
||||
*/
|
||||
xfs_bmbt_rec_t *
|
||||
xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *,
|
||||
xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_BMAP_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_BMAP_BTREE_H__
|
||||
#define __XFS_BMAP_BTREE_H__
|
||||
|
||||
#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */
|
||||
|
||||
struct xfs_btree_cur;
|
||||
struct xfs_btree_lblock;
|
||||
struct xfs_mount;
|
||||
struct xfs_inode;
|
||||
|
||||
/*
|
||||
* Bmap root header, on-disk form only.
|
||||
*/
|
||||
typedef struct xfs_bmdr_block {
|
||||
__be16 bb_level; /* 0 is a leaf */
|
||||
__be16 bb_numrecs; /* current # of data records */
|
||||
} xfs_bmdr_block_t;
|
||||
|
||||
/*
|
||||
* Bmap btree record and extent descriptor.
|
||||
* For 32-bit kernels,
|
||||
* l0:31 is an extent flag (value 1 indicates non-normal).
|
||||
* l0:0-30 and l1:9-31 are startoff.
|
||||
* l1:0-8, l2:0-31, and l3:21-31 are startblock.
|
||||
* l3:0-20 are blockcount.
|
||||
* For 64-bit kernels,
|
||||
* l0:63 is an extent flag (value 1 indicates non-normal).
|
||||
* l0:9-62 are startoff.
|
||||
* l0:0-8 and l1:21-63 are startblock.
|
||||
* l1:0-20 are blockcount.
|
||||
*/
|
||||
|
||||
#ifndef XFS_NATIVE_HOST
|
||||
|
||||
#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */
|
||||
#define BMBT_EXNTFLAG_BITOFF 0
|
||||
#define BMBT_EXNTFLAG_BITLEN 1
|
||||
#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF + BMBT_EXNTFLAG_BITLEN)
|
||||
#define BMBT_STARTOFF_BITLEN 54
|
||||
#define BMBT_STARTBLOCK_BITOFF (BMBT_STARTOFF_BITOFF + BMBT_STARTOFF_BITLEN)
|
||||
#define BMBT_STARTBLOCK_BITLEN 52
|
||||
#define BMBT_BLOCKCOUNT_BITOFF \
|
||||
(BMBT_STARTBLOCK_BITOFF + BMBT_STARTBLOCK_BITLEN)
|
||||
#define BMBT_BLOCKCOUNT_BITLEN (BMBT_TOTAL_BITLEN - BMBT_BLOCKCOUNT_BITOFF)
|
||||
|
||||
#else
|
||||
|
||||
#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */
|
||||
#define BMBT_EXNTFLAG_BITOFF 63
|
||||
#define BMBT_EXNTFLAG_BITLEN 1
|
||||
#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF - BMBT_STARTOFF_BITLEN)
|
||||
#define BMBT_STARTOFF_BITLEN 54
|
||||
#define BMBT_STARTBLOCK_BITOFF 85 /* 128 - 43 (other 9 is in first word) */
|
||||
#define BMBT_STARTBLOCK_BITLEN 52
|
||||
#define BMBT_BLOCKCOUNT_BITOFF 64 /* Start of second 64 bit container */
|
||||
#define BMBT_BLOCKCOUNT_BITLEN 21
|
||||
|
||||
#endif /* XFS_NATIVE_HOST */
|
||||
|
||||
|
||||
#define BMBT_USE_64 1
|
||||
|
||||
typedef struct xfs_bmbt_rec_32
|
||||
{
|
||||
__uint32_t l0, l1, l2, l3;
|
||||
} xfs_bmbt_rec_32_t;
|
||||
typedef struct xfs_bmbt_rec_64
|
||||
{
|
||||
__uint64_t l0, l1;
|
||||
} xfs_bmbt_rec_64_t;
|
||||
|
||||
typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */
|
||||
typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
|
||||
|
||||
/*
|
||||
* Values and macros for delayed-allocation startblock fields.
|
||||
*/
|
||||
#define STARTBLOCKVALBITS 17
|
||||
#define STARTBLOCKMASKBITS (15 + XFS_BIG_BLKNOS * 20)
|
||||
#define DSTARTBLOCKMASKBITS (15 + 20)
|
||||
#define STARTBLOCKMASK \
|
||||
(((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS)
|
||||
#define DSTARTBLOCKMASK \
|
||||
(((((xfs_dfsbno_t)1) << DSTARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS)
|
||||
|
||||
#define ISNULLSTARTBLOCK(x) isnullstartblock(x)
|
||||
static inline int isnullstartblock(xfs_fsblock_t x)
|
||||
{
|
||||
return ((x) & STARTBLOCKMASK) == STARTBLOCKMASK;
|
||||
}
|
||||
|
||||
#define ISNULLDSTARTBLOCK(x) isnulldstartblock(x)
|
||||
static inline int isnulldstartblock(xfs_dfsbno_t x)
|
||||
{
|
||||
return ((x) & DSTARTBLOCKMASK) == DSTARTBLOCKMASK;
|
||||
}
|
||||
|
||||
#define NULLSTARTBLOCK(k) nullstartblock(k)
|
||||
static inline xfs_fsblock_t nullstartblock(int k)
|
||||
{
|
||||
ASSERT(k < (1 << STARTBLOCKVALBITS));
|
||||
return STARTBLOCKMASK | (k);
|
||||
}
|
||||
|
||||
#define STARTBLOCKVAL(x) startblockval(x)
|
||||
static inline xfs_filblks_t startblockval(xfs_fsblock_t x)
|
||||
{
|
||||
return (xfs_filblks_t)((x) & ~STARTBLOCKMASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Possible extent formats.
|
||||
*/
|
||||
typedef enum {
|
||||
XFS_EXTFMT_NOSTATE = 0,
|
||||
XFS_EXTFMT_HASSTATE
|
||||
} xfs_exntfmt_t;
|
||||
|
||||
/*
|
||||
* Possible extent states.
|
||||
*/
|
||||
typedef enum {
|
||||
XFS_EXT_NORM, XFS_EXT_UNWRITTEN,
|
||||
XFS_EXT_DMAPI_OFFLINE, XFS_EXT_INVALID
|
||||
} xfs_exntst_t;
|
||||
|
||||
/*
|
||||
* Extent state and extent format macros.
|
||||
*/
|
||||
#define XFS_EXTFMT_INODE(x) \
|
||||
(XFS_SB_VERSION_HASEXTFLGBIT(&((x)->i_mount->m_sb)) ? \
|
||||
XFS_EXTFMT_HASSTATE : XFS_EXTFMT_NOSTATE)
|
||||
#define ISUNWRITTEN(x) ((x)->br_state == XFS_EXT_UNWRITTEN)
|
||||
|
||||
/*
|
||||
* Incore version of above.
|
||||
*/
|
||||
typedef struct xfs_bmbt_irec
|
||||
{
|
||||
xfs_fileoff_t br_startoff; /* starting file offset */
|
||||
xfs_fsblock_t br_startblock; /* starting block number */
|
||||
xfs_filblks_t br_blockcount; /* number of blocks */
|
||||
xfs_exntst_t br_state; /* extent state */
|
||||
} xfs_bmbt_irec_t;
|
||||
|
||||
/*
|
||||
* Key structure for non-leaf levels of the tree.
|
||||
*/
|
||||
typedef struct xfs_bmbt_key
|
||||
{
|
||||
xfs_dfiloff_t br_startoff; /* starting file offset */
|
||||
} xfs_bmbt_key_t, xfs_bmdr_key_t;
|
||||
|
||||
typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */
|
||||
/* btree block header type */
|
||||
typedef struct xfs_btree_lblock xfs_bmbt_block_t;
|
||||
|
||||
#define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
#define XFS_BMAP_IBLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog)
|
||||
#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) ((cur)->bc_private.b.forksize)
|
||||
#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) \
|
||||
((int)XFS_IFORK_PTR((cur)->bc_private.b.ip, \
|
||||
(cur)->bc_private.b.whichfork)->if_broot_bytes)
|
||||
|
||||
#define XFS_BMAP_BLOCK_DSIZE(lev,cur) \
|
||||
(((lev) == (cur)->bc_nlevels - 1 ? \
|
||||
XFS_BMAP_RBLOCK_DSIZE(lev,cur) : XFS_BMAP_IBLOCK_SIZE(lev,cur)))
|
||||
#define XFS_BMAP_BLOCK_ISIZE(lev,cur) \
|
||||
(((lev) == (cur)->bc_nlevels - 1 ? \
|
||||
XFS_BMAP_RBLOCK_ISIZE(lev,cur) : XFS_BMAP_IBLOCK_SIZE(lev,cur)))
|
||||
|
||||
#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) \
|
||||
(((lev) == (cur)->bc_nlevels - 1 ? \
|
||||
XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \
|
||||
xfs_bmdr, (lev) == 0) : \
|
||||
((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])))
|
||||
#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) \
|
||||
(((lev) == (cur)->bc_nlevels - 1 ? \
|
||||
XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur),\
|
||||
xfs_bmbt, (lev) == 0) : \
|
||||
((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])))
|
||||
|
||||
#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) \
|
||||
(((lev) == (cur)->bc_nlevels - 1 ? \
|
||||
XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur),\
|
||||
xfs_bmdr, (lev) == 0) : \
|
||||
((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])))
|
||||
#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) \
|
||||
(((lev) == (cur)->bc_nlevels - 1 ? \
|
||||
XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur),\
|
||||
xfs_bmbt, (lev) == 0) : \
|
||||
((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])))
|
||||
|
||||
#define XFS_BMAP_REC_DADDR(bb,i,cur) \
|
||||
(XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_DSIZE( \
|
||||
be16_to_cpu((bb)->bb_level), cur), \
|
||||
xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \
|
||||
be16_to_cpu((bb)->bb_level), cur)))
|
||||
#define XFS_BMAP_REC_IADDR(bb,i,cur) \
|
||||
(XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_ISIZE( \
|
||||
be16_to_cpu((bb)->bb_level), cur), \
|
||||
xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \
|
||||
be16_to_cpu((bb)->bb_level), cur)))
|
||||
|
||||
#define XFS_BMAP_KEY_DADDR(bb,i,cur) \
|
||||
(XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_DSIZE( \
|
||||
be16_to_cpu((bb)->bb_level), cur), \
|
||||
xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \
|
||||
be16_to_cpu((bb)->bb_level), cur)))
|
||||
#define XFS_BMAP_KEY_IADDR(bb,i,cur) \
|
||||
(XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_ISIZE( \
|
||||
be16_to_cpu((bb)->bb_level), cur), \
|
||||
xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \
|
||||
be16_to_cpu((bb)->bb_level), cur)))
|
||||
|
||||
#define XFS_BMAP_PTR_DADDR(bb,i,cur) \
|
||||
(XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_DSIZE( \
|
||||
be16_to_cpu((bb)->bb_level), cur), \
|
||||
xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \
|
||||
be16_to_cpu((bb)->bb_level), cur)))
|
||||
#define XFS_BMAP_PTR_IADDR(bb,i,cur) \
|
||||
(XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_ISIZE( \
|
||||
be16_to_cpu((bb)->bb_level), cur), \
|
||||
xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \
|
||||
be16_to_cpu((bb)->bb_level), cur)))
|
||||
|
||||
/*
|
||||
* These are to be used when we know the size of the block and
|
||||
* we don't have a cursor.
|
||||
*/
|
||||
#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) \
|
||||
(XFS_BTREE_REC_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)))
|
||||
#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) \
|
||||
(XFS_BTREE_KEY_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)))
|
||||
#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) \
|
||||
(XFS_BTREE_PTR_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)))
|
||||
|
||||
#define XFS_BMAP_BROOT_NUMRECS(bb) be16_to_cpu((bb)->bb_numrecs)
|
||||
#define XFS_BMAP_BROOT_MAXRECS(sz) XFS_BTREE_BLOCK_MAXRECS(sz,xfs_bmbt,0)
|
||||
|
||||
#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \
|
||||
(int)(sizeof(xfs_bmbt_block_t) + \
|
||||
((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
|
||||
|
||||
#define XFS_BMAP_BROOT_SPACE(bb) \
|
||||
(XFS_BMAP_BROOT_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs)))
|
||||
#define XFS_BMDR_SPACE_CALC(nrecs) \
|
||||
(int)(sizeof(xfs_bmdr_block_t) + \
|
||||
((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
|
||||
|
||||
/*
|
||||
* Maximum number of bmap btree levels.
|
||||
*/
|
||||
#define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[(w)])
|
||||
|
||||
#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \
|
||||
(be32_to_cpu((bb)->bb_magic) == XFS_BMAP_MAGIC && \
|
||||
be16_to_cpu((bb)->bb_level) == level && \
|
||||
be16_to_cpu((bb)->bb_numrecs) > 0 && \
|
||||
be16_to_cpu((bb)->bb_numrecs) <= (mp)->m_bmap_dmxr[(level) != 0])
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#if defined(XFS_BMBT_TRACE)
|
||||
/*
|
||||
* Trace buffer entry types.
|
||||
*/
|
||||
#define XFS_BMBT_KTRACE_ARGBI 1
|
||||
#define XFS_BMBT_KTRACE_ARGBII 2
|
||||
#define XFS_BMBT_KTRACE_ARGFFFI 3
|
||||
#define XFS_BMBT_KTRACE_ARGI 4
|
||||
#define XFS_BMBT_KTRACE_ARGIFK 5
|
||||
#define XFS_BMBT_KTRACE_ARGIFR 6
|
||||
#define XFS_BMBT_KTRACE_ARGIK 7
|
||||
#define XFS_BMBT_KTRACE_CUR 8
|
||||
|
||||
#define XFS_BMBT_TRACE_SIZE 4096 /* size of global trace buffer */
|
||||
#define XFS_BMBT_KTRACE_SIZE 32 /* size of per-inode trace buffer */
|
||||
extern ktrace_t *xfs_bmbt_trace_buf;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prototypes for xfs_bmap.c to call.
|
||||
*/
|
||||
extern void xfs_bmdr_to_bmbt(xfs_bmdr_block_t *, int, xfs_bmbt_block_t *, int);
|
||||
extern int xfs_bmbt_decrement(struct xfs_btree_cur *, int, int *);
|
||||
extern int xfs_bmbt_delete(struct xfs_btree_cur *, int *);
|
||||
extern void xfs_bmbt_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
|
||||
extern xfs_bmbt_block_t *xfs_bmbt_get_block(struct xfs_btree_cur *cur,
|
||||
int, struct xfs_buf **bpp);
|
||||
extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_t *r);
|
||||
extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_t *r);
|
||||
extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_t *r);
|
||||
extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_t *r);
|
||||
|
||||
#ifndef XFS_NATIVE_HOST
|
||||
extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
|
||||
extern xfs_exntst_t xfs_bmbt_disk_get_state(xfs_bmbt_rec_t *r);
|
||||
extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r);
|
||||
extern xfs_fsblock_t xfs_bmbt_disk_get_startblock(xfs_bmbt_rec_t *r);
|
||||
extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r);
|
||||
#else
|
||||
#define xfs_bmbt_disk_get_all(r, s) xfs_bmbt_get_all(r, s)
|
||||
#define xfs_bmbt_disk_get_state(r) xfs_bmbt_get_state(r)
|
||||
#define xfs_bmbt_disk_get_blockcount(r) xfs_bmbt_get_blockcount(r)
|
||||
#define xfs_bmbt_disk_get_startblock(r) xfs_bmbt_get_blockcount(r)
|
||||
#define xfs_bmbt_disk_get_startoff(r) xfs_bmbt_get_startoff(r)
|
||||
#endif /* XFS_NATIVE_HOST */
|
||||
|
||||
extern int xfs_bmbt_increment(struct xfs_btree_cur *, int, int *);
|
||||
extern int xfs_bmbt_insert(struct xfs_btree_cur *, int *);
|
||||
extern void xfs_bmbt_log_block(struct xfs_btree_cur *, struct xfs_buf *, int);
|
||||
extern void xfs_bmbt_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int,
|
||||
int);
|
||||
extern int xfs_bmbt_lookup_eq(struct xfs_btree_cur *, xfs_fileoff_t,
|
||||
xfs_fsblock_t, xfs_filblks_t, int *);
|
||||
extern int xfs_bmbt_lookup_ge(struct xfs_btree_cur *, xfs_fileoff_t,
|
||||
xfs_fsblock_t, xfs_filblks_t, int *);
|
||||
|
||||
/*
|
||||
* Give the bmap btree a new root block. Copy the old broot contents
|
||||
* down into a real block and make the broot point to it.
|
||||
*/
|
||||
extern int xfs_bmbt_newroot(struct xfs_btree_cur *cur, int *lflags, int *stat);
|
||||
|
||||
extern void xfs_bmbt_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
|
||||
extern void xfs_bmbt_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o,
|
||||
xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v);
|
||||
extern void xfs_bmbt_set_blockcount(xfs_bmbt_rec_t *r, xfs_filblks_t v);
|
||||
extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_t *r, xfs_fsblock_t v);
|
||||
extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_t *r, xfs_fileoff_t v);
|
||||
extern void xfs_bmbt_set_state(xfs_bmbt_rec_t *r, xfs_exntst_t v);
|
||||
|
||||
#ifndef XFS_NATIVE_HOST
|
||||
extern void xfs_bmbt_disk_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
|
||||
extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o,
|
||||
xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v);
|
||||
#else
|
||||
#define xfs_bmbt_disk_set_all(r, s) xfs_bmbt_set_all(r, s)
|
||||
#define xfs_bmbt_disk_set_allf(r, o, b, c, v) xfs_bmbt_set_allf(r, o, b, c, v)
|
||||
#endif /* XFS_NATIVE_HOST */
|
||||
|
||||
extern void xfs_bmbt_to_bmdr(xfs_bmbt_block_t *, int, xfs_bmdr_block_t *, int);
|
||||
extern int xfs_bmbt_update(struct xfs_btree_cur *, xfs_fileoff_t,
|
||||
xfs_fsblock_t, xfs_filblks_t, xfs_exntst_t);
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Get the data from the pointed-to record.
|
||||
*/
|
||||
extern int xfs_bmbt_get_rec(struct xfs_btree_cur *, xfs_fileoff_t *,
|
||||
xfs_fsblock_t *, xfs_filblks_t *,
|
||||
xfs_exntst_t *, int *);
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_BMAP_BTREE_H__ */
|
@ -1,943 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_types.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_inum.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_bmap_btree.h"
|
||||
#include "xfs_alloc_btree.h"
|
||||
#include "xfs_ialloc_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_ialloc.h"
|
||||
#include "xfs_error.h"
|
||||
|
||||
/*
|
||||
* Cursor allocation zone.
|
||||
*/
|
||||
kmem_zone_t *xfs_btree_cur_zone;
|
||||
|
||||
/*
|
||||
* Btree magic numbers.
|
||||
*/
|
||||
const __uint32_t xfs_magics[XFS_BTNUM_MAX] =
|
||||
{
|
||||
XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC
|
||||
};
|
||||
|
||||
/*
|
||||
* Prototypes for internal routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Checking routine: return maxrecs for the block.
|
||||
*/
|
||||
STATIC int /* number of records fitting in block */
|
||||
xfs_btree_maxrecs(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_block_t *block);/* generic btree block pointer */
|
||||
|
||||
/*
|
||||
* Internal routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Retrieve the block pointer from the cursor at the given level.
|
||||
* This may be a bmap btree root or from a buffer.
|
||||
*/
|
||||
STATIC xfs_btree_block_t * /* generic btree block pointer */
|
||||
xfs_btree_get_block(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level, /* level in btree */
|
||||
struct xfs_buf **bpp); /* buffer containing the block */
|
||||
|
||||
/*
|
||||
* Checking routine: return maxrecs for the block.
|
||||
*/
|
||||
STATIC int /* number of records fitting in block */
|
||||
xfs_btree_maxrecs(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_block_t *block) /* generic btree block pointer */
|
||||
{
|
||||
switch (cur->bc_btnum) {
|
||||
case XFS_BTNUM_BNO:
|
||||
case XFS_BTNUM_CNT:
|
||||
return (int)XFS_ALLOC_BLOCK_MAXRECS(
|
||||
be16_to_cpu(block->bb_h.bb_level), cur);
|
||||
case XFS_BTNUM_BMAP:
|
||||
return (int)XFS_BMAP_BLOCK_IMAXRECS(
|
||||
be16_to_cpu(block->bb_h.bb_level), cur);
|
||||
case XFS_BTNUM_INO:
|
||||
return (int)XFS_INOBT_BLOCK_MAXRECS(
|
||||
be16_to_cpu(block->bb_h.bb_level), cur);
|
||||
default:
|
||||
ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* External routines.
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Debug routine: check that block header is ok.
|
||||
*/
|
||||
void
|
||||
xfs_btree_check_block(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_block_t *block, /* generic btree block pointer */
|
||||
int level, /* level of the btree block */
|
||||
xfs_buf_t *bp) /* buffer containing block, if any */
|
||||
{
|
||||
if (XFS_BTREE_LONG_PTRS(cur->bc_btnum))
|
||||
xfs_btree_check_lblock(cur, (xfs_btree_lblock_t *)block, level,
|
||||
bp);
|
||||
else
|
||||
xfs_btree_check_sblock(cur, (xfs_btree_sblock_t *)block, level,
|
||||
bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug routine: check that keys are in the right order.
|
||||
*/
|
||||
void
|
||||
xfs_btree_check_key(
|
||||
xfs_btnum_t btnum, /* btree identifier */
|
||||
void *ak1, /* pointer to left (lower) key */
|
||||
void *ak2) /* pointer to right (higher) key */
|
||||
{
|
||||
switch (btnum) {
|
||||
case XFS_BTNUM_BNO: {
|
||||
xfs_alloc_key_t *k1;
|
||||
xfs_alloc_key_t *k2;
|
||||
|
||||
k1 = ak1;
|
||||
k2 = ak2;
|
||||
ASSERT(be32_to_cpu(k1->ar_startblock) < be32_to_cpu(k2->ar_startblock));
|
||||
break;
|
||||
}
|
||||
case XFS_BTNUM_CNT: {
|
||||
xfs_alloc_key_t *k1;
|
||||
xfs_alloc_key_t *k2;
|
||||
|
||||
k1 = ak1;
|
||||
k2 = ak2;
|
||||
ASSERT(be32_to_cpu(k1->ar_blockcount) < be32_to_cpu(k2->ar_blockcount) ||
|
||||
(k1->ar_blockcount == k2->ar_blockcount &&
|
||||
be32_to_cpu(k1->ar_startblock) < be32_to_cpu(k2->ar_startblock)));
|
||||
break;
|
||||
}
|
||||
case XFS_BTNUM_BMAP: {
|
||||
xfs_bmbt_key_t *k1;
|
||||
xfs_bmbt_key_t *k2;
|
||||
|
||||
k1 = ak1;
|
||||
k2 = ak2;
|
||||
ASSERT(INT_GET(k1->br_startoff, ARCH_CONVERT) < INT_GET(k2->br_startoff, ARCH_CONVERT));
|
||||
break;
|
||||
}
|
||||
case XFS_BTNUM_INO: {
|
||||
xfs_inobt_key_t *k1;
|
||||
xfs_inobt_key_t *k2;
|
||||
|
||||
k1 = ak1;
|
||||
k2 = ak2;
|
||||
ASSERT(INT_GET(k1->ir_startino, ARCH_CONVERT) < INT_GET(k2->ir_startino, ARCH_CONVERT));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* Checking routine: check that long form block header is ok.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_lblock(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_lblock_t *block, /* btree long form block pointer */
|
||||
int level, /* level of the btree block */
|
||||
xfs_buf_t *bp) /* buffer for block, if any */
|
||||
{
|
||||
int lblock_ok; /* block passes checks */
|
||||
xfs_mount_t *mp; /* file system mount point */
|
||||
|
||||
mp = cur->bc_mp;
|
||||
lblock_ok =
|
||||
be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] &&
|
||||
be16_to_cpu(block->bb_level) == level &&
|
||||
be16_to_cpu(block->bb_numrecs) <=
|
||||
xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) &&
|
||||
block->bb_leftsib &&
|
||||
(be64_to_cpu(block->bb_leftsib) == NULLDFSBNO ||
|
||||
XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_leftsib))) &&
|
||||
block->bb_rightsib &&
|
||||
(be64_to_cpu(block->bb_rightsib) == NULLDFSBNO ||
|
||||
XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_rightsib)));
|
||||
if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK,
|
||||
XFS_RANDOM_BTREE_CHECK_LBLOCK))) {
|
||||
if (bp)
|
||||
xfs_buftrace("LBTREE ERROR", bp);
|
||||
XFS_ERROR_REPORT("xfs_btree_check_lblock", XFS_ERRLEVEL_LOW,
|
||||
mp);
|
||||
return XFS_ERROR(EFSCORRUPTED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checking routine: check that (long) pointer is ok.
|
||||
*/
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_lptr(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_dfsbno_t ptr, /* btree block disk address */
|
||||
int level) /* btree block level */
|
||||
{
|
||||
xfs_mount_t *mp; /* file system mount point */
|
||||
|
||||
mp = cur->bc_mp;
|
||||
XFS_WANT_CORRUPTED_RETURN(
|
||||
level > 0 &&
|
||||
ptr != NULLDFSBNO &&
|
||||
XFS_FSB_SANITY_CHECK(mp, ptr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Debug routine: check that records are in the right order.
|
||||
*/
|
||||
void
|
||||
xfs_btree_check_rec(
|
||||
xfs_btnum_t btnum, /* btree identifier */
|
||||
void *ar1, /* pointer to left (lower) record */
|
||||
void *ar2) /* pointer to right (higher) record */
|
||||
{
|
||||
switch (btnum) {
|
||||
case XFS_BTNUM_BNO: {
|
||||
xfs_alloc_rec_t *r1;
|
||||
xfs_alloc_rec_t *r2;
|
||||
|
||||
r1 = ar1;
|
||||
r2 = ar2;
|
||||
ASSERT(be32_to_cpu(r1->ar_startblock) +
|
||||
be32_to_cpu(r1->ar_blockcount) <=
|
||||
be32_to_cpu(r2->ar_startblock));
|
||||
break;
|
||||
}
|
||||
case XFS_BTNUM_CNT: {
|
||||
xfs_alloc_rec_t *r1;
|
||||
xfs_alloc_rec_t *r2;
|
||||
|
||||
r1 = ar1;
|
||||
r2 = ar2;
|
||||
ASSERT(be32_to_cpu(r1->ar_blockcount) < be32_to_cpu(r2->ar_blockcount) ||
|
||||
(r1->ar_blockcount == r2->ar_blockcount &&
|
||||
be32_to_cpu(r1->ar_startblock) < be32_to_cpu(r2->ar_startblock)));
|
||||
break;
|
||||
}
|
||||
case XFS_BTNUM_BMAP: {
|
||||
xfs_bmbt_rec_t *r1;
|
||||
xfs_bmbt_rec_t *r2;
|
||||
|
||||
r1 = ar1;
|
||||
r2 = ar2;
|
||||
ASSERT(xfs_bmbt_disk_get_startoff(r1) +
|
||||
xfs_bmbt_disk_get_blockcount(r1) <=
|
||||
xfs_bmbt_disk_get_startoff(r2));
|
||||
break;
|
||||
}
|
||||
case XFS_BTNUM_INO: {
|
||||
xfs_inobt_rec_t *r1;
|
||||
xfs_inobt_rec_t *r2;
|
||||
|
||||
r1 = ar1;
|
||||
r2 = ar2;
|
||||
ASSERT(INT_GET(r1->ir_startino, ARCH_CONVERT) + XFS_INODES_PER_CHUNK <=
|
||||
INT_GET(r2->ir_startino, ARCH_CONVERT));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* Checking routine: check that block header is ok.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_sblock(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_sblock_t *block, /* btree short form block pointer */
|
||||
int level, /* level of the btree block */
|
||||
xfs_buf_t *bp) /* buffer containing block */
|
||||
{
|
||||
xfs_buf_t *agbp; /* buffer for ag. freespace struct */
|
||||
xfs_agf_t *agf; /* ag. freespace structure */
|
||||
xfs_agblock_t agflen; /* native ag. freespace length */
|
||||
int sblock_ok; /* block passes checks */
|
||||
|
||||
agbp = cur->bc_private.a.agbp;
|
||||
agf = XFS_BUF_TO_AGF(agbp);
|
||||
agflen = be32_to_cpu(agf->agf_length);
|
||||
sblock_ok =
|
||||
be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] &&
|
||||
be16_to_cpu(block->bb_level) == level &&
|
||||
be16_to_cpu(block->bb_numrecs) <=
|
||||
xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) &&
|
||||
(be32_to_cpu(block->bb_leftsib) == NULLAGBLOCK ||
|
||||
be32_to_cpu(block->bb_leftsib) < agflen) &&
|
||||
block->bb_leftsib &&
|
||||
(be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK ||
|
||||
be32_to_cpu(block->bb_rightsib) < agflen) &&
|
||||
block->bb_rightsib;
|
||||
if (unlikely(XFS_TEST_ERROR(!sblock_ok, cur->bc_mp,
|
||||
XFS_ERRTAG_BTREE_CHECK_SBLOCK,
|
||||
XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
|
||||
if (bp)
|
||||
xfs_buftrace("SBTREE ERROR", bp);
|
||||
XFS_ERROR_REPORT("xfs_btree_check_sblock", XFS_ERRLEVEL_LOW,
|
||||
cur->bc_mp);
|
||||
return XFS_ERROR(EFSCORRUPTED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checking routine: check that (short) pointer is ok.
|
||||
*/
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_sptr(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_agblock_t ptr, /* btree block disk address */
|
||||
int level) /* btree block level */
|
||||
{
|
||||
xfs_buf_t *agbp; /* buffer for ag. freespace struct */
|
||||
xfs_agf_t *agf; /* ag. freespace structure */
|
||||
|
||||
agbp = cur->bc_private.a.agbp;
|
||||
agf = XFS_BUF_TO_AGF(agbp);
|
||||
XFS_WANT_CORRUPTED_RETURN(
|
||||
level > 0 &&
|
||||
ptr != NULLAGBLOCK && ptr != 0 &&
|
||||
ptr < be32_to_cpu(agf->agf_length));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete the btree cursor.
|
||||
*/
|
||||
void
|
||||
xfs_btree_del_cursor(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int error) /* del because of error */
|
||||
{
|
||||
int i; /* btree level */
|
||||
|
||||
/*
|
||||
* Clear the buffer pointers, and release the buffers.
|
||||
* If we're doing this in the face of an error, we
|
||||
* need to make sure to inspect all of the entries
|
||||
* in the bc_bufs array for buffers to be unlocked.
|
||||
* This is because some of the btree code works from
|
||||
* level n down to 0, and if we get an error along
|
||||
* the way we won't have initialized all the entries
|
||||
* down to 0.
|
||||
*/
|
||||
for (i = 0; i < cur->bc_nlevels; i++) {
|
||||
if (cur->bc_bufs[i])
|
||||
xfs_btree_setbuf(cur, i, NULL);
|
||||
else if (!error)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Can't free a bmap cursor without having dealt with the
|
||||
* allocated indirect blocks' accounting.
|
||||
*/
|
||||
ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP ||
|
||||
cur->bc_private.b.allocated == 0);
|
||||
/*
|
||||
* Free the cursor.
|
||||
*/
|
||||
kmem_zone_free(xfs_btree_cur_zone, cur);
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate the btree cursor.
|
||||
* Allocate a new one, copy the record, re-get the buffers.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_btree_dup_cursor(
|
||||
xfs_btree_cur_t *cur, /* input cursor */
|
||||
xfs_btree_cur_t **ncur) /* output cursor */
|
||||
{
|
||||
xfs_buf_t *bp; /* btree block's buffer pointer */
|
||||
int error; /* error return value */
|
||||
int i; /* level number of btree block */
|
||||
xfs_mount_t *mp; /* mount structure for filesystem */
|
||||
xfs_btree_cur_t *new; /* new cursor value */
|
||||
xfs_trans_t *tp; /* transaction pointer, can be NULL */
|
||||
|
||||
tp = cur->bc_tp;
|
||||
mp = cur->bc_mp;
|
||||
/*
|
||||
* Allocate a new cursor like the old one.
|
||||
*/
|
||||
new = xfs_btree_init_cursor(mp, tp, cur->bc_private.a.agbp,
|
||||
cur->bc_private.a.agno, cur->bc_btnum, cur->bc_private.b.ip,
|
||||
cur->bc_private.b.whichfork);
|
||||
/*
|
||||
* Copy the record currently in the cursor.
|
||||
*/
|
||||
new->bc_rec = cur->bc_rec;
|
||||
/*
|
||||
* For each level current, re-get the buffer and copy the ptr value.
|
||||
*/
|
||||
for (i = 0; i < new->bc_nlevels; i++) {
|
||||
new->bc_ptrs[i] = cur->bc_ptrs[i];
|
||||
new->bc_ra[i] = cur->bc_ra[i];
|
||||
if ((bp = cur->bc_bufs[i])) {
|
||||
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
|
||||
XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) {
|
||||
xfs_btree_del_cursor(new, error);
|
||||
*ncur = NULL;
|
||||
return error;
|
||||
}
|
||||
new->bc_bufs[i] = bp;
|
||||
ASSERT(bp);
|
||||
ASSERT(!XFS_BUF_GETERROR(bp));
|
||||
} else
|
||||
new->bc_bufs[i] = NULL;
|
||||
}
|
||||
/*
|
||||
* For bmap btrees, copy the firstblock, flist, and flags values,
|
||||
* since init cursor doesn't get them.
|
||||
*/
|
||||
if (new->bc_btnum == XFS_BTNUM_BMAP) {
|
||||
new->bc_private.b.firstblock = cur->bc_private.b.firstblock;
|
||||
new->bc_private.b.flist = cur->bc_private.b.flist;
|
||||
new->bc_private.b.flags = cur->bc_private.b.flags;
|
||||
}
|
||||
*ncur = new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the cursor to point to the first record at the given level.
|
||||
* Other levels are unaffected.
|
||||
*/
|
||||
int /* success=1, failure=0 */
|
||||
xfs_btree_firstrec(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level) /* level to change */
|
||||
{
|
||||
xfs_btree_block_t *block; /* generic btree block pointer */
|
||||
xfs_buf_t *bp; /* buffer containing block */
|
||||
|
||||
/*
|
||||
* Get the block pointer for this level.
|
||||
*/
|
||||
block = xfs_btree_get_block(cur, level, &bp);
|
||||
xfs_btree_check_block(cur, block, level, bp);
|
||||
/*
|
||||
* It's empty, there is no such record.
|
||||
*/
|
||||
if (!block->bb_h.bb_numrecs)
|
||||
return 0;
|
||||
/*
|
||||
* Set the ptr value to 1, that's the first record/key.
|
||||
*/
|
||||
cur->bc_ptrs[level] = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the block pointer from the cursor at the given level.
|
||||
* This may be a bmap btree root or from a buffer.
|
||||
*/
|
||||
STATIC xfs_btree_block_t * /* generic btree block pointer */
|
||||
xfs_btree_get_block(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level, /* level in btree */
|
||||
xfs_buf_t **bpp) /* buffer containing the block */
|
||||
{
|
||||
xfs_btree_block_t *block; /* return value */
|
||||
xfs_buf_t *bp; /* return buffer */
|
||||
xfs_ifork_t *ifp; /* inode fork pointer */
|
||||
int whichfork; /* data or attr fork */
|
||||
|
||||
if (cur->bc_btnum == XFS_BTNUM_BMAP && level == cur->bc_nlevels - 1) {
|
||||
whichfork = cur->bc_private.b.whichfork;
|
||||
ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, whichfork);
|
||||
block = (xfs_btree_block_t *)ifp->if_broot;
|
||||
bp = NULL;
|
||||
} else {
|
||||
bp = cur->bc_bufs[level];
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
}
|
||||
ASSERT(block != NULL);
|
||||
*bpp = bp;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it with no data read.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
xfs_buf_t * /* buffer for fsbno */
|
||||
xfs_btree_get_bufl(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock) /* lock flags for get_buf */
|
||||
{
|
||||
xfs_buf_t *bp; /* buffer pointer (return value) */
|
||||
xfs_daddr_t d; /* real disk block address */
|
||||
|
||||
ASSERT(fsbno != NULLFSBLOCK);
|
||||
d = XFS_FSB_TO_DADDR(mp, fsbno);
|
||||
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
|
||||
ASSERT(bp);
|
||||
ASSERT(!XFS_BUF_GETERROR(bp));
|
||||
return bp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it with no data read.
|
||||
* Short-form addressing.
|
||||
*/
|
||||
xfs_buf_t * /* buffer for agno/agbno */
|
||||
xfs_btree_get_bufs(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
uint lock) /* lock flags for get_buf */
|
||||
{
|
||||
xfs_buf_t *bp; /* buffer pointer (return value) */
|
||||
xfs_daddr_t d; /* real disk block address */
|
||||
|
||||
ASSERT(agno != NULLAGNUMBER);
|
||||
ASSERT(agbno != NULLAGBLOCK);
|
||||
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
|
||||
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
|
||||
ASSERT(bp);
|
||||
ASSERT(!XFS_BUF_GETERROR(bp));
|
||||
return bp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new btree cursor.
|
||||
* The cursor is either for allocation (A) or bmap (B) or inodes (I).
|
||||
*/
|
||||
xfs_btree_cur_t * /* new btree cursor */
|
||||
xfs_btree_init_cursor(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_buf_t *agbp, /* (A only) buffer for agf structure */
|
||||
/* (I only) buffer for agi structure */
|
||||
xfs_agnumber_t agno, /* (AI only) allocation group number */
|
||||
xfs_btnum_t btnum, /* btree identifier */
|
||||
xfs_inode_t *ip, /* (B only) inode owning the btree */
|
||||
int whichfork) /* (B only) data or attr fork */
|
||||
{
|
||||
xfs_agf_t *agf; /* (A) allocation group freespace */
|
||||
xfs_agi_t *agi; /* (I) allocation group inodespace */
|
||||
xfs_btree_cur_t *cur; /* return value */
|
||||
xfs_ifork_t *ifp; /* (I) inode fork pointer */
|
||||
int nlevels=0; /* number of levels in the btree */
|
||||
|
||||
ASSERT(xfs_btree_cur_zone != NULL);
|
||||
/*
|
||||
* Allocate a new cursor.
|
||||
*/
|
||||
cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
|
||||
/*
|
||||
* Deduce the number of btree levels from the arguments.
|
||||
*/
|
||||
switch (btnum) {
|
||||
case XFS_BTNUM_BNO:
|
||||
case XFS_BTNUM_CNT:
|
||||
agf = XFS_BUF_TO_AGF(agbp);
|
||||
nlevels = be32_to_cpu(agf->agf_levels[btnum]);
|
||||
break;
|
||||
case XFS_BTNUM_BMAP:
|
||||
ifp = XFS_IFORK_PTR(ip, whichfork);
|
||||
nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
|
||||
break;
|
||||
case XFS_BTNUM_INO:
|
||||
agi = XFS_BUF_TO_AGI(agbp);
|
||||
nlevels = be32_to_cpu(agi->agi_level);
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
/*
|
||||
* Fill in the common fields.
|
||||
*/
|
||||
cur->bc_tp = tp;
|
||||
cur->bc_mp = mp;
|
||||
cur->bc_nlevels = nlevels;
|
||||
cur->bc_btnum = btnum;
|
||||
cur->bc_blocklog = mp->m_sb.sb_blocklog;
|
||||
/*
|
||||
* Fill in private fields.
|
||||
*/
|
||||
switch (btnum) {
|
||||
case XFS_BTNUM_BNO:
|
||||
case XFS_BTNUM_CNT:
|
||||
/*
|
||||
* Allocation btree fields.
|
||||
*/
|
||||
cur->bc_private.a.agbp = agbp;
|
||||
cur->bc_private.a.agno = agno;
|
||||
break;
|
||||
case XFS_BTNUM_BMAP:
|
||||
/*
|
||||
* Bmap btree fields.
|
||||
*/
|
||||
cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
|
||||
cur->bc_private.b.ip = ip;
|
||||
cur->bc_private.b.firstblock = NULLFSBLOCK;
|
||||
cur->bc_private.b.flist = NULL;
|
||||
cur->bc_private.b.allocated = 0;
|
||||
cur->bc_private.b.flags = 0;
|
||||
cur->bc_private.b.whichfork = whichfork;
|
||||
break;
|
||||
case XFS_BTNUM_INO:
|
||||
/*
|
||||
* Inode allocation btree fields.
|
||||
*/
|
||||
cur->bc_private.i.agbp = agbp;
|
||||
cur->bc_private.i.agno = agno;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for the cursor referring to the last block at the given level.
|
||||
*/
|
||||
int /* 1=is last block, 0=not last block */
|
||||
xfs_btree_islastblock(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level) /* level to check */
|
||||
{
|
||||
xfs_btree_block_t *block; /* generic btree block pointer */
|
||||
xfs_buf_t *bp; /* buffer containing block */
|
||||
|
||||
block = xfs_btree_get_block(cur, level, &bp);
|
||||
xfs_btree_check_block(cur, block, level, bp);
|
||||
if (XFS_BTREE_LONG_PTRS(cur->bc_btnum))
|
||||
return be64_to_cpu(block->bb_u.l.bb_rightsib) == NULLDFSBNO;
|
||||
else
|
||||
return be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the cursor to point to the last record in the current block
|
||||
* at the given level. Other levels are unaffected.
|
||||
*/
|
||||
int /* success=1, failure=0 */
|
||||
xfs_btree_lastrec(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level) /* level to change */
|
||||
{
|
||||
xfs_btree_block_t *block; /* generic btree block pointer */
|
||||
xfs_buf_t *bp; /* buffer containing block */
|
||||
|
||||
/*
|
||||
* Get the block pointer for this level.
|
||||
*/
|
||||
block = xfs_btree_get_block(cur, level, &bp);
|
||||
xfs_btree_check_block(cur, block, level, bp);
|
||||
/*
|
||||
* It's empty, there is no such record.
|
||||
*/
|
||||
if (!block->bb_h.bb_numrecs)
|
||||
return 0;
|
||||
/*
|
||||
* Set the ptr value to numrecs, that's the last record/key.
|
||||
*/
|
||||
cur->bc_ptrs[level] = be16_to_cpu(block->bb_h.bb_numrecs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute first and last byte offsets for the fields given.
|
||||
* Interprets the offsets table, which contains struct field offsets.
|
||||
*/
|
||||
void
|
||||
xfs_btree_offsets(
|
||||
__int64_t fields, /* bitmask of fields */
|
||||
const short *offsets, /* table of field offsets */
|
||||
int nbits, /* number of bits to inspect */
|
||||
int *first, /* output: first byte offset */
|
||||
int *last) /* output: last byte offset */
|
||||
{
|
||||
int i; /* current bit number */
|
||||
__int64_t imask; /* mask for current bit number */
|
||||
|
||||
ASSERT(fields != 0);
|
||||
/*
|
||||
* Find the lowest bit, so the first byte offset.
|
||||
*/
|
||||
for (i = 0, imask = 1LL; ; i++, imask <<= 1) {
|
||||
if (imask & fields) {
|
||||
*first = offsets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Find the highest bit, so the last byte offset.
|
||||
*/
|
||||
for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) {
|
||||
if (imask & fields) {
|
||||
*last = offsets[i + 1] - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it read in.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_btree_read_bufl(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
xfs_buf_t **bpp, /* buffer for fsbno */
|
||||
int refval) /* ref count value for buffer */
|
||||
{
|
||||
xfs_buf_t *bp; /* return value */
|
||||
xfs_daddr_t d; /* real disk block address */
|
||||
int error;
|
||||
|
||||
ASSERT(fsbno != NULLFSBLOCK);
|
||||
d = XFS_FSB_TO_DADDR(mp, fsbno);
|
||||
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
|
||||
mp->m_bsize, lock, &bp))) {
|
||||
return error;
|
||||
}
|
||||
ASSERT(!bp || !XFS_BUF_GETERROR(bp));
|
||||
if (bp != NULL) {
|
||||
XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
|
||||
}
|
||||
*bpp = bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it read in.
|
||||
* Short-form addressing.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_btree_read_bufs(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
xfs_buf_t **bpp, /* buffer for agno/agbno */
|
||||
int refval) /* ref count value for buffer */
|
||||
{
|
||||
xfs_buf_t *bp; /* return value */
|
||||
xfs_daddr_t d; /* real disk block address */
|
||||
int error;
|
||||
|
||||
ASSERT(agno != NULLAGNUMBER);
|
||||
ASSERT(agbno != NULLAGBLOCK);
|
||||
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
|
||||
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
|
||||
mp->m_bsize, lock, &bp))) {
|
||||
return error;
|
||||
}
|
||||
ASSERT(!bp || !XFS_BUF_GETERROR(bp));
|
||||
if (bp != NULL) {
|
||||
switch (refval) {
|
||||
case XFS_ALLOC_BTREE_REF:
|
||||
XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
|
||||
break;
|
||||
case XFS_INO_BTREE_REF:
|
||||
XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*bpp = bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read-ahead the block, don't wait for it, don't return a buffer.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
void
|
||||
xfs_btree_reada_bufl(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
xfs_extlen_t count) /* count of filesystem blocks */
|
||||
{
|
||||
xfs_daddr_t d;
|
||||
|
||||
ASSERT(fsbno != NULLFSBLOCK);
|
||||
d = XFS_FSB_TO_DADDR(mp, fsbno);
|
||||
xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read-ahead the block, don't wait for it, don't return a buffer.
|
||||
* Short-form addressing.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
void
|
||||
xfs_btree_reada_bufs(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
xfs_extlen_t count) /* count of filesystem blocks */
|
||||
{
|
||||
xfs_daddr_t d;
|
||||
|
||||
ASSERT(agno != NULLAGNUMBER);
|
||||
ASSERT(agbno != NULLAGBLOCK);
|
||||
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
|
||||
xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read-ahead btree blocks, at the given level.
|
||||
* Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA.
|
||||
*/
|
||||
int
|
||||
xfs_btree_readahead_core(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int lev, /* level in btree */
|
||||
int lr) /* left/right bits */
|
||||
{
|
||||
xfs_alloc_block_t *a;
|
||||
xfs_bmbt_block_t *b;
|
||||
xfs_inobt_block_t *i;
|
||||
int rval = 0;
|
||||
|
||||
ASSERT(cur->bc_bufs[lev] != NULL);
|
||||
cur->bc_ra[lev] |= lr;
|
||||
switch (cur->bc_btnum) {
|
||||
case XFS_BTNUM_BNO:
|
||||
case XFS_BTNUM_CNT:
|
||||
a = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]);
|
||||
if ((lr & XFS_BTCUR_LEFTRA) && be32_to_cpu(a->bb_leftsib) != NULLAGBLOCK) {
|
||||
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno,
|
||||
be32_to_cpu(a->bb_leftsib), 1);
|
||||
rval++;
|
||||
}
|
||||
if ((lr & XFS_BTCUR_RIGHTRA) && be32_to_cpu(a->bb_rightsib) != NULLAGBLOCK) {
|
||||
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno,
|
||||
be32_to_cpu(a->bb_rightsib), 1);
|
||||
rval++;
|
||||
}
|
||||
break;
|
||||
case XFS_BTNUM_BMAP:
|
||||
b = XFS_BUF_TO_BMBT_BLOCK(cur->bc_bufs[lev]);
|
||||
if ((lr & XFS_BTCUR_LEFTRA) && be64_to_cpu(b->bb_leftsib) != NULLDFSBNO) {
|
||||
xfs_btree_reada_bufl(cur->bc_mp, be64_to_cpu(b->bb_leftsib), 1);
|
||||
rval++;
|
||||
}
|
||||
if ((lr & XFS_BTCUR_RIGHTRA) && be64_to_cpu(b->bb_rightsib) != NULLDFSBNO) {
|
||||
xfs_btree_reada_bufl(cur->bc_mp, be64_to_cpu(b->bb_rightsib), 1);
|
||||
rval++;
|
||||
}
|
||||
break;
|
||||
case XFS_BTNUM_INO:
|
||||
i = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]);
|
||||
if ((lr & XFS_BTCUR_LEFTRA) && be32_to_cpu(i->bb_leftsib) != NULLAGBLOCK) {
|
||||
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno,
|
||||
be32_to_cpu(i->bb_leftsib), 1);
|
||||
rval++;
|
||||
}
|
||||
if ((lr & XFS_BTCUR_RIGHTRA) && be32_to_cpu(i->bb_rightsib) != NULLAGBLOCK) {
|
||||
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno,
|
||||
be32_to_cpu(i->bb_rightsib), 1);
|
||||
rval++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the buffer for level "lev" in the cursor to bp, releasing
|
||||
* any previous buffer.
|
||||
*/
|
||||
void
|
||||
xfs_btree_setbuf(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int lev, /* level in btree */
|
||||
xfs_buf_t *bp) /* new buffer to set */
|
||||
{
|
||||
xfs_btree_block_t *b; /* btree block */
|
||||
xfs_buf_t *obp; /* old buffer pointer */
|
||||
|
||||
obp = cur->bc_bufs[lev];
|
||||
if (obp)
|
||||
xfs_trans_brelse(cur->bc_tp, obp);
|
||||
cur->bc_bufs[lev] = bp;
|
||||
cur->bc_ra[lev] = 0;
|
||||
if (!bp)
|
||||
return;
|
||||
b = XFS_BUF_TO_BLOCK(bp);
|
||||
if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) {
|
||||
if (be64_to_cpu(b->bb_u.l.bb_leftsib) == NULLDFSBNO)
|
||||
cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA;
|
||||
if (be64_to_cpu(b->bb_u.l.bb_rightsib) == NULLDFSBNO)
|
||||
cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA;
|
||||
} else {
|
||||
if (be32_to_cpu(b->bb_u.s.bb_leftsib) == NULLAGBLOCK)
|
||||
cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA;
|
||||
if (be32_to_cpu(b->bb_u.s.bb_rightsib) == NULLAGBLOCK)
|
||||
cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA;
|
||||
}
|
||||
}
|
@ -1,473 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_BTREE_H__
|
||||
#define __XFS_BTREE_H__
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_bmap_free;
|
||||
struct xfs_inode;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* This nonsense is to make -wlint happy.
|
||||
*/
|
||||
#define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi)
|
||||
#define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi)
|
||||
#define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi)
|
||||
|
||||
#define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi)
|
||||
#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi)
|
||||
#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi)
|
||||
#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi)
|
||||
|
||||
/*
|
||||
* Short form header: space allocation btrees.
|
||||
*/
|
||||
typedef struct xfs_btree_sblock {
|
||||
__be32 bb_magic; /* magic number for block type */
|
||||
__be16 bb_level; /* 0 is a leaf */
|
||||
__be16 bb_numrecs; /* current # of data records */
|
||||
__be32 bb_leftsib; /* left sibling block or NULLAGBLOCK */
|
||||
__be32 bb_rightsib; /* right sibling block or NULLAGBLOCK */
|
||||
} xfs_btree_sblock_t;
|
||||
|
||||
/*
|
||||
* Long form header: bmap btrees.
|
||||
*/
|
||||
typedef struct xfs_btree_lblock {
|
||||
__be32 bb_magic; /* magic number for block type */
|
||||
__be16 bb_level; /* 0 is a leaf */
|
||||
__be16 bb_numrecs; /* current # of data records */
|
||||
__be64 bb_leftsib; /* left sibling block or NULLDFSBNO */
|
||||
__be64 bb_rightsib; /* right sibling block or NULLDFSBNO */
|
||||
} xfs_btree_lblock_t;
|
||||
|
||||
/*
|
||||
* Combined header and structure, used by common code.
|
||||
*/
|
||||
typedef struct xfs_btree_hdr
|
||||
{
|
||||
__be32 bb_magic; /* magic number for block type */
|
||||
__be16 bb_level; /* 0 is a leaf */
|
||||
__be16 bb_numrecs; /* current # of data records */
|
||||
} xfs_btree_hdr_t;
|
||||
|
||||
typedef struct xfs_btree_block {
|
||||
xfs_btree_hdr_t bb_h; /* header */
|
||||
union {
|
||||
struct {
|
||||
__be32 bb_leftsib;
|
||||
__be32 bb_rightsib;
|
||||
} s; /* short form pointers */
|
||||
struct {
|
||||
__be64 bb_leftsib;
|
||||
__be64 bb_rightsib;
|
||||
} l; /* long form pointers */
|
||||
} bb_u; /* rest */
|
||||
} xfs_btree_block_t;
|
||||
|
||||
/*
|
||||
* For logging record fields.
|
||||
*/
|
||||
#define XFS_BB_MAGIC 0x01
|
||||
#define XFS_BB_LEVEL 0x02
|
||||
#define XFS_BB_NUMRECS 0x04
|
||||
#define XFS_BB_LEFTSIB 0x08
|
||||
#define XFS_BB_RIGHTSIB 0x10
|
||||
#define XFS_BB_NUM_BITS 5
|
||||
#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1)
|
||||
|
||||
/*
|
||||
* Boolean to select which form of xfs_btree_block_t.bb_u to use.
|
||||
*/
|
||||
#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP)
|
||||
|
||||
/*
|
||||
* Magic numbers for btree blocks.
|
||||
*/
|
||||
extern const __uint32_t xfs_magics[];
|
||||
|
||||
/*
|
||||
* Maximum and minimum records in a btree block.
|
||||
* Given block size, type prefix, and leaf flag (0 or 1).
|
||||
* The divisor below is equivalent to lf ? (e1) : (e2) but that produces
|
||||
* compiler warnings.
|
||||
*/
|
||||
#define XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) \
|
||||
((int)(((bsz) - (uint)sizeof(t ## _block_t)) / \
|
||||
(((lf) * (uint)sizeof(t ## _rec_t)) + \
|
||||
((1 - (lf)) * \
|
||||
((uint)sizeof(t ## _key_t) + (uint)sizeof(t ## _ptr_t))))))
|
||||
#define XFS_BTREE_BLOCK_MINRECS(bsz,t,lf) \
|
||||
(XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) / 2)
|
||||
|
||||
/*
|
||||
* Record, key, and pointer address calculation macros.
|
||||
* Given block size, type prefix, block pointer, and index of requested entry
|
||||
* (first entry numbered 1).
|
||||
*/
|
||||
#define XFS_BTREE_REC_ADDR(bsz,t,bb,i,mxr) \
|
||||
((t ## _rec_t *)((char *)(bb) + sizeof(t ## _block_t) + \
|
||||
((i) - 1) * sizeof(t ## _rec_t)))
|
||||
#define XFS_BTREE_KEY_ADDR(bsz,t,bb,i,mxr) \
|
||||
((t ## _key_t *)((char *)(bb) + sizeof(t ## _block_t) + \
|
||||
((i) - 1) * sizeof(t ## _key_t)))
|
||||
#define XFS_BTREE_PTR_ADDR(bsz,t,bb,i,mxr) \
|
||||
((t ## _ptr_t *)((char *)(bb) + sizeof(t ## _block_t) + \
|
||||
(mxr) * sizeof(t ## _key_t) + ((i) - 1) * sizeof(t ## _ptr_t)))
|
||||
|
||||
#define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */
|
||||
|
||||
/*
|
||||
* Btree cursor structure.
|
||||
* This collects all information needed by the btree code in one place.
|
||||
*/
|
||||
typedef struct xfs_btree_cur
|
||||
{
|
||||
struct xfs_trans *bc_tp; /* transaction we're in, if any */
|
||||
struct xfs_mount *bc_mp; /* file system mount struct */
|
||||
union {
|
||||
xfs_alloc_rec_incore_t a;
|
||||
xfs_bmbt_irec_t b;
|
||||
xfs_inobt_rec_t i;
|
||||
} bc_rec; /* current insert/search record value */
|
||||
struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */
|
||||
int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */
|
||||
__uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */
|
||||
#define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */
|
||||
#define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */
|
||||
__uint8_t bc_nlevels; /* number of levels in the tree */
|
||||
__uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */
|
||||
xfs_btnum_t bc_btnum; /* identifies which btree type */
|
||||
union {
|
||||
struct { /* needed for BNO, CNT */
|
||||
struct xfs_buf *agbp; /* agf buffer pointer */
|
||||
xfs_agnumber_t agno; /* ag number */
|
||||
} a;
|
||||
struct { /* needed for BMAP */
|
||||
struct xfs_inode *ip; /* pointer to our inode */
|
||||
struct xfs_bmap_free *flist; /* list to free after */
|
||||
xfs_fsblock_t firstblock; /* 1st blk allocated */
|
||||
int allocated; /* count of alloced */
|
||||
short forksize; /* fork's inode space */
|
||||
char whichfork; /* data or attr fork */
|
||||
char flags; /* flags */
|
||||
#define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */
|
||||
} b;
|
||||
struct { /* needed for INO */
|
||||
struct xfs_buf *agbp; /* agi buffer pointer */
|
||||
xfs_agnumber_t agno; /* ag number */
|
||||
} i;
|
||||
} bc_private; /* per-btree type data */
|
||||
} xfs_btree_cur_t;
|
||||
|
||||
#define XFS_BTREE_NOERROR 0
|
||||
#define XFS_BTREE_ERROR 1
|
||||
|
||||
/*
|
||||
* Convert from buffer to btree block header.
|
||||
*/
|
||||
#define XFS_BUF_TO_BLOCK(bp) ((xfs_btree_block_t *)XFS_BUF_PTR(bp))
|
||||
#define XFS_BUF_TO_LBLOCK(bp) ((xfs_btree_lblock_t *)XFS_BUF_PTR(bp))
|
||||
#define XFS_BUF_TO_SBLOCK(bp) ((xfs_btree_sblock_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Debug routine: check that block header is ok.
|
||||
*/
|
||||
void
|
||||
xfs_btree_check_block(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_block_t *block, /* generic btree block pointer */
|
||||
int level, /* level of the btree block */
|
||||
struct xfs_buf *bp); /* buffer containing block, if any */
|
||||
|
||||
/*
|
||||
* Debug routine: check that keys are in the right order.
|
||||
*/
|
||||
void
|
||||
xfs_btree_check_key(
|
||||
xfs_btnum_t btnum, /* btree identifier */
|
||||
void *ak1, /* pointer to left (lower) key */
|
||||
void *ak2); /* pointer to right (higher) key */
|
||||
|
||||
/*
|
||||
* Debug routine: check that records are in the right order.
|
||||
*/
|
||||
void
|
||||
xfs_btree_check_rec(
|
||||
xfs_btnum_t btnum, /* btree identifier */
|
||||
void *ar1, /* pointer to left (lower) record */
|
||||
void *ar2); /* pointer to right (higher) record */
|
||||
#else
|
||||
#define xfs_btree_check_block(a,b,c,d)
|
||||
#define xfs_btree_check_key(a,b,c)
|
||||
#define xfs_btree_check_rec(a,b,c)
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* Checking routine: check that long form block header is ok.
|
||||
*/
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_lblock(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_lblock_t *block, /* btree long form block pointer */
|
||||
int level, /* level of the btree block */
|
||||
struct xfs_buf *bp); /* buffer containing block, if any */
|
||||
|
||||
/*
|
||||
* Checking routine: check that (long) pointer is ok.
|
||||
*/
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_lptr(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_dfsbno_t ptr, /* btree block disk address */
|
||||
int level); /* btree block level */
|
||||
|
||||
/*
|
||||
* Checking routine: check that short form block header is ok.
|
||||
*/
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_sblock(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_btree_sblock_t *block, /* btree short form block pointer */
|
||||
int level, /* level of the btree block */
|
||||
struct xfs_buf *bp); /* buffer containing block */
|
||||
|
||||
/*
|
||||
* Checking routine: check that (short) pointer is ok.
|
||||
*/
|
||||
int /* error (0 or EFSCORRUPTED) */
|
||||
xfs_btree_check_sptr(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
xfs_agblock_t ptr, /* btree block disk address */
|
||||
int level); /* btree block level */
|
||||
|
||||
/*
|
||||
* Delete the btree cursor.
|
||||
*/
|
||||
void
|
||||
xfs_btree_del_cursor(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int error); /* del because of error */
|
||||
|
||||
/*
|
||||
* Duplicate the btree cursor.
|
||||
* Allocate a new one, copy the record, re-get the buffers.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_btree_dup_cursor(
|
||||
xfs_btree_cur_t *cur, /* input cursor */
|
||||
xfs_btree_cur_t **ncur);/* output cursor */
|
||||
|
||||
/*
|
||||
* Change the cursor to point to the first record in the current block
|
||||
* at the given level. Other levels are unaffected.
|
||||
*/
|
||||
int /* success=1, failure=0 */
|
||||
xfs_btree_firstrec(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level); /* level to change */
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it with no data read.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
struct xfs_buf * /* buffer for fsbno */
|
||||
xfs_btree_get_bufl(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock); /* lock flags for get_buf */
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it with no data read.
|
||||
* Short-form addressing.
|
||||
*/
|
||||
struct xfs_buf * /* buffer for agno/agbno */
|
||||
xfs_btree_get_bufs(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
uint lock); /* lock flags for get_buf */
|
||||
|
||||
/*
|
||||
* Allocate a new btree cursor.
|
||||
* The cursor is either for allocation (A) or bmap (B).
|
||||
*/
|
||||
xfs_btree_cur_t * /* new btree cursor */
|
||||
xfs_btree_init_cursor(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
struct xfs_buf *agbp, /* (A only) buffer for agf structure */
|
||||
xfs_agnumber_t agno, /* (A only) allocation group number */
|
||||
xfs_btnum_t btnum, /* btree identifier */
|
||||
struct xfs_inode *ip, /* (B only) inode owning the btree */
|
||||
int whichfork); /* (B only) data/attr fork */
|
||||
|
||||
/*
|
||||
* Check for the cursor referring to the last block at the given level.
|
||||
*/
|
||||
int /* 1=is last block, 0=not last block */
|
||||
xfs_btree_islastblock(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level); /* level to check */
|
||||
|
||||
/*
|
||||
* Change the cursor to point to the last record in the current block
|
||||
* at the given level. Other levels are unaffected.
|
||||
*/
|
||||
int /* success=1, failure=0 */
|
||||
xfs_btree_lastrec(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level); /* level to change */
|
||||
|
||||
/*
|
||||
* Compute first and last byte offsets for the fields given.
|
||||
* Interprets the offsets table, which contains struct field offsets.
|
||||
*/
|
||||
void
|
||||
xfs_btree_offsets(
|
||||
__int64_t fields, /* bitmask of fields */
|
||||
const short *offsets,/* table of field offsets */
|
||||
int nbits, /* number of bits to inspect */
|
||||
int *first, /* output: first byte offset */
|
||||
int *last); /* output: last byte offset */
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it read in.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_btree_read_bufl(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
struct xfs_buf **bpp, /* buffer for fsbno */
|
||||
int refval);/* ref count value for buffer */
|
||||
|
||||
/*
|
||||
* Get a buffer for the block, return it read in.
|
||||
* Short-form addressing.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_btree_read_bufs(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
struct xfs_buf **bpp, /* buffer for agno/agbno */
|
||||
int refval);/* ref count value for buffer */
|
||||
|
||||
/*
|
||||
* Read-ahead the block, don't wait for it, don't return a buffer.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
void /* error */
|
||||
xfs_btree_reada_bufl(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
xfs_extlen_t count); /* count of filesystem blocks */
|
||||
|
||||
/*
|
||||
* Read-ahead the block, don't wait for it, don't return a buffer.
|
||||
* Short-form addressing.
|
||||
*/
|
||||
void /* error */
|
||||
xfs_btree_reada_bufs(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
xfs_extlen_t count); /* count of filesystem blocks */
|
||||
|
||||
/*
|
||||
* Read-ahead btree blocks, at the given level.
|
||||
* Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA.
|
||||
*/
|
||||
int /* readahead block count */
|
||||
xfs_btree_readahead_core(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int lev, /* level in btree */
|
||||
int lr); /* left/right bits */
|
||||
|
||||
static inline int /* readahead block count */
|
||||
xfs_btree_readahead(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int lev, /* level in btree */
|
||||
int lr) /* left/right bits */
|
||||
{
|
||||
if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev])
|
||||
return 0;
|
||||
|
||||
return xfs_btree_readahead_core(cur, lev, lr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the buffer for level "lev" in the cursor to bp, releasing
|
||||
* any previous buffer.
|
||||
*/
|
||||
void
|
||||
xfs_btree_setbuf(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int lev, /* level in btree */
|
||||
struct xfs_buf *bp); /* new buffer to set */
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
|
||||
/*
|
||||
* Min and max functions for extlen, agblock, fileoff, and filblks types.
|
||||
*/
|
||||
#define XFS_EXTLEN_MIN(a,b) \
|
||||
((xfs_extlen_t)(a) < (xfs_extlen_t)(b) ? \
|
||||
(xfs_extlen_t)(a) : (xfs_extlen_t)(b))
|
||||
#define XFS_EXTLEN_MAX(a,b) \
|
||||
((xfs_extlen_t)(a) > (xfs_extlen_t)(b) ? \
|
||||
(xfs_extlen_t)(a) : (xfs_extlen_t)(b))
|
||||
#define XFS_AGBLOCK_MIN(a,b) \
|
||||
((xfs_agblock_t)(a) < (xfs_agblock_t)(b) ? \
|
||||
(xfs_agblock_t)(a) : (xfs_agblock_t)(b))
|
||||
#define XFS_AGBLOCK_MAX(a,b) \
|
||||
((xfs_agblock_t)(a) > (xfs_agblock_t)(b) ? \
|
||||
(xfs_agblock_t)(a) : (xfs_agblock_t)(b))
|
||||
#define XFS_FILEOFF_MIN(a,b) \
|
||||
((xfs_fileoff_t)(a) < (xfs_fileoff_t)(b) ? \
|
||||
(xfs_fileoff_t)(a) : (xfs_fileoff_t)(b))
|
||||
#define XFS_FILEOFF_MAX(a,b) \
|
||||
((xfs_fileoff_t)(a) > (xfs_fileoff_t)(b) ? \
|
||||
(xfs_fileoff_t)(a) : (xfs_fileoff_t)(b))
|
||||
#define XFS_FILBLKS_MIN(a,b) \
|
||||
((xfs_filblks_t)(a) < (xfs_filblks_t)(b) ? \
|
||||
(xfs_filblks_t)(a) : (xfs_filblks_t)(b))
|
||||
#define XFS_FILBLKS_MAX(a,b) \
|
||||
((xfs_filblks_t)(a) > (xfs_filblks_t)(b) ? \
|
||||
(xfs_filblks_t)(a) : (xfs_filblks_t)(b))
|
||||
|
||||
#define XFS_FSB_SANITY_CHECK(mp,fsb) \
|
||||
(XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \
|
||||
XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks)
|
||||
|
||||
#endif /* __XFS_BTREE_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_BUF_ITEM_H__
|
||||
#define __XFS_BUF_ITEM_H__
|
||||
|
||||
/*
|
||||
* This is the structure used to lay out a buf log item in the
|
||||
* log. The data map describes which 128 byte chunks of the buffer
|
||||
* have been logged. This structure works only on buffers that
|
||||
* reside up to the first TB in the filesystem. These buffers are
|
||||
* generated only by pre-6.2 systems and are known as XFS_LI_6_1_BUF.
|
||||
*/
|
||||
typedef struct xfs_buf_log_format_v1 {
|
||||
unsigned short blf_type; /* buf log item type indicator */
|
||||
unsigned short blf_size; /* size of this item */
|
||||
__int32_t blf_blkno; /* starting blkno of this buf */
|
||||
ushort blf_flags; /* misc state */
|
||||
ushort blf_len; /* number of blocks in this buf */
|
||||
unsigned int blf_map_size; /* size of data bitmap in words */
|
||||
unsigned int blf_data_map[1];/* variable size bitmap of */
|
||||
/* regions of buffer in this item */
|
||||
} xfs_buf_log_format_v1_t;
|
||||
|
||||
/*
|
||||
* This is a form of the above structure with a 64 bit blkno field.
|
||||
* For 6.2 and beyond, this is XFS_LI_BUF. We use this to log everything.
|
||||
*/
|
||||
typedef struct xfs_buf_log_format_t {
|
||||
unsigned short blf_type; /* buf log item type indicator */
|
||||
unsigned short blf_size; /* size of this item */
|
||||
ushort blf_flags; /* misc state */
|
||||
ushort blf_len; /* number of blocks in this buf */
|
||||
__int64_t blf_blkno; /* starting blkno of this buf */
|
||||
unsigned int blf_map_size; /* size of data bitmap in words */
|
||||
unsigned int blf_data_map[1];/* variable size bitmap of */
|
||||
/* regions of buffer in this item */
|
||||
} xfs_buf_log_format_t;
|
||||
|
||||
/*
|
||||
* This flag indicates that the buffer contains on disk inodes
|
||||
* and requires special recovery handling.
|
||||
*/
|
||||
#define XFS_BLI_INODE_BUF 0x1
|
||||
/*
|
||||
* This flag indicates that the buffer should not be replayed
|
||||
* during recovery because its blocks are being freed.
|
||||
*/
|
||||
#define XFS_BLI_CANCEL 0x2
|
||||
/*
|
||||
* This flag indicates that the buffer contains on disk
|
||||
* user or group dquots and may require special recovery handling.
|
||||
*/
|
||||
#define XFS_BLI_UDQUOT_BUF 0x4
|
||||
#define XFS_BLI_PDQUOT_BUF 0x8
|
||||
#define XFS_BLI_GDQUOT_BUF 0x10
|
||||
|
||||
#define XFS_BLI_CHUNK 128
|
||||
#define XFS_BLI_SHIFT 7
|
||||
#define BIT_TO_WORD_SHIFT 5
|
||||
#define NBWORD (NBBY * sizeof(unsigned int))
|
||||
|
||||
/*
|
||||
* buf log item flags
|
||||
*/
|
||||
#define XFS_BLI_HOLD 0x01
|
||||
#define XFS_BLI_DIRTY 0x02
|
||||
#define XFS_BLI_STALE 0x04
|
||||
#define XFS_BLI_LOGGED 0x08
|
||||
#define XFS_BLI_INODE_ALLOC_BUF 0x10
|
||||
#define XFS_BLI_STALE_INODE 0x20
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct xfs_buf;
|
||||
struct ktrace;
|
||||
struct xfs_mount;
|
||||
struct xfs_buf_log_item;
|
||||
|
||||
#if defined(XFS_BLI_TRACE)
|
||||
#define XFS_BLI_TRACE_SIZE 32
|
||||
|
||||
void xfs_buf_item_trace(char *, struct xfs_buf_log_item *);
|
||||
#else
|
||||
#define xfs_buf_item_trace(id, bip)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the in core log item structure used to track information
|
||||
* needed to log buffers. It tracks how many times the lock has been
|
||||
* locked, and which 128 byte chunks of the buffer are dirty.
|
||||
*/
|
||||
typedef struct xfs_buf_log_item {
|
||||
xfs_log_item_t bli_item; /* common item structure */
|
||||
struct xfs_buf *bli_buf; /* real buffer pointer */
|
||||
unsigned int bli_flags; /* misc flags */
|
||||
unsigned int bli_recur; /* lock recursion count */
|
||||
atomic_t bli_refcount; /* cnt of tp refs */
|
||||
#ifdef XFS_BLI_TRACE
|
||||
struct ktrace *bli_trace; /* event trace buf */
|
||||
#endif
|
||||
#ifdef XFS_TRANS_DEBUG
|
||||
char *bli_orig; /* original buffer copy */
|
||||
char *bli_logged; /* bytes logged (bitmap) */
|
||||
#endif
|
||||
xfs_buf_log_format_t bli_format; /* in-log header */
|
||||
} xfs_buf_log_item_t;
|
||||
|
||||
/*
|
||||
* This structure is used during recovery to record the buf log
|
||||
* items which have been canceled and should not be replayed.
|
||||
*/
|
||||
typedef struct xfs_buf_cancel {
|
||||
xfs_daddr_t bc_blkno;
|
||||
uint bc_len;
|
||||
int bc_refcount;
|
||||
struct xfs_buf_cancel *bc_next;
|
||||
} xfs_buf_cancel_t;
|
||||
|
||||
void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
|
||||
void xfs_buf_item_relse(struct xfs_buf *);
|
||||
void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint);
|
||||
uint xfs_buf_item_dirty(xfs_buf_log_item_t *);
|
||||
void xfs_buf_attach_iodone(struct xfs_buf *,
|
||||
void(*)(struct xfs_buf *, xfs_log_item_t *),
|
||||
xfs_log_item_t *);
|
||||
void xfs_buf_iodone_callbacks(struct xfs_buf *);
|
||||
void xfs_buf_iodone(struct xfs_buf *, xfs_buf_log_item_t *);
|
||||
|
||||
#ifdef XFS_TRANS_DEBUG
|
||||
void
|
||||
xfs_buf_item_flush_log_debug(
|
||||
struct xfs_buf *bp,
|
||||
uint first,
|
||||
uint last);
|
||||
#else
|
||||
#define xfs_buf_item_flush_log_debug(bp, first, last)
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_BUF_ITEM_H__ */
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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"
|
||||
|
||||
STATIC int xfs_cap_allow_set(xfs_vnode_t *);
|
||||
|
||||
|
||||
/*
|
||||
* Test for existence of capability attribute as efficiently as possible.
|
||||
*/
|
||||
int
|
||||
xfs_cap_vhascap(
|
||||
xfs_vnode_t *vp)
|
||||
{
|
||||
int error;
|
||||
int len = sizeof(xfs_cap_set_t);
|
||||
int flags = ATTR_KERNOVAL|ATTR_ROOT;
|
||||
|
||||
XVOP_ATTR_GET(vp, SGI_CAP_LINUX, NULL, &len, flags, sys_cred, error);
|
||||
return (error == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from extended attribute representation to in-memory for XFS.
|
||||
*/
|
||||
STATIC int
|
||||
posix_cap_xattr_to_xfs(
|
||||
posix_cap_xattr *src,
|
||||
size_t size,
|
||||
xfs_cap_set_t *dest)
|
||||
{
|
||||
if (!src || !dest)
|
||||
return EINVAL;
|
||||
|
||||
if (src->c_version != cpu_to_le32(POSIX_CAP_XATTR_VERSION))
|
||||
return EINVAL;
|
||||
if (src->c_abiversion != cpu_to_le32(_LINUX_CAPABILITY_VERSION))
|
||||
return EINVAL;
|
||||
|
||||
if (size < sizeof(posix_cap_xattr))
|
||||
return EINVAL;
|
||||
|
||||
ASSERT(sizeof(dest->cap_effective) == sizeof(src->c_effective));
|
||||
|
||||
dest->cap_effective = src->c_effective;
|
||||
dest->cap_permitted = src->c_permitted;
|
||||
dest->cap_inheritable = src->c_inheritable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from in-memory XFS to extended attribute representation.
|
||||
*/
|
||||
STATIC int
|
||||
posix_cap_xfs_to_xattr(
|
||||
xfs_cap_set_t *src,
|
||||
posix_cap_xattr *xattr_cap,
|
||||
size_t size)
|
||||
{
|
||||
size_t new_size = posix_cap_xattr_size();
|
||||
|
||||
if (size < new_size)
|
||||
return -ERANGE;
|
||||
|
||||
ASSERT(sizeof(xattr_cap->c_effective) == sizeof(src->cap_effective));
|
||||
|
||||
xattr_cap->c_version = cpu_to_le32(POSIX_CAP_XATTR_VERSION);
|
||||
xattr_cap->c_abiversion = cpu_to_le32(_LINUX_CAPABILITY_VERSION);
|
||||
xattr_cap->c_effective = src->cap_effective;
|
||||
xattr_cap->c_permitted = src->cap_permitted;
|
||||
xattr_cap->c_inheritable= src->cap_inheritable;
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_cap_vget(
|
||||
xfs_vnode_t *vp,
|
||||
void *cap,
|
||||
size_t size)
|
||||
{
|
||||
int error;
|
||||
int len = sizeof(xfs_cap_set_t);
|
||||
int flags = ATTR_ROOT;
|
||||
xfs_cap_set_t xfs_cap = { 0 };
|
||||
posix_cap_xattr *xattr_cap = cap;
|
||||
char *data = (char *)&xfs_cap;
|
||||
|
||||
VN_HOLD(vp);
|
||||
if ((error = _MAC_VACCESS(vp, NULL, VREAD)))
|
||||
goto out;
|
||||
|
||||
if (!size) {
|
||||
flags |= ATTR_KERNOVAL;
|
||||
data = NULL;
|
||||
}
|
||||
XVOP_ATTR_GET(vp, SGI_CAP_LINUX, data, &len, flags, sys_cred, error);
|
||||
if (error)
|
||||
goto out;
|
||||
ASSERT(len == sizeof(xfs_cap_set_t));
|
||||
|
||||
error = (size)? -posix_cap_xattr_size() :
|
||||
-posix_cap_xfs_to_xattr(&xfs_cap, xattr_cap, size);
|
||||
out:
|
||||
VN_RELE(vp);
|
||||
return -error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_cap_vremove(
|
||||
xfs_vnode_t *vp)
|
||||
{
|
||||
int error;
|
||||
|
||||
VN_HOLD(vp);
|
||||
error = xfs_cap_allow_set(vp);
|
||||
if (!error) {
|
||||
XVOP_ATTR_REMOVE(vp, SGI_CAP_LINUX, ATTR_ROOT, sys_cred, error);
|
||||
if (error == ENOATTR)
|
||||
error = 0; /* 'scool */
|
||||
}
|
||||
VN_RELE(vp);
|
||||
return -error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_cap_vset(
|
||||
xfs_vnode_t *vp,
|
||||
void *cap,
|
||||
size_t size)
|
||||
{
|
||||
posix_cap_xattr *xattr_cap = cap;
|
||||
xfs_cap_set_t xfs_cap;
|
||||
int error;
|
||||
|
||||
if (!cap)
|
||||
return -EINVAL;
|
||||
|
||||
error = posix_cap_xattr_to_xfs(xattr_cap, size, &xfs_cap);
|
||||
if (error)
|
||||
return -error;
|
||||
|
||||
VN_HOLD(vp);
|
||||
error = xfs_cap_allow_set(vp);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
XVOP_ATTR_SET(vp, SGI_CAP_LINUX, (char *)&xfs_cap,
|
||||
sizeof(xfs_cap_set_t), ATTR_ROOT, sys_cred, error);
|
||||
out:
|
||||
VN_RELE(vp);
|
||||
return -error;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_cap_allow_set(
|
||||
xfs_vnode_t *vp)
|
||||
{
|
||||
vattr_t va;
|
||||
int error;
|
||||
|
||||
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
|
||||
return EROFS;
|
||||
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
|
||||
return EPERM;
|
||||
if ((error = _MAC_VACCESS(vp, NULL, VWRITE)))
|
||||
return error;
|
||||
va.va_mask = XFS_AT_UID;
|
||||
XVOP_GETATTR(vp, &va, 0, NULL, error);
|
||||
if (error)
|
||||
return error;
|
||||
if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
|
||||
return EPERM;
|
||||
return error;
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_CAP_H__
|
||||
#define __XFS_CAP_H__
|
||||
|
||||
/*
|
||||
* Capabilities
|
||||
*/
|
||||
typedef __uint64_t xfs_cap_value_t;
|
||||
|
||||
typedef struct xfs_cap_set {
|
||||
xfs_cap_value_t cap_effective; /* use in capability checks */
|
||||
xfs_cap_value_t cap_permitted; /* combined with file attrs */
|
||||
xfs_cap_value_t cap_inheritable;/* pass through exec */
|
||||
} xfs_cap_set_t;
|
||||
|
||||
/* On-disk XFS extended attribute names */
|
||||
#define SGI_CAP_FILE "SGI_CAP_FILE"
|
||||
#define SGI_CAP_FILE_SIZE (sizeof(SGI_CAP_FILE)-1)
|
||||
#define SGI_CAP_LINUX "SGI_CAP_LINUX"
|
||||
#define SGI_CAP_LINUX_SIZE (sizeof(SGI_CAP_LINUX)-1)
|
||||
|
||||
/*
|
||||
* For Linux, we take the bitfields directly from capability.h
|
||||
* and no longer attempt to keep this attribute ondisk compatible
|
||||
* with IRIX. Since this attribute is only set on executables,
|
||||
* it just doesn't make much sense to try. We do use a different
|
||||
* named attribute though, to avoid confusion.
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#ifdef CONFIG_FS_POSIX_CAP
|
||||
|
||||
#include <linux/posix_cap_xattr.h>
|
||||
|
||||
struct xfs_vnode;
|
||||
|
||||
extern int xfs_cap_vhascap(struct xfs_vnode *);
|
||||
extern int xfs_cap_vset(struct xfs_vnode *, void *, size_t);
|
||||
extern int xfs_cap_vget(struct xfs_vnode *, void *, size_t);
|
||||
extern int xfs_cap_vremove(struct xfs_vnode *vp);
|
||||
|
||||
#define _CAP_EXISTS xfs_cap_vhascap
|
||||
|
||||
#else
|
||||
#define xfs_cap_vset(v,p,sz) (-EOPNOTSUPP)
|
||||
#define xfs_cap_vget(v,p,sz) (-EOPNOTSUPP)
|
||||
#define xfs_cap_vremove(v) (-EOPNOTSUPP)
|
||||
#define _CAP_EXISTS (NULL)
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_CAP_H__ */
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_CLNT_H__
|
||||
#define __XFS_CLNT_H__
|
||||
|
||||
/*
|
||||
* XFS arguments structure, constructed from the arguments we
|
||||
* are passed via the mount system call.
|
||||
*
|
||||
* NOTE: The mount system call is handled differently between
|
||||
* Linux and IRIX. In IRIX we worked work with a binary data
|
||||
* structure coming in across the syscall interface from user
|
||||
* space (the mount userspace knows about each filesystem type
|
||||
* and the set of valid options for it, and converts the users
|
||||
* argument string into a binary structure _before_ making the
|
||||
* system call), and the ABI issues that this implies.
|
||||
*
|
||||
* In Linux, we are passed a comma separated set of options;
|
||||
* ie. a NULL terminated string of characters. Userspace mount
|
||||
* code does not have any knowledge of mount options expected by
|
||||
* each filesystem type and so each filesystem parses its mount
|
||||
* options in kernel space.
|
||||
*
|
||||
* For the Linux port, we kept this structure pretty much intact
|
||||
* and use it internally (because the existing code groks it).
|
||||
*/
|
||||
struct xfs_mount_args {
|
||||
int flags; /* flags -> see XFSMNT_... macros below */
|
||||
int flags2; /* flags -> see XFSMNT2_... macros below */
|
||||
int logbufs; /* Number of log buffers, -1 to default */
|
||||
int logbufsize; /* Size of log buffers, -1 to default */
|
||||
char fsname[MAXNAMELEN+1]; /* data device name */
|
||||
char rtname[MAXNAMELEN+1]; /* realtime device filename */
|
||||
char logname[MAXNAMELEN+1]; /* journal device filename */
|
||||
char mtpt[MAXNAMELEN+1]; /* filesystem mount point */
|
||||
int sunit; /* stripe unit (BBs) */
|
||||
int swidth; /* stripe width (BBs), multiple of sunit */
|
||||
uchar_t iosizelog; /* log2 of the preferred I/O size */
|
||||
int ihashsize; /* inode hash table size (buckets) */
|
||||
};
|
||||
|
||||
/*
|
||||
* XFS mount option flags -- args->flags1
|
||||
*/
|
||||
#define XFSMNT_ATTR2 0x00000001 /* allow ATTR2 EA format */
|
||||
#define XFSMNT_WSYNC 0x00000002 /* safe mode nfs mount
|
||||
* compatible */
|
||||
#define XFSMNT_INO64 0x00000004 /* move inode numbers up
|
||||
* past 2^32 */
|
||||
#define XFSMNT_UQUOTA 0x00000008 /* user quota accounting */
|
||||
#define XFSMNT_PQUOTA 0x00000010 /* IRIX prj quota accounting */
|
||||
#define XFSMNT_UQUOTAENF 0x00000020 /* user quota limit
|
||||
* enforcement */
|
||||
#define XFSMNT_PQUOTAENF 0x00000040 /* IRIX project quota limit
|
||||
* enforcement */
|
||||
#define XFSMNT_QUIET 0x00000080 /* don't report mount errors */
|
||||
#define XFSMNT_NOALIGN 0x00000200 /* don't allocate at
|
||||
* stripe boundaries*/
|
||||
#define XFSMNT_RETERR 0x00000400 /* return error to user */
|
||||
#define XFSMNT_NORECOVERY 0x00000800 /* no recovery, implies
|
||||
* read-only mount */
|
||||
#define XFSMNT_SHARED 0x00001000 /* shared XFS mount */
|
||||
#define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */
|
||||
#define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */
|
||||
/* (osyncisdsync is default) */
|
||||
#define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32
|
||||
* bits of address space */
|
||||
#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */
|
||||
#define XFSMNT_GQUOTAENF 0x00800000 /* group quota limit
|
||||
* enforcement */
|
||||
#define XFSMNT_NOUUID 0x01000000 /* Ignore fs uuid */
|
||||
#define XFSMNT_DMAPI 0x02000000 /* enable dmapi/xdsm */
|
||||
#define XFSMNT_BARRIER 0x04000000 /* use write barriers */
|
||||
#define XFSMNT_IDELETE 0x08000000 /* inode cluster delete */
|
||||
#define XFSMNT_SWALLOC 0x10000000 /* turn on stripe width
|
||||
* allocation */
|
||||
#define XFSMNT_IHASHSIZE 0x20000000 /* inode hash table size */
|
||||
#define XFSMNT_DIRSYNC 0x40000000 /* sync creat,link,unlink,rename
|
||||
* symlink,mkdir,rmdir,mknod */
|
||||
#define XFSMNT_FLAGS2 0x80000000 /* more flags set in flags2 */
|
||||
|
||||
/*
|
||||
* XFS mount option flags -- args->flags2
|
||||
*/
|
||||
#define XFSMNT2_COMPAT_IOSIZE 0x00000001 /* don't report large preferred
|
||||
* I/O size in stat(2) */
|
||||
|
||||
#endif /* __XFS_CLNT_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DA_BTREE_H__
|
||||
#define __XFS_DA_BTREE_H__
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_bmap_free;
|
||||
struct xfs_inode;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
struct zone;
|
||||
|
||||
/*========================================================================
|
||||
* Directory Structure when greater than XFS_LBSIZE(mp) bytes.
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* This structure is common to both leaf nodes and non-leaf nodes in the Btree.
|
||||
*
|
||||
* Is is used to manage a doubly linked list of all blocks at the same
|
||||
* level in the Btree, and to identify which type of block this is.
|
||||
*/
|
||||
#define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */
|
||||
#define XFS_DIR_LEAF_MAGIC 0xfeeb /* magic number: directory leaf blks */
|
||||
#define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */
|
||||
#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */
|
||||
#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */
|
||||
|
||||
#define XFS_DIRX_LEAF_MAGIC(mp) \
|
||||
(XFS_DIR_IS_V1(mp) ? XFS_DIR_LEAF_MAGIC : XFS_DIR2_LEAFN_MAGIC)
|
||||
|
||||
typedef struct xfs_da_blkinfo {
|
||||
__be32 forw; /* previous block in list */
|
||||
__be32 back; /* following block in list */
|
||||
__be16 magic; /* validity check on block */
|
||||
__be16 pad; /* unused */
|
||||
} xfs_da_blkinfo_t;
|
||||
|
||||
/*
|
||||
* This is the structure of the root and intermediate nodes in the Btree.
|
||||
* The leaf nodes are defined above.
|
||||
*
|
||||
* Entries are not packed.
|
||||
*
|
||||
* Since we have duplicate keys, use a binary search but always follow
|
||||
* all match in the block, not just the first match found.
|
||||
*/
|
||||
#define XFS_DA_NODE_MAXDEPTH 5 /* max depth of Btree */
|
||||
|
||||
typedef struct xfs_da_intnode {
|
||||
struct xfs_da_node_hdr { /* constant-structure header block */
|
||||
xfs_da_blkinfo_t info; /* block type, links, etc. */
|
||||
__be16 count; /* count of active entries */
|
||||
__be16 level; /* level above leaves (leaf == 0) */
|
||||
} hdr;
|
||||
struct xfs_da_node_entry {
|
||||
__be32 hashval; /* hash value for this descendant */
|
||||
__be32 before; /* Btree block before this key */
|
||||
} btree[1]; /* variable sized array of keys */
|
||||
} xfs_da_intnode_t;
|
||||
typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
|
||||
typedef struct xfs_da_node_entry xfs_da_node_entry_t;
|
||||
|
||||
#define XFS_DA_MAXHASH ((xfs_dahash_t)-1) /* largest valid hash value */
|
||||
|
||||
#define XFS_LBSIZE(mp) (mp)->m_sb.sb_blocksize
|
||||
#define XFS_LBLOG(mp) (mp)->m_sb.sb_blocklog
|
||||
|
||||
#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \
|
||||
(((bno) << (mp)->m_dircook_elog) | (entry))
|
||||
#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \
|
||||
(((xfs_off_t)XFS_DA_MAKE_BNOENTRY(mp, bno, entry) << 32) | (hash))
|
||||
#define XFS_DA_COOKIE_HASH(mp,cookie) ((xfs_dahash_t)cookie)
|
||||
#define XFS_DA_COOKIE_BNO(mp,cookie) \
|
||||
((((xfs_off_t)(cookie) >> 31) == -1LL ? \
|
||||
(xfs_dablk_t)0 : \
|
||||
(xfs_dablk_t)((xfs_off_t)(cookie) >> \
|
||||
((mp)->m_dircook_elog + 32))))
|
||||
#define XFS_DA_COOKIE_ENTRY(mp,cookie) \
|
||||
((((xfs_off_t)(cookie) >> 31) == -1LL ? \
|
||||
(xfs_dablk_t)0 : \
|
||||
(xfs_dablk_t)(((xfs_off_t)(cookie) >> 32) & \
|
||||
((1 << (mp)->m_dircook_elog) - 1))))
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Btree searching and modification structure definitions.
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* Structure to ease passing around component names.
|
||||
*/
|
||||
typedef struct xfs_da_args {
|
||||
const uchar_t *name; /* string (maybe not NULL terminated) */
|
||||
int namelen; /* length of string (maybe no NULL) */
|
||||
uchar_t *value; /* set of bytes (maybe contain NULLs) */
|
||||
int valuelen; /* length of value */
|
||||
int flags; /* argument flags (eg: ATTR_NOCREATE) */
|
||||
xfs_dahash_t hashval; /* hash value of name */
|
||||
xfs_ino_t inumber; /* input/output inode number */
|
||||
struct xfs_inode *dp; /* directory inode to manipulate */
|
||||
xfs_fsblock_t *firstblock; /* ptr to firstblock for bmap calls */
|
||||
struct xfs_bmap_free *flist; /* ptr to freelist for bmap_finish */
|
||||
struct xfs_trans *trans; /* current trans (changes over time) */
|
||||
xfs_extlen_t total; /* total blocks needed, for 1st bmap */
|
||||
int whichfork; /* data or attribute fork */
|
||||
xfs_dablk_t blkno; /* blkno of attr leaf of interest */
|
||||
int index; /* index of attr of interest in blk */
|
||||
xfs_dablk_t rmtblkno; /* remote attr value starting blkno */
|
||||
int rmtblkcnt; /* remote attr value block count */
|
||||
xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */
|
||||
int index2; /* index of 2nd attr in blk */
|
||||
xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */
|
||||
int rmtblkcnt2; /* remote attr value block count */
|
||||
unsigned char justcheck; /* T/F: check for ok with no space */
|
||||
unsigned char rename; /* T/F: this is an atomic rename op */
|
||||
unsigned char addname; /* T/F: this is an add operation */
|
||||
unsigned char oknoent; /* T/F: ok to return ENOENT, else die */
|
||||
} xfs_da_args_t;
|
||||
|
||||
/*
|
||||
* Structure to describe buffer(s) for a block.
|
||||
* This is needed in the directory version 2 format case, when
|
||||
* multiple non-contiguous fsblocks might be needed to cover one
|
||||
* logical directory block.
|
||||
* If the buffer count is 1 then the data pointer points to the
|
||||
* same place as the b_addr field for the buffer, else to kmem_alloced memory.
|
||||
*/
|
||||
typedef struct xfs_dabuf {
|
||||
int nbuf; /* number of buffer pointers present */
|
||||
short dirty; /* data needs to be copied back */
|
||||
short bbcount; /* how large is data in bbs */
|
||||
void *data; /* pointer for buffers' data */
|
||||
#ifdef XFS_DABUF_DEBUG
|
||||
inst_t *ra; /* return address of caller to make */
|
||||
struct xfs_dabuf *next; /* next in global chain */
|
||||
struct xfs_dabuf *prev; /* previous in global chain */
|
||||
struct xfs_buftarg *target; /* device for buffer */
|
||||
xfs_daddr_t blkno; /* daddr first in bps[0] */
|
||||
#endif
|
||||
struct xfs_buf *bps[1]; /* actually nbuf of these */
|
||||
} xfs_dabuf_t;
|
||||
#define XFS_DA_BUF_SIZE(n) \
|
||||
(sizeof(xfs_dabuf_t) + sizeof(struct xfs_buf *) * ((n) - 1))
|
||||
|
||||
#ifdef XFS_DABUF_DEBUG
|
||||
extern xfs_dabuf_t *xfs_dabuf_global_list;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Storage for holding state during Btree searches and split/join ops.
|
||||
*
|
||||
* Only need space for 5 intermediate nodes. With a minimum of 62-way
|
||||
* fanout to the Btree, we can support over 900 million directory blocks,
|
||||
* which is slightly more than enough.
|
||||
*/
|
||||
typedef struct xfs_da_state_blk {
|
||||
xfs_dabuf_t *bp; /* buffer containing block */
|
||||
xfs_dablk_t blkno; /* filesystem blkno of buffer */
|
||||
xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */
|
||||
int index; /* relevant index into block */
|
||||
xfs_dahash_t hashval; /* last hash value in block */
|
||||
int magic; /* blk's magic number, ie: blk type */
|
||||
} xfs_da_state_blk_t;
|
||||
|
||||
typedef struct xfs_da_state_path {
|
||||
int active; /* number of active levels */
|
||||
xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH];
|
||||
} xfs_da_state_path_t;
|
||||
|
||||
typedef struct xfs_da_state {
|
||||
xfs_da_args_t *args; /* filename arguments */
|
||||
struct xfs_mount *mp; /* filesystem mount point */
|
||||
unsigned int blocksize; /* logical block size */
|
||||
unsigned int node_ents; /* how many entries in danode */
|
||||
xfs_da_state_path_t path; /* search/split paths */
|
||||
xfs_da_state_path_t altpath; /* alternate path for join */
|
||||
unsigned char inleaf; /* insert into 1->lf, 0->splf */
|
||||
unsigned char extravalid; /* T/F: extrablk is in use */
|
||||
unsigned char extraafter; /* T/F: extrablk is after new */
|
||||
xfs_da_state_blk_t extrablk; /* for double-splits on leafs */
|
||||
/* for dirv2 extrablk is data */
|
||||
} xfs_da_state_t;
|
||||
|
||||
/*
|
||||
* Utility macros to aid in logging changed structure fields.
|
||||
*/
|
||||
#define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE))
|
||||
#define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \
|
||||
(uint)(XFS_DA_LOGOFF(BASE, ADDR)), \
|
||||
(uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1)
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/*========================================================================
|
||||
* Function prototypes for the kernel.
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* Routines used for growing the Btree.
|
||||
*/
|
||||
int xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level,
|
||||
xfs_dabuf_t **bpp, int whichfork);
|
||||
int xfs_da_split(xfs_da_state_t *state);
|
||||
|
||||
/*
|
||||
* Routines used for shrinking the Btree.
|
||||
*/
|
||||
int xfs_da_join(xfs_da_state_t *state);
|
||||
void xfs_da_fixhashpath(xfs_da_state_t *state,
|
||||
xfs_da_state_path_t *path_to_to_fix);
|
||||
|
||||
/*
|
||||
* Routines used for finding things in the Btree.
|
||||
*/
|
||||
int xfs_da_node_lookup_int(xfs_da_state_t *state, int *result);
|
||||
int xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
|
||||
int forward, int release, int *result);
|
||||
/*
|
||||
* Utility routines.
|
||||
*/
|
||||
int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
|
||||
xfs_da_state_blk_t *new_blk);
|
||||
|
||||
/*
|
||||
* Utility routines.
|
||||
*/
|
||||
int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno);
|
||||
int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp,
|
||||
xfs_dablk_t bno, xfs_daddr_t mappedbno,
|
||||
xfs_dabuf_t **bp, int whichfork);
|
||||
int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp,
|
||||
xfs_dablk_t bno, xfs_daddr_t mappedbno,
|
||||
xfs_dabuf_t **bpp, int whichfork);
|
||||
xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp,
|
||||
xfs_dablk_t bno, int whichfork);
|
||||
int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
|
||||
xfs_dabuf_t *dead_buf);
|
||||
|
||||
uint xfs_da_hashname(const uchar_t *name_string, int name_length);
|
||||
uint xfs_da_log2_roundup(uint i);
|
||||
xfs_da_state_t *xfs_da_state_alloc(void);
|
||||
void xfs_da_state_free(xfs_da_state_t *state);
|
||||
|
||||
void xfs_da_buf_done(xfs_dabuf_t *dabuf);
|
||||
void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first,
|
||||
uint last);
|
||||
void xfs_da_brelse(struct xfs_trans *tp, xfs_dabuf_t *dabuf);
|
||||
void xfs_da_binval(struct xfs_trans *tp, xfs_dabuf_t *dabuf);
|
||||
xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf);
|
||||
|
||||
extern struct kmem_zone *xfs_da_state_zone;
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_DA_BTREE_H__ */
|
@ -1,413 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2006 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_types.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_inum.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_bmap_btree.h"
|
||||
#include "xfs_alloc_btree.h"
|
||||
#include "xfs_ialloc_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_inode_item.h"
|
||||
#include "xfs_bmap.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_ialloc.h"
|
||||
#include "xfs_itable.h"
|
||||
#include "xfs_dfrag.h"
|
||||
#include "xfs_error.h"
|
||||
#include "xfs_mac.h"
|
||||
#include "xfs_rw.h"
|
||||
|
||||
#include <sys/capability.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
/*
|
||||
* Syssgi interface for swapext
|
||||
*/
|
||||
int
|
||||
xfs_swapext(
|
||||
xfs_swapext_t __user *sxu)
|
||||
{
|
||||
xfs_swapext_t *sxp;
|
||||
xfs_inode_t *ip=NULL, *tip=NULL;
|
||||
xfs_mount_t *mp;
|
||||
xfs_vnode_t *vp = NULL, *tvp = NULL;
|
||||
struct vnode *bvp, *btvp;
|
||||
int error = 0;
|
||||
|
||||
sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL);
|
||||
if (!sxp) {
|
||||
error = XFS_ERROR(ENOMEM);
|
||||
goto error0;
|
||||
}
|
||||
struct thread *td;
|
||||
struct cred *cred;
|
||||
|
||||
td = curthread;
|
||||
cred = td->td_ucred;
|
||||
|
||||
if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) {
|
||||
error = XFS_ERROR(EFAULT);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* Pull information for the target fd */
|
||||
if (fgetvp(td, (int)sxp->sx_fdtarget, CAP_READ | CAP_WRITE, &bvp)
|
||||
!= 0) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
vp = VPTOXFSVP(bvp);
|
||||
ip = xfs_vtoi(vp);
|
||||
if (ip == NULL) {
|
||||
error = XFS_ERROR(EBADF);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
if (fgetvp(td, (int)sxp->sx_fdtmp, CAP_READ | CAP_WRITE, &btvp) != 0) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
tvp = VPTOXFSVP(btvp);
|
||||
tip = xfs_vtoi(tvp);
|
||||
if (tip == NULL) {
|
||||
error = XFS_ERROR(EBADF);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
if (ip->i_mount != tip->i_mount) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
if (ip->i_ino == tip->i_ino) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
mp = ip->i_mount;
|
||||
|
||||
if (XFS_FORCED_SHUTDOWN(mp)) {
|
||||
error = XFS_ERROR(EIO);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
error = XFS_SWAP_EXTENTS(mp, &ip->i_iocore, &tip->i_iocore, sxp);
|
||||
|
||||
error0:
|
||||
#ifdef RMC
|
||||
if (fp != NULL)
|
||||
fput(fp);
|
||||
if (tfp != NULL)
|
||||
fput(tfp);
|
||||
#endif
|
||||
|
||||
if (sxp != NULL)
|
||||
kmem_free(sxp, sizeof(xfs_swapext_t));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_swap_extents(
|
||||
xfs_inode_t *ip,
|
||||
xfs_inode_t *tip,
|
||||
xfs_swapext_t *sxp)
|
||||
{
|
||||
xfs_mount_t *mp;
|
||||
xfs_inode_t *ips[2];
|
||||
xfs_trans_t *tp;
|
||||
xfs_bstat_t *sbp = &sxp->sx_stat;
|
||||
xfs_vnode_t *vp, *tvp;
|
||||
xfs_ifork_t *tempifp, *ifp, *tifp;
|
||||
int ilf_fields, tilf_fields;
|
||||
static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
|
||||
int error = 0;
|
||||
int aforkblks = 0;
|
||||
int taforkblks = 0;
|
||||
__uint64_t tmp;
|
||||
char locked = 0;
|
||||
|
||||
mp = ip->i_mount;
|
||||
|
||||
tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
|
||||
if (!tempifp) {
|
||||
error = XFS_ERROR(ENOMEM);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
sbp = &sxp->sx_stat;
|
||||
vp = XFS_ITOV(ip);
|
||||
tvp = XFS_ITOV(tip);
|
||||
|
||||
/* Lock in i_ino order */
|
||||
if (ip->i_ino < tip->i_ino) {
|
||||
ips[0] = ip;
|
||||
ips[1] = tip;
|
||||
} else {
|
||||
ips[0] = tip;
|
||||
ips[1] = ip;
|
||||
}
|
||||
|
||||
xfs_lock_inodes(ips, 2, 0, lock_flags);
|
||||
locked = 1;
|
||||
|
||||
/* Check permissions */
|
||||
error = xfs_iaccess(ip, VWRITE, NULL);
|
||||
if (error)
|
||||
goto error0;
|
||||
|
||||
error = xfs_iaccess(tip, VWRITE, NULL);
|
||||
if (error)
|
||||
goto error0;
|
||||
|
||||
/* Verify that both files have the same format */
|
||||
if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* Verify both files are either real-time or non-realtime */
|
||||
if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) !=
|
||||
(tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* Should never get a local format */
|
||||
if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
|
||||
tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
if (VN_CACHED(tvp) != 0) {
|
||||
xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1);
|
||||
XVOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED);
|
||||
}
|
||||
|
||||
/* Verify O_DIRECT for ftmp */
|
||||
if (VN_CACHED(tvp) != 0) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* Verify all data are being swapped */
|
||||
if (sxp->sx_offset != 0 ||
|
||||
sxp->sx_length != ip->i_d.di_size ||
|
||||
sxp->sx_length != tip->i_d.di_size) {
|
||||
error = XFS_ERROR(EFAULT);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target has extended attributes, the tmp file
|
||||
* must also in order to ensure the correct data fork
|
||||
* format.
|
||||
*/
|
||||
if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) {
|
||||
error = XFS_ERROR(EINVAL);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare the current change & modify times with that
|
||||
* passed in. If they differ, we abort this swap.
|
||||
* This is the mechanism used to ensure the calling
|
||||
* process that the file was not changed out from
|
||||
* under it.
|
||||
*/
|
||||
if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) ||
|
||||
(sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) ||
|
||||
(sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) ||
|
||||
(sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) {
|
||||
error = XFS_ERROR(EBUSY);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* We need to fail if the file is memory mapped. Once we have tossed
|
||||
* all existing pages, the page fault will have no option
|
||||
* but to go to the filesystem for pages. By making the page fault call
|
||||
* VOP_READ (or write in the case of autogrow) they block on the iolock
|
||||
* until we have switched the extents.
|
||||
*/
|
||||
if (VN_MAPPED(vp)) {
|
||||
error = XFS_ERROR(EBUSY);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||
xfs_iunlock(tip, XFS_ILOCK_EXCL);
|
||||
|
||||
/*
|
||||
* There is a race condition here since we gave up the
|
||||
* ilock. However, the data fork will not change since
|
||||
* we have the iolock (locked for truncation too) so we
|
||||
* are safe. We don't really care if non-io related
|
||||
* fields change.
|
||||
*/
|
||||
|
||||
XVOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);
|
||||
|
||||
tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
|
||||
if ((error = xfs_trans_reserve(tp, 0,
|
||||
XFS_ICHANGE_LOG_RES(mp), 0,
|
||||
0, 0))) {
|
||||
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
||||
xfs_iunlock(tip, XFS_IOLOCK_EXCL);
|
||||
xfs_trans_cancel(tp, 0);
|
||||
locked = 0;
|
||||
goto error0;
|
||||
}
|
||||
xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL);
|
||||
|
||||
/*
|
||||
* Count the number of extended attribute blocks
|
||||
*/
|
||||
if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
|
||||
(ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
|
||||
error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks);
|
||||
if (error) {
|
||||
xfs_trans_cancel(tp, 0);
|
||||
goto error0;
|
||||
}
|
||||
}
|
||||
if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
|
||||
(tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
|
||||
error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
|
||||
&taforkblks);
|
||||
if (error) {
|
||||
xfs_trans_cancel(tp, 0);
|
||||
goto error0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Swap the data forks of the inodes
|
||||
*/
|
||||
ifp = &ip->i_df;
|
||||
tifp = &tip->i_df;
|
||||
*tempifp = *ifp; /* struct copy */
|
||||
*ifp = *tifp; /* struct copy */
|
||||
*tifp = *tempifp; /* struct copy */
|
||||
|
||||
/*
|
||||
* Fix the on-disk inode values
|
||||
*/
|
||||
tmp = (__uint64_t)ip->i_d.di_nblocks;
|
||||
ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks;
|
||||
tip->i_d.di_nblocks = tmp + taforkblks - aforkblks;
|
||||
|
||||
tmp = (__uint64_t) ip->i_d.di_nextents;
|
||||
ip->i_d.di_nextents = tip->i_d.di_nextents;
|
||||
tip->i_d.di_nextents = tmp;
|
||||
|
||||
tmp = (__uint64_t) ip->i_d.di_format;
|
||||
ip->i_d.di_format = tip->i_d.di_format;
|
||||
tip->i_d.di_format = tmp;
|
||||
|
||||
ilf_fields = XFS_ILOG_CORE;
|
||||
|
||||
switch(ip->i_d.di_format) {
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
/* If the extents fit in the inode, fix the
|
||||
* pointer. Otherwise it's already NULL or
|
||||
* pointing to the extent.
|
||||
*/
|
||||
if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
|
||||
ifp->if_u1.if_extents =
|
||||
ifp->if_u2.if_inline_ext;
|
||||
}
|
||||
ilf_fields |= XFS_ILOG_DEXT;
|
||||
break;
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
ilf_fields |= XFS_ILOG_DBROOT;
|
||||
break;
|
||||
}
|
||||
|
||||
tilf_fields = XFS_ILOG_CORE;
|
||||
|
||||
switch(tip->i_d.di_format) {
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
/* If the extents fit in the inode, fix the
|
||||
* pointer. Otherwise it's already NULL or
|
||||
* pointing to the extent.
|
||||
*/
|
||||
if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
|
||||
tifp->if_u1.if_extents =
|
||||
tifp->if_u2.if_inline_ext;
|
||||
}
|
||||
tilf_fields |= XFS_ILOG_DEXT;
|
||||
break;
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
tilf_fields |= XFS_ILOG_DBROOT;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef XXXKAN /* Not necessary, vnodes are vrefed already by fgetvp */
|
||||
/*
|
||||
* Increment vnode ref counts since xfs_trans_commit &
|
||||
* xfs_trans_cancel will both unlock the inodes and
|
||||
* decrement the associated ref counts.
|
||||
*/
|
||||
VN_HOLD(vp);
|
||||
VN_HOLD(tvp);
|
||||
#endif
|
||||
|
||||
xfs_trans_ijoin(tp, ip, lock_flags);
|
||||
xfs_trans_ijoin(tp, tip, lock_flags);
|
||||
|
||||
xfs_trans_log_inode(tp, ip, ilf_fields);
|
||||
xfs_trans_log_inode(tp, tip, tilf_fields);
|
||||
|
||||
/*
|
||||
* If this is a synchronous mount, make sure that the
|
||||
* transaction goes to disk before returning to the user.
|
||||
*/
|
||||
if (mp->m_flags & XFS_MOUNT_WSYNC) {
|
||||
xfs_trans_set_sync(tp);
|
||||
}
|
||||
|
||||
error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL);
|
||||
|
||||
locked = 0;
|
||||
|
||||
error0:
|
||||
if (locked) {
|
||||
xfs_iunlock(ip, lock_flags);
|
||||
xfs_iunlock(tip, lock_flags);
|
||||
}
|
||||
if (tempifp != NULL)
|
||||
kmem_free(tempifp, sizeof(xfs_ifork_t));
|
||||
return error;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DFRAG_H__
|
||||
#define __XFS_DFRAG_H__
|
||||
|
||||
/*
|
||||
* Structure passed to xfs_swapext
|
||||
*/
|
||||
|
||||
typedef struct xfs_swapext
|
||||
{
|
||||
__int64_t sx_version; /* version */
|
||||
__int64_t sx_fdtarget; /* fd of target file */
|
||||
__int64_t sx_fdtmp; /* fd of tmp file */
|
||||
xfs_off_t sx_offset; /* offset into file */
|
||||
xfs_off_t sx_length; /* leng from offset */
|
||||
char sx_pad[16]; /* pad space, unused */
|
||||
xfs_bstat_t sx_stat; /* stat of target b4 copy */
|
||||
} xfs_swapext_t;
|
||||
|
||||
/*
|
||||
* Version flag
|
||||
*/
|
||||
#define XFS_SX_VERSION 0
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/*
|
||||
* Prototypes for visible xfs_dfrag.c routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Syscall interface for xfs_swapext
|
||||
*/
|
||||
int xfs_swapext(struct xfs_swapext __user *sx);
|
||||
|
||||
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
|
||||
struct xfs_swapext *sxp);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_DFRAG_H__ */
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DINODE_H__
|
||||
#define __XFS_DINODE_H__
|
||||
|
||||
struct xfs_buf;
|
||||
struct xfs_mount;
|
||||
|
||||
#define XFS_DINODE_VERSION_1 1
|
||||
#define XFS_DINODE_VERSION_2 2
|
||||
#define XFS_DINODE_GOOD_VERSION(v) \
|
||||
(((v) == XFS_DINODE_VERSION_1 || (v) == XFS_DINODE_VERSION_2))
|
||||
#define XFS_DINODE_MAGIC 0x494e /* 'IN' */
|
||||
|
||||
/*
|
||||
* Disk inode structure.
|
||||
* This is just the header; the inode is expanded to fill a variable size
|
||||
* with the last field expanding. It is split into the core and "other"
|
||||
* because we only need the core part in the in-core inode.
|
||||
*/
|
||||
typedef struct xfs_timestamp {
|
||||
__int32_t t_sec; /* timestamp seconds */
|
||||
__int32_t t_nsec; /* timestamp nanoseconds */
|
||||
} xfs_timestamp_t;
|
||||
|
||||
/*
|
||||
* Note: Coordinate changes to this structure with the XFS_DI_* #defines
|
||||
* below and the offsets table in xfs_ialloc_log_di().
|
||||
*/
|
||||
typedef struct xfs_dinode_core
|
||||
{
|
||||
__uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
|
||||
__uint16_t di_mode; /* mode and type of file */
|
||||
__int8_t di_version; /* inode version */
|
||||
__int8_t di_format; /* format of di_c data */
|
||||
__uint16_t di_onlink; /* old number of links to file */
|
||||
__uint32_t di_uid; /* owner's user id */
|
||||
__uint32_t di_gid; /* owner's group id */
|
||||
__uint32_t di_nlink; /* number of links to file */
|
||||
__uint16_t di_projid; /* owner's project id */
|
||||
__uint8_t di_pad[8]; /* unused, zeroed space */
|
||||
__uint16_t di_flushiter; /* incremented on flush */
|
||||
xfs_timestamp_t di_atime; /* time last accessed */
|
||||
xfs_timestamp_t di_mtime; /* time last modified */
|
||||
xfs_timestamp_t di_ctime; /* time created/inode modified */
|
||||
xfs_fsize_t di_size; /* number of bytes in file */
|
||||
xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */
|
||||
xfs_extlen_t di_extsize; /* basic/minimum extent size for file */
|
||||
xfs_extnum_t di_nextents; /* number of extents in data fork */
|
||||
xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/
|
||||
__uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
|
||||
__int8_t di_aformat; /* format of attr fork's data */
|
||||
__uint32_t di_dmevmask; /* DMIG event mask */
|
||||
__uint16_t di_dmstate; /* DMIG state info */
|
||||
__uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
|
||||
__uint32_t di_gen; /* generation number */
|
||||
} xfs_dinode_core_t;
|
||||
|
||||
#define DI_MAX_FLUSH 0xffff
|
||||
|
||||
typedef struct xfs_dinode
|
||||
{
|
||||
xfs_dinode_core_t di_core;
|
||||
/*
|
||||
* In adding anything between the core and the union, be
|
||||
* sure to update the macros like XFS_LITINO below and
|
||||
* XFS_BMAP_RBLOCK_DSIZE in xfs_bmap_btree.h.
|
||||
*/
|
||||
xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */
|
||||
union {
|
||||
xfs_bmdr_block_t di_bmbt; /* btree root block */
|
||||
xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */
|
||||
xfs_dir_shortform_t di_dirsf; /* shortform directory */
|
||||
xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */
|
||||
char di_c[1]; /* local contents */
|
||||
xfs_dev_t di_dev; /* device for S_IFCHR/S_IFBLK */
|
||||
uuid_t di_muuid; /* mount point value */
|
||||
char di_symlink[1]; /* local symbolic link */
|
||||
} di_u;
|
||||
union {
|
||||
xfs_bmdr_block_t di_abmbt; /* btree root block */
|
||||
xfs_bmbt_rec_32_t di_abmx[1]; /* extent list */
|
||||
xfs_attr_shortform_t di_attrsf; /* shortform attribute list */
|
||||
} di_a;
|
||||
} xfs_dinode_t;
|
||||
|
||||
/*
|
||||
* The 32 bit link count in the inode theoretically maxes out at UINT_MAX.
|
||||
* Since the pathconf interface is signed, we use 2^31 - 1 instead.
|
||||
* The old inode format had a 16 bit link count, so its maximum is USHRT_MAX.
|
||||
*/
|
||||
#define XFS_MAXLINK ((1U << 31) - 1U)
|
||||
#define XFS_MAXLINK_1 65535U
|
||||
|
||||
/*
|
||||
* Bit names for logging disk inodes only
|
||||
*/
|
||||
#define XFS_DI_MAGIC 0x0000001
|
||||
#define XFS_DI_MODE 0x0000002
|
||||
#define XFS_DI_VERSION 0x0000004
|
||||
#define XFS_DI_FORMAT 0x0000008
|
||||
#define XFS_DI_ONLINK 0x0000010
|
||||
#define XFS_DI_UID 0x0000020
|
||||
#define XFS_DI_GID 0x0000040
|
||||
#define XFS_DI_NLINK 0x0000080
|
||||
#define XFS_DI_PROJID 0x0000100
|
||||
#define XFS_DI_PAD 0x0000200
|
||||
#define XFS_DI_ATIME 0x0000400
|
||||
#define XFS_DI_MTIME 0x0000800
|
||||
#define XFS_DI_CTIME 0x0001000
|
||||
#define XFS_DI_SIZE 0x0002000
|
||||
#define XFS_DI_NBLOCKS 0x0004000
|
||||
#define XFS_DI_EXTSIZE 0x0008000
|
||||
#define XFS_DI_NEXTENTS 0x0010000
|
||||
#define XFS_DI_NAEXTENTS 0x0020000
|
||||
#define XFS_DI_FORKOFF 0x0040000
|
||||
#define XFS_DI_AFORMAT 0x0080000
|
||||
#define XFS_DI_DMEVMASK 0x0100000
|
||||
#define XFS_DI_DMSTATE 0x0200000
|
||||
#define XFS_DI_FLAGS 0x0400000
|
||||
#define XFS_DI_GEN 0x0800000
|
||||
#define XFS_DI_NEXT_UNLINKED 0x1000000
|
||||
#define XFS_DI_U 0x2000000
|
||||
#define XFS_DI_A 0x4000000
|
||||
#define XFS_DI_NUM_BITS 27
|
||||
#define XFS_DI_ALL_BITS ((1 << XFS_DI_NUM_BITS) - 1)
|
||||
#define XFS_DI_CORE_BITS (XFS_DI_ALL_BITS & ~(XFS_DI_U|XFS_DI_A))
|
||||
|
||||
/*
|
||||
* Values for di_format
|
||||
*/
|
||||
typedef enum xfs_dinode_fmt
|
||||
{
|
||||
XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */
|
||||
XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */
|
||||
/* LNK: di_symlink */
|
||||
XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */
|
||||
XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */
|
||||
XFS_DINODE_FMT_UUID /* MNT: di_uuid */
|
||||
} xfs_dinode_fmt_t;
|
||||
|
||||
/*
|
||||
* Inode minimum and maximum sizes.
|
||||
*/
|
||||
#define XFS_DINODE_MIN_LOG 8
|
||||
#define XFS_DINODE_MAX_LOG 11
|
||||
#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG)
|
||||
#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG)
|
||||
|
||||
/*
|
||||
* Inode size for given fs.
|
||||
*/
|
||||
#define XFS_LITINO(mp) ((mp)->m_litino)
|
||||
#define XFS_BROOT_SIZE_ADJ \
|
||||
(sizeof(xfs_bmbt_block_t) - sizeof(xfs_bmdr_block_t))
|
||||
|
||||
/*
|
||||
* Inode data & attribute fork sizes, per inode.
|
||||
*/
|
||||
#define XFS_CFORK_Q(dcp) ((dcp)->di_forkoff != 0)
|
||||
#define XFS_CFORK_Q_DISK(dcp) ((dcp)->di_forkoff != 0)
|
||||
|
||||
#define XFS_CFORK_BOFF(dcp) ((int)((dcp)->di_forkoff << 3))
|
||||
#define XFS_CFORK_BOFF_DISK(dcp) \
|
||||
((int)(INT_GET((dcp)->di_forkoff, ARCH_CONVERT) << 3))
|
||||
|
||||
#define XFS_CFORK_DSIZE_DISK(dcp,mp) \
|
||||
(XFS_CFORK_Q_DISK(dcp) ? XFS_CFORK_BOFF_DISK(dcp) : XFS_LITINO(mp))
|
||||
#define XFS_CFORK_DSIZE(dcp,mp) \
|
||||
(XFS_CFORK_Q(dcp) ? XFS_CFORK_BOFF(dcp) : XFS_LITINO(mp))
|
||||
|
||||
#define XFS_CFORK_ASIZE_DISK(dcp,mp) \
|
||||
(XFS_CFORK_Q_DISK(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_DISK(dcp) : 0)
|
||||
#define XFS_CFORK_ASIZE(dcp,mp) \
|
||||
(XFS_CFORK_Q(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF(dcp) : 0)
|
||||
|
||||
#define XFS_CFORK_SIZE_DISK(dcp,mp,w) \
|
||||
((w) == XFS_DATA_FORK ? \
|
||||
XFS_CFORK_DSIZE_DISK(dcp, mp) : \
|
||||
XFS_CFORK_ASIZE_DISK(dcp, mp))
|
||||
#define XFS_CFORK_SIZE(dcp,mp,w) \
|
||||
((w) == XFS_DATA_FORK ? \
|
||||
XFS_CFORK_DSIZE(dcp, mp) : XFS_CFORK_ASIZE(dcp, mp))
|
||||
|
||||
#define XFS_DFORK_DSIZE(dip,mp) \
|
||||
XFS_CFORK_DSIZE_DISK(&(dip)->di_core, mp)
|
||||
#define XFS_DFORK_DSIZE_HOST(dip,mp) \
|
||||
XFS_CFORK_DSIZE(&(dip)->di_core, mp)
|
||||
#define XFS_DFORK_ASIZE(dip,mp) \
|
||||
XFS_CFORK_ASIZE_DISK(&(dip)->di_core, mp)
|
||||
#define XFS_DFORK_ASIZE_HOST(dip,mp) \
|
||||
XFS_CFORK_ASIZE(&(dip)->di_core, mp)
|
||||
#define XFS_DFORK_SIZE(dip,mp,w) \
|
||||
XFS_CFORK_SIZE_DISK(&(dip)->di_core, mp, w)
|
||||
#define XFS_DFORK_SIZE_HOST(dip,mp,w) \
|
||||
XFS_CFORK_SIZE(&(dip)->di_core, mp, w)
|
||||
|
||||
#define XFS_DFORK_Q(dip) XFS_CFORK_Q_DISK(&(dip)->di_core)
|
||||
#define XFS_DFORK_BOFF(dip) XFS_CFORK_BOFF_DISK(&(dip)->di_core)
|
||||
#define XFS_DFORK_DPTR(dip) ((dip)->di_u.di_c)
|
||||
#define XFS_DFORK_APTR(dip) \
|
||||
((dip)->di_u.di_c + XFS_DFORK_BOFF(dip))
|
||||
#define XFS_DFORK_PTR(dip,w) \
|
||||
((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip))
|
||||
#define XFS_CFORK_FORMAT(dcp,w) \
|
||||
((w) == XFS_DATA_FORK ? (dcp)->di_format : (dcp)->di_aformat)
|
||||
#define XFS_CFORK_FMT_SET(dcp,w,n) \
|
||||
((w) == XFS_DATA_FORK ? \
|
||||
((dcp)->di_format = (n)) : ((dcp)->di_aformat = (n)))
|
||||
#define XFS_DFORK_FORMAT(dip,w) XFS_CFORK_FORMAT(&(dip)->di_core, w)
|
||||
|
||||
#define XFS_CFORK_NEXTENTS_DISK(dcp,w) \
|
||||
((w) == XFS_DATA_FORK ? \
|
||||
INT_GET((dcp)->di_nextents, ARCH_CONVERT) : \
|
||||
INT_GET((dcp)->di_anextents, ARCH_CONVERT))
|
||||
#define XFS_CFORK_NEXTENTS(dcp,w) \
|
||||
((w) == XFS_DATA_FORK ? (dcp)->di_nextents : (dcp)->di_anextents)
|
||||
#define XFS_DFORK_NEXTENTS(dip,w) XFS_CFORK_NEXTENTS_DISK(&(dip)->di_core, w)
|
||||
#define XFS_DFORK_NEXTENTS_HOST(dip,w) XFS_CFORK_NEXTENTS(&(dip)->di_core, w)
|
||||
|
||||
#define XFS_CFORK_NEXT_SET(dcp,w,n) \
|
||||
((w) == XFS_DATA_FORK ? \
|
||||
((dcp)->di_nextents = (n)) : ((dcp)->di_anextents = (n)))
|
||||
|
||||
#define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)XFS_BUF_PTR(bp))
|
||||
|
||||
/*
|
||||
* Values for di_flags
|
||||
* There should be a one-to-one correspondence between these flags and the
|
||||
* XFS_XFLAG_s.
|
||||
*/
|
||||
#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */
|
||||
#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */
|
||||
#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */
|
||||
#define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */
|
||||
#define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */
|
||||
#define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */
|
||||
#define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */
|
||||
#define XFS_DIFLAG_NODUMP_BIT 7 /* do not dump */
|
||||
#define XFS_DIFLAG_RTINHERIT_BIT 8 /* create with realtime bit set */
|
||||
#define XFS_DIFLAG_PROJINHERIT_BIT 9 /* create with parents projid */
|
||||
#define XFS_DIFLAG_NOSYMLINKS_BIT 10 /* disallow symlink creation */
|
||||
#define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */
|
||||
#define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */
|
||||
#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT)
|
||||
#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT)
|
||||
#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT)
|
||||
#define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT)
|
||||
#define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT)
|
||||
#define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT)
|
||||
#define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT)
|
||||
#define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT)
|
||||
#define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT)
|
||||
#define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT)
|
||||
#define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
|
||||
#define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT)
|
||||
#define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
|
||||
|
||||
#define XFS_DIFLAG_ANY \
|
||||
(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
|
||||
XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
|
||||
XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
|
||||
XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
|
||||
XFS_DIFLAG_EXTSZINHERIT)
|
||||
|
||||
#endif /* __XFS_DINODE_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DIR_H__
|
||||
#define __XFS_DIR_H__
|
||||
|
||||
/*
|
||||
* Large directories are structured around Btrees where all the data
|
||||
* elements are in the leaf nodes. Filenames are hashed into an int,
|
||||
* then that int is used as the index into the Btree. Since the hashval
|
||||
* of a filename may not be unique, we may have duplicate keys. The
|
||||
* internal links in the Btree are logical block offsets into the file.
|
||||
*
|
||||
* Small directories use a different format and are packed as tightly
|
||||
* as possible so as to fit into the literal area of the inode.
|
||||
*/
|
||||
|
||||
/*========================================================================
|
||||
* Function prototypes for the kernel.
|
||||
*========================================================================*/
|
||||
|
||||
struct uio;
|
||||
struct xfs_bmap_free;
|
||||
struct xfs_da_args;
|
||||
struct xfs_dinode;
|
||||
struct xfs_inode;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* Directory function types.
|
||||
* Put in structures (xfs_dirops_t) for v1 and v2 directories.
|
||||
*/
|
||||
typedef void (*xfs_dir_mount_t)(struct xfs_mount *mp);
|
||||
typedef int (*xfs_dir_isempty_t)(struct xfs_inode *dp);
|
||||
typedef int (*xfs_dir_init_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
struct xfs_inode *pdp);
|
||||
typedef int (*xfs_dir_createname_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
char *name,
|
||||
int namelen,
|
||||
xfs_ino_t inum,
|
||||
xfs_fsblock_t *first,
|
||||
struct xfs_bmap_free *flist,
|
||||
xfs_extlen_t total);
|
||||
typedef int (*xfs_dir_lookup_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
char *name,
|
||||
int namelen,
|
||||
xfs_ino_t *inum);
|
||||
typedef int (*xfs_dir_removename_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
char *name,
|
||||
int namelen,
|
||||
xfs_ino_t ino,
|
||||
xfs_fsblock_t *first,
|
||||
struct xfs_bmap_free *flist,
|
||||
xfs_extlen_t total);
|
||||
typedef int (*xfs_dir_getdents_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
struct uio *uio,
|
||||
int *eofp);
|
||||
typedef int (*xfs_dir_replace_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
char *name,
|
||||
int namelen,
|
||||
xfs_ino_t inum,
|
||||
xfs_fsblock_t *first,
|
||||
struct xfs_bmap_free *flist,
|
||||
xfs_extlen_t total);
|
||||
typedef int (*xfs_dir_canenter_t)(struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
char *name,
|
||||
int namelen);
|
||||
typedef int (*xfs_dir_shortform_validate_ondisk_t)(struct xfs_mount *mp,
|
||||
struct xfs_dinode *dip);
|
||||
typedef int (*xfs_dir_shortform_to_single_t)(struct xfs_da_args *args);
|
||||
|
||||
typedef struct xfs_dirops {
|
||||
xfs_dir_mount_t xd_mount;
|
||||
xfs_dir_isempty_t xd_isempty;
|
||||
xfs_dir_init_t xd_init;
|
||||
xfs_dir_createname_t xd_createname;
|
||||
xfs_dir_lookup_t xd_lookup;
|
||||
xfs_dir_removename_t xd_removename;
|
||||
xfs_dir_getdents_t xd_getdents;
|
||||
xfs_dir_replace_t xd_replace;
|
||||
xfs_dir_canenter_t xd_canenter;
|
||||
xfs_dir_shortform_validate_ondisk_t xd_shortform_validate_ondisk;
|
||||
xfs_dir_shortform_to_single_t xd_shortform_to_single;
|
||||
} xfs_dirops_t;
|
||||
|
||||
/*
|
||||
* Overall external interface routines.
|
||||
*/
|
||||
void xfs_dir_startup(void); /* called exactly once */
|
||||
|
||||
#define XFS_DIR_MOUNT(mp) \
|
||||
((mp)->m_dirops.xd_mount(mp))
|
||||
#define XFS_DIR_ISEMPTY(mp,dp) \
|
||||
((mp)->m_dirops.xd_isempty(dp))
|
||||
#define XFS_DIR_INIT(mp,tp,dp,pdp) \
|
||||
((mp)->m_dirops.xd_init(tp,dp,pdp))
|
||||
#define XFS_DIR_CREATENAME(mp,tp,dp,name,namelen,inum,first,flist,total) \
|
||||
((mp)->m_dirops.xd_createname(tp,dp,name,namelen,inum,first,flist,\
|
||||
total))
|
||||
#define XFS_DIR_LOOKUP(mp,tp,dp,name,namelen,inum) \
|
||||
((mp)->m_dirops.xd_lookup(tp,dp,name,namelen,inum))
|
||||
#define XFS_DIR_REMOVENAME(mp,tp,dp,name,namelen,ino,first,flist,total) \
|
||||
((mp)->m_dirops.xd_removename(tp,dp,name,namelen,ino,first,flist,total))
|
||||
#define XFS_DIR_GETDENTS(mp,tp,dp,uio,eofp) \
|
||||
((mp)->m_dirops.xd_getdents(tp,dp,uio,eofp))
|
||||
#define XFS_DIR_REPLACE(mp,tp,dp,name,namelen,inum,first,flist,total) \
|
||||
((mp)->m_dirops.xd_replace(tp,dp,name,namelen,inum,first,flist,total))
|
||||
#define XFS_DIR_CANENTER(mp,tp,dp,name,namelen) \
|
||||
((mp)->m_dirops.xd_canenter(tp,dp,name,namelen))
|
||||
#define XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip) \
|
||||
((mp)->m_dirops.xd_shortform_validate_ondisk(mp,dip))
|
||||
#define XFS_DIR_SHORTFORM_TO_SINGLE(mp,args) \
|
||||
((mp)->m_dirops.xd_shortform_to_single(args))
|
||||
|
||||
#define XFS_DIR_IS_V1(mp) ((mp)->m_dirversion == 1)
|
||||
#define XFS_DIR_IS_V2(mp) ((mp)->m_dirversion == 2)
|
||||
extern xfs_dirops_t xfsv1_dirops;
|
||||
extern xfs_dirops_t xfsv2_dirops;
|
||||
|
||||
#endif /* __XFS_DIR_H__ */
|
@ -1,851 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_types.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_inum.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_da_btree.h"
|
||||
#include "xfs_bmap_btree.h"
|
||||
#include "xfs_alloc_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_inode_item.h"
|
||||
#include "xfs_bmap.h"
|
||||
#include "xfs_dir_leaf.h"
|
||||
#include "xfs_dir2_data.h"
|
||||
#include "xfs_dir2_leaf.h"
|
||||
#include "xfs_dir2_block.h"
|
||||
#include "xfs_dir2_node.h"
|
||||
#include "xfs_dir2_trace.h"
|
||||
#include "xfs_error.h"
|
||||
|
||||
/*
|
||||
* Declarations for interface routines.
|
||||
*/
|
||||
static void xfs_dir2_mount(xfs_mount_t *mp);
|
||||
static int xfs_dir2_isempty(xfs_inode_t *dp);
|
||||
static int xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp,
|
||||
xfs_inode_t *pdp);
|
||||
static int xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp,
|
||||
char *name, int namelen, xfs_ino_t inum,
|
||||
xfs_fsblock_t *first,
|
||||
xfs_bmap_free_t *flist, xfs_extlen_t total);
|
||||
static int xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
|
||||
int namelen, xfs_ino_t *inum);
|
||||
static int xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp,
|
||||
char *name, int namelen, xfs_ino_t ino,
|
||||
xfs_fsblock_t *first,
|
||||
xfs_bmap_free_t *flist, xfs_extlen_t total);
|
||||
static int xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio,
|
||||
int *eofp);
|
||||
static int xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
|
||||
int namelen, xfs_ino_t inum,
|
||||
xfs_fsblock_t *first, xfs_bmap_free_t *flist,
|
||||
xfs_extlen_t total);
|
||||
static int xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
|
||||
int namelen);
|
||||
static int xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp,
|
||||
xfs_dinode_t *dip);
|
||||
|
||||
/*
|
||||
* Utility routine declarations.
|
||||
*/
|
||||
static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa);
|
||||
static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa);
|
||||
|
||||
/*
|
||||
* Directory operations vector.
|
||||
*/
|
||||
xfs_dirops_t xfsv2_dirops = {
|
||||
.xd_mount = xfs_dir2_mount,
|
||||
.xd_isempty = xfs_dir2_isempty,
|
||||
.xd_init = xfs_dir2_init,
|
||||
.xd_createname = xfs_dir2_createname,
|
||||
.xd_lookup = xfs_dir2_lookup,
|
||||
.xd_removename = xfs_dir2_removename,
|
||||
.xd_getdents = xfs_dir2_getdents,
|
||||
.xd_replace = xfs_dir2_replace,
|
||||
.xd_canenter = xfs_dir2_canenter,
|
||||
.xd_shortform_validate_ondisk = xfs_dir2_shortform_validate_ondisk,
|
||||
.xd_shortform_to_single = xfs_dir2_sf_to_block,
|
||||
};
|
||||
|
||||
/*
|
||||
* Interface routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize directory-related fields in the mount structure.
|
||||
*/
|
||||
static void
|
||||
xfs_dir2_mount(
|
||||
xfs_mount_t *mp) /* filesystem mount point */
|
||||
{
|
||||
mp->m_dirversion = 2;
|
||||
ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
|
||||
XFS_MAX_BLOCKSIZE);
|
||||
mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
|
||||
mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
|
||||
mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));
|
||||
mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
|
||||
mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));
|
||||
mp->m_attr_node_ents =
|
||||
(mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
|
||||
(uint)sizeof(xfs_da_node_entry_t);
|
||||
mp->m_dir_node_ents =
|
||||
(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
|
||||
(uint)sizeof(xfs_da_node_entry_t);
|
||||
mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if directory contains only "." and "..".
|
||||
*/
|
||||
static int /* return code */
|
||||
xfs_dir2_isempty(
|
||||
xfs_inode_t *dp) /* incore inode structure */
|
||||
{
|
||||
xfs_dir2_sf_t *sfp; /* shortform directory structure */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
/*
|
||||
* Might happen during shutdown.
|
||||
*/
|
||||
if (dp->i_d.di_size == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
|
||||
return 0;
|
||||
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
|
||||
return !sfp->hdr.count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a directory with its "." and ".." entries.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_init(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
xfs_inode_t *pdp) /* incore parent directory inode */
|
||||
{
|
||||
xfs_da_args_t args; /* operation arguments */
|
||||
int error; /* error return value */
|
||||
|
||||
memset((char *)&args, 0, sizeof(args));
|
||||
args.dp = dp;
|
||||
args.trans = tp;
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) {
|
||||
return error;
|
||||
}
|
||||
return xfs_dir2_sf_create(&args, pdp->i_ino);
|
||||
}
|
||||
|
||||
/*
|
||||
Enter a name in a directory.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_createname(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
char *name, /* new entry name */
|
||||
int namelen, /* new entry name length */
|
||||
xfs_ino_t inum, /* new entry inode number */
|
||||
xfs_fsblock_t *first, /* bmap's firstblock */
|
||||
xfs_bmap_free_t *flist, /* bmap's freeblock list */
|
||||
xfs_extlen_t total) /* bmap's total block count */
|
||||
{
|
||||
xfs_da_args_t args; /* operation arguments */
|
||||
int rval; /* return value */
|
||||
int v; /* type-checking value */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
|
||||
return rval;
|
||||
}
|
||||
XFS_STATS_INC(xs_dir_create);
|
||||
/*
|
||||
* Fill in the arg structure for this request.
|
||||
*/
|
||||
args.name = name;
|
||||
args.namelen = namelen;
|
||||
args.hashval = xfs_da_hashname(name, namelen);
|
||||
args.inumber = inum;
|
||||
args.dp = dp;
|
||||
args.firstblock = first;
|
||||
args.flist = flist;
|
||||
args.total = total;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = 0;
|
||||
args.addname = args.oknoent = 1;
|
||||
/*
|
||||
* Decide on what work routines to call based on the inode size.
|
||||
*/
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_addname(&args);
|
||||
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_block_addname(&args);
|
||||
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_leaf_addname(&args);
|
||||
else
|
||||
rval = xfs_dir2_node_addname(&args);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a name in a directory, give back the inode number.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_lookup(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
char *name, /* lookup name */
|
||||
int namelen, /* lookup name length */
|
||||
xfs_ino_t *inum) /* out: inode number */
|
||||
{
|
||||
xfs_da_args_t args; /* operation arguments */
|
||||
int rval; /* return value */
|
||||
int v; /* type-checking value */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
XFS_STATS_INC(xs_dir_lookup);
|
||||
|
||||
/*
|
||||
* Fill in the arg structure for this request.
|
||||
*/
|
||||
args.name = name;
|
||||
args.namelen = namelen;
|
||||
args.hashval = xfs_da_hashname(name, namelen);
|
||||
args.inumber = 0;
|
||||
args.dp = dp;
|
||||
args.firstblock = NULL;
|
||||
args.flist = NULL;
|
||||
args.total = 0;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = args.addname = 0;
|
||||
args.oknoent = 1;
|
||||
/*
|
||||
* Decide on what work routines to call based on the inode size.
|
||||
*/
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_lookup(&args);
|
||||
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_block_lookup(&args);
|
||||
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_leaf_lookup(&args);
|
||||
else
|
||||
rval = xfs_dir2_node_lookup(&args);
|
||||
if (rval == EEXIST)
|
||||
rval = 0;
|
||||
if (rval == 0)
|
||||
*inum = args.inumber;
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an entry from a directory.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_removename(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
char *name, /* name of entry to remove */
|
||||
int namelen, /* name length of entry to remove */
|
||||
xfs_ino_t ino, /* inode number of entry to remove */
|
||||
xfs_fsblock_t *first, /* bmap's firstblock */
|
||||
xfs_bmap_free_t *flist, /* bmap's freeblock list */
|
||||
xfs_extlen_t total) /* bmap's total block count */
|
||||
{
|
||||
xfs_da_args_t args; /* operation arguments */
|
||||
int rval; /* return value */
|
||||
int v; /* type-checking value */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
XFS_STATS_INC(xs_dir_remove);
|
||||
/*
|
||||
* Fill in the arg structure for this request.
|
||||
*/
|
||||
args.name = name;
|
||||
args.namelen = namelen;
|
||||
args.hashval = xfs_da_hashname(name, namelen);
|
||||
args.inumber = ino;
|
||||
args.dp = dp;
|
||||
args.firstblock = first;
|
||||
args.flist = flist;
|
||||
args.total = total;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = args.addname = args.oknoent = 0;
|
||||
/*
|
||||
* Decide on what work routines to call based on the inode size.
|
||||
*/
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_removename(&args);
|
||||
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_block_removename(&args);
|
||||
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_leaf_removename(&args);
|
||||
else
|
||||
rval = xfs_dir2_node_removename(&args);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a directory.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_getdents(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
uio_t *uio, /* caller's buffer control */
|
||||
int *eofp) /* out: eof reached */
|
||||
{
|
||||
int alignment; /* alignment required for ABI */
|
||||
xfs_dirent_t *dbp; /* malloc'ed buffer */
|
||||
xfs_dir2_put_t put; /* entry formatting routine */
|
||||
int rval; /* return value */
|
||||
int v; /* type-checking value */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
XFS_STATS_INC(xs_dir_getdents);
|
||||
/*
|
||||
* If our caller has given us a single contiguous aligned memory buffer,
|
||||
* just work directly within that buffer. If it's in user memory,
|
||||
* lock it down first.
|
||||
*/
|
||||
alignment = sizeof(xfs_off_t) - 1;
|
||||
if ((uio->uio_iovcnt == 1) &&
|
||||
(((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) &&
|
||||
((uio->uio_iov[0].iov_len & alignment) == 0)) {
|
||||
dbp = NULL;
|
||||
put = xfs_dir2_put_dirent64_direct;
|
||||
} else {
|
||||
dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);
|
||||
put = xfs_dir2_put_dirent64_uio;
|
||||
}
|
||||
|
||||
*eofp = 0;
|
||||
/*
|
||||
* Decide on what work routines to call based on the inode size.
|
||||
*/
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put);
|
||||
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
|
||||
;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put);
|
||||
else
|
||||
rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put);
|
||||
if (dbp != NULL)
|
||||
kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace the inode number of a directory entry.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_replace(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
char *name, /* name of entry to replace */
|
||||
int namelen, /* name length of entry to replace */
|
||||
xfs_ino_t inum, /* new inode number */
|
||||
xfs_fsblock_t *first, /* bmap's firstblock */
|
||||
xfs_bmap_free_t *flist, /* bmap's freeblock list */
|
||||
xfs_extlen_t total) /* bmap's total block count */
|
||||
{
|
||||
xfs_da_args_t args; /* operation arguments */
|
||||
int rval; /* return value */
|
||||
int v; /* type-checking value */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
|
||||
if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
|
||||
return rval;
|
||||
}
|
||||
/*
|
||||
* Fill in the arg structure for this request.
|
||||
*/
|
||||
args.name = name;
|
||||
args.namelen = namelen;
|
||||
args.hashval = xfs_da_hashname(name, namelen);
|
||||
args.inumber = inum;
|
||||
args.dp = dp;
|
||||
args.firstblock = first;
|
||||
args.flist = flist;
|
||||
args.total = total;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = args.addname = args.oknoent = 0;
|
||||
/*
|
||||
* Decide on what work routines to call based on the inode size.
|
||||
*/
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_replace(&args);
|
||||
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_block_replace(&args);
|
||||
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_leaf_replace(&args);
|
||||
else
|
||||
rval = xfs_dir2_node_replace(&args);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if this entry can be added to the directory without allocating space.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_canenter(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
char *name, /* name of entry to add */
|
||||
int namelen) /* name length of entry to add */
|
||||
{
|
||||
xfs_da_args_t args; /* operation arguments */
|
||||
int rval; /* return value */
|
||||
int v; /* type-checking value */
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
/*
|
||||
* Fill in the arg structure for this request.
|
||||
*/
|
||||
args.name = name;
|
||||
args.namelen = namelen;
|
||||
args.hashval = xfs_da_hashname(name, namelen);
|
||||
args.inumber = 0;
|
||||
args.dp = dp;
|
||||
args.firstblock = NULL;
|
||||
args.flist = NULL;
|
||||
args.total = 0;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = args.addname = args.oknoent = 1;
|
||||
/*
|
||||
* Decide on what work routines to call based on the inode size.
|
||||
*/
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_addname(&args);
|
||||
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_block_addname(&args);
|
||||
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
|
||||
return rval;
|
||||
} else if (v)
|
||||
rval = xfs_dir2_leaf_addname(&args);
|
||||
else
|
||||
rval = xfs_dir2_node_addname(&args);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy routine for shortform inode validation.
|
||||
* Can't really do this.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int /* error */
|
||||
xfs_dir2_shortform_validate_ondisk(
|
||||
xfs_mount_t *mp, /* filesystem mount point */
|
||||
xfs_dinode_t *dip) /* ondisk inode */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add a block to the directory.
|
||||
* This routine is for data and free blocks, not leaf/node blocks
|
||||
* which are handled by xfs_da_grow_inode.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_dir2_grow_inode(
|
||||
xfs_da_args_t *args, /* operation arguments */
|
||||
int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */
|
||||
xfs_dir2_db_t *dbp) /* out: block number added */
|
||||
{
|
||||
xfs_fileoff_t bno; /* directory offset of new block */
|
||||
int count; /* count of filesystem blocks */
|
||||
xfs_inode_t *dp; /* incore directory inode */
|
||||
int error; /* error return value */
|
||||
int got; /* blocks actually mapped */
|
||||
int i; /* temp mapping index */
|
||||
xfs_bmbt_irec_t map; /* single structure for bmap */
|
||||
int mapi; /* mapping index */
|
||||
xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
int nmap; /* number of bmap entries */
|
||||
xfs_trans_t *tp; /* transaction pointer */
|
||||
|
||||
xfs_dir2_trace_args_s("grow_inode", args, space);
|
||||
dp = args->dp;
|
||||
tp = args->trans;
|
||||
mp = dp->i_mount;
|
||||
/*
|
||||
* Set lowest possible block in the space requested.
|
||||
*/
|
||||
bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
|
||||
count = mp->m_dirblkfsbs;
|
||||
/*
|
||||
* Find the first hole for our block.
|
||||
*/
|
||||
if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) {
|
||||
return error;
|
||||
}
|
||||
nmap = 1;
|
||||
ASSERT(args->firstblock != NULL);
|
||||
/*
|
||||
* Try mapping the new block contiguously (one extent).
|
||||
*/
|
||||
if ((error = xfs_bmapi(tp, dp, bno, count,
|
||||
XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
|
||||
args->firstblock, args->total, &map, &nmap,
|
||||
args->flist, NULL))) {
|
||||
return error;
|
||||
}
|
||||
ASSERT(nmap <= 1);
|
||||
/*
|
||||
* Got it in 1.
|
||||
*/
|
||||
if (nmap == 1) {
|
||||
mapp = ↦
|
||||
mapi = 1;
|
||||
}
|
||||
/*
|
||||
* Didn't work and this is a multiple-fsb directory block.
|
||||
* Try again with contiguous flag turned on.
|
||||
*/
|
||||
else if (nmap == 0 && count > 1) {
|
||||
xfs_fileoff_t b; /* current file offset */
|
||||
|
||||
/*
|
||||
* Space for maximum number of mappings.
|
||||
*/
|
||||
mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP);
|
||||
/*
|
||||
* Iterate until we get to the end of our block.
|
||||
*/
|
||||
for (b = bno, mapi = 0; b < bno + count; ) {
|
||||
int c; /* current fsb count */
|
||||
|
||||
/*
|
||||
* Can't map more than MAX_NMAP at once.
|
||||
*/
|
||||
nmap = MIN(XFS_BMAP_MAX_NMAP, count);
|
||||
c = (int)(bno + count - b);
|
||||
if ((error = xfs_bmapi(tp, dp, b, c,
|
||||
XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
|
||||
args->firstblock, args->total,
|
||||
&mapp[mapi], &nmap, args->flist,
|
||||
NULL))) {
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
return error;
|
||||
}
|
||||
if (nmap < 1)
|
||||
break;
|
||||
/*
|
||||
* Add this bunch into our table, go to the next offset.
|
||||
*/
|
||||
mapi += nmap;
|
||||
b = mapp[mapi - 1].br_startoff +
|
||||
mapp[mapi - 1].br_blockcount;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Didn't work.
|
||||
*/
|
||||
else {
|
||||
mapi = 0;
|
||||
mapp = NULL;
|
||||
}
|
||||
/*
|
||||
* See how many fsb's we got.
|
||||
*/
|
||||
for (i = 0, got = 0; i < mapi; i++)
|
||||
got += mapp[i].br_blockcount;
|
||||
/*
|
||||
* Didn't get enough fsb's, or the first/last block's are wrong.
|
||||
*/
|
||||
if (got != count || mapp[0].br_startoff != bno ||
|
||||
mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
|
||||
bno + count) {
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
return XFS_ERROR(ENOSPC);
|
||||
}
|
||||
/*
|
||||
* Done with the temporary mapping table.
|
||||
*/
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
*dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno);
|
||||
/*
|
||||
* Update file's size if this is the data space and it grew.
|
||||
*/
|
||||
if (space == XFS_DIR2_DATA_SPACE) {
|
||||
xfs_fsize_t size; /* directory file (data) size */
|
||||
|
||||
size = XFS_FSB_TO_B(mp, bno + count);
|
||||
if (size > dp->i_d.di_size) {
|
||||
dp->i_d.di_size = size;
|
||||
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the directory is a single-block form directory.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_dir2_isblock(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
int *vp) /* out: 1 is block, 0 is not block */
|
||||
{
|
||||
xfs_fileoff_t last; /* last file offset */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
int rval; /* return value */
|
||||
|
||||
mp = dp->i_mount;
|
||||
if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
|
||||
return rval;
|
||||
}
|
||||
rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
|
||||
ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
|
||||
*vp = rval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the directory is a single-leaf form directory.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_dir2_isleaf(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_inode_t *dp, /* incore directory inode */
|
||||
int *vp) /* out: 1 is leaf, 0 is not leaf */
|
||||
{
|
||||
xfs_fileoff_t last; /* last file offset */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
int rval; /* return value */
|
||||
|
||||
mp = dp->i_mount;
|
||||
if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
|
||||
return rval;
|
||||
}
|
||||
*vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Getdents put routine for 64-bit ABI, direct form.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_put_dirent64_direct(
|
||||
xfs_dir2_put_args_t *pa) /* argument bundle */
|
||||
{
|
||||
struct dirent *idbp, dtmp; /* dirent pointer */
|
||||
iovec_t *iovp; /* io vector */
|
||||
int namelen; /* entry name length */
|
||||
int reclen; /* entry total length */
|
||||
uio_t *uio; /* I/O control */
|
||||
|
||||
namelen = pa->namelen;
|
||||
|
||||
dtmp.d_namlen = namelen;
|
||||
dtmp.d_reclen = GENERIC_DIRSIZ(&dtmp);
|
||||
reclen = dtmp.d_reclen;
|
||||
|
||||
uio = pa->uio;
|
||||
/*
|
||||
* Won't fit in the remaining space.
|
||||
*/
|
||||
if (reclen > uio->uio_resid) {
|
||||
pa->done = 0;
|
||||
return 0;
|
||||
}
|
||||
iovp = uio->uio_iov;
|
||||
idbp = (struct dirent *)iovp->iov_base;
|
||||
iovp->iov_base = (char *)idbp + reclen;
|
||||
iovp->iov_len -= reclen;
|
||||
uio->uio_resid -= reclen;
|
||||
idbp->d_reclen = reclen;
|
||||
idbp->d_fileno = pa->ino;
|
||||
idbp->d_type = DT_UNKNOWN;
|
||||
idbp->d_namlen = namelen;
|
||||
memcpy(idbp->d_name, pa->name, namelen);
|
||||
idbp->d_name[namelen] = '\0';
|
||||
pa->done = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Getdents put routine for 64-bit ABI, uio form.
|
||||
*/
|
||||
static int /* error */
|
||||
xfs_dir2_put_dirent64_uio(
|
||||
xfs_dir2_put_args_t *pa) /* argument bundle */
|
||||
{
|
||||
struct dirent *idbp, dtmp; /* dirent pointer */
|
||||
int namelen; /* entry name length */
|
||||
int reclen; /* entry total length */
|
||||
int rval; /* return value */
|
||||
uio_t *uio; /* I/O control */
|
||||
|
||||
namelen = pa->namelen;
|
||||
|
||||
dtmp.d_namlen = namelen;
|
||||
dtmp.d_reclen = GENERIC_DIRSIZ(&dtmp);
|
||||
reclen = dtmp.d_reclen;
|
||||
|
||||
uio = pa->uio;
|
||||
/*
|
||||
* Won't fit in the remaining space.
|
||||
*/
|
||||
if (reclen > uio->uio_resid) {
|
||||
pa->done = 0;
|
||||
return 0;
|
||||
}
|
||||
idbp = &dtmp;
|
||||
idbp->d_reclen = reclen;
|
||||
idbp->d_fileno = pa->ino;
|
||||
idbp->d_type = DT_UNKNOWN;
|
||||
idbp->d_namlen = namelen;
|
||||
memcpy(idbp->d_name, pa->name, namelen);
|
||||
idbp->d_name[namelen] = '\0';
|
||||
rval = uio_read((caddr_t)idbp, reclen, uio);
|
||||
pa->done = (rval == 0);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given block from the directory.
|
||||
* This routine is used for data and free blocks, leaf/node are done
|
||||
* by xfs_da_shrink_inode.
|
||||
*/
|
||||
int
|
||||
xfs_dir2_shrink_inode(
|
||||
xfs_da_args_t *args, /* operation arguments */
|
||||
xfs_dir2_db_t db, /* directory block number */
|
||||
xfs_dabuf_t *bp) /* block's buffer */
|
||||
{
|
||||
xfs_fileoff_t bno; /* directory file offset */
|
||||
xfs_dablk_t da; /* directory file offset */
|
||||
int done; /* bunmap is finished */
|
||||
xfs_inode_t *dp; /* incore directory inode */
|
||||
int error; /* error return value */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
xfs_trans_t *tp; /* transaction pointer */
|
||||
|
||||
xfs_dir2_trace_args_db("shrink_inode", args, db, bp);
|
||||
dp = args->dp;
|
||||
mp = dp->i_mount;
|
||||
tp = args->trans;
|
||||
da = XFS_DIR2_DB_TO_DA(mp, db);
|
||||
/*
|
||||
* Unmap the fsblock(s).
|
||||
*/
|
||||
if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
|
||||
XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
|
||||
NULL, &done))) {
|
||||
/*
|
||||
* ENOSPC actually can happen if we're in a removename with
|
||||
* no space reservation, and the resulting block removal
|
||||
* would cause a bmap btree split or conversion from extents
|
||||
* to btree. This can only happen for un-fragmented
|
||||
* directory blocks, since you need to be punching out
|
||||
* the middle of an extent.
|
||||
* In this case we need to leave the block in the file,
|
||||
* and not binval it.
|
||||
* So the block has to be in a consistent empty state
|
||||
* and appropriately logged.
|
||||
* We don't free up the buffer, the caller can tell it
|
||||
* hasn't happened since it got an error back.
|
||||
*/
|
||||
return error;
|
||||
}
|
||||
ASSERT(done);
|
||||
/*
|
||||
* Invalidate the buffer from the transaction.
|
||||
*/
|
||||
xfs_da_binval(tp, bp);
|
||||
/*
|
||||
* If it's not a data block, we're done.
|
||||
*/
|
||||
if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
|
||||
return 0;
|
||||
/*
|
||||
* If the block isn't the last one in the directory, we're done.
|
||||
*/
|
||||
if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0))
|
||||
return 0;
|
||||
bno = da;
|
||||
if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
|
||||
/*
|
||||
* This can't really happen unless there's kernel corruption.
|
||||
*/
|
||||
return error;
|
||||
}
|
||||
if (db == mp->m_dirdatablk)
|
||||
ASSERT(bno == 0);
|
||||
else
|
||||
ASSERT(bno > 0);
|
||||
/*
|
||||
* Set the size to the new last block.
|
||||
*/
|
||||
dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
|
||||
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DIR2_H__
|
||||
#define __XFS_DIR2_H__
|
||||
|
||||
struct uio;
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_dir2_put_args;
|
||||
struct xfs_inode;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* Directory version 2.
|
||||
* There are 4 possible formats:
|
||||
* shortform
|
||||
* single block - data with embedded leaf at the end
|
||||
* multiple data blocks, single leaf+freeindex block
|
||||
* data blocks, node&leaf blocks (btree), freeindex blocks
|
||||
*
|
||||
* The shortform format is in xfs_dir2_sf.h.
|
||||
* The single block format is in xfs_dir2_block.h.
|
||||
* The data block format is in xfs_dir2_data.h.
|
||||
* The leaf and freeindex block formats are in xfs_dir2_leaf.h.
|
||||
* Node blocks are the same as the other version, in xfs_da_btree.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Byte offset in data block and shortform entry.
|
||||
*/
|
||||
typedef __uint16_t xfs_dir2_data_off_t;
|
||||
#define NULLDATAOFF 0xffffU
|
||||
typedef uint xfs_dir2_data_aoff_t; /* argument form */
|
||||
|
||||
/*
|
||||
* Directory block number (logical dirblk in file)
|
||||
*/
|
||||
typedef __uint32_t xfs_dir2_db_t;
|
||||
|
||||
/*
|
||||
* Byte offset in a directory.
|
||||
*/
|
||||
typedef xfs_off_t xfs_dir2_off_t;
|
||||
|
||||
/*
|
||||
* For getdents, argument struct for put routines.
|
||||
*/
|
||||
typedef int (*xfs_dir2_put_t)(struct xfs_dir2_put_args *pa);
|
||||
typedef struct xfs_dir2_put_args {
|
||||
xfs_off_t cook; /* cookie of (next) entry */
|
||||
xfs_intino_t ino; /* inode number */
|
||||
xfs_dirent_t *dbp; /* buffer pointer */
|
||||
char *name; /* directory entry name */
|
||||
int namelen; /* length of name */
|
||||
int done; /* output: set if value was stored */
|
||||
xfs_dir2_put_t put; /* put function ptr (i/o) */
|
||||
struct uio *uio; /* uio control structure */
|
||||
} xfs_dir2_put_args_t;
|
||||
|
||||
/*
|
||||
* Other interfaces used by the rest of the dir v2 code.
|
||||
*/
|
||||
extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
|
||||
xfs_dir2_db_t *dbp);
|
||||
extern int xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
int *vp);
|
||||
extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
int *vp);
|
||||
extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
|
||||
struct xfs_dabuf *bp);
|
||||
|
||||
#endif /* __XFS_DIR2_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DIR2_BLOCK_H__
|
||||
#define __XFS_DIR2_BLOCK_H__
|
||||
|
||||
/*
|
||||
* xfs_dir2_block.h
|
||||
* Directory version 2, single block format structures
|
||||
*/
|
||||
|
||||
struct uio;
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_dir2_data_hdr;
|
||||
struct xfs_dir2_leaf_entry;
|
||||
struct xfs_inode;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* The single block format is as follows:
|
||||
* xfs_dir2_data_hdr_t structure
|
||||
* xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures
|
||||
* xfs_dir2_leaf_entry_t structures
|
||||
* xfs_dir2_block_tail_t structure
|
||||
*/
|
||||
|
||||
#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */
|
||||
|
||||
typedef struct xfs_dir2_block_tail {
|
||||
__be32 count; /* count of leaf entries */
|
||||
__be32 stale; /* count of stale lf entries */
|
||||
} xfs_dir2_block_tail_t;
|
||||
|
||||
/*
|
||||
* Generic single-block structure, for xfs_db.
|
||||
*/
|
||||
typedef struct xfs_dir2_block {
|
||||
xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_BLOCK_MAGIC */
|
||||
xfs_dir2_data_union_t u[1];
|
||||
xfs_dir2_leaf_entry_t leaf[1];
|
||||
xfs_dir2_block_tail_t tail;
|
||||
} xfs_dir2_block_t;
|
||||
|
||||
/*
|
||||
* Pointer to the leaf header embedded in a data block (1-block format)
|
||||
*/
|
||||
#define XFS_DIR2_BLOCK_TAIL_P(mp,block) xfs_dir2_block_tail_p(mp,block)
|
||||
static inline xfs_dir2_block_tail_t *
|
||||
xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block)
|
||||
{
|
||||
return (((xfs_dir2_block_tail_t *)
|
||||
((char *)(block) + (mp)->m_dirblksize)) - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointer to the leaf entries embedded in a data block (1-block format)
|
||||
*/
|
||||
#define XFS_DIR2_BLOCK_LEAF_P(btp) xfs_dir2_block_leaf_p(btp)
|
||||
static inline struct xfs_dir2_leaf_entry *
|
||||
xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
|
||||
{
|
||||
return ((struct xfs_dir2_leaf_entry *)btp) - be32_to_cpu(btp->count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function declarations.
|
||||
*/
|
||||
extern int xfs_dir2_block_addname(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_block_getdents(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
struct uio *uio, int *eofp,
|
||||
struct xfs_dirent *dbp, xfs_dir2_put_t put);
|
||||
extern int xfs_dir2_block_lookup(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_block_removename(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_block_replace(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
|
||||
struct xfs_dabuf *lbp, struct xfs_dabuf *dbp);
|
||||
extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
|
||||
|
||||
#endif /* __XFS_DIR2_BLOCK_H__ */
|
@ -1,837 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_types.h"
|
||||
#include "xfs_log.h"
|
||||
#include "xfs_inum.h"
|
||||
#include "xfs_trans.h"
|
||||
#include "xfs_sb.h"
|
||||
#include "xfs_dir.h"
|
||||
#include "xfs_dir2.h"
|
||||
#include "xfs_dmapi.h"
|
||||
#include "xfs_mount.h"
|
||||
#include "xfs_da_btree.h"
|
||||
#include "xfs_bmap_btree.h"
|
||||
#include "xfs_dir_sf.h"
|
||||
#include "xfs_dir2_sf.h"
|
||||
#include "xfs_attr_sf.h"
|
||||
#include "xfs_dinode.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_dir_leaf.h"
|
||||
#include "xfs_dir2_data.h"
|
||||
#include "xfs_dir2_leaf.h"
|
||||
#include "xfs_dir2_block.h"
|
||||
#include "xfs_error.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Check the consistency of the data block.
|
||||
* The input can also be a block-format directory.
|
||||
* Pop an assert if we find anything bad.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_check(
|
||||
xfs_inode_t *dp, /* incore inode pointer */
|
||||
xfs_dabuf_t *bp) /* data block's buffer */
|
||||
{
|
||||
xfs_dir2_dataptr_t addr; /* addr for leaf lookup */
|
||||
xfs_dir2_data_free_t *bf; /* bestfree table */
|
||||
xfs_dir2_block_tail_t *btp=NULL; /* block tail */
|
||||
int count; /* count of entries found */
|
||||
xfs_dir2_data_t *d; /* data block pointer */
|
||||
xfs_dir2_data_entry_t *dep; /* data entry */
|
||||
xfs_dir2_data_free_t *dfp; /* bestfree entry */
|
||||
xfs_dir2_data_unused_t *dup; /* unused entry */
|
||||
char *endp; /* end of useful data */
|
||||
int freeseen; /* mask of bestfrees seen */
|
||||
xfs_dahash_t hash; /* hash of current name */
|
||||
int i; /* leaf index */
|
||||
int lastfree; /* last entry was unused */
|
||||
xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
char *p; /* current data position */
|
||||
int stale; /* count of stale leaves */
|
||||
|
||||
mp = dp->i_mount;
|
||||
d = bp->data;
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
bf = d->hdr.bestfree;
|
||||
p = (char *)d->u;
|
||||
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
|
||||
btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
|
||||
lep = XFS_DIR2_BLOCK_LEAF_P(btp);
|
||||
endp = (char *)lep;
|
||||
} else
|
||||
endp = (char *)d + mp->m_dirblksize;
|
||||
count = lastfree = freeseen = 0;
|
||||
/*
|
||||
* Account for zero bestfree entries.
|
||||
*/
|
||||
if (!bf[0].length) {
|
||||
ASSERT(!bf[0].offset);
|
||||
freeseen |= 1 << 0;
|
||||
}
|
||||
if (!bf[1].length) {
|
||||
ASSERT(!bf[1].offset);
|
||||
freeseen |= 1 << 1;
|
||||
}
|
||||
if (!bf[2].length) {
|
||||
ASSERT(!bf[2].offset);
|
||||
freeseen |= 1 << 2;
|
||||
}
|
||||
ASSERT(be16_to_cpu(bf[0].length) >= be16_to_cpu(bf[1].length));
|
||||
ASSERT(be16_to_cpu(bf[1].length) >= be16_to_cpu(bf[2].length));
|
||||
/*
|
||||
* Loop over the data/unused entries.
|
||||
*/
|
||||
while (p < endp) {
|
||||
dup = (xfs_dir2_data_unused_t *)p;
|
||||
/*
|
||||
* If it's unused, look for the space in the bestfree table.
|
||||
* If we find it, account for that, else make sure it
|
||||
* doesn't need to be there.
|
||||
*/
|
||||
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
|
||||
ASSERT(lastfree == 0);
|
||||
ASSERT(be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)) ==
|
||||
(char *)dup - (char *)d);
|
||||
dfp = xfs_dir2_data_freefind(d, dup);
|
||||
if (dfp) {
|
||||
i = (int)(dfp - bf);
|
||||
ASSERT((freeseen & (1 << i)) == 0);
|
||||
freeseen |= 1 << i;
|
||||
} else {
|
||||
ASSERT(be16_to_cpu(dup->length) <=
|
||||
be16_to_cpu(bf[2].length));
|
||||
}
|
||||
p += be16_to_cpu(dup->length);
|
||||
lastfree = 1;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* It's a real entry. Validate the fields.
|
||||
* If this is a block directory then make sure it's
|
||||
* in the leaf section of the block.
|
||||
* The linear search is crude but this is DEBUG code.
|
||||
*/
|
||||
dep = (xfs_dir2_data_entry_t *)p;
|
||||
ASSERT(dep->namelen != 0);
|
||||
ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0);
|
||||
ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) ==
|
||||
(char *)dep - (char *)d);
|
||||
count++;
|
||||
lastfree = 0;
|
||||
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
|
||||
addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
|
||||
(xfs_dir2_data_aoff_t)
|
||||
((char *)dep - (char *)d));
|
||||
hash = xfs_da_hashname((char *)dep->name, dep->namelen);
|
||||
for (i = 0; i < be32_to_cpu(btp->count); i++) {
|
||||
if (be32_to_cpu(lep[i].address) == addr &&
|
||||
be32_to_cpu(lep[i].hashval) == hash)
|
||||
break;
|
||||
}
|
||||
ASSERT(i < be32_to_cpu(btp->count));
|
||||
}
|
||||
p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
|
||||
}
|
||||
/*
|
||||
* Need to have seen all the entries and all the bestfree slots.
|
||||
*/
|
||||
ASSERT(freeseen == 7);
|
||||
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
|
||||
for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
|
||||
if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
|
||||
stale++;
|
||||
if (i > 0)
|
||||
ASSERT(be32_to_cpu(lep[i].hashval) >= be32_to_cpu(lep[i - 1].hashval));
|
||||
}
|
||||
ASSERT(count == be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
|
||||
ASSERT(stale == be32_to_cpu(btp->stale));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Given a data block and an unused entry from that block,
|
||||
* return the bestfree entry if any that corresponds to it.
|
||||
*/
|
||||
xfs_dir2_data_free_t *
|
||||
xfs_dir2_data_freefind(
|
||||
xfs_dir2_data_t *d, /* data block */
|
||||
xfs_dir2_data_unused_t *dup) /* data unused entry */
|
||||
{
|
||||
xfs_dir2_data_free_t *dfp; /* bestfree entry */
|
||||
xfs_dir2_data_aoff_t off; /* offset value needed */
|
||||
#if defined(DEBUG) && defined(__KERNEL__)
|
||||
int matched; /* matched the value */
|
||||
int seenzero; /* saw a 0 bestfree entry */
|
||||
#endif
|
||||
|
||||
off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)d);
|
||||
#if defined(DEBUG) && defined(__KERNEL__)
|
||||
/*
|
||||
* Validate some consistency in the bestfree table.
|
||||
* Check order, non-overlapping entries, and if we find the
|
||||
* one we're looking for it has to be exact.
|
||||
*/
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
for (dfp = &d->hdr.bestfree[0], seenzero = matched = 0;
|
||||
dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT];
|
||||
dfp++) {
|
||||
if (!dfp->offset) {
|
||||
ASSERT(!dfp->length);
|
||||
seenzero = 1;
|
||||
continue;
|
||||
}
|
||||
ASSERT(seenzero == 0);
|
||||
if (be16_to_cpu(dfp->offset) == off) {
|
||||
matched = 1;
|
||||
ASSERT(dfp->length == dup->length);
|
||||
} else if (off < be16_to_cpu(dfp->offset))
|
||||
ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset));
|
||||
else
|
||||
ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
|
||||
ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
|
||||
if (dfp > &d->hdr.bestfree[0])
|
||||
ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* If this is smaller than the smallest bestfree entry,
|
||||
* it can't be there since they're sorted.
|
||||
*/
|
||||
if (be16_to_cpu(dup->length) <
|
||||
be16_to_cpu(d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length))
|
||||
return NULL;
|
||||
/*
|
||||
* Look at the three bestfree entries for our guy.
|
||||
*/
|
||||
for (dfp = &d->hdr.bestfree[0];
|
||||
dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT];
|
||||
dfp++) {
|
||||
if (!dfp->offset)
|
||||
return NULL;
|
||||
if (be16_to_cpu(dfp->offset) == off)
|
||||
return dfp;
|
||||
}
|
||||
/*
|
||||
* Didn't find it. This only happens if there are duplicate lengths.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an unused-space entry into the bestfree table.
|
||||
*/
|
||||
xfs_dir2_data_free_t * /* entry inserted */
|
||||
xfs_dir2_data_freeinsert(
|
||||
xfs_dir2_data_t *d, /* data block pointer */
|
||||
xfs_dir2_data_unused_t *dup, /* unused space */
|
||||
int *loghead) /* log the data header (out) */
|
||||
{
|
||||
xfs_dir2_data_free_t *dfp; /* bestfree table pointer */
|
||||
xfs_dir2_data_free_t new; /* new bestfree entry */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
#endif
|
||||
dfp = d->hdr.bestfree;
|
||||
new.length = dup->length;
|
||||
new.offset = cpu_to_be16((char *)dup - (char *)d);
|
||||
/*
|
||||
* Insert at position 0, 1, or 2; or not at all.
|
||||
*/
|
||||
if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
|
||||
dfp[2] = dfp[1];
|
||||
dfp[1] = dfp[0];
|
||||
dfp[0] = new;
|
||||
*loghead = 1;
|
||||
return &dfp[0];
|
||||
}
|
||||
if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
|
||||
dfp[2] = dfp[1];
|
||||
dfp[1] = new;
|
||||
*loghead = 1;
|
||||
return &dfp[1];
|
||||
}
|
||||
if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
|
||||
dfp[2] = new;
|
||||
*loghead = 1;
|
||||
return &dfp[2];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a bestfree entry from the table.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_dir2_data_freeremove(
|
||||
xfs_dir2_data_t *d, /* data block pointer */
|
||||
xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */
|
||||
int *loghead) /* out: log data header */
|
||||
{
|
||||
#ifdef __KERNEL__
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
#endif
|
||||
/*
|
||||
* It's the first entry, slide the next 2 up.
|
||||
*/
|
||||
if (dfp == &d->hdr.bestfree[0]) {
|
||||
d->hdr.bestfree[0] = d->hdr.bestfree[1];
|
||||
d->hdr.bestfree[1] = d->hdr.bestfree[2];
|
||||
}
|
||||
/*
|
||||
* It's the second entry, slide the 3rd entry up.
|
||||
*/
|
||||
else if (dfp == &d->hdr.bestfree[1])
|
||||
d->hdr.bestfree[1] = d->hdr.bestfree[2];
|
||||
/*
|
||||
* Must be the last entry.
|
||||
*/
|
||||
else
|
||||
ASSERT(dfp == &d->hdr.bestfree[2]);
|
||||
/*
|
||||
* Clear the 3rd entry, must be zero now.
|
||||
*/
|
||||
d->hdr.bestfree[2].length = 0;
|
||||
d->hdr.bestfree[2].offset = 0;
|
||||
*loghead = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a data block, reconstruct its bestfree map.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_freescan(
|
||||
xfs_mount_t *mp, /* filesystem mount point */
|
||||
xfs_dir2_data_t *d, /* data block pointer */
|
||||
int *loghead, /* out: log data header */
|
||||
char *aendp) /* in: caller's endp */
|
||||
{
|
||||
xfs_dir2_block_tail_t *btp; /* block tail */
|
||||
xfs_dir2_data_entry_t *dep; /* active data entry */
|
||||
xfs_dir2_data_unused_t *dup; /* unused data entry */
|
||||
char *endp; /* end of block's data */
|
||||
char *p; /* current entry pointer */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
#endif
|
||||
/*
|
||||
* Start by clearing the table.
|
||||
*/
|
||||
memset(d->hdr.bestfree, 0, sizeof(d->hdr.bestfree));
|
||||
*loghead = 1;
|
||||
/*
|
||||
* Set up pointers.
|
||||
*/
|
||||
p = (char *)d->u;
|
||||
if (aendp)
|
||||
endp = aendp;
|
||||
else if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
|
||||
btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
|
||||
endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
|
||||
} else
|
||||
endp = (char *)d + mp->m_dirblksize;
|
||||
/*
|
||||
* Loop over the block's entries.
|
||||
*/
|
||||
while (p < endp) {
|
||||
dup = (xfs_dir2_data_unused_t *)p;
|
||||
/*
|
||||
* If it's a free entry, insert it.
|
||||
*/
|
||||
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
|
||||
ASSERT((char *)dup - (char *)d ==
|
||||
be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
|
||||
xfs_dir2_data_freeinsert(d, dup, loghead);
|
||||
p += be16_to_cpu(dup->length);
|
||||
}
|
||||
/*
|
||||
* For active entries, check their tags and skip them.
|
||||
*/
|
||||
else {
|
||||
dep = (xfs_dir2_data_entry_t *)p;
|
||||
ASSERT((char *)dep - (char *)d ==
|
||||
be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)));
|
||||
p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a data block at the given block number in the directory.
|
||||
* Give back the buffer for the created block.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_dir2_data_init(
|
||||
xfs_da_args_t *args, /* directory operation args */
|
||||
xfs_dir2_db_t blkno, /* logical dir block number */
|
||||
xfs_dabuf_t **bpp) /* output block buffer */
|
||||
{
|
||||
xfs_dabuf_t *bp; /* block buffer */
|
||||
xfs_dir2_data_t *d; /* pointer to block */
|
||||
xfs_inode_t *dp; /* incore directory inode */
|
||||
xfs_dir2_data_unused_t *dup; /* unused entry pointer */
|
||||
int error; /* error return value */
|
||||
int i; /* bestfree index */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
xfs_trans_t *tp; /* transaction pointer */
|
||||
int t; /* temp */
|
||||
|
||||
dp = args->dp;
|
||||
mp = dp->i_mount;
|
||||
tp = args->trans;
|
||||
/*
|
||||
* Get the buffer set up for the block.
|
||||
*/
|
||||
error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp,
|
||||
XFS_DATA_FORK);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
ASSERT(bp != NULL);
|
||||
/*
|
||||
* Initialize the header.
|
||||
*/
|
||||
d = bp->data;
|
||||
d->hdr.magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
|
||||
d->hdr.bestfree[0].offset = cpu_to_be16(sizeof(d->hdr));
|
||||
for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
|
||||
d->hdr.bestfree[i].length = 0;
|
||||
d->hdr.bestfree[i].offset = 0;
|
||||
}
|
||||
/*
|
||||
* Set up an unused entry for the block's body.
|
||||
*/
|
||||
dup = &d->u[0].unused;
|
||||
dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
|
||||
|
||||
t=mp->m_dirblksize - (uint)sizeof(d->hdr);
|
||||
d->hdr.bestfree[0].length = cpu_to_be16(t);
|
||||
dup->length = cpu_to_be16(t);
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16((char *)dup - (char *)d);
|
||||
/*
|
||||
* Log it and return it.
|
||||
*/
|
||||
xfs_dir2_data_log_header(tp, bp);
|
||||
xfs_dir2_data_log_unused(tp, bp, dup);
|
||||
*bpp = bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log an active data entry from the block.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_log_entry(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_dabuf_t *bp, /* block buffer */
|
||||
xfs_dir2_data_entry_t *dep) /* data entry pointer */
|
||||
{
|
||||
xfs_dir2_data_t *d; /* data block pointer */
|
||||
|
||||
d = bp->data;
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d),
|
||||
(uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) -
|
||||
(char *)d - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Log a data block header.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_log_header(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_dabuf_t *bp) /* block buffer */
|
||||
{
|
||||
xfs_dir2_data_t *d; /* data block pointer */
|
||||
|
||||
d = bp->data;
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d),
|
||||
(uint)(sizeof(d->hdr) - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Log a data unused entry.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_log_unused(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_dabuf_t *bp, /* block buffer */
|
||||
xfs_dir2_data_unused_t *dup) /* data unused pointer */
|
||||
{
|
||||
xfs_dir2_data_t *d; /* data block pointer */
|
||||
|
||||
d = bp->data;
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
/*
|
||||
* Log the first part of the unused entry.
|
||||
*/
|
||||
xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)d),
|
||||
(uint)((char *)&dup->length + sizeof(dup->length) -
|
||||
1 - (char *)d));
|
||||
/*
|
||||
* Log the end (tag) of the unused entry.
|
||||
*/
|
||||
xfs_da_log_buf(tp, bp,
|
||||
(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d),
|
||||
(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d +
|
||||
sizeof(xfs_dir2_data_off_t) - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a byte range in the data block unused.
|
||||
* Its current contents are unimportant.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_make_free(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_dabuf_t *bp, /* block buffer */
|
||||
xfs_dir2_data_aoff_t offset, /* starting byte offset */
|
||||
xfs_dir2_data_aoff_t len, /* length in bytes */
|
||||
int *needlogp, /* out: log header */
|
||||
int *needscanp) /* out: regen bestfree */
|
||||
{
|
||||
xfs_dir2_data_t *d; /* data block pointer */
|
||||
xfs_dir2_data_free_t *dfp; /* bestfree pointer */
|
||||
char *endptr; /* end of data area */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
int needscan; /* need to regen bestfree */
|
||||
xfs_dir2_data_unused_t *newdup; /* new unused entry */
|
||||
xfs_dir2_data_unused_t *postdup; /* unused entry after us */
|
||||
xfs_dir2_data_unused_t *prevdup; /* unused entry before us */
|
||||
|
||||
mp = tp->t_mountp;
|
||||
d = bp->data;
|
||||
/*
|
||||
* Figure out where the end of the data area is.
|
||||
*/
|
||||
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC)
|
||||
endptr = (char *)d + mp->m_dirblksize;
|
||||
else {
|
||||
xfs_dir2_block_tail_t *btp; /* block tail */
|
||||
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
|
||||
endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
|
||||
}
|
||||
/*
|
||||
* If this isn't the start of the block, then back up to
|
||||
* the previous entry and see if it's free.
|
||||
*/
|
||||
if (offset > sizeof(d->hdr)) {
|
||||
__be16 *tagp; /* tag just before us */
|
||||
|
||||
tagp = (__be16 *)((char *)d + offset) - 1;
|
||||
prevdup = (xfs_dir2_data_unused_t *)((char *)d + be16_to_cpu(*tagp));
|
||||
if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
|
||||
prevdup = NULL;
|
||||
} else
|
||||
prevdup = NULL;
|
||||
/*
|
||||
* If this isn't the end of the block, see if the entry after
|
||||
* us is free.
|
||||
*/
|
||||
if ((char *)d + offset + len < endptr) {
|
||||
postdup =
|
||||
(xfs_dir2_data_unused_t *)((char *)d + offset + len);
|
||||
if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
|
||||
postdup = NULL;
|
||||
} else
|
||||
postdup = NULL;
|
||||
ASSERT(*needscanp == 0);
|
||||
needscan = 0;
|
||||
/*
|
||||
* Previous and following entries are both free,
|
||||
* merge everything into a single free entry.
|
||||
*/
|
||||
if (prevdup && postdup) {
|
||||
xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */
|
||||
|
||||
/*
|
||||
* See if prevdup and/or postdup are in bestfree table.
|
||||
*/
|
||||
dfp = xfs_dir2_data_freefind(d, prevdup);
|
||||
dfp2 = xfs_dir2_data_freefind(d, postdup);
|
||||
/*
|
||||
* We need a rescan unless there are exactly 2 free entries
|
||||
* namely our two. Then we know what's happening, otherwise
|
||||
* since the third bestfree is there, there might be more
|
||||
* entries.
|
||||
*/
|
||||
needscan = (d->hdr.bestfree[2].length != 0);
|
||||
/*
|
||||
* Fix up the new big freespace.
|
||||
*/
|
||||
be16_add(&prevdup->length, len + be16_to_cpu(postdup->length));
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
|
||||
cpu_to_be16((char *)prevdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, prevdup);
|
||||
if (!needscan) {
|
||||
/*
|
||||
* Has to be the case that entries 0 and 1 are
|
||||
* dfp and dfp2 (don't know which is which), and
|
||||
* entry 2 is empty.
|
||||
* Remove entry 1 first then entry 0.
|
||||
*/
|
||||
ASSERT(dfp && dfp2);
|
||||
if (dfp == &d->hdr.bestfree[1]) {
|
||||
dfp = &d->hdr.bestfree[0];
|
||||
ASSERT(dfp2 == dfp);
|
||||
dfp2 = &d->hdr.bestfree[1];
|
||||
}
|
||||
xfs_dir2_data_freeremove(d, dfp2, needlogp);
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
/*
|
||||
* Now insert the new entry.
|
||||
*/
|
||||
dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp);
|
||||
ASSERT(dfp == &d->hdr.bestfree[0]);
|
||||
ASSERT(dfp->length == prevdup->length);
|
||||
ASSERT(!dfp[1].length);
|
||||
ASSERT(!dfp[2].length);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The entry before us is free, merge with it.
|
||||
*/
|
||||
else if (prevdup) {
|
||||
dfp = xfs_dir2_data_freefind(d, prevdup);
|
||||
be16_add(&prevdup->length, len);
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
|
||||
cpu_to_be16((char *)prevdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, prevdup);
|
||||
/*
|
||||
* If the previous entry was in the table, the new entry
|
||||
* is longer, so it will be in the table too. Remove
|
||||
* the old one and add the new one.
|
||||
*/
|
||||
if (dfp) {
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
(void)xfs_dir2_data_freeinsert(d, prevdup, needlogp);
|
||||
}
|
||||
/*
|
||||
* Otherwise we need a scan if the new entry is big enough.
|
||||
*/
|
||||
else {
|
||||
needscan = be16_to_cpu(prevdup->length) >
|
||||
be16_to_cpu(d->hdr.bestfree[2].length);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The following entry is free, merge with it.
|
||||
*/
|
||||
else if (postdup) {
|
||||
dfp = xfs_dir2_data_freefind(d, postdup);
|
||||
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
|
||||
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
|
||||
newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
|
||||
cpu_to_be16((char *)newdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, newdup);
|
||||
/*
|
||||
* If the following entry was in the table, the new entry
|
||||
* is longer, so it will be in the table too. Remove
|
||||
* the old one and add the new one.
|
||||
*/
|
||||
if (dfp) {
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);
|
||||
}
|
||||
/*
|
||||
* Otherwise we need a scan if the new entry is big enough.
|
||||
*/
|
||||
else {
|
||||
needscan = be16_to_cpu(newdup->length) >
|
||||
be16_to_cpu(d->hdr.bestfree[2].length);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Neither neighbor is free. Make a new entry.
|
||||
*/
|
||||
else {
|
||||
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
|
||||
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
|
||||
newdup->length = cpu_to_be16(len);
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
|
||||
cpu_to_be16((char *)newdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, newdup);
|
||||
(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);
|
||||
}
|
||||
*needscanp = needscan;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a byte range out of an existing unused space and make it un-free.
|
||||
*/
|
||||
void
|
||||
xfs_dir2_data_use_free(
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_dabuf_t *bp, /* data block buffer */
|
||||
xfs_dir2_data_unused_t *dup, /* unused entry */
|
||||
xfs_dir2_data_aoff_t offset, /* starting offset to use */
|
||||
xfs_dir2_data_aoff_t len, /* length to use */
|
||||
int *needlogp, /* out: need to log header */
|
||||
int *needscanp) /* out: need regen bestfree */
|
||||
{
|
||||
xfs_dir2_data_t *d; /* data block */
|
||||
xfs_dir2_data_free_t *dfp; /* bestfree pointer */
|
||||
int matchback; /* matches end of freespace */
|
||||
int matchfront; /* matches start of freespace */
|
||||
int needscan; /* need to regen bestfree */
|
||||
xfs_dir2_data_unused_t *newdup; /* new unused entry */
|
||||
xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
|
||||
int oldlen; /* old unused entry's length */
|
||||
|
||||
d = bp->data;
|
||||
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
|
||||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
|
||||
ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
|
||||
ASSERT(offset >= (char *)dup - (char *)d);
|
||||
ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)d);
|
||||
ASSERT((char *)dup - (char *)d == be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
|
||||
/*
|
||||
* Look up the entry in the bestfree table.
|
||||
*/
|
||||
dfp = xfs_dir2_data_freefind(d, dup);
|
||||
oldlen = be16_to_cpu(dup->length);
|
||||
ASSERT(dfp || oldlen <= be16_to_cpu(d->hdr.bestfree[2].length));
|
||||
/*
|
||||
* Check for alignment with front and back of the entry.
|
||||
*/
|
||||
matchfront = (char *)dup - (char *)d == offset;
|
||||
matchback = (char *)dup + oldlen - (char *)d == offset + len;
|
||||
ASSERT(*needscanp == 0);
|
||||
needscan = 0;
|
||||
/*
|
||||
* If we matched it exactly we just need to get rid of it from
|
||||
* the bestfree table.
|
||||
*/
|
||||
if (matchfront && matchback) {
|
||||
if (dfp) {
|
||||
needscan = (d->hdr.bestfree[2].offset != 0);
|
||||
if (!needscan)
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We match the first part of the entry.
|
||||
* Make a new entry with the remaining freespace.
|
||||
*/
|
||||
else if (matchfront) {
|
||||
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
|
||||
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
|
||||
newdup->length = cpu_to_be16(oldlen - len);
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
|
||||
cpu_to_be16((char *)newdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, newdup);
|
||||
/*
|
||||
* If it was in the table, remove it and add the new one.
|
||||
*/
|
||||
if (dfp) {
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp);
|
||||
ASSERT(dfp != NULL);
|
||||
ASSERT(dfp->length == newdup->length);
|
||||
ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)d);
|
||||
/*
|
||||
* If we got inserted at the last slot,
|
||||
* that means we don't know if there was a better
|
||||
* choice for the last slot, or not. Rescan.
|
||||
*/
|
||||
needscan = dfp == &d->hdr.bestfree[2];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We match the last part of the entry.
|
||||
* Trim the allocated space off the tail of the entry.
|
||||
*/
|
||||
else if (matchback) {
|
||||
newdup = dup;
|
||||
newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
|
||||
cpu_to_be16((char *)newdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, newdup);
|
||||
/*
|
||||
* If it was in the table, remove it and add the new one.
|
||||
*/
|
||||
if (dfp) {
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp);
|
||||
ASSERT(dfp != NULL);
|
||||
ASSERT(dfp->length == newdup->length);
|
||||
ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)d);
|
||||
/*
|
||||
* If we got inserted at the last slot,
|
||||
* that means we don't know if there was a better
|
||||
* choice for the last slot, or not. Rescan.
|
||||
*/
|
||||
needscan = dfp == &d->hdr.bestfree[2];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Poking out the middle of an entry.
|
||||
* Make two new entries.
|
||||
*/
|
||||
else {
|
||||
newdup = dup;
|
||||
newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
|
||||
cpu_to_be16((char *)newdup - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, newdup);
|
||||
newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
|
||||
newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
|
||||
newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
|
||||
*XFS_DIR2_DATA_UNUSED_TAG_P(newdup2) =
|
||||
cpu_to_be16((char *)newdup2 - (char *)d);
|
||||
xfs_dir2_data_log_unused(tp, bp, newdup2);
|
||||
/*
|
||||
* If the old entry was in the table, we need to scan
|
||||
* if the 3rd entry was valid, since these entries
|
||||
* are smaller than the old one.
|
||||
* If we don't need to scan that means there were 1 or 2
|
||||
* entries in the table, and removing the old and adding
|
||||
* the 2 new will work.
|
||||
*/
|
||||
if (dfp) {
|
||||
needscan = (d->hdr.bestfree[2].length != 0);
|
||||
if (!needscan) {
|
||||
xfs_dir2_data_freeremove(d, dfp, needlogp);
|
||||
(void)xfs_dir2_data_freeinsert(d, newdup,
|
||||
needlogp);
|
||||
(void)xfs_dir2_data_freeinsert(d, newdup2,
|
||||
needlogp);
|
||||
}
|
||||
}
|
||||
}
|
||||
*needscanp = needscan;
|
||||
}
|
@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DIR2_DATA_H__
|
||||
#define __XFS_DIR2_DATA_H__
|
||||
|
||||
/*
|
||||
* Directory format 2, data block structures.
|
||||
*/
|
||||
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_inode;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
#define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: for multiblock dirs */
|
||||
#define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */
|
||||
#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG)
|
||||
#define XFS_DIR2_DATA_FREE_TAG 0xffff
|
||||
#define XFS_DIR2_DATA_FD_COUNT 3
|
||||
|
||||
/*
|
||||
* Directory address space divided into sections,
|
||||
* spaces separated by 32gb.
|
||||
*/
|
||||
#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
|
||||
#define XFS_DIR2_DATA_SPACE 0
|
||||
#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE)
|
||||
#define XFS_DIR2_DATA_FIRSTDB(mp) \
|
||||
XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATA_OFFSET)
|
||||
|
||||
/*
|
||||
* Offsets of . and .. in data space (always block 0)
|
||||
*/
|
||||
#define XFS_DIR2_DATA_DOT_OFFSET \
|
||||
((xfs_dir2_data_aoff_t)sizeof(xfs_dir2_data_hdr_t))
|
||||
#define XFS_DIR2_DATA_DOTDOT_OFFSET \
|
||||
(XFS_DIR2_DATA_DOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(1))
|
||||
#define XFS_DIR2_DATA_FIRST_OFFSET \
|
||||
(XFS_DIR2_DATA_DOTDOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(2))
|
||||
|
||||
/*
|
||||
* Structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Describe a free area in the data block.
|
||||
* The freespace will be formatted as a xfs_dir2_data_unused_t.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_free {
|
||||
__be16 offset; /* start of freespace */
|
||||
__be16 length; /* length of freespace */
|
||||
} xfs_dir2_data_free_t;
|
||||
|
||||
/*
|
||||
* Header for the data blocks.
|
||||
* Always at the beginning of a directory-sized block.
|
||||
* The code knows that XFS_DIR2_DATA_FD_COUNT is 3.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_hdr {
|
||||
__be32 magic; /* XFS_DIR2_DATA_MAGIC */
|
||||
/* or XFS_DIR2_BLOCK_MAGIC */
|
||||
xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
|
||||
} xfs_dir2_data_hdr_t;
|
||||
|
||||
/*
|
||||
* Active entry in a data block. Aligned to 8 bytes.
|
||||
* Tag appears as the last 2 bytes.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_entry {
|
||||
xfs_ino_t inumber; /* inode number */
|
||||
__uint8_t namelen; /* name length */
|
||||
__uint8_t name[1]; /* name bytes, no null */
|
||||
/* variable offset */
|
||||
xfs_dir2_data_off_t tag; /* starting offset of us */
|
||||
} xfs_dir2_data_entry_t;
|
||||
|
||||
/*
|
||||
* Unused entry in a data block. Aligned to 8 bytes.
|
||||
* Tag appears as the last 2 bytes.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_unused {
|
||||
__be16 freetag; /* XFS_DIR2_DATA_FREE_TAG */
|
||||
__be16 length; /* total free length */
|
||||
/* variable offset */
|
||||
__be16 tag; /* starting offset of us */
|
||||
} xfs_dir2_data_unused_t;
|
||||
|
||||
typedef union {
|
||||
xfs_dir2_data_entry_t entry;
|
||||
xfs_dir2_data_unused_t unused;
|
||||
} xfs_dir2_data_union_t;
|
||||
|
||||
/*
|
||||
* Generic data block structure, for xfs_db.
|
||||
*/
|
||||
typedef struct xfs_dir2_data {
|
||||
xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_DATA_MAGIC */
|
||||
xfs_dir2_data_union_t u[1];
|
||||
} xfs_dir2_data_t;
|
||||
|
||||
/*
|
||||
* Macros.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Size of a data entry.
|
||||
*/
|
||||
#define XFS_DIR2_DATA_ENTSIZE(n) xfs_dir2_data_entsize(n)
|
||||
static inline int xfs_dir2_data_entsize(int n)
|
||||
{
|
||||
return (int)roundup(offsetof(xfs_dir2_data_entry_t, name[0]) + (n) + \
|
||||
(uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointer to an entry's tag word.
|
||||
*/
|
||||
#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) xfs_dir2_data_entry_tag_p(dep)
|
||||
static inline __be16 *
|
||||
xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep)
|
||||
{
|
||||
return (__be16 *)((char *)dep +
|
||||
XFS_DIR2_DATA_ENTSIZE(dep->namelen) - sizeof(__be16));
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointer to a freespace's tag word.
|
||||
*/
|
||||
#define XFS_DIR2_DATA_UNUSED_TAG_P(dup) \
|
||||
xfs_dir2_data_unused_tag_p(dup)
|
||||
static inline __be16 *
|
||||
xfs_dir2_data_unused_tag_p(xfs_dir2_data_unused_t *dup)
|
||||
{
|
||||
return (__be16 *)((char *)dup +
|
||||
be16_to_cpu(dup->length) - sizeof(__be16));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function declarations.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
extern void xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_dabuf *bp);
|
||||
#else
|
||||
#define xfs_dir2_data_check(dp,bp)
|
||||
#endif
|
||||
extern xfs_dir2_data_free_t *xfs_dir2_data_freefind(xfs_dir2_data_t *d,
|
||||
xfs_dir2_data_unused_t *dup);
|
||||
extern xfs_dir2_data_free_t *xfs_dir2_data_freeinsert(xfs_dir2_data_t *d,
|
||||
xfs_dir2_data_unused_t *dup, int *loghead);
|
||||
extern void xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d,
|
||||
int *loghead, char *aendp);
|
||||
extern int xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
|
||||
struct xfs_dabuf **bpp);
|
||||
extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp,
|
||||
xfs_dir2_data_entry_t *dep);
|
||||
extern void xfs_dir2_data_log_header(struct xfs_trans *tp,
|
||||
struct xfs_dabuf *bp);
|
||||
extern void xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_dabuf *bp,
|
||||
xfs_dir2_data_unused_t *dup);
|
||||
extern void xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_dabuf *bp,
|
||||
xfs_dir2_data_aoff_t offset,
|
||||
xfs_dir2_data_aoff_t len, int *needlogp,
|
||||
int *needscanp);
|
||||
extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_dabuf *bp,
|
||||
xfs_dir2_data_unused_t *dup,
|
||||
xfs_dir2_data_aoff_t offset,
|
||||
xfs_dir2_data_aoff_t len, int *needlogp,
|
||||
int *needscanp);
|
||||
|
||||
#endif /* __XFS_DIR2_DATA_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DIR2_LEAF_H__
|
||||
#define __XFS_DIR2_LEAF_H__
|
||||
|
||||
struct uio;
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_inode;
|
||||
struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* Offset of the leaf/node space. First block in this space
|
||||
* is the btree root.
|
||||
*/
|
||||
#define XFS_DIR2_LEAF_SPACE 1
|
||||
#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
|
||||
#define XFS_DIR2_LEAF_FIRSTDB(mp) \
|
||||
XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_LEAF_OFFSET)
|
||||
|
||||
/*
|
||||
* Offset in data space of a data entry.
|
||||
*/
|
||||
typedef __uint32_t xfs_dir2_dataptr_t;
|
||||
#define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0xffffffff)
|
||||
#define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0)
|
||||
|
||||
/*
|
||||
* Leaf block header.
|
||||
*/
|
||||
typedef struct xfs_dir2_leaf_hdr {
|
||||
xfs_da_blkinfo_t info; /* header for da routines */
|
||||
__be16 count; /* count of entries */
|
||||
__be16 stale; /* count of stale entries */
|
||||
} xfs_dir2_leaf_hdr_t;
|
||||
|
||||
/*
|
||||
* Leaf block entry.
|
||||
*/
|
||||
typedef struct xfs_dir2_leaf_entry {
|
||||
__be32 hashval; /* hash value of name */
|
||||
__be32 address; /* address of data entry */
|
||||
} xfs_dir2_leaf_entry_t;
|
||||
|
||||
/*
|
||||
* Leaf block tail.
|
||||
*/
|
||||
typedef struct xfs_dir2_leaf_tail {
|
||||
__be32 bestcount;
|
||||
} xfs_dir2_leaf_tail_t;
|
||||
|
||||
/*
|
||||
* Leaf block.
|
||||
* bests and tail are at the end of the block for single-leaf only
|
||||
* (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC).
|
||||
*/
|
||||
typedef struct xfs_dir2_leaf {
|
||||
xfs_dir2_leaf_hdr_t hdr; /* leaf header */
|
||||
xfs_dir2_leaf_entry_t ents[1]; /* entries */
|
||||
/* ... */
|
||||
xfs_dir2_data_off_t bests[1]; /* best free counts */
|
||||
xfs_dir2_leaf_tail_t tail; /* leaf tail */
|
||||
} xfs_dir2_leaf_t;
|
||||
|
||||
/*
|
||||
* DB blocks here are logical directory block numbers, not filesystem blocks.
|
||||
*/
|
||||
|
||||
#define XFS_DIR2_MAX_LEAF_ENTS(mp) xfs_dir2_max_leaf_ents(mp)
|
||||
static inline int xfs_dir2_max_leaf_ents(struct xfs_mount *mp)
|
||||
{
|
||||
return (int)(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_leaf_hdr_t)) /
|
||||
(uint)sizeof(xfs_dir2_leaf_entry_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get address of the bestcount field in the single-leaf block.
|
||||
*/
|
||||
#define XFS_DIR2_LEAF_TAIL_P(mp,lp) xfs_dir2_leaf_tail_p(mp, lp)
|
||||
static inline xfs_dir2_leaf_tail_t *
|
||||
xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp)
|
||||
{
|
||||
return (xfs_dir2_leaf_tail_t *)
|
||||
((char *)(lp) + (mp)->m_dirblksize -
|
||||
(uint)sizeof(xfs_dir2_leaf_tail_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get address of the bests array in the single-leaf block.
|
||||
*/
|
||||
#define XFS_DIR2_LEAF_BESTS_P(ltp) xfs_dir2_leaf_bests_p(ltp)
|
||||
static inline __be16 *
|
||||
xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp)
|
||||
{
|
||||
return (__be16 *)ltp - be32_to_cpu(ltp->bestcount);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert dataptr to byte in file space
|
||||
*/
|
||||
#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) xfs_dir2_dataptr_to_byte(mp, dp)
|
||||
static inline xfs_dir2_off_t
|
||||
xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
|
||||
{
|
||||
return (xfs_dir2_off_t)(dp) << XFS_DIR2_DATA_ALIGN_LOG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert byte in file space to dataptr. It had better be aligned.
|
||||
*/
|
||||
#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) xfs_dir2_byte_to_dataptr(mp,by)
|
||||
static inline xfs_dir2_dataptr_t
|
||||
xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by)
|
||||
{
|
||||
return (xfs_dir2_dataptr_t)((by) >> XFS_DIR2_DATA_ALIGN_LOG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert byte in space to (DB) block
|
||||
*/
|
||||
#define XFS_DIR2_BYTE_TO_DB(mp,by) xfs_dir2_byte_to_db(mp, by)
|
||||
static inline xfs_dir2_db_t
|
||||
xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by)
|
||||
{
|
||||
return (xfs_dir2_db_t)((by) >> \
|
||||
((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert dataptr to a block number
|
||||
*/
|
||||
#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) xfs_dir2_dataptr_to_db(mp, dp)
|
||||
static inline xfs_dir2_db_t
|
||||
xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
|
||||
{
|
||||
return XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert byte in space to offset in a block
|
||||
*/
|
||||
#define XFS_DIR2_BYTE_TO_OFF(mp,by) xfs_dir2_byte_to_off(mp, by)
|
||||
static inline xfs_dir2_data_aoff_t
|
||||
xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by)
|
||||
{
|
||||
return (xfs_dir2_data_aoff_t)((by) & \
|
||||
((1 << ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog)) - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert dataptr to a byte offset in a block
|
||||
*/
|
||||
#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) xfs_dir2_dataptr_to_off(mp, dp)
|
||||
static inline xfs_dir2_data_aoff_t
|
||||
xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
|
||||
{
|
||||
return XFS_DIR2_BYTE_TO_OFF(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert block and offset to byte in space
|
||||
*/
|
||||
#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \
|
||||
xfs_dir2_db_off_to_byte(mp, db, o)
|
||||
static inline xfs_dir2_off_t
|
||||
xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db,
|
||||
xfs_dir2_data_aoff_t o)
|
||||
{
|
||||
return ((xfs_dir2_off_t)(db) << \
|
||||
((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog)) + (o);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert block (DB) to block (dablk)
|
||||
*/
|
||||
#define XFS_DIR2_DB_TO_DA(mp,db) xfs_dir2_db_to_da(mp, db)
|
||||
static inline xfs_dablk_t
|
||||
xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db)
|
||||
{
|
||||
return (xfs_dablk_t)((db) << (mp)->m_sb.sb_dirblklog);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert byte in space to (DA) block
|
||||
*/
|
||||
#define XFS_DIR2_BYTE_TO_DA(mp,by) xfs_dir2_byte_to_da(mp, by)
|
||||
static inline xfs_dablk_t
|
||||
xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by)
|
||||
{
|
||||
return XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, by));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert block and offset to dataptr
|
||||
*/
|
||||
#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \
|
||||
xfs_dir2_db_off_to_dataptr(mp, db, o)
|
||||
static inline xfs_dir2_dataptr_t
|
||||
xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db,
|
||||
xfs_dir2_data_aoff_t o)
|
||||
{
|
||||
return XFS_DIR2_BYTE_TO_DATAPTR(mp, XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert block (dablk) to block (DB)
|
||||
*/
|
||||
#define XFS_DIR2_DA_TO_DB(mp,da) xfs_dir2_da_to_db(mp, da)
|
||||
static inline xfs_dir2_db_t
|
||||
xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da)
|
||||
{
|
||||
return (xfs_dir2_db_t)((da) >> (mp)->m_sb.sb_dirblklog);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert block (dablk) to byte offset in space
|
||||
*/
|
||||
#define XFS_DIR2_DA_TO_BYTE(mp,da) xfs_dir2_da_to_byte(mp, da)
|
||||
static inline xfs_dir2_off_t
|
||||
xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da)
|
||||
{
|
||||
return XFS_DIR2_DB_OFF_TO_BYTE(mp, XFS_DIR2_DA_TO_DB(mp, da), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function declarations.
|
||||
*/
|
||||
extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
|
||||
struct xfs_dabuf *dbp);
|
||||
extern int xfs_dir2_leaf_addname(struct xfs_da_args *args);
|
||||
extern void xfs_dir2_leaf_compact(struct xfs_da_args *args,
|
||||
struct xfs_dabuf *bp);
|
||||
extern void xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp,
|
||||
int *lowstalep, int *highstalep,
|
||||
int *lowlogp, int *highlogp);
|
||||
extern int xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
struct uio *uio, int *eofp,
|
||||
struct xfs_dirent *dbp, xfs_dir2_put_t put);
|
||||
extern int xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno,
|
||||
struct xfs_dabuf **bpp, int magic);
|
||||
extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp,
|
||||
int first, int last);
|
||||
extern void xfs_dir2_leaf_log_header(struct xfs_trans *tp,
|
||||
struct xfs_dabuf *bp);
|
||||
extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_leaf_removename(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_leaf_replace(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_leaf_search_hash(struct xfs_da_args *args,
|
||||
struct xfs_dabuf *lbp);
|
||||
extern int xfs_dir2_leaf_trim_data(struct xfs_da_args *args,
|
||||
struct xfs_dabuf *lbp, xfs_dir2_db_t db);
|
||||
extern int xfs_dir2_node_to_leaf(struct xfs_da_state *state);
|
||||
|
||||
#endif /* __XFS_DIR2_LEAF_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000,2005 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __XFS_DIR2_NODE_H__
|
||||
#define __XFS_DIR2_NODE_H__
|
||||
|
||||
/*
|
||||
* Directory version 2, btree node format structures
|
||||
*/
|
||||
|
||||
struct uio;
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_da_state;
|
||||
struct xfs_da_state_blk;
|
||||
struct xfs_inode;
|
||||
struct xfs_trans;
|
||||
|
||||
/*
|
||||
* Offset of the freespace index.
|
||||
*/
|
||||
#define XFS_DIR2_FREE_SPACE 2
|
||||
#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE)
|
||||
#define XFS_DIR2_FREE_FIRSTDB(mp) \
|
||||
XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_FREE_OFFSET)
|
||||
|
||||
#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F */
|
||||
|
||||
typedef struct xfs_dir2_free_hdr {
|
||||
__be32 magic; /* XFS_DIR2_FREE_MAGIC */
|
||||
__be32 firstdb; /* db of first entry */
|
||||
__be32 nvalid; /* count of valid entries */
|
||||
__be32 nused; /* count of used entries */
|
||||
} xfs_dir2_free_hdr_t;
|
||||
|
||||
typedef struct xfs_dir2_free {
|
||||
xfs_dir2_free_hdr_t hdr; /* block header */
|
||||
__be16 bests[1]; /* best free counts */
|
||||
/* unused entries are -1 */
|
||||
} xfs_dir2_free_t;
|
||||
|
||||
#define XFS_DIR2_MAX_FREE_BESTS(mp) \
|
||||
(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_free_hdr_t)) / \
|
||||
(uint)sizeof(xfs_dir2_data_off_t))
|
||||
|
||||
/*
|
||||
* Convert data space db to the corresponding free db.
|
||||
*/
|
||||
#define XFS_DIR2_DB_TO_FDB(mp,db) xfs_dir2_db_to_fdb(mp, db)
|
||||
static inline xfs_dir2_db_t
|
||||
xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
|
||||
{
|
||||
return (XFS_DIR2_FREE_FIRSTDB(mp) + (db) / XFS_DIR2_MAX_FREE_BESTS(mp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert data space db to the corresponding index in a free db.
|
||||
*/
|
||||
#define XFS_DIR2_DB_TO_FDINDEX(mp,db) xfs_dir2_db_to_fdindex(mp, db)
|
||||
static inline int
|
||||
xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
|
||||
{
|
||||
return ((db) % XFS_DIR2_MAX_FREE_BESTS(mp));
|
||||
}
|
||||
|
||||
extern void xfs_dir2_free_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp,
|
||||
int first, int last);
|
||||
extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args,
|
||||
struct xfs_dabuf *lbp);
|
||||
extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count);
|
||||
extern int xfs_dir2_leafn_lookup_int(struct xfs_dabuf *bp,
|
||||
struct xfs_da_args *args, int *indexp,
|
||||
struct xfs_da_state *state);
|
||||
extern int xfs_dir2_leafn_order(struct xfs_dabuf *leaf1_bp,
|
||||
struct xfs_dabuf *leaf2_bp);
|
||||
extern int xfs_dir2_leafn_split(struct xfs_da_state *state,
|
||||
struct xfs_da_state_blk *oldblk,
|
||||
struct xfs_da_state_blk *newblk);
|
||||
extern int xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action);
|
||||
extern void xfs_dir2_leafn_unbalance(struct xfs_da_state *state,
|
||||
struct xfs_da_state_blk *drop_blk,
|
||||
struct xfs_da_state_blk *save_blk);
|
||||
extern int xfs_dir2_node_addname(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_node_lookup(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_node_removename(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_node_replace(struct xfs_da_args *args);
|
||||
extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo,
|
||||
int *rvalp);
|
||||
|
||||
#endif /* __XFS_DIR2_NODE_H__ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user