diff options
author | mdf <mdf@FreeBSD.org> | 2011-04-18 16:32:22 +0000 |
---|---|---|
committer | mdf <mdf@FreeBSD.org> | 2011-04-18 16:32:22 +0000 |
commit | 9c9a32d97b41ab9d0cae56c7e428ad6d5cd1302f (patch) | |
tree | 99ab3d40a9311d51c78c3b3e6b880d6ba7d2560c /sys/kern/vfs_syscalls.c | |
parent | 0bbb5b8e1ab919b4d265f1857ccd42679a2cb39c (diff) | |
download | FreeBSD-src-9c9a32d97b41ab9d0cae56c7e428ad6d5cd1302f.zip FreeBSD-src-9c9a32d97b41ab9d0cae56c7e428ad6d5cd1302f.tar.gz |
Add the posix_fallocate(2) syscall. The default implementation in
vop_stdallocate() is filesystem agnostic and will run as slow as a
read/write loop in userspace; however, it serves to correctly
implement the functionality for filesystems that do not implement a
VOP_ALLOCATE.
Note that __FreeBSD_version was already bumped today to 900036 for any
ports which would like to use this function.
Also reserve space in the syscall table for posix_fadvise(2).
Reviewed by: -arch (previous version)
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r-- | sys/kern/vfs_syscalls.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 4fc198e..26a21e3 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -4671,3 +4671,83 @@ out: VFS_UNLOCK_GIANT(vfslocked); return (error); } + +static int +kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len) +{ + struct file *fp; + struct mount *mp; + struct vnode *vp; + int error, vfslocked, vnlocked; + + fp = NULL; + mp = NULL; + vfslocked = 0; + vnlocked = 0; + error = fget(td, fd, &fp); + if (error != 0) + goto out; + + switch (fp->f_type) { + case DTYPE_VNODE: + break; + case DTYPE_PIPE: + case DTYPE_FIFO: + error = ESPIPE; + goto out; + default: + error = ENODEV; + goto out; + } + if ((fp->f_flag & FWRITE) == 0) { + error = EBADF; + goto out; + } + vp = fp->f_vnode; + if (vp->v_type != VREG) { + error = ENODEV; + goto out; + } + if (offset < 0 || len <= 0) { + error = EINVAL; + goto out; + } + /* Check for wrap. */ + if (offset > OFF_MAX - len) { + error = EFBIG; + goto out; + } + + bwillwrite(); + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + error = vn_start_write(vp, &mp, V_WAIT | PCATCH); + if (error != 0) + goto out; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) + goto out; + vnlocked = 1; +#ifdef MAC + error = mac_vnode_check_write(td->td_ucred, fp->f_cred, vp); + if (error != 0) + goto out; +#endif + error = VOP_ALLOCATE(vp, offset, len); + if (error != 0) + vnlocked = 0; + out: + if (vnlocked) + VOP_UNLOCK(vp, 0); + vn_finished_write(mp); + VFS_UNLOCK_GIANT(vfslocked); + if (fp != NULL) + fdrop(fp, td); + return (error); +} + +int +posix_fallocate(struct thread *td, struct posix_fallocate_args *uap) +{ + + return (kern_posix_fallocate(td, uap->fd, uap->offset, uap->len)); +} |