diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-03-23 14:40:56 -0400 |
---|---|---|
committer | Jeff Layton <jlayton@redhat.com> | 2012-03-23 14:40:56 -0400 |
commit | 597b027f694481ffeebcffe634c24b807198d46c (patch) | |
tree | 2dce2da017aa89c9e7465014ffa7aced11393b28 /fs | |
parent | e9492871fb0546f1b73f309d9e8c0f030bfdfdca (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 9 |
3 files changed, 11 insertions, 2 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d7e39b0de5b0..4ff6313f0a91 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -626,7 +626,7 @@ struct cifsInodeInfo { | |||
626 | bool delete_pending; /* DELETE_ON_CLOSE is set */ | 626 | bool delete_pending; /* DELETE_ON_CLOSE is set */ |
627 | bool invalid_mapping; /* pagecache is invalid */ | 627 | bool invalid_mapping; /* pagecache is invalid */ |
628 | unsigned long time; /* jiffies of last update of inode */ | 628 | unsigned long time; /* jiffies of last update of inode */ |
629 | u64 server_eof; /* current file size on server */ | 629 | u64 server_eof; /* current file size on server -- protected by i_lock */ |
630 | u64 uniqueid; /* server inode number */ | 630 | u64 uniqueid; /* server inode number */ |
631 | u64 createtime; /* creation time on server */ | 631 | u64 createtime; /* creation time on server */ |
632 | #ifdef CONFIG_CIFS_FSCACHE | 632 | #ifdef CONFIG_CIFS_FSCACHE |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5ec0b90b0444..b63bf5f0698a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -2044,7 +2044,9 @@ cifs_writev_complete(struct work_struct *work) | |||
2044 | int i = 0; | 2044 | int i = 0; |
2045 | 2045 | ||
2046 | if (wdata->result == 0) { | 2046 | if (wdata->result == 0) { |
2047 | spin_lock(&inode->i_lock); | ||
2047 | cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); | 2048 | cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); |
2049 | spin_unlock(&inode->i_lock); | ||
2048 | cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), | 2050 | cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), |
2049 | wdata->bytes); | 2051 | wdata->bytes); |
2050 | } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) | 2052 | } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 58ac0f0512e7..6883b08f848c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1399,7 +1399,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
1399 | return rc; | 1399 | return rc; |
1400 | } | 1400 | } |
1401 | 1401 | ||
1402 | /* update the file size (if needed) after a write */ | 1402 | /* |
1403 | * update the file size (if needed) after a write. Should be called with | ||
1404 | * the inode->i_lock held | ||
1405 | */ | ||
1403 | void | 1406 | void |
1404 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 1407 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
1405 | unsigned int bytes_written) | 1408 | unsigned int bytes_written) |
@@ -1471,7 +1474,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid, | |||
1471 | return rc; | 1474 | return rc; |
1472 | } | 1475 | } |
1473 | } else { | 1476 | } else { |
1477 | spin_lock(&dentry->d_inode->i_lock); | ||
1474 | cifs_update_eof(cifsi, *poffset, bytes_written); | 1478 | cifs_update_eof(cifsi, *poffset, bytes_written); |
1479 | spin_unlock(&dentry->d_inode->i_lock); | ||
1475 | *poffset += bytes_written; | 1480 | *poffset += bytes_written; |
1476 | } | 1481 | } |
1477 | } | 1482 | } |
@@ -2197,7 +2202,9 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2197 | if (written) { | 2202 | if (written) { |
2198 | len -= written; | 2203 | len -= written; |
2199 | total_written += written; | 2204 | total_written += written; |
2205 | spin_lock(&inode->i_lock); | ||
2200 | cifs_update_eof(CIFS_I(inode), *poffset, written); | 2206 | cifs_update_eof(CIFS_I(inode), *poffset, written); |
2207 | spin_unlock(&inode->i_lock); | ||
2201 | *poffset += written; | 2208 | *poffset += written; |
2202 | } else if (rc < 0) { | 2209 | } else if (rc < 0) { |
2203 | if (!total_written) | 2210 | if (!total_written) |