aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-06-11 12:21:19 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-07-15 18:10:51 -0400
commita3d01454bc58b5a211ef64a7670572a40b71e682 (patch)
tree68c1ba383fb2c6702a8cc02bc81d51da6fb2920b /fs/nfs/write.c
parent1b83d707032a1be40a60ed0a9bd841662cc04a5d (diff)
NFS: Remove BKL requirement from attribute updates
The main problem is dealing with inode->i_size: we need to set the inode->i_lock on all attribute updates, and so vmtruncate won't cut it. Make an NFS-private version of vmtruncate that has the necessary locking semantics. The result should be that the following inode attribute updates are protected by inode->i_lock nfsi->cache_validity nfsi->read_cache_jiffies nfsi->attrtimeo nfsi->attrtimeo_timestamp nfsi->change_attr nfsi->last_updated nfsi->cache_change_attribute nfsi->access_cache nfsi->access_cache_entry_lru nfsi->access_cache_inode_lru nfsi->acl_access nfsi->acl_default nfsi->nfs_page_tree nfsi->ncommit nfsi->npages nfsi->open_files nfsi->silly_list nfsi->acl nfsi->open_states inode->i_size inode->i_atime inode->i_mtime inode->i_ctime inode->i_nlink inode->i_uid inode->i_gid The following is protected by dir->i_mutex nfsi->cookieverf Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r--fs/nfs/write.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index feca8c648766..3229e217c773 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -133,16 +133,21 @@ static struct nfs_page *nfs_page_find_request(struct page *page)
133static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) 133static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
134{ 134{
135 struct inode *inode = page->mapping->host; 135 struct inode *inode = page->mapping->host;
136 loff_t end, i_size = i_size_read(inode); 136 loff_t end, i_size;
137 pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; 137 pgoff_t end_index;
138 138
139 spin_lock(&inode->i_lock);
140 i_size = i_size_read(inode);
141 end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
139 if (i_size > 0 && page->index < end_index) 142 if (i_size > 0 && page->index < end_index)
140 return; 143 goto out;
141 end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); 144 end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
142 if (i_size >= end) 145 if (i_size >= end)
143 return; 146 goto out;
144 nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
145 i_size_write(inode, end); 147 i_size_write(inode, end);
148 nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
149out:
150 spin_unlock(&inode->i_lock);
146} 151}
147 152
148/* A writeback failed: mark the page as bad, and invalidate the page cache */ 153/* A writeback failed: mark the page as bad, and invalidate the page cache */