diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-05-31 12:22:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-31 11:41:36 -0700 |
commit | 1d59d61f606547f0712aa6971f91f71154071c99 (patch) | |
tree | cb2fd4b9ce3e3ee9440d566d43ea350221edfc8e /fs/nfs | |
parent | 2d117403b30cd7301af60d7d54b279a9f566d10d (diff) |
NFS: Ensure that setattr and getattr wait for O_DIRECT write completion
Use the same mechanism as the block devices are using, but move the
helper functions from fs/direct-io.c into fs/inode.c to remove the
dependency on CONFIG_BLOCK.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/direct.c | 15 | ||||
-rw-r--r-- | fs/nfs/inode.c | 5 | ||||
-rw-r--r-- | fs/nfs/internal.h | 4 |
3 files changed, 20 insertions, 4 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 23d170bc44f4..ad2775d3e219 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -454,6 +454,12 @@ out: return result; } +static void nfs_inode_dio_write_done(struct inode *inode) +{ + nfs_zap_mapping(inode, inode->i_mapping); + inode_dio_done(inode); +} + #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) { @@ -564,7 +570,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) nfs_direct_write_reschedule(dreq); break; default: - nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping); + nfs_inode_dio_write_done(dreq->inode); nfs_direct_complete(dreq); } } @@ -581,7 +587,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) { - nfs_zap_mapping(inode, inode->i_mapping); + nfs_inode_dio_write_done(inode); nfs_direct_complete(dreq); } #endif @@ -766,14 +772,16 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, loff_t pos) { struct nfs_pageio_descriptor desc; + struct inode *inode = dreq->inode; ssize_t result = 0; size_t requested_bytes = 0; unsigned long seg; - nfs_pageio_init_write(&desc, dreq->inode, FLUSH_COND_STABLE, + nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE, &nfs_direct_write_completion_ops); desc.pg_dreq = dreq; get_dreq(dreq); + atomic_inc(&inode->i_dio_count); for (seg = 0; seg < nr_segs; seg++) { const struct iovec *vec = &iov[seg]; @@ -793,6 +801,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, * generic layer handle the completion. */ if (requested_bytes == 0) { + inode_dio_done(inode); nfs_direct_req_release(dreq); return result < 0 ? result : -EIO; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2f6f78c4b42d..e605d695dbcb 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -418,8 +418,10 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) return 0; /* Write all dirty data */ - if (S_ISREG(inode->i_mode)) + if (S_ISREG(inode->i_mode)) { + nfs_inode_dio_wait(inode); nfs_wb_all(inode); + } fattr = nfs_alloc_fattr(); if (fattr == NULL) @@ -503,6 +505,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) /* Flush out writes to the server in order to update c/mtime. */ if (S_ISREG(inode->i_mode)) { + nfs_inode_dio_wait(inode); err = filemap_write_and_wait(inode->i_mapping); if (err) goto out; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 1848a7275592..18f99ef71343 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -369,6 +369,10 @@ extern int nfs_migrate_page(struct address_space *, /* direct.c */ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, struct nfs_direct_req *dreq); +static inline void nfs_inode_dio_wait(struct inode *inode) +{ + inode_dio_wait(inode); +} /* nfs4proc.c */ extern void __nfs4_read_done_cb(struct nfs_read_data *); |