diff options
author | david m. richter <richterd@citi.umich.edu> | 2007-07-31 03:39:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 18:39:42 -0400 |
commit | 9700382c3c9ff3e673e587084d76eedb3ba88668 (patch) | |
tree | 57ed58d87e765323692e463c8b7ee64f702dff0d | |
parent | 937472b00b666ecbf1464502f857ec63b024af72 (diff) |
VFS: fix a race in lease-breaking during truncate
It is possible that another process could acquire a new file lease right
after break_lease() is called during a truncate, but before lease-granting
is disabled by the subsequent get_write_access(). Merely switching the
order of the break_lease() and get_write_access() calls prevents this race.
Signed-off-by: David M. Richter <richterd@citi.umich.edu>
Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/open.c | 16 |
1 files changed, 9 insertions, 7 deletions
@@ -256,24 +256,26 @@ static long do_sys_truncate(const char __user * path, loff_t length) | |||
256 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 256 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
257 | goto dput_and_out; | 257 | goto dput_and_out; |
258 | 258 | ||
259 | /* | 259 | error = get_write_access(inode); |
260 | * Make sure that there are no leases. | ||
261 | */ | ||
262 | error = break_lease(inode, FMODE_WRITE); | ||
263 | if (error) | 260 | if (error) |
264 | goto dput_and_out; | 261 | goto dput_and_out; |
265 | 262 | ||
266 | error = get_write_access(inode); | 263 | /* |
264 | * Make sure that there are no leases. get_write_access() protects | ||
265 | * against the truncate racing with a lease-granting setlease(). | ||
266 | */ | ||
267 | error = break_lease(inode, FMODE_WRITE); | ||
267 | if (error) | 268 | if (error) |
268 | goto dput_and_out; | 269 | goto put_write_and_out; |
269 | 270 | ||
270 | error = locks_verify_truncate(inode, NULL, length); | 271 | error = locks_verify_truncate(inode, NULL, length); |
271 | if (!error) { | 272 | if (!error) { |
272 | DQUOT_INIT(inode); | 273 | DQUOT_INIT(inode); |
273 | error = do_truncate(nd.dentry, length, 0, NULL); | 274 | error = do_truncate(nd.dentry, length, 0, NULL); |
274 | } | 275 | } |
275 | put_write_access(inode); | ||
276 | 276 | ||
277 | put_write_and_out: | ||
278 | put_write_access(inode); | ||
277 | dput_and_out: | 279 | dput_and_out: |
278 | path_release(&nd); | 280 | path_release(&nd); |
279 | out: | 281 | out: |