git: 8d7cd10ba633 - main - tmpfs: Implement VOP_DEALLOCATE

Ka Ho Ng khng at FreeBSD.org
Wed Aug 25 21:35:14 UTC 2021


The branch main has been updated by khng:

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

commit 8d7cd10ba633309a2fa8c0d6475f85e0266e3d94
Author:     Ka Ho Ng <khng at FreeBSD.org>
AuthorDate: 2021-08-25 21:34:35 +0000
Commit:     Ka Ho Ng <khng at FreeBSD.org>
CommitDate: 2021-08-25 21:34:54 +0000

    tmpfs: Implement VOP_DEALLOCATE
    
    Implementing VOP_DEALLOCATE to allow hole-punching in the same manner as
    POSIX shared memory's fspacectl(SPACECTL_DEALLOC) support.
    
    Sponsored by:   The FreeBSD Foundation
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D31684
---
 sys/fs/tmpfs/tmpfs.h       |  1 +
 sys/fs/tmpfs/tmpfs_subr.c  | 85 ++++++++++++++++++++++++++++++++++++++++++++++
 sys/fs/tmpfs/tmpfs_vnops.c |  7 ++++
 3 files changed, 93 insertions(+)

diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h
index 99368d67aaaa..bfa12b0382bc 100644
--- a/sys/fs/tmpfs/tmpfs.h
+++ b/sys/fs/tmpfs/tmpfs.h
@@ -459,6 +459,7 @@ int	tmpfs_dir_getdents(struct tmpfs_mount *, struct tmpfs_node *,
 int	tmpfs_dir_whiteout_add(struct vnode *, struct componentname *);
 void	tmpfs_dir_whiteout_remove(struct vnode *, struct componentname *);
 int	tmpfs_reg_resize(struct vnode *, off_t, boolean_t);
+int	tmpfs_reg_punch_hole(struct vnode *vp, off_t *, off_t *);
 int	tmpfs_chflags(struct vnode *, u_long, struct ucred *, struct thread *);
 int	tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct thread *);
 int	tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *,
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c
index e746a7455860..1b7521cf0b0d 100644
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -1775,6 +1775,91 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize, boolean_t ignerr)
 	return (0);
 }
 
+/*
+ * Punch hole in the aobj associated with the regular file pointed to by 'vp'.
+ * Requests completely beyond the end-of-file are converted to no-op.
+ *
+ * Returns 0 on success or error code from tmpfs_partial_page_invalidate() on
+ * failure.
+ */
+int
+tmpfs_reg_punch_hole(struct vnode *vp, off_t *offset, off_t *length)
+{
+	struct tmpfs_mount *tmp;
+	struct tmpfs_node *node;
+	vm_object_t object;
+	vm_pindex_t pistart, pi, piend;
+	int startofs, endofs, end;
+	off_t off, len;
+	int error;
+
+	KASSERT(*length <= OFF_MAX - *offset, ("%s: offset + length overflows",
+	    __func__));
+	node = VP_TO_TMPFS_NODE(vp);
+	KASSERT(node->tn_type == VREG, ("%s: node is not regular file",
+	    __func__));
+	object = node->tn_reg.tn_aobj;
+	tmp = VFS_TO_TMPFS(vp->v_mount);
+	off = *offset;
+	len = omin(node->tn_size - off, *length);
+	startofs = off & PAGE_MASK;
+	endofs = (off + len) & PAGE_MASK;
+	pistart = OFF_TO_IDX(off);
+	piend = OFF_TO_IDX(off + len);
+	pi = OFF_TO_IDX((vm_ooffset_t)off + PAGE_MASK);
+	error = 0;
+
+	/* Handle the case when offset is on or beyond file size. */
+	if (len <= 0) {
+		*length = 0;
+		return (0);
+	}
+
+	VM_OBJECT_WLOCK(object);
+
+	/*
+	 * If there is a partial page at the beginning of the hole-punching
+	 * request, fill the partial page with zeroes.
+	 */
+	if (startofs != 0) {
+		end = pistart != piend ? PAGE_SIZE : endofs;
+		error = tmpfs_partial_page_invalidate(object, pistart, startofs,
+		    end, FALSE);
+		if (error != 0)
+			goto out;
+		off += end - startofs;
+		len -= end - startofs;
+	}
+
+	/*
+	 * Toss away the full pages in the affected area.
+	 */
+	if (pi < piend) {
+		vm_object_page_remove(object, pi, piend, 0);
+		off += IDX_TO_OFF(piend - pi);
+		len -= IDX_TO_OFF(piend - pi);
+	}
+
+	/*
+	 * If there is a partial page at the end of the hole-punching request,
+	 * fill the partial page with zeroes.
+	 */
+	if (endofs != 0 && pistart != piend) {
+		error = tmpfs_partial_page_invalidate(object, piend, 0, endofs,
+		    FALSE);
+		if (error != 0)
+			goto out;
+		off += endofs;
+		len -= endofs;
+	}
+
+out:
+	VM_OBJECT_WUNLOCK(object);
+	*offset = off;
+	*length = len;
+	return (error);
+}
+
 void
 tmpfs_check_mtime(struct vnode *vp)
 {
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 326a5132990d..d8c74cecdfe4 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -695,6 +695,12 @@ out:
 	return (error);
 }
 
+static int
+tmpfs_deallocate(struct vop_deallocate_args *v)
+{
+	return (tmpfs_reg_punch_hole(v->a_vp, v->a_offset, v->a_len));
+}
+
 static int
 tmpfs_fsync(struct vop_fsync_args *v)
 {
@@ -1840,6 +1846,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
 	.vop_read =			tmpfs_read,
 	.vop_read_pgcache =		tmpfs_read_pgcache,
 	.vop_write =			tmpfs_write,
+	.vop_deallocate =		tmpfs_deallocate,
 	.vop_fsync =			tmpfs_fsync,
 	.vop_remove =			tmpfs_remove,
 	.vop_link =			tmpfs_link,


More information about the dev-commits-src-main mailing list