Fix 2.4.19-pre3 NFS reads from holding a write leases.
PATCH 1/1 Fix 2.4.19-pre3 NFS reads from holding a write leases.
Hi,
The VFS does not like us holding the 'write_access' lease on a
file for too long. The function 'get_write_access()' gets called on an inode whenever a struct file is created for writing, and is only released on the last fput() of that struct file.
NFS caches the struct file in the nfs_page in order to access
the RPC credentials that are cached in the filp->private_data area. Unfortunately this means that both NFS reads and writes can end up prolonging the write_access lease beyond the end of the 'sys_close()'.
The following patch changes the NFS code so that it caches the RPC
credentials directly in the nfs_page. The struct file is still kept around for ordinary writes, in order that we can report asynchronous write errors in sys_close() via filp->f_error.
Cheers,
Trond
fs/nfs/flushd.c +2 -2
@@ -59,7 +59,7 @@static void nfs_flushd_exit (struct rpc_task *); -int nfs_reqlist_init (struct nfs_server *server) +static int nfs_reqlist_init (struct nfs_server *server) {struct nfs_reqlist *cache;struct rpc_task *task;
@@ -136,7 +136,7 @@init_waitqueue_head (&cache->request_wait); server->rw_requests = cache; -return 0 ; +return nfs_reqlist_init (server); }void nfs_reqlist_free (struct nfs_server *server)
fs/nfs/pagelist.c +34 -24
126 lines not on this page · raw message
fs/nfs/read.c +5 -13
@@ -168,7 +168,7 @@ {struct nfs_page *new; - new =nfs_create_request (file, inode, page,0 ,PAGE_CACHE_SIZE ); + new =nfs_create_request (nfs_file_cred (file), inode, page,0 ,PAGE_CACHE_SIZE );if (IS_ERR (new))return PTR_ERR (new);nfs_mark_request_read (new);
@@ -224,8 +224,9 @@nfs_list_remove_request (req);SetPageError (page);UnlockPage (page); -nfs_unlock_request (req); +nfs_clear_request (req);nfs_release_request (req); +nfs_unlock_request (req); } }
@@ -431,6 +432,7 @@ (long long )NFS_FILEID (req->wb_inode), req->wb_bytes, (long long)(page_offset(page) + req->wb_offset)); +nfs_clear_request (req);nfs_release_request (req);nfs_unlock_request (req); }
@@ -448,19 +450,9 @@int nfs_readpage (struct file *file,struct page *page) { -struct inode *inode; +struct inode *inode = page->mapping->host;int error; -if (!file) { -struct address_space *mapping = page->mapping; -if (!mapping) -BUG (); - inode = mapping->host; - }else - inode = file->f_dentry->d_inode; -if (!inode) -BUG (); -dprintk ("NFS: nfs_readpage (%p %ld@%lu)\n" , page,PAGE_CACHE_SIZE , page->index);/*
fs/nfs/write.c +11 -11
@@ -238,17 +238,11 @@int nfs_writepage (struct page *page) { -struct inode *inode; +struct inode *inode = page->mapping->host;unsigned long end_index;unsigned offset =PAGE_CACHE_SIZE ;int err; -struct address_space *mapping = page->mapping; -if (!mapping) -BUG (); - inode = mapping->host; -if (!inode) -BUG (); end_index = inode->i_size >>PAGE_CACHE_SHIFT ;/* Ensure we've flushed out any previous writes */
@@ -362,6 +356,7 @@iput (inode); }else spin_unlock (&nfs_wreq_lock); +nfs_clear_request (req);nfs_release_request (req); }
@@ -688,9 +683,13 @@ }spin_unlock (&nfs_wreq_lock); - new =nfs_create_request (file, inode, page, offset, bytes); + new =nfs_create_request (nfs_file_cred (file), inode, page, offset, bytes);if (IS_ERR (new))return new; +if (file) { + new->wb_file = file; +get_file (file); + }/* If the region is locked, adjust the timeout */ if (region_locked (inode, new)) new->wb_timeout = jiffies +NFS_WRITEBACK_LOCKDELAY ;
@@ -768,7 +767,8 @@int nfs_flush_incompatible (struct file *file,struct page *page) { -struct inode *inode = file->f_dentry->d_inode; +struct rpc_cred *cred =nfs_file_cred (file); +struct inode *inode = page->mapping->host;struct nfs_page *req;int status =0 ;/*
@@ -781,7 +781,7 @@*/ req =nfs_find_request (inode,page);if (req) { -if (req->wb_file != file || req->wb_page != page) +if (req->wb_file != file || req->wb_cred != cred || req->wb_page != page) status =nfs_wb_page (inode, page);nfs_release_request (req); }
@@ -798,7 +798,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) { struct dentry *dentry = file->f_dentry; -struct inode *inode = dentry->d_inode; +struct inode *inode = page->mapping->host;struct nfs_page *req;loff_t end;int status =0 ;
include/linux/nfs_flushd.h +0 -1
@@ -32,7 +32,6 @@*/ extern int nfs_reqlist_alloc (struct nfs_server *);extern void nfs_reqlist_free (struct nfs_server *); -extern int nfs_reqlist_init (struct nfs_server *);extern void nfs_reqlist_exit (struct nfs_server *);extern void nfs_wake_flushd (void );
include/linux/nfs_fs.h +3 -1
@@ -165,7 +165,9 @@static __inline__struct rpc_cred *nfs_file_cred (struct file *file) { -struct rpc_cred *cred = (struct rpc_cred *)(file->private_data); +struct rpc_cred *cred =NULL ; +if (file) + cred = (struct rpc_cred *)file->private_data;#ifdef RPC_DEBUG if (cred && cred->cr_magic !=RPCAUTH_CRED_MAGIC )BUG ();
include/linux/nfs_page.h +2 -1
@@ -41,9 +41,10 @@#define NFS_WBACK_BUSY (req) (test_bit(PG_BUSY,&(req)->wb_flags)) -extern struct nfs_page *nfs_create_request (struct file *,struct inode *, +extern struct nfs_page *nfs_create_request (struct rpc_cred *,struct inode *,struct page *,unsigned int ,unsigned int ); +extern void nfs_clear_request (struct nfs_page *req);extern void nfs_release_request (struct nfs_page *req);