diff options
author | Kyle Evans <kevans@FreeBSD.org> | 2020-01-08 19:05:32 +0000 |
---|---|---|
committer | Kyle Evans <kevans@FreeBSD.org> | 2020-01-08 19:05:32 +0000 |
commit | 2856d85ecbe2e402e55913c31d77823f83316a5a (patch) | |
tree | 4fff4fdea8b74e3436b02ce7fbcf31319ed0d65b /sys/kern | |
parent | f57d4d4641a329fad1d373d2d098560da48d53ee (diff) | |
download | src-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')
-rw-r--r-- | sys/kern/sys_generic.c | 41 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 93 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 59 |
3 files changed, 100 insertions, 93 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index cd78cfbfbba2..8e614a0accc6 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -819,6 +819,47 @@ out: } int +sys_posix_fallocate(struct thread *td, struct posix_fallocate_args *uap) +{ + int error; + + error = kern_posix_fallocate(td, uap->fd, uap->offset, uap->len); + return (kern_posix_error(td, error)); +} + +int +kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len) +{ + struct file *fp; + int error; + + AUDIT_ARG_FD(fd); + if (offset < 0 || len <= 0) + return (EINVAL); + /* Check for wrap. */ + if (offset > OFF_MAX - len) + return (EFBIG); + AUDIT_ARG_FD(fd); + error = fget(td, fd, &cap_pwrite_rights, &fp); + if (error != 0) + return (error); + AUDIT_ARG_FILE(td->td_proc, fp); + if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) { + error = ESPIPE; + goto out; + } + if ((fp->f_flag & FWRITE) == 0) { + error = EBADF; + goto out; + } + + error = fo_fallocate(fp, offset, len, td); + out: + fdrop(fp, td); + return (error); +} + +int poll_no_poll(int events) { /* diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index b954e3a6dd45..a3b66f0bcf47 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -4565,99 +4565,6 @@ out: return (error); } -int -kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len) -{ - struct file *fp; - struct mount *mp; - struct vnode *vp; - off_t olen, ooffset; - int error; -#ifdef AUDIT - int audited_vnode1 = 0; -#endif - - AUDIT_ARG_FD(fd); - if (offset < 0 || len <= 0) - return (EINVAL); - /* Check for wrap. */ - if (offset > OFF_MAX - len) - return (EFBIG); - AUDIT_ARG_FD(fd); - error = fget(td, fd, &cap_pwrite_rights, &fp); - if (error != 0) - return (error); - AUDIT_ARG_FILE(td->td_proc, fp); - if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) { - error = ESPIPE; - goto out; - } - if ((fp->f_flag & FWRITE) == 0) { - error = EBADF; - goto out; - } - if (fp->f_type != DTYPE_VNODE) { - error = ENODEV; - goto out; - } - vp = fp->f_vnode; - if (vp->v_type != VREG) { - error = ENODEV; - goto out; - } - - /* 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(); - } - out: - fdrop(fp, td); - return (error); -} - -int -sys_posix_fallocate(struct thread *td, struct posix_fallocate_args *uap) -{ - int error; - - error = kern_posix_fallocate(td, uap->fd, uap->offset, uap->len); - return (kern_posix_error(td, error)); -} - /* * Unlike madvise(2), we do not make a best effort to remember every * possible caching hint. Instead, we remember the last setting with 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); +} |