Skip to content

Commit 9f3afb5

Browse files
committed
xfs: implement deferred bmbt map/unmap operations
Implement deferred versions of the inode block map/unmap functions. These will be used in subsequent patches to make reflink operations atomic. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 4847acf commit 9f3afb5

File tree

9 files changed

+393
-3
lines changed

9 files changed

+393
-3
lines changed

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6062,3 +6062,146 @@ xfs_bmap_split_extent(
60626062
xfs_trans_cancel(tp);
60636063
return error;
60646064
}
6065+
6066+
/* Deferred mapping is only for real extents in the data fork. */
6067+
static bool
6068+
xfs_bmap_is_update_needed(
6069+
struct xfs_bmbt_irec *bmap)
6070+
{
6071+
return bmap->br_startblock != HOLESTARTBLOCK &&
6072+
bmap->br_startblock != DELAYSTARTBLOCK;
6073+
}
6074+
6075+
/* Record a bmap intent. */
6076+
static int
6077+
__xfs_bmap_add(
6078+
struct xfs_mount *mp,
6079+
struct xfs_defer_ops *dfops,
6080+
enum xfs_bmap_intent_type type,
6081+
struct xfs_inode *ip,
6082+
int whichfork,
6083+
struct xfs_bmbt_irec *bmap)
6084+
{
6085+
int error;
6086+
struct xfs_bmap_intent *bi;
6087+
6088+
trace_xfs_bmap_defer(mp,
6089+
XFS_FSB_TO_AGNO(mp, bmap->br_startblock),
6090+
type,
6091+
XFS_FSB_TO_AGBNO(mp, bmap->br_startblock),
6092+
ip->i_ino, whichfork,
6093+
bmap->br_startoff,
6094+
bmap->br_blockcount,
6095+
bmap->br_state);
6096+
6097+
bi = kmem_alloc(sizeof(struct xfs_bmap_intent), KM_SLEEP | KM_NOFS);
6098+
INIT_LIST_HEAD(&bi->bi_list);
6099+
bi->bi_type = type;
6100+
bi->bi_owner = ip;
6101+
bi->bi_whichfork = whichfork;
6102+
bi->bi_bmap = *bmap;
6103+
6104+
error = xfs_defer_join(dfops, bi->bi_owner);
6105+
if (error) {
6106+
kmem_free(bi);
6107+
return error;
6108+
}
6109+
6110+
xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_BMAP, &bi->bi_list);
6111+
return 0;
6112+
}
6113+
6114+
/* Map an extent into a file. */
6115+
int
6116+
xfs_bmap_map_extent(
6117+
struct xfs_mount *mp,
6118+
struct xfs_defer_ops *dfops,
6119+
struct xfs_inode *ip,
6120+
struct xfs_bmbt_irec *PREV)
6121+
{
6122+
if (!xfs_bmap_is_update_needed(PREV))
6123+
return 0;
6124+
6125+
return __xfs_bmap_add(mp, dfops, XFS_BMAP_MAP, ip,
6126+
XFS_DATA_FORK, PREV);
6127+
}
6128+
6129+
/* Unmap an extent out of a file. */
6130+
int
6131+
xfs_bmap_unmap_extent(
6132+
struct xfs_mount *mp,
6133+
struct xfs_defer_ops *dfops,
6134+
struct xfs_inode *ip,
6135+
struct xfs_bmbt_irec *PREV)
6136+
{
6137+
if (!xfs_bmap_is_update_needed(PREV))
6138+
return 0;
6139+
6140+
return __xfs_bmap_add(mp, dfops, XFS_BMAP_UNMAP, ip,
6141+
XFS_DATA_FORK, PREV);
6142+
}
6143+
6144+
/*
6145+
* Process one of the deferred bmap operations. We pass back the
6146+
* btree cursor to maintain our lock on the bmapbt between calls.
6147+
*/
6148+
int
6149+
xfs_bmap_finish_one(
6150+
struct xfs_trans *tp,
6151+
struct xfs_defer_ops *dfops,
6152+
struct xfs_inode *ip,
6153+
enum xfs_bmap_intent_type type,
6154+
int whichfork,
6155+
xfs_fileoff_t startoff,
6156+
xfs_fsblock_t startblock,
6157+
xfs_filblks_t blockcount,
6158+
xfs_exntst_t state)
6159+
{
6160+
struct xfs_bmbt_irec bmap;
6161+
int nimaps = 1;
6162+
xfs_fsblock_t firstfsb;
6163+
int flags = XFS_BMAPI_REMAP;
6164+
int done;
6165+
int error = 0;
6166+
6167+
bmap.br_startblock = startblock;
6168+
bmap.br_startoff = startoff;
6169+
bmap.br_blockcount = blockcount;
6170+
bmap.br_state = state;
6171+
6172+
trace_xfs_bmap_deferred(tp->t_mountp,
6173+
XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type,
6174+
XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
6175+
ip->i_ino, whichfork, startoff, blockcount, state);
6176+
6177+
if (whichfork != XFS_DATA_FORK && whichfork != XFS_ATTR_FORK)
6178+
return -EFSCORRUPTED;
6179+
if (whichfork == XFS_ATTR_FORK)
6180+
flags |= XFS_BMAPI_ATTRFORK;
6181+
6182+
if (XFS_TEST_ERROR(false, tp->t_mountp,
6183+
XFS_ERRTAG_BMAP_FINISH_ONE,
6184+
XFS_RANDOM_BMAP_FINISH_ONE))
6185+
return -EIO;
6186+
6187+
switch (type) {
6188+
case XFS_BMAP_MAP:
6189+
firstfsb = bmap.br_startblock;
6190+
error = xfs_bmapi_write(tp, ip, bmap.br_startoff,
6191+
bmap.br_blockcount, flags, &firstfsb,
6192+
bmap.br_blockcount, &bmap, &nimaps,
6193+
dfops);
6194+
break;
6195+
case XFS_BMAP_UNMAP:
6196+
error = xfs_bunmapi(tp, ip, bmap.br_startoff,
6197+
bmap.br_blockcount, flags, 1, &firstfsb,
6198+
dfops, &done);
6199+
ASSERT(done);
6200+
break;
6201+
default:
6202+
ASSERT(0);
6203+
error = -EFSCORRUPTED;
6204+
}
6205+
6206+
return error;
6207+
}

