cifs: have cifs_fattr_to_inode() refuse to change type on live inode
[sfrench/cifs-2.6.git] / fs / cifs / inode.c
index 80c487fcf10e540cd07b1006acbf639202731d66..51cb1ca829ec83354043444a6093e56c9cb25889 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,13 +433,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                }
 
                /* if filetype is different, return error */
-               if (unlikely(inode_wrong_type(*pinode, fattr.cf_mode))) {
-                       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:
@@ -782,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;
@@ -1099,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);
@@ -1214,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);
@@ -1316,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;