|
@@ -1591,7 +1591,8 @@ out:
|
|
|
/* Apply the lock described by l to an open file descriptor.
|
|
|
* This implements both the F_SETLK and F_SETLKW commands of fcntl().
|
|
|
*/
|
|
|
-int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l)
|
|
|
+int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
|
|
|
+ struct flock __user *l)
|
|
|
{
|
|
|
struct file_lock *file_lock = locks_alloc_lock();
|
|
|
struct flock flock;
|
|
@@ -1620,6 +1621,7 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+again:
|
|
|
error = flock_to_posix_lock(filp, file_lock, &flock);
|
|
|
if (error)
|
|
|
goto out;
|
|
@@ -1648,25 +1650,33 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l)
|
|
|
if (error)
|
|
|
goto out;
|
|
|
|
|
|
- if (filp->f_op && filp->f_op->lock != NULL) {
|
|
|
+ if (filp->f_op && filp->f_op->lock != NULL)
|
|
|
error = filp->f_op->lock(filp, cmd, file_lock);
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ else {
|
|
|
+ for (;;) {
|
|
|
+ error = __posix_lock_file(inode, file_lock);
|
|
|
+ if ((error != -EAGAIN) || (cmd == F_SETLK))
|
|
|
+ break;
|
|
|
+ error = wait_event_interruptible(file_lock->fl_wait,
|
|
|
+ !file_lock->fl_next);
|
|
|
+ if (!error)
|
|
|
+ continue;
|
|
|
|
|
|
- for (;;) {
|
|
|
- error = __posix_lock_file(inode, file_lock);
|
|
|
- if ((error != -EAGAIN) || (cmd == F_SETLK))
|
|
|
+ locks_delete_block(file_lock);
|
|
|
break;
|
|
|
- error = wait_event_interruptible(file_lock->fl_wait,
|
|
|
- !file_lock->fl_next);
|
|
|
- if (!error)
|
|
|
- continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- locks_delete_block(file_lock);
|
|
|
- break;
|
|
|
+ /*
|
|
|
+ * Attempt to detect a close/fcntl race and recover by
|
|
|
+ * releasing the lock that was just acquired.
|
|
|
+ */
|
|
|
+ if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) {
|
|
|
+ flock.l_type = F_UNLCK;
|
|
|
+ goto again;
|
|
|
}
|
|
|
|
|
|
- out:
|
|
|
+out:
|
|
|
locks_free_lock(file_lock);
|
|
|
return error;
|
|
|
}
|
|
@@ -1724,7 +1734,8 @@ out:
|
|
|
/* Apply the lock described by l to an open file descriptor.
|
|
|
* This implements both the F_SETLK and F_SETLKW commands of fcntl().
|
|
|
*/
|
|
|
-int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
|
|
|
+int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
|
|
|
+ struct flock64 __user *l)
|
|
|
{
|
|
|
struct file_lock *file_lock = locks_alloc_lock();
|
|
|
struct flock64 flock;
|
|
@@ -1753,6 +1764,7 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+again:
|
|
|
error = flock64_to_posix_lock(filp, file_lock, &flock);
|
|
|
if (error)
|
|
|
goto out;
|
|
@@ -1781,22 +1793,30 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
|
|
|
if (error)
|
|
|
goto out;
|
|
|
|
|
|
- if (filp->f_op && filp->f_op->lock != NULL) {
|
|
|
+ if (filp->f_op && filp->f_op->lock != NULL)
|
|
|
error = filp->f_op->lock(filp, cmd, file_lock);
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ else {
|
|
|
+ for (;;) {
|
|
|
+ error = __posix_lock_file(inode, file_lock);
|
|
|
+ if ((error != -EAGAIN) || (cmd == F_SETLK64))
|
|
|
+ break;
|
|
|
+ error = wait_event_interruptible(file_lock->fl_wait,
|
|
|
+ !file_lock->fl_next);
|
|
|
+ if (!error)
|
|
|
+ continue;
|
|
|
|
|
|
- for (;;) {
|
|
|
- error = __posix_lock_file(inode, file_lock);
|
|
|
- if ((error != -EAGAIN) || (cmd == F_SETLK64))
|
|
|
+ locks_delete_block(file_lock);
|
|
|
break;
|
|
|
- error = wait_event_interruptible(file_lock->fl_wait,
|
|
|
- !file_lock->fl_next);
|
|
|
- if (!error)
|
|
|
- continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- locks_delete_block(file_lock);
|
|
|
- break;
|
|
|
+ /*
|
|
|
+ * Attempt to detect a close/fcntl race and recover by
|
|
|
+ * releasing the lock that was just acquired.
|
|
|
+ */
|
|
|
+ if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) {
|
|
|
+ flock.l_type = F_UNLCK;
|
|
|
+ goto again;
|
|
|
}
|
|
|
|
|
|
out:
|
|
@@ -1888,12 +1908,7 @@ void locks_remove_flock(struct file *filp)
|
|
|
|
|
|
while ((fl = *before) != NULL) {
|
|
|
if (fl->fl_file == filp) {
|
|
|
- /*
|
|
|
- * We might have a POSIX lock that was created at the same time
|
|
|
- * the filp was closed for the last time. Just remove that too,
|
|
|
- * regardless of ownership, since nobody can own it.
|
|
|
- */
|
|
|
- if (IS_FLOCK(fl) || IS_POSIX(fl)) {
|
|
|
+ if (IS_FLOCK(fl)) {
|
|
|
locks_delete_lock(before);
|
|
|
continue;
|
|
|
}
|