Commit 2164f9b9 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Andreas Gruenbacher

gfs2: use iomap for buffered I/O in ordered and writeback mode

Switch to using the iomap readpage and writepage helpers for all I/O in
the ordered and writeback modes, and thus eliminate using buffer_heads
for I/O in these cases.  The journaled data mode is left untouched.

(Andreas Gruenbacher: In gfs2_unstuffer_page, switch from mark_buffer_dirty
to set_page_dirty instead of accidentally leaving the page / buffer clean.)
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent ee1e2c77
...@@ -91,22 +91,13 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) ...@@ -91,22 +91,13 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
loff_t i_size = i_size_read(inode); struct iomap_writepage_ctx wpc = { };
pgoff_t end_index = i_size >> PAGE_SHIFT;
unsigned offset;
if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl)))
goto out; goto out;
if (current->journal_info) if (current->journal_info)
goto redirty; goto redirty;
/* Is the page fully outside i_size? (truncate in progress) */ return iomap_writepage(page, wbc, &wpc, &gfs2_writeback_ops);
offset = i_size & (PAGE_SIZE-1);
if (page->index > end_index || (page->index == end_index && !offset)) {
page->mapping->a_ops->invalidatepage(page, 0, PAGE_SIZE);
goto out;
}
return nobh_writepage(page, gfs2_get_block_noalloc, wbc);
redirty: redirty:
redirty_page_for_writepage(wbc, page); redirty_page_for_writepage(wbc, page);
...@@ -208,7 +199,8 @@ static int gfs2_writepages(struct address_space *mapping, ...@@ -208,7 +199,8 @@ static int gfs2_writepages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping); struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
int ret = mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); struct iomap_writepage_ctx wpc = { };
int ret;
/* /*
* Even if we didn't write any pages here, we might still be holding * Even if we didn't write any pages here, we might still be holding
...@@ -216,9 +208,9 @@ static int gfs2_writepages(struct address_space *mapping, ...@@ -216,9 +208,9 @@ static int gfs2_writepages(struct address_space *mapping,
* want balance_dirty_pages() to loop indefinitely trying to write out * want balance_dirty_pages() to loop indefinitely trying to write out
* pages held in the ail that it can't find. * pages held in the ail that it can't find.
*/ */
ret = iomap_writepages(mapping, wbc, &wpc, &gfs2_writeback_ops);
if (ret == 0) if (ret == 0)
set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
return ret; return ret;
} }
...@@ -470,12 +462,13 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) ...@@ -470,12 +462,13 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
static int __gfs2_readpage(void *file, struct page *page) static int __gfs2_readpage(void *file, struct page *page)
{ {
struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct inode *inode = page->mapping->host;
struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
int error; int error;
if (i_blocksize(page->mapping->host) == PAGE_SIZE && if (!gfs2_is_jdata(ip) ||
!page_has_buffers(page)) { (i_blocksize(inode) == PAGE_SIZE && !page_has_buffers(page))) {
error = iomap_readpage(page, &gfs2_iomap_ops); error = iomap_readpage(page, &gfs2_iomap_ops);
} else if (gfs2_is_stuffed(ip)) { } else if (gfs2_is_stuffed(ip)) {
error = stuffed_readpage(ip, page); error = stuffed_readpage(ip, page);
...@@ -563,8 +556,12 @@ static void gfs2_readahead(struct readahead_control *rac) ...@@ -563,8 +556,12 @@ static void gfs2_readahead(struct readahead_control *rac)
struct inode *inode = rac->mapping->host; struct inode *inode = rac->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
if (!gfs2_is_stuffed(ip)) if (gfs2_is_stuffed(ip))
;
else if (gfs2_is_jdata(ip))
mpage_readahead(rac, gfs2_block_map); mpage_readahead(rac, gfs2_block_map);
else
iomap_readahead(rac, &gfs2_iomap_ops);
} }
/** /**
...@@ -784,12 +781,13 @@ static const struct address_space_operations gfs2_aops = { ...@@ -784,12 +781,13 @@ static const struct address_space_operations gfs2_aops = {
.writepages = gfs2_writepages, .writepages = gfs2_writepages,
.readpage = gfs2_readpage, .readpage = gfs2_readpage,
.readahead = gfs2_readahead, .readahead = gfs2_readahead,
.set_page_dirty = iomap_set_page_dirty,
.releasepage = iomap_releasepage,
.invalidatepage = iomap_invalidatepage,
.bmap = gfs2_bmap, .bmap = gfs2_bmap,
.invalidatepage = gfs2_invalidatepage,
.releasepage = gfs2_releasepage,
.direct_IO = noop_direct_IO, .direct_IO = noop_direct_IO,
.migratepage = buffer_migrate_page, .migratepage = iomap_migrate_page,
.is_partially_uptodate = block_is_partially_uptodate, .is_partially_uptodate = iomap_is_partially_uptodate,
.error_remove_page = generic_error_remove_page, .error_remove_page = generic_error_remove_page,
}; };
......
...@@ -56,7 +56,6 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -56,7 +56,6 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
u64 block, struct page *page) u64 block, struct page *page)
{ {
struct inode *inode = &ip->i_inode; struct inode *inode = &ip->i_inode;
struct buffer_head *bh;
int release = 0; int release = 0;
if (!page || page->index) { if (!page || page->index) {
...@@ -80,20 +79,21 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -80,20 +79,21 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
SetPageUptodate(page); SetPageUptodate(page);
} }
if (gfs2_is_jdata(ip)) {
struct buffer_head *bh;
if (!page_has_buffers(page)) if (!page_has_buffers(page))
create_empty_buffers(page, BIT(inode->i_blkbits), create_empty_buffers(page, BIT(inode->i_blkbits),
BIT(BH_Uptodate)); BIT(BH_Uptodate));
bh = page_buffers(page); bh = page_buffers(page);
if (!buffer_mapped(bh)) if (!buffer_mapped(bh))
map_bh(bh, inode->i_sb, block); map_bh(bh, inode->i_sb, block);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
if (gfs2_is_jdata(ip))
gfs2_trans_add_data(ip->i_gl, bh); gfs2_trans_add_data(ip->i_gl, bh);
else { } else {
mark_buffer_dirty(bh); set_page_dirty(page);
gfs2_ordered_add_inode(ip); gfs2_ordered_add_inode(ip);
} }
...@@ -1158,6 +1158,7 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, ...@@ -1158,6 +1158,7 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
struct metapath mp = { .mp_aheight = 1, }; struct metapath mp = { .mp_aheight = 1, };
int ret; int ret;
if (gfs2_is_jdata(ip))
iomap->flags |= IOMAP_F_BUFFER_HEAD; iomap->flags |= IOMAP_F_BUFFER_HEAD;
trace_gfs2_iomap_start(ip, pos, length, flags); trace_gfs2_iomap_start(ip, pos, length, flags);
...@@ -2518,3 +2519,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) ...@@ -2518,3 +2519,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
return error; return error;
} }
static int gfs2_map_blocks(struct iomap_writepage_ctx *wpc, struct inode *inode,
loff_t offset)
{
struct metapath mp = { .mp_aheight = 1, };
int ret;
if (WARN_ON_ONCE(gfs2_is_stuffed(GFS2_I(inode))))
return -EIO;
if (offset >= wpc->iomap.offset &&
offset < wpc->iomap.offset + wpc->iomap.length)
return 0;
memset(&wpc->iomap, 0, sizeof(wpc->iomap));
ret = gfs2_iomap_get(inode, offset, INT_MAX, 0, &wpc->iomap, &mp);
release_metapath(&mp);
return ret;
}
const struct iomap_writeback_ops gfs2_writeback_ops = {
.map_blocks = gfs2_map_blocks,
};
...@@ -44,6 +44,7 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip, ...@@ -44,6 +44,7 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
} }
extern const struct iomap_ops gfs2_iomap_ops; extern const struct iomap_ops gfs2_iomap_ops;
extern const struct iomap_writeback_ops gfs2_writeback_ops;
extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
extern int gfs2_block_map(struct inode *inode, sector_t lblock, extern int gfs2_block_map(struct inode *inode, sector_t lblock,
......
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