From 0ceaf6c700f8245946a163e387add8675a0c302f Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sat, 30 Oct 2010 17:31:13 -0400 Subject: locks: prevent ENOMEM on lease unlock Removing a lock shouldn't require any allocations; a failure due to ENOMEM leaves the caller with a choice between retrying or giving up and leaking an unused lease. Next we should split the other lease calls into add and delete cases. I wanted to start with just the bugfix. Signed-off-by: J. Bruce Fields Acked-by: Arnd Bergmann Signed-off-by: Linus Torvalds --- fs/locks.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/locks.c b/fs/locks.c index 50ec15927aa..06c77734f58 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1441,7 +1441,8 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) return 0; out: - locks_free_lock(lease); + if (arg != F_UNLCK) + locks_free_lock(lease); return error; } EXPORT_SYMBOL(generic_setlease); @@ -1493,17 +1494,16 @@ int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) } EXPORT_SYMBOL_GPL(vfs_setlease); -/** - * fcntl_setlease - sets a lease on an open file - * @fd: open file descriptor - * @filp: file pointer - * @arg: type of lease to obtain - * - * Call this fcntl to establish a lease on the file. - * Note that you also need to call %F_SETSIG to - * receive a signal when the lease is broken. - */ -int fcntl_setlease(unsigned int fd, struct file *filp, long arg) +static int do_fcntl_delete_lease(struct file *filp) +{ + struct file_lock fl, *flp = &fl; + + lease_init(filp, F_UNLCK, flp); + + return vfs_setlease(filp, F_UNLCK, &flp); +} + +static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) { struct file_lock *fl; struct fasync_struct *new; @@ -1521,7 +1521,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) } lock_flocks(); error = __vfs_setlease(filp, arg, &fl); - if (error || arg == F_UNLCK) + if (error) goto out_unlock; /* @@ -1549,6 +1549,23 @@ out_unlock: return error; } +/** + * fcntl_setlease - sets a lease on an open file + * @fd: open file descriptor + * @filp: file pointer + * @arg: type of lease to obtain + * + * Call this fcntl to establish a lease on the file. + * Note that you also need to call %F_SETSIG to + * receive a signal when the lease is broken. + */ +int fcntl_setlease(unsigned int fd, struct file *filp, long arg) +{ + if (arg == F_UNLCK) + return do_fcntl_delete_lease(filp); + return do_fcntl_add_lease(fd, filp, arg); +} + /** * flock_lock_file_wait - Apply a FLOCK-style lock to a file * @filp: The file to apply the lock to -- cgit v1.2.2