aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r--fs/gfs2/bmap.c67
1 files changed, 62 insertions, 5 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 98fa07c2b710..72b19c5d7807 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -48,6 +48,65 @@ struct strip_mine {
48}; 48};
49 49
50/** 50/**
51 * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
52 * @ip: the inode
53 * @dibh: the dinode buffer
54 * @block: the block number that was allocated
55 * @private: any locked page held by the caller process
56 *
57 * Returns: errno
58 */
59
60static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
61 uint64_t block, struct page *page)
62{
63 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
64 struct inode *inode = &ip->i_inode;
65 struct buffer_head *bh;
66 int release = 0;
67
68 if (!page || page->index) {
69 page = grab_cache_page(inode->i_mapping, 0);
70 if (!page)
71 return -ENOMEM;
72 release = 1;
73 }
74
75 if (!PageUptodate(page)) {
76 void *kaddr = kmap(page);
77
78 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
79 ip->i_di.di_size);
80 memset(kaddr + ip->i_di.di_size, 0,
81 PAGE_CACHE_SIZE - ip->i_di.di_size);
82 kunmap(page);
83
84 SetPageUptodate(page);
85 }
86
87 if (!page_has_buffers(page))
88 create_empty_buffers(page, 1 << inode->i_blkbits,
89 (1 << BH_Uptodate));
90
91 bh = page_buffers(page);
92
93 if (!buffer_mapped(bh))
94 map_bh(bh, inode->i_sb, block);
95
96 set_buffer_uptodate(bh);
97 if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED) || gfs2_is_jdata(ip))
98 gfs2_trans_add_bh(ip->i_gl, bh, 0);
99 mark_buffer_dirty(bh);
100
101 if (release) {
102 unlock_page(page);
103 page_cache_release(page);
104 }
105
106 return 0;
107}
108
109/**
51 * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big 110 * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
52 * @ip: The GFS2 inode to unstuff 111 * @ip: The GFS2 inode to unstuff
53 * @unstuffer: the routine that handles unstuffing a non-zero length file 112 * @unstuffer: the routine that handles unstuffing a non-zero length file
@@ -59,8 +118,7 @@ struct strip_mine {
59 * Returns: errno 118 * Returns: errno
60 */ 119 */
61 120
62int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, 121int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
63 void *private)
64{ 122{
65 struct buffer_head *bh, *dibh; 123 struct buffer_head *bh, *dibh;
66 uint64_t block = 0; 124 uint64_t block = 0;
@@ -90,7 +148,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer,
90 } else { 148 } else {
91 block = gfs2_alloc_data(ip); 149 block = gfs2_alloc_data(ip);
92 150
93 error = unstuffer(ip, dibh, block, private); 151 error = gfs2_unstuffer_page(ip, dibh, block, page);
94 if (error) 152 if (error)
95 goto out_brelse; 153 goto out_brelse;
96 } 154 }
@@ -786,8 +844,7 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size)
786 844
787 if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { 845 if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
788 if (gfs2_is_stuffed(ip)) { 846 if (gfs2_is_stuffed(ip)) {
789 error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, 847 error = gfs2_unstuff_dinode(ip, NULL);
790 NULL);
791 if (error) 848 if (error)
792 goto out_end_trans; 849 goto out_end_trans;
793 } 850 }