Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/fs/tmpfs PR kern/55268: tmpfs is slow



details:   https://anonhg.NetBSD.org/src/rev/f64477af20d8
branches:  trunk
changeset: 1010201:f64477af20d8
user:      ad <ad%NetBSD.org@localhost>
date:      Sun May 17 19:39:15 2020 +0000

description:
PR kern/55268: tmpfs is slow

tmpfs_getpages(): handle the PGO_LOCKED case and implement lazy update of
atime/mtime.

diffstat:

 sys/fs/tmpfs/tmpfs.h       |   8 ++++-
 sys/fs/tmpfs/tmpfs_subr.c  |  54 ++++++++++++++++++++++++++++++++----
 sys/fs/tmpfs/tmpfs_vnops.c |  68 +++++++++++++++++++++++++++++----------------
 3 files changed, 97 insertions(+), 33 deletions(-)

diffs (truncated from 323 to 300 lines):

diff -r 8abe0efb85c0 -r f64477af20d8 sys/fs/tmpfs/tmpfs.h
--- a/sys/fs/tmpfs/tmpfs.h      Sun May 17 19:38:16 2020 +0000
+++ b/sys/fs/tmpfs/tmpfs.h      Sun May 17 19:39:15 2020 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: tmpfs.h,v 1.55 2018/04/19 21:50:09 christos Exp $      */
+/*     $NetBSD: tmpfs.h,v 1.56 2020/05/17 19:39:15 ad Exp $    */
 
 /*
- * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005, 2006, 2007, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -112,10 +112,12 @@
        mode_t                  tn_mode;
        int                     tn_flags;
        nlink_t                 tn_links;
+       unsigned                tn_tflags;
        struct timespec         tn_atime;
        struct timespec         tn_mtime;
        struct timespec         tn_ctime;
        struct timespec         tn_birthtime;
+       kmutex_t                tn_timelock;
 
        /* Head of byte-level lock list (used by tmpfs_advlock). */
        struct lockf *          tn_lockf;
@@ -274,6 +276,8 @@
                    const struct timespec *, const struct timespec *, int,
                    kauth_cred_t, lwp_t *);
 void           tmpfs_update(vnode_t *, unsigned);
+void           tmpfs_update_locked(vnode_t *, unsigned);
+void           tmpfs_update_lazily(vnode_t *, unsigned);
 
 /*
  * Prototypes for tmpfs_mem.c.
diff -r 8abe0efb85c0 -r f64477af20d8 sys/fs/tmpfs/tmpfs_subr.c
--- a/sys/fs/tmpfs/tmpfs_subr.c Sun May 17 19:38:16 2020 +0000
+++ b/sys/fs/tmpfs/tmpfs_subr.c Sun May 17 19:39:15 2020 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: tmpfs_subr.c,v 1.111 2020/05/16 18:31:49 christos Exp $        */
+/*     $NetBSD: tmpfs_subr.c,v 1.112 2020/05/17 19:39:15 ad Exp $      */
 
 /*
- * Copyright (c) 2005-2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005-2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -73,7 +73,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.111 2020/05/16 18:31:49 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.112 2020/05/17 19:39:15 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/cprng.h>
@@ -230,10 +230,12 @@
        node->tn_flags = 0;
        node->tn_lockf = NULL;
 
+       node->tn_tflags = 0;
        vfs_timestamp(&node->tn_atime);
        node->tn_birthtime = node->tn_atime;
        node->tn_ctime = node->tn_atime;
        node->tn_mtime = node->tn_atime;
+       mutex_init(&node->tn_timelock, MUTEX_DEFAULT, IPL_NONE);
 
        if (dvp == NULL) {
                KASSERT(vap->va_uid != VNOVAL && vap->va_gid != VNOVAL);
@@ -350,6 +352,7 @@
        KASSERT(node->tn_vnode == NULL);
        KASSERT(node->tn_links == 0);
 
+       mutex_destroy(&node->tn_timelock);
        tmpfs_node_put(tmp, node);
 }
 
@@ -1167,29 +1170,35 @@
        if (error)
                return error;
 
+       mutex_enter(&node->tn_timelock);
        if (atime->tv_sec != VNOVAL) {
+               atomic_and_uint(&node->tn_tflags, ~TMPFS_UPDATE_ATIME);
                node->tn_atime = *atime;
        }
        if (mtime->tv_sec != VNOVAL) {
+               atomic_and_uint(&node->tn_tflags, ~TMPFS_UPDATE_MTIME);
                node->tn_mtime = *mtime;
        }
        if (btime->tv_sec != VNOVAL) {
                node->tn_birthtime = *btime;
        }
+       mutex_exit(&node->tn_timelock);
        VN_KNOTE(vp, NOTE_ATTRIB);
        return 0;
 }
 
 /*
- * tmpfs_update: update the timestamps as indicated by the flags.
+ * tmpfs_update_locked: update the timestamps as indicated by the flags.
  */
 void
-tmpfs_update(vnode_t *vp, unsigned tflags)
+tmpfs_update_locked(vnode_t *vp, unsigned tflags)
 {
        tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
        struct timespec nowtm;
 
-       if (tflags == 0) {
+       KASSERT(mutex_owned(&node->tn_timelock));
+
+       if ((tflags |= atomic_swap_uint(&node->tn_tflags, 0)) == 0) {
                return;
        }
        vfs_timestamp(&nowtm);
@@ -1204,3 +1213,36 @@
                node->tn_ctime = nowtm;
        }
 }
+
+/*
+ * tmpfs_update: update the timestamps as indicated by the flags.
+ */
+void
+tmpfs_update(vnode_t *vp, unsigned tflags)
+{
+       tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
+
+       if ((tflags | atomic_load_relaxed(&node->tn_tflags)) == 0) {
+               return;
+       }
+
+       mutex_enter(&node->tn_timelock);
+       tmpfs_update_locked(vp, tflags);
+       mutex_exit(&node->tn_timelock);
+}
+
+/*
+ * tmpfs_update_lazily: schedule a deferred timestamp update.
+ */
+void
+tmpfs_update_lazily(vnode_t *vp, unsigned tflags)
+{
+       tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
+       unsigned cur;
+
+       cur = atomic_load_relaxed(&node->tn_tflags);
+       if ((cur & tflags) != tflags) {
+               atomic_or_uint(&node->tn_tflags, tflags);
+               return;
+       }
+}
diff -r 8abe0efb85c0 -r f64477af20d8 sys/fs/tmpfs/tmpfs_vnops.c
--- a/sys/fs/tmpfs/tmpfs_vnops.c        Sun May 17 19:38:16 2020 +0000
+++ b/sys/fs/tmpfs/tmpfs_vnops.c        Sun May 17 19:39:15 2020 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: tmpfs_vnops.c,v 1.138 2020/05/16 18:31:49 christos Exp $       */
+/*     $NetBSD: tmpfs_vnops.c,v 1.139 2020/05/17 19:39:15 ad Exp $     */
 
 /*
- * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005, 2006, 2007, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.138 2020/05/16 18:31:49 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.139 2020/05/17 19:39:15 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
@@ -438,10 +438,6 @@
        vap->va_fileid = node->tn_id;
        vap->va_size = node->tn_size;
        vap->va_blocksize = PAGE_SIZE;
-       vap->va_atime = node->tn_atime;
-       vap->va_mtime = node->tn_mtime;
-       vap->va_ctime = node->tn_ctime;
-       vap->va_birthtime = node->tn_birthtime;
        vap->va_gen = TMPFS_NODE_GEN(node);
        vap->va_flags = node->tn_flags;
        vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
@@ -451,6 +447,14 @@
        vap->va_vaflags = 0;
        vap->va_spare = VNOVAL; /* XXX */
 
