cifs: have cifs_fattr_to_inode() refuse to change type on live inode
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 11 Feb 2021 02:23:04 +0000 (21:23 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 13 Mar 2021 03:15:20 +0000 (22:15 -0500)
... instead of trying to do that in the callers (and missing some,
at that)

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/cifs/cifsproto.h
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/readdir.c

index 75ce6f742b8d76203f2e6d9f9179bf2c113a108b..2a72dc24b00a36d78a54c7dd85c6687d9788fa98 100644 (file)
@@ -194,7 +194,7 @@ extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
                                     struct cifs_sb_info *cifs_sb);
 extern void cifs_dir_info_to_fattr(struct cifs_fattr *, FILE_DIRECTORY_INFO *,
                                        struct cifs_sb_info *);
-extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
+extern int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
 extern struct inode *cifs_iget(struct super_block *sb,
                               struct cifs_fattr *fattr);
 
index 26de4329d16158363b054e38464a13b19cb4d6d0..78266f0e05958d2023a63cd1a5af89c00b9ff965 100644 (file)
@@ -165,7 +165,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
                        goto posix_open_ret;
                }
        } else {
-               cifs_fattr_to_inode(*pinode, &fattr);
+               rc = cifs_fattr_to_inode(*pinode, &fattr);
        }
 
 posix_open_ret:
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;
index 80bf4c6f4c7bc7d209e95898b8ec43cb29104424..e563c0fb47cbc9ac2128db31620b08515d81825f 100644 (file)
@@ -119,9 +119,7 @@ retry:
                        /* update inode in place
                         * if both i_ino and i_mode didn't change */
                        if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid &&
-                           (inode->i_mode & S_IFMT) ==
-                           (fattr->cf_mode & S_IFMT)) {
-                               cifs_fattr_to_inode(inode, fattr);
+                           cifs_fattr_to_inode(inode, fattr) == 0) {
                                dput(dentry);
                                return;
                        }