summary refs log tree commit diff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/lops.c11
-rw-r--r--fs/gfs2/ops_address.c33
2 files changed, 40 insertions, 4 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 08de8b7fb316..0ec38b399097 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 48720421c796..0de7a9523633 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);