Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
Browse files Browse the repository at this point in the history
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
  xfs: xfs_bmap_add_extent_delay_real should init br_startblock
  xfs: fix dquot shaker deadlock
  xfs: handle CIl transaction commit failures correctly
  xfs: limit extsize to size of AGs and/or MAXEXTLEN
  xfs: prevent extsize alignment from exceeding maximum extent size
  xfs: limit extent length for allocation to AG size
  xfs: speculative delayed allocation uses rounddown_power_of_2 badly
  xfs: fix efi item leak on forced shutdown
  xfs: fix log ticket leak on forced shutdown.
  • Loading branch information
torvalds committed Jan 31, 2011
2 parents 2426ec8 + 24446fc commit fb9f1f1
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 71 deletions.
20 changes: 18 additions & 2 deletions fs/xfs/linux-2.6/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -985,10 +985,22 @@ xfs_ioctl_setattr(

/*
* Extent size must be a multiple of the appropriate block
* size, if set at all.
* size, if set at all. It must also be smaller than the
* maximum extent size supported by the filesystem.
*
* Also, for non-realtime files, limit the extent size hint to
* half the size of the AGs in the filesystem so alignment
* doesn't result in extents larger than an AG.
*/
if (fa->fsx_extsize != 0) {
xfs_extlen_t size;
xfs_extlen_t size;
xfs_fsblock_t extsize_fsb;

extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
if (extsize_fsb > MAXEXTLEN) {
code = XFS_ERROR(EINVAL);
goto error_return;
}

if (XFS_IS_REALTIME_INODE(ip) ||
((mask & FSX_XFLAGS) &&
Expand All @@ -997,6 +1009,10 @@ xfs_ioctl_setattr(
mp->m_sb.sb_blocklog;
} else {
size = mp->m_sb.sb_blocksize;
if (extsize_fsb > mp->m_sb.sb_agblocks / 2) {
code = XFS_ERROR(EINVAL);
goto error_return;
}
}

if (fa->fsx_extsize % size) {
Expand Down
46 changes: 21 additions & 25 deletions fs/xfs/quota/xfs_qm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1863,12 +1863,14 @@ xfs_qm_dqreclaim_one(void)
xfs_dquot_t *dqpout;
xfs_dquot_t *dqp;
int restarts;
int startagain;

restarts = 0;
dqpout = NULL;

/* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
startagain:
again:
startagain = 0;
mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);

list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
Expand All @@ -1885,13 +1887,10 @@ xfs_qm_dqreclaim_one(void)
ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));

trace_xfs_dqreclaim_want(dqp);

xfs_dqunlock(dqp);
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
return NULL;
XQM_STATS_INC(xqmstats.xs_qm_dqwants);
goto startagain;
restarts++;
startagain = 1;
goto dqunlock;
}

/*
Expand All @@ -1906,23 +1905,20 @@ xfs_qm_dqreclaim_one(void)
ASSERT(list_empty(&dqp->q_mplist));
list_del_init(&dqp->q_freelist);
xfs_Gqm->qm_dqfrlist_cnt--;
xfs_dqunlock(dqp);
dqpout = dqp;
XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
break;
goto dqunlock;
}

ASSERT(dqp->q_hash);
ASSERT(!list_empty(&dqp->q_mplist));

/*
* Try to grab the flush lock. If this dquot is in the process of
* getting flushed to disk, we don't want to reclaim it.
* Try to grab the flush lock. If this dquot is in the process
* of getting flushed to disk, we don't want to reclaim it.
*/
if (!xfs_dqflock_nowait(dqp)) {
xfs_dqunlock(dqp);
continue;
}
if (!xfs_dqflock_nowait(dqp))
goto dqunlock;

/*
* We have the flush lock so we know that this is not in the
Expand All @@ -1944,8 +1940,7 @@ xfs_qm_dqreclaim_one(void)
xfs_fs_cmn_err(CE_WARN, mp,
"xfs_qm_dqreclaim: dquot %p flush failed", dqp);
}
xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
continue;
goto dqunlock;
}

/*
Expand All @@ -1967,13 +1962,8 @@ xfs_qm_dqreclaim_one(void)
*/
if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
restarts++;
mutex_unlock(&dqp->q_hash->qh_lock);
xfs_dqfunlock(dqp);
xfs_dqunlock(dqp);
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
if (restarts++ >= XFS_QM_RECLAIM_MAX_RESTARTS)
return NULL;
goto startagain;
startagain = 1;
goto qhunlock;
}

ASSERT(dqp->q_nrefs == 0);
Expand All @@ -1986,14 +1976,20 @@ xfs_qm_dqreclaim_one(void)
xfs_Gqm->qm_dqfrlist_cnt--;
dqpout = dqp;
mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
qhunlock:
mutex_unlock(&dqp->q_hash->qh_lock);
dqfunlock:
xfs_dqfunlock(dqp);
dqunlock:
xfs_dqunlock(dqp);
if (dqpout)
break;
if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
return NULL;
break;
if (startagain) {
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
goto again;
}
}
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
return dqpout;
Expand Down
16 changes: 16 additions & 0 deletions fs/xfs/xfs_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ typedef unsigned int xfs_alloctype_t;
*/
#define XFS_ALLOC_SET_ASIDE(mp) (4 + ((mp)->m_sb.sb_agcount * 4))

/*
* When deciding how much space to allocate out of an AG, we limit the
* allocation maximum size to the size the AG. However, we cannot use all the
* blocks in the AG - some are permanently used by metadata. These
* blocks are generally:
* - the AG superblock, AGF, AGI and AGFL
* - the AGF (bno and cnt) and AGI btree root blocks
* - 4 blocks on the AGFL according to XFS_ALLOC_SET_ASIDE() limits
*
* The AG headers are sector sized, so the amount of space they take up is
* dependent on filesystem geometry. The others are all single blocks.
*/
#define XFS_ALLOC_AG_MAX_USABLE(mp) \
((mp)->m_sb.sb_agblocks - XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)) - 7)


/*
* Argument structure for xfs_alloc routines.
* This is turned into a structure to avoid having 20 arguments passed
Expand Down
61 changes: 45 additions & 16 deletions fs/xfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,17 +1038,34 @@ xfs_bmap_add_extent_delay_real(
* Filling in the middle part of a previous delayed allocation.
* Contiguity is impossible here.
* This case is avoided almost all the time.
*
* We start with a delayed allocation:
*
* +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+
* PREV @ idx
*
* and we are allocating:
* +rrrrrrrrrrrrrrrrr+
* new
*
* and we set it up for insertion as:
* +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+
* new
* PREV @ idx LEFT RIGHT
* inserted at idx + 1
*/
temp = new->br_startoff - PREV.br_startoff;
trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
xfs_bmbt_set_blockcount(ep, temp);
r[0] = *new;
r[1].br_state = PREV.br_state;
r[1].br_startblock = 0;
r[1].br_startoff = new_endoff;
temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
r[1].br_blockcount = temp2;
xfs_iext_insert(ip, idx + 1, 2, &r[0], state);
trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
xfs_bmbt_set_blockcount(ep, temp); /* truncate PREV */
LEFT = *new;
RIGHT.br_state = PREV.br_state;
RIGHT.br_startblock = nullstartblock(
(int)xfs_bmap_worst_indlen(ip, temp2));
RIGHT.br_startoff = new_endoff;
RIGHT.br_blockcount = temp2;
/* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
xfs_iext_insert(ip, idx + 1, 2, &LEFT, state);
ip->i_df.if_lastex = idx + 1;
ip->i_d.di_nextents++;
if (cur == NULL)
Expand Down Expand Up @@ -2430,7 +2447,7 @@ xfs_bmap_btalloc_nullfb(
startag = ag = 0;

pag = xfs_perag_get(mp, ag);
while (*blen < ap->alen) {
while (*blen < args->maxlen) {
if (!pag->pagf_init) {
error = xfs_alloc_pagf_init(mp, args->tp, ag,
XFS_ALLOC_FLAG_TRYLOCK);
Expand All @@ -2452,7 +2469,7 @@ xfs_bmap_btalloc_nullfb(
notinit = 1;

if (xfs_inode_is_filestream(ap->ip)) {
if (*blen >= ap->alen)
if (*blen >= args->maxlen)
break;

if (ap->userdata) {
Expand Down Expand Up @@ -2498,14 +2515,14 @@ xfs_bmap_btalloc_nullfb(
* If the best seen length is less than the request
* length, use the best as the minimum.
*/
else if (*blen < ap->alen)
else if (*blen < args->maxlen)
args->minlen = *blen;
/*
* Otherwise we've seen an extent as big as alen,
* Otherwise we've seen an extent as big as maxlen,
* use that as the minimum.
*/
else
args->minlen = ap->alen;
args->minlen = args->maxlen;

/*
* set the failure fallback case to look in the selected
Expand Down Expand Up @@ -2573,7 +2590,9 @@ xfs_bmap_btalloc(
args.tp = ap->tp;
args.mp = mp;
args.fsbno = ap->rval;
args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks);

/* Trim the allocation back to the maximum an AG can fit. */
args.maxlen = MIN(ap->alen, XFS_ALLOC_AG_MAX_USABLE(mp));
args.firstblock = ap->firstblock;
blen = 0;
if (nullfb) {
Expand Down Expand Up @@ -2621,7 +2640,7 @@ xfs_bmap_btalloc(
/*
* Adjust for alignment
*/
if (blen > args.alignment && blen <= ap->alen)
if (blen > args.alignment && blen <= args.maxlen)
args.minlen = blen - args.alignment;
args.minalignslop = 0;
} else {
Expand All @@ -2640,7 +2659,7 @@ xfs_bmap_btalloc(
* of minlen+alignment+slop doesn't go up
* between the calls.
*/
if (blen > mp->m_dalign && blen <= ap->alen)
if (blen > mp->m_dalign && blen <= args.maxlen)
nextminlen = blen - mp->m_dalign;
else
nextminlen = args.minlen;
Expand Down Expand Up @@ -4485,6 +4504,16 @@ xfs_bmapi(
/* Figure out the extent size, adjust alen */
extsz = xfs_get_extsz_hint(ip);
if (extsz) {
/*
* make sure we don't exceed a single
* extent length when we align the
* extent by reducing length we are
* going to allocate by the maximum
* amount extent size aligment may
* require.
*/
alen = XFS_FILBLKS_MIN(len,
MAXEXTLEN - (2 * extsz - 1));
error = xfs_bmap_extsize_align(mp,
&got, &prev, extsz,
rt, eof,
Expand Down
12 changes: 7 additions & 5 deletions fs/xfs/xfs_buf_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,15 @@ xfs_buf_item_unpin(

if (remove) {
/*
* We have to remove the log item from the transaction
* as we are about to release our reference to the
* buffer. If we don't, the unlock that occurs later
* in xfs_trans_uncommit() will ry to reference the
* If we are in a transaction context, we have to
* remove the log item from the transaction as we are
* about to release our reference to the buffer. If we
* don't, the unlock that occurs later in
* xfs_trans_uncommit() will try to reference the
* buffer which we no longer have a hold on.
*/
xfs_trans_del_item(lip);
if (lip->li_desc)
xfs_trans_del_item(lip);

/*
* Since the transaction no longer refers to the buffer,
Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/xfs_extfree_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ xfs_efi_item_unpin(

if (remove) {
ASSERT(!(lip->li_flags & XFS_LI_IN_AIL));
xfs_trans_del_item(lip);
if (lip->li_desc)
xfs_trans_del_item(lip);
xfs_efi_item_free(efip);
return;
}
Expand Down
7 changes: 6 additions & 1 deletion fs/xfs/xfs_iomap.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,12 @@ xfs_iomap_prealloc_size(
int shift = 0;
int64_t freesp;

alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size);
/*
* rounddown_pow_of_two() returns an undefined result
* if we pass in alloc_blocks = 0. Hence the "+ 1" to
* ensure we always pass in a non-zero value.
*/
alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1;
alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN,
rounddown_pow_of_two(alloc_blocks));

Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ void xfs_log_ticket_put(struct xlog_ticket *ticket);

xlog_tid_t xfs_log_get_trans_ident(struct xfs_trans *tp);

int xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
void xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
struct xfs_log_vec *log_vector,
xfs_lsn_t *commit_lsn, int flags);
bool xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
Expand Down
Loading

0 comments on commit fb9f1f1

Please sign in to comment.