@@ -130,7 +130,8 @@ extern int cifs_reconnect(struct TCP_Server_Info *server);
extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr);
extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
extern bool backup_cred(struct cifs_sb_info *);
-extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
+extern bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 eof,
+ bool from_readdir);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
@@ -186,7 +187,8 @@ 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 void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
+ bool from_readdir);
extern struct inode *cifs_iget(struct super_block *sb,
struct cifs_fattr *fattr);
@@ -165,7 +165,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
}
} else {
cifs_revalidate_mapping(*pinode);
- cifs_fattr_to_inode(*pinode, &fattr);
+ cifs_fattr_to_inode(*pinode, &fattr, false);
}
posix_open_ret:
@@ -4562,12 +4562,14 @@ static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
refreshing the inode only on increases in the file size
but this is tricky to do without racing with writebehind
page caching in the current Linux kernel design */
-bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
+bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
+ bool from_readdir)
{
if (!cifsInode)
return true;
- if (is_inode_writable(cifsInode)) {
+ if (is_inode_writable(cifsInode) ||
+ ((cifsInode->oplock & CIFS_CACHE_RW_FLG) != 0 && from_readdir)) {
/* This inode is open for write at least once */
struct cifs_sb_info *cifs_sb;
@@ -154,7 +154,8 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
/* populate an inode with info from a cifs_fattr struct */
void
-cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
+cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
+ bool from_readdir)
{
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -196,7 +197,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
* Can't safely change the file size here if the client is writing to
* it due to potential races.
*/
- if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
+ if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) {
i_size_write(inode, fattr->cf_eof);
/*
@@ -357,7 +358,7 @@ cifs_get_file_info_unix(struct file *filp)
rc = 0;
}
- cifs_fattr_to_inode(inode, &fattr);
+ cifs_fattr_to_inode(inode, &fattr, false);
free_xid(xid);
return rc;
}
@@ -427,7 +428,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
goto cgiiu_exit;
}
- cifs_fattr_to_inode(*pinode, &fattr);
+ cifs_fattr_to_inode(*pinode, &fattr, false);
}
cgiiu_exit:
@@ -707,7 +708,7 @@ 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);
+ cifs_fattr_to_inode(inode, &fattr, false);
cgfi_exit:
free_xid(xid);
return rc;
@@ -950,7 +951,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
goto cgii_exit;
}
- cifs_fattr_to_inode(*inode, &fattr);
+ cifs_fattr_to_inode(*inode, &fattr, false);
}
cgii_exit:
@@ -1048,7 +1049,8 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
}
}
- cifs_fattr_to_inode(inode, fattr);
+ /* can't fail - see cifs_find_inode() */
+ cifs_fattr_to_inode(inode, fattr, false);
if (sb->s_flags & SB_NOATIME)
inode->i_flags |= S_NOATIME | S_NOCMTIME;
if (inode->i_state & I_NEW) {
@@ -119,7 +119,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
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, true);
dput(dentry);
return;
}