Commit e28ac1fc authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xfs-for-linus-4.10-rc4-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Darrick Wong:
 "As promised last week, here's some stability fixes from Christoph and
  Jan Kara:

   - fix free space request handling when low on disk space

   - remove redundant log failure error messages

   - free truncated dirty pages instead of letting them build up
     forever"

* tag 'xfs-for-linus-4.10-rc4-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: Timely free truncated dirty pages
  xfs: don't print warnings when xfs_log_force fails
  xfs: don't rely on ->total in xfs_alloc_space_available
  xfs: adjust allocation length in xfs_alloc_space_available
  xfs: fix bogus minleft manipulations
  xfs: bump up reserved blocks in xfs_alloc_set_aside
parents 9ca277eb 0a417b8d
...@@ -95,10 +95,7 @@ unsigned int ...@@ -95,10 +95,7 @@ unsigned int
xfs_alloc_set_aside( xfs_alloc_set_aside(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
unsigned int blocks; return mp->m_sb.sb_agcount * (XFS_ALLOC_AGFL_RESERVE + 4);
blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE);
return blocks;
} }
/* /*
...@@ -365,35 +362,11 @@ xfs_alloc_fix_len( ...@@ -365,35 +362,11 @@ xfs_alloc_fix_len(
return; return;
ASSERT(rlen >= args->minlen && rlen <= args->maxlen); ASSERT(rlen >= args->minlen && rlen <= args->maxlen);
ASSERT(rlen % args->prod == args->mod); ASSERT(rlen % args->prod == args->mod);
ASSERT(args->pag->pagf_freeblks + args->pag->pagf_flcount >=
rlen + args->minleft);
args->len = rlen; args->len = rlen;
} }
/*
* Fix up length if there is too little space left in the a.g.
* Return 1 if ok, 0 if too little, should give up.
*/
STATIC int
xfs_alloc_fix_minleft(
xfs_alloc_arg_t *args) /* allocation argument structure */
{
xfs_agf_t *agf; /* a.g. freelist header */
int diff; /* free space difference */
if (args->minleft == 0)
return 1;
agf = XFS_BUF_TO_AGF(args->agbp);
diff = be32_to_cpu(agf->agf_freeblks)
- args->len - args->minleft;
if (diff >= 0)
return 1;
args->len += diff; /* shrink the allocated space */
/* casts to (int) catch length underflows */
if ((int)args->len >= (int)args->minlen)
return 1;
args->agbno = NULLAGBLOCK;
return 0;
}
/* /*
* Update the two btrees, logically removing from freespace the extent * Update the two btrees, logically removing from freespace the extent
* starting at rbno, rlen blocks. The extent is contained within the * starting at rbno, rlen blocks. The extent is contained within the
...@@ -689,8 +662,6 @@ xfs_alloc_ag_vextent( ...@@ -689,8 +662,6 @@ xfs_alloc_ag_vextent(
xfs_alloc_arg_t *args) /* argument structure for allocation */ xfs_alloc_arg_t *args) /* argument structure for allocation */
{ {
int error=0; int error=0;
xfs_extlen_t reservation;
xfs_extlen_t oldmax;
ASSERT(args->minlen > 0); ASSERT(args->minlen > 0);
ASSERT(args->maxlen > 0); ASSERT(args->maxlen > 0);
...@@ -698,20 +669,6 @@ xfs_alloc_ag_vextent( ...@@ -698,20 +669,6 @@ xfs_alloc_ag_vextent(
ASSERT(args->mod < args->prod); ASSERT(args->mod < args->prod);
ASSERT(args->alignment > 0); ASSERT(args->alignment > 0);
/*
* Clamp maxlen to the amount of free space minus any reservations
* that have been made.
*/
oldmax = args->maxlen;
reservation = xfs_ag_resv_needed(args->pag, args->resv);
if (args->maxlen > args->pag->pagf_freeblks - reservation)
args->maxlen = args->pag->pagf_freeblks - reservation;
if (args->maxlen == 0) {
args->agbno = NULLAGBLOCK;
args->maxlen = oldmax;
return 0;
}
/* /*
* Branch to correct routine based on the type. * Branch to correct routine based on the type.
*/ */
...@@ -731,8 +688,6 @@ xfs_alloc_ag_vextent( ...@@ -731,8 +688,6 @@ xfs_alloc_ag_vextent(
/* NOTREACHED */ /* NOTREACHED */
} }
args->maxlen = oldmax;
if (error || args->agbno == NULLAGBLOCK) if (error || args->agbno == NULLAGBLOCK)
return error; return error;
...@@ -841,9 +796,6 @@ xfs_alloc_ag_vextent_exact( ...@@ -841,9 +796,6 @@ xfs_alloc_ag_vextent_exact(
args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen) args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen)
- args->agbno; - args->agbno;
xfs_alloc_fix_len(args); xfs_alloc_fix_len(args);
if (!xfs_alloc_fix_minleft(args))
goto not_found;
ASSERT(args->agbno + args->len <= tend); ASSERT(args->agbno + args->len <= tend);
/* /*
...@@ -1149,12 +1101,7 @@ xfs_alloc_ag_vextent_near( ...@@ -1149,12 +1101,7 @@ xfs_alloc_ag_vextent_near(
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
args->len = blen; args->len = blen;
if (!xfs_alloc_fix_minleft(args)) {
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
trace_xfs_alloc_near_nominleft(args);
return 0;
}
blen = args->len;
/* /*
* We are allocating starting at bnew for blen blocks. * We are allocating starting at bnew for blen blocks.
*/ */
...@@ -1346,12 +1293,6 @@ xfs_alloc_ag_vextent_near( ...@@ -1346,12 +1293,6 @@ xfs_alloc_ag_vextent_near(
*/ */
args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
xfs_alloc_fix_len(args); xfs_alloc_fix_len(args);
if (!xfs_alloc_fix_minleft(args)) {
trace_xfs_alloc_near_nominleft(args);
xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
return 0;
}
rlen = args->len; rlen = args->len;
(void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment,
args->datatype, ltbnoa, ltlena, &ltnew); args->datatype, ltbnoa, ltlena, &ltnew);
...@@ -1553,8 +1494,6 @@ xfs_alloc_ag_vextent_size( ...@@ -1553,8 +1494,6 @@ xfs_alloc_ag_vextent_size(
} }
xfs_alloc_fix_len(args); xfs_alloc_fix_len(args);
if (!xfs_alloc_fix_minleft(args))
goto out_nominleft;
rlen = args->len; rlen = args->len;
XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0); XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0);
/* /*
...@@ -2056,7 +1995,7 @@ xfs_alloc_space_available( ...@@ -2056,7 +1995,7 @@ xfs_alloc_space_available(
int flags) int flags)
{ {
struct xfs_perag *pag = args->pag; struct xfs_perag *pag = args->pag;
xfs_extlen_t longest; xfs_extlen_t alloc_len, longest;
xfs_extlen_t reservation; /* blocks that are still reserved */ xfs_extlen_t reservation; /* blocks that are still reserved */
int available; int available;
...@@ -2066,17 +2005,28 @@ xfs_alloc_space_available( ...@@ -2066,17 +2005,28 @@ xfs_alloc_space_available(
reservation = xfs_ag_resv_needed(pag, args->resv); reservation = xfs_ag_resv_needed(pag, args->resv);
/* do we have enough contiguous free space for the allocation? */ /* 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(args->mp, pag, min_free, longest = xfs_alloc_longest_free_extent(args->mp, pag, min_free,
reservation); reservation);
if ((args->minlen + args->alignment + args->minalignslop - 1) > longest) if (longest < alloc_len)
return false; return false;
/* do we have enough free space remaining for the allocation? */ /* do we have enough free space remaining for the allocation? */
available = (int)(pag->pagf_freeblks + pag->pagf_flcount - available = (int)(pag->pagf_freeblks + pag->pagf_flcount -
reservation - min_free - args->total); reservation - min_free - args->minleft);
if (available < (int)args->minleft || available <= 0) if (available < (int)max(args->total, alloc_len))
return false; return false;
/*
* Clamp maxlen to the amount of free space available for the actual
* extent allocation.
*/
if (available < (int)args->maxlen && !(flags & XFS_ALLOC_FLAG_CHECK)) {
args->maxlen = available;
ASSERT(args->maxlen > 0);
ASSERT(args->maxlen >= args->minlen);
}
return true; return true;
} }
...@@ -2122,7 +2072,8 @@ xfs_alloc_fix_freelist( ...@@ -2122,7 +2072,8 @@ xfs_alloc_fix_freelist(
} }
need = xfs_alloc_min_freelist(mp, pag); need = xfs_alloc_min_freelist(mp, pag);
if (!xfs_alloc_space_available(args, need, flags)) if (!xfs_alloc_space_available(args, need, flags |
XFS_ALLOC_FLAG_CHECK))
goto out_agbp_relse; goto out_agbp_relse;
/* /*
...@@ -2638,12 +2589,10 @@ xfs_alloc_vextent( ...@@ -2638,12 +2589,10 @@ xfs_alloc_vextent(
xfs_agblock_t agsize; /* allocation group size */ xfs_agblock_t agsize; /* allocation group size */
int error; int error;
int flags; /* XFS_ALLOC_FLAG_... locking flags */ int flags; /* XFS_ALLOC_FLAG_... locking flags */
xfs_extlen_t minleft;/* minimum left value, temp copy */
xfs_mount_t *mp; /* mount structure pointer */ xfs_mount_t *mp; /* mount structure pointer */
xfs_agnumber_t sagno; /* starting allocation group number */ xfs_agnumber_t sagno; /* starting allocation group number */
xfs_alloctype_t type; /* input allocation type */ xfs_alloctype_t type; /* input allocation type */
int bump_rotor = 0; int bump_rotor = 0;
int no_min = 0;
xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */ xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */
mp = args->mp; mp = args->mp;
...@@ -2672,7 +2621,6 @@ xfs_alloc_vextent( ...@@ -2672,7 +2621,6 @@ xfs_alloc_vextent(
trace_xfs_alloc_vextent_badargs(args); trace_xfs_alloc_vextent_badargs(args);
return 0; return 0;
} }
minleft = args->minleft;
switch (type) { switch (type) {
case XFS_ALLOCTYPE_THIS_AG: case XFS_ALLOCTYPE_THIS_AG:
...@@ -2683,9 +2631,7 @@ xfs_alloc_vextent( ...@@ -2683,9 +2631,7 @@ xfs_alloc_vextent(
*/ */
args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
args->pag = xfs_perag_get(mp, args->agno); args->pag = xfs_perag_get(mp, args->agno);
args->minleft = 0;
error = xfs_alloc_fix_freelist(args, 0); error = xfs_alloc_fix_freelist(args, 0);
args->minleft = minleft;
if (error) { if (error) {
trace_xfs_alloc_vextent_nofix(args); trace_xfs_alloc_vextent_nofix(args);
goto error0; goto error0;
...@@ -2750,9 +2696,7 @@ xfs_alloc_vextent( ...@@ -2750,9 +2696,7 @@ xfs_alloc_vextent(
*/ */
for (;;) { for (;;) {
args->pag = xfs_perag_get(mp, args->agno); args->pag = xfs_perag_get(mp, args->agno);
if (no_min) args->minleft = 0;
error = xfs_alloc_fix_freelist(args, flags); error = xfs_alloc_fix_freelist(args, flags);
args->minleft = minleft;
if (error) { if (error) {
trace_xfs_alloc_vextent_nofix(args); trace_xfs_alloc_vextent_nofix(args);
goto error0; goto error0;
...@@ -2792,20 +2736,17 @@ xfs_alloc_vextent( ...@@ -2792,20 +2736,17 @@ xfs_alloc_vextent(
* or switch to non-trylock mode. * or switch to non-trylock mode.
*/ */
if (args->agno == sagno) { if (args->agno == sagno) {
if (no_min == 1) { if (flags == 0) {
args->agbno = NULLAGBLOCK; args->agbno = NULLAGBLOCK;
trace_xfs_alloc_vextent_allfailed(args); trace_xfs_alloc_vextent_allfailed(args);
break; break;
} }
if (flags == 0) {
no_min = 1; flags = 0;
} else { if (type == XFS_ALLOCTYPE_START_BNO) {
flags = 0; args->agbno = XFS_FSB_TO_AGBNO(mp,
if (type == XFS_ALLOCTYPE_START_BNO) { args->fsbno);
args->agbno = XFS_FSB_TO_AGBNO(mp, args->type = XFS_ALLOCTYPE_NEAR_BNO;
args->fsbno);
args->type = XFS_ALLOCTYPE_NEAR_BNO;
}
} }
} }
xfs_perag_put(args->pag); xfs_perag_put(args->pag);
......
...@@ -56,7 +56,7 @@ typedef unsigned int xfs_alloctype_t; ...@@ -56,7 +56,7 @@ typedef unsigned int xfs_alloctype_t;
#define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/
#define XFS_ALLOC_FLAG_NORMAP 0x00000004 /* don't modify the rmapbt */ #define XFS_ALLOC_FLAG_NORMAP 0x00000004 /* don't modify the rmapbt */
#define XFS_ALLOC_FLAG_NOSHRINK 0x00000008 /* don't shrink the freelist */ #define XFS_ALLOC_FLAG_NOSHRINK 0x00000008 /* don't shrink the freelist */
#define XFS_ALLOC_FLAG_CHECK 0x00000010 /* test only, don't modify args */
/* /*
* Argument structure for xfs_alloc routines. * Argument structure for xfs_alloc routines.
......
...@@ -3812,7 +3812,6 @@ xfs_bmap_btalloc( ...@@ -3812,7 +3812,6 @@ xfs_bmap_btalloc(
args.fsbno = 0; args.fsbno = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG; args.type = XFS_ALLOCTYPE_FIRST_AG;
args.total = ap->minlen; args.total = ap->minlen;
args.minleft = 0;
if ((error = xfs_alloc_vextent(&args))) if ((error = xfs_alloc_vextent(&args)))
return error; return error;
ap->dfops->dop_low = true; ap->dfops->dop_low = true;
...@@ -4344,8 +4343,6 @@ xfs_bmapi_allocate( ...@@ -4344,8 +4343,6 @@ xfs_bmapi_allocate(
if (error) if (error)
return error; return error;
if (bma->dfops->dop_low)
bma->minleft = 0;
if (bma->cur) if (bma->cur)
bma->cur->bc_private.b.firstblock = *bma->firstblock; bma->cur->bc_private.b.firstblock = *bma->firstblock;
if (bma->blkno == NULLFSBLOCK) if (bma->blkno == NULLFSBLOCK)
......
...@@ -502,12 +502,11 @@ xfs_bmbt_alloc_block( ...@@ -502,12 +502,11 @@ xfs_bmbt_alloc_block(
if (args.fsbno == NULLFSBLOCK && args.minleft) { if (args.fsbno == NULLFSBLOCK && args.minleft) {
/* /*
* Could not find an AG with enough free space to satisfy * Could not find an AG with enough free space to satisfy
* a full btree split. Try again without minleft and if * a full btree split. Try again and if
* successful activate the lowspace algorithm. * successful activate the lowspace algorithm.
*/ */
args.fsbno = 0; args.fsbno = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG; args.type = XFS_ALLOCTYPE_FIRST_AG;
args.minleft = 0;
error = xfs_alloc_vextent(&args); error = xfs_alloc_vextent(&args);
if (error) if (error)
goto error0; goto error0;
......
...@@ -1152,19 +1152,22 @@ xfs_vm_releasepage( ...@@ -1152,19 +1152,22 @@ xfs_vm_releasepage(
* block_invalidatepage() can send pages that are still marked dirty * block_invalidatepage() can send pages that are still marked dirty
* but otherwise have invalidated buffers. * but otherwise have invalidated buffers.
* *
* We've historically freed buffers on the latter. Instead, quietly * We want to release the latter to avoid unnecessary buildup of the
* filter out all dirty pages to avoid spurious buffer state warnings. * LRU, skip the former and warn if we've left any lingering
* This can likely be removed once shrink_active_list() is fixed. * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
* or unwritten buffers and warn if the page is not dirty. Otherwise
* try to release the buffers.
*/ */
if (PageDirty(page))
return 0;
xfs_count_page_state(page, &delalloc, &unwritten); xfs_count_page_state(page, &delalloc, &unwritten);
if (WARN_ON_ONCE(delalloc)) if (delalloc) {
WARN_ON_ONCE(!PageDirty(page));
return 0; return 0;
if (WARN_ON_ONCE(unwritten)) }
if (unwritten) {
WARN_ON_ONCE(!PageDirty(page));
return 0; return 0;
}
return try_to_free_buffers(page); return try_to_free_buffers(page);
} }
......
...@@ -3317,12 +3317,8 @@ xfs_log_force( ...@@ -3317,12 +3317,8 @@ xfs_log_force(
xfs_mount_t *mp, xfs_mount_t *mp,
uint flags) uint flags)
{ {
int error;
trace_xfs_log_force(mp, 0, _RET_IP_); trace_xfs_log_force(mp, 0, _RET_IP_);
error = _xfs_log_force(mp, flags, NULL); _xfs_log_force(mp, flags, NULL);
if (error)
xfs_warn(mp, "%s: error %d returned.", __func__, error);
} }
/* /*
...@@ -3466,12 +3462,8 @@ xfs_log_force_lsn( ...@@ -3466,12 +3462,8 @@ xfs_log_force_lsn(
xfs_lsn_t lsn, xfs_lsn_t lsn,
uint flags) uint flags)
{ {
int error;
trace_xfs_log_force(mp, lsn, _RET_IP_); trace_xfs_log_force(mp, lsn, _RET_IP_);
error = _xfs_log_force_lsn(mp, lsn, flags, NULL); _xfs_log_force_lsn(mp, lsn, flags, NULL);
if (error)
xfs_warn(mp, "%s: error %d returned.", __func__, error);
} }
/* /*
......
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