+       mutex_enter(&node->tn_timelock);
+       tmpfs_update_locked(vp, 0);
+       vap->va_atime = node->tn_atime;
+       vap->va_mtime = node->tn_mtime;
+       vap->va_ctime = node->tn_ctime;
+       vap->va_birthtime = node->tn_birthtime;
+       mutex_exit(&node->tn_timelock);
+
        return 0;
 }
 
@@ -661,7 +665,7 @@
        vnode_t *dvp = ap->a_dvp, *vp = ap->a_vp;
        tmpfs_node_t *dnode, *node;
        tmpfs_dirent_t *de;
-       int error;
+       int error, tflags;
 
        KASSERT(VOP_ISLOCKED(dvp));
        KASSERT(VOP_ISLOCKED(vp));
@@ -710,11 +714,12 @@
        else
                tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);
 
+       tflags = TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME;
        if (node->tn_links > 0) {
                /* We removed a hard link. */
-               tmpfs_update(vp, TMPFS_UPDATE_CTIME);
+               tflags |= TMPFS_UPDATE_CTIME;
        }
-       tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
+       tmpfs_update(dvp, tflags);
        error = 0;
 out:
        /* Drop the reference and unlock the node. */
@@ -1062,6 +1067,7 @@
                }
                *ap->a_recycle = true;
        } else {
+               tmpfs_update(vp, 0);
                *ap->a_recycle = false;
        }
 
@@ -1170,7 +1176,7 @@
        const vm_prot_t access_type = ap->a_access_type;
        const int advice = ap->a_advice;
        const int flags = ap->a_flags;
-       int error, npages = *ap->a_count;
+       int error, iflag, npages = *ap->a_count;
        tmpfs_node_t *node;
        struct uvm_object *uobj;
 
@@ -1190,18 +1196,30 @@
                npages = (round_page(vp->v_size) - offset) >> PAGE_SHIFT;
        }
 
-       if ((flags & PGO_LOCKED) != 0)
-               return EBUSY;
-
-       mutex_enter(vp->v_interlock);
-       error = vdead_check(vp, VDEAD_NOWAIT);
-       mutex_exit(vp->v_interlock);
-       if (error != 0)
-               return ENOENT;
+       /*
+        * Check for reclaimed vnode.  v_interlock is not held here, but
+        * VI_DEADCHECK is set with vmobjlock held.
+        */
+       iflag = atomic_load_relaxed(&vp->v_iflag);
+       if (__predict_false((iflag & VI_DEADCHECK) != 0) {
+               mutex_enter(vp->v_interlock);
+               error = vdead_check(vp, VDEAD_NOWAIT);
+               mutex_exit(vp->v_interlock);
+               if (error) {
+                       if ((flags & PGO_LOCKED) == 0)
+                               rw_exit(vp->v_uobj.vmobjlock);
+                       return error;
+               }
+       }
 
        node = VP_TO_TMPFS_NODE(vp);
        uobj = node->tn_spec.tn_reg.tn_aobj;
 
+       /*
+        * Update timestamp lazily.  The update will be made real when
+        * a synchronous update is next made -- or by tmpfs_getattr,
+        * tmpfs_putpages, and tmpfs_inactive.
+        */
        if ((flags & PGO_NOTIMESTAMP) == 0) {
                u_int tflags = 0;
 
@@ -1213,7 +1231,7 @@
                        if (vp->v_mount->mnt_flag & MNT_RELATIME)
                                tflags |= TMPFS_UPDATE_ATIME;
                }
-               tmpfs_update(vp, tflags);
+               tmpfs_update_lazily(vp, tflags);
        }
 
        /*
@@ -1222,19 +1240,17 @@
         * Clean the array of pages before.  XXX: PR/32166
         * Note that vnode lock is shared with underlying UVM object.
         */
-       if (pgs) {
+       if ((flags & PGO_LOCKED) == 0 && pgs) {
                memset(pgs, 0, sizeof(struct vm_pages *) * npages);
        }
        KASSERT(vp->v_uobj.vmobjlock == uobj->vmobjlock);



Home | Main Index | Thread Index | Old Index