Linux: always use afs_maybe_unlock_kernel
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index 7067384..553e070 100644 (file)
@@ -436,6 +436,12 @@ afs_linux_release(struct inode *ip, struct file *fp)
     afs_maybe_lock_kernel();
     AFS_GLOCK();
     code = afs_close(vcp, fp->f_flags, credp);
+    ObtainWriteLock(&vcp->lock, 807);
+    if (vcp->cred) {
+       crfree(vcp->cred);
+       vcp->cred = NULL;
+    }
+    ReleaseWriteLock(&vcp->lock);
     AFS_GUNLOCK();
     afs_maybe_unlock_kernel();
 
@@ -1067,7 +1073,7 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
                dput(alias);
            } else {
                iput(ip);
-               unlock_kernel();
+               afs_maybe_unlock_kernel();
                crfree(credp);
                return alias;
            }
@@ -1685,7 +1691,7 @@ afs_linux_bypass_readpages(struct file *fp, struct address_space *mapping,
     afs_offs_t offset;
     struct iovec* iovecp;
     struct nocache_read_request *ancr;
-    struct page *pp, *ppt;
+    struct page *pp;
     struct pagevec lrupv;
     afs_int32 code = 0;
 
@@ -1782,7 +1788,6 @@ afs_linux_bypass_readpages(struct file *fp, struct address_space *mapping,
     /* we do not flush, release, or unmap pages--that will be
      * done for us by the background thread as each page comes in
      * from the fileserver */
-out:
     return afs_convert_code(code);
 }
 
@@ -1794,7 +1799,7 @@ afs_linux_bypass_readpage(struct file *fp, struct page *pp)
     uio_t *auio;
     struct iovec *iovecp;
     struct nocache_read_request *ancr;
-    afs_int32 isize;
+    int code;
 
     ClearPageError(pp);
 
@@ -1812,7 +1817,7 @@ afs_linux_bypass_readpage(struct file *fp, struct page *pp)
     /* the background thread will free this */
     ancr = osi_Alloc(sizeof(struct nocache_read_request));
     ancr->auio = auio;
-    ancr->offset = offset;
+    ancr->offset = page_offset(pp);
     ancr->length = PAGE_SIZE;
 
     credp = crref();
@@ -1835,8 +1840,8 @@ afs_linux_can_bypass(struct inode *ip) {
            if(i_size_read(ip) > cache_bypass_threshold)
                return 1;
        default:
+           return 0;
      }
-     return 0;
 }
 
 /* Check if a file is permitted to bypass the cache by policy, and modify
@@ -1844,12 +1849,12 @@ afs_linux_can_bypass(struct inode *ip) {
 
 static inline int
 afs_linux_bypass_check(struct inode *ip) {
-    struct cred* credp;
+    cred_t* credp;
 
     int bypass = afs_linux_can_bypass(ip);
 
     credp = crref();
-    trydo_cache_transition(VTOAFS(ip)), credp, bypass);
+    trydo_cache_transition(VTOAFS(ip), credp, bypass);
     crfree(credp);
 
     return bypass;
@@ -1997,7 +2002,7 @@ afs_linux_prepare_writeback(struct vcache *avc) {
 static inline int
 afs_linux_dopartialwrite(struct vcache *avc, cred_t *credp) {
     struct vrequest treq;
-    int code;
+    int code = 0;
 
     if (!afs_InitReq(&treq, credp))
        code = afs_DoPartialWrite(avc, &treq);
@@ -2058,20 +2063,19 @@ afs_linux_writepage_sync(struct inode *ip, struct page *pp,
                         unsigned long offset, unsigned int count)
 {
     int code;
+    int code1 = 0;
     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. */
+     * flushing to the server. When we're running syncronously (as
+     * opposed to from writepage) we can't actually do anything about
+     * this case - as we can't return AOP_WRITEPAGE_ACTIVATE to write()
+     */
     AFS_GLOCK();
     ObtainWriteLock(&vcp->lock, 532);
