diff options
| -rw-r--r-- | fs/buffer.c | 47 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 16 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 30 | ||||
| -rw-r--r-- | include/linux/buffer_head.h | 2 |
4 files changed, 93 insertions, 2 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); |
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 2d4be2f247b2..0d4001eafd16 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
| @@ -413,6 +413,20 @@ xfs_file_open_exec( | |||
| 413 | } | 413 | } |
| 414 | #endif /* HAVE_FOP_OPEN_EXEC */ | 414 | #endif /* HAVE_FOP_OPEN_EXEC */ |
| 415 | 415 | ||
| 416 | /* | ||
| 417 | * mmap()d file has taken write protection fault and is being made | ||
| 418 | * writable. We can set the page state up correctly for a writable | ||
| 419 | * page, which means we can do correct delalloc accounting (ENOSPC | ||
| 420 | * checking!) and unwritten extent mapping. | ||
| 421 | */ | ||
| 422 | STATIC int | ||
| 423 | xfs_vm_page_mkwrite( | ||
| 424 | struct vm_area_struct *vma, | ||
| 425 | struct page *page) | ||
| 426 | { | ||
| 427 | return block_page_mkwrite(vma, page, xfs_get_blocks); | ||
| 428 | } | ||
| 429 | |||
| 416 | const struct file_operations xfs_file_operations = { | 430 | const struct file_operations xfs_file_operations = { |
| 417 | .llseek = generic_file_llseek, | 431 | .llseek = generic_file_llseek, |
| 418 | .read = do_sync_read, | 432 | .read = do_sync_read, |
| @@ -465,11 +479,13 @@ const struct file_operations xfs_dir_file_operations = { | |||
| 465 | 479 | ||
| 466 | static struct vm_operations_struct xfs_file_vm_ops = { | 480 | static struct vm_operations_struct xfs_file_vm_ops = { |
| 467 | .fault = filemap_fault, | 481 | .fault = filemap_fault, |
| 482 | .page_mkwrite = xfs_vm_page_mkwrite, | ||
| 468 | }; | 483 | }; |
| 469 | 484 | ||
| 470 | #ifdef CONFIG_XFS_DMAPI | 485 | #ifdef CONFIG_XFS_DMAPI |
| 471 | static struct vm_operations_struct xfs_dmapi_file_vm_ops = { | 486 | static struct vm_operations_struct xfs_dmapi_file_vm_ops = { |
| 472 | .fault = xfs_vm_fault, | 487 | .fault = xfs_vm_fault, |
| 488 | .page_mkwrite = xfs_vm_page_mkwrite, | ||
| 473 | #ifdef HAVE_VMOP_MPROTECT | 489 | #ifdef HAVE_VMOP_MPROTECT |
| 474 | .mprotect = xfs_vm_mprotect, | 490 | .mprotect = xfs_vm_mprotect, |
| 475 | #endif | 491 | #endif |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 79b522779aa4..1a5ad8cd97b0 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -589,7 +589,30 @@ xfs_setattr( | |||
| 589 | code = xfs_igrow_start(ip, vap->va_size, credp); | 589 | code = xfs_igrow_start(ip, vap->va_size, credp); |
| 590 | } | 590 | } |
| 591 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 591 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 592 | vn_iowait(vp); /* wait for the completion of any pending DIOs */ | 592 | |
| 593 | /* | ||
| 594 | * We are going to log the inode size change in this | ||
| 595 | * transaction so any previous writes that are beyond the on | ||
| 596 | * disk EOF and the new EOF that have not been written out need | ||
| 597 | * to be written here. If we do not write the data out, we | ||
| 598 | * expose ourselves to the null files problem. | ||
| 599 | * | ||
| 600 | * Only flush from the on disk size to the smaller of the in | ||
| 601 | * memory file size or the new size as that's the range we | ||
| 602 | * really care about here and prevents waiting for other data | ||
| 603 | * not within the range we care about here. | ||
| 604 | */ | ||
| 605 | if (!code && | ||
| 606 | (ip->i_size != ip->i_d.di_size) && | ||
| 607 | (vap->va_size > ip->i_d.di_size)) { | ||
| 608 | code = bhv_vop_flush_pages(XFS_ITOV(ip), | ||
| 609 | ip->i_d.di_size, vap->va_size, | ||
| 610 | XFS_B_ASYNC, FI_NONE); | ||
| 611 | } | ||
| 612 | |||
| 613 | /* wait for all I/O to complete */ | ||
| 614 | vn_iowait(vp); | ||
| 615 | |||
| 593 | if (!code) | 616 | if (!code) |
| 594 | code = xfs_itruncate_data(ip, vap->va_size); | 617 | code = xfs_itruncate_data(ip, vap->va_size); |
| 595 | if (code) { | 618 | if (code) { |
| @@ -4434,9 +4457,12 @@ xfs_free_file_space( | |||
| 4434 | while (!error && !done) { | 4457 | while (!error && !done) { |
| 4435 | 4458 | ||
| 4436 | /* | 4459 | /* |
| 4437 | * allocate and setup the transaction | 4460 | * allocate and setup the transaction. Allow this |
| 4461 | * transaction to dip into the reserve blocks to ensure | ||
| 4462 | * the freeing of the space succeeds at ENOSPC. | ||
| 4438 | */ | 4463 | */ |
| 4439 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | 4464 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); |
| 4465 | tp->t_flags |= XFS_TRANS_RESERVE; | ||
| 4440 | error = xfs_trans_reserve(tp, | 4466 | error = xfs_trans_reserve(tp, |
| 4441 | resblks, | 4467 | resblks, |
| 4442 | XFS_WRITE_LOG_RES(mp), | 4468 | XFS_WRITE_LOG_RES(mp), |
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 5c6e12853a9b..35cadad84b14 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h | |||
| @@ -209,6 +209,8 @@ int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*, | |||
| 209 | int generic_cont_expand(struct inode *inode, loff_t size); | 209 | int generic_cont_expand(struct inode *inode, loff_t size); |
| 210 | int generic_cont_expand_simple(struct inode *inode, loff_t size); | 210 | int generic_cont_expand_simple(struct inode *inode, loff_t size); |
| 211 | int block_commit_write(struct page *page, unsigned from, unsigned to); | 211 | int block_commit_write(struct page *page, unsigned from, unsigned to); |
| 212 | int block_page_mkwrite(struct vm_area_struct *vma, struct page *page, | ||
| 213 | get_block_t get_block); | ||
| 212 | void block_sync_page(struct page *); | 214 | void block_sync_page(struct page *); |
| 213 | sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); | 215 | sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); |
| 214 | int generic_commit_write(struct file *, struct page *, unsigned, unsigned); | 216 | int generic_commit_write(struct file *, struct page *, unsigned, unsigned); |
