aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2010-03-25 10:32:43 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2010-03-29 09:29:17 -0400
commit602c89d2e3e8652f94a697c9a919be739b9bcdd5 (patch)
tree791c0f4ea2b1f9028f7fdf60dbedd42fa0f8ce06
parent4cb947b59c5835783fb96aad2f7d92b1e4250aff (diff)
GFS2: Clean up stuffed file copying
If the inode size was corrupt for stuffed files, it was possible for the copying of data to overrun the block and/or page. This patch checks for that condition so that this is no longer possible. This is also preparation for the new truncate sequence patch which requires the ability to have stuffed files with larger sizes than (disk block size - sizeof(on disk inode)) with the restriction that only the initial part of the file may be non-zero. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/aops.c8
-rw-r--r--fs/gfs2/bmap.c17
2 files changed, 15 insertions, 10 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 0c1d0b82dcf1..a739a0a48067 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -418,6 +418,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping,
418static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) 418static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
419{ 419{
420 struct buffer_head *dibh; 420 struct buffer_head *dibh;
421 u64 dsize = i_size_read(&ip->i_inode);
421 void *kaddr; 422 void *kaddr;
422 int error; 423 int error;
423 424
@@ -437,9 +438,10 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
437 return error; 438 return error;
438 439
439 kaddr = kmap_atomic(page, KM_USER0); 440 kaddr = kmap_atomic(page, KM_USER0);
440 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), 441 if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode)))
441 ip->i_disksize); 442 dsize = (dibh->b_size - sizeof(struct gfs2_dinode));
442 memset(kaddr + ip->i_disksize, 0, PAGE_CACHE_SIZE - ip->i_disksize); 443 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
444 memset(kaddr + dsize, 0, PAGE_CACHE_SIZE - dsize);
443 kunmap_atomic(kaddr, KM_USER0); 445 kunmap_atomic(kaddr, KM_USER0);
444 flush_dcache_page(page); 446 flush_dcache_page(page);
445 brelse(dibh); 447 brelse(dibh);
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 583e823307ae..0db0cd92a38d 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -72,11 +72,13 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
72 72
73 if (!PageUptodate(page)) { 73 if (!PageUptodate(page)) {
74 void *kaddr = kmap(page); 74 void *kaddr = kmap(page);
75 u64 dsize = i_size_read(inode);
76
77 if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode)))
78 dsize = dibh->b_size - sizeof(struct gfs2_dinode);
75 79
76 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), 80 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
77 ip->i_disksize); 81 memset(kaddr + dsize, 0, PAGE_CACHE_SIZE - dsize);
78 memset(kaddr + ip->i_disksize, 0,
79 PAGE_CACHE_SIZE - ip->i_disksize);
80 kunmap(page); 82 kunmap(page);
81 83
82 SetPageUptodate(page); 84 SetPageUptodate(page);
@@ -1039,13 +1041,14 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
1039 goto out; 1041 goto out;
1040 1042
1041 if (gfs2_is_stuffed(ip)) { 1043 if (gfs2_is_stuffed(ip)) {
1042 ip->i_disksize = size; 1044 u64 dsize = size + sizeof(struct gfs2_inode);
1043 ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 1045 ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
1044 gfs2_trans_add_bh(ip->i_gl, dibh, 1); 1046 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
1045 gfs2_dinode_out(ip, dibh->b_data); 1047 gfs2_dinode_out(ip, dibh->b_data);
1046 gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size); 1048 if (dsize > dibh->b_size)
1049 dsize = dibh->b_size;
1050 gfs2_buffer_clear_tail(dibh, dsize);
1047 error = 1; 1051 error = 1;
1048
1049 } else { 1052 } else {
1050 if (size & (u64)(sdp->sd_sb.sb_bsize - 1)) 1053 if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
1051 error = gfs2_block_truncate_page(ip->i_inode.i_mapping); 1054 error = gfs2_block_truncate_page(ip->i_inode.i_mapping);