History

NFS: Fix another O_DIRECT race

Ensure we call unmap_mapping_range() and sync dirty pages to disk before doing an NFS direct write. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Trond Myklebust committed 20 years ago

Commit 29884df1 parent b079fa74 files · +34 −42Browse files

Unified · Split

4 files
  1. fs/nfs/direct.c +6 −18
  2. fs/nfs/file.c +4 −19
  3. fs/nfs/inode.c +23 −5
  4. include/linux/nfs_fs.h +1 −0
fs/nfs/direct.c+6−18
@@ -678,15 +678,9 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t · 677 unmodified lines
678 if (!count)678 if (!count)
679 goto out;679 goto out;
680 680
681 if (mapping->nrpages) {681 retval = nfs_sync_mapping(mapping);
682 retval = filemap_fdatawrite(mapping);682 if (retval)
683 if (retval == 0)683 goto out;
684 retval = nfs_wb_all(inode);
685 if (retval == 0)
686 retval = filemap_fdatawait(mapping);
687 if (retval)
688 goto out;
689 }
690 684
691 retval = nfs_direct_read(inode, ctx, &iov, pos, 1);685 retval = nfs_direct_read(inode, ctx, &iov, pos, 1);
692 if (retval > 0)686 if (retval > 0)
@@ -764,15 +758,9 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, · 71 unmodified lines
764 if (!count)758 if (!count)
765 goto out;759 goto out;
766 760
767 if (mapping->nrpages) {761 retval = nfs_sync_mapping(mapping);
768 retval = filemap_fdatawrite(mapping);762 if (retval)
769 if (retval == 0)763 goto out;
770 retval = nfs_wb_all(inode);
771 if (retval == 0)
772 retval = filemap_fdatawait(mapping);
773 if (retval)
774 goto out;
775 }
776 764
777 retval = nfs_direct_write(inode, ctx, &iov, pos, 1);765 retval = nfs_direct_write(inode, ctx, &iov, pos, 1);
778 if (mapping->nrpages)766 if (mapping->nrpages)
fs/nfs/file.c+4−19
@@ -433,11 +433,7 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) · 432 unmodified lines
433 * Flush all pending writes before doing anything433 * Flush all pending writes before doing anything
434 * with locks..434 * with locks..
435 */435 */
436 filemap_fdatawrite(filp->f_mapping);436 nfs_sync_mapping(filp->f_mapping);
437 down(&inode->i_sem);
438 nfs_wb_all(inode);
439 up(&inode->i_sem);
440 filemap_fdatawait(filp->f_mapping);
441 437
442 /* NOTE: special case438 /* NOTE: special case
443 * If we're signalled while cleaning up locks on process exit, we439 * If we're signalled while cleaning up locks on process exit, we
@@ -465,15 +461,8 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) · 21 unmodified lines
465 * Flush all pending writes before doing anything461 * Flush all pending writes before doing anything
466 * with locks..462 * with locks..
467 */463 */
468 status = filemap_fdatawrite(filp->f_mapping);464 status = nfs_sync_mapping(filp->f_mapping);
469 if (status == 0) {465 if (status != 0)
470 down(&inode->i_sem);
471 status = nfs_wb_all(inode);
472 up(&inode->i_sem);
473 if (status == 0)
474 status = filemap_fdatawait(filp->f_mapping);
475 }
476 if (status < 0)
477 goto out;466 goto out;
478 467
479 lock_kernel();468 lock_kernel();
@@ -497,11 +486,7 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) · 17 unmodified lines
497 * Make sure we clear the cache whenever we try to get the lock.486 * Make sure we clear the cache whenever we try to get the lock.
498 * This makes locking act as a cache coherency point.487 * This makes locking act as a cache coherency point.
499 */488 */
500 filemap_fdatawrite(filp->f_mapping);489 nfs_sync_mapping(filp->f_mapping);
501 down(&inode->i_sem);
502 nfs_wb_all(inode); /* we may have slept */
503 up(&inode->i_sem);
504 filemap_fdatawait(filp->f_mapping);
505 nfs_zap_caches(inode);490 nfs_zap_caches(inode);
506out:491out:
507 rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);492 rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
fs/nfs/inode.c+23−5
@@ -640,6 +640,27 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) · 639 unmodified lines
640 return 0;640 return 0;
641}641}
642 642
643/**
644 * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
645 */
646int nfs_sync_mapping(struct address_space *mapping)
647{
648 int ret;
649
650 if (mapping->nrpages == 0)
651 return 0;
652 unmap_mapping_range(mapping, 0, 0, 0);
653 ret = filemap_fdatawrite(mapping);
654 if (ret != 0)
655 goto out;
656 ret = filemap_fdatawait(mapping);
657 if (ret != 0)
658 goto out;
659 ret = nfs_wb_all(mapping->host);
660out:
661 return ret;
662}
663
643/*664/*
644 * Invalidate the local caches665 * Invalidate the local caches
645 */666 */
@@ -1179,11 +1200,8 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) · 533 unmodified lines
1179 struct nfs_inode *nfsi = NFS_I(inode);1200 struct nfs_inode *nfsi = NFS_I(inode);
1180 1201
1181 if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {1202 if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
1182 if (S_ISREG(inode->i_mode)) {1203 if (S_ISREG(inode->i_mode))
1183 if (filemap_fdatawrite(mapping) == 0)1204 nfs_sync_mapping(mapping);
1184 filemap_fdatawait(mapping);
1185 nfs_wb_all(inode);
1186 }
1187 invalidate_inode_pages2(mapping);1205 invalidate_inode_pages2(mapping);
1188 1206
1189 spin_lock(&inode->i_lock);1207 spin_lock(&inode->i_lock);
include/linux/nfs_fs.h+1−0
@@ -291,6 +291,7 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long · 290 unmodified lines
291/*291/*
292 * linux/fs/nfs/inode.c292 * linux/fs/nfs/inode.c
293 */293 */
294extern int nfs_sync_mapping(struct address_space *mapping);
294extern void nfs_zap_caches(struct inode *);295extern void nfs_zap_caches(struct inode *);
295extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,296extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
296 struct nfs_fattr *);297 struct nfs_fattr *);