diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-05-07 23:02:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-08 11:07:17 -0400 |
commit | 75dff55af9a989293e9f9bacf049858f4262bc08 (patch) | |
tree | 0de0ec3f7910ef24201ae2eaf3c3f4ae4cfcb7f7 /fs/locks.c | |
parent | 9d21f09ca03d1142f1988001f228d02581d8986c (diff) |
[PATCH] fs/locks.c: Fix lease_init
It is insane to be giving lease_init() the task of freeing the lock it is
supposed to initialise, given that the lock is not guaranteed to be
allocated on the stack. This causes lockups in fcntl_setlease().
Problem diagnosed by Daniel Hokka Zakrisson <daniel@hozac.com>
Also fix a slab leak in __setlease() due to an uninitialised return value.
Problem diagnosed by Björn Steinbrink.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Tested-by: Daniel Hokka Zakrisson <daniel@hozac.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/fs/locks.c b/fs/locks.c index efad798824dc..6f99c0a6f836 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -446,15 +446,14 @@ static struct lock_manager_operations lease_manager_ops = { | |||
446 | */ | 446 | */ |
447 | static int lease_init(struct file *filp, int type, struct file_lock *fl) | 447 | static int lease_init(struct file *filp, int type, struct file_lock *fl) |
448 | { | 448 | { |
449 | if (assign_type(fl, type) != 0) | ||
450 | return -EINVAL; | ||
451 | |||
449 | fl->fl_owner = current->files; | 452 | fl->fl_owner = current->files; |
450 | fl->fl_pid = current->tgid; | 453 | fl->fl_pid = current->tgid; |
451 | 454 | ||
452 | fl->fl_file = filp; | 455 | fl->fl_file = filp; |
453 | fl->fl_flags = FL_LEASE; | 456 | fl->fl_flags = FL_LEASE; |
454 | if (assign_type(fl, type) != 0) { | ||
455 | locks_free_lock(fl); | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | fl->fl_start = 0; | 457 | fl->fl_start = 0; |
459 | fl->fl_end = OFFSET_MAX; | 458 | fl->fl_end = OFFSET_MAX; |
460 | fl->fl_ops = NULL; | 459 | fl->fl_ops = NULL; |
@@ -466,16 +465,19 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl) | |||
466 | static int lease_alloc(struct file *filp, int type, struct file_lock **flp) | 465 | static int lease_alloc(struct file *filp, int type, struct file_lock **flp) |
467 | { | 466 | { |
468 | struct file_lock *fl = locks_alloc_lock(); | 467 | struct file_lock *fl = locks_alloc_lock(); |
469 | int error; | 468 | int error = -ENOMEM; |
470 | 469 | ||
471 | if (fl == NULL) | 470 | if (fl == NULL) |
472 | return -ENOMEM; | 471 | goto out; |
473 | 472 | ||
474 | error = lease_init(filp, type, fl); | 473 | error = lease_init(filp, type, fl); |
475 | if (error) | 474 | if (error) { |
476 | return error; | 475 | locks_free_lock(fl); |
476 | fl = NULL; | ||
477 | } | ||
478 | out: | ||
477 | *flp = fl; | 479 | *flp = fl; |
478 | return 0; | 480 | return error; |
479 | } | 481 | } |
480 | 482 | ||
481 | /* Check if two locks overlap each other. | 483 | /* Check if two locks overlap each other. |
@@ -1372,6 +1374,7 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1372 | goto out; | 1374 | goto out; |
1373 | 1375 | ||
1374 | if (my_before != NULL) { | 1376 | if (my_before != NULL) { |
1377 | *flp = *my_before; | ||
1375 | error = lease->fl_lmops->fl_change(my_before, arg); | 1378 | error = lease->fl_lmops->fl_change(my_before, arg); |
1376 | goto out; | 1379 | goto out; |
1377 | } | 1380 | } |