summaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2007-02-26 16:46:11 +0000
committerSteve French <sfrench@us.ibm.com>2007-02-26 16:46:11 +0000
commit3677db10a635a39f63ea509f8f0056d95589ff90 (patch)
tree5256a408110c91947d9b9543199003fb976948a8 /fs/cifs/readdir.c
parent9654640d0af8f2de40ff3807d3695109d3463f54 (diff)
downloadlinux-3677db10a635a39f63ea509f8f0056d95589ff90.tar.gz
linux-3677db10a635a39f63ea509f8f0056d95589ff90.tar.bz2
linux-3677db10a635a39f63ea509f8f0056d95589ff90.zip
[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/readdir.c')
-rw-r--r--fs/cifs/readdir.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index c444798f0740..44cfb528797d 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -3,7 +3,7 @@
*
* Directory search handling
*
- * Copyright (C) International Business Machines Corp., 2004, 2005
+ * Copyright (C) International Business Machines Corp., 2004, 2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -226,6 +226,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
atomic_set(&cifsInfo->inUse, 1);
}
+ spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
@@ -235,6 +236,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
/* for this calculation, even though the reported blocksize is larger */
tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
}
+ spin_unlock(&tmp_inode->i_lock);
if (allocation_size < end_of_file)
cFYI(1, ("May be sparse file, allocation less than file size"));
@@ -355,6 +357,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
+ spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
@@ -364,6 +367,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
/* for this calculation, not the real blocksize */
tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
}
+ spin_unlock(&tmp_inode->i_lock);
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode"));