Skip to content

Commit

Permalink
xfs: block allocation work needs to be kswapd aware
Browse files Browse the repository at this point in the history
Upon memory pressure, kswapd calls xfs_vm_writepage() from
shrink_page_list(). This can result in delayed allocation occurring
and that gets deferred to the the allocation workqueue.

The allocation then runs outside kswapd context, which means if it
needs memory (and it does to demand page metadata from disk) it can
block in shrink_inactive_list() waiting for IO congestion. These
blocking waits are normally avoiding in kswapd context, so under
memory pressure writeback from kswapd can be arbitrarily delayed by
memory reclaim.

To avoid this, pass the kswapd context to the allocation being done
by the workqueue, so that memory reclaim understands correctly that
the work is being done for kswapd and therefore it is not blocked
and does not delay memory reclaim.

To avoid issues with int->char conversion of flag fields (as noticed
in v1 of this patch) convert the flag fields in the struct
xfs_bmalloca to bool types. pahole indicates these variables are
still single byte variables, so no extra space is consumed by this
change.

cc: <stable@vger.kernel.org>
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
  • Loading branch information
Dave Chinner authored and Dave Chinner committed Jun 6, 2014
1 parent d6d211d commit 1f6d648
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 9 deletions.
16 changes: 13 additions & 3 deletions fs/xfs/xfs_bmap_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,23 @@ xfs_bmapi_allocate_worker(
struct xfs_bmalloca *args = container_of(work,
struct xfs_bmalloca, work);
unsigned long pflags;
unsigned long new_pflags = PF_FSTRANS;

/* we are in a transaction context here */
current_set_flags_nested(&pflags, PF_FSTRANS);
/*
* we are in a transaction context here, but may also be doing work
* in kswapd context, and hence we may need to inherit that state
* temporarily to ensure that we don't block waiting for memory reclaim
* in any way.
*/
if (args->kswapd)
new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;

current_set_flags_nested(&pflags, new_pflags);

args->result = __xfs_bmapi_allocate(args);
complete(args->done);

current_restore_flags_nested(&pflags, PF_FSTRANS);
current_restore_flags_nested(&pflags, new_pflags);
}

/*
Expand All @@ -284,6 +293,7 @@ xfs_bmapi_allocate(


args->done = &done;
args->kswapd = current_is_kswapd();
INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker);
queue_work(xfs_alloc_wq, &args->work);
wait_for_completion(&done);
Expand Down
13 changes: 7 additions & 6 deletions fs/xfs/xfs_bmap_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ struct xfs_bmalloca {
xfs_extlen_t total; /* total blocks needed for xaction */
xfs_extlen_t minlen; /* minimum allocation size (blocks) */
xfs_extlen_t minleft; /* amount must be left after alloc */
char eof; /* set if allocating past last extent */
char wasdel; /* replacing a delayed allocation */
char userdata;/* set if is user data */
char aeof; /* allocated space at eof */
char conv; /* overwriting unwritten extents */
char stack_switch;
bool eof; /* set if allocating past last extent */
bool wasdel; /* replacing a delayed allocation */
bool userdata;/* set if is user data */
bool aeof; /* allocated space at eof */
bool conv; /* overwriting unwritten extents */
bool stack_switch;
bool kswapd; /* allocation in kswapd context */
int flags;
struct completion *done;
struct work_struct work;
Expand Down

0 comments on commit 1f6d648

Please sign in to comment.