1997-10-16 17:48:22 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1989, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed
|
|
|
|
* to Berkeley by John Heidemann of the UCLA Ficus project.
|
|
|
|
*
|
|
|
|
* Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
1997-12-05 19:55:52 +00:00
|
|
|
#include <sys/lock.h>
|
1997-10-26 20:55:39 +00:00
|
|
|
#include <sys/malloc.h>
|
1997-10-16 20:32:40 +00:00
|
|
|
#include <sys/unistd.h>
|
1997-10-16 17:48:22 +00:00
|
|
|
#include <sys/vnode.h>
|
The intent is to get rid of WILLRELE in vnode_if.src by making
a complement to all ops that return a vpp, VFS_VRELE. This is
initially only for file systems that implement the following ops
that do a WILLRELE:
vop_create, vop_whiteout, vop_mknod, vop_remove, vop_link,
vop_rename, vop_mkdir, vop_rmdir, vop_symlink
This is initial DNA that doesn't do anything yet. VFS_VRELE is
implemented but not called.
A default vfs_vrele was created for fs implementations that use the
standard vnode management routines.
VFS_VRELE implementations were made for the following file systems:
Standard (vfs_vrele)
ffs mfs nfs msdosfs devfs ext2fs
Custom
union umapfs
Just EOPNOTSUPP
fdesc procfs kernfs portal cd9660
These implementations may change as VOP changes are implemented.
In the next phase, in the vop implementations calls to vrele and the vrele
part of vput will be moved to the top layer vfs_vnops and made visible
to all layers. vput will be replaced by unlock in these cases. Unlocking
will still be done in the per fs layer but the refcount decrement will be
triggered at the top because it doesn't hurt to hold a vnode reference a
little longer. This will have minimal impact on the structure of the
existing code.
This will only be done for vnode arguments that are released by the various
fs vop implementations.
Wider use of VFS_VRELE will likely require restructuring of the code.
Reviewed by: phk, dyson, terry et. al.
Submitted by: Michael Hancock <michaelh@cet.co.jp>
1998-03-01 22:46:53 +00:00
|
|
|
#include <sys/mount.h>
|
1997-10-26 20:55:39 +00:00
|
|
|
#include <sys/poll.h>
|
1997-10-16 17:48:22 +00:00
|
|
|
|
The intent is to get rid of WILLRELE in vnode_if.src by making
a complement to all ops that return a vpp, VFS_VRELE. This is
initially only for file systems that implement the following ops
that do a WILLRELE:
vop_create, vop_whiteout, vop_mknod, vop_remove, vop_link,
vop_rename, vop_mkdir, vop_rmdir, vop_symlink
This is initial DNA that doesn't do anything yet. VFS_VRELE is
implemented but not called.
A default vfs_vrele was created for fs implementations that use the
standard vnode management routines.
VFS_VRELE implementations were made for the following file systems:
Standard (vfs_vrele)
ffs mfs nfs msdosfs devfs ext2fs
Custom
union umapfs
Just EOPNOTSUPP
fdesc procfs kernfs portal cd9660
These implementations may change as VOP changes are implemented.
In the next phase, in the vop implementations calls to vrele and the vrele
part of vput will be moved to the top layer vfs_vnops and made visible
to all layers. vput will be replaced by unlock in these cases. Unlocking
will still be done in the per fs layer but the refcount decrement will be
triggered at the top because it doesn't hurt to hold a vnode reference a
little longer. This will have minimal impact on the structure of the
existing code.
This will only be done for vnode arguments that are released by the various
fs vop implementations.
Wider use of VFS_VRELE will likely require restructuring of the code.
Reviewed by: phk, dyson, terry et. al.
Submitted by: Michael Hancock <michaelh@cet.co.jp>
1998-03-01 22:46:53 +00:00
|
|
|
/*
|
|
|
|
* VFS operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Complement to all vpp returning ops.
|
|
|
|
* XXX - initially only to get rid of WILLRELE.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
|
|
vfs_vrele(mp, vp)
|
|
|
|
struct mount *mp;
|
|
|
|
struct vnode *vp;
|
|
|
|
{
|
|
|
|
vrele(vp);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vnode operations
|
|
|
|
*/
|
|
|
|
|
1997-10-16 17:48:22 +00:00
|
|
|
static int vop_nostrategy __P((struct vop_strategy_args *));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This vnode table stores what we want to do if the filesystem doesn't
|
|
|
|
* implement a particular VOP.
|
|
|
|
*
|
|
|
|
* If there is no specific entry here, we will return EOPNOTSUPP.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
vop_t **default_vnodeop_p;
|
|
|
|
static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
|
1997-10-16 20:32:40 +00:00
|
|
|
{ &vop_default_desc, (vop_t *) vop_eopnotsupp },
|
1997-10-26 20:55:39 +00:00
|
|
|
{ &vop_abortop_desc, (vop_t *) vop_null },
|
1997-10-16 20:32:40 +00:00
|
|
|
{ &vop_advlock_desc, (vop_t *) vop_einval },
|
1997-10-26 20:55:39 +00:00
|
|
|
{ &vop_bwrite_desc, (vop_t *) vop_stdbwrite },
|
1997-10-16 20:32:40 +00:00
|
|
|
{ &vop_close_desc, (vop_t *) vop_null },
|
|
|
|
{ &vop_fsync_desc, (vop_t *) vop_null },
|
|
|
|
{ &vop_ioctl_desc, (vop_t *) vop_enotty },
|
1997-10-16 22:01:05 +00:00
|
|
|
{ &vop_islocked_desc, (vop_t *) vop_noislocked },
|
1997-10-26 20:26:33 +00:00
|
|
|
{ &vop_lease_desc, (vop_t *) vop_null },
|
1997-10-16 22:01:05 +00:00
|
|
|
{ &vop_lock_desc, (vop_t *) vop_nolock },
|
1997-10-16 20:32:40 +00:00
|
|
|
{ &vop_mmap_desc, (vop_t *) vop_einval },
|
|
|
|
{ &vop_open_desc, (vop_t *) vop_null },
|
|
|
|
{ &vop_pathconf_desc, (vop_t *) vop_einval },
|
1997-10-16 17:48:22 +00:00
|
|
|
{ &vop_poll_desc, (vop_t *) vop_nopoll },
|
1997-10-16 20:32:40 +00:00
|
|
|
{ &vop_readlink_desc, (vop_t *) vop_einval },
|
|
|
|
{ &vop_reallocblks_desc, (vop_t *) vop_eopnotsupp },
|
1997-10-16 17:48:22 +00:00
|
|
|
{ &vop_revoke_desc, (vop_t *) vop_revoke },
|
|
|
|
{ &vop_strategy_desc, (vop_t *) vop_nostrategy },
|
1997-10-16 22:01:05 +00:00
|
|
|
{ &vop_unlock_desc, (vop_t *) vop_nounlock },
|
1997-10-16 17:48:22 +00:00
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct vnodeopv_desc default_vnodeop_opv_desc =
|
|
|
|
{ &default_vnodeop_p, default_vnodeop_entries };
|
|
|
|
|
|
|
|
VNODEOP_SET(default_vnodeop_opv_desc);
|
|
|
|
|
|
|
|
int
|
1997-10-16 20:32:40 +00:00
|
|
|
vop_eopnotsupp(struct vop_generic_args *ap)
|
1997-10-16 17:48:22 +00:00
|
|
|
{
|
|
|
|
/*
|
1997-10-16 20:32:40 +00:00
|
|
|
printf("vop_notsupp[%s]\n", ap->a_desc->vdesc_name);
|
1997-10-16 17:48:22 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1997-10-16 20:32:40 +00:00
|
|
|
vop_ebadf(struct vop_generic_args *ap)
|
1997-10-16 17:48:22 +00:00
|
|
|
{
|
|
|
|
|
1997-10-16 20:32:40 +00:00
|
|
|
return (EBADF);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vop_enotty(struct vop_generic_args *ap)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (ENOTTY);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vop_einval(struct vop_generic_args *ap)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vop_null(struct vop_generic_args *ap)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (0);
|
1997-10-16 17:48:22 +00:00
|
|
|
}
|
|
|
|
|
1997-10-16 20:32:40 +00:00
|
|
|
int
|
|
|
|
vop_defaultop(struct vop_generic_args *ap)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (VOCALL(default_vnodeop_p, ap->a_desc->vdesc_offset, ap));
|
|
|
|
}
|
1997-10-16 17:48:22 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
vop_nostrategy (struct vop_strategy_args *ap)
|
|
|
|
{
|
|
|
|
printf("No strategy for buffer at %p\n", ap->a_bp);
|
|
|
|
vprint("", ap->a_bp->b_vp);
|
|
|
|
ap->a_bp->b_flags |= B_ERROR;
|
|
|
|
ap->a_bp->b_error = EOPNOTSUPP;
|
|
|
|
biodone(ap->a_bp);
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
1997-10-16 20:32:40 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
vop_stdpathconf(ap)
|
|
|
|
struct vop_pathconf_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_name;
|
|
|
|
int *a_retval;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (ap->a_name) {
|
|
|
|
case _PC_LINK_MAX:
|
|
|
|
*ap->a_retval = LINK_MAX;
|
|
|
|
return (0);
|
|
|
|
case _PC_MAX_CANON:
|
|
|
|
*ap->a_retval = MAX_CANON;
|
|
|
|
return (0);
|
|
|
|
case _PC_MAX_INPUT:
|
|
|
|
*ap->a_retval = MAX_INPUT;
|
|
|
|
return (0);
|
|
|
|
case _PC_PIPE_BUF:
|
|
|
|
*ap->a_retval = PIPE_BUF;
|
|
|
|
return (0);
|
|
|
|
case _PC_CHOWN_RESTRICTED:
|
|
|
|
*ap->a_retval = 1;
|
|
|
|
return (0);
|
|
|
|
case _PC_VDISABLE:
|
|
|
|
*ap->a_retval = _POSIX_VDISABLE;
|
|
|
|
return (0);
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
1997-10-17 12:36:19 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Standard lock, unlock and islocked functions.
|
|
|
|
*
|
|
|
|
* These depend on the lock structure being the first element in the
|
|
|
|
* inode, ie: vp->v_data points to the the lock!
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_stdlock(ap)
|
|
|
|
struct vop_lock_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_flags;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
struct lock *l;
|
|
|
|
|
|
|
|
if ((l = (struct lock *)ap->a_vp->v_data) == NULL) {
|
|
|
|
if (ap->a_flags & LK_INTERLOCK)
|
|
|
|
simple_unlock(&ap->a_vp->v_interlock);
|
|
|
|
return 0;
|
|
|
|
}
|
1997-10-17 12:36:19 +00:00
|
|
|
|
|
|
|
return (lockmgr(l, ap->a_flags, &ap->a_vp->v_interlock, ap->a_p));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vop_stdunlock(ap)
|
|
|
|
struct vop_unlock_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_flags;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
struct lock *l;
|
|
|
|
|
|
|
|
if ((l = (struct lock *)ap->a_vp->v_data) == NULL) {
|
|
|
|
if (ap->a_flags & LK_INTERLOCK)
|
|
|
|
simple_unlock(&ap->a_vp->v_interlock);
|
|
|
|
return 0;
|
|
|
|
}
|
1997-10-17 12:36:19 +00:00
|
|
|
|
|
|
|
return (lockmgr(l, ap->a_flags | LK_RELEASE, &ap->a_vp->v_interlock,
|
|
|
|
ap->a_p));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vop_stdislocked(ap)
|
|
|
|
struct vop_islocked_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
struct lock *l;
|
|
|
|
|
|
|
|
if ((l = (struct lock *)ap->a_vp->v_data) == NULL)
|
|
|
|
return 0;
|
1997-10-17 12:36:19 +00:00
|
|
|
|
|
|
|
return (lockstatus(l));
|
|
|
|
}
|
|
|
|
|
1997-10-26 20:55:39 +00:00
|
|
|
/*
|
|
|
|
* Return true for select/poll.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_nopoll(ap)
|
|
|
|
struct vop_poll_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_events;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
/*
|
1997-12-15 03:09:59 +00:00
|
|
|
* Return true for read/write. If the user asked for something
|
|
|
|
* special, return POLLNVAL, so that clients have a way of
|
|
|
|
* determining reliably whether or not the extended
|
|
|
|
* functionality is present without hard-coding knowledge
|
|
|
|
* of specific filesystem implementations.
|
1997-10-26 20:55:39 +00:00
|
|
|
*/
|
1997-12-15 03:09:59 +00:00
|
|
|
if (ap->a_events & ~POLLSTANDARD)
|
|
|
|
return (POLLNVAL);
|
|
|
|
|
1997-10-26 20:55:39 +00:00
|
|
|
return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
|
|
|
|
}
|
|
|
|
|
1997-12-15 03:09:59 +00:00
|
|
|
/*
|
|
|
|
* Implement poll for local filesystems that support it.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_stdpoll(ap)
|
|
|
|
struct vop_poll_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_events;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
1997-12-17 14:44:23 +00:00
|
|
|
if ((ap->a_events & ~POLLSTANDARD) == 0)
|
|
|
|
return (ap->a_events & (POLLRDNORM|POLLWRNORM));
|
1997-12-15 03:09:59 +00:00
|
|
|
return (vn_pollrecord(ap->a_vp, ap->a_p, ap->a_events));
|
|
|
|
}
|
|
|
|
|
1997-10-26 20:55:39 +00:00
|
|
|
int
|
|
|
|
vop_stdbwrite(ap)
|
|
|
|
struct vop_bwrite_args *ap;
|
|
|
|
{
|
|
|
|
return (bwrite(ap->a_bp));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stubs to use when there is no locking to be done on the underlying object.
|
|
|
|
* A minimal shared lock is necessary to ensure that the underlying object
|
|
|
|
* is not revoked while an operation is in progress. So, an active shared
|
|
|
|
* count is maintained in an auxillary vnode lock structure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_sharedlock(ap)
|
|
|
|
struct vop_lock_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_flags;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This code cannot be used until all the non-locking filesystems
|
|
|
|
* (notably NFS) are converted to properly lock and release nodes.
|
|
|
|
* Also, certain vnode operations change the locking state within
|
|
|
|
* the operation (create, mknod, remove, link, rename, mkdir, rmdir,
|
|
|
|
* and symlink). Ideally these operations should not change the
|
|
|
|
* lock state, but should be changed to let the caller of the
|
|
|
|
* function unlock them. Otherwise all intermediate vnode layers
|
|
|
|
* (such as union, umapfs, etc) must catch these functions to do
|
|
|
|
* the necessary locking at their layer. Note that the inactive
|
|
|
|
* and lookup operations also change their lock state, but this
|
|
|
|
* cannot be avoided, so these two operations will always need
|
|
|
|
* to be handled in intermediate layers.
|
|
|
|
*/
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
int vnflags, flags = ap->a_flags;
|
|
|
|
|
|
|
|
if (vp->v_vnlock == NULL) {
|
|
|
|
if ((flags & LK_TYPE_MASK) == LK_DRAIN)
|
|
|
|
return (0);
|
|
|
|
MALLOC(vp->v_vnlock, struct lock *, sizeof(struct lock),
|
|
|
|
M_VNODE, M_WAITOK);
|
|
|
|
lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0);
|
|
|
|
}
|
|
|
|
switch (flags & LK_TYPE_MASK) {
|
|
|
|
case LK_DRAIN:
|
|
|
|
vnflags = LK_DRAIN;
|
|
|
|
break;
|
|
|
|
case LK_EXCLUSIVE:
|
|
|
|
#ifdef DEBUG_VFS_LOCKS
|
|
|
|
/*
|
|
|
|
* Normally, we use shared locks here, but that confuses
|
|
|
|
* the locking assertions.
|
|
|
|
*/
|
|
|
|
vnflags = LK_EXCLUSIVE;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case LK_SHARED:
|
|
|
|
vnflags = LK_SHARED;
|
|
|
|
break;
|
|
|
|
case LK_UPGRADE:
|
|
|
|
case LK_EXCLUPGRADE:
|
|
|
|
case LK_DOWNGRADE:
|
|
|
|
return (0);
|
|
|
|
case LK_RELEASE:
|
|
|
|
default:
|
|
|
|
panic("vop_sharedlock: bad operation %d", flags & LK_TYPE_MASK);
|
|
|
|
}
|
|
|
|
if (flags & LK_INTERLOCK)
|
|
|
|
vnflags |= LK_INTERLOCK;
|
|
|
|
return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stubs to use when there is no locking to be done on the underlying object.
|
|
|
|
* A minimal shared lock is necessary to ensure that the underlying object
|
|
|
|
* is not revoked while an operation is in progress. So, an active shared
|
|
|
|
* count is maintained in an auxillary vnode lock structure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_nolock(ap)
|
|
|
|
struct vop_lock_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_flags;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
#ifdef notyet
|
|
|
|
/*
|
|
|
|
* This code cannot be used until all the non-locking filesystems
|
|
|
|
* (notably NFS) are converted to properly lock and release nodes.
|
|
|
|
* Also, certain vnode operations change the locking state within
|
|
|
|
* the operation (create, mknod, remove, link, rename, mkdir, rmdir,
|
|
|
|
* and symlink). Ideally these operations should not change the
|
|
|
|
* lock state, but should be changed to let the caller of the
|
|
|
|
* function unlock them. Otherwise all intermediate vnode layers
|
|
|
|
* (such as union, umapfs, etc) must catch these functions to do
|
|
|
|
* the necessary locking at their layer. Note that the inactive
|
|
|
|
* and lookup operations also change their lock state, but this
|
|
|
|
* cannot be avoided, so these two operations will always need
|
|
|
|
* to be handled in intermediate layers.
|
|
|
|
*/
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
int vnflags, flags = ap->a_flags;
|
|
|
|
|
|
|
|
if (vp->v_vnlock == NULL) {
|
|
|
|
if ((flags & LK_TYPE_MASK) == LK_DRAIN)
|
|
|
|
return (0);
|
|
|
|
MALLOC(vp->v_vnlock, struct lock *, sizeof(struct lock),
|
|
|
|
M_VNODE, M_WAITOK);
|
|
|
|
lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0);
|
|
|
|
}
|
|
|
|
switch (flags & LK_TYPE_MASK) {
|
|
|
|
case LK_DRAIN:
|
|
|
|
vnflags = LK_DRAIN;
|
|
|
|
break;
|
|
|
|
case LK_EXCLUSIVE:
|
|
|
|
case LK_SHARED:
|
|
|
|
vnflags = LK_SHARED;
|
|
|
|
break;
|
|
|
|
case LK_UPGRADE:
|
|
|
|
case LK_EXCLUPGRADE:
|
|
|
|
case LK_DOWNGRADE:
|
|
|
|
return (0);
|
|
|
|
case LK_RELEASE:
|
|
|
|
default:
|
|
|
|
panic("vop_nolock: bad operation %d", flags & LK_TYPE_MASK);
|
|
|
|
}
|
|
|
|
if (flags & LK_INTERLOCK)
|
|
|
|
vnflags |= LK_INTERLOCK;
|
|
|
|
return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p));
|
|
|
|
#else /* for now */
|
|
|
|
/*
|
|
|
|
* Since we are not using the lock manager, we must clear
|
|
|
|
* the interlock here.
|
|
|
|
*/
|
1997-11-18 13:03:48 +00:00
|
|
|
if (ap->a_flags & LK_INTERLOCK)
|
1997-10-26 20:55:39 +00:00
|
|
|
simple_unlock(&ap->a_vp->v_interlock);
|
|
|
|
return (0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do the inverse of vop_nolock, handling the interlock in a compatible way.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_nounlock(ap)
|
|
|
|
struct vop_unlock_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_flags;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
|
|
|
|
if (vp->v_vnlock == NULL) {
|
|
|
|
if (ap->a_flags & LK_INTERLOCK)
|
|
|
|
simple_unlock(&ap->a_vp->v_interlock);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (lockmgr(vp->v_vnlock, LK_RELEASE | ap->a_flags,
|
|
|
|
&ap->a_vp->v_interlock, ap->a_p));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return whether or not the node is in use.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vop_noislocked(ap)
|
|
|
|
struct vop_islocked_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
|
|
|
|
if (vp->v_vnlock == NULL)
|
|
|
|
return (0);
|
|
|
|
return (lockstatus(vp->v_vnlock));
|
|
|
|
}
|
|
|
|
|