Commit 5842add2f3b519111b6401f3a35862bd00a3aa7e
Committed by
Linus Torvalds
1 parent
6dc0fe8f8b
Exists in
master
and in
4 other branches
[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>
Showing 2 changed files with 25 additions and 8 deletions Side-by-side Diff
fs/locks.c
... | ... | @@ -792,9 +792,7 @@ |
792 | 792 | return error; |
793 | 793 | } |
794 | 794 | |
795 | -EXPORT_SYMBOL(posix_lock_file); | |
796 | - | |
797 | -static int __posix_lock_file(struct inode *inode, struct file_lock *request) | |
795 | +static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) | |
798 | 796 | { |
799 | 797 | struct file_lock *fl; |
800 | 798 | struct file_lock *new_fl, *new_fl2; |
... | ... | @@ -818,6 +816,8 @@ |
818 | 816 | continue; |
819 | 817 | if (!posix_locks_conflict(request, fl)) |
820 | 818 | continue; |
819 | + if (conflock) | |
820 | + locks_copy_lock(conflock, fl); | |
821 | 821 | error = -EAGAIN; |
822 | 822 | if (!(request->fl_flags & FL_SLEEP)) |
823 | 823 | goto out; |
824 | 824 | |
825 | 825 | |
... | ... | @@ -987,10 +987,26 @@ |
987 | 987 | */ |
988 | 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 | 991 | } |
992 | +EXPORT_SYMBOL(posix_lock_file); | |
992 | 993 | |
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); | |
1006 | +} | |
1007 | +EXPORT_SYMBOL(posix_lock_file_conf); | |
1008 | + | |
1009 | +/** | |
994 | 1010 | * posix_lock_file_wait - Apply a POSIX-style lock to a file |
995 | 1011 | * @filp: The file to apply the lock to |
996 | 1012 | * @fl: The lock to be applied |
... | ... | @@ -1004,7 +1020,7 @@ |
1004 | 1020 | int error; |
1005 | 1021 | might_sleep (); |
1006 | 1022 | for (;;) { |
1007 | - error = __posix_lock_file(filp->f_dentry->d_inode, fl); | |
1023 | + error = posix_lock_file(filp, fl); | |
1008 | 1024 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) |
1009 | 1025 | break; |
1010 | 1026 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
... | ... | @@ -1076,7 +1092,7 @@ |
1076 | 1092 | fl.fl_end = offset + count - 1; |
1077 | 1093 | |
1078 | 1094 | for (;;) { |
1079 | - error = __posix_lock_file(inode, &fl); | |
1095 | + error = __posix_lock_file_conf(inode, &fl, NULL); | |
1080 | 1096 | if (error != -EAGAIN) |
1081 | 1097 | break; |
1082 | 1098 | if (!(fl.fl_flags & FL_SLEEP)) |
... | ... | @@ -1689,7 +1705,7 @@ |
1689 | 1705 | error = filp->f_op->lock(filp, cmd, file_lock); |
1690 | 1706 | else { |
1691 | 1707 | for (;;) { |
1692 | - error = __posix_lock_file(inode, file_lock); | |
1708 | + error = posix_lock_file(filp, file_lock); | |
1693 | 1709 | if ((error != -EAGAIN) || (cmd == F_SETLK)) |
1694 | 1710 | break; |
1695 | 1711 | error = wait_event_interruptible(file_lock->fl_wait, |
... | ... | @@ -1832,7 +1848,7 @@ |
1832 | 1848 | error = filp->f_op->lock(filp, cmd, file_lock); |
1833 | 1849 | else { |
1834 | 1850 | for (;;) { |
1835 | - error = __posix_lock_file(inode, file_lock); | |
1851 | + error = posix_lock_file(filp, file_lock); | |
1836 | 1852 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) |
1837 | 1853 | break; |
1838 | 1854 | error = wait_event_interruptible(file_lock->fl_wait, |
include/linux/fs.h
... | ... | @@ -763,6 +763,7 @@ |
763 | 763 | extern void locks_remove_posix(struct file *, fl_owner_t); |
764 | 764 | extern void locks_remove_flock(struct file *); |
765 | 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 | 767 | extern int posix_lock_file(struct file *, struct file_lock *); |
767 | 768 | extern int posix_lock_file_wait(struct file *, struct file_lock *); |
768 | 769 | extern int posix_unblock_lock(struct file *, struct file_lock *); |