diff options
-rw-r--r-- | fs/gfs2/lops.c | 11 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 33 |
2 files changed, 40 insertions, 4 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 08de8b7fb31..0ec38b39909 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -592,6 +592,17 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) gfs2_log_lock(sdp); if (n++ > num) break; + } else if (!bd1->bd_bh) { + total_dbuf--; + sdp->sd_log_num_databuf--; + list_del_init(&bd1->bd_le.le_list); + if (bd1 == bd2) { + bd2 = NULL; + bd2 = list_prepare_entry(bd2, + &sdp->sd_log_le_databuf, + bd_le.le_list); + } + kmem_cache_free(gfs2_bufdata_cachep, bd1); } } gfs2_log_unlock(sdp); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 48720421c79..0de7a952363 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -118,6 +118,25 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, return error; } +static int get_block_direct(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + int new = 0; + u64 dblock; + int error, boundary; + + error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); + if (error) + return error; + + if (dblock) { + map_bh(bh_result, inode->i_sb, dblock); + if (boundary) + set_buffer_boundary(bh_result); + } + + return 0; +} /** * gfs2_writepage - Write complete page * @page: Page to write @@ -661,7 +680,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, rv = blockdev_direct_IO_own_locking(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, - gfs2_get_block, NULL); + get_block_direct, NULL); out: gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); @@ -724,7 +743,7 @@ static unsigned limit = 0; } /** - * gfs2_aspace_releasepage - free the metadata associated with a page + * gfs2_releasepage - free the metadata associated with a page * @page: the page that's being released * @gfp_mask: passed from Linux VFS, ignored by us * @@ -761,16 +780,22 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) } gfs2_assert_warn(sdp, !buffer_pinned(bh)); + gfs2_assert_warn(sdp, !buffer_dirty(bh)); + gfs2_log_lock(sdp); bd = bh->b_private; if (bd) { gfs2_assert_warn(sdp, bd->bd_bh == bh); gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); - gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); gfs2_assert_warn(sdp, !bd->bd_ail); - kmem_cache_free(gfs2_bufdata_cachep, bd); + bd->bd_bh = NULL; + if (!list_empty(&bd->bd_le.le_list)) + bd = NULL; bh->b_private = NULL; } + gfs2_log_unlock(sdp); + if (bd) + kmem_cache_free(gfs2_bufdata_cachep, bd); bh = bh->b_this_page; } while (bh != head); |