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
This commit is contained in:
parent
aeace3c33c
commit
ce958bdefe
@ -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);
|
||||
|
@ -142,6 +142,8 @@ typedef __pid_t pid_t;
|
||||
/* Only for devfs d_close() flags. */
|
||||
#define FLASTCLOSE O_DIRECTORY
|
||||
#define FREVOKE O_VERIFY
|
||||
/* Only for fo_close() from half-succeeded open */
|
||||
#define FOPENFAILED O_TTY_INIT
|
||||
|
||||
/* convert from open() flags to/from fflags; convert O_RD/WR to FREAD/FWRITE */
|
||||
#define FFLAGS(oflags) ((oflags) & O_EXEC ? (oflags) : (oflags) + 1)
|
||||
|
Loading…
Reference in New Issue
Block a user