aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/buffer.c47
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c16
-rw-r--r--fs/xfs/xfs_vnodeops.c30
-rw-r--r--include/linux/buffer_head.h2
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 */
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);
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 */
422STATIC int
423xfs_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
416const struct file_operations xfs_file_operations = { 430const 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
466static struct vm_operations_struct xfs_file_vm_ops = { 480static 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
471static struct vm_operations_struct xfs_dmapi_file_vm_ops = { 486static 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*,
209int generic_cont_expand(struct inode *inode, loff_t size); 209int generic_cont_expand(struct inode *inode, loff_t size);
210int generic_cont_expand_simple(struct inode *inode, loff_t size); 210int generic_cont_expand_simple(struct inode *inode, loff_t size);
211int block_commit_write(struct page *page, unsigned from, unsigned to); 211int block_commit_write(struct page *page, unsigned from, unsigned to);
212int block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
213 get_block_t get_block);
212void block_sync_page(struct page *); 214void block_sync_page(struct page *);
213sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); 215sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
214int generic_commit_write(struct file *, struct page *, unsigned, unsigned); 216int generic_commit_write(struct file *, struct page *, unsigned, unsigned);