Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b969c4ab authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds
Browse files

mm: compaction: determine if dirty pages can be migrated without blocking within ->migratepage



Asynchronous compaction is used when allocating transparent hugepages to
avoid blocking for long periods of time.  Due to reports of stalling,
there was a debate on disabling synchronous compaction but this severely
impacted allocation success rates.  Part of the reason was that many dirty
pages are skipped in asynchronous compaction by the following check;

	if (PageDirty(page) && !sync &&
		mapping->a_ops->migratepage != migrate_page)
			rc = -EBUSY;

This skips over all mapping aops using buffer_migrate_page() even though
it is possible to migrate some of these pages without blocking.  This
patch updates the ->migratepage callback with a "sync" parameter.  It is
the responsibility of the callback to fail gracefully if migration would
block.

Signed-off-by: default avatarMel Gorman <mgorman@suse.de>
Reviewed-by: default avatarRik van Riel <riel@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: Dave Jones <davej@redhat.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Andy Isaacson <adi@hexapodia.org>
Cc: Nai Xia <nai.xia@gmail.com>
Cc: Johannes Weiner <jweiner@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7335084d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -872,7 +872,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,

#ifdef CONFIG_MIGRATION
static int btree_migratepage(struct address_space *mapping,
			struct page *newpage, struct page *page)
			struct page *newpage, struct page *page, bool sync)
{
	/*
	 * we can't safely write a btree page from here,
@@ -887,7 +887,7 @@ static int btree_migratepage(struct address_space *mapping,
	if (page_has_private(page) &&
	    !try_to_release_page(page, GFP_KERNEL))
		return -EAGAIN;
	return migrate_page(mapping, newpage, page);
	return migrate_page(mapping, newpage, page, sync);
}
#endif

+2 −1
Original line number Diff line number Diff line
@@ -583,7 +583,8 @@ static int hugetlbfs_set_page_dirty(struct page *page)
}

static int hugetlbfs_migrate_page(struct address_space *mapping,
				struct page *newpage, struct page *page)
				struct page *newpage, struct page *page,
				bool sync)
{
	int rc;

+1 −1
Original line number Diff line number Diff line
@@ -332,7 +332,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data);

#ifdef CONFIG_MIGRATION
extern int nfs_migrate_page(struct address_space *,
		struct page *, struct page *);
		struct page *, struct page *, bool);
#else
#define nfs_migrate_page NULL
#endif
+2 −2
Original line number Diff line number Diff line
@@ -1688,7 +1688,7 @@ int nfs_wb_page(struct inode *inode, struct page *page)

#ifdef CONFIG_MIGRATION
int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
		struct page *page)
		struct page *page, bool sync)
{
	/*
	 * If PagePrivate is set, then the page is currently associated with
@@ -1703,7 +1703,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,

	nfs_fscache_release_page(page, GFP_KERNEL);

	return migrate_page(mapping, newpage, page);
	return migrate_page(mapping, newpage, page, sync);
}
#endif

+6 −3
Original line number Diff line number Diff line
@@ -609,9 +609,12 @@ struct address_space_operations {
			loff_t offset, unsigned long nr_segs);
	int (*get_xip_mem)(struct address_space *, pgoff_t, int,
						void **, unsigned long *);
	/* migrate the contents of a page to the specified target */
	/*
	 * migrate the contents of a page to the specified target. If sync
	 * is false, it must not block.
	 */
	int (*migratepage) (struct address_space *,
			struct page *, struct page *);
			struct page *, struct page *, bool);
	int (*launder_page) (struct page *);
	int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
					unsigned long);
@@ -2537,7 +2540,7 @@ extern int generic_check_addressable(unsigned, u64);

#ifdef CONFIG_MIGRATION
extern int buffer_migrate_page(struct address_space *,
				struct page *, struct page *);
				struct page *, struct page *, bool);
#else
#define buffer_migrate_page NULL
#endif
Loading