Message ID | 79781ca99470475ff33382e67571eeb914edac63.1623567940.git.rgoldwyn@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs buffered iomap support | expand |
On 13.06.21 г. 16:39, Goldwyn Rodrigues wrote: > From: Goldwyn Rodrigues <rgoldwyn@suse.com> > > btrfs requires page->private set to get a callback to releasepage(). nit: This is somewhat terse of an explanation and someone not familiar with btrfs might wonder what's going on. In fact, btrfs uses the PagePrivate flag to indicate that the page has undergone CoW and has ordered extents created. And this is in fact problematic because iomap assume page_private is not in use by the underlying fs. So, > for normal circumstances of blocksize==PAGE_SIZE, btrfs will have > page->private set to 1. In order to avoid a crash, check for the > blocksize==PAGE_SIZE in to_iomap_page(). > --- > fs/iomap/buffered-io.c | 10 ++++++---- > 1 file changed, 6 insertions(+), 4 deletions(-) > > diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c > index 9023717c5188..d30683734d01 100644 > --- a/fs/iomap/buffered-io.c > +++ b/fs/iomap/buffered-io.c > @@ -41,9 +41,11 @@ static inline struct iomap_page *to_iomap_page(struct page *page) > */ > VM_BUG_ON_PGFLAGS(PageTail(page), page); > > - if (page_has_private(page)) > - return (struct iomap_page *)page_private(page); > - return NULL; > + if (i_blocksize(page->mapping->host) == PAGE_SIZE) > + return NULL; > + if (!page_has_private(page)) > + return NULL; > + return (struct iomap_page *)page_private(page); > } > > static struct bio_set iomap_ioend_bioset; > @@ -163,7 +165,7 @@ iomap_set_range_uptodate(struct page *page, unsigned off, unsigned len) > if (PageError(page)) > return; > > - if (page_has_private(page)) > + if (i_blocksize(page->mapping->host) != PAGE_SIZE) > iomap_iop_set_range_uptodate(page, off, len); > else > SetPageUptodate(page); >
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 9023717c5188..d30683734d01 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -41,9 +41,11 @@ static inline struct iomap_page *to_iomap_page(struct page *page) */ VM_BUG_ON_PGFLAGS(PageTail(page), page); - if (page_has_private(page)) - return (struct iomap_page *)page_private(page); - return NULL; + if (i_blocksize(page->mapping->host) == PAGE_SIZE) + return NULL; + if (!page_has_private(page)) + return NULL; + return (struct iomap_page *)page_private(page); } static struct bio_set iomap_ioend_bioset; @@ -163,7 +165,7 @@ iomap_set_range_uptodate(struct page *page, unsigned off, unsigned len) if (PageError(page)) return; - if (page_has_private(page)) + if (i_blocksize(page->mapping->host) != PAGE_SIZE) iomap_iop_set_range_uptodate(page, off, len); else SetPageUptodate(page);
From: Goldwyn Rodrigues <rgoldwyn@suse.com> btrfs requires page->private set to get a callback to releasepage(). So, for normal circumstances of blocksize==PAGE_SIZE, btrfs will have page->private set to 1. In order to avoid a crash, check for the blocksize==PAGE_SIZE in to_iomap_page(). --- fs/iomap/buffered-io.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)