diff options
author | Steve French <sfrench@us.ibm.com> | 2007-02-26 11:46:11 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-02-26 11:46:11 -0500 |
commit | 3677db10a635a39f63ea509f8f0056d95589ff90 (patch) | |
tree | 5256a408110c91947d9b9543199003fb976948a8 /fs/cifs/readdir.c | |
parent | 9654640d0af8f2de40ff3807d3695109d3463f54 (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/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 6 |
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 @@ | |||
3 | * | 3 | * |
4 | * Directory search handling | 4 | * Directory search handling |
5 | * | 5 | * |
6 | * Copyright (C) International Business Machines Corp., 2004, 2005 | 6 | * Copyright (C) International Business Machines Corp., 2004, 2007 |
7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
8 | * | 8 | * |
9 | * This library is free software; you can redistribute it and/or modify | 9 | * 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, | |||
226 | atomic_set(&cifsInfo->inUse, 1); | 226 | atomic_set(&cifsInfo->inUse, 1); |
227 | } | 227 | } |
228 | 228 | ||
229 | spin_lock(&tmp_inode->i_lock); | ||
229 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 230 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
230 | /* can not safely change the file size here if the | 231 | /* can not safely change the file size here if the |
231 | client is writing to it due to potential races */ | 232 | 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, | |||
235 | /* for this calculation, even though the reported blocksize is larger */ | 236 | /* for this calculation, even though the reported blocksize is larger */ |
236 | tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; | 237 | tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; |
237 | } | 238 | } |
239 | spin_unlock(&tmp_inode->i_lock); | ||
238 | 240 | ||
239 | if (allocation_size < end_of_file) | 241 | if (allocation_size < end_of_file) |
240 | cFYI(1, ("May be sparse file, allocation less than file size")); | 242 | 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, | |||
355 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); | 357 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); |
356 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); | 358 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); |
357 | 359 | ||
360 | spin_lock(&tmp_inode->i_lock); | ||
358 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 361 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
359 | /* can not safely change the file size here if the | 362 | /* can not safely change the file size here if the |
360 | client is writing to it due to potential races */ | 363 | client is writing to it due to potential races */ |
@@ -364,6 +367,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
364 | /* for this calculation, not the real blocksize */ | 367 | /* for this calculation, not the real blocksize */ |
365 | tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | 368 | tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; |
366 | } | 369 | } |
370 | spin_unlock(&tmp_inode->i_lock); | ||
367 | 371 | ||
368 | if (S_ISREG(tmp_inode->i_mode)) { | 372 | if (S_ISREG(tmp_inode->i_mode)) { |
369 | cFYI(1, ("File inode")); | 373 | cFYI(1, ("File inode")); |