break;
case F_SETLK:
case F_SETLKW:
- err = fcntl_setlk(fd, cmd, (struct flock *) arg);
+ err = fcntl_setlk(fd, filp, cmd, (struct flock *) arg);
break;
case F_GETOWN:
/*
err = fcntl_getlk64(fd, (struct flock64 *) arg);
break;
case F_SETLK64:
- err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
+ err = fcntl_setlk64(fd, filp, cmd,
+ (struct flock64 *) arg);
break;
case F_SETLKW64:
- err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
+ err = fcntl_setlk64(fd, filp, cmd,
+ (struct flock64 *) arg);
break;
default:
err = do_fcntl(fd, cmd, arg, filp);
/* 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(unsigned int fd, unsigned int cmd, struct flock *l)
+int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
+ struct flock *l)
{
- struct file *filp;
+ struct file *f;
struct file_lock *file_lock = locks_alloc_lock();
struct flock flock;
struct inode *inode;
/* Get arguments and validate them ...
*/
- error = -EBADF;
- filp = fget(fd);
- if (!filp)
- goto out;
-
error = -EINVAL;
inode = filp->f_dentry->d_inode;
if (mapping->i_mmap_shared != NULL) {
error = -EAGAIN;
- goto out_putf;
+ goto out;
}
}
error = flock_to_posix_lock(filp, file_lock, &flock);
if (error)
- goto out_putf;
+ goto out;
error = -EBADF;
switch (flock.l_type) {
case F_RDLCK:
if (!(filp->f_mode & FMODE_READ))
- goto out_putf;
+ goto out;
break;
case F_WRLCK:
if (!(filp->f_mode & FMODE_WRITE))
- goto out_putf;
+ goto out;
break;
case F_UNLCK:
break;
}
}
if (!(filp->f_mode & 3))
- goto out_putf;
+ goto out;
break;
#endif
default:
error = -EINVAL;
- goto out_putf;
+ goto out;
}
+do_it:
if (filp->f_op && filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, file_lock);
if (error < 0)
- goto out_putf;
+ goto out;
}
error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);
-
-out_putf:
- fput(filp);
+ read_lock(¤t->files->file_lock);
+ f = fcheck(fd);
+ read_unlock(¤t->files->file_lock);
+ /* lost race with close, kill stuck lock if close didn't get it */
+ if (!error && flock.l_type != F_UNLCK && filp != f) {
+ file_lock->fl_type = F_UNLCK;
+ goto do_it;
+ }
out:
locks_free_lock(file_lock);
return error;
/* 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(unsigned int fd, unsigned int cmd, struct flock64 *l)
+int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
+ struct flock64 *l)
{
- struct file *filp;
+ struct file *f;
struct file_lock *file_lock = locks_alloc_lock();
struct flock64 flock;
struct inode *inode;
/* Get arguments and validate them ...
*/
- error = -EBADF;
- filp = fget(fd);
- if (!filp)
- goto out;
-
error = -EINVAL;
inode = filp->f_dentry->d_inode;
if (mapping->i_mmap_shared != NULL) {
error = -EAGAIN;
- goto out_putf;
+ goto out;
}
}
error = flock64_to_posix_lock(filp, file_lock, &flock);
if (error)
- goto out_putf;
+ goto out;
error = -EBADF;
switch (flock.l_type) {
case F_RDLCK:
if (!(filp->f_mode & FMODE_READ))
- goto out_putf;
+ goto out;
break;
case F_WRLCK:
if (!(filp->f_mode & FMODE_WRITE))
- goto out_putf;
+ goto out;
break;
case F_UNLCK:
break;
case F_EXLCK:
default:
error = -EINVAL;
- goto out_putf;
+ goto out;
}
+do_it:
if (filp->f_op && filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, file_lock);
if (error < 0)
- goto out_putf;
+ goto out;
}
error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64);
-
-out_putf:
- fput(filp);
+ read_lock(¤t->files->file_lock);
+ f = fcheck(fd);
+ read_unlock(¤t->files->file_lock);
+ /* lost race with close, kill stuck lock if close didn't get it */
+ if (!error && flock.l_type != F_UNLCK && filp != f) {
+ file_lock->fl_type = F_UNLCK;
+ goto do_it;
+ }
out:
locks_free_lock(file_lock);
return error;
#include <linux/fcntl.h>
extern int fcntl_getlk(unsigned int, struct flock *);
-extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
+extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
+ struct flock *);
extern int fcntl_getlk64(unsigned int, struct flock64 *);
-extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *);
+extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
+ struct flock64 *);
/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);