The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=fa3bd463cee5c3abeac29a83dc86eb3abfa97b06

commit fa3bd463cee5c3abeac29a83dc86eb3abfa97b06
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2021-01-29 23:48:55 +0000
Commit:     Konstantin Belousov <k...@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) {
+               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;
+                       }
+                       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 */
 
 #define        VV_ROOT         0x0001  /* root of its filesystem */
 #define        VV_ISTTY        0x0002  /* vnode represents a tty */
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to