aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-06-23 05:05:09 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:43:02 -0400
commit0d9a490abe1f69fda220f7866f6f23af41daa128 (patch)
tree499b7f9c44bb5a079f8ba303fefba402e603c314 /fs
parent090d2b185d8680fc26a2eaf4245d4171dcf4baf1 (diff)
[PATCH] locks: don't unnecessarily fail posix lock operations
posix_lock_file() was too cautious, failing operations on OOM, even if they didn't actually require an allocation. This has the disadvantage, that a failing unlock on process exit could lead to a memory leak. There are two possibilites for this: - filesystem implements .lock() and calls back to posix_lock_file(). On cleanup of files_struct locks_remove_posix() is called which should remove all locks belonging to files_struct. However if filesystem calls posix_lock_file() which fails, then those locks will never be freed. - if a file is closed while a lock is blocked, then after acquiring fcntl_setlk() will undo the lock. But this unlock itself might fail on OOM, again possibly leaking the lock. The solution is to move the checking of the allocations until after it is sure that they will be needed. This will solve the above problem since unlock will always succeed unless it splits an existing region. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/locks.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 69435c68c1e..c5ac6b40e76 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -834,14 +834,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
834 if (request->fl_flags & FL_ACCESS) 834 if (request->fl_flags & FL_ACCESS)
835 goto out; 835 goto out;
836 836
837 error = -ENOLCK; /* "no luck" */
838 if (!(new_fl && new_fl2))
839 goto out;
840
841 /* 837 /*
842 * We've allocated the new locks in advance, so there are no
843 * errors possible (and no blocking operations) from here on.
844 *
845 * Find the first old lock with the same owner as the new lock. 838 * Find the first old lock with the same owner as the new lock.
846 */ 839 */
847 840
@@ -938,10 +931,25 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
938 before = &fl->fl_next; 931 before = &fl->fl_next;
939 } 932 }
940 933
934 /*
935 * The above code only modifies existing locks in case of
936 * merging or replacing. If new lock(s) need to be inserted
937 * all modifications are done bellow this, so it's safe yet to
938 * bail out.
939 */
940 error = -ENOLCK; /* "no luck" */
941 if (right && left == right && !new_fl2)
942 goto out;
943
941 error = 0; 944 error = 0;
942 if (!added) { 945 if (!added) {
943 if (request->fl_type == F_UNLCK) 946 if (request->fl_type == F_UNLCK)
944 goto out; 947 goto out;
948
949 if (!new_fl) {
950 error = -ENOLCK;
951 goto out;
952 }
945 locks_copy_lock(new_fl, request); 953 locks_copy_lock(new_fl, request);
946 locks_insert_lock(before, new_fl); 954 locks_insert_lock(before, new_fl);
947 new_fl = NULL; 955 new_fl = NULL;