LINUX vcache lock ordering in afs_linux_readdir
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index 17a1b62..57dc081 100644 (file)
@@ -263,6 +263,7 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
     int offset;
     int dirpos;
     struct DirEntry *de;
+    struct DirBuffer entry;
     ino_t ino;
     int len;
     afs_size_t origOffset, tlen;
@@ -295,8 +296,7 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
        code = -ENOENT;
        goto out;
     }
-    ObtainSharedLock(&avc->lock, 810);
-    UpgradeSToWLock(&avc->lock, 811);
+    ObtainWriteLock(&avc->lock, 811);
     ObtainReadLock(&tdc->lock);
     /*
      * Make sure that the data in the cache is current. There are two
@@ -308,15 +308,15 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
           && (tdc->dflags & DFFetching)
           && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
        ReleaseReadLock(&tdc->lock);
-       ReleaseSharedLock(&avc->lock);
+       ReleaseWriteLock(&avc->lock);
        afs_osi_Sleep(&tdc->validPos);
-       ObtainSharedLock(&avc->lock, 812);
+       ObtainWriteLock(&avc->lock, 812);
        ObtainReadLock(&tdc->lock);
     }
     if (!(avc->f.states & CStatd)
        || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
        ReleaseReadLock(&tdc->lock);
-       ReleaseSharedLock(&avc->lock);
+       ReleaseWriteLock(&avc->lock);
        afs_PutDCache(tdc);
        goto tagain;
     }
@@ -339,23 +339,20 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
        if (!dirpos)
            break;
 
-       de = afs_dir_GetBlob(tdc, dirpos);
-       if (!de)
-           break;
-
-       ino = afs_calc_inum (avc->f.fid.Fid.Volume, ntohl(de->fid.vnode));
-
-       if (de->name)
-           len = strlen(de->name);
-       else {
-           printf("afs_linux_readdir: afs_dir_GetBlob failed, null name (inode %lx, dirpos %d)\n", 
-                  (unsigned long)&tdc->f.inode, dirpos);
-           DRelease(de, 0);
+       code = afs_dir_GetVerifiedBlob(tdc, dirpos, &entry);
+       if (code) {
+           afs_warn("Corrupt directory (inode %lx, dirpos %d)",
+                    (unsigned long)&tdc->f.inode, dirpos);
            ReleaseSharedLock(&avc->lock);
            afs_PutDCache(tdc);
            code = -ENOENT;
            goto out;
-       }
+        }
+
+       de = (struct DirEntry *)entry.data;
+       ino = afs_calc_inum (avc->f.fid.Cell, avc->f.fid.Fid.Volume,
+                            ntohl(de->fid.vnode));
+       len = strlen(de->name);
 
        /* filldir returns -EINVAL when the buffer is full. */
        {
@@ -397,7 +394,7 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
            code = (*filldir) (dirbuf, de->name, len, offset, ino, type);
            AFS_GLOCK();
        }
-       DRelease(de, 0);
+       DRelease(&entry, 0);
        if (code)
            break;
        offset = dirpos + 1 + ((len + 16) >> 5);
