aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c60
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 */
2163int generic_cont_expand(struct inode *inode, loff_t size) 2163static 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
2206int 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
2226int 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);
3145EXPORT_SYMBOL(generic_block_bmap); 3176EXPORT_SYMBOL(generic_block_bmap);
3146EXPORT_SYMBOL(generic_commit_write); 3177EXPORT_SYMBOL(generic_commit_write);
3147EXPORT_SYMBOL(generic_cont_expand); 3178EXPORT_SYMBOL(generic_cont_expand);
3179EXPORT_SYMBOL(generic_cont_expand_simple);
3148EXPORT_SYMBOL(init_buffer); 3180EXPORT_SYMBOL(init_buffer);
3149EXPORT_SYMBOL(invalidate_bdev); 3181EXPORT_SYMBOL(invalidate_bdev);
3150EXPORT_SYMBOL(ll_rw_block); 3182EXPORT_SYMBOL(ll_rw_block);