Linux 4: struct address_space no longer has backing_dev_info
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index fbaa410..5869eb9 100644 (file)
@@ -1171,30 +1171,34 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags)
            locked = 1;
        }
 
-       if (locked && vcp->mvstat == 1) {         /* mount point */
-           if (vcp->mvid && (vcp->f.states & CMValid)) {
-               int tryEvalOnly = 0;
-               int code = 0;
-               struct vrequest *treq = NULL;
-
-               code = afs_CreateReq(&treq, credp);
-               if (code) {
-                   dput(parent);
-                   goto bad_dentry;
-               }
-               if ((strcmp(dp->d_name.name, ".directory") == 0)) {
-                   tryEvalOnly = 1;
-               }
-               if (tryEvalOnly)
-                   code = afs_TryEvalFakeStat(&vcp, &fakestate, treq);
-               else
-                   code = afs_EvalFakeStat(&vcp, &fakestate, treq);
-               afs_DestroyReq(treq);
-               if ((tryEvalOnly && vcp->mvstat == 1) || code) {
-                   /* a mount point, not yet replaced by its directory */
-                   dput(parent);
-                   goto bad_dentry;
+       if (locked) {
+           if (vcp->mvstat == 1) {         /* mount point */
+               if (vcp->mvid && (vcp->f.states & CMValid)) {
+                   int tryEvalOnly = 0;
+                   int code = 0;
+                   struct vrequest *treq = NULL;
+
+                   code = afs_CreateReq(&treq, credp);
+                   if (code) {
+                       dput(parent);
+                       goto bad_dentry;
+                   }
+                   if ((strcmp(dp->d_name.name, ".directory") == 0)) {
+                       tryEvalOnly = 1;
+                   }
+                   if (tryEvalOnly)
+                       code = afs_TryEvalFakeStat(&vcp, &fakestate, treq);
+                   else
+                       code = afs_EvalFakeStat(&vcp, &fakestate, treq);
+                   afs_DestroyReq(treq);
+                   if ((tryEvalOnly && vcp->mvstat == 1) || code) {
+                       /* a mount point, not yet replaced by its directory */
+                       dput(parent);
+                       goto bad_dentry;
+                   }
                }
+           } else if (vcp->mvstat == 2 && *dp->d_name.name != '/') {
+               osi_Assert(vcp->mvid != NULL);
            }
        }
 
@@ -1550,6 +1554,17 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
        ip->i_flags |= S_AUTOMOUNT;
 #endif
     }
+    /*
+     * Take an extra reference so the inode doesn't go away if
+     * d_splice_alias drops our reference on error.
+     */
+    if (ip)
+#ifdef HAVE_LINUX_IHOLD
+       ihold(ip);
+#else
+       igrab(ip);
+#endif
+
     newdp = d_splice_alias(ip, dp);
 
  done:
@@ -1563,14 +1578,26 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
         * d_splice_alias can return an error (EIO) if there is an existing
         * connected directory alias for this dentry.
         */
-       if (!IS_ERR(newdp))
+       if (!IS_ERR(newdp)) {
+           iput(ip);
            return newdp;
-       else {
+       } else {
            d_add(dp, ip);
+           /*
+            * Depending on the kernel version, d_splice_alias may or may
+            * not drop the inode reference on error.  If it didn't, do it
+            * here.
+            */
+#if defined(D_SPLICE_ALIAS_LEAK_ON_ERROR)
+           iput(ip);
+#endif
            return NULL;
        }
-    } else
+    } else {
+       if (ip)
+           iput(ip);
        return ERR_PTR(afs_convert_code(code));
+    }
 }
 
 static int
@@ -1832,6 +1859,9 @@ afs_linux_ireadlink(struct inode *ip, char *target, int maxlen, uio_seg_t seg)
     struct uio tuio;
     struct iovec iov;
 
+    memset(&tuio, 0, sizeof(tuio));
+    memset(&iov, 0, sizeof(iov));
+
     setup_uio(&tuio, &iov, target, (afs_offs_t) 0, maxlen, UIO_READ, seg);
     code = afs_readlink(VTOAFS(ip), &tuio, credp);
     crfree(credp);
@@ -2585,6 +2615,9 @@ afs_linux_page_writeback(struct inode *ip, struct page *pp,
     struct iovec iovec;
     int f_flags = 0;
 
+    memset(&tuio, 0, sizeof(tuio));
+    memset(&iovec, 0, sizeof(iovec));
+
     buffer = kmap(pp) + offset;
     base = page_offset(pp) + offset;
 
@@ -3023,7 +3056,9 @@ afs_fill_inode(struct inode *ip, struct vattr *vattr)
     if (vattr)
        vattr2inode(ip, vattr);
 
+#ifdef STRUCT_ADDRESS_SPACE_HAS_BACKING_DEV_INFO
     ip->i_mapping->backing_dev_info = afs_backing_dev_info;
+#endif
 /* Reset ops if symlink or directory. */
     if (S_ISREG(ip->i_mode)) {
        ip->i_op = &afs_file_iops;