Merge branch 'work.inode-type-fixes' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / fs / cifs / inode.c
index a0846f7..002d864 100644 (file)
@@ -157,12 +157,18 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 }
 
 /* populate an inode with info from a cifs_fattr struct */
-void
+int
 cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 {
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
+       if (!(inode->i_state & I_NEW) &&
+           unlikely(inode_wrong_type(inode, fattr->cf_mode))) {
+               CIFS_I(inode)->time = 0; /* force reval */
+               return -ESTALE;
+       }
+
        cifs_revalidate_cache(inode, fattr);
 
        spin_lock(&inode->i_lock);
@@ -219,6 +225,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
                inode->i_flags |= S_AUTOMOUNT;
        if (inode->i_state & I_NEW)
                cifs_set_ops(inode);
+       return 0;
 }
 
 void
@@ -363,7 +370,7 @@ cifs_get_file_info_unix(struct file *filp)
                rc = 0;
        }
 
-       cifs_fattr_to_inode(inode, &fattr);
+       rc = cifs_fattr_to_inode(inode, &fattr);
        free_xid(xid);
        return rc;
 }
@@ -426,14 +433,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                }
 
                /* if filetype is different, return error */
-               if (unlikely(((*pinode)->i_mode & S_IFMT) !=
-                   (fattr.cf_mode & S_IFMT))) {
-                       CIFS_I(*pinode)->time = 0; /* force reval */
-                       rc = -ESTALE;
-                       goto cgiiu_exit;
-               }
-
-               cifs_fattr_to_inode(*pinode, &fattr);
+               rc = cifs_fattr_to_inode(*pinode, &fattr);
        }
 
 cgiiu_exit:
@@ -783,7 +783,8 @@ cifs_get_file_info(struct file *filp)
         */
        fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
        fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
-       cifs_fattr_to_inode(inode, &fattr);
+       /* if filetype is different, return error */
+       rc = cifs_fattr_to_inode(inode, &fattr);
 cgfi_exit:
        free_xid(xid);
        return rc;
@@ -1100,16 +1101,8 @@ handle_mnt_opt:
                        rc = -ESTALE;
                        goto out;
                }
-
                /* if filetype is different, return error */
-               if (unlikely(((*inode)->i_mode & S_IFMT) !=
-                   (fattr.cf_mode & S_IFMT))) {
-                       CIFS_I(*inode)->time = 0; /* force reval */
-                       rc = -ESTALE;
-                       goto out;
-               }
-
-               cifs_fattr_to_inode(*inode, &fattr);
+               rc = cifs_fattr_to_inode(*inode, &fattr);
        }
 out:
        cifs_buf_release(smb1_backup_rsp_buf);
@@ -1215,14 +1208,7 @@ smb311_posix_get_inode_info(struct inode **inode,
                }
 
                /* if filetype is different, return error */
-               if (unlikely(((*inode)->i_mode & S_IFMT) !=
-                   (fattr.cf_mode & S_IFMT))) {
-                       CIFS_I(*inode)->time = 0; /* force reval */
-                       rc = -ESTALE;
-                       goto out;
-               }
-
-               cifs_fattr_to_inode(*inode, &fattr);
+               rc = cifs_fattr_to_inode(*inode, &fattr);
        }
 out:
        cifs_put_tlink(tlink);
@@ -1249,7 +1235,7 @@ cifs_find_inode(struct inode *inode, void *opaque)
                return 0;
 
        /* don't match inode of different type */
-       if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
+       if (inode_wrong_type(inode, fattr->cf_mode))
                return 0;
 
        /* if it's not a directory or has no dentries, then flag it */
@@ -1317,6 +1303,7 @@ retry_iget5_locked:
                        }
                }
 
+               /* can't fail - see cifs_find_inode() */
                cifs_fattr_to_inode(inode, fattr);
                if (sb->s_flags & SB_NOATIME)
                        inode->i_flags |= S_NOATIME | S_NOCMTIME;
@@ -1742,6 +1729,16 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
        if (rc)
                return rc;
 
+       if (!S_ISDIR(inode->i_mode)) {
+               /*
+                * mkdir succeeded, but another client has managed to remove the
+                * sucker and replace it with non-directory.  Return success,
+                * but don't leave the child in dcache.
+                */
+                iput(inode);
+                d_drop(dentry);
+                return 0;
+       }
        /*
         * setting nlink not necessary except in cases where we failed to get it
         * from the server or was set bogus. Also, since this is a brand new
@@ -1793,7 +1790,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
                }
        }
        d_instantiate(dentry, inode);
-       return rc;
+       return 0;
 }
 
 static int