fs/xfs/libxfs/xfs_bmap.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,13 @@ struct xfs_bmap_intent {
231231
struct xfs_bmbt_irec bi_bmap;
232232
};
233233

234+
int xfs_bmap_finish_one(struct xfs_trans *tp, struct xfs_defer_ops *dfops,
235+
struct xfs_inode *ip, enum xfs_bmap_intent_type type,
236+
int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock,
237+
xfs_filblks_t blockcount, xfs_exntst_t state);
238+
int xfs_bmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
239+
struct xfs_inode *ip, struct xfs_bmbt_irec *imap);
240+
int xfs_bmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
241+
struct xfs_inode *ip, struct xfs_bmbt_irec *imap);
242+
234243
#endif /* __XFS_BMAP_H__ */

fs/xfs/libxfs/xfs_defer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct xfs_defer_pending {
5151
* find all the space it needs.
5252
*/
5353
enum xfs_defer_ops_type {
54+
XFS_DEFER_OPS_TYPE_BMAP,
5455
XFS_DEFER_OPS_TYPE_REFCOUNT,
5556
XFS_DEFER_OPS_TYPE_RMAP,
5657
XFS_DEFER_OPS_TYPE_FREE,

fs/xfs/xfs_bmap_item.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,19 @@ xfs_bui_recover(
389389
struct xfs_bui_log_item *buip)
390390
{
391391
int error = 0;
392+
unsigned int bui_type;
392393
struct xfs_map_extent *bmap;
393394
xfs_fsblock_t startblock_fsb;
394395
xfs_fsblock_t inode_fsb;
395396
bool op_ok;
397+
struct xfs_bud_log_item *budp;
398+
enum xfs_bmap_intent_type type;
399+
int whichfork;
400+
xfs_exntst_t state;
401+
struct xfs_trans *tp;
402+
struct xfs_inode *ip = NULL;
403+
struct xfs_defer_ops dfops;
404+
xfs_fsblock_t firstfsb;
396405

397406
ASSERT(!test_bit(XFS_BUI_RECOVERED, &buip->bui_flags));
398407

@@ -437,7 +446,61 @@ xfs_bui_recover(
437446
return -EIO;
438447
}
439448

449+
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
450+
if (error)
451+
return error;
452+
budp = xfs_trans_get_bud(tp, buip);
453+
454+
/* Grab the inode. */
455+
error = xfs_iget(mp, tp, bmap->me_owner, 0, XFS_ILOCK_EXCL, &ip);
456+
if (error)
457+
goto err_inode;
458+
459+
xfs_defer_init(&dfops, &firstfsb);
460+
461+
/* Process deferred bmap item. */
462+
state = (bmap->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ?
463+
XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
464+
whichfork = (bmap->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ?
465+
XFS_ATTR_FORK : XFS_DATA_FORK;
466+
bui_type = bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK;
467+
switch (bui_type) {
468+
case XFS_BMAP_MAP:
469+
case XFS_BMAP_UNMAP:
470+
type = bui_type;
471+
break;
472+
default:
473+
error = -EFSCORRUPTED;
474+
goto err_dfops;
475+
}
476+
xfs_trans_ijoin(tp, ip, 0);
477+
478+
error = xfs_trans_log_finish_bmap_update(tp, budp, &dfops, type,
479+
ip, whichfork, bmap->me_startoff,
480+
bmap->me_startblock, bmap->me_len,
481+
state);
482+
if (error)
483+
goto err_dfops;
484+
485+
/* Finish transaction, free inodes. */
486+
error = xfs_defer_finish(&tp, &dfops, NULL);
487+
if (error)
488+
goto err_dfops;
489+
440490
set_bit(XFS_BUI_RECOVERED, &buip->bui_flags);
441-
xfs_bui_release(buip);
491+
error = xfs_trans_commit(tp);
492+
xfs_iunlock(ip, XFS_ILOCK_EXCL);
493+
IRELE(ip);
494+
495+
return error;
496+
497+
err_dfops:
498+
xfs_defer_cancel(&dfops);
499+
err_inode:
500+
xfs_trans_cancel(tp);
501+
if (ip) {
502+
xfs_iunlock(ip, XFS_ILOCK_EXCL);
503+
IRELE(ip);
504+
}
442505
return error;
443506
}

fs/xfs/xfs_error.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
9494
#define XFS_ERRTAG_RMAP_FINISH_ONE 23
9595
#define XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE 24
9696
#define XFS_ERRTAG_REFCOUNT_FINISH_ONE 25
97-
#define XFS_ERRTAG_MAX 26
97+
#define XFS_ERRTAG_BMAP_FINISH_ONE 26
98+
#define XFS_ERRTAG_MAX 27
9899

99100
/*
100101
* Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -125,6 +126,7 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
125126
#define XFS_RANDOM_RMAP_FINISH_ONE 1
126127
#define XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE 1
127128
#define XFS_RANDOM_REFCOUNT_FINISH_ONE 1
129+
#define XFS_RANDOM_BMAP_FINISH_ONE 1
128130

129131
#ifdef DEBUG
130132
extern int xfs_error_test_active;

fs/xfs/xfs_super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,7 @@ init_xfs_fs(void)
19221922
xfs_extent_free_init_defer_op();
19231923
xfs_rmap_update_init_defer_op();
19241924
xfs_refcount_update_init_defer_op();
1925+
xfs_bmap_update_init_defer_op();
19251926

19261927
xfs_dir_startup();
19271928

fs/xfs/xfs_trace.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,6 +2587,11 @@ DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result);
25872587
DEFINE_RMAPBT_EVENT(xfs_rmap_find_right_neighbor_result);
25882588
DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_result);
25892589

2590+
/* deferred bmbt updates */
2591+
#define DEFINE_BMAP_DEFERRED_EVENT DEFINE_RMAP_DEFERRED_EVENT
2592+
DEFINE_BMAP_DEFERRED_EVENT(xfs_bmap_defer);
2593+
DEFINE_BMAP_DEFERRED_EVENT(xfs_bmap_deferred);
2594+
25902595
/* per-AG reservation */
25912596
DECLARE_EVENT_CLASS(xfs_ag_resv_class,
25922597
TP_PROTO(struct xfs_perag *pag, enum xfs_ag_resv_type resv,

fs/xfs/xfs_trans.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct xfs_cui_log_item;
4040
struct xfs_cud_log_item;
4141
struct xfs_defer_ops;
4242
struct xfs_bui_log_item;
43+
struct xfs_bud_log_item;
4344

4445
typedef struct xfs_log_item {
4546
struct list_head li_ail; /* AIL pointers */

0 commit comments

Comments
 (0)