Commit 9589ef2a authored by Nathan Scott's avatar Nathan Scott

[XFS] Next step in bhv code cleanup - this is a start on moving quota and dmapi

into behavior layers, purging several points where these sit slap bang in
the middle of XFS code (esp. read_super).  Also removes numerous #ifdef's
and a bunch of unused #define's from all over the place.  More to come.

SGI Modid: 2.5.x-xfs:slinx:141499a
parent d189d057
#
# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
# 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
......@@ -32,10 +32,6 @@
# Makefile for XFS on Linux.
#
# This needs -I. because everything does #include <xfs.h> instead of "xfs.h".
# The code is wrong, local files should be included using "xfs.h", not <xfs.h>
# but I am not going to change every file at the moment.
EXTRA_CFLAGS += -Ifs/xfs -funsigned-char
ifeq ($(CONFIG_XFS_DEBUG),y)
......@@ -54,6 +50,7 @@ xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \
xfs_dquot_item.o \
xfs_trans_dquot.o \
xfs_qm_syscalls.o \
xfs_qmops.o \
xfs_qm.o
xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
......@@ -127,6 +124,7 @@ xfs-y += $(addprefix linux/, \
xfs_iops.o \
xfs_lrw.o \
xfs_super.o \
xfs_vfs.o \
xfs_vnode.o)
# Objects in support/
......
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -30,41 +30,77 @@
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*
*/
#include <xfs.h>
/*
* Source file used to associate/disassociate behaviors with virtualized
* objects. See behavior.h for more information about behaviors, etc.
* objects. See xfs_behavior.h for more information about behaviors, etc.
*
* The implementation is split between functions in this file and macros
* in behavior.h.
* in xfs_behavior.h.
*/
#include <xfs.h>
kmem_zone_t *bhv_global_zone;
/*
* Global initialization function called out of main.
* 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).
*
* Attemps to insert duplicate ops result in an EINVAL return code.
* Otherwise, return 0 to indicate success.
*/
void
bhv_global_init(void)
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);
/*
* Initialize a behavior zone used by subsystems using behaviors
* but without any private data. In the UNIKERNEL case, this zone
* is used only for behaviors that are not yet isolated to a single
* cell. The only such user is in pshm.c in which a dummy vnode is
* obtained in support of vce avoidance logic.
* Find location to insert behavior. Check for duplicates.
*/
bhv_global_zone = kmem_zone_init(sizeof(bhv_desc_t), "bhv_global_zone");
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 postition is guaranteed not to be the first position.
* Should only be called by the bhv_remove() macro.
*
* The act of modifying the chain is done atomically w.r.t. ops-in-progress
* (see comment at top of behavior.h for more info on synchronization).
*/
void
bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
......@@ -86,7 +122,6 @@ bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
ASSERT(curdesc == bdp);
prev->bd_next = bdp->bd_next; /* remove from after prev */
/* atomic wrt oip's */
}
/*
......@@ -110,20 +145,28 @@ bhv_lookup(bhv_head_t *bhp, void *ops)
}
/*
* Look for a specific ops vector on the specified behavior chain.
* Return the associated behavior descriptor. Or NULL, if not found.
*
* The caller has not read locked the behavior chain, so acquire the
* lock before traversing the chain.
* 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_unlocked(bhv_head_t *bhp, void *ops)
bhv_lookup_range(bhv_head_t *bhp, int low, int high)
{
bhv_desc_t *bdp;
bhv_desc_t *curdesc;
for (curdesc = bhp->bh_first;
curdesc != NULL;
curdesc = curdesc->bd_next) {
bdp = bhv_lookup(bhp, ops);
int position = BHV_POSITION(curdesc);
return bdp;
if (position <= high) {
if (position >= low)
return curdesc;
return NULL;
}
}
return NULL;
}
/*
......@@ -134,49 +177,36 @@ bhv_lookup_unlocked(bhv_head_t *bhp, void *ops)
* lock before traversing the chain.
*/
bhv_desc_t *
bhv_base_unlocked(bhv_head_t *bhp)
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)
if (curdesc->bd_next == NULL) {
return curdesc;
}
}
return NULL;
}
#define BHVMAGIC (void *)0xf00d
/* ARGSUSED */
void
bhv_head_init(
bhv_head_t *bhp,
char *name)
{
bhp->bh_first = NULL;
bhp->bh_lockp = BHVMAGIC;
}
/* ARGSUSED */
void
bhv_head_reinit(
bhv_head_t *bhp)
{
ASSERT(bhp->bh_first == NULL);
ASSERT(bhp->bh_lockp == BHVMAGIC);
}
void
bhv_insert_initial(
bhv_head_t *bhp,
bhv_desc_t *bdp)
{
ASSERT(bhp->bh_first == NULL);
ASSERT(bhp->bh_lockp == BHVMAGIC);
(bhp)->bh_first = bdp;
}
......@@ -185,7 +215,4 @@ bhv_head_destroy(
bhv_head_t *bhp)
{
ASSERT(bhp->bh_first == NULL);
ASSERT(bhp->bh_lockp == BHVMAGIC);
bhp->bh_lockp = NULL;
}
/*
* Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -92,7 +92,7 @@
*
*/
typedef void bhv_head_lock_t;
struct bhv_head_lock;
/*
* Behavior head. Head of the chain of behaviors.
......@@ -100,7 +100,7 @@ typedef void bhv_head_lock_t;
*/
typedef struct bhv_head {
struct bhv_desc *bh_first; /* first behavior in chain */
bhv_head_lock_t *bh_lockp; /* pointer to lock info struct */
struct bhv_head_lock *bh_lockp; /* pointer to lock info struct */
} bhv_head_t;
/*
......@@ -128,10 +128,8 @@ typedef struct bhv_identity {
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.
*/
......@@ -154,7 +152,7 @@ typedef bhv_identity_t bhv_position_t;
extern void bhv_head_init(bhv_head_t *, char *);
extern void bhv_head_destroy(bhv_head_t *);
extern void bhv_head_reinit(bhv_head_t *);
extern int bhv_insert(bhv_head_t *, bhv_desc_t *);
extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *);
/*
......@@ -196,7 +194,11 @@ extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *);
*/
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_unlocked(bhv_head_t *bhp, void *ops);
extern bhv_desc_t * bhv_base_unlocked(bhv_head_t *bhp);
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__ */
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -130,7 +130,7 @@ xfs_find_handle(
int lock_mode;
/* need to get access to the xfs_inode to read the generation */
bhv = VNODE_TO_FIRST_BHV(vp);
bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);
ASSERT(bhv);
ip = XFS_BHVTOI(bhv);
ASSERT(ip);
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -44,6 +44,7 @@
#include <linux/major.h>
#include <linux/pagemap.h>
#include <linux/vfs.h>
#include <linux/seq_file.h>
#include <asm/page.h>
#include <asm/div64.h>
......@@ -160,6 +161,15 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh)
#define SYNCHRONIZE() barrier()
#define __return_address __builtin_return_address(0)
/*
* IRIX (BSD) quotactl makes use of separate commands for user/group,
* whereas on Linux the syscall encodes this information into the cmd
* field (see the QCMD macro in quota.h). These macros help keep the
* code portable - they are not visible from the syscall interface.
*/
#define Q_XSETGQLIM XQM_CMD(0x8) /* set groups disk limits */
#define Q_XGETGQUOTA XQM_CMD(0x9) /* get groups disk limits */
/* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */
/* we may well need to fine-tune this if it ever becomes an issue. */
#define DQUOT_MAX_HEURISTIC 1024 /* NR_DQUOTS */
......
This diff is collapsed.
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -34,20 +34,34 @@
#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_DMAPI
# define XFS_DMAPI_STRING "DMAPI, "
# define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops_xfs)
# define vfs_initdmapi() (0) /* temporarily */
# define vfs_exitdmapi() do { } while (0) /* temporarily */
#else
# define XFS_DMAPI_STRING
# define vfs_insertdmapi(vfs) do { } while (0)
# define vfs_initdmapi() (0)
# define vfs_exitdmapi() do { } while (0)
#endif
#ifdef CONFIG_XFS_QUOTA
# define XFS_QUOTA_STRING "quota, "
# define vfs_insertquota(vfs) vfs_insertops(vfsp, &xfs_qmops_xfs)
# define vfs_initquota() (0) /* temporarily */
# define vfs_exitquota() do { } while (0) /* temporarily */
#else
# define XFS_QUOTA_STRING
# define vfs_insertquota(vfs) do { } while (0)
# define vfs_initquota() (0)
# define vfs_exitquota() do { } while (0)
#endif
#ifdef CONFIG_XFS_RT
......@@ -82,6 +96,8 @@ struct xfs_mount;
struct pb_target;
struct block_device;
extern int xfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int);
extern int xfs_showargs(bhv_desc_t *, struct seq_file *);
extern void xfs_initialize_vnode(bhv_desc_t *, vnode_t *, bhv_desc_t *, int);
extern int xfs_blkdev_get(struct xfs_mount *, const char *,
......@@ -95,4 +111,8 @@ extern void xfs_free_buftarg(struct pb_target *);
extern void xfs_setsize_buftarg(struct pb_target *, unsigned int, unsigned int);
extern unsigned int xfs_getsize_buftarg(struct pb_target *);
extern void bhv_insert_all_vfsops(struct vfs *);
extern void bhv_remove_all_vfsops(struct vfs *, int);
extern void bhv_remove_vfsops(struct vfs *, int);
#endif /* __XFS_SUPER_H__ */
/*
* 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>
int
vfs_mount(bhv_desc_t *bdp, struct xfs_mount_args *args, struct cred *cr)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_mount)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_mount)(next, args, cr));
}
int
vfs_parseargs(bhv_desc_t *bdp, char *s, struct xfs_mount_args *args, int f)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_parseargs)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_parseargs)(next, s, args, f));
}
int
vfs_showargs(bhv_desc_t *bdp, struct seq_file *m)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_showargs)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_showargs)(next, m));
}
int
vfs_unmount(bhv_desc_t *bdp, int fl, struct cred *cr)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_unmount)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_unmount)(next, fl, cr));
}
int
vfs_root(bhv_desc_t *bdp, struct vnode **vpp)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_root)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_root)(next, vpp));
}
int
vfs_statvfs(bhv_desc_t *bdp, struct statfs *sp, struct vnode *vp)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_statvfs)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_statvfs)(next, sp, vp));
}
int
vfs_sync(bhv_desc_t *bdp, int fl, struct cred *cr)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_sync)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_sync)(next, fl, cr));
}
int
vfs_vget(bhv_desc_t *bdp, struct vnode **vpp, struct fid *fidp)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_vget)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_vget)(next, vpp, fidp));
}
int
vfs_dmapiops(bhv_desc_t *bdp, caddr_t addr)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_dmapiops)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_dmapiops)(next, addr));
}
int
vfs_quotactl(bhv_desc_t *bdp, int cmd, int id, caddr_t addr)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_quotactl)
next = BHV_NEXT(next);
return ((*bhvtovfsops(next)->vfs_quotactl)(next, cmd, id, addr));
}
void
vfs_init_vnode(bhv_desc_t *bdp, struct vnode *vp, bhv_desc_t *bp, int unlock)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_init_vnode)
next = BHV_NEXT(next);
((*bhvtovfsops(next)->vfs_init_vnode)(next, vp, bp, unlock));
}
void
vfs_force_shutdown(bhv_desc_t *bdp, int fl, char *file, int line)
{
bhv_desc_t *next = bdp;
ASSERT(next);
while (! (bhvtovfsops(next))->vfs_force_shutdown)
next = BHV_NEXT(next);
((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line));
}
vfs_t *
vfs_allocate(void)
{
vfs_t *vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP);
bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
return vfsp;
}
void
vfs_deallocate(vfs_t *vfsp)
{
bhv_head_destroy(VFS_BHVHEAD(vfsp));
kmem_free(vfsp, sizeof(vfs_t));
}
void
vfs_insertops(vfs_t *vfsp, vfsops_t *vfsops)
{
bhv_desc_t *bdp = kmem_alloc(sizeof(bhv_desc_t), KM_SLEEP);
bhv_desc_init(bdp, NULL, vfsp, vfsops);
bhv_insert(&vfsp->vfs_bh, bdp);
}
void
vfs_insertbhv(vfs_t *vfsp, bhv_desc_t *bdp, vfsops_t *vfsops, void *mount)
{
bhv_desc_init(bdp, mount, vfsp, vfsops);
bhv_insert_initial(&vfsp->vfs_bh, bdp);
}
This diff is collapsed.
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -85,10 +85,16 @@ typedef struct vnode {
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)
/*
* Macros for dealing with the behavior descriptor inside of the vnode.
......@@ -96,7 +102,6 @@ typedef enum {
#define BHV_TO_VNODE(bdp) ((vnode_t *)BHV_VOBJ(bdp))
#define BHV_TO_VNODE_NULL(bdp) ((vnode_t *)BHV_VOBJNULL(bdp))
#define VNODE_TO_FIRST_BHV(vp) (BHV_HEAD_FIRST(&(vp)->v_bh))
#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)
......@@ -127,16 +132,6 @@ extern ushort vttoif_tab[];
#define VWAIT 0x4 /* waiting for VINACT/VRECLM to end */
#define VMODIFIED 0x8 /* XFS inode state possibly differs */
/* to the Linux inode state. */
#define VROOT 0x100000 /* root of its file system */
#define VNOSWAP 0x200000 /* cannot be used as virt swap device */
#define VISSWAP 0x400000 /* vnode is part of virt swap device */
#define VREPLICABLE 0x800000 /* Vnode can have replicated pages */
#define VNONREPLICABLE 0x1000000 /* Vnode has writers. Don't replicate */
#define VDOCMP 0x2000000 /* Vnode has special VOP_CMP impl. */
#define VSHARE 0x4000000 /* vnode part of global cache */
#define VFRLOCKS 0x8000000 /* vnode has FR locks applied */
#define VENF_LOCKING 0x10000000 /* enf. mode FR locking in effect */
#define VOPLOCK 0x20000000 /* oplock set on the vnode */
typedef enum vrwlock { VRWLOCK_NONE, VRWLOCK_READ,
VRWLOCK_WRITE, VRWLOCK_WRITE_DIRECT,
......@@ -268,162 +263,91 @@ typedef struct vnodeops {
#define _VOP_(op, vp) (*((vnodeops_t *)(vp)->v_fops)->op)
#define VOP_READ(vp,file,iov,segs,offset,cr,rv) \
{ \
rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,cr); \
}
rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,cr)
#define VOP_WRITE(vp,file,iov,segs,offset,cr,rv) \
{ \
rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr);\
}
#define VOP_SENDFILE(vp,f,of,cnt,act,targ,cr,rv) \
{ \
rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,of,cnt,act,targ,cr);\
}
rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr)
#define VOP_SENDFILE(vp,f,off,cnt,act,targ,cr,rv) \
rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,cnt,act,targ,cr)
#define VOP_BMAP(vp,of,sz,rw,b,n,rv) \
{ \
rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n); \
}
rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n)
#define VOP_OPEN(vp, cr, rv) \
{ \
rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr); \
}
rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr)
#define VOP_GETATTR(vp, vap, f, cr, rv) \
{ \
rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr); \
}
rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr)
#define VOP_SETATTR(vp, vap, f, cr, rv) \
{ \
rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr); \
}
rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr)
#define VOP_ACCESS(vp, mode, cr, rv) \
{ \
rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr); \
}
rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr)
#define VOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv) \
{ \
rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr); \
}
rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr)
#define VOP_CREATE(dvp,d,vap,vpp,cr,rv) \
{ \
rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr); \
}
rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr)
#define VOP_REMOVE(dvp,d,cr,rv) \
{ \
rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr); \
}
rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr)
#define VOP_LINK(tdvp,fvp,d,cr,rv) \
{ \
rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr); \
}
rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr)
#define VOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv) \
{ \
rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr); \
}
rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr)
#define VOP_MKDIR(dp,d,vap,vpp,cr,rv) \
{ \
rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr); \
}
rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr)
#define VOP_RMDIR(dp,d,cr,rv) \
{ \
rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr); \
}
rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr)
#define VOP_READDIR(vp,uiop,cr,eofp,rv) \
{ \
rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp); \
}
rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp)
#define VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv) \
{ \
rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr); \
}
rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr)
#define VOP_READLINK(vp,uiop,cr,rv) \
{ \
rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr); \
}
rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr)
#define VOP_FSYNC(vp,f,cr,b,e,rv) \
{ \
rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e); \
}
rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e)
#define VOP_INACTIVE(vp, cr, rv) \
{ \
rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr); \
}
rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr)
#define VOP_RELEASE(vp, rv) \
{ \
rv = _VOP_(vop_release, vp)((vp)->v_fbhv); \
}
rv = _VOP_(vop_release, vp)((vp)->v_fbhv)
#define VOP_FID2(vp, fidp, rv) \
{ \
rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp); \
}
rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp)
#define VOP_RWLOCK(vp,i) \
{ \
(void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i); \
}
(void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
#define VOP_RWLOCK_TRY(vp,i) \
_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
#define VOP_RWUNLOCK(vp,i) \
{ \
(void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i); \
}
(void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i)
#define VOP_FRLOCK(vp,c,fl,flags,offset,fr,rv) \
rv = _VOP_(vop_frlock, vp)((vp)->v_fbhv,c,fl,flags,offset,fr)
#define VOP_RECLAIM(vp, rv) \
{ \
rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv); \
}
rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv)
#define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv) \
{ \
rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred); \
}
rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred)
#define VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv) \
{ \
rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred); \
}
rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred)
#define VOP_ATTR_REMOVE(vp, name, flags, cred, rv) \
{ \
rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred); \
}
rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred)
#define VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv) \
{ \
rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred);\
}
rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred)
#define VOP_LINK_REMOVED(vp, dvp, linkzero) \
{ \
(void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero); \
}
(void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero)
#define VOP_VNODE_CHANGE(vp, cmd, val) \
{ \
(void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,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 VOP_TOSS_PAGES(vp, first, last, fiopt) \
{ \
_VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt); \
}
_VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt)
/*
* 'last' parameter is unused and left in for IRIX compatibility
*/
#define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt) \
{ \
_VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,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 VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv) \
{ \
rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt);\
}
rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt)
#define VOP_IOCTL(vp, inode, filp, cmd, arg, rv) \
{ \
rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg); \
}
rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg)
#define VOP_IFLUSH(vp, flags, rv) \
{ \
rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags); \
}
rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags)
/*
* Flags for VOP_IFLUSH call
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -144,16 +144,10 @@
(1 << DM_EVENT_DESTROY) )
extern int
xfs_dm_mount(
vfs_t *vfsp,
char *dir_name,
char *fsname);
extern int
xfs_dm_get_fsys_vector(
bhv_desc_t *bdp,
dm_fcntl_vector_t *vecrq);
caddr_t vecrq);
extern int
xfs_dm_send_data_event(
......
/*
* 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>
#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */
#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */
STATIC int
xfs_dm_parseargs(
struct bhv_desc *bhv,
char *options,
struct xfs_mount_args *args,
int update)
{
size_t length;
char *local_options = options;
char *this_char;
int error;
while ((this_char = strsep(&local_options, ",")) != NULL) {
length = strlen(this_char);
if (local_options)
length++;
if (!strcmp(this_char, MNTOPT_DMAPI)) {
args->flags |= XFSMNT_DMAPI;
} else if (!strcmp(this_char, MNTOPT_XDSM)) {
args->flags |= XFSMNT_DMAPI;
} else {
if (local_options)
*(local_options-1) = ',';
continue;
}
while (length--)
*this_char++ = ',';
}
PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
if (!error && (args->flags & XFSMNT_DMAPI) && (*args->mtpt == '\0'))
error = EINVAL;
if (!error && !update && !(args->flags & XFSMNT_DMAPI))
bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_DM);
return error;
}
STATIC int
xfs_dm_showargs(
struct bhv_desc *bhv,
struct seq_file *m)
{
struct vfs *vfsp = bhvtovfs(bhv);
int error;
if (vfsp->vfs_flag & VFS_DMI)
seq_puts(m, "," MNTOPT_DMAPI);
PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
return error;
}
STATIC int
xfs_dm_mount(
struct bhv_desc *bhv,
struct xfs_mount_args *args,
struct cred *cr)
{
struct bhv_desc *rootbdp;
struct vnode *rootvp;
struct vfs *vfsp;
int error = 0;
PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
if (error)
return error;
if (args->flags & XFSMNT_DMAPI) {
vfsp = bhvtovfs(bhv);
VFS_ROOT(vfsp, &rootvp, error);
if (!error) {
vfsp->vfs_flag |= VFS_DMI;
rootbdp = vn_bhv_lookup_unlocked(
VN_BHV_HEAD(rootvp), &xfs_vnodeops);
VN_RELE(rootvp);
error = dm_send_mount_event(vfsp, DM_RIGHT_NULL, NULL,
DM_RIGHT_NULL, rootbdp, DM_RIGHT_NULL,
args->mtpt, args->fsname);
}
}
return error;
}
vfsops_t xfs_dmops_xfs = {
BHV_IDENTITY_INIT(VFS_BHV_DM, VFS_POSITION_DM),
.vfs_mount = xfs_dm_mount,
.vfs_parseargs = xfs_dm_parseargs,
.vfs_showargs = xfs_dm_showargs,
.vfs_dmapiops = xfs_dm_get_fsys_vector,
};
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -1190,25 +1190,6 @@ xfs_ialloc(
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
ip->i_d.di_anextents = 0;
#if DEBUG
{
uint badflags = VNOSWAP |
VISSWAP |
VREPLICABLE |
/* VNONREPLICABLE | XXX uncomment this */
VDOCMP |
VFRLOCKS;
/*
* For shared mounts, VNOSWAP is set in xfs_iget
*/
if (tp->t_mountp->m_cxfstype != XFS_CXFS_NOT)
badflags &= ~VNOSWAP;
ASSERT(!(vp->v_flag & badflags));
}
#endif /* DEBUG */
/*
* Log the new values stuffed into the inode.
*/
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -33,15 +33,25 @@
#include <xfs.h>
static xfs_fsize_t
STATIC xfs_fsize_t
xfs_size_fn(
xfs_inode_t *ip)
{
return (ip->i_d.di_size);
}
STATIC int
xfs_ioinit(
struct vfs *vfsp,
struct xfs_mount_args *mntargs,
int flags)
{
return xfs_mountfs(vfsp, XFS_VFSTOM(vfsp),
vfsp->vfs_super->s_bdev->bd_dev, flags);
}
xfs_ioops_t xfs_iocore_xfs = {
.xfs_ioinit = (xfs_ioinit_t) fs_noerr,
.xfs_ioinit = (xfs_ioinit_t) xfs_ioinit,
.xfs_bmapi_func = (xfs_bmapi_t) xfs_bmapi,
.xfs_bmap_eof_func = (xfs_bmap_eof_t) xfs_bmap_eof,
.xfs_iomap_write_direct =
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -358,6 +358,14 @@ xfs_bhvtom(bhv_desc_t *bdp)
}
#endif
#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_VFSTOM)
xfs_mount_t *
xfs_vfstom(vfs_t *vfs)
{
return XFS_VFSTOM(vfs);
}
#endif
#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BM_MAXLEVELS)
int
xfs_bm_maxlevels(xfs_mount_t *mp, int w)
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -40,8 +40,6 @@ mutex_t xfs_uuidtabmon; /* monitor for uuidtab */
STATIC int xfs_uuidtab_size;
STATIC uuid_t *xfs_uuidtab;
STATIC void xfs_uuid_unmount(xfs_mount_t *);
void xfs_xlatesb(void *, xfs_sb_t *, int, xfs_arch_t, __int64_t);
static struct {
......@@ -120,10 +118,9 @@ xfs_mount_init(void)
spinlock_init(&mp->m_freeze_lock, "xfs_freeze");
init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0);
atomic_set(&mp->m_active_trans, 0);
mp->m_cxfstype = XFS_CXFS_NOT;
return mp;
} /* xfs_mount_init */
}
/*
* Free up the resources associated with a mount structure. Assume that
......@@ -146,19 +143,12 @@ xfs_mount_free(
for (agno = 0; agno < mp->m_maxagi; agno++)
if (mp->m_perag[agno].pagb_list)
kmem_free(mp->m_perag[agno].pagb_list,
sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS);
sizeof(xfs_perag_busy_t) *
XFS_PAGB_NUM_SLOTS);
kmem_free(mp->m_perag,
sizeof(xfs_perag_t) * mp->m_sb.sb_agcount);
}
#if 0
/*
* XXXdpd - Doesn't work now for shutdown case.
* Should at least free the memory.
*/
ASSERT(mp->m_ail.ail_back == (xfs_log_item_t*)&(mp->m_ail));
ASSERT(mp->m_ail.ail_forw == (xfs_log_item_t*)&(mp->m_ail));
#endif
AIL_LOCK_DESTROY(&mp->m_ail_lock);
spinlock_destroy(&mp->m_sb_lock);
mutex_destroy(&mp->m_ilock);
......@@ -172,8 +162,12 @@ xfs_mount_free(
}
if (remove_bhv) {
VFS_REMOVEBHV(XFS_MTOVFS(mp), &mp->m_bhv);
struct vfs *vfsp = XFS_MTOVFS(mp);
bhv_remove_all_vfsops(vfsp, 0);
VFS_REMOVEBHV(vfsp, &mp->m_bhv);
}
spinlock_destroy(&mp->m_freeze_lock);
sv_destroy(&mp->m_wait_unfreeze);
kmem_free(mp, sizeof(xfs_mount_t));
......@@ -605,14 +599,11 @@ xfs_mountfs(
{
xfs_buf_t *bp;
xfs_sb_t *sbp = &(mp->m_sb);
int error = 0;
xfs_inode_t *rip;
vnode_t *rvp = 0;
int readio_log;
int writeio_log;
int readio_log, writeio_log;
vmap_t vmap;
xfs_daddr_t d;
extern xfs_ioops_t xfs_iocore_xfs; /* from xfs_iocore.c */
__uint64_t ret64;
uint quotaflags, quotaondisk;
uint uquotaondisk = 0, gquotaondisk = 0;
......@@ -620,6 +611,7 @@ xfs_mountfs(
__int64_t update_flags;
int agno, noio;
int uuid_mounted = 0;
int error = 0;
noio = dev == 0 && mp->m_sb_bp != NULL;
if (mp->m_sb_bp == NULL) {
......@@ -644,7 +636,8 @@ xfs_mountfs(
if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
(BBTOB(mp->m_swidth) & mp->m_blockmask)) {
if (mp->m_flags & XFS_MOUNT_RETERR) {
cmn_err(CE_WARN, "XFS: alignment check 1 failed");
cmn_err(CE_WARN,
"XFS: alignment check 1 failed");
error = XFS_ERROR(EINVAL);
goto error1;
}
......@@ -664,7 +657,8 @@ xfs_mountfs(
mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
} else {
if (mp->m_flags & XFS_MOUNT_RETERR) {
cmn_err(CE_WARN, "XFS: alignment check 3 failed");
cmn_err(CE_WARN,
"XFS: alignment check 3 failed");
error = XFS_ERROR(EINVAL);
goto error1;
}
......@@ -718,7 +712,8 @@ xfs_mountfs(
* since a single partition filesystem is identical to a single
* partition volume/filesystem.
*/
if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && (mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
if ((mfsi_flags & XFS_MFSI_SECOND) == 0 &&
(mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
if (xfs_uuid_mount(mp)) {
error = XFS_ERROR(EINVAL);
goto error1;
......@@ -859,9 +854,6 @@ xfs_mountfs(
return(0);
}
/* Initialize the I/O function vector with XFS functions */
mp->m_io_ops = xfs_iocore_xfs;
/*
* Copies the low order bits of the timestamp and the randomly
* set "sequence" number out of a UUID.
......@@ -1118,6 +1110,7 @@ xfs_mountfs(
int
xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
{
struct vfs *vfsp = XFS_MTOVFS(mp);
int ndquots;
#if defined(DEBUG) || defined(INDUCE_IO_ERROR)
int64_t fsid;
......@@ -1178,10 +1171,10 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
/*
* clear all error tags on this filesystem
*/
memcpy(&fsid, &(XFS_MTOVFS(mp)->vfs_fsid), sizeof(int64_t));
(void) xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);
memcpy(&fsid, &vfsp->vfs_fsid, sizeof(int64_t));
xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);
#endif
XFS_IODONE(vfsp);
xfs_mount_free(mp, 1);
return 0;
}
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -95,7 +95,7 @@ struct flid;
struct buf;
typedef int (*xfs_ioinit_t)(struct vfs *,
struct xfs_mount_args *, int *);
struct xfs_mount_args *, int);
typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *,
xfs_fileoff_t, xfs_filblks_t, int,
xfs_fsblock_t *, xfs_extlen_t,
......@@ -187,11 +187,6 @@ typedef struct xfs_ioops {
(*(mp)->m_io_ops.xfs_iodone)(vfsp)
/*
* Prototypes and functions for the XFS realtime subsystem.
*/
typedef struct xfs_mount {
bhv_desc_t m_bhv; /* vfs xfs behavior */
xfs_tid_t m_tid; /* next unused tid for fs */
......@@ -324,8 +319,7 @@ typedef struct xfs_mount {
#define XFS_MOUNT_NOALIGN 0x00000080 /* turn off stripe alignment
allocations */
/* 0x00000100 -- currently unused */
#define XFS_MOUNT_REGISTERED 0x00000200 /* registered with cxfs master
cell logic */
/* 0x00000200 -- currently unused */
#define XFS_MOUNT_NORECOVERY 0x00000400 /* no recovery - dirty fs */
#define XFS_MOUNT_SHARED 0x00000800 /* shared mount */
#define XFS_MOUNT_DFLT_IOSIZE 0x00001000 /* set default i/o size */
......@@ -336,14 +330,6 @@ typedef struct xfs_mount {
* 32 bits in size */
#define XFS_MOUNT_NOLOGFLUSH 0x00010000
/*
* Flags for m_cxfstype
*/
#define XFS_CXFS_NOT 0x00000001 /* local mount */
#define XFS_CXFS_SERVER 0x00000002 /* we're the CXFS server */
#define XFS_CXFS_CLIENT 0x00000004 /* We're a CXFS client */
#define XFS_CXFS_REC_ENABLED 0x00000008 /* recovery is enabled */
#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
/*
......@@ -370,15 +356,17 @@ typedef struct xfs_mount {
#define XFS_WSYNC_READIO_LOG 15 /* 32K */
#define XFS_WSYNC_WRITEIO_LOG 14 /* 16K */
#define xfs_force_shutdown(m,f) VFS_FORCE_SHUTDOWN(XFS_MTOVFS(m),f)
#define xfs_force_shutdown(m,f) \
VFS_FORCE_SHUTDOWN((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
/*
* Flags sent to xfs_force_shutdown.
*/
#define XFS_METADATA_IO_ERROR 0x1
#define XFS_LOG_IO_ERROR 0x2
#define XFS_FORCE_UMOUNT 0x4
#define XFS_CORRUPT_INCORE 0x8 /* corrupt in-memory data structures */
#define XFS_SHUTDOWN_REMOTE_REQ 0x10 /* shutdown came from remote cell */
#define XFS_CORRUPT_INCORE 0x8 /* Corrupt in-memory data structures */
#define XFS_SHUTDOWN_REMOTE_REQ 0x10 /* Shutdown came from remote cell */
/*
* xflags for xfs_syncsub
......@@ -388,9 +376,7 @@ typedef struct xfs_mount {
/*
* Flags for xfs_mountfs
*/
#define XFS_MFSI_SECOND 0x01 /* Is a cxfs secondary mount -- skip */
/* stuff which should only be done */
/* once. */
#define XFS_MFSI_SECOND 0x01 /* Secondary mount -- skip stuff */
#define XFS_MFSI_CLIENT 0x02 /* Is a client -- skip lots of stuff */
#define XFS_MFSI_NOUNLINK 0x08 /* Skip unlinked inode processing in */
/* log recovery */
......@@ -410,6 +396,13 @@ xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp);
#else
#define XFS_BHVTOM(bdp) ((xfs_mount_t *)BHV_PDATA(bdp))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_VFSTOM)
xfs_mount_t *xfs_vfstom(vfs_t *vfs);
#define XFS_VFSTOM(vfs) xfs_vfstom(vfs)
#else
#define XFS_VFSTOM(vfs) \
(XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops)))
#endif
/*
......@@ -447,7 +440,7 @@ static inline xfs_agblock_t XFS_DADDR_TO_AGBNO(xfs_mount_t *mp, xfs_daddr_t d)
*/
typedef struct xfs_mod_sb {
xfs_sb_field_t msb_field; /* Field to modify, see below */
int msb_delta; /* change to make to the specified field */
int msb_delta; /* Change to make to specified field */
} xfs_mod_sb_t;
#define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock), PINOD)
......@@ -455,24 +448,26 @@ typedef struct xfs_mod_sb {
#define XFS_SB_LOCK(mp) mutex_spinlock(&(mp)->m_sb_lock)
#define XFS_SB_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_sb_lock,(s))
void xfs_mod_sb(xfs_trans_t *, __int64_t);
xfs_mount_t *xfs_mount_init(void);
void xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
int xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int);
int xfs_unmountfs(xfs_mount_t *, struct cred *);
void xfs_unmountfs_close(xfs_mount_t *, struct cred *);
int xfs_unmountfs_writesb(xfs_mount_t *);
int xfs_unmount_flush(xfs_mount_t *, int);
int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int);
int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, uint, int);
int xfs_readsb(xfs_mount_t *mp);
struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
void xfs_freesb(xfs_mount_t *);
void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
int xfs_syncsub(xfs_mount_t *, int, int, int *);
void xfs_initialize_perag(xfs_mount_t *, int);
void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t);
extern xfs_mount_t *xfs_mount_init(void);
extern void xfs_mod_sb(xfs_trans_t *, __int64_t);
extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int);
extern int xfs_unmountfs(xfs_mount_t *, struct cred *);
extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *);
extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_unmount_flush(xfs_mount_t *, int);
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int);
extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
uint, int);
extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
extern int xfs_readsb(xfs_mount_t *mp);
extern void xfs_freesb(xfs_mount_t *);
extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
extern int xfs_syncsub(xfs_mount_t *, int, int, int *);
extern void xfs_initialize_perag(xfs_mount_t *, int);
extern void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t,
__int64_t);
/*
* Flags for freeze operations.
......@@ -480,11 +475,20 @@ void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t);
#define XFS_FREEZE_WRITE 1
#define XFS_FREEZE_TRANS 2
void xfs_start_freeze(xfs_mount_t *, int);
void xfs_finish_freeze(xfs_mount_t *);
void xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int);
extern void xfs_start_freeze(xfs_mount_t *, int);
extern void xfs_finish_freeze(xfs_mount_t *);
extern void xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int);
extern struct vfsops xfs_vfsops;
extern struct vnodeops xfs_vnodeops;
extern struct xfs_ioops xfs_iocore_xfs;
extern struct vfsops xfs_qmops_xfs;
extern struct vfsops xfs_dmops_xfs;
extern int xfs_init(void);
extern void xfs_cleanup(void);
#endif /* __KERNEL__ */
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -199,10 +199,7 @@ extern int xfs_qm_mplist_nowait(xfs_mount_t *);
extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
/* system call interface */
extern int linvfs_getxstate(struct super_block *, struct fs_quota_stat *);
extern int linvfs_setxstate(struct super_block *, unsigned int, int);
extern int linvfs_getxquota(struct super_block *, int, qid_t, struct fs_disk_quota *);
extern int linvfs_setxquota(struct super_block *, int, qid_t, struct fs_disk_quota *);
extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t);
#ifdef DEBUG
extern int xfs_qm_internalqcheck(xfs_mount_t *);
......
This diff is collapsed.
/*
* 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>
#define MNTOPT_QUOTA "quota" /* disk quotas (user) */
#define MNTOPT_NOQUOTA "noquota" /* no quotas */
#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */
#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */
#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */
#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */
#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
STATIC int
xfs_qm_parseargs(
struct bhv_desc *bhv,
char *options,
struct xfs_mount_args *args,
int update)
{
size_t length;
char *local_options = options;
char *this_char;
int error;
int referenced = update;
while ((this_char = strsep(&local_options, ",")) != NULL) {
length = strlen(this_char);
if (local_options)
length++;
if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
referenced = update;
} else if (!strcmp(this_char, MNTOPT_QUOTA) ||
!strcmp(this_char, MNTOPT_UQUOTA) ||
!strcmp(this_char, MNTOPT_USRQUOTA)) {
args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
referenced = 1;
} else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
!strcmp(this_char, MNTOPT_UQUOTANOENF)) {
args->flags |= XFSMNT_UQUOTA;
args->flags &= ~XFSMNT_UQUOTAENF;
referenced = 1;
} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
!strcmp(this_char, MNTOPT_GRPQUOTA)) {
args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
referenced = 1;
} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
args->flags |= XFSMNT_GQUOTA;
args->flags &= ~XFSMNT_GQUOTAENF;
referenced = 1;
} else {
if (local_options)
*(local_options-1) = ',';
continue;
}
while (length--)
*this_char++ = ',';
}
PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
if (!error && !referenced)
bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
return error;
}
STATIC int
xfs_qm_showargs(
struct bhv_desc *bhv,
struct seq_file *m)
{
struct vfs *vfsp = bhvtovfs(bhv);
struct xfs_mount *mp = XFS_VFSTOM(vfsp);
int error;
if (mp->m_qflags & XFS_UQUOTA_ACCT) {
(mp->m_qflags & XFS_UQUOTA_ENFD) ?
seq_puts(m, "," MNTOPT_UQUOTA) :
seq_puts(m, "," MNTOPT_UQUOTANOENF);
}
if (mp->m_qflags & XFS_GQUOTA_ACCT) {
(mp->m_qflags & XFS_GQUOTA_ENFD) ?
seq_puts(m, "," MNTOPT_GQUOTA) :
seq_puts(m, "," MNTOPT_GQUOTANOENF);
}
if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)))
seq_puts(m, "," MNTOPT_NOQUOTA);
PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
return error;
}
STATIC int
xfs_qm_mount(
struct bhv_desc *bhv,
struct xfs_mount_args *args,
struct cred *cr)
{
struct vfs *vfsp = bhvtovfs(bhv);
struct xfs_mount *mp = XFS_VFSTOM(vfsp);
int error;
if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
xfs_qm_mount_quotainit(mp, args->flags);
PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
return error;
}
STATIC int
xfs_qm_syncall(
struct bhv_desc *bhv,
int flags,
cred_t *credp)
{
struct vfs *vfsp = bhvtovfs(bhv);
struct xfs_mount *mp = XFS_VFSTOM(vfsp);
int error;
/*
* Get the Quota Manager to flush the dquots.
*/
if (XFS_IS_QUOTA_ON(mp)) {
if ((error = xfs_qm_sync(mp, flags))) {
/*
* If we got an IO error, we will be shutting down.
* So, there's nothing more for us to do here.
*/
ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
if (XFS_FORCED_SHUTDOWN(mp)) {
return XFS_ERROR(error);
}
}
}
PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error);
return error;
}
vfsops_t xfs_qmops_xfs = {
BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
.vfs_parseargs = xfs_qm_parseargs,
.vfs_showargs = xfs_qm_showargs,
.vfs_mount = xfs_qm_mount,
.vfs_sync = xfs_qm_syncall,
.vfs_quotactl = xfs_qm_quotactl,
};
/*
* XFS filesystem operations.
*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* 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
......@@ -248,9 +248,6 @@ xfs_start_flags(
if (ap->flags & XFSMNT_NOATIME)
mp->m_flags |= XFS_MOUNT_NOATIME;
if (ap->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
xfs_qm_mount_quotainit(mp, ap->flags);
if (ap->flags & XFSMNT_RETERR)
mp->m_flags |= XFS_MOUNT_RETERR;
......@@ -387,11 +384,12 @@ xfs_finish_flags(
*/
STATIC int
xfs_mount(
vfs_t *vfsp,
struct bhv_desc *bhvp,
struct xfs_mount_args *args,
cred_t *credp)
{
xfs_mount_t *mp;
struct vfs *vfsp = bhvtovfs(bhvp);
struct xfs_mount *mp = XFS_BHVTOM(bhvp);
struct block_device *ddev, *logdev, *rtdev;
int ronly = (vfsp->vfs_flag & VFS_RDONLY);
int flags = 0, error;
......@@ -399,24 +397,19 @@ xfs_mount(
ddev = vfsp->vfs_super->s_bdev;
logdev = rtdev = NULL;
/*
* Allocate VFS private data (xfs mount structure).
*/
mp = xfs_mount_init();
/*
* Open real time and log devices - order is important.
*/
if (args->logname[0]) {
error = xfs_blkdev_get(mp, args->logname, &logdev);
if (error)
goto free_mp;
return error;
}
if (args->rtname[0]) {
error = xfs_blkdev_get(mp, args->rtname, &rtdev);
if (error) {
xfs_blkdev_put(logdev);
goto free_mp;
return error;
}
if (rtdev == ddev || rtdev == logdev) {
......@@ -424,12 +417,11 @@ xfs_mount(
"XFS: Cannot mount filesystem with identical rtdev and ddev/logdev.");
xfs_blkdev_put(logdev);
xfs_blkdev_put(rtdev);
error = EINVAL;
goto free_mp;
return EINVAL;
}
}
vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
mp->m_io_ops = xfs_iocore_xfs;
mp->m_ddev_targp = xfs_alloc_buftarg(ddev);
if (rtdev)
......@@ -465,9 +457,7 @@ xfs_mount(
xfs_setsize_buftarg(mp->m_rtdev_targp, mp->m_sb.sb_blocksize,
mp->m_sb.sb_blocksize);
error = xfs_mountfs(vfsp, mp, ddev->bd_dev, flags);
if (error)
goto error;
if (!(error = XFS_IOINIT(vfsp, args, flags)))
return 0;
error:
......@@ -479,9 +469,6 @@ xfs_mount(
xfs_binval(mp->m_rtdev_targp);
}
xfs_unmountfs_close(mp, NULL);
free_mp:
xfs_mount_free(mp, 1);
return error;
}
......@@ -523,8 +510,9 @@ xfs_ibusy(
continue;
}
#ifdef DEBUG
printk("busy vp=0x%p ip=0x%p inum %Ld count=%d\n",
vp, ip, ip->i_ino, vn_count(vp));
cmn_err(CE_WARN, "%s: busy vp=0x%p ip=0x%p "
"inum %Ld count=%d",
__FUNCTION__, vp, ip, ip->i_ino, vn_count(vp));
#endif
busy++;
}
......@@ -577,7 +565,8 @@ xfs_unmount(
*/
if (xfs_ibusy(mp)) {
error = XFS_ERROR(EBUSY);
printk("xfs_unmount: xfs_ibusy says error/%d\n", error);
cmn_err(CE_ALERT, "%s: xfs_ibusy failed -- error code %d",
__FUNCTION__, error);
goto out;
}
......@@ -641,7 +630,7 @@ xfs_unmount_flush(
{
xfs_inode_t *rip = mp->m_rootip;
xfs_inode_t *rbmip;
xfs_inode_t *rsumip=NULL;
xfs_inode_t *rsumip = NULL;
vnode_t *rvp = XFS_ITOV(rip);
int error;
......@@ -675,18 +664,17 @@ xfs_unmount_flush(
}
/*
* synchronously flush root inode to disk
* Synchronously flush root inode to disk
*/
error = xfs_iflush(rip, XFS_IFLUSH_SYNC);
if (error == EFSCORRUPTED)
goto fscorrupt_out2;
if (vn_count(rvp) != 1 && !relocation) {
xfs_iunlock(rip, XFS_ILOCK_EXCL);
error = XFS_ERROR(EBUSY);
return (error);
return XFS_ERROR(EBUSY);
}
/*
* Release dquot that rootinode, rbmino and rsumino might be holding,
* flush and purge the quota inodes.
......@@ -701,7 +689,7 @@ xfs_unmount_flush(
}
xfs_iunlock(rip, XFS_ILOCK_EXCL);
return (0);
return 0;
fscorrupt_out:
xfs_ifunlock(rip);
......@@ -709,8 +697,7 @@ xfs_unmount_flush(
fscorrupt_out2:
xfs_iunlock(rip, XFS_ILOCK_EXCL);
error = XFS_ERROR(EFSCORRUPTED);
return (error);
return XFS_ERROR(EFSCORRUPTED);
}
/*
......@@ -730,7 +717,6 @@ xfs_root(
vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip);
VN_HOLD(vp);
*vpp = vp;
return 0;
}
......@@ -1410,23 +1396,6 @@ xfs_syncsub(
ASSERT(ipointer_in == B_FALSE);
/*
* Get the Quota Manager to flush the dquots in a similar manner.
*/
if (XFS_IS_QUOTA_ON(mp)) {
if ((error = xfs_qm_sync(mp, flags))) {
/*
* If we got an IO error, we will be shutting down.
* So, there's nothing more for us to do here.
*/
ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
if (XFS_FORCED_SHUTDOWN(mp)) {
kmem_free(ipointer, sizeof(xfs_iptr_t));
return XFS_ERROR(error);
}
}
}
/*
* Flushing out dirty data above probably generated more
* log activity, so if this isn't vfs_sync() then flush
......@@ -1581,16 +1550,17 @@ xfs_vget(
vfsops_t xfs_vfsops = {
BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS),
.vfs_parseargs = xfs_parseargs,
.vfs_showargs = xfs_showargs,
.vfs_mount = xfs_mount,
.vfs_unmount = xfs_unmount,
.vfs_root = xfs_root,
.vfs_statvfs = xfs_statvfs,
.vfs_sync = xfs_sync,
.vfs_vget = xfs_vget,
.vfs_dmapiops = (vfs_dmapiops_t)fs_nosys,
.vfs_quotactl = (vfs_quotactl_t)fs_nosys,
.vfs_init_vnode = xfs_initialize_vnode,
.vfs_force_shutdown = xfs_do_force_shutdown,
#ifdef CONFIG_XFS_DMAPI
.vfs_dmapi_mount = xfs_dm_mount,
.vfs_dmapi_fsys_vector = xfs_dm_get_fsys_vector,
#endif
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment