git: fa3bd463cee5 - main - lockf: ensure atomicity of lockf for open(O_CREAT|O_EXCL|O_EXLOCK)
Mateusz Guzik
mjguzik at gmail.com
Thu Feb 18 01:16:59 UTC 2021
On 2/18/21, Konstantin Belousov <kib at freebsd.org> wrote:
> The branch main has been updated by kib:
>
> URL:
> https://cgit.FreeBSD.org/src/commit/?id=fa3bd463cee5c3abeac29a83dc86eb3abfa97b06
>
> commit fa3bd463cee5c3abeac29a83dc86eb3abfa97b06
> Author: Konstantin Belousov <kib at FreeBSD.org>
> AuthorDate: 2021-01-29 23:48:55 +0000
> Commit: Konstantin Belousov <kib at FreeBSD.org>
> CommitDate: 2021-02-17 23:22:05 +0000
>
> lockf: ensure atomicity of lockf for open(O_CREAT|O_EXCL|O_EXLOCK)
>
> or EX_SHLOCK. Do it by setting a vnode iflag indicating that the
> locking
> exclusive open is in progress, and not allowing F_LOCK request to make
> a progress until the first open finishes.
>
> Requested by: mckusick
> Reviewed by: markj, mckusick
> Tested by: pho
> Sponsored by: The FreeBSD Foundation
> MFC after: 1 week
> Differential Revision: https://reviews.freebsd.org/D28697
> ---
> sys/kern/vfs_default.c | 15 +++++++++++++++
> sys/kern/vfs_vnops.c | 23 ++++++++++++++++++++---
> sys/sys/fcntl.h | 1 +
> sys/sys/vnode.h | 2 ++
> 4 files changed, 38 insertions(+), 3 deletions(-)
>
> diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
> index 382fbb2d9ace..3c428d7b7511 100644
> --- a/sys/kern/vfs_default.c
> +++ b/sys/kern/vfs_default.c
> @@ -423,10 +423,25 @@ int
> vop_stdadvlock(struct vop_advlock_args *ap)
> {
> struct vnode *vp;
> + struct mount *mp;
> struct vattr vattr;
> int error;
>
> vp = ap->a_vp;
> +
> + /*
> + * Provide atomicity of open(O_CREAT | O_EXCL | O_EXLOCK) for
> + * local filesystems. See vn_open_cred() for reciprocal part.
> + */
> + mp = vp->v_mount;
> + if (mp != NULL && (mp->mnt_flag & MNT_LOCAL) != 0 &&
> + ap->a_op == F_SETLK && (ap->a_flags & F_FIRSTOPEN) == 0) {
This should check for FIRSTOPEN first, which will be least likely of
the entire bunch.
> + VI_LOCK(vp);
> + while ((vp->v_iflag & VI_FOPENING) != 0)
> + msleep(vp, VI_MTX(vp), PLOCK, "lockfo", 0);
> + VI_UNLOCK(vp);
> + }
> +
> if (ap->a_fl->l_whence == SEEK_END) {
> /*
> * The NFSv4 server must avoid doing a vn_lock() here, since it
> diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
> index 71dd379558cb..781968f2db53 100644
> --- a/sys/kern/vfs_vnops.c
> +++ b/sys/kern/vfs_vnops.c
> @@ -228,8 +228,10 @@ vn_open_cred(struct nameidata *ndp, int *flagp, int
> cmode, u_int vn_open_flags,
> struct vattr vat;
> struct vattr *vap = &vat;
> int fmode, error;
> + bool first_open;
>
> restart:
> + first_open = false;
> fmode = *flagp;
> if ((fmode & (O_CREAT | O_EXCL | O_DIRECTORY)) == (O_CREAT |
> O_EXCL | O_DIRECTORY))
> @@ -275,8 +277,16 @@ restart:
> #endif
> error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
> &ndp->ni_cnd, vap);
> - VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp :
> - NULL, false);
> + vp = ndp->ni_vp;
> + if (error == 0 && (fmode & O_EXCL) != 0 &&
> + (fmode & (O_EXLOCK | O_SHLOCK)) != 0) {
> + VI_LOCK(vp);
> + vp->v_iflag |= VI_FOPENING;
> + VI_UNLOCK(vp);
> + first_open = true;
> + }
error tends to be 0, so this can inspect fmode first
> + VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &vp : NULL,
> + false);
> vn_finished_write(mp);
> if (error) {
> NDFREE(ndp, NDF_ONLY_PNBUF);
> @@ -287,7 +297,6 @@ restart:
> return (error);
> }
> fmode &= ~O_TRUNC;
> - vp = ndp->ni_vp;
> } else {
> if (ndp->ni_dvp == ndp->ni_vp)
> vrele(ndp->ni_dvp);
> @@ -317,6 +326,12 @@ restart:
> vp = ndp->ni_vp;
> }
> error = vn_open_vnode(vp, fmode, cred, td, fp);
> + if (first_open) {
> + VI_LOCK(vp);
> + vp->v_iflag &= ~VI_FOPENING;
> + wakeup(vp);
> + VI_UNLOCK(vp);
> + }
> if (error)
> goto bad;
> *flagp = fmode;
> @@ -352,6 +367,8 @@ vn_open_vnode_advlock(struct vnode *vp, int fmode,
> struct file *fp)
> type = F_FLOCK;
> if ((fmode & FNONBLOCK) == 0)
> type |= F_WAIT;
> + if ((fmode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
> + type |= F_FIRSTOPEN;
> error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
> if (error == 0)
> fp->f_flag |= FHASLOCK;
> diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
> index 3c29c04e46db..70e68246be13 100644
> --- a/sys/sys/fcntl.h
> +++ b/sys/sys/fcntl.h
> @@ -287,6 +287,7 @@ typedef __pid_t pid_t;
> #define F_POSIX 0x040 /* Use POSIX semantics for lock */
> #define F_REMOTE 0x080 /* Lock owner is remote NFS client */
> #define F_NOINTR 0x100 /* Ignore signals when waiting */
> +#define F_FIRSTOPEN 0x200 /* First right to advlock file */
> #endif
>
> /*
> diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
> index 639a16881e09..9d68f9e236f6 100644
> --- a/sys/sys/vnode.h
> +++ b/sys/sys/vnode.h
> @@ -254,6 +254,8 @@ struct xvnode {
> #define VI_DOINGINACT 0x0004 /* VOP_INACTIVE is in progress */
> #define VI_OWEINACT 0x0008 /* Need to call inactive */
> #define VI_DEFINACT 0x0010 /* deferred inactive */
> +#define VI_FOPENING 0x0020 /* In open, with opening process having the
> + first right to advlock file */
The flag was not added to vn_printf
>
> #define VV_ROOT 0x0001 /* root of its filesystem */
> #define VV_ISTTY 0x0002 /* vnode represents a tty */
> _______________________________________________
> dev-commits-src-all at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
> To unsubscribe, send any mail to
> "dev-commits-src-all-unsubscribe at freebsd.org"
>
--
Mateusz Guzik <mjguzik gmail.com>
More information about the dev-commits-src-all
mailing list