@@ -1431,7 +1428,7 @@ afs_linux_ireadlink(struct inode *ip, char *target, int maxlen, uio_seg_t seg)
 {
     int code;
     cred_t *credp = crref();
-    uio_t tuio;
+    struct uio tuio;
     struct iovec iov;
 
     setup_uio(&tuio, &iov, target, (afs_offs_t) 0, maxlen, UIO_READ, seg);
@@ -1469,7 +1466,7 @@ static int afs_linux_follow_link(struct dentry *dentry, struct nameidata *nd)
     int code;
     char *name;
 
-    name = osi_Alloc(PATH_MAX);
+    name = kmalloc(PATH_MAX, GFP_NOFS);
     if (!name) {
        return -EIO;
     }
@@ -1491,9 +1488,9 @@ static void
 afs_linux_put_link(struct dentry *dentry, struct nameidata *nd)
 {
     char *name = nd_get_link(nd);
-    if (name && !IS_ERR(name)) {
-       osi_Free(name, PATH_MAX);
-    }
+
+    if (name && !IS_ERR(name))
+       kfree(name);
 }
 
 #endif /* USABLE_KERNEL_PAGE_SYMLINK_CACHE */
@@ -1513,7 +1510,7 @@ afs_linux_read_cache(struct file *cachefp, struct page *page,
     struct inode *cacheinode = cachefp->f_dentry->d_inode;
     struct page *newpage, *cachepage;
     struct address_space *cachemapping;
-    int pageindex, endindex;
+    int pageindex;
     int code = 0;
 
     cachemapping = cacheinode->i_mapping;
@@ -1720,7 +1717,7 @@ afs_linux_fillpage(struct file *fp, struct page *pp)
 {
     afs_int32 code;
     char *address;
-    uio_t *auio;
+    struct uio *auio;
     struct iovec *iovecp;
     struct inode *ip = FILE_INODE(fp);
     afs_int32 cnt = page_count(pp);
@@ -1739,8 +1736,8 @@ afs_linux_fillpage(struct file *fp, struct page *pp)
     address = kmap(pp);
     ClearPageError(pp);
 
-    auio = osi_Alloc(sizeof(uio_t));
-    iovecp = osi_Alloc(sizeof(struct iovec));
+    auio = kmalloc(sizeof(struct uio), GFP_NOFS);
+    iovecp = kmalloc(sizeof(struct iovec), GFP_NOFS);
 
     setup_uio(auio, iovecp, (char *)address, offset, PAGE_SIZE, UIO_READ,
               AFS_UIOSYS);
@@ -1771,8 +1768,8 @@ afs_linux_fillpage(struct file *fp, struct page *pp)
 
     kunmap(pp);
 
-    osi_Free(auio, sizeof(uio_t));
-    osi_Free(iovecp, sizeof(struct iovec));
+    kfree(auio);
+    kfree(iovecp);
 
     crfree(credp);
     return afs_convert_code(code);
@@ -1814,7 +1811,7 @@ afs_linux_bypass_readpages(struct file *fp, struct address_space *mapping,
                           struct list_head *page_list, unsigned num_pages)
 {
     afs_int32 page_ix;
-    uio_t *auio;
+    struct uio *auio;
     afs_offs_t offset;
     struct iovec* iovecp;
     struct nocache_read_request *ancr;
@@ -1832,7 +1829,7 @@ afs_linux_bypass_readpages(struct file *fp, struct address_space *mapping,
     /* background thread must free: iovecp, auio, ancr */
     iovecp = osi_Alloc(num_pages * sizeof(struct iovec));
 
-    auio = osi_Alloc(sizeof(uio_t));
+    auio = osi_Alloc(sizeof(struct uio));
     auio->uio_iov = iovecp;
     auio->uio_iovcnt = num_pages;
     auio->uio_flag = UIO_READ;
@@ -1918,7 +1915,7 @@ afs_linux_bypass_readpages(struct file *fp, struct address_space *mapping,
         /* If there is nothing for the background thread to handle,
          * it won't be freeing the things that we never gave it */
         osi_Free(iovecp, num_pages * sizeof(struct iovec));
-        osi_Free(auio, sizeof(uio_t));
+        osi_Free(auio, sizeof(struct uio));
         osi_Free(ancr, sizeof(struct nocache_read_request));
     }
     /* we do not flush, release, or unmap pages--that will be
@@ -1932,7 +1929,7 @@ static int
 afs_linux_bypass_readpage(struct file *fp, struct page *pp)
 {
     cred_t *credp = NULL;
-    uio_t *auio;
+    struct uio *auio;
     struct iovec *iovecp;
     struct nocache_read_request *ancr;
     int code;
@@ -1951,7 +1948,7 @@ afs_linux_bypass_readpage(struct file *fp, struct page *pp)
     ClearPageError(pp);
 
     /* receiver frees */
-    auio = osi_Alloc(sizeof(uio_t));
+    auio = osi_Alloc(sizeof(struct uio));
     iovecp = osi_Alloc(sizeof(struct iovec));
 
     /* address can be NULL, because we overwrite it with 'pp', below */
@@ -2158,7 +2155,7 @@ afs_linux_page_writeback(struct inode *ip, struct page *pp,
     char *buffer;
     afs_offs_t base;
     int code = 0;
-    uio_t tuio;
+    struct uio tuio;
     struct iovec iovec;
     int f_flags = 0;