diff options
author | Eric Sandeen <sandeen@redhat.com> | 2008-01-28 23:58:27 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-01-28 23:58:27 -0500 |
commit | e2b4657453c0d5571bd3c7256585c486ed42d364 (patch) | |
tree | 5b8ab501cdf5fa7427ef32440ace56eac72e9ecf | |
parent | 19295529db35381d46dbaf246f69b4e3b3393996 (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>
-rw-r--r-- | fs/ext4/file.c | 19 | ||||
-rw-r--r-- | fs/ext4/inode.c | 16 | ||||
-rw-r--r-- | fs/ext4/super.c | 1 | ||||
-rw-r--r-- | include/linux/ext4_fs_sb.h | 1 |
4 files changed, 35 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) { |
diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h index f15821c5e4c4..38a47ec06df9 100644 --- a/include/linux/ext4_fs_sb.h +++ b/include/linux/ext4_fs_sb.h | |||
@@ -38,6 +38,7 @@ struct ext4_sb_info { | |||
38 | ext4_group_t s_groups_count; /* Number of groups in the fs */ | 38 | ext4_group_t s_groups_count; /* Number of groups in the fs */ |
39 | unsigned long s_overhead_last; /* Last calculated overhead */ | 39 | unsigned long s_overhead_last; /* Last calculated overhead */ |
40 | unsigned long s_blocks_last; /* Last seen block count */ | 40 | unsigned long s_blocks_last; /* Last seen block count */ |
41 | loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ | ||
41 | struct buffer_head * s_sbh; /* Buffer containing the super block */ | 42 | struct buffer_head * s_sbh; /* Buffer containing the super block */ |
42 | struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */ | 43 | struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */ |
43 | struct buffer_head ** s_group_desc; | 44 | struct buffer_head ** s_group_desc; |