From owner-svn-src-head@freebsd.org Tue Sep 15 22:19:17 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 82E4D3E2434; Tue, 15 Sep 2020 22:19:17 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Brd1d2pdWz3WBG; Tue, 15 Sep 2020 22:19:17 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 3F823F2A6; Tue, 15 Sep 2020 22:19:17 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 08FMJGuV065725; Tue, 15 Sep 2020 22:19:16 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 08FMJGMw065722; Tue, 15 Sep 2020 22:19:16 GMT (envelope-from kib@FreeBSD.org) Message-Id: <202009152219.08FMJGMw065722@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Tue, 15 Sep 2020 22:19:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r365787 - head/sys/fs/tmpfs X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: head/sys/fs/tmpfs X-SVN-Commit-Revision: 365787 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Sep 2020 22:19:17 -0000 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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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,