Commit 597b027f authored by Jeff Layton's avatar Jeff Layton

cifs: call cifs_update_eof with i_lock held

cifs_update_eof has the potential to be racy if multiple threads are
trying to modify it at the same time. Protect modifications of the
server_eof value with the inode->i_lock.
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
parent e9492871
...@@ -626,7 +626,7 @@ struct cifsInodeInfo { ...@@ -626,7 +626,7 @@ struct cifsInodeInfo {
bool delete_pending; /* DELETE_ON_CLOSE is set */ bool delete_pending; /* DELETE_ON_CLOSE is set */
bool invalid_mapping; /* pagecache is invalid */ bool invalid_mapping; /* pagecache is invalid */
unsigned long time; /* jiffies of last update of inode */ unsigned long time; /* jiffies of last update of inode */
u64 server_eof; /* current file size on server */ u64 server_eof; /* current file size on server -- protected by i_lock */
u64 uniqueid; /* server inode number */ u64 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */ u64 createtime; /* creation time on server */
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
......
...@@ -2044,7 +2044,9 @@ cifs_writev_complete(struct work_struct *work) ...@@ -2044,7 +2044,9 @@ cifs_writev_complete(struct work_struct *work)
int i = 0; int i = 0;
if (wdata->result == 0) { if (wdata->result == 0) {
spin_lock(&inode->i_lock);
cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
spin_unlock(&inode->i_lock);
cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
wdata->bytes); wdata->bytes);
} else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
......
...@@ -1399,7 +1399,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) ...@@ -1399,7 +1399,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
return rc; return rc;
} }
/* update the file size (if needed) after a write */ /*
* update the file size (if needed) after a write. Should be called with
* the inode->i_lock held
*/
void void
cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written) unsigned int bytes_written)
...@@ -1471,7 +1474,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid, ...@@ -1471,7 +1474,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
return rc; return rc;
} }
} else { } else {
spin_lock(&dentry->d_inode->i_lock);
cifs_update_eof(cifsi, *poffset, bytes_written); cifs_update_eof(cifsi, *poffset, bytes_written);
spin_unlock(&dentry->d_inode->i_lock);
*poffset += bytes_written; *poffset += bytes_written;
} }
} }
...@@ -2197,7 +2202,9 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, ...@@ -2197,7 +2202,9 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
if (written) { if (written) {
len -= written; len -= written;
total_written += written; total_written += written;
spin_lock(&inode->i_lock);
cifs_update_eof(CIFS_I(inode), *poffset, written); cifs_update_eof(CIFS_I(inode), *poffset, written);
spin_unlock(&inode->i_lock);
*poffset += written; *poffset += written;
} else if (rc < 0) { } else if (rc < 0) {
if (!total_written) if (!total_written)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment