diff options
Diffstat (limited to 'fs/buffer.c')
-rw-r--r-- | fs/buffer.c | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 5287be18633b..55023231e460 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2160,11 +2160,12 @@ int block_read_full_page(struct page *page, get_block_t *get_block) | |||
2160 | * truncates. Uses prepare/commit_write to allow the filesystem to | 2160 | * truncates. Uses prepare/commit_write to allow the filesystem to |
2161 | * deal with the hole. | 2161 | * deal with the hole. |
2162 | */ | 2162 | */ |
2163 | int generic_cont_expand(struct inode *inode, loff_t size) | 2163 | static int __generic_cont_expand(struct inode *inode, loff_t size, |
2164 | pgoff_t index, unsigned int offset) | ||
2164 | { | 2165 | { |
2165 | struct address_space *mapping = inode->i_mapping; | 2166 | struct address_space *mapping = inode->i_mapping; |
2166 | struct page *page; | 2167 | struct page *page; |
2167 | unsigned long index, offset, limit; | 2168 | unsigned long limit; |
2168 | int err; | 2169 | int err; |
2169 | 2170 | ||
2170 | err = -EFBIG; | 2171 | err = -EFBIG; |
@@ -2176,24 +2177,24 @@ int generic_cont_expand(struct inode *inode, loff_t size) | |||
2176 | if (size > inode->i_sb->s_maxbytes) | 2177 | if (size > inode->i_sb->s_maxbytes) |
2177 | goto out; | 2178 | goto out; |
2178 | 2179 | ||
2179 | offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */ | ||
2180 | |||
2181 | /* ugh. in prepare/commit_write, if from==to==start of block, we | ||
2182 | ** skip the prepare. make sure we never send an offset for the start | ||
2183 | ** of a block | ||
2184 | */ | ||
2185 | if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) { | ||
2186 | offset++; | ||
2187 | } | ||
2188 | index = size >> PAGE_CACHE_SHIFT; | ||
2189 | err = -ENOMEM; | 2180 | err = -ENOMEM; |
2190 | page = grab_cache_page(mapping, index); | 2181 | page = grab_cache_page(mapping, index); |
2191 | if (!page) | 2182 | if (!page) |
2192 | goto out; | 2183 | goto out; |
2193 | err = mapping->a_ops->prepare_write(NULL, page, offset, offset); | 2184 | err = mapping->a_ops->prepare_write(NULL, page, offset, offset); |
2194 | if (!err) { | 2185 | if (err) { |
2195 | err = mapping->a_ops->commit_write(NULL, page, offset, offset); | 2186 | /* |
2187 | * ->prepare_write() may have instantiated a few blocks | ||
2188 | * outside i_size. Trim these off again. | ||
2189 | */ | ||
2190 | unlock_page(page); | ||
2191 | page_cache_release(page); | ||
2192 | vmtruncate(inode, inode->i_size); | ||
2193 | goto out; | ||
2196 | } | 2194 | } |
2195 | |||
2196 | err = mapping->a_ops->commit_write(NULL, page, offset, offset); | ||
2197 | |||
2197 | unlock_page(page); | 2198 | unlock_page(page); |
2198 | page_cache_release(page); | 2199 | page_cache_release(page); |
2199 | if (err > 0) | 2200 | if (err > 0) |
@@ -2202,6 +2203,36 @@ out: | |||
2202 | return err; | 2203 | return err; |
2203 | } | 2204 | } |
2204 | 2205 | ||
2206 | int generic_cont_expand(struct inode *inode, loff_t size) | ||
2207 | { | ||
2208 | pgoff_t index; | ||
2209 | unsigned int offset; | ||
2210 | |||
2211 | offset = (size & (PAGE_CACHE_SIZE - 1)); /* Within page */ | ||
2212 | |||
2213 | /* ugh. in prepare/commit_write, if from==to==start of block, we | ||
2214 | ** skip the prepare. make sure we never send an offset for the start | ||
2215 | ** of a block | ||
2216 | */ | ||
2217 | if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) { | ||
2218 | /* caller must handle this extra byte. */ | ||
2219 | offset++; | ||
2220 | } | ||
2221 | index = size >> PAGE_CACHE_SHIFT; | ||
2222 | |||
2223 | return __generic_cont_expand(inode, size, index, offset); | ||
2224 | } | ||
2225 | |||
2226 | int generic_cont_expand_simple(struct inode *inode, loff_t size) | ||
2227 | { | ||
2228 | loff_t pos = size - 1; | ||
2229 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | ||
2230 | unsigned int offset = (pos & (PAGE_CACHE_SIZE - 1)) + 1; | ||
2231 | |||
2232 | /* prepare/commit_write can handle even if from==to==start of block. */ | ||
2233 | return __generic_cont_expand(inode, size, index, offset); | ||
2234 | } | ||
2235 | |||
2205 | /* | 2236 | /* |
2206 | * For moronic filesystems that do not allow holes in file. | 2237 | * For moronic filesystems that do not allow holes in file. |
2207 | * We may have to extend the file. | 2238 | * We may have to extend the file. |
@@ -3145,6 +3176,7 @@ EXPORT_SYMBOL(fsync_bdev); | |||
3145 | EXPORT_SYMBOL(generic_block_bmap); | 3176 | EXPORT_SYMBOL(generic_block_bmap); |
3146 | EXPORT_SYMBOL(generic_commit_write); | 3177 | EXPORT_SYMBOL(generic_commit_write); |
3147 | EXPORT_SYMBOL(generic_cont_expand); | 3178 | EXPORT_SYMBOL(generic_cont_expand); |
3179 | EXPORT_SYMBOL(generic_cont_expand_simple); | ||
3148 | EXPORT_SYMBOL(init_buffer); | 3180 | EXPORT_SYMBOL(init_buffer); |
3149 | EXPORT_SYMBOL(invalidate_bdev); | 3181 | EXPORT_SYMBOL(invalidate_bdev); |
3150 | EXPORT_SYMBOL(ll_rw_block); | 3182 | EXPORT_SYMBOL(ll_rw_block); |