aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_vnops.c
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2020-01-08 19:05:32 +0000
committerKyle Evans <kevans@FreeBSD.org>2020-01-08 19:05:32 +0000
commit2856d85ecbe2e402e55913c31d77823f83316a5a (patch)
tree4fff4fdea8b74e3436b02ce7fbcf31319ed0d65b /sys/kern/vfs_vnops.c
parentf57d4d4641a329fad1d373d2d098560da48d53ee (diff)
downloadsrc-2856d85ecbe2e402e55913c31d77823f83316a5a.tar.gz
src-2856d85ecbe2e402e55913c31d77823f83316a5a.zip
posix_fallocate: push vnop implementation into the fileop layer
This opens the door for other descriptor types to implement posix_fallocate(2) as needed. Reviewed by: kib, bcr (manpages) Differential Revision: https://reviews.freebsd.org/D23042
Notes
Notes: svn path=/head/; revision=356510
Diffstat (limited to 'sys/kern/vfs_vnops.c')
-rw-r--r--sys/kern/vfs_vnops.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index f15ea0969b7e..61edb3165e01 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -103,6 +103,7 @@ static fo_kqfilter_t vn_kqfilter;
static fo_stat_t vn_statfile;
static fo_close_t vn_closefile;
static fo_mmap_t vn_mmap;
+static fo_fallocate_t vn_fallocate;
struct fileops vnops = {
.fo_read = vn_io_fault,
@@ -119,6 +120,7 @@ struct fileops vnops = {
.fo_seek = vn_seek,
.fo_fill_kinfo = vn_fill_kinfo,
.fo_mmap = vn_mmap,
+ .fo_fallocate = vn_fallocate,
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
};
@@ -3150,3 +3152,60 @@ out:
free(dat, M_TEMP);
return (error);
}
+
+static int
+vn_fallocate(struct file *fp, off_t offset, off_t len, struct thread *td)
+{
+ struct mount *mp;
+ struct vnode *vp;
+ off_t olen, ooffset;
+ int error;
+#ifdef AUDIT
+ int audited_vnode1 = 0;
+#endif
+
+ vp = fp->f_vnode;
+ if (vp->v_type != VREG)
+ return (ENODEV);
+
+ /* Allocating blocks may take a long time, so iterate. */
+ for (;;) {
+ olen = len;
+ ooffset = offset;
+
+ bwillwrite();
+ mp = NULL;
+ error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
+ if (error != 0)
+ break;
+ error = vn_lock(vp, LK_EXCLUSIVE);
+ if (error != 0) {
+ vn_finished_write(mp);
+ break;
+ }
+#ifdef AUDIT
+ if (!audited_vnode1) {
+ AUDIT_ARG_VNODE1(vp);
+ audited_vnode1 = 1;
+ }
+#endif
+#ifdef MAC
+ error = mac_vnode_check_write(td->td_ucred, fp->f_cred, vp);
+ if (error == 0)
+#endif
+ error = VOP_ALLOCATE(vp, &offset, &len);
+ VOP_UNLOCK(vp);
+ vn_finished_write(mp);
+
+ if (olen + ooffset != offset + len) {
+ panic("offset + len changed from %jx/%jx to %jx/%jx",
+ ooffset, olen, offset, len);
+ }
+ if (error != 0 || len == 0)
+ break;
+ KASSERT(olen > len, ("Iteration did not make progress?"));
+ maybe_yield();
+ }
+
+ return (error);
+}