aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-04-19 10:25:30 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-04-21 15:06:51 +0000
commit54f98c4dbf9b1203a4e3e1b13fd0738441226991 (patch)
tree484ff3b37934e2d79ad9d8598b0330ff0b7a107f
parent45aec46246fe61a3f45cf7da1c80850dc226f609 (diff)
downloadsrc-54f98c4dbf9b1203a4e3e1b13fd0738441226991.tar.gz
src-54f98c4dbf9b1203a4e3e1b13fd0738441226991.zip
vn_open_vnode(): handle error when fp == NULL
If VOP_ADD_WRITECOUNT() or adv locking failed, so VOP_CLOSE() needs to be called, we cannot use fp fo_close() when there is no fp. This occurs when e.g. kernel code directly calls vn_open() instead of the open(2) syscall. In this case, VOP_CLOSE() can be called directly, after possible lock upgrade. Reported by: nvass@gmx.com PR: 255119 Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D29830
-rw-r--r--sys/kern/vfs_vnops.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 9da35721def4..f715c9828d04 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -451,16 +451,34 @@ vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
/*
* Error from advlock or VOP_ADD_WRITECOUNT() still requires
* calling VOP_CLOSE() to pair with earlier VOP_OPEN().
- * Arrange for that by having fdrop() to use vn_closefile().
*/
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;
+ if (fp != NULL) {
+ /*
+ * Arrange the call by having fdrop() to use
+ * vn_closefile(). This is to satisfy
+ * filesystems like devfs or tmpfs, which
+ * override fo_close().
+ */
+ fp->f_flag |= FOPENFAILED;
+ fp->f_vnode = vp;
+ if (fp->f_ops == &badfileops) {
+ fp->f_type = DTYPE_VNODE;
+ fp->f_ops = &vnops;
+ }
+ vref(vp);
+ } else {
+ /*
+ * If there is no fp, due to kernel-mode open,
+ * we can call VOP_CLOSE() now.
+ */
+ if (vp->v_type != VFIFO && (fmode & FWRITE) != 0 &&
+ !MNT_EXTENDED_SHARED(vp->v_mount) &&
+ VOP_ISLOCKED(vp) != LK_EXCLUSIVE)
+ vn_lock(vp, LK_UPGRADE | LK_RETRY);
+ (void)VOP_CLOSE(vp, fmode & (FREAD | FWRITE | FEXEC),
+ cred, td);
}
- vref(vp);
}
ASSERT_VOP_LOCKED(vp, "vn_open_vnode");