aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2007-02-26 11:46:11 -0500
committerSteve French <sfrench@us.ibm.com>2007-02-26 11:46:11 -0500
commit3677db10a635a39f63ea509f8f0056d95589ff90 (patch)
tree5256a408110c91947d9b9543199003fb976948a8 /fs/cifs/file.c
parent9654640d0af8f2de40ff3807d3695109d3463f54 (diff)
[CIFS] Fix locking problem around some cifs uses of i_size write
Could cause hangs on smp systems in i_size_read on a cifs inode whose size has been previously simultaneously updated from different processes. Thanks to Brian Wang for some great testing/debugging on this hard problem. Fixes kernel bugzilla #7903 CC: Shirish Pargoankar <shirishp@us.ibm.com> CC: Shaggy <shaggy@us.ibm.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c43
1 files changed, 23 insertions, 20 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index a1265c9bfec0..c07ff8317a8b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -879,18 +879,19 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
879 cifs_stats_bytes_written(pTcon, total_written); 879 cifs_stats_bytes_written(pTcon, total_written);
880 880
881 /* since the write may have blocked check these pointers again */ 881 /* since the write may have blocked check these pointers again */
882 if (file->f_path.dentry) { 882 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
883 if (file->f_path.dentry->d_inode) { 883 struct inode *inode = file->f_path.dentry->d_inode;
884 struct inode *inode = file->f_path.dentry->d_inode; 884/* Do not update local mtime - server will set its actual value on write
885 inode->i_ctime = inode->i_mtime = 885 * inode->i_ctime = inode->i_mtime =
886 current_fs_time(inode->i_sb); 886 * current_fs_time(inode->i_sb);*/
887 if (total_written > 0) { 887 if (total_written > 0) {
888 if (*poffset > file->f_path.dentry->d_inode->i_size) 888 spin_lock(&inode->i_lock);
889 i_size_write(file->f_path.dentry->d_inode, 889 if (*poffset > file->f_path.dentry->d_inode->i_size)
890 i_size_write(file->f_path.dentry->d_inode,
890 *poffset); 891 *poffset);
891 } 892 spin_unlock(&inode->i_lock);
892 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
893 } 893 }
894 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
894 } 895 }
895 FreeXid(xid); 896 FreeXid(xid);
896 return total_written; 897 return total_written;
@@ -1012,18 +1013,18 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
1012 cifs_stats_bytes_written(pTcon, total_written); 1013 cifs_stats_bytes_written(pTcon, total_written);
1013 1014
1014 /* since the write may have blocked check these pointers again */ 1015 /* since the write may have blocked check these pointers again */
1015 if (file->f_path.dentry) { 1016 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1016 if (file->f_path.dentry->d_inode) {
1017/*BB We could make this contingent on superblock ATIME flag too */ 1017/*BB We could make this contingent on superblock ATIME flag too */
1018/* file->f_path.dentry->d_inode->i_ctime = 1018/* file->f_path.dentry->d_inode->i_ctime =
1019 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/ 1019 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1020 if (total_written > 0) { 1020 if (total_written > 0) {
1021 if (*poffset > file->f_path.dentry->d_inode->i_size) 1021 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1022 i_size_write(file->f_path.dentry->d_inode, 1022 if (*poffset > file->f_path.dentry->d_inode->i_size)
1023 *poffset); 1023 i_size_write(file->f_path.dentry->d_inode,
1024 } 1024 *poffset);
1025 mark_inode_dirty_sync(file->f_path.dentry->d_inode); 1025 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
1026 } 1026 }
1027 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
1027 } 1028 }
1028 FreeXid(xid); 1029 FreeXid(xid);
1029 return total_written; 1030 return total_written;
@@ -1400,6 +1401,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
1400 xid = GetXid(); 1401 xid = GetXid();
1401 cFYI(1, ("commit write for page %p up to position %lld for %d", 1402 cFYI(1, ("commit write for page %p up to position %lld for %d",
1402 page, position, to)); 1403 page, position, to));
1404 spin_lock(&inode->i_lock);
1403 if (position > inode->i_size) { 1405 if (position > inode->i_size) {
1404 i_size_write(inode, position); 1406 i_size_write(inode, position);
1405 /* if (file->private_data == NULL) { 1407 /* if (file->private_data == NULL) {
@@ -1429,6 +1431,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
1429 cFYI(1, (" SetEOF (commit write) rc = %d", rc)); 1431 cFYI(1, (" SetEOF (commit write) rc = %d", rc));
1430 } */ 1432 } */
1431 } 1433 }
1434 spin_unlock(&inode->i_lock);
1432 if (!PageUptodate(page)) { 1435 if (!PageUptodate(page)) {
1433 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; 1436 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1434 /* can not rely on (or let) writepage write this data */ 1437 /* can not rely on (or let) writepage write this data */