diff options
Diffstat (limited to 'fs/buffer.c')
-rw-r--r-- | fs/buffer.c | 47 |
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 | */ | ||
2212 | int | ||
2213 | block_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 | |||
2239 | out_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); | |||
2977 | EXPORT_SYMBOL(__wait_on_buffer); | 3023 | EXPORT_SYMBOL(__wait_on_buffer); |
2978 | EXPORT_SYMBOL(block_commit_write); | 3024 | EXPORT_SYMBOL(block_commit_write); |
2979 | EXPORT_SYMBOL(block_prepare_write); | 3025 | EXPORT_SYMBOL(block_prepare_write); |
3026 | EXPORT_SYMBOL(block_page_mkwrite); | ||
2980 | EXPORT_SYMBOL(block_read_full_page); | 3027 | EXPORT_SYMBOL(block_read_full_page); |
2981 | EXPORT_SYMBOL(block_sync_page); | 3028 | EXPORT_SYMBOL(block_sync_page); |
2982 | EXPORT_SYMBOL(block_truncate_page); | 3029 | EXPORT_SYMBOL(block_truncate_page); |