Commit f477cedc authored by Dave Chinner's avatar Dave Chinner

Merge branch 'xfs-4.8-misc-fixes-2' into for-next

parents 9b7fad20 19b54ee6
...@@ -1839,19 +1839,8 @@ void ...@@ -1839,19 +1839,8 @@ void
xfs_alloc_compute_maxlevels( xfs_alloc_compute_maxlevels(
xfs_mount_t *mp) /* file system mount structure */ xfs_mount_t *mp) /* file system mount structure */
{ {
int level; mp->m_ag_maxlevels = xfs_btree_compute_maxlevels(mp, mp->m_alloc_mnr,
uint maxblocks; (mp->m_sb.sb_agblocks + 1) / 2);
uint maxleafents;
int minleafrecs;
int minnoderecs;
maxleafents = (mp->m_sb.sb_agblocks + 1) / 2;
minleafrecs = mp->m_alloc_mnr[0];
minnoderecs = mp->m_alloc_mnr[1];
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
for (level = 1; maxblocks > 1; level++)
maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
mp->m_ag_maxlevels = level;
} }
/* /*
...@@ -2658,55 +2647,79 @@ xfs_alloc_vextent( ...@@ -2658,55 +2647,79 @@ xfs_alloc_vextent(
return error; return error;
} }
/* /* Ensure that the freelist is at full capacity. */
* Free an extent. int
* Just break up the extent address and hand off to xfs_free_ag_extent xfs_free_extent_fix_freelist(
* after fixing up the freelist. struct xfs_trans *tp,
*/ xfs_agnumber_t agno,
int /* error */ struct xfs_buf **agbp)
xfs_free_extent(
xfs_trans_t *tp, /* transaction pointer */
xfs_fsblock_t bno, /* starting block number of extent */
xfs_extlen_t len) /* length of extent */
{ {
xfs_alloc_arg_t args; struct xfs_alloc_arg args;
int error; int error;
ASSERT(len != 0); memset(&args, 0, sizeof(struct xfs_alloc_arg));
memset(&args, 0, sizeof(xfs_alloc_arg_t));
args.tp = tp; args.tp = tp;
args.mp = tp->t_mountp; args.mp = tp->t_mountp;
args.agno = agno;
/* /*
* validate that the block number is legal - the enables us to detect * validate that the block number is legal - the enables us to detect
* and handle a silent filesystem corruption rather than crashing. * and handle a silent filesystem corruption rather than crashing.
*/ */
args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
if (args.agno >= args.mp->m_sb.sb_agcount) if (args.agno >= args.mp->m_sb.sb_agcount)
return -EFSCORRUPTED; return -EFSCORRUPTED;
args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
if (args.agbno >= args.mp->m_sb.sb_agblocks)
return -EFSCORRUPTED;
args.pag = xfs_perag_get(args.mp, args.agno); args.pag = xfs_perag_get(args.mp, args.agno);
ASSERT(args.pag); ASSERT(args.pag);
error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
if (error) if (error)
goto error0; goto out;
*agbp = args.agbp;
out:
xfs_perag_put(args.pag);
return error;
}
/*
* Free an extent.
* Just break up the extent address and hand off to xfs_free_ag_extent
* after fixing up the freelist.
*/
int /* error */
xfs_free_extent(
struct xfs_trans *tp, /* transaction pointer */
xfs_fsblock_t bno, /* starting block number of extent */
xfs_extlen_t len) /* length of extent */
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_buf *agbp;
xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, bno);
xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, bno);
int error;
ASSERT(len != 0);
error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
if (error)
return error;
XFS_WANT_CORRUPTED_GOTO(mp, agbno < mp->m_sb.sb_agblocks, err);
/* validate the extent size is legal now we have the agf locked */ /* validate the extent size is legal now we have the agf locked */
if (args.agbno + len > XFS_WANT_CORRUPTED_GOTO(mp,
be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) { agbno + len <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length),
error = -EFSCORRUPTED; err);
goto error0;
}
error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, 0);
if (!error) if (error)
xfs_extent_busy_insert(tp, args.agno, args.agbno, len, 0); goto err;
error0:
xfs_perag_put(args.pag); xfs_extent_busy_insert(tp, agno, agbno, len, 0);
return 0;
err:
xfs_trans_brelse(tp, agbp);
return error; return error;
} }
...@@ -229,5 +229,7 @@ xfs_alloc_get_rec( ...@@ -229,5 +229,7 @@ xfs_alloc_get_rec(
int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp, int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, int flags, struct xfs_buf **bpp); xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags); int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno,
struct xfs_buf **agbp);
#endif /* __XFS_ALLOC_H__ */ #endif /* __XFS_ALLOC_H__ */
...@@ -570,14 +570,12 @@ xfs_bmap_validate_ret( ...@@ -570,14 +570,12 @@ xfs_bmap_validate_ret(
*/ */
void void
xfs_bmap_add_free( xfs_bmap_add_free(
struct xfs_mount *mp, /* mount point structure */
struct xfs_bmap_free *flist, /* list of extents */
xfs_fsblock_t bno, /* fs block number of extent */ xfs_fsblock_t bno, /* fs block number of extent */
xfs_filblks_t len, /* length of extent */ xfs_filblks_t len) /* length of extent */
xfs_bmap_free_t *flist, /* list of extents */
xfs_mount_t *mp) /* mount point structure */
{ {
xfs_bmap_free_item_t *cur; /* current (next) element */ struct xfs_bmap_free_item *new; /* new element */
xfs_bmap_free_item_t *new; /* new element */
xfs_bmap_free_item_t *prev; /* previous element */
#ifdef DEBUG #ifdef DEBUG
xfs_agnumber_t agno; xfs_agnumber_t agno;
xfs_agblock_t agbno; xfs_agblock_t agbno;
...@@ -597,17 +595,7 @@ xfs_bmap_add_free( ...@@ -597,17 +595,7 @@ xfs_bmap_add_free(
new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP);
new->xbfi_startblock = bno; new->xbfi_startblock = bno;
new->xbfi_blockcount = (xfs_extlen_t)len; new->xbfi_blockcount = (xfs_extlen_t)len;
for (prev = NULL, cur = flist->xbf_first; list_add(&new->xbfi_list, &flist->xbf_flist);
cur != NULL;
prev = cur, cur = cur->xbfi_next) {
if (cur->xbfi_startblock >= bno)
break;
}
if (prev)
prev->xbfi_next = new;
else
flist->xbf_first = new;
new->xbfi_next = cur;
flist->xbf_count++; flist->xbf_count++;
} }
...@@ -617,14 +605,10 @@ xfs_bmap_add_free( ...@@ -617,14 +605,10 @@ xfs_bmap_add_free(
*/ */
void void
xfs_bmap_del_free( xfs_bmap_del_free(
xfs_bmap_free_t *flist, /* free item list header */ struct xfs_bmap_free *flist, /* free item list header */
xfs_bmap_free_item_t *prev, /* previous item on list, if any */ struct xfs_bmap_free_item *free) /* list item to be freed */
xfs_bmap_free_item_t *free) /* list item to be freed */
{ {
if (prev) list_del(&free->xbfi_list);
prev->xbfi_next = free->xbfi_next;
else
flist->xbf_first = free->xbfi_next;
flist->xbf_count--; flist->xbf_count--;
kmem_zone_free(xfs_bmap_free_item_zone, free); kmem_zone_free(xfs_bmap_free_item_zone, free);
} }
...@@ -634,17 +618,16 @@ xfs_bmap_del_free( ...@@ -634,17 +618,16 @@ xfs_bmap_del_free(
*/ */
void void
xfs_bmap_cancel( xfs_bmap_cancel(
xfs_bmap_free_t *flist) /* list of bmap_free_items */ struct xfs_bmap_free *flist) /* list of bmap_free_items */
{ {
xfs_bmap_free_item_t *free; /* free list item */ struct xfs_bmap_free_item *free; /* free list item */
xfs_bmap_free_item_t *next;
if (flist->xbf_count == 0) if (flist->xbf_count == 0)
return; return;
ASSERT(flist->xbf_first != NULL); while (!list_empty(&flist->xbf_flist)) {
for (free = flist->xbf_first; free; free = next) { free = list_first_entry(&flist->xbf_flist,
next = free->xbfi_next; struct xfs_bmap_free_item, xbfi_list);
xfs_bmap_del_free(flist, NULL, free); xfs_bmap_del_free(flist, free);
} }
ASSERT(flist->xbf_count == 0); ASSERT(flist->xbf_count == 0);
} }
...@@ -699,7 +682,7 @@ xfs_bmap_btree_to_extents( ...@@ -699,7 +682,7 @@ xfs_bmap_btree_to_extents(
cblock = XFS_BUF_TO_BLOCK(cbp); cblock = XFS_BUF_TO_BLOCK(cbp);
if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) if ((error = xfs_btree_check_block(cur, cblock, 0, cbp)))
return error; return error;
xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp); xfs_bmap_add_free(mp, cur->bc_private.b.flist, cbno, 1);
ip->i_d.di_nblocks--; ip->i_d.di_nblocks--;
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
xfs_trans_binval(tp, cbp); xfs_trans_binval(tp, cbp);
...@@ -5073,8 +5056,8 @@ xfs_bmap_del_extent( ...@@ -5073,8 +5056,8 @@ xfs_bmap_del_extent(
* If we need to, add to list of extents to delete. * If we need to, add to list of extents to delete.
*/ */
if (do_fx) if (do_fx)
xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist, xfs_bmap_add_free(mp, flist, del->br_startblock,
mp); del->br_blockcount);
/* /*
* Adjust inode # blocks in the file. * Adjust inode # blocks in the file.
*/ */
......
...@@ -62,12 +62,12 @@ struct xfs_bmalloca { ...@@ -62,12 +62,12 @@ struct xfs_bmalloca {
* List of extents to be free "later". * List of extents to be free "later".
* The list is kept sorted on xbf_startblock. * The list is kept sorted on xbf_startblock.
*/ */
typedef struct xfs_bmap_free_item struct xfs_bmap_free_item
{ {
xfs_fsblock_t xbfi_startblock;/* starting fs block number */ xfs_fsblock_t xbfi_startblock;/* starting fs block number */
xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */ xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */
struct xfs_bmap_free_item *xbfi_next; /* link to next entry */ struct list_head xbfi_list;
} xfs_bmap_free_item_t; };
/* /*
* Header for free extent list. * Header for free extent list.
...@@ -85,7 +85,7 @@ typedef struct xfs_bmap_free_item ...@@ -85,7 +85,7 @@ typedef struct xfs_bmap_free_item
*/ */
typedef struct xfs_bmap_free typedef struct xfs_bmap_free
{ {
xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ struct list_head xbf_flist; /* list of to-be-free extents */
int xbf_count; /* count of items on list */ int xbf_count; /* count of items on list */
int xbf_low; /* alloc in low mode */ int xbf_low; /* alloc in low mode */
} xfs_bmap_free_t; } xfs_bmap_free_t;
...@@ -141,8 +141,10 @@ static inline int xfs_bmapi_aflag(int w) ...@@ -141,8 +141,10 @@ static inline int xfs_bmapi_aflag(int w)
static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp) static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp)
{ {
((flp)->xbf_first = NULL, (flp)->xbf_count = 0, \ INIT_LIST_HEAD(&flp->xbf_flist);
(flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK); flp->xbf_count = 0;
flp->xbf_low = 0;
*fbp = NULLFSBLOCK;
} }
/* /*
...@@ -191,8 +193,8 @@ void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt, ...@@ -191,8 +193,8 @@ void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
void xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len, void xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_bmap_free *flist,
struct xfs_bmap_free *flist, struct xfs_mount *mp); xfs_fsblock_t bno, xfs_filblks_t len);
void xfs_bmap_cancel(struct xfs_bmap_free *flist); void xfs_bmap_cancel(struct xfs_bmap_free *flist);
int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist, int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
struct xfs_inode *ip); struct xfs_inode *ip);
......
...@@ -526,7 +526,7 @@ xfs_bmbt_free_block( ...@@ -526,7 +526,7 @@ xfs_bmbt_free_block(
struct xfs_trans *tp = cur->bc_tp; struct xfs_trans *tp = cur->bc_tp;
xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp); xfs_bmap_add_free(mp, cur->bc_private.b.flist, fsbno, 1);
ip->i_d.di_nblocks--; ip->i_d.di_nblocks--;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
......
...@@ -4152,3 +4152,22 @@ xfs_btree_sblock_verify( ...@@ -4152,3 +4152,22 @@ xfs_btree_sblock_verify(
return true; return true;
} }
/*
* Calculate the number of btree levels needed to store a given number of
* records in a short-format btree.
*/
uint
xfs_btree_compute_maxlevels(
struct xfs_mount *mp,
uint *limits,
unsigned long len)
{
uint level;
unsigned long maxblocks;
maxblocks = (len + limits[0] - 1) / limits[0];
for (level = 1; maxblocks > 1; level++)
maxblocks = (maxblocks + limits[1] - 1) / limits[1];
return level;
}
...@@ -474,5 +474,7 @@ static inline int xfs_btree_get_level(struct xfs_btree_block *block) ...@@ -474,5 +474,7 @@ static inline int xfs_btree_get_level(struct xfs_btree_block *block)
bool xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp); bool xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp);
bool xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs); bool xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs);
uint xfs_btree_compute_maxlevels(struct xfs_mount *mp, uint *limits,
unsigned long len);
#endif /* __XFS_BTREE_H__ */ #endif /* __XFS_BTREE_H__ */
...@@ -1828,9 +1828,8 @@ xfs_difree_inode_chunk( ...@@ -1828,9 +1828,8 @@ xfs_difree_inode_chunk(
if (!xfs_inobt_issparse(rec->ir_holemask)) { if (!xfs_inobt_issparse(rec->ir_holemask)) {
/* not sparse, calculate extent info directly */ /* not sparse, calculate extent info directly */
xfs_bmap_add_free(XFS_AGB_TO_FSB(mp, agno, xfs_bmap_add_free(mp, flist, XFS_AGB_TO_FSB(mp, agno, sagbno),
XFS_AGINO_TO_AGBNO(mp, rec->ir_startino)), mp->m_ialloc_blks);
mp->m_ialloc_blks, flist, mp);
return; return;
} }
...@@ -1873,8 +1872,8 @@ xfs_difree_inode_chunk( ...@@ -1873,8 +1872,8 @@ xfs_difree_inode_chunk(
ASSERT(agbno % mp->m_sb.sb_spino_align == 0); ASSERT(agbno % mp->m_sb.sb_spino_align == 0);
ASSERT(contigblk % mp->m_sb.sb_spino_align == 0); ASSERT(contigblk % mp->m_sb.sb_spino_align == 0);
xfs_bmap_add_free(XFS_AGB_TO_FSB(mp, agno, agbno), contigblk, xfs_bmap_add_free(mp, flist, XFS_AGB_TO_FSB(mp, agno, agbno),
flist, mp); contigblk);
/* reset range to current bit and carry on... */ /* reset range to current bit and carry on... */
startidx = endidx = nextbit; startidx = endidx = nextbit;
...@@ -2395,20 +2394,11 @@ void ...@@ -2395,20 +2394,11 @@ void
xfs_ialloc_compute_maxlevels( xfs_ialloc_compute_maxlevels(
xfs_mount_t *mp) /* file system mount structure */ xfs_mount_t *mp) /* file system mount structure */
{ {
int level; uint inodes;
uint maxblocks;
uint maxleafents; inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG;
int minleafrecs; mp->m_in_maxlevels = xfs_btree_compute_maxlevels(mp, mp->m_inobt_mnr,
int minnoderecs; inodes);
maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >>
XFS_INODES_PER_CHUNK_LOG;
minleafrecs = mp->m_inobt_mnr[0];
minnoderecs = mp->m_inobt_mnr[1];
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
for (level = 1; maxblocks > 1; level++)
maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
mp->m_in_maxlevels = level;
} }
/* /*
......
...@@ -79,6 +79,23 @@ xfs_zero_extent( ...@@ -79,6 +79,23 @@ xfs_zero_extent(
GFP_NOFS, true); GFP_NOFS, true);
} }
/* Sort bmap items by AG. */
static int
xfs_bmap_free_list_cmp(
void *priv,
struct list_head *a,
struct list_head *b)
{
struct xfs_mount *mp = priv;
struct xfs_bmap_free_item *ra;
struct xfs_bmap_free_item *rb;
ra = container_of(a, struct xfs_bmap_free_item, xbfi_list);
rb = container_of(b, struct xfs_bmap_free_item, xbfi_list);
return XFS_FSB_TO_AGNO(mp, ra->xbfi_startblock) -
XFS_FSB_TO_AGNO(mp, rb->xbfi_startblock);
}
/* /*
* Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
* caller. Frees all the extents that need freeing, which must be done * caller. Frees all the extents that need freeing, which must be done
...@@ -99,14 +116,15 @@ xfs_bmap_finish( ...@@ -99,14 +116,15 @@ xfs_bmap_finish(
int error; /* error return value */ int error; /* error return value */
int committed;/* xact committed or not */ int committed;/* xact committed or not */
struct xfs_bmap_free_item *free; /* free extent item */ struct xfs_bmap_free_item *free; /* free extent item */
struct xfs_bmap_free_item *next; /* next item on free list */
ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
if (flist->xbf_count == 0) if (flist->xbf_count == 0)
return 0; return 0;
list_sort((*tp)->t_mountp, &flist->xbf_flist, xfs_bmap_free_list_cmp);
efi = xfs_trans_get_efi(*tp, flist->xbf_count); efi = xfs_trans_get_efi(*tp, flist->xbf_count);
for (free = flist->xbf_first; free; free = free->xbfi_next) list_for_each_entry(free, &flist->xbf_flist, xbfi_list)
xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock, xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock,
free->xbfi_blockcount); free->xbfi_blockcount);
...@@ -136,15 +154,15 @@ xfs_bmap_finish( ...@@ -136,15 +154,15 @@ xfs_bmap_finish(
* on error. * on error.
*/ */
efd = xfs_trans_get_efd(*tp, efi, flist->xbf_count); efd = xfs_trans_get_efd(*tp, efi, flist->xbf_count);
for (free = flist->xbf_first; free != NULL; free = next) { while (!list_empty(&flist->xbf_flist)) {
next = free->xbfi_next; free = list_first_entry(&flist->xbf_flist,
struct xfs_bmap_free_item, xbfi_list);
error = xfs_trans_free_extent(*tp, efd, free->xbfi_startblock, error = xfs_trans_free_extent(*tp, efd, free->xbfi_startblock,
free->xbfi_blockcount); free->xbfi_blockcount);
if (error) if (error)
return error; return error;
xfs_bmap_del_free(flist, NULL, free); xfs_bmap_del_free(flist, free);
} }
return 0; return 0;
...@@ -797,7 +815,7 @@ xfs_bmap_punch_delalloc_range( ...@@ -797,7 +815,7 @@ xfs_bmap_punch_delalloc_range(
if (error) if (error)
break; break;
ASSERT(!flist.xbf_count && !flist.xbf_first); ASSERT(!flist.xbf_count && list_empty(&flist.xbf_flist));
next_block: next_block:
start_fsb++; start_fsb++;
remaining--; remaining--;
......
...@@ -41,7 +41,6 @@ int xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv, ...@@ -41,7 +41,6 @@ int xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
/* functions in xfs_bmap.c that are only needed by xfs_bmap_util.c */ /* functions in xfs_bmap.c that are only needed by xfs_bmap_util.c */
void xfs_bmap_del_free(struct xfs_bmap_free *flist, void xfs_bmap_del_free(struct xfs_bmap_free *flist,
struct xfs_bmap_free_item *prev,
struct xfs_bmap_free_item *free); struct xfs_bmap_free_item *free);
int xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp, int xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp,
struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz, struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz,
......
...@@ -944,10 +944,12 @@ xfs_buf_trylock( ...@@ -944,10 +944,12 @@ xfs_buf_trylock(
int locked; int locked;
locked = down_trylock(&bp->b_sema) == 0; locked = down_trylock(&bp->b_sema) == 0;
if (locked) if (locked) {
XB_SET_OWNER(bp); XB_SET_OWNER(bp);
trace_xfs_buf_trylock(bp, _RET_IP_);
trace_xfs_buf_trylock(bp, _RET_IP_); } else {
trace_xfs_buf_trylock_fail(bp, _RET_IP_);
}
return locked; return locked;
} }
......
...@@ -61,6 +61,9 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp) ...@@ -61,6 +61,9 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp)
int len; int len;
int64_t fsid; int64_t fsid;
if (error_tag >= XFS_ERRTAG_MAX)
return -EINVAL;
memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)); memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
......
...@@ -667,8 +667,11 @@ xfs_reserve_blocks( ...@@ -667,8 +667,11 @@ xfs_reserve_blocks(
__uint64_t *inval, __uint64_t *inval,
xfs_fsop_resblks_t *outval) xfs_fsop_resblks_t *outval)
{ {
__int64_t lcounter, delta, fdblks_delta; __int64_t lcounter, delta;
__int64_t fdblks_delta = 0;
__uint64_t request; __uint64_t request;
__int64_t free;
int error = 0;
/* If inval is null, report current values and return */ /* If inval is null, report current values and return */
if (inval == (__uint64_t *)NULL) { if (inval == (__uint64_t *)NULL) {
...@@ -682,24 +685,23 @@ xfs_reserve_blocks( ...@@ -682,24 +685,23 @@ xfs_reserve_blocks(
request = *inval; request = *inval;
/* /*
* With per-cpu counters, this becomes an interesting * With per-cpu counters, this becomes an interesting problem. we need
* problem. we needto work out if we are freeing or allocation * to work out if we are freeing or allocation blocks first, then we can
* blocks first, then we can do the modification as necessary. * do the modification as necessary.
* *
* We do this under the m_sb_lock so that if we are near * We do this under the m_sb_lock so that if we are near ENOSPC, we will
* ENOSPC, we will hold out any changes while we work out * hold out any changes while we work out what to do. This means that
* what to do. This means that the amount of free space can * the amount of free space can change while we do this, so we need to
* change while we do this, so we need to retry if we end up * retry if we end up trying to reserve more space than is available.
* trying to reserve more space than is available.
*/ */
retry:
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
/* /*
* If our previous reservation was larger than the current value, * If our previous reservation was larger than the current value,
* then move any unused blocks back to the free pool. * then move any unused blocks back to the free pool. Modify the resblks
* counters directly since we shouldn't have any problems unreserving
* space.
*/ */
fdblks_delta = 0;
if (mp->m_resblks > request) { if (mp->m_resblks > request) {
lcounter = mp->m_resblks_avail - request; lcounter = mp->m_resblks_avail - request;
if (lcounter > 0) { /* release unused blocks */ if (lcounter > 0) { /* release unused blocks */
...@@ -707,54 +709,67 @@ xfs_reserve_blocks( ...@@ -707,54 +709,67 @@ xfs_reserve_blocks(
mp->m_resblks_avail -= lcounter; mp->m_resblks_avail -= lcounter;
} }
mp->m_resblks = request; mp->m_resblks = request;
} else { if (fdblks_delta) {
__int64_t free; spin_unlock(&mp->m_sb_lock);
error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
spin_lock(&mp->m_sb_lock);
}
goto out;
}
/*
* If the request is larger than the current reservation, reserve the
* blocks before we update the reserve counters. Sample m_fdblocks and
* perform a partial reservation if the request exceeds free space.
*/
error = -ENOSPC;
do {
free = percpu_counter_sum(&mp->m_fdblocks) - free = percpu_counter_sum(&mp->m_fdblocks) -
XFS_ALLOC_SET_ASIDE(mp); XFS_ALLOC_SET_ASIDE(mp);
if (!free) if (!free)
goto out; /* ENOSPC and fdblks_delta = 0 */ break;
delta = request - mp->m_resblks; delta = request - mp->m_resblks;
lcounter = free - delta; lcounter = free - delta;
if (lcounter < 0) { if (lcounter < 0)
/* We can't satisfy the request, just get what we can */ /* We can't satisfy the request, just get what we can */
mp->m_resblks += free; fdblks_delta = free;
mp->m_resblks_avail += free; else
fdblks_delta = -free; fdblks_delta = delta;
} else {
fdblks_delta = -delta;
mp->m_resblks = request;
mp->m_resblks_avail += delta;
}
}
out:
if (outval) {
outval->resblks = mp->m_resblks;
outval->resblks_avail = mp->m_resblks_avail;
}
spin_unlock(&mp->m_sb_lock);
if (fdblks_delta) {
/* /*
* If we are putting blocks back here, m_resblks_avail is * We'll either succeed in getting space from the free block
* already at its max so this will put it in the free pool. * count or we'll get an ENOSPC. If we get a ENOSPC, it means
* * things changed while we were calculating fdblks_delta and so
* If we need space, we'll either succeed in getting it * we should try again to see if there is anything left to
* from the free block count or we'll get an enospc. If * reserve.
* we get a ENOSPC, it means things changed while we were
* calculating fdblks_delta and so we should try again to
* see if there is anything left to reserve.
* *
* Don't set the reserved flag here - we don't want to reserve * Don't set the reserved flag here - we don't want to reserve
* the extra reserve blocks from the reserve..... * the extra reserve blocks from the reserve.....
*/ */
int error; spin_unlock(&mp->m_sb_lock);
error = xfs_mod_fdblocks(mp, fdblks_delta, 0); error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
if (error == -ENOSPC) spin_lock(&mp->m_sb_lock);
goto retry; } while (error == -ENOSPC);
/*
* Update the reserve counters if blocks have been successfully
* allocated.
*/
if (!error && fdblks_delta) {
mp->m_resblks += fdblks_delta;
mp->m_resblks_avail += fdblks_delta;
} }
return 0;
out:
if (outval) {
outval->resblks = mp->m_resblks;
outval->resblks_avail = mp->m_resblks_avail;
}
spin_unlock(&mp->m_sb_lock);
return error;
} }
int int
......
...@@ -765,7 +765,7 @@ xfs_inode_ag_walk( ...@@ -765,7 +765,7 @@ xfs_inode_ag_walk(
* Background scanning to trim post-EOF preallocated space. This is queued * Background scanning to trim post-EOF preallocated space. This is queued
* based on the 'speculative_prealloc_lifetime' tunable (5m by default). * based on the 'speculative_prealloc_lifetime' tunable (5m by default).
*/ */
STATIC void void
xfs_queue_eofblocks( xfs_queue_eofblocks(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
......
...@@ -68,6 +68,7 @@ void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip); ...@@ -68,6 +68,7 @@ void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *); int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
int xfs_inode_free_quota_eofblocks(struct xfs_inode *ip); int xfs_inode_free_quota_eofblocks(struct xfs_inode *ip);
void xfs_eofblocks_worker(struct work_struct *); void xfs_eofblocks_worker(struct work_struct *);
void xfs_queue_eofblocks(struct xfs_mount *);
int xfs_inode_ag_iterator(struct xfs_mount *mp, int xfs_inode_ag_iterator(struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip, int flags, void *args), int (*execute)(struct xfs_inode *ip, int flags, void *args),
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
BUILD_BUG_ON_MSG(sizeof(structname) != (size), "XFS: sizeof(" \ BUILD_BUG_ON_MSG(sizeof(structname) != (size), "XFS: sizeof(" \
#structname ") is wrong, expected " #size) #structname ") is wrong, expected " #size)
#define XFS_CHECK_OFFSET(structname, member, off) \
BUILD_BUG_ON_MSG(offsetof(structname, member) != (off), \
"XFS: offsetof(" #structname ", " #member ") is wrong, " \
"expected " #off)
static inline void __init static inline void __init
xfs_check_ondisk_structs(void) xfs_check_ondisk_structs(void)
{ {
...@@ -75,15 +80,28 @@ xfs_check_ondisk_structs(void) ...@@ -75,15 +80,28 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_remote_t, 12); XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_remote_t, 12);
*/ */
XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, valuelen, 0);
XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, namelen, 2);
XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, nameval, 3);
XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, valueblk, 0);
XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, valuelen, 4);
XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, namelen, 8);
XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, name, 9);
XFS_CHECK_STRUCT_SIZE(xfs_attr_leafblock_t, 40); XFS_CHECK_STRUCT_SIZE(xfs_attr_leafblock_t, 40);
XFS_CHECK_STRUCT_SIZE(xfs_attr_shortform_t, 8); XFS_CHECK_OFFSET(xfs_attr_shortform_t, hdr.totsize, 0);
XFS_CHECK_OFFSET(xfs_attr_shortform_t, hdr.count, 2);
XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].namelen, 4);
XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].valuelen, 5);
XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].flags, 6);
XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].nameval, 7);
XFS_CHECK_STRUCT_SIZE(xfs_da_blkinfo_t, 12); XFS_CHECK_STRUCT_SIZE(xfs_da_blkinfo_t, 12);
XFS_CHECK_STRUCT_SIZE(xfs_da_intnode_t, 16); XFS_CHECK_STRUCT_SIZE(xfs_da_intnode_t, 16);
XFS_CHECK_STRUCT_SIZE(xfs_da_node_entry_t, 8); XFS_CHECK_STRUCT_SIZE(xfs_da_node_entry_t, 8);
XFS_CHECK_STRUCT_SIZE(xfs_da_node_hdr_t, 16); XFS_CHECK_STRUCT_SIZE(xfs_da_node_hdr_t, 16);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_free_t, 4); XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_free_t, 4);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_hdr_t, 16); XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_hdr_t, 16);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_unused_t, 6); XFS_CHECK_OFFSET(xfs_dir2_data_unused_t, freetag, 0);
XFS_CHECK_OFFSET(xfs_dir2_data_unused_t, length, 2);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_free_hdr_t, 16); XFS_CHECK_STRUCT_SIZE(xfs_dir2_free_hdr_t, 16);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_free_t, 16); XFS_CHECK_STRUCT_SIZE(xfs_dir2_free_t, 16);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_ino4_t, 4); XFS_CHECK_STRUCT_SIZE(xfs_dir2_ino4_t, 4);
...@@ -94,6 +112,9 @@ xfs_check_ondisk_structs(void) ...@@ -94,6 +112,9 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_t, 16); XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_t, 16);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_tail_t, 4); XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_tail_t, 4);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_entry_t, 3); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_entry_t, 3);
XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, namelen, 0);
XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, offset, 1);
XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_off_t, 2); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_off_t, 2);
......
...@@ -1294,6 +1294,7 @@ xfs_fs_remount( ...@@ -1294,6 +1294,7 @@ xfs_fs_remount(
*/ */
xfs_restore_resvblks(mp); xfs_restore_resvblks(mp);
xfs_log_work_queue(mp); xfs_log_work_queue(mp);
xfs_queue_eofblocks(mp);
} }
/* rw -> ro */ /* rw -> ro */
...@@ -1306,6 +1307,13 @@ xfs_fs_remount( ...@@ -1306,6 +1307,13 @@ xfs_fs_remount(
* return it to the same size. * return it to the same size.
*/ */
xfs_save_resvblks(mp); xfs_save_resvblks(mp);
/*
* Cancel background eofb scanning so it cannot race with the
* final log force+buftarg wait and deadlock the remount.
*/
cancel_delayed_work_sync(&mp->m_eofblocks_work);
xfs_quiesce_attr(mp); xfs_quiesce_attr(mp);
mp->m_flags |= XFS_MOUNT_RDONLY; mp->m_flags |= XFS_MOUNT_RDONLY;
} }
...@@ -1692,8 +1700,9 @@ xfs_init_zones(void) ...@@ -1692,8 +1700,9 @@ xfs_init_zones(void)
if (!xfs_log_ticket_zone) if (!xfs_log_ticket_zone)
goto out_free_ioend_bioset; goto out_free_ioend_bioset;
xfs_bmap_free_item_zone = kmem_zone_init(sizeof(xfs_bmap_free_item_t), xfs_bmap_free_item_zone = kmem_zone_init(
"xfs_bmap_free_item"); sizeof(struct xfs_bmap_free_item),
"xfs_bmap_free_item");
if (!xfs_bmap_free_item_zone) if (!xfs_bmap_free_item_zone)
goto out_destroy_log_ticket_zone; goto out_destroy_log_ticket_zone;
......
...@@ -354,6 +354,7 @@ DEFINE_BUF_EVENT(xfs_buf_submit_wait); ...@@ -354,6 +354,7 @@ DEFINE_BUF_EVENT(xfs_buf_submit_wait);
DEFINE_BUF_EVENT(xfs_buf_bawrite); DEFINE_BUF_EVENT(xfs_buf_bawrite);
DEFINE_BUF_EVENT(xfs_buf_lock); DEFINE_BUF_EVENT(xfs_buf_lock);
DEFINE_BUF_EVENT(xfs_buf_lock_done); DEFINE_BUF_EVENT(xfs_buf_lock_done);
DEFINE_BUF_EVENT(xfs_buf_trylock_fail);
DEFINE_BUF_EVENT(xfs_buf_trylock); DEFINE_BUF_EVENT(xfs_buf_trylock);
DEFINE_BUF_EVENT(xfs_buf_unlock); DEFINE_BUF_EVENT(xfs_buf_unlock);
DEFINE_BUF_EVENT(xfs_buf_iowait); DEFINE_BUF_EVENT(xfs_buf_iowait);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment