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: Christoph Hellwig <hch@lst.de> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Jeff Layton <jlayton@redhat.com>
This commit is contained in:
Родитель
80b79dd0e2
Коммит
a75d30c772
27
fs/fcntl.c
27
fs/fcntl.c
|
@ -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,
|
||||
struct file *filp)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct flock flock;
|
||||
long err = -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -273,7 +275,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|||
case F_OFD_GETLK:
|
||||
#endif
|
||||
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;
|
||||
#if BITS_PER_LONG != 32
|
||||
/* 32-bit arches must use fcntl64() */
|
||||
|
@ -283,7 +289,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|||
/* Fallthrough */
|
||||
case F_SETLK:
|
||||
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;
|
||||
case F_GETOWN:
|
||||
/*
|
||||
|
@ -383,7 +391,9 @@ out:
|
|||
SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
|
||||
unsigned long, arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct fd f = fdget_raw(fd);
|
||||
struct flock64 flock;
|
||||
long err = -EBADF;
|
||||
|
||||
if (!f.file)
|
||||
|
@ -401,14 +411,21 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
|
|||
switch (cmd) {
|
||||
case F_GETLK64:
|
||||
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;
|
||||
case F_SETLK64:
|
||||
case F_SETLKW64:
|
||||
case F_OFD_SETLK:
|
||||
case F_OFD_SETLKW:
|
||||
err = fcntl_setlk64(fd, f.file, cmd,
|
||||
(struct flock64 __user *) arg);
|
||||
err = -EFAULT;
|
||||
if (copy_from_user(&flock, argp, sizeof(flock)))
|
||||
break;
|
||||
err = fcntl_setlk64(fd, f.file, cmd, &flock);
|
||||
break;
|
||||
default:
|
||||
err = do_fcntl(fd, cmd, arg, f.file);
|
||||
|
|
79
fs/locks.c
79
fs/locks.c
|
@ -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.
|
||||
* 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 flock flock;
|
||||
int error;
|
||||
|
||||
error = -EFAULT;
|
||||
if (copy_from_user(&flock, l, sizeof(flock)))
|
||||
goto out;
|
||||
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;
|
||||
|
||||
error = flock_to_posix_lock(filp, &file_lock, &flock);
|
||||
error = flock_to_posix_lock(filp, &file_lock, flock);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (cmd == F_OFD_GETLK) {
|
||||
error = -EINVAL;
|
||||
if (flock.l_pid != 0)
|
||||
if (flock->l_pid != 0)
|
||||
goto out;
|
||||
|
||||
cmd = F_GETLK;
|
||||
|
@ -2115,15 +2111,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
|
|||
if (error)
|
||||
goto out;
|
||||
|
||||
flock.l_type = file_lock.fl_type;
|
||||
flock->l_type = file_lock.fl_type;
|
||||
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)
|
||||
goto rel_priv;
|
||||
}
|
||||
error = -EFAULT;
|
||||
if (!copy_to_user(l, &flock, sizeof(flock)))
|
||||
error = 0;
|
||||
rel_priv:
|
||||
locks_release_private(&file_lock);
|
||||
out:
|
||||
|
@ -2216,26 +2209,16 @@ check_fmode_for_setlk(struct file_lock *fl)
|
|||
* This implements both the F_SETLK and F_SETLKW commands of fcntl().
|
||||
*/
|
||||
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 flock flock;
|
||||
struct inode *inode;
|
||||
struct inode *inode = locks_inode(filp);
|
||||
struct file *f;
|
||||
int error;
|
||||
|
||||
if (file_lock == NULL)
|
||||
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
|
||||
* and shared.
|
||||
*/
|
||||
|
@ -2244,7 +2227,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
goto out;
|
||||
}
|
||||
|
||||
error = flock_to_posix_lock(filp, file_lock, &flock);
|
||||
error = flock_to_posix_lock(filp, file_lock, flock);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
@ -2259,7 +2242,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
switch (cmd) {
|
||||
case F_OFD_SETLK:
|
||||
error = -EINVAL;
|
||||
if (flock.l_pid != 0)
|
||||
if (flock->l_pid != 0)
|
||||
goto out;
|
||||
|
||||
cmd = F_SETLK;
|
||||
|
@ -2268,7 +2251,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
break;
|
||||
case F_OFD_SETLKW:
|
||||
error = -EINVAL;
|
||||
if (flock.l_pid != 0)
|
||||
if (flock->l_pid != 0)
|
||||
goto out;
|
||||
|
||||
cmd = F_SETLKW;
|
||||
|
@ -2313,26 +2296,22 @@ out:
|
|||
/* Report the first existing lock that would conflict with l.
|
||||
* 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 flock64 flock;
|
||||
int error;
|
||||
|
||||
error = -EFAULT;
|
||||
if (copy_from_user(&flock, l, sizeof(flock)))
|
||||
goto out;
|
||||
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;
|
||||
|
||||
error = flock64_to_posix_lock(filp, &file_lock, &flock);
|
||||
error = flock64_to_posix_lock(filp, &file_lock, flock);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (cmd == F_OFD_GETLK) {
|
||||
error = -EINVAL;
|
||||
if (flock.l_pid != 0)
|
||||
if (flock->l_pid != 0)
|
||||
goto out;
|
||||
|
||||
cmd = F_GETLK64;
|
||||
|
@ -2344,13 +2323,9 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
|
|||
if (error)
|
||||
goto out;
|
||||
|
||||
flock.l_type = file_lock.fl_type;
|
||||
flock->l_type = file_lock.fl_type;
|
||||
if (file_lock.fl_type != F_UNLCK)
|
||||
posix_lock_to_flock64(&flock, &file_lock);
|
||||
|
||||
error = -EFAULT;
|
||||
if (!copy_to_user(l, &flock, sizeof(flock)))
|
||||
error = 0;
|
||||
posix_lock_to_flock64(flock, &file_lock);
|
||||
|
||||
locks_release_private(&file_lock);
|
||||
out:
|
||||
|
@ -2361,26 +2336,16 @@ out:
|
|||
* This implements both the F_SETLK and F_SETLKW commands of fcntl().
|
||||
*/
|
||||
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 flock64 flock;
|
||||
struct inode *inode;
|
||||
struct inode *inode = locks_inode(filp);
|
||||
struct file *f;
|
||||
int error;
|
||||
|
||||
if (file_lock == NULL)
|
||||
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
|
||||
* and shared.
|
||||
*/
|
||||
|
@ -2389,7 +2354,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
goto out;
|
||||
}
|
||||
|
||||
error = flock64_to_posix_lock(filp, file_lock, &flock);
|
||||
error = flock64_to_posix_lock(filp, file_lock, flock);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
@ -2404,7 +2369,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
switch (cmd) {
|
||||
case F_OFD_SETLK:
|
||||
error = -EINVAL;
|
||||
if (flock.l_pid != 0)
|
||||
if (flock->l_pid != 0)
|
||||
goto out;
|
||||
|
||||
cmd = F_SETLK64;
|
||||
|
@ -2413,7 +2378,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
break;
|
||||
case F_OFD_SETLKW:
|
||||
error = -EINVAL;
|
||||
if (flock.l_pid != 0)
|
||||
if (flock->l_pid != 0)
|
||||
goto out;
|
||||
|
||||
cmd = F_SETLKW64;
|
||||
|
|
|
@ -1038,14 +1038,14 @@ static inline struct inode *locks_inode(const struct file *f)
|
|||
}
|
||||
|
||||
#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,
|
||||
struct flock __user *);
|
||||
struct flock *);
|
||||
|
||||
#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,
|
||||
struct flock64 __user *);
|
||||
struct flock64 *);
|
||||
#endif
|
||||
|
||||
extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
|
||||
|
|
Загрузка…
Ссылка в новой задаче