Skip to content

Commit 89cb088

Browse files
jankaratorvalds
authored andcommitted
mm: migrate: provide buffer_migrate_page_norefs()
Provide a variant of buffer_migrate_page() that also checks whether there are no unexpected references to buffer heads. This function will then be safe to use for block device pages. [akpm@linux-foundation.org: remove EXPORT_SYMBOL(buffer_migrate_page_norefs)] Link: http://lkml.kernel.org/r/20181211172143.7358-5-jack@suse.cz Signed-off-by: Jan Kara <jack@suse.cz> Acked-by: Mel Gorman <mgorman@suse.de> Cc: Michal Hocko <mhocko@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 84ade7c commit 89cb088

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

include/linux/fs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3269,8 +3269,12 @@ extern int generic_check_addressable(unsigned, u64);
32693269
extern int buffer_migrate_page(struct address_space *,
32703270
struct page *, struct page *,
32713271
enum migrate_mode);
3272+
extern int buffer_migrate_page_norefs(struct address_space *,
3273+
struct page *, struct page *,
3274+
enum migrate_mode);
32723275
#else
32733276
#define buffer_migrate_page NULL
3277+
#define buffer_migrate_page_norefs NULL
32743278
#endif
32753279

32763280
extern int setattr_prepare(struct dentry *, struct iattr *);

mm/migrate.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -743,13 +743,9 @@ static bool buffer_migrate_lock_buffers(struct buffer_head *head,
743743
return true;
744744
}
745745

746-
/*
747-
* Migration function for pages with buffers. This function can only be used
748-
* if the underlying filesystem guarantees that no other references to "page"
749-
* exist.
750-
*/
751-
int buffer_migrate_page(struct address_space *mapping,
752-
struct page *newpage, struct page *page, enum migrate_mode mode)
746+
static int __buffer_migrate_page(struct address_space *mapping,
747+
struct page *newpage, struct page *page, enum migrate_mode mode,
748+
bool check_refs)
753749
{
754750
struct buffer_head *bh, *head;
755751
int rc;
@@ -767,6 +763,33 @@ int buffer_migrate_page(struct address_space *mapping,
767763
if (!buffer_migrate_lock_buffers(head, mode))
768764
return -EAGAIN;
769765

766+
if (check_refs) {
767+
bool busy;
768+
bool invalidated = false;
769+
770+
recheck_buffers:
771+
busy = false;
772+
spin_lock(&mapping->private_lock);
773+
bh = head;
774+
do {
775+
if (atomic_read(&bh->b_count)) {
776+
busy = true;
777+
break;
778+
}
779+
bh = bh->b_this_page;
780+
} while (bh != head);
781+
spin_unlock(&mapping->private_lock);
782+
if (busy) {
783+
if (invalidated) {
784+
rc = -EAGAIN;
785+
goto unlock_buffers;
786+
}
787+
invalidate_bh_lrus();
788+
invalidated = true;
789+
goto recheck_buffers;
790+
}
791+
}
792+
770793
rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode, 0);
771794
if (rc != MIGRATEPAGE_SUCCESS)
772795
goto unlock_buffers;
@@ -803,7 +826,30 @@ int buffer_migrate_page(struct address_space *mapping,
803826

804827
return rc;
805828
}
829+
830+
/*
831+
* Migration function for pages with buffers. This function can only be used
832+
* if the underlying filesystem guarantees that no other references to "page"
833+
* exist. For example attached buffer heads are accessed only under page lock.
834+
*/
835+
int buffer_migrate_page(struct address_space *mapping,
836+
struct page *newpage, struct page *page, enum migrate_mode mode)
837+
{
838+
return __buffer_migrate_page(mapping, newpage, page, mode, false);
839+
}
806840
EXPORT_SYMBOL(buffer_migrate_page);
841+
842+
/*
843+
* Same as above except that this variant is more careful and checks that there
844+
* are also no buffer head references. This function is the right one for
845+
* mappings where buffer heads are directly looked up and referenced (such as
846+
* block device mappings).
847+
*/
848+
int buffer_migrate_page_norefs(struct address_space *mapping,
849+
struct page *newpage, struct page *page, enum migrate_mode mode)
850+
{
851+
return __buffer_migrate_page(mapping, newpage, page, mode, true);
852+
}
807853
#endif
808854

809855
/*

0 commit comments

Comments
 (0)