ffs_truncate3 panics
Rick Macklem
rmacklem at uoguelph.ca
Sun Aug 12 12:26:00 UTC 2018
Konstantin Belousov wrote:
[stuff snipped]
>Problem with this buffer is that BX_ALTDATA bit is not set.
>This is the reason why vinvalbuf(V_ALT) skips it.
[more stuff snipped]
>The vnode is exclusively locked. Other thread must not be able to
>instantiate a buffer under us.
That's what I thought, but I wasn't sure that UFS never did anything to the buffers
without the vnode lock.
[more stuff snipped]
>This is the patch that I posted long time ago. It is obviously related
>to missed BX_ALTDATA. Can you add this patch to your kernel ?
>
>diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c
>index 552c295753d..6d89a229ea7 100644
>--- a/sys/ufs/ffs/ffs_balloc.c
>+++ b/sys/ufs/ffs/ffs_balloc.c
>@@ -682,8 +682,16 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
> ffs_blkpref_ufs2(ip, lbn, (int)lbn,
> &dp->di_extb[0]), osize, nsize, flags,
> cred, &bp);
>- if (error)
>+ if (error != 0) {
>+ /* getblk does truncation, if needed */
>+ bp = getblk(vp, -1 - lbn, osize, 0, 0,
>+ GB_NOCREAT);
>+ if (bp != NULL) {
>+ bp->b_xflags |= BX_ALTDATA;
>+ brelse(bp);
>+ }
> return (error);
>+ }
> bp->b_xflags |= BX_ALTDATA;
> if (DOINGSOFTDEP(vp))
> softdep_setup_allocext(ip, lbn,
>@@ -699,8 +707,17 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
> error = ffs_alloc(ip, lbn,
> ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]),
> nsize, flags, cred, &newb);
>- if (error)
>+ if (error != 0) {
>+ bp = getblk(vp, -1 - lbn, nsize, 0, 0,
>+ GB_NOCREAT);
>+ if (bp != NULL) {
>+ bp->b_xflags |= BX_ALTDATA;
>+ bp->b_flags |= B_RELBUF | B_INVAL;
>+ bp->b_flags &= ~B_ASYNC;
>+ brelse(bp);
>+ }
> return (error);
>+ }
> bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags);
> bp->b_blkno = fsbtodb(fs, newb);
> bp->b_xflags |= BX_ALTDATA;
I don't think this patch helped. I still get printf()s with b_xflags == clear with it
applied. I haven't gotten one that would cause the panic yet, but it didn't
make the BX_ALTDATA flag get set.
However, I have narrowed down how the ones that cause a panic() occur.
Turns out I was wrong when I said di_size == 0 for all these files.
They don't store any data, but if an application does a truncate(2) with length > 0,
the di_size does get set non-zero.
It is when one of these files hits the ffs_truncate() with the extended attribute
buffer on it, that the panic() happens.
(Most of them have di_size == 0 and return from the function in the code block
that starts with "if (ip->I_size == length)" at around line#299, before the panic()
check.)
rick
More information about the freebsd-current
mailing list