On 4/23/20 2:34 PM, Eric Sandeen wrote: > This scenario is the source of much confusion for admins and > support folks alike: > > # touch mnt/newfile > touch: cannot touch ‘mnt/newfile’: No space left on device > # df -h mnt > Filesystem Size Used Avail Use% Mounted on > /dev/loop0 196M 137M 59M 71% /tmp/mnt > # df -i mnt/ > Filesystem Inodes IUsed IFree IUse% Mounted on > /dev/loop0 102400 64256 38144 63% /tmp/mnt > > because it appears that there is plenty of space available, yet ENOSPC > is returned. > > Track this case in the allocation args structure, and when an allocation > fails due to alignment constraints, leave a clue in the kernel logs: > > XFS (loop0): Failed metadata allocation due to 4-block alignment constraint Welp, I always realize what's wrong with the patch right after I send it; I think this reports the failure on each AG that fails, even if a later AG succeeds so I need to get the result up to a higher level. Still, can see what people think of the idea in general? Thanks, -Eric > Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> > --- > > Right now this depends on my "printk_once" patch but you can change > xfs_warn_once to xfs_warn or xfs_warn_ratelimited for testing. > > Perhaps a 2nd patch to log a similar message if alignment failed due to > /contiguous/ free space constraints would be good as well? > > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c > index 203e74fa64aa..10f32797e5ca 100644 > --- a/fs/xfs/libxfs/xfs_alloc.c > +++ b/fs/xfs/libxfs/xfs_alloc.c > @@ -2303,8 +2303,12 @@ xfs_alloc_space_available( > /* do we have enough contiguous free space for the allocation? */ > alloc_len = args->minlen + (args->alignment - 1) + args->minalignslop; > longest = xfs_alloc_longest_free_extent(pag, min_free, reservation); > - if (longest < alloc_len) > + if (longest < alloc_len) { > + /* Did we fail only due to alignment? */ > + if (longest >= args->minlen) > + args->alignfail = 1; > return false; > + } > > /* > * Do we have enough free space remaining for the allocation? Don't > @@ -3067,8 +3071,10 @@ xfs_alloc_vextent( > agsize = mp->m_sb.sb_agblocks; > if (args->maxlen > agsize) > args->maxlen = agsize; > - if (args->alignment == 0) > + if (args->alignment == 0) { > args->alignment = 1; > + args->alignfail = 0; > + } > ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); > ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); > ASSERT(args->minlen <= args->maxlen); > @@ -3227,6 +3233,13 @@ xfs_alloc_vextent( > > } > xfs_perag_put(args->pag); > + if (!args->agbp && args->alignment > 1 && args->alignfail) { > + xfs_warn_once(args->mp, > +"Failed %s allocation due to %u-block alignment constraint", > + XFS_RMAP_NON_INODE_OWNER(args->oinfo.oi_owner) ? > + "metadata" : "data", > + args->alignment); > + } > return 0; > error0: > xfs_perag_put(args->pag); > diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h > index a851bf77f17b..29d13cd5c9ac 100644 > --- a/fs/xfs/libxfs/xfs_alloc.h > +++ b/fs/xfs/libxfs/xfs_alloc.h > @@ -73,6 +73,7 @@ typedef struct xfs_alloc_arg { > int datatype; /* mask defining data type treatment */ > char wasdel; /* set if allocation was prev delayed */ > char wasfromfl; /* set if allocation is from freelist */ > + char alignfail; /* set if alloc failed due to alignmt */ > struct xfs_owner_info oinfo; /* owner of blocks being allocated */ > enum xfs_ag_resv_type resv; /* block reservation to use */ > } xfs_alloc_arg_t; > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > index fda13cd7add0..808060649cad 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -3563,6 +3563,7 @@ xfs_bmap_btalloc( > args.mp = mp; > args.fsbno = ap->blkno; > args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE; > + args.alignfail = 0; > > /* Trim the allocation back to the maximum an AG can fit. */ > args.maxlen = min(ap->length, mp->m_ag_max_usable); > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c > index 7fcf62b324b0..e98dcb8e65eb 100644 > --- a/fs/xfs/libxfs/xfs_ialloc.c > +++ b/fs/xfs/libxfs/xfs_ialloc.c > @@ -685,6 +685,7 @@ xfs_ialloc_ag_alloc( > * but not to use them in the actual exact allocation. > */ > args.alignment = 1; > + args.alignfail = 0; > args.minalignslop = igeo->cluster_align - 1; > > /* Allow space for the inode btree to split. */ >