Commit a75d30c7 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jeff Layton

fs/locks: pass kernel struct flock to fcntl_getlk/setlk

This will make it easier to implement a sane compat fcntl syscall.

[ jlayton: fix undeclared identifiers in 32-bit fcntl64 syscall handler ]
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
parent 80b79dd0
...@@ -246,6 +246,8 @@ static int f_getowner_uids(struct file *filp, unsigned long arg) ...@@ -246,6 +246,8 @@ static int f_getowner_uids(struct file *filp, unsigned long arg)
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
struct file *filp) struct file *filp)
{ {
void __user *argp = (void __user *)arg;
struct flock flock;
long err = -EINVAL; long err = -EINVAL;
switch (cmd) { switch (cmd) {
...@@ -273,7 +275,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, ...@@ -273,7 +275,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
case F_OFD_GETLK: case F_OFD_GETLK:
#endif #endif
case F_GETLK: case F_GETLK:
err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); if (copy_from_user(&flock, argp, sizeof(flock)))
return -EFAULT;
err = fcntl_getlk(filp, cmd, &flock);
if (!err && copy_to_user(argp, &flock, sizeof(flock)))
return -EFAULT;
break; break;
#if BITS_PER_LONG != 32 #if BITS_PER_LONG != 32
/* 32-bit arches must use fcntl64() */ /* 32-bit arches must use fcntl64() */
...@@ -283,7 +289,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, ...@@ -283,7 +289,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
/* Fallthrough */ /* Fallthrough */
case F_SETLK: case F_SETLK:
case F_SETLKW: case F_SETLKW:
err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); if (copy_from_user(&flock, argp, sizeof(flock)))
return -EFAULT;
err = fcntl_setlk(fd, filp, cmd, &flock);
break; break;
case F_GETOWN: case F_GETOWN:
/* /*
...@@ -383,7 +391,9 @@ SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) ...@@ -383,7 +391,9 @@ SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
unsigned long, arg) unsigned long, arg)
{ {
void __user *argp = (void __user *)arg;
struct fd f = fdget_raw(fd); struct fd f = fdget_raw(fd);
struct flock64 flock;
long err = -EBADF; long err = -EBADF;
if (!f.file) if (!f.file)
...@@ -401,14 +411,21 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, ...@@ -401,14 +411,21 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
switch (cmd) { switch (cmd) {
case F_GETLK64: case F_GETLK64:
case F_OFD_GETLK: case F_OFD_GETLK:
err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); err = -EFAULT;
if (copy_from_user(&flock, argp, sizeof(flock)))
break;
err = fcntl_getlk64(f.file, cmd, &flock);
if (!err && copy_to_user(argp, &flock, sizeof(flock)))
err = -EFAULT;
break; break;
case F_SETLK64: case F_SETLK64:
case F_SETLKW64: case F_SETLKW64:
case F_OFD_SETLK: case F_OFD_SETLK:
case F_OFD_SETLKW: case F_OFD_SETLKW:
err = fcntl_setlk64(fd, f.file, cmd, err = -EFAULT;
(struct flock64 __user *) arg); if (copy_from_user(&flock, argp, sizeof(flock)))
break;
err = fcntl_setlk64(fd, f.file, cmd, &flock);
break; break;
default: default:
err = do_fcntl(fd, cmd, arg, f.file); err = do_fcntl(fd, cmd, arg, f.file);
......
...@@ -2084,26 +2084,22 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) ...@@ -2084,26 +2084,22 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
/* Report the first existing lock that would conflict with l. /* Report the first existing lock that would conflict with l.
* This implements the F_GETLK command of fcntl(). * This implements the F_GETLK command of fcntl().
*/ */
int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
{ {
struct file_lock file_lock; struct file_lock file_lock;
struct flock flock;
int error; int error;
error = -EFAULT;
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
error = -EINVAL; error = -EINVAL;
if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
goto out; goto out;
error = flock_to_posix_lock(filp, &file_lock, &flock); error = flock_to_posix_lock(filp, &file_lock, flock);
if (error) if (error)
goto out; goto out;
if (cmd == F_OFD_GETLK) { if (cmd == F_OFD_GETLK) {
error = -EINVAL; error = -EINVAL;
if (flock.l_pid != 0) if (flock->l_pid != 0)
goto out; goto out;
cmd = F_GETLK; cmd = F_GETLK;
...@@ -2115,15 +2111,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) ...@@ -2115,15 +2111,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
if (error) if (error)
goto out; goto out;
flock.l_type = file_lock.fl_type; flock->l_type = file_lock.fl_type;
if (file_lock.fl_type != F_UNLCK) { if (file_lock.fl_type != F_UNLCK) {
error = posix_lock_to_flock(&flock, &file_lock); error = posix_lock_to_flock(flock, &file_lock);
if (error) if (error)
goto rel_priv; goto rel_priv;
} }
error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0;
rel_priv: rel_priv:
locks_release_private(&file_lock); locks_release_private(&file_lock);
out: out:
...@@ -2216,26 +2209,16 @@ check_fmode_for_setlk(struct file_lock *fl) ...@@ -2216,26 +2209,16 @@ check_fmode_for_setlk(struct file_lock *fl)
* This implements both the F_SETLK and F_SETLKW commands of fcntl(). * This implements both the F_SETLK and F_SETLKW commands of fcntl().
*/ */
int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
struct flock __user *l) struct flock *flock)
{ {
struct file_lock *file_lock = locks_alloc_lock(); struct file_lock *file_lock = locks_alloc_lock();
struct flock flock; struct inode *inode = locks_inode(filp);
struct inode *inode;
struct file *f; struct file *f;
int error; int error;
if (file_lock == NULL) if (file_lock == NULL)
return -ENOLCK; return -ENOLCK;
inode = locks_inode(filp);
/*
* This might block, so we do it before checking the inode.
*/
error = -EFAULT;
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
/* Don't allow mandatory locks on files that may be memory mapped /* Don't allow mandatory locks on files that may be memory mapped
* and shared. * and shared.
*/ */
...@@ -2244,7 +2227,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2244,7 +2227,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
goto out; goto out;
} }
error = flock_to_posix_lock(filp, file_lock, &flock); error = flock_to_posix_lock(filp, file_lock, flock);
if (error) if (error)
goto out; goto out;
...@@ -2259,7 +2242,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2259,7 +2242,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
switch (cmd) { switch (cmd) {
case F_OFD_SETLK: case F_OFD_SETLK:
error = -EINVAL; error = -EINVAL;
if (flock.l_pid != 0) if (flock->l_pid != 0)
goto out; goto out;
cmd = F_SETLK; cmd = F_SETLK;
...@@ -2268,7 +2251,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2268,7 +2251,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
break; break;
case F_OFD_SETLKW: case F_OFD_SETLKW:
error = -EINVAL; error = -EINVAL;
if (flock.l_pid != 0) if (flock->l_pid != 0)
goto out; goto out;
cmd = F_SETLKW; cmd = F_SETLKW;
...@@ -2313,26 +2296,22 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2313,26 +2296,22 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
/* Report the first existing lock that would conflict with l. /* Report the first existing lock that would conflict with l.
* This implements the F_GETLK command of fcntl(). * This implements the F_GETLK command of fcntl().
*/ */
int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
{ {
struct file_lock file_lock; struct file_lock file_lock;
struct flock64 flock;
int error; int error;
error = -EFAULT;
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
error = -EINVAL; error = -EINVAL;
if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
goto out; goto out;
error = flock64_to_posix_lock(filp, &file_lock, &flock); error = flock64_to_posix_lock(filp, &file_lock, flock);
if (error) if (error)
goto out; goto out;
if (cmd == F_OFD_GETLK) { if (cmd == F_OFD_GETLK) {
error = -EINVAL; error = -EINVAL;
if (flock.l_pid != 0) if (flock->l_pid != 0)
goto out; goto out;
cmd = F_GETLK64; cmd = F_GETLK64;
...@@ -2344,13 +2323,9 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) ...@@ -2344,13 +2323,9 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
if (error) if (error)
goto out; goto out;
flock.l_type = file_lock.fl_type; flock->l_type = file_lock.fl_type;
if (file_lock.fl_type != F_UNLCK) if (file_lock.fl_type != F_UNLCK)
posix_lock_to_flock64(&flock, &file_lock); posix_lock_to_flock64(flock, &file_lock);
error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0;
locks_release_private(&file_lock); locks_release_private(&file_lock);
out: out:
...@@ -2361,26 +2336,16 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) ...@@ -2361,26 +2336,16 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
* This implements both the F_SETLK and F_SETLKW commands of fcntl(). * This implements both the F_SETLK and F_SETLKW commands of fcntl().
*/ */
int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
struct flock64 __user *l) struct flock64 *flock)
{ {
struct file_lock *file_lock = locks_alloc_lock(); struct file_lock *file_lock = locks_alloc_lock();
struct flock64 flock; struct inode *inode = locks_inode(filp);
struct inode *inode;
struct file *f; struct file *f;
int error; int error;
if (file_lock == NULL) if (file_lock == NULL)
return -ENOLCK; return -ENOLCK;
/*
* This might block, so we do it before checking the inode.
*/
error = -EFAULT;
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
inode = locks_inode(filp);
/* Don't allow mandatory locks on files that may be memory mapped /* Don't allow mandatory locks on files that may be memory mapped
* and shared. * and shared.
*/ */
...@@ -2389,7 +2354,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2389,7 +2354,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
goto out; goto out;
} }
error = flock64_to_posix_lock(filp, file_lock, &flock); error = flock64_to_posix_lock(filp, file_lock, flock);
if (error) if (error)
goto out; goto out;
...@@ -2404,7 +2369,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2404,7 +2369,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
switch (cmd) { switch (cmd) {
case F_OFD_SETLK: case F_OFD_SETLK:
error = -EINVAL; error = -EINVAL;
if (flock.l_pid != 0) if (flock->l_pid != 0)
goto out; goto out;
cmd = F_SETLK64; cmd = F_SETLK64;
...@@ -2413,7 +2378,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -2413,7 +2378,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
break; break;
case F_OFD_SETLKW: case F_OFD_SETLKW:
error = -EINVAL; error = -EINVAL;
if (flock.l_pid != 0) if (flock->l_pid != 0)
goto out; goto out;
cmd = F_SETLKW64; cmd = F_SETLKW64;
......
...@@ -1038,14 +1038,14 @@ static inline struct inode *locks_inode(const struct file *f) ...@@ -1038,14 +1038,14 @@ static inline struct inode *locks_inode(const struct file *f)
} }
#ifdef CONFIG_FILE_LOCKING #ifdef CONFIG_FILE_LOCKING
extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *); extern int fcntl_getlk(struct file *, unsigned int, struct flock *);
extern int fcntl_setlk(unsigned int, struct file *, unsigned int, extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
struct flock __user *); struct flock *);
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 __user *); extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 *);
extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
struct flock64 __user *); struct flock64 *);
#endif #endif
extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment