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
This commit is contained in:
Ka Ho Ng 2021-08-26 05:34:35 +08:00
parent 399be91098
commit 8d7cd10ba6
3 changed files with 93 additions and 0 deletions

View File

@ -459,6 +459,7 @@ int tmpfs_dir_getdents(struct tmpfs_mount *, struct tmpfs_node *,
int tmpfs_dir_whiteout_add(struct vnode *, struct componentname *); int tmpfs_dir_whiteout_add(struct vnode *, struct componentname *);
void tmpfs_dir_whiteout_remove(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_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_chflags(struct vnode *, u_long, struct ucred *, struct thread *);
int tmpfs_chmod(struct vnode *, mode_t, 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 *, int tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *,

View File

@ -1775,6 +1775,91 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize, boolean_t ignerr)
return (0); 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 void
tmpfs_check_mtime(struct vnode *vp) tmpfs_check_mtime(struct vnode *vp)
{ {

View File

@ -695,6 +695,12 @@ out:
return (error); 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 static int
tmpfs_fsync(struct vop_fsync_args *v) tmpfs_fsync(struct vop_fsync_args *v)
{ {
@ -1840,6 +1846,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
.vop_read = tmpfs_read, .vop_read = tmpfs_read,
.vop_read_pgcache = tmpfs_read_pgcache, .vop_read_pgcache = tmpfs_read_pgcache,
.vop_write = tmpfs_write, .vop_write = tmpfs_write,
.vop_deallocate = tmpfs_deallocate,
.vop_fsync = tmpfs_fsync, .vop_fsync = tmpfs_fsync,
.vop_remove = tmpfs_remove, .vop_remove = tmpfs_remove,
.vop_link = tmpfs_link, .vop_link = tmpfs_link,