-    code = afs_linux_prepare_writeback(vcp);
-    if (code) {
-       ReleaseWriteLock(&vcp->lock);
-       AFS_GUNLOCK();
-       return code;
-    }
+    afs_linux_prepare_writeback(vcp);
     ReleaseWriteLock(&vcp->lock);
     AFS_GUNLOCK();
 
@@ -2081,14 +2085,17 @@ afs_linux_writepage_sync(struct inode *ip, struct page *pp,
     afs_maybe_lock_kernel();
     AFS_GLOCK();
     ObtainWriteLock(&vcp->lock, 533);
-    if (code == 0)
-       code = afs_linux_dopartialwrite(vcp, credp);
+    if (code > 0)
+       code1 = afs_linux_dopartialwrite(vcp, credp);
     afs_linux_complete_writeback(vcp);
     ReleaseWriteLock(&vcp->lock);
     AFS_GUNLOCK();
     afs_maybe_unlock_kernel();
     crfree(credp);
 
+    if (code1)
+       return code1;
+
     return code;
 }
 
@@ -2101,9 +2108,12 @@ afs_linux_writepage(struct page *pp)
 {
     struct address_space *mapping = pp->mapping;
     struct inode *inode;
+    struct vcache *vcp;
+    cred_t *credp;
     unsigned int to = PAGE_CACHE_SIZE;
     loff_t isize;
-    int status = 0;
+    int code = 0;
+    int code1 = 0;
 
     if (PageReclaim(pp)) {
        return AOP_WRITEPAGE_ACTIVATE;
@@ -2112,33 +2122,70 @@ afs_linux_writepage(struct page *pp)
 
     page_cache_get(pp);
 
-    inode = (struct inode *)mapping->host;
+    inode = mapping->host;
+    vcp = VTOAFS(inode);
     isize = i_size_read(inode);
 
     /* Don't defeat an earlier truncate */
     if (page_offset(pp) > isize)
        goto done;
 
+    AFS_GLOCK();
+    ObtainWriteLock(&vcp->lock, 537);
+    code = afs_linux_prepare_writeback(vcp);
+    if (code) {
+       ReleaseWriteLock(&vcp->lock);
+       AFS_GUNLOCK();
+       return code;
+    }
+    /* Grab the creds structure currently held in the vnode, and
+     * get a reference to it, in case it goes away ... */
+    credp = vcp->cred;
+    crhold(credp);
+    ReleaseWriteLock(&vcp->lock);
+    AFS_GUNLOCK();
+
     /* If this is the final page, then just write the number of bytes that
      * are actually in it */
     if ((isize - page_offset(pp)) < to )
        to = isize - page_offset(pp);
 
-    status = afs_linux_writepage_sync(inode, pp, 0, to);
+    code = afs_linux_page_writeback(inode, pp, 0, to, credp);
+
+    afs_maybe_lock_kernel();
+    AFS_GLOCK();
+    ObtainWriteLock(&vcp->lock, 538);
+
+    /* As much as we might like to ignore a file server error here,
+     * and just try again when we close(), unfortunately StoreAllSegments
+     * will invalidate our chunks if the server returns a permanent error,
+     * so we need to at least try and get that error back to the user
+     */
+    if (code == to)
+       code1 = afs_linux_dopartialwrite(vcp, credp);
+
+    afs_linux_complete_writeback(vcp);
+    ReleaseWriteLock(&vcp->lock);
+    crfree(credp);
+    AFS_GUNLOCK();
+    afs_maybe_unlock_kernel();
 
 done:
     SetPageUptodate(pp);
-    if ( status != AOP_WRITEPAGE_ACTIVATE ) {
+    if ( code != AOP_WRITEPAGE_ACTIVATE ) {
        /* XXX - do we need to redirty the page here? */
        unlock_page(pp);
     }
 
     page_cache_release(pp);
 
-    if (status == to)
+    if (code1)
+       return code1;
+
+    if (code == to)
        return 0;
-    else
-       return status;
+
+    return code;
 }
 
 /* afs_linux_permission