Index: lib/libc/sys/posix_fallocate.2 =================================================================== --- lib/libc/sys/posix_fallocate.2 +++ lib/libc/sys/posix_fallocate.2 @@ -28,7 +28,7 @@ .\" @(#)open.2 8.2 (Berkeley) 11/16/93 .\" $FreeBSD$ .\" -.Dd November 4, 2017 +.Dd January 5, 2020 .Dt POSIX_FALLOCATE 2 .Os .Sh NAME @@ -115,7 +115,8 @@ .It Bq Er ENODEV The .Fa fd -argument does not refer to a regular file. +argument does not refer to a file that supports +.Nm . .It Bq Er ENOSPC There is insufficient free space remaining on the file system storage media. Index: sys/kern/uipc_shm.c =================================================================== --- sys/kern/uipc_shm.c +++ sys/kern/uipc_shm.c @@ -138,6 +138,7 @@ static fo_mmap_t shm_mmap; static fo_get_seals_t shm_get_seals; static fo_add_seals_t shm_add_seals; +static fo_fallocate_t shm_fallocate; /* File descriptor operations. */ struct fileops shm_ops = { @@ -157,6 +158,7 @@ .fo_mmap = shm_mmap, .fo_get_seals = shm_get_seals, .fo_add_seals = shm_add_seals, + .fo_fallocate = shm_fallocate, .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; @@ -1437,6 +1439,25 @@ return (0); } +static int +shm_fallocate(struct file *fp, off_t offset, off_t len, struct thread *td) +{ + struct shmfd *shmfd; + size_t size; + int error; + + /* This assumes that the caller already checked for overflow. */ + error = 0; + shmfd = fp->f_data; + size = offset + len; + if (size > shmfd->shm_size) + error = shm_dotruncate(shmfd, size); + /* Translate to posix_fallocate(2) return value as needed. */ + if (error == ENOMEM) + error = ENOSPC; + return (error); +} + static int sysctl_posix_shm_list(SYSCTL_HANDLER_ARGS) { Index: sys/kern/vfs_syscalls.c =================================================================== --- sys/kern/vfs_syscalls.c +++ sys/kern/vfs_syscalls.c @@ -4569,13 +4569,7 @@ 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) @@ -4596,54 +4590,8 @@ 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(); - } + error = fo_fallocate(fp, offset, len, td); out: fdrop(fp, td); return (error); Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -103,6 +103,7 @@ 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 @@ .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 @@ 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); +} Index: sys/sys/file.h =================================================================== --- sys/sys/file.h +++ sys/sys/file.h @@ -125,6 +125,8 @@ typedef int fo_aio_queue_t(struct file *fp, struct kaiocb *job); typedef int fo_add_seals_t(struct file *fp, int flags); typedef int fo_get_seals_t(struct file *fp, int *flags); +typedef int fo_fallocate_t(struct file *fp, off_t offset, off_t len, + struct thread *td); typedef int fo_flags_t; struct fileops { @@ -145,6 +147,7 @@ fo_aio_queue_t *fo_aio_queue; fo_add_seals_t *fo_add_seals; fo_get_seals_t *fo_get_seals; + fo_fallocate_t *fo_fallocate; fo_flags_t fo_flags; /* DFLAG_* below */ }; @@ -446,6 +449,15 @@ return ((*fp->f_ops->fo_get_seals)(fp, seals)); } +static __inline int +fo_fallocate(struct file *fp, off_t offset, off_t len, struct thread *td) +{ + + if (fp->f_ops->fo_fallocate == NULL) + return (ENODEV); + return ((*fp->f_ops->fo_fallocate)(fp, offset, len, td)); +} + #endif /* _KERNEL */ #endif /* !SYS_FILE_H */