On Fri, May 20, 2022 at 05:25:59PM +0000, Mateusz Guzik wrote:
> The branch main has been updated by mjg:
>
> URL:
> https://cgit.FreeBSD.org/src/commit/?id=ec3c225711ae7d5b8e71ed036aada09ef91149ec
>
> commit ec3c225711ae7d5b8e71ed036aada09ef91149ec
> Author: Mateusz Guzik <[email protected]>
> AuthorDate: 2022-05-16 01:28:22 +0000
> Commit: Mateusz Guzik <[email protected]>
> CommitDate: 2022-05-20 17:25:51 +0000
>
> vfs: call vn_truncate_locked from kern_truncate
>
> This fixes a bug where the syscall would not bump writecount.
>
> PR: 263999
> ---
> sys/kern/vfs_syscalls.c | 22 ++++++++++++----------
> 1 file changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
> index 86ef3fc7a095..600299fbe6eb 100644
> --- a/sys/kern/vfs_syscalls.c
> +++ b/sys/kern/vfs_syscalls.c
> @@ -3460,7 +3460,6 @@ kern_truncate(struct thread *td, const char *path, enum
> uio_seg pathseg,
> struct mount *mp;
> struct vnode *vp;
> void *rl_cookie;
> - struct vattr vattr;
> struct nameidata nd;
> int error;
>
> @@ -3480,18 +3479,21 @@ retry:
> return (error);
> }
> vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
> - if (vp->v_type == VDIR)
> + if (vp->v_type == VDIR) {
> error = EISDIR;
> -#ifdef MAC
> - else if ((error = mac_vnode_check_write(td->td_ucred, NOCRED, vp))) {
> + goto out;
> }
> +#ifdef MAC
> + error = mac_vnode_check_write(td->td_ucred, NOCRED, vp);
> + if (error != 0)
> + goto out;
> #endif
> - else if ((error = vn_writechk(vp)) == 0 &&
> - (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
> - VATTR_NULL(&vattr);
> - vattr.va_size = length;
> - error = VOP_SETATTR(vp, &vattr, td->td_ucred);
> - }
> + error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td);
> + if (error != 0)
> + goto out;
> +
> + error = vn_truncate_locked(vp, 0, false, td->td_ucred);
> +out:
> VOP_UNLOCK(vp);
> vn_finished_write(mp);
> vn_rangelock_unlock(vp, rl_cookie);
seems this broke truncate, test attached.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static char *temp_filename;
static int temp_fd;
#define FAIL(str) \
do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0)
int
main(void)
{
struct stat st;
char buf[1000];
off_t offset=0;
asprintf(&temp_filename, "/%s/%sXXXXXX", "tmp", "trunc");
temp_fd = mkstemp(temp_filename);
memset (buf, 0xcf, sizeof (buf));
if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf))
FAIL ("write failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf)))
FAIL ("initial size wrong");
if (ftruncate (temp_fd, offset + 800) < 0)
FAIL ("size reduction with ftruncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
FAIL ("size after reduction with ftruncate is incorrect");
/* The following test covers more than POSIX. POSIX does not require
that ftruncate() can increase the file size. But we are testing
Unix systems. */
if (ftruncate (temp_fd, offset + 1200) < 0)
FAIL ("size increate with ftruncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
FAIL ("size after increase is incorrect");
if (truncate (temp_filename, offset + 800) < 0)
FAIL ("size reduction with truncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
FAIL ("size after reduction with truncate incorrect");
/* The following test covers more than POSIX. POSIX does not require
that truncate() can increase the file size. But we are testing
Unix systems. */
if (truncate (temp_filename, (offset + 1200)) < 0)
FAIL ("size increase with truncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
FAIL ("size increase with truncate is incorrect");
return 0;
}