Skip to content

Commit 3015196

Browse files
chandanrDarrick J. Wong
authored andcommitted
xfs: Introduce error injection to allocate only minlen size extents for files
This commit adds XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT error tag which helps userspace test programs to get xfs_bmap_btalloc() to always allocate minlen sized extents. This is required for test programs which need a guarantee that minlen extents allocated for a file do not get merged with their existing neighbours in the inode's BMBT. "Inode fork extent overflow check" for Directories, Xattrs and extension of realtime inodes need this since the file offset at which the extents are being allocated cannot be explicitly controlled from userspace. One way to use this error tag is to, 1. Consume all of the free space by sequentially writing to a file. 2. Punch alternate blocks of the file. This causes CNTBT to contain sufficient number of one block sized extent records. 3. Inject XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT error tag. After step 3, xfs_bmap_btalloc() will issue space allocation requests for minlen sized extents only. ENOSPC error code is returned to userspace when there aren't any "one block sized" extents left in any of the AGs. Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Chandan Babu R <[email protected]> Signed-off-by: Darrick J. Wong <[email protected]>
1 parent 07c72e5 commit 3015196

File tree

5 files changed

+159
-25
lines changed

5 files changed

+159
-25
lines changed

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2474,6 +2474,47 @@ xfs_defer_agfl_block(
24742474
xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_AGFL_FREE, &new->xefi_list);
24752475
}
24762476

2477+
#ifdef DEBUG
2478+
/*
2479+
* Check if an AGF has a free extent record whose length is equal to
2480+
* args->minlen.
2481+
*/
2482+
STATIC int
2483+
xfs_exact_minlen_extent_available(
2484+
struct xfs_alloc_arg *args,
2485+
struct xfs_buf *agbp,
2486+
int *stat)
2487+
{
2488+
struct xfs_btree_cur *cnt_cur;
2489+
xfs_agblock_t fbno;
2490+
xfs_extlen_t flen;
2491+
int error = 0;
2492+
2493+
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
2494+
args->agno, XFS_BTNUM_CNT);
2495+
error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
2496+
if (error)
2497+
goto out;
2498+
2499+
if (*stat == 0) {
2500+
error = -EFSCORRUPTED;
2501+
goto out;
2502+
}
2503+
2504+
error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, stat);
2505+
if (error)
2506+
goto out;
2507+
2508+
if (*stat == 1 && flen != args->minlen)
2509+
*stat = 0;
2510+
2511+
out:
2512+
xfs_btree_del_cursor(cnt_cur, error);
2513+
2514+
return error;
2515+
}
2516+
#endif
2517+
24772518
/*
24782519
* Decide whether to use this allocation group for this allocation.
24792520
* If so, fix up the btree freelist's size.
@@ -2545,6 +2586,15 @@ xfs_alloc_fix_freelist(
25452586
if (!xfs_alloc_space_available(args, need, flags))
25462587
goto out_agbp_relse;
25472588

2589+
#ifdef DEBUG
2590+
if (args->alloc_minlen_only) {
2591+
int stat;
2592+
2593+
error = xfs_exact_minlen_extent_available(args, agbp, &stat);
2594+
if (error || !stat)
2595+
goto out_agbp_relse;
2596+
}
2597+
#endif
25482598
/*
25492599
* Make the freelist shorter if it's too long.
25502600
*

fs/xfs/libxfs/xfs_alloc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ typedef struct xfs_alloc_arg {
7575
char wasfromfl; /* set if allocation is from freelist */
7676
struct xfs_owner_info oinfo; /* owner of blocks being allocated */
7777
enum xfs_ag_resv_type resv; /* block reservation to use */
78+
#ifdef DEBUG
79+
bool alloc_minlen_only; /* allocate exact minlen extent */
80+
#endif
7881
} xfs_alloc_arg_t;
7982

8083
/*

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 100 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,34 +3552,101 @@ xfs_bmap_process_allocated_extent(
35523552
xfs_bmap_btalloc_accounting(ap, args);
35533553
}
35543554

3555-
STATIC int
3556-
xfs_bmap_btalloc(
3557-
struct xfs_bmalloca *ap) /* bmap alloc argument struct */
3555+
#ifdef DEBUG
3556+
static int
3557+
xfs_bmap_exact_minlen_extent_alloc(
3558+
struct xfs_bmalloca *ap)
35583559
{
3559-
xfs_mount_t *mp; /* mount point structure */
3560-
xfs_alloctype_t atype = 0; /* type for allocation routines */
3561-
xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */
3562-
xfs_agnumber_t ag;
3563-
xfs_alloc_arg_t args;
3564-
xfs_fileoff_t orig_offset;
3565-
xfs_extlen_t orig_length;
3566-
xfs_extlen_t blen;
3567-
xfs_extlen_t nextminlen = 0;
3568-
int nullfb; /* true if ap->firstblock isn't set */
3569-
int isaligned;
3570-
int tryagain;
3571-
int error;
3572-
int stripe_align;
3560+
struct xfs_mount *mp = ap->ip->i_mount;
3561+
struct xfs_alloc_arg args = { .tp = ap->tp, .mp = mp };
3562+
xfs_fileoff_t orig_offset;
3563+
xfs_extlen_t orig_length;
3564+
int error;
35733565

35743566
ASSERT(ap->length);
3567+
3568+
if (ap->minlen != 1) {
3569+
ap->blkno = NULLFSBLOCK;
3570+
ap->length = 0;
3571+
return 0;
3572+
}
3573+
35753574
orig_offset = ap->offset;
35763575
orig_length = ap->length;
35773576

3578-
mp = ap->ip->i_mount;
3577+
args.alloc_minlen_only = 1;
35793578

3580-
memset(&args, 0, sizeof(args));
3581-
args.tp = ap->tp;
3582-
args.mp = mp;
3579+
xfs_bmap_compute_alignments(ap, &args);
3580+
3581+
if (ap->tp->t_firstblock == NULLFSBLOCK) {
3582+
/*
3583+
* Unlike the longest extent available in an AG, we don't track
3584+
* the length of an AG's shortest extent.
3585+
* XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT is a debug only knob and
3586+
* hence we can afford to start traversing from the 0th AG since
3587+
* we need not be concerned about a drop in performance in
3588+
* "debug only" code paths.
3589+
*/
3590+
ap->blkno = XFS_AGB_TO_FSB(mp, 0, 0);
3591+
} else {
3592+
ap->blkno = ap->tp->t_firstblock;
3593+
}
3594+
3595+
args.fsbno = ap->blkno;
3596+
args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
3597+
args.type = XFS_ALLOCTYPE_FIRST_AG;
3598+
args.total = args.minlen = args.maxlen = ap->minlen;
3599+
3600+
args.alignment = 1;
3601+
args.minalignslop = 0;
3602+
3603+
args.minleft = ap->minleft;
3604+
args.wasdel = ap->wasdel;
3605+
args.resv = XFS_AG_RESV_NONE;
3606+
args.datatype = ap->datatype;
3607+
3608+
error = xfs_alloc_vextent(&args);
3609+
if (error)
3610+
return error;
3611+
3612+
if (args.fsbno != NULLFSBLOCK) {
3613+
xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
3614+
orig_length);
3615+
} else {
3616+
ap->blkno = NULLFSBLOCK;
3617+
ap->length = 0;
3618+
}
3619+
3620+
return 0;
3621+
}
3622+
#else
3623+
3624+
#define xfs_bmap_exact_minlen_extent_alloc(bma) (-EFSCORRUPTED)
3625+
3626+
#endif
3627+
3628+
STATIC int
3629+
xfs_bmap_btalloc(
3630+
struct xfs_bmalloca *ap)
3631+
{
3632+
struct xfs_mount *mp = ap->ip->i_mount;
3633+
struct xfs_alloc_arg args = { .tp = ap->tp, .mp = mp };
3634+
xfs_alloctype_t atype = 0;
3635+
xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */
3636+
xfs_agnumber_t ag;
3637+
xfs_fileoff_t orig_offset;
3638+
xfs_extlen_t orig_length;
3639+
xfs_extlen_t blen;
3640+
xfs_extlen_t nextminlen = 0;
3641+
int nullfb; /* true if ap->firstblock isn't set */
3642+
int isaligned;
3643+
int tryagain;
3644+
int error;
3645+
int stripe_align;
3646+
3647+
ASSERT(ap->length);
3648+
orig_offset = ap->offset;
3649+
orig_length = ap->length;
35833650

35843651
stripe_align = xfs_bmap_compute_alignments(ap, &args);
35853652

@@ -4113,6 +4180,10 @@ xfs_bmap_alloc_userdata(
41134180
return xfs_bmap_rtalloc(bma);
41144181
}
41154182

4183+
if (unlikely(XFS_TEST_ERROR(false, mp,
4184+
XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
4185+
return xfs_bmap_exact_minlen_extent_alloc(bma);
4186+
41164187
return xfs_bmap_btalloc(bma);
41174188
}
41184189

@@ -4149,10 +4220,15 @@ xfs_bmapi_allocate(
41494220
else
41504221
bma->minlen = 1;
41514222

4152-
if (bma->flags & XFS_BMAPI_METADATA)
4153-
error = xfs_bmap_btalloc(bma);
4154-
else
4223+
if (bma->flags & XFS_BMAPI_METADATA) {
4224+
if (unlikely(XFS_TEST_ERROR(false, mp,
4225+
XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
4226+
error = xfs_bmap_exact_minlen_extent_alloc(bma);
4227+
else
4228+
error = xfs_bmap_btalloc(bma);
4229+
} else {
41554230
error = xfs_bmap_alloc_userdata(bma);
4231+
}
41564232
if (error || bma->blkno == NULLFSBLOCK)
41574233
return error;
41584234

fs/xfs/libxfs/xfs_errortag.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
#define XFS_ERRTAG_IUNLINK_FALLBACK 34
5858
#define XFS_ERRTAG_BUF_IOERROR 35
5959
#define XFS_ERRTAG_REDUCE_MAX_IEXTENTS 36
60-
#define XFS_ERRTAG_MAX 37
60+
#define XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT 37
61+
#define XFS_ERRTAG_MAX 38
6162

6263
/*
6364
* Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -99,5 +100,6 @@
99100
#define XFS_RANDOM_IUNLINK_FALLBACK (XFS_RANDOM_DEFAULT/10)
100101
#define XFS_RANDOM_BUF_IOERROR XFS_RANDOM_DEFAULT
101102
#define XFS_RANDOM_REDUCE_MAX_IEXTENTS 1
103+
#define XFS_RANDOM_BMAP_ALLOC_MINLEN_EXTENT 1
102104

103105
#endif /* __XFS_ERRORTAG_H_ */

fs/xfs/xfs_error.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static unsigned int xfs_errortag_random_default[] = {
5555
XFS_RANDOM_IUNLINK_FALLBACK,
5656
XFS_RANDOM_BUF_IOERROR,
5757
XFS_RANDOM_REDUCE_MAX_IEXTENTS,
58+
XFS_RANDOM_BMAP_ALLOC_MINLEN_EXTENT,
5859
};
5960

6061
struct xfs_errortag_attr {
@@ -166,6 +167,7 @@ XFS_ERRORTAG_ATTR_RW(bad_summary, XFS_ERRTAG_FORCE_SUMMARY_RECALC);
166167
XFS_ERRORTAG_ATTR_RW(iunlink_fallback, XFS_ERRTAG_IUNLINK_FALLBACK);
167168
XFS_ERRORTAG_ATTR_RW(buf_ioerror, XFS_ERRTAG_BUF_IOERROR);
168169
XFS_ERRORTAG_ATTR_RW(reduce_max_iextents, XFS_ERRTAG_REDUCE_MAX_IEXTENTS);
170+
XFS_ERRORTAG_ATTR_RW(bmap_alloc_minlen_extent, XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT);
169171

170172
static struct attribute *xfs_errortag_attrs[] = {
171173
XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -205,6 +207,7 @@ static struct attribute *xfs_errortag_attrs[] = {
205207
XFS_ERRORTAG_ATTR_LIST(iunlink_fallback),
206208
XFS_ERRORTAG_ATTR_LIST(buf_ioerror),
207209
XFS_ERRORTAG_ATTR_LIST(reduce_max_iextents),
210+
XFS_ERRORTAG_ATTR_LIST(bmap_alloc_minlen_extent),
208211
NULL,
209212
};
210213

0 commit comments

Comments
 (0)