aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 0f9006714230..02ebb1f1d3b0 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2194,6 +2194,52 @@ int generic_commit_write(struct file *file, struct page *page,
2194 return 0; 2194 return 0;
2195} 2195}
2196 2196
2197/*
2198 * block_page_mkwrite() is not allowed to change the file size as it gets
2199 * called from a page fault handler when a page is first dirtied. Hence we must
2200 * be careful to check for EOF conditions here. We set the page up correctly
2201 * for a written page which means we get ENOSPC checking when writing into
2202 * holes and correct delalloc and unwritten extent mapping on filesystems that
2203 * support these features.
2204 *
2205 * We are not allowed to take the i_mutex here so we have to play games to
2206 * protect against truncate races as the page could now be beyond EOF. Because
2207 * vmtruncate() writes the inode size before removing pages, once we have the
2208 * page lock we can determine safely if the page is beyond EOF. If it is not
2209 * beyond EOF, then the page is guaranteed safe against truncation until we
2210 * unlock the page.
2211 */
2212int
2213block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
2214 get_block_t get_block)
2215{
2216 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
2217 unsigned long end;
2218 loff_t size;
2219 int ret = -EINVAL;
2220
2221 lock_page(page);
2222 size = i_size_read(inode);
2223 if ((page->mapping != inode->i_mapping) ||
2224 ((page->index << PAGE_CACHE_SHIFT) > size)) {
2225 /* page got truncated out from underneath us */
2226 goto out_unlock;
2227 }
2228
2229 /* page is wholly or partially inside EOF */
2230 if (((page->index + 1) << PAGE_CACHE_SHIFT) > size)
2231 end = size & ~PAGE_CACHE_MASK;
2232 else
2233 end = PAGE_CACHE_SIZE;
2234
2235 ret = block_prepare_write(page, 0, end, get_block);
2236 if (!ret)
2237 ret = block_commit_write(page, 0, end);
2238
2239out_unlock:
2240 unlock_page(page);
2241 return ret;
2242}
2197 2243
2198/* 2244/*
2199 * nobh_prepare_write()'s prereads are special: the buffer_heads are freed 2245 * nobh_prepare_write()'s prereads are special: the buffer_heads are freed
@@ -2977,6 +3023,7 @@ EXPORT_SYMBOL(__brelse);
2977EXPORT_SYMBOL(__wait_on_buffer); 3023EXPORT_SYMBOL(__wait_on_buffer);
2978EXPORT_SYMBOL(block_commit_write); 3024EXPORT_SYMBOL(block_commit_write);
2979EXPORT_SYMBOL(block_prepare_write); 3025EXPORT_SYMBOL(block_prepare_write);
3026EXPORT_SYMBOL(block_page_mkwrite);
2980EXPORT_SYMBOL(block_read_full_page); 3027EXPORT_SYMBOL(block_read_full_page);
2981EXPORT_SYMBOL(block_sync_page); 3028EXPORT_SYMBOL(block_sync_page);
2982EXPORT_SYMBOL(block_truncate_page); 3029EXPORT_SYMBOL(block_truncate_page);