Author: kib
Date: Tue Sep 15 22:19:16 2020
New Revision: 365787
URL: https://svnweb.freebsd.org/changeset/base/365787

Log:
  Add tmpfs page cache read support.
  
  Or it could be explained as lockless (for vnode lock) reads.  Reads
  are performed from the node tn_obj object.  Tmpfs regular vnode object
  lifecycle is significantly different from the normal OBJT_VNODE: it is
  alive as far as ref_count > 0.
  
  Ensure liveness of the tmpfs VREG node and consequently v_object
  inside VOP_READ_PGCACHE by referencing tmpfs node in tmpfs_open().
  Provide custom tmpfs fo_close() method on file, to ensure that close
  is paired with open.
  
  Add tmpfs VOP_READ_PGCACHE that takes advantage of all tmpfs quirks.
  It is quite cheap in code size sense to support page-ins for read for
  tmpfs even if we do not own tmpfs vnode lock.  Also, we can handle
  holes in tmpfs node without additional efforts, and do not have
  limitation of the transfer size.
  
  Reviewed by:  markj
  Discussed with and benchmarked by:    mjg (previous version)
  Tested by:    pho
  Sponsored by: The FreeBSD Foundation
  Differential revision:        https://reviews.freebsd.org/D26346

Modified:
  head/sys/fs/tmpfs/tmpfs.h
  head/sys/fs/tmpfs/tmpfs_subr.c
  head/sys/fs/tmpfs/tmpfs_vfsops.c
  head/sys/fs/tmpfs/tmpfs_vnops.c

Modified: head/sys/fs/tmpfs/tmpfs.h
==============================================================================
--- head/sys/fs/tmpfs/tmpfs.h   Tue Sep 15 22:13:21 2020        (r365786)
+++ head/sys/fs/tmpfs/tmpfs.h   Tue Sep 15 22:19:16 2020        (r365787)
@@ -287,6 +287,7 @@ struct tmpfs_node {
                         * a position within the file is accessed.
                         */
                        vm_object_t             tn_aobj;        /* (c) */
+                       struct tmpfs_mount      *tn_tmp;        /* (c) */
                } tn_reg;
        } tn_spec;      /* (v) */
 };
@@ -415,6 +416,7 @@ void        tmpfs_ref_node(struct tmpfs_node *node);
 int    tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *, enum vtype,
            uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *,
            const char *, dev_t, struct tmpfs_node **);
+int    tmpfs_fo_close(struct file *fp, struct thread *td);
 void   tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);
 bool   tmpfs_free_node_locked(struct tmpfs_mount *, struct tmpfs_node *, bool);
 void   tmpfs_free_tmp(struct tmpfs_mount *);
@@ -557,6 +559,8 @@ tmpfs_update_getattr(struct vnode *vp)
        if (__predict_false(node->tn_status & update_flags) != 0)
                tmpfs_update(vp);
 }
+
+extern struct fileops tmpfs_fnops;
 
 #endif /* _KERNEL */
 

Modified: head/sys/fs/tmpfs/tmpfs_subr.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_subr.c      Tue Sep 15 22:13:21 2020        
(r365786)
+++ head/sys/fs/tmpfs/tmpfs_subr.c      Tue Sep 15 22:19:16 2020        
(r365787)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/random.h>
 #include <sys/refcount.h>
 #include <sys/rwlock.h>
+#include <sys/smr.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
@@ -340,6 +341,7 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount 
                /* OBJ_TMPFS is set together with the setting of vp->v_object */
                vm_object_set_flag(obj, OBJ_TMPFS_NODE);
                VM_OBJECT_WUNLOCK(obj);
+               nnode->tn_reg.tn_tmp = tmp;
                break;
 
        default:
@@ -697,6 +699,7 @@ loop:
                vp->v_object = object;
                object->un_pager.swp.swp_tmpfs = vp;
                vm_object_set_flag(object, OBJ_TMPFS);
+               vp->v_irflag |= VIRF_PGREAD;
                VI_UNLOCK(vp);
                VM_OBJECT_WUNLOCK(object);
                break;

Modified: head/sys/fs/tmpfs/tmpfs_vfsops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vfsops.c    Tue Sep 15 22:13:21 2020        
(r365786)
+++ head/sys/fs/tmpfs/tmpfs_vfsops.c    Tue Sep 15 22:19:16 2020        
(r365787)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/dirent.h>
+#include <sys/file.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/mount.h>
@@ -662,6 +663,8 @@ static int
 tmpfs_init(struct vfsconf *conf)
 {
        tmpfs_subr_init();
+       memcpy(&tmpfs_fnops, &vnops, sizeof(struct fileops));
+       tmpfs_fnops.fo_close = tmpfs_fo_close;
        return (0);
 }
 

Modified: head/sys/fs/tmpfs/tmpfs_vnops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vnops.c     Tue Sep 15 22:13:21 2020        
(r365786)
+++ head/sys/fs/tmpfs/tmpfs_vnops.c     Tue Sep 15 22:19:16 2020        
(r365787)
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/dirent.h>
 #include <sys/fcntl.h>
+#include <sys/file.h>
 #include <sys/limits.h>
 #include <sys/lockf.h>
 #include <sys/lock.h>
@@ -276,22 +277,25 @@ tmpfs_mknod(struct vop_mknod_args *v)
        return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 }
 
+struct fileops tmpfs_fnops;
+
 static int
 tmpfs_open(struct vop_open_args *v)
 {
-       struct vnode *vp = v->a_vp;
-       int mode = v->a_mode;
-
-       int error;
+       struct vnode *vp;
        struct tmpfs_node *node;
+       struct file *fp;
+       int error, mode;
 
-       MPASS(VOP_ISLOCKED(vp));
-
+       vp = v->a_vp;
+       mode = v->a_mode;
        node = VP_TO_TMPFS_NODE(vp);
 
-       /* The file is still active but all its names have been removed
+       /*
+        * The file is still active but all its names have been removed
         * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
-        * it is about to die. */
+        * it is about to die.
+        */
        if (node->tn_links < 1)
                return (ENOENT);
 
@@ -306,8 +310,13 @@ tmpfs_open(struct vop_open_args *v)
                vnode_create_vobject(vp, node->tn_size, v->a_td);
        }
 
-       MPASS(VOP_ISLOCKED(vp));
-       return error;
+       fp = v->a_fp;
+       if (error == 0 && fp != NULL && vp->v_type == VREG) {
+               tmpfs_ref_node(node);
+               finit_vnode(fp, mode, node, &tmpfs_fnops);
+       }
+
+       return (error);
 }
 
 static int
@@ -321,6 +330,19 @@ tmpfs_close(struct vop_close_args *v)
        return (0);
 }
 
+int
+tmpfs_fo_close(struct file *fp, struct thread *td)
+{
+       struct tmpfs_node *node;
+
+       node = fp->f_data;
+       if (node != NULL) {
+               MPASS(node->tn_type == VREG);
+               tmpfs_free_node(node->tn_reg.tn_tmp, node);
+       }
+       return (vnops.fo_close(fp, td));
+}
+
 /*
  * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see
  * the comment above cache_fplookup for details.
@@ -567,6 +589,47 @@ tmpfs_read(struct vop_read_args *v)
 }
 
 static int
+tmpfs_read_pgcache(struct vop_read_pgcache_args *v)
+{
+       struct vnode *vp;
+       struct tmpfs_node *node;
+       vm_object_t object;
+       off_t size;
+       int error;
+
+       vp = v->a_vp;
+       MPASS((vp->v_irflag & VIRF_PGREAD) != 0);
+
+       if (v->a_uio->uio_offset < 0)
+               return (EINVAL);
+
+       error = EJUSTRETURN;
+       vfs_smr_enter();
+
+       node = VP_TO_TMPFS_NODE_SMR(vp);
+       if (node == NULL)
+               goto out_smr;
+       MPASS(node->tn_type == VREG);
+       MPASS(node->tn_refcount >= 1);
+       object = node->tn_reg.tn_aobj;
+       if (object == NULL)
+               goto out_smr;
+
+       MPASS((object->flags & (OBJ_ANON | OBJ_DEAD | OBJ_TMPFS_NODE)) ==
+           OBJ_TMPFS_NODE);
+       if (!VN_IS_DOOMED(vp)) {
+               /* size cannot become shorter due to rangelock. */
+               size = node->tn_size;
+               vfs_smr_exit();
+               error = uiomove_object(object, size, v->a_uio);
+               return (error);
+       }
+out_smr:
+       vfs_smr_exit();
+       return (error);
+}
+
+static int
 tmpfs_write(struct vop_write_args *v)
 {
        struct vnode *vp;
@@ -1721,6 +1784,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
        .vop_getattr =                  tmpfs_getattr,
        .vop_setattr =                  tmpfs_setattr,
        .vop_read =                     tmpfs_read,
+       .vop_read_pgcache =             tmpfs_read_pgcache,
        .vop_write =                    tmpfs_write,
        .vop_fsync =                    tmpfs_fsync,
        .vop_remove =                   tmpfs_remove,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to