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: Jeff Layton <jlayton@redhat.com>
This commit is contained in:
@@ -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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
||||||
|
Reference in New Issue
Block a user