diff options
| author | Andy Adamson <andros@citi.umich.edu> | 2006-03-26 04:37:26 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-26 11:56:56 -0500 |
| commit | 5842add2f3b519111b6401f3a35862bd00a3aa7e (patch) | |
| tree | 299e5653ec2b7dfc9fa565920d7320bbf1c9c07e | |
| parent | 6dc0fe8f8b40854982929e4f24d8c65115769b60 (diff) | |
[PATCH] VFS,fs/locks.c,NFSD4: add race_free posix_lock_file_conf() interface
Lockd and the NFSv4 server both exercise a race condition where
posix_test_lock() is called either before or after posix_lock_file() to
deal with a denied lock request due to a conflicting lock.
Remove the race condition for the NFSv4 server by adding a new conflicting
lock parameter to __posix_lock_file() , changing the name to
__posix_lock_file_conf().
Keep posix_lock_file() interface, add posix_lock_conf() interface, both
call __posix_lock_file_conf().
[akpm@osdl.org: Put the EXPORT_SYMBOL() where it belongs]
Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | fs/locks.c | 32 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 |
2 files changed, 25 insertions, 8 deletions
diff --git a/fs/locks.c b/fs/locks.c index 4badf6a0e7b..4d9e71d43e7 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -792,9 +792,7 @@ out: | |||
| 792 | return error; | 792 | return error; |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | EXPORT_SYMBOL(posix_lock_file); | 795 | static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
| 796 | |||
| 797 | static int __posix_lock_file(struct inode *inode, struct file_lock *request) | ||
| 798 | { | 796 | { |
| 799 | struct file_lock *fl; | 797 | struct file_lock *fl; |
| 800 | struct file_lock *new_fl, *new_fl2; | 798 | struct file_lock *new_fl, *new_fl2; |
| @@ -818,6 +816,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) | |||
| 818 | continue; | 816 | continue; |
| 819 | if (!posix_locks_conflict(request, fl)) | 817 | if (!posix_locks_conflict(request, fl)) |
| 820 | continue; | 818 | continue; |
| 819 | if (conflock) | ||
| 820 | locks_copy_lock(conflock, fl); | ||
| 821 | error = -EAGAIN; | 821 | error = -EAGAIN; |
| 822 | if (!(request->fl_flags & FL_SLEEP)) | 822 | if (!(request->fl_flags & FL_SLEEP)) |
| 823 | goto out; | 823 | goto out; |
| @@ -987,8 +987,24 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) | |||
| 987 | */ | 987 | */ |
| 988 | int posix_lock_file(struct file *filp, struct file_lock *fl) | 988 | int posix_lock_file(struct file *filp, struct file_lock *fl) |
| 989 | { | 989 | { |
| 990 | return __posix_lock_file(filp->f_dentry->d_inode, fl); | 990 | return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL); |
| 991 | } | ||
| 992 | EXPORT_SYMBOL(posix_lock_file); | ||
| 993 | |||
| 994 | /** | ||
| 995 | * posix_lock_file_conf - Apply a POSIX-style lock to a file | ||
| 996 | * @filp: The file to apply the lock to | ||
| 997 | * @fl: The lock to be applied | ||
| 998 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
| 999 | * | ||
| 1000 | * Except for the conflock parameter, acts just like posix_lock_file. | ||
| 1001 | */ | ||
| 1002 | int posix_lock_file_conf(struct file *filp, struct file_lock *fl, | ||
| 1003 | struct file_lock *conflock) | ||
| 1004 | { | ||
| 1005 | return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock); | ||
| 991 | } | 1006 | } |
| 1007 | EXPORT_SYMBOL(posix_lock_file_conf); | ||
| 992 | 1008 | ||
| 993 | /** | 1009 | /** |
| 994 | * posix_lock_file_wait - Apply a POSIX-style lock to a file | 1010 | * posix_lock_file_wait - Apply a POSIX-style lock to a file |
| @@ -1004,7 +1020,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) | |||
| 1004 | int error; | 1020 | int error; |
| 1005 | might_sleep (); | 1021 | might_sleep (); |
| 1006 | for (;;) { | 1022 | for (;;) { |
| 1007 | error = __posix_lock_file(filp->f_dentry->d_inode, fl); | 1023 | error = posix_lock_file(filp, fl); |
| 1008 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) | 1024 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) |
| 1009 | break; | 1025 | break; |
| 1010 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | 1026 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
| @@ -1076,7 +1092,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
| 1076 | fl.fl_end = offset + count - 1; | 1092 | fl.fl_end = offset + count - 1; |
| 1077 | 1093 | ||
| 1078 | for (;;) { | 1094 | for (;;) { |
| 1079 | error = __posix_lock_file(inode, &fl); | 1095 | error = __posix_lock_file_conf(inode, &fl, NULL); |
| 1080 | if (error != -EAGAIN) | 1096 | if (error != -EAGAIN) |
| 1081 | break; | 1097 | break; |
| 1082 | if (!(fl.fl_flags & FL_SLEEP)) | 1098 | if (!(fl.fl_flags & FL_SLEEP)) |
| @@ -1689,7 +1705,7 @@ again: | |||
| 1689 | error = filp->f_op->lock(filp, cmd, file_lock); | 1705 | error = filp->f_op->lock(filp, cmd, file_lock); |
| 1690 | else { | 1706 | else { |
| 1691 | for (;;) { | 1707 | for (;;) { |
| 1692 | error = __posix_lock_file(inode, file_lock); | 1708 | error = posix_lock_file(filp, file_lock); |
| 1693 | if ((error != -EAGAIN) || (cmd == F_SETLK)) | 1709 | if ((error != -EAGAIN) || (cmd == F_SETLK)) |
| 1694 | break; | 1710 | break; |
| 1695 | error = wait_event_interruptible(file_lock->fl_wait, | 1711 | error = wait_event_interruptible(file_lock->fl_wait, |
| @@ -1832,7 +1848,7 @@ again: | |||
| 1832 | error = filp->f_op->lock(filp, cmd, file_lock); | 1848 | error = filp->f_op->lock(filp, cmd, file_lock); |
| 1833 | else { | 1849 | else { |
| 1834 | for (;;) { | 1850 | for (;;) { |
| 1835 | error = __posix_lock_file(inode, file_lock); | 1851 | error = posix_lock_file(filp, file_lock); |
| 1836 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) | 1852 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) |
| 1837 | break; | 1853 | break; |
| 1838 | error = wait_event_interruptible(file_lock->fl_wait, | 1854 | error = wait_event_interruptible(file_lock->fl_wait, |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 9674679525f..ab67181a5a5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -763,6 +763,7 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *); | |||
| 763 | extern void locks_remove_posix(struct file *, fl_owner_t); | 763 | extern void locks_remove_posix(struct file *, fl_owner_t); |
| 764 | extern void locks_remove_flock(struct file *); | 764 | extern void locks_remove_flock(struct file *); |
| 765 | extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *); | 765 | extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *); |
| 766 | extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *); | ||
| 766 | extern int posix_lock_file(struct file *, struct file_lock *); | 767 | extern int posix_lock_file(struct file *, struct file_lock *); |
| 767 | extern int posix_lock_file_wait(struct file *, struct file_lock *); | 768 | extern int posix_lock_file_wait(struct file *, struct file_lock *); |
| 768 | extern int posix_unblock_lock(struct file *, struct file_lock *); | 769 | extern int posix_unblock_lock(struct file *, struct file_lock *); |
