Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+22 −5
Original line number Diff line number Diff line
@@ -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 @@ SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
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);
+22 −57
Original line number Diff line number Diff line
@@ -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 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
/* 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 @@ 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().
 */
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;
+4 −4
Original line number Diff line number Diff line
@@ -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);