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:
parent
399be91098
commit
8d7cd10ba6
@ -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 *,
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user