From e16ce66634a85a870dae3323a2257953cfe571be Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Tue, 20 Oct 2009 12:38:53 +0100 Subject: [PATCH] Refactor writepage_sync This change refactors writepage_sync into 4 functions - *) prepare_writeback() readies a vnode for writeback, and performs the anti-recursion check. *) dopartialwrite() intialises a request and performs the call to DoPartialWrite *) page_writeback() does the actual work of writing an AFS page into the disk cache page *) complete_writeback clears the writeback flag from a vnode There should be no change to the current behaviour of writepage_sync, these modifications are the first part of a fix to our writepage() behaviour. Reviewed-on: http://gerrit.openafs.org/712 Tested-by: Derrick Brashear Reviewed-by: Marc Dionne Reviewed-by: Derrick Brashear --- src/afs/LINUX/osi_vnodeops.c | 96 +++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index ee05352..7067384 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1983,15 +1983,43 @@ afs_linux_readpages(struct file *fp, struct address_space *mapping, return 0; } +/* Prepare an AFS vcache for writeback. Should be called with the vcache + * locked */ +static inline int +afs_linux_prepare_writeback(struct vcache *avc) { + if (avc->f.states & CPageWrite) { + return AOP_WRITEPAGE_ACTIVATE; + } + avc->f.states |= CPageWrite; + return 0; +} + +static inline int +afs_linux_dopartialwrite(struct vcache *avc, cred_t *credp) { + struct vrequest treq; + int code; + + if (!afs_InitReq(&treq, credp)) + code = afs_DoPartialWrite(avc, &treq); + + return afs_convert_code(code); +} + +static inline void +afs_linux_complete_writeback(struct vcache *avc) { + avc->f.states &= ~CPageWrite; +} + +/* Writeback a given page syncronously. Called with no AFS locks held */ static int -afs_linux_writepage_sync(struct inode *ip, struct page *pp, - unsigned long offset, unsigned int count) +afs_linux_page_writeback(struct inode *ip, struct page *pp, + unsigned long offset, unsigned int count, + cred_t *credp) { struct vcache *vcp = VTOAFS(ip); char *buffer; afs_offs_t base; int code = 0; - cred_t *credp; uio_t tuio; struct iovec iovec; int f_flags = 0; @@ -1999,25 +2027,12 @@ afs_linux_writepage_sync(struct inode *ip, struct page *pp, buffer = kmap(pp) + offset; base = page_offset(pp) + offset; - credp = crref(); afs_maybe_lock_kernel(); AFS_GLOCK(); afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp), ICL_TYPE_INT32, 99999); - ObtainWriteLock(&vcp->lock, 532); - if (vcp->f.states & CPageWrite) { - ReleaseWriteLock(&vcp->lock); - AFS_GUNLOCK(); - afs_maybe_unlock_kernel(); - crfree(credp); - kunmap(pp); - return AOP_WRITEPAGE_ACTIVATE; - } - vcp->f.states |= CPageWrite; - ReleaseWriteLock(&vcp->lock); - setup_uio(&tuio, &iovec, buffer, base, count, UIO_WRITE, AFS_UIOSYS); code = afs_write(vcp, &tuio, f_flags, credp, 0); @@ -2025,30 +2040,57 @@ afs_linux_writepage_sync(struct inode *ip, struct page *pp, i_size_write(ip, vcp->f.m.Length); ip->i_blocks = ((vcp->f.m.Length + 1023) >> 10) << 1; - ObtainWriteLock(&vcp->lock, 533); - if (!code) { - struct vrequest treq; - - if (!afs_InitReq(&treq, credp)) - code = afs_DoPartialWrite(vcp, &treq); - } code = code ? afs_convert_code(code) : count - tuio.uio_resid; - vcp->f.states &= ~CPageWrite; - ReleaseWriteLock(&vcp->lock); - afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp), ICL_TYPE_INT32, code); AFS_GUNLOCK(); afs_maybe_unlock_kernel(); - crfree(credp); kunmap(pp); return code; } +static int +afs_linux_writepage_sync(struct inode *ip, struct page *pp, + unsigned long offset, unsigned int count) +{ + int code; + struct vcache *vcp = VTOAFS(ip); + cred_t *credp; + + /* Catch recursive writeback. This occurs if the kernel decides + * writeback is required whilst we are writing to the cache, or + * flushing to the server. */ + AFS_GLOCK(); + ObtainWriteLock(&vcp->lock, 532); + code = afs_linux_prepare_writeback(vcp); + if (code) { + ReleaseWriteLock(&vcp->lock); + AFS_GUNLOCK(); + return code; + } + ReleaseWriteLock(&vcp->lock); + AFS_GUNLOCK(); + + credp = crref(); + code = afs_linux_page_writeback(ip, pp, offset, count, credp); + + afs_maybe_lock_kernel(); + AFS_GLOCK(); + ObtainWriteLock(&vcp->lock, 533); + if (code == 0) + code = afs_linux_dopartialwrite(vcp, credp); + afs_linux_complete_writeback(vcp); + ReleaseWriteLock(&vcp->lock); + AFS_GUNLOCK(); + afs_maybe_unlock_kernel(); + crfree(credp); + + return code; +} static int #ifdef AOP_WRITEPAGE_TAKES_WRITEBACK_CONTROL -- 1.9.4