aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_vnops.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2016-01-17 08:40:51 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2016-01-17 08:40:51 +0000
commitce958bdefe9897b395da652686a9104b401f4265 (patch)
tree16b9eb6d93a01d3b7c2e3468655dd69e5581a46d /sys/kern/vfs_vnops.c
parentaeace3c33cc49227dc51892c0afa7023555f6ddf (diff)
downloadsrc-ce958bdefe9897b395da652686a9104b401f4265.tar.gz
src-ce958bdefe9897b395da652686a9104b401f4265.zip
When cleaning up from failed adv locking and checking for write, do
not call VOP_CLOSE() manually. Instead, delegate the close to fo_close() performed as part of the fdrop() on the file failed to open. For this, finish constructing file on error, in particular, set f_vnode and f_ops. Forcibly resetting f_ops to badfileops disabled additional cleanups performed by fo_close() for some file types, in this case it was noted that cdevpriv data was corrupted. Since fo_close() call must be enabled for some file types, it makes more sense to enable it for all files opened through vn_open_cred(). In collaboration with: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=294205
Diffstat (limited to 'sys/kern/vfs_vnops.c')
-rw-r--r--sys/kern/vfs_vnops.c39
1 files changed, 15 insertions, 24 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 6d07e7f9d45c..5f8bddc0419d 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -299,10 +299,9 @@ int
vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
struct thread *td, struct file *fp)
{
- struct mount *mp;
accmode_t accmode;
struct flock lf;
- int error, have_flock, lock_flags, type;
+ int error, lock_flags, type;
if (vp->v_type == VLNK)
return (EMLINK);
@@ -365,10 +364,12 @@ vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
if ((fmode & FNONBLOCK) == 0)
type |= F_WAIT;
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
- have_flock = (error == 0);
+ if (error == 0)
+ fp->f_flag |= FHASLOCK;
vn_lock(vp, lock_flags | LK_RETRY);
if (error == 0 && vp->v_iflag & VI_DOOMED)
error = ENOENT;
+
/*
* Another thread might have used this vnode as an
* executable while the vnode lock was dropped.
@@ -377,34 +378,24 @@ vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
*/
if (error == 0 && accmode & VWRITE)
error = vn_writechk(vp);
- if (error) {
- VOP_UNLOCK(vp, 0);
- if (have_flock) {
- lf.l_whence = SEEK_SET;
- lf.l_start = 0;
- lf.l_len = 0;
- lf.l_type = F_UNLCK;
- (void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf,
- F_FLOCK);
+
+ if (error != 0) {
+ fp->f_flag |= FOPENFAILED;
+ fp->f_vnode = vp;
+ if (fp->f_ops == &badfileops) {
+ fp->f_type = DTYPE_VNODE;
+ fp->f_ops = &vnops;
}
- vn_start_write(vp, &mp, V_WAIT);
- vn_lock(vp, lock_flags | LK_RETRY);
- (void)VOP_CLOSE(vp, fmode, cred, td);
- vn_finished_write(mp);
- /* Prevent second close from fdrop()->vn_close(). */
- if (fp != NULL)
- fp->f_ops= &badfileops;
- return (error);
+ vref(vp);
}
- fp->f_flag |= FHASLOCK;
}
- if (fmode & FWRITE) {
+ if (error == 0 && fmode & FWRITE) {
VOP_ADD_WRITECOUNT(vp, 1);
CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d",
__func__, vp, vp->v_writecount);
}
ASSERT_VOP_LOCKED(vp, "vn_open_vnode");
- return (0);
+ return (error);
}
/*
@@ -449,7 +440,7 @@ vn_close(vp, flags, file_cred, td)
vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, lock_flags | LK_RETRY);
- if (flags & FWRITE) {
+ if ((flags & (FWRITE | FOPENFAILED)) == FWRITE) {
VNASSERT(vp->v_writecount > 0, vp,
("vn_close: negative writecount"));
VOP_ADD_WRITECOUNT(vp, -1);