Re: git: 40a42785dbba - main - fcntl(F_SETFL): only allow one thread to perform F_SETFL
- Reply: John Baldwin : "Re: git: 40a42785dbba - main - fcntl(F_SETFL): only allow one thread to perform F_SETFL"
- Reply: Mateusz Guzik : "Re: git: 40a42785dbba - main - fcntl(F_SETFL): only allow one thread to perform F_SETFL"
- In reply to: Konstantin Belousov : "git: 40a42785dbba - main - fcntl(F_SETFL): only allow one thread to perform F_SETFL"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 22 Sep 2025 08:41:18 UTC
On 9/19/25 10:19, Konstantin Belousov wrote: > The branch main has been updated by kib: > > URL: https://cgit.FreeBSD.org/src/commit/?id=40a42785dbba93cc5196178fc49d340c1a89cabe > > commit 40a42785dbba93cc5196178fc49d340c1a89cabe > Author: Konstantin Belousov <kib@FreeBSD.org> > AuthorDate: 2025-09-11 10:05:04 +0000 > Commit: Konstantin Belousov <kib@FreeBSD.org> > CommitDate: 2025-09-19 14:19:13 +0000 > > fcntl(F_SETFL): only allow one thread to perform F_SETFL > > Use f_vflags file locking for this. > Allowing more than one thread handling F_SETFL might cause de-sync > between real driver state and flags. > > Reviewed by: markj > Tested by: pho > Sponsored by: The FreeBSD Foundation > MFC after: 2 weeks > Differential revision: https://reviews.freebsd.org/D52487 Thanks for fixing this. I still slightly worry that "home-grown" locks aren't visible to WITNESS and it's checking. I was also expecting this to require more changes, but apparently if a process directly invokes FIONBIO on a file descriptor, f_flags isn't updated currently. I wonder if that is a bug. (Similarly for FIOASYNC.) Oh, we do handle that, but poorly. We don't revert on errors, and this should be updated to use fsetfl_lock now I think: kern_ioctl(...) { ... switch (com) { ... case FIONBIO: if ((tmp = *(int *)data)) atomic_set_int(&fp->f_flag, FNONBLOCK); else atomic_clear_int(&fp->f_flag, FNONBLOCK); data = (void *)&tmp; break; case FIOASYNC: if ((tmp = *(int *)data)) atomic_set_int(&fp->f_flag, FASYNC); else atomic_clear_int(&fp->f_flag, FASYNC); data = (void *)&tmp; break; } error = fo_ioctl(fp, com, data, td->td_ucred, td); out: I think instead we want something like: int f_flag; switch (com) { ... case FIONBIO: case FIOASYNC: fsetfl_lock(fp); tmp = *(int *)data; f_flag = com == FIONBIO ? FNONBLOCK : FASYNC; if ((fp->f_flag & f_flag) != 0) { fsetfl_unlock(fp); goto out; } data = (void *)&tmp; break; } error = fo_ioctl(fp, com, data, td->td_ucred, td); switch (com) { ... case FIONBIO: case FIOASYNC: if (error == 0) { if (tmp) atomic_set_int(&fp->f_flag, f_flag); else atomic_clear_int(&fp->f_flag, f_flag); } fsetfl_unlock(fp); break; } out: This only updates the flag if the underlying ioctl succeeds, and it also avoids invoking the underlying ioctl if the flag is already in the correct\ state. -- John Baldwin