]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
GFS2: Clean up stuffed file copying
authorSteven Whitehouse <swhiteho@redhat.com>
Thu, 25 Mar 2010 14:32:43 +0000 (14:32 +0000)
committerSteven Whitehouse <swhiteho@redhat.com>
Mon, 29 Mar 2010 13:29:17 +0000 (14:29 +0100)
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>
fs/gfs2/aops.c
fs/gfs2/bmap.c

index 0c1d0b82dcf1042f6cf5a431ffe6aa8f57b935bb..a739a0a480670698cb06ed9106a9f710981f3a96 100644 (file)
@@ -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;
 
@@ -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);
index 583e823307ae7a17cd58b34027f11cea4e3f6437..0db0cd92a38d92f7dcf882c2d942b037c632da17 100644 (file)
@@ -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);
@@ -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);