OSDN Git Service

compat_ioctl: fix FIONREAD on devices
authorArnd Bergmann <arnd@arndb.de>
Fri, 7 Feb 2020 16:55:48 +0000 (17:55 +0100)
committerArnd Bergmann <arnd@arndb.de>
Sat, 8 Feb 2020 17:02:54 +0000 (18:02 +0100)
My final cleanup patch for sys_compat_ioctl() introduced a regression on
the FIONREAD ioctl command, which is used for both regular and special
files, but only works on regular files after my patch, as I had missed
the warning that Al Viro put into a comment right above it.

Change it back so it can work on any file again by moving the implementation
to do_vfs_ioctl() instead.

Fixes: 77b9040195de ("compat_ioctl: simplify the implementation")
Reported-and-tested-by: Christian Zigotzky <chzigotzky@xenosoft.de>
Reported-and-tested-by: youling257 <youling257@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
fs/ioctl.c

index 7c9a5df..5152c98 100644 (file)
@@ -523,13 +523,9 @@ static int compat_ioctl_preallocate(struct file *file, int mode,
 
 static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p)
 {
-       struct inode *inode = file_inode(filp);
-
        switch (cmd) {
        case FIBMAP:
                return ioctl_fibmap(filp, p);
-       case FIONREAD:
-               return put_user(i_size_read(inode) - filp->f_pos, p);
        case FS_IOC_RESVSP:
        case FS_IOC_RESVSP64:
                return ioctl_preallocate(filp, 0, p);
@@ -721,6 +717,13 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd,
        case FIDEDUPERANGE:
                return ioctl_file_dedupe_range(filp, argp);
 
+       case FIONREAD:
+               if (!S_ISREG(inode->i_mode))
+                       return vfs_ioctl(filp, cmd, arg);
+
+               return put_user(i_size_read(inode) - filp->f_pos,
+                               (int __user *)argp);
+
        default:
                if (S_ISREG(inode->i_mode))
                        return file_ioctl(filp, cmd, argp);