Skip to content

Commit

Permalink
GFS2: Clean up stuffed file copying
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Steven Whitehouse committed Mar 29, 2010
1 parent 4cb947b commit 602c89d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 10 deletions.
8 changes: 5 additions & 3 deletions fs/gfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping,
static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
{
struct buffer_head *dibh;
u64 dsize = i_size_read(&ip->i_inode);
void *kaddr;
int error;

Expand All @@ -437,9 +438,10 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
return error;

kaddr = kmap_atomic(page, KM_USER0);
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
ip->i_disksize);
memset(kaddr + ip->i_disksize, 0, PAGE_CACHE_SIZE - ip->i_disksize);
if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode)))
dsize = (dibh->b_size - sizeof(struct gfs2_dinode));
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
memset(kaddr + dsize, 0, PAGE_CACHE_SIZE - dsize);
kunmap_atomic(kaddr, KM_USER0);
flush_dcache_page(page);
brelse(dibh);
Expand Down
17 changes: 10 additions & 7 deletions fs/gfs2/bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,

if (!PageUptodate(page)) {
void *kaddr = kmap(page);
u64 dsize = i_size_read(inode);

if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode)))
dsize = dibh->b_size - sizeof(struct gfs2_dinode);

memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
ip->i_disksize);
memset(kaddr + ip->i_disksize, 0,
PAGE_CACHE_SIZE - ip->i_disksize);
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
memset(kaddr + dsize, 0, PAGE_CACHE_SIZE - dsize);
kunmap(page);

SetPageUptodate(page);
Expand Down Expand Up @@ -1039,13 +1041,14 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
goto out;

if (gfs2_is_stuffed(ip)) {
ip->i_disksize = size;
u64 dsize = size + sizeof(struct gfs2_inode);
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
if (dsize > dibh->b_size)
dsize = dibh->b_size;
gfs2_buffer_clear_tail(dibh, dsize);
error = 1;

} else {
if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
Expand Down

0 comments on commit 602c89d

Please sign in to comment.