Add a lock structure to vnode structure. Previously it was either allocated
separately (nfs, cd9660 etc) or keept as a first element of structure referenced by v_data pointer(ffs). Such organization leads to known problems with stacked filesystems. From this point vop_no*lock*() functions maintain only interlock lock. vop_std*lock*() functions maintain built-in v_lock structure using lockmgr(). vop_sharedlock() is compatible with vop_stdunlock(), but maintains a shared lock on vnode. If filesystem wishes to export lockmgr compatible lock, it can put an address of this lock to v_vnlock field. This indicates that the upper filesystem can take advantage of it and use single lock structure for entire (or part) of stack of vnodes. This field shouldn't be examined or modified by VFS code except for initialization purposes. Reviewed in general by: mckusick
This commit is contained in:
parent
f568640168
commit
67e871664b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=66355
@ -130,7 +130,7 @@ ufs_ihashins(ip)
|
||||
struct ihashhead *ipp;
|
||||
|
||||
/* lock the inode, then put it on the appropriate hash list */
|
||||
lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p);
|
||||
lockmgr(&ip->i_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0, p);
|
||||
|
||||
simple_lock(&ufs_ihash_slock);
|
||||
ipp = INOHASH(ip->i_dev, ip->i_number);
|
||||
|
@ -66,7 +66,6 @@ typedef long ufs_lbn_t;
|
||||
* active, and is put back when the file is no longer being used.
|
||||
*/
|
||||
struct inode {
|
||||
struct lock i_lock; /* Inode lock. >Keep this first< */
|
||||
LIST_ENTRY(inode) i_hash;/* Hash chain. */
|
||||
struct vnode *i_vnode;/* Vnode associated with this inode. */
|
||||
struct vnode *i_devvp;/* Vnode for block I/O. */
|
||||
|
@ -66,7 +66,6 @@ typedef long ufs_lbn_t;
|
||||
* active, and is put back when the file is no longer being used.
|
||||
*/
|
||||
struct inode {
|
||||
struct lock i_lock; /* Inode lock. >Keep this first< */
|
||||
LIST_ENTRY(inode) i_hash;/* Hash chain. */
|
||||
struct vnode *i_vnode;/* Vnode associated with this inode. */
|
||||
struct vnode *i_devvp;/* Vnode for block I/O. */
|
||||
|
@ -231,19 +231,13 @@ vop_stdlock(ap)
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
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;
|
||||
}
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
#ifndef DEBUG_LOCKS
|
||||
return (lockmgr(l, ap->a_flags, &ap->a_vp->v_interlock, ap->a_p));
|
||||
return (lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock, ap->a_p));
|
||||
#else
|
||||
return (debuglockmgr(l, ap->a_flags, &ap->a_vp->v_interlock, ap->a_p,
|
||||
"vop_stdlock", ap->a_vp->filename, ap->a_vp->line));
|
||||
return (debuglockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock,
|
||||
ap->a_p, "vop_stdlock", vp->filename, vp->line));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -255,15 +249,9 @@ vop_stdunlock(ap)
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct lock *l;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return (lockmgr(l, ap->a_flags | LK_RELEASE, &ap->a_vp->v_interlock,
|
||||
return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
|
||||
ap->a_p));
|
||||
}
|
||||
|
||||
@ -274,12 +262,8 @@ vop_stdislocked(ap)
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct lock *l;
|
||||
|
||||
if ((l = (struct lock *)ap->a_vp->v_data) == NULL)
|
||||
return 0;
|
||||
|
||||
return (lockstatus(l, ap->a_p));
|
||||
return (lockstatus(&ap->a_vp->v_lock, ap->a_p));
|
||||
}
|
||||
|
||||
int
|
||||
@ -374,13 +358,6 @@ vop_sharedlock(ap)
|
||||
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, LK_NOPAUSE);
|
||||
}
|
||||
switch (flags & LK_TYPE_MASK) {
|
||||
case LK_DRAIN:
|
||||
vnflags = LK_DRAIN;
|
||||
@ -408,9 +385,9 @@ vop_sharedlock(ap)
|
||||
if (flags & LK_INTERLOCK)
|
||||
vnflags |= LK_INTERLOCK;
|
||||
#ifndef DEBUG_LOCKS
|
||||
return (lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p));
|
||||
return (lockmgr(&vp->v_lock, vnflags, &vp->v_interlock, ap->a_p));
|
||||
#else
|
||||
return (debuglockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p,
|
||||
return (debuglockmgr(&vp->v_lock, vnflags, &vp->v_interlock, ap->a_p,
|
||||
"vop_sharedlock", vp->filename, vp->line));
|
||||
#endif
|
||||
}
|
||||
@ -447,13 +424,6 @@ vop_nolock(ap)
|
||||
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, LK_NOPAUSE);
|
||||
}
|
||||
switch (flags & LK_TYPE_MASK) {
|
||||
case LK_DRAIN:
|
||||
vnflags = LK_DRAIN;
|
||||
@ -472,7 +442,7 @@ vop_nolock(ap)
|
||||
}
|
||||
if (flags & LK_INTERLOCK)
|
||||
vnflags |= LK_INTERLOCK;
|
||||
return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p));
|
||||
return(lockmgr(&vp->v_lock, vnflags, &vp->v_interlock, ap->a_p));
|
||||
#else /* for now */
|
||||
/*
|
||||
* Since we are not using the lock manager, we must clear
|
||||
@ -495,15 +465,14 @@ vop_nounlock(ap)
|
||||
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));
|
||||
/*
|
||||
* Since we are not using the lock manager, we must clear
|
||||
* the interlock here.
|
||||
*/
|
||||
if (ap->a_flags & LK_INTERLOCK)
|
||||
simple_unlock(&ap->a_vp->v_interlock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -516,11 +485,8 @@ vop_noislocked(ap)
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
if (vp->v_vnlock == NULL)
|
||||
return (0);
|
||||
return (lockstatus(vp->v_vnlock, ap->a_p));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -618,6 +618,7 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
vp->v_type = VNON;
|
||||
vp->v_tag = tag;
|
||||
vp->v_op = vops;
|
||||
lockinit(&vp->v_lock, PVFS, "vnlock", 0, LK_NOPAUSE);
|
||||
insmntque(vp, mp);
|
||||
*vpp = vp;
|
||||
vp->v_usecount = 1;
|
||||
@ -1373,6 +1374,9 @@ addaliasu(nvp, nvp_rdev)
|
||||
ops = nvp->v_op;
|
||||
nvp->v_op = ovp->v_op;
|
||||
ovp->v_op = ops;
|
||||
lockinit(&ovp->v_lock, PVFS, "vnlock", 0, LK_NOPAUSE);
|
||||
if (nvp->v_vnlock)
|
||||
ovp->v_vnlock = &ovp->v_lock;
|
||||
insmntque(ovp, nvp->v_mount);
|
||||
vrele(nvp);
|
||||
vgone(nvp);
|
||||
@ -1773,10 +1777,7 @@ vclean(vp, flags, p)
|
||||
}
|
||||
|
||||
cache_purge(vp);
|
||||
if (vp->v_vnlock) {
|
||||
FREE(vp->v_vnlock, M_VNODE);
|
||||
vp->v_vnlock = NULL;
|
||||
}
|
||||
vp->v_vnlock = NULL;
|
||||
|
||||
if (VSHOULDFREE(vp))
|
||||
vfree(vp);
|
||||
|
@ -618,6 +618,7 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
vp->v_type = VNON;
|
||||
vp->v_tag = tag;
|
||||
vp->v_op = vops;
|
||||
lockinit(&vp->v_lock, PVFS, "vnlock", 0, LK_NOPAUSE);
|
||||
insmntque(vp, mp);
|
||||
*vpp = vp;
|
||||
vp->v_usecount = 1;
|
||||
@ -1373,6 +1374,9 @@ addaliasu(nvp, nvp_rdev)
|
||||
ops = nvp->v_op;
|
||||
nvp->v_op = ovp->v_op;
|
||||
ovp->v_op = ops;
|
||||
lockinit(&ovp->v_lock, PVFS, "vnlock", 0, LK_NOPAUSE);
|
||||
if (nvp->v_vnlock)
|
||||
ovp->v_vnlock = &ovp->v_lock;
|
||||
insmntque(ovp, nvp->v_mount);
|
||||
vrele(nvp);
|
||||
vgone(nvp);
|
||||
@ -1773,10 +1777,7 @@ vclean(vp, flags, p)
|
||||
}
|
||||
|
||||
cache_purge(vp);
|
||||
if (vp->v_vnlock) {
|
||||
FREE(vp->v_vnlock, M_VNODE);
|
||||
vp->v_vnlock = NULL;
|
||||
}
|
||||
vp->v_vnlock = NULL;
|
||||
|
||||
if (VSHOULDFREE(vp))
|
||||
vfree(vp);
|
||||
|
@ -148,6 +148,7 @@ static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
|
||||
{ &vop_getpages_desc, (vop_t *) nfs_getpages },
|
||||
{ &vop_putpages_desc, (vop_t *) nfs_putpages },
|
||||
{ &vop_inactive_desc, (vop_t *) nfs_inactive },
|
||||
{ &vop_islocked_desc, (vop_t *) vop_stdislocked },
|
||||
{ &vop_lease_desc, (vop_t *) vop_null },
|
||||
{ &vop_link_desc, (vop_t *) nfs_link },
|
||||
{ &vop_lock_desc, (vop_t *) vop_sharedlock },
|
||||
@ -168,6 +169,7 @@ static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
|
||||
{ &vop_setattr_desc, (vop_t *) nfs_setattr },
|
||||
{ &vop_strategy_desc, (vop_t *) nfs_strategy },
|
||||
{ &vop_symlink_desc, (vop_t *) nfs_symlink },
|
||||
{ &vop_unlock_desc, (vop_t *) vop_stdunlock },
|
||||
{ &vop_write_desc, (vop_t *) nfs_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@ -185,12 +187,14 @@ static struct vnodeopv_entry_desc nfsv2_specop_entries[] = {
|
||||
{ &vop_close_desc, (vop_t *) nfsspec_close },
|
||||
{ &vop_fsync_desc, (vop_t *) nfs_fsync },
|
||||
{ &vop_getattr_desc, (vop_t *) nfs_getattr },
|
||||
{ &vop_islocked_desc, (vop_t *) vop_stdislocked },
|
||||
{ &vop_inactive_desc, (vop_t *) nfs_inactive },
|
||||
{ &vop_lock_desc, (vop_t *) vop_sharedlock },
|
||||
{ &vop_print_desc, (vop_t *) nfs_print },
|
||||
{ &vop_read_desc, (vop_t *) nfsspec_read },
|
||||
{ &vop_reclaim_desc, (vop_t *) nfs_reclaim },
|
||||
{ &vop_setattr_desc, (vop_t *) nfs_setattr },
|
||||
{ &vop_unlock_desc, (vop_t *) vop_stdunlock },
|
||||
{ &vop_write_desc, (vop_t *) nfsspec_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
@ -148,6 +148,7 @@ static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
|
||||
{ &vop_getpages_desc, (vop_t *) nfs_getpages },
|
||||
{ &vop_putpages_desc, (vop_t *) nfs_putpages },
|
||||
{ &vop_inactive_desc, (vop_t *) nfs_inactive },
|
||||
{ &vop_islocked_desc, (vop_t *) vop_stdislocked },
|
||||
{ &vop_lease_desc, (vop_t *) vop_null },
|
||||
{ &vop_link_desc, (vop_t *) nfs_link },
|
||||
{ &vop_lock_desc, (vop_t *) vop_sharedlock },
|
||||
@ -168,6 +169,7 @@ static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
|
||||
{ &vop_setattr_desc, (vop_t *) nfs_setattr },
|
||||
{ &vop_strategy_desc, (vop_t *) nfs_strategy },
|
||||
{ &vop_symlink_desc, (vop_t *) nfs_symlink },
|
||||
{ &vop_unlock_desc, (vop_t *) vop_stdunlock },
|
||||
{ &vop_write_desc, (vop_t *) nfs_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@ -185,12 +187,14 @@ static struct vnodeopv_entry_desc nfsv2_specop_entries[] = {
|
||||
{ &vop_close_desc, (vop_t *) nfsspec_close },
|
||||
{ &vop_fsync_desc, (vop_t *) nfs_fsync },
|
||||
{ &vop_getattr_desc, (vop_t *) nfs_getattr },
|
||||
{ &vop_islocked_desc, (vop_t *) vop_stdislocked },
|
||||
{ &vop_inactive_desc, (vop_t *) nfs_inactive },
|
||||
{ &vop_lock_desc, (vop_t *) vop_sharedlock },
|
||||
{ &vop_print_desc, (vop_t *) nfs_print },
|
||||
{ &vop_read_desc, (vop_t *) nfsspec_read },
|
||||
{ &vop_reclaim_desc, (vop_t *) nfs_reclaim },
|
||||
{ &vop_setattr_desc, (vop_t *) nfs_setattr },
|
||||
{ &vop_unlock_desc, (vop_t *) vop_stdunlock },
|
||||
{ &vop_write_desc, (vop_t *) nfsspec_write },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
@ -37,6 +37,7 @@
|
||||
#ifndef _SYS_VNODE_H_
|
||||
#define _SYS_VNODE_H_
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/uio.h>
|
||||
@ -115,7 +116,8 @@ struct vnode {
|
||||
int v_clen; /* length of current cluster */
|
||||
struct vm_object *v_object; /* Place to store VM object */
|
||||
struct simplelock v_interlock; /* lock on usecount and flag */
|
||||
struct lock *v_vnlock; /* used for non-locking fs's */
|
||||
struct lock v_lock; /* used if fs don't have one */
|
||||
struct lock *v_vnlock; /* pointer to vnode lock */
|
||||
enum vtagtype v_tag; /* type of underlying data */
|
||||
void *v_data; /* private data for fs */
|
||||
LIST_HEAD(, namecache) v_cache_src; /* Cache entries from us */
|
||||
|
@ -1056,7 +1056,11 @@ ffs_vget(mp, ino, vpp)
|
||||
return (error);
|
||||
}
|
||||
bzero((caddr_t)ip, sizeof(struct inode));
|
||||
lockinit(&ip->i_lock, PINOD, "inode", 0, LK_CANRECURSE);
|
||||
/*
|
||||
* FFS supports lock sharing in the stack of vnodes
|
||||
*/
|
||||
vp->v_vnlock = &vp->v_lock;
|
||||
lockinit(vp->v_vnlock, PINOD, "inode", 0, LK_CANRECURSE);
|
||||
vp->v_data = ip;
|
||||
ip->i_vnode = vp;
|
||||
ip->i_fs = fs = ump->um_fs;
|
||||
|
@ -66,7 +66,6 @@ typedef long ufs_lbn_t;
|
||||
* active, and is put back when the file is no longer being used.
|
||||
*/
|
||||
struct inode {
|
||||
struct lock i_lock; /* Inode lock. >Keep this first< */
|
||||
LIST_ENTRY(inode) i_hash;/* Hash chain. */
|
||||
struct vnode *i_vnode;/* Vnode associated with this inode. */
|
||||
struct vnode *i_devvp;/* Vnode for block I/O. */
|
||||
|
@ -130,7 +130,7 @@ ufs_ihashins(ip)
|
||||
struct ihashhead *ipp;
|
||||
|
||||
/* lock the inode, then put it on the appropriate hash list */
|
||||
lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p);
|
||||
lockmgr(&ip->i_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0, p);
|
||||
|
||||
simple_lock(&ufs_ihash_slock);
|
||||
ipp = INOHASH(ip->i_dev, ip->i_number);
|
||||
|
@ -1782,7 +1782,7 @@ ufs_print(ap)
|
||||
minor(ip->i_dev));
|
||||
if (vp->v_type == VFIFO)
|
||||
fifo_printinfo(vp);
|
||||
lockmgr_printinfo(&ip->i_lock);
|
||||
lockmgr_printinfo(&vp->v_lock);
|
||||
printf("\n");
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user