aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2008-01-28 23:58:27 -0500
committerTheodore Ts'o <tytso@mit.edu>2008-01-28 23:58:27 -0500
commite2b4657453c0d5571bd3c7256585c486ed42d364 (patch)
tree5b8ab501cdf5fa7427ef32440ace56eac72e9ecf /fs/ext4
parent19295529db35381d46dbaf246f69b4e3b3393996 (diff)
ext4: store maxbytes for bitmapped files and return EFBIG as appropriate
Calculate & store the max offset for bitmapped files, and catch too-large seeks, truncates, and writes in ext4, shortening or rejecting as appropriate. Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/file.c19
-rw-r--r--fs/ext4/inode.c16
-rw-r--r--fs/ext4/super.c1
3 files changed, 34 insertions, 2 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 1a81cd66d63b..a6b2aa14626e 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -56,8 +56,25 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
56 ssize_t ret; 56 ssize_t ret;
57 int err; 57 int err;
58 58
59 ret = generic_file_aio_write(iocb, iov, nr_segs, pos); 59 /*
60 * If we have encountered a bitmap-format file, the size limit
61 * is smaller than s_maxbytes, which is for extent-mapped files.
62 */
63
64 if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
65 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
66 size_t length = iov_length(iov, nr_segs);
60 67
68 if (pos > sbi->s_bitmap_maxbytes)
69 return -EFBIG;
70
71 if (pos + length > sbi->s_bitmap_maxbytes) {
72 nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
73 sbi->s_bitmap_maxbytes - pos);
74 }
75 }
76
77 ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
61 /* 78 /*
62 * Skip flushing if there was an error, or if nothing was written. 79 * Skip flushing if there was an error, or if nothing was written.
63 */ 80 */
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9cf85721d83c..eaace1373ccb 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -314,7 +314,10 @@ static int ext4_block_to_path(struct inode *inode,
314 offsets[n++] = i_block & (ptrs - 1); 314 offsets[n++] = i_block & (ptrs - 1);
315 final = ptrs; 315 final = ptrs;
316 } else { 316 } else {
317 ext4_warning(inode->i_sb, "ext4_block_to_path", "block > big"); 317 ext4_warning(inode->i_sb, "ext4_block_to_path",
318 "block %u > max",
319 i_block + direct_blocks +
320 indirect_blocks + double_blocks);
318 } 321 }
319 if (boundary) 322 if (boundary)
320 *boundary = final - 1 - (i_block & (ptrs - 1)); 323 *boundary = final - 1 - (i_block & (ptrs - 1));
@@ -3092,6 +3095,17 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
3092 ext4_journal_stop(handle); 3095 ext4_journal_stop(handle);
3093 } 3096 }
3094 3097
3098 if (attr->ia_valid & ATTR_SIZE) {
3099 if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
3100 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
3101
3102 if (attr->ia_size > sbi->s_bitmap_maxbytes) {
3103 error = -EFBIG;
3104 goto err_out;
3105 }
3106 }
3107 }
3108
3095 if (S_ISREG(inode->i_mode) && 3109 if (S_ISREG(inode->i_mode) &&
3096 attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { 3110 attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
3097 handle_t *handle; 3111 handle_t *handle;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c79e46b7f159..0931831537a2 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1922,6 +1922,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
1922 } 1922 }
1923 } 1923 }
1924 1924
1925 sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits);
1925 sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits); 1926 sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
1926 1927
1927 if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { 1928 if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {