Skip to content

Commit 77b9040

Browse files
committed
compat_ioctl: simplify the implementation
Now that both native and compat ioctl syscalls are in the same file, a couple of simplifications can be made, bringing the implementation closer together: - do_vfs_ioctl(), ioctl_preallocate(), and compat_ioctl_preallocate() can become static, allowing the compiler to optimize better - slightly update the coding style for consistency between the functions. - rather than listing each command in two switch statements for the compat case, just call a single function that has all the common commands. As a side-effect, FS_IOC_RESVSP/FS_IOC_RESVSP64 are now available to x86 compat tasks, along with FS_IOC_RESVSP_32/FS_IOC_RESVSP64_32. This is harmless for i386 emulation, and can be considered a bugfix for x32 emulation, which never supported these in the past. Reviewed-by: Ben Hutchings <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
1 parent 2af563d commit 77b9040

File tree

4 files changed

+64
-105
lines changed

4 files changed

+64
-105
lines changed

fs/internal.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,5 @@ extern void mnt_pin_kill(struct mount *m);
180180
*/
181181
extern const struct dentry_operations ns_dentry_operations;
182182

183-
/*
184-
* fs/ioctl.c
185-
*/
186-
extern int do_vfs_ioctl(struct file *file, unsigned int fd, unsigned int cmd,
187-
unsigned long arg);
188-
189183
/* direct-io.c: */
190184
int sb_init_dio_done_wq(struct super_block *sb);

fs/ioctl.c

Lines changed: 64 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ EXPORT_SYMBOL(generic_block_fiemap);
467467
* Only the l_start, l_len and l_whence fields of the 'struct space_resv'
468468
* are used here, rest are ignored.
469469
*/
470-
int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
470+
static int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
471471
{
472472
struct inode *inode = file_inode(filp);
473473
struct space_resv sr;
@@ -495,8 +495,8 @@ int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
495495
/* on ia32 l_start is on a 32-bit boundary */
496496
#if defined CONFIG_COMPAT && defined(CONFIG_X86_64)
497497
/* just account for different alignment */
498-
int compat_ioctl_preallocate(struct file *file, int mode,
499-
struct space_resv_32 __user *argp)
498+
static int compat_ioctl_preallocate(struct file *file, int mode,
499+
struct space_resv_32 __user *argp)
500500
{
501501
struct inode *inode = file_inode(file);
502502
struct space_resv_32 sr;
@@ -521,11 +521,9 @@ int compat_ioctl_preallocate(struct file *file, int mode,
521521
}
522522
#endif
523523

524-
static int file_ioctl(struct file *filp, unsigned int cmd,
525-
unsigned long arg)
524+
static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p)
526525
{
527526
struct inode *inode = file_inode(filp);
528-
int __user *p = (int __user *)arg;
529527

530528
switch (cmd) {
531529
case FIBMAP:
@@ -542,7 +540,7 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
542540
return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
543541
}
544542

545-
return vfs_ioctl(filp, cmd, arg);
543+
return -ENOIOCTLCMD;
546544
}
547545

548546
static int ioctl_fionbio(struct file *filp, int __user *argp)
@@ -661,53 +659,48 @@ static int ioctl_file_dedupe_range(struct file *file,
661659
}
662660

663661
/*
664-
* When you add any new common ioctls to the switches above and below
665-
* please update compat_sys_ioctl() too.
666-
*
667662
* do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
668663
* It's just a simple helper for sys_ioctl and compat_sys_ioctl.
664+
*
665+
* When you add any new common ioctls to the switches above and below,
666+
* please ensure they have compatible arguments in compat mode.
669667
*/
670-
int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
671-
unsigned long arg)
668+
static int do_vfs_ioctl(struct file *filp, unsigned int fd,
669+
unsigned int cmd, unsigned long arg)
672670
{
673-
int error = 0;
674671
void __user *argp = (void __user *)arg;
675672
struct inode *inode = file_inode(filp);
676673

677674
switch (cmd) {
678675
case FIOCLEX:
679676
set_close_on_exec(fd, 1);
680-
break;
677+
return 0;
681678

682679
case FIONCLEX:
683680
set_close_on_exec(fd, 0);
684-
break;
681+
return 0;
685682

686683
case FIONBIO:
687-
error = ioctl_fionbio(filp, argp);
688-
break;
684+
return ioctl_fionbio(filp, argp);
689685

690686
case FIOASYNC:
691-
error = ioctl_fioasync(fd, filp, argp);
692-
break;
687+
return ioctl_fioasync(fd, filp, argp);
693688

694689
case FIOQSIZE:
695690
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
696691
S_ISLNK(inode->i_mode)) {
697692
loff_t res = inode_get_bytes(inode);
698-
error = copy_to_user(argp, &res, sizeof(res)) ?
699-
-EFAULT : 0;
700-
} else
701-
error = -ENOTTY;
702-
break;
693+
return copy_to_user(argp, &res, sizeof(res)) ?
694+
-EFAULT : 0;
695+
}
696+
697+
return -ENOTTY;
703698

704699
case FIFREEZE:
705-
error = ioctl_fsfreeze(filp);
706-
break;
700+
return ioctl_fsfreeze(filp);
707701

708702
case FITHAW:
709-
error = ioctl_fsthaw(filp);
710-
break;
703+
return ioctl_fsthaw(filp);
711704

712705
case FS_IOC_FIEMAP:
713706
return ioctl_fiemap(filp, argp);
@@ -716,6 +709,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
716709
/* anon_bdev filesystems may not have a block size */
717710
if (!inode->i_sb->s_blocksize)
718711
return -EINVAL;
712+
719713
return put_user(inode->i_sb->s_blocksize, (int __user *)argp);
720714

721715
case FICLONE:
@@ -729,24 +723,30 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
729723

730724
default:
731725
if (S_ISREG(inode->i_mode))
732-
error = file_ioctl(filp, cmd, arg);
733-
else
734-
error = vfs_ioctl(filp, cmd, arg);
726+
return file_ioctl(filp, cmd, argp);
735727
break;
736728
}
737-
return error;
729+
730+
return -ENOIOCTLCMD;
738731
}
739732

740733
int ksys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
741734
{
742-
int error;
743735
struct fd f = fdget(fd);
736+
int error;
744737

745738
if (!f.file)
746739
return -EBADF;
740+
747741
error = security_file_ioctl(f.file, cmd, arg);
748-
if (!error)
749-
error = do_vfs_ioctl(f.file, fd, cmd, arg);
742+
if (error)
743+
goto out;
744+
745+
error = do_vfs_ioctl(f.file, fd, cmd, arg);
746+
if (error == -ENOIOCTLCMD)
747+
error = vfs_ioctl(f.file, cmd, arg);
748+
749+
out:
750750
fdput(f);
751751
return error;
752752
}
@@ -790,92 +790,63 @@ long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
790790
EXPORT_SYMBOL(compat_ptr_ioctl);
791791

792792
COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
793-
compat_ulong_t, arg32)
793+
compat_ulong_t, arg)
794794
{
795-
unsigned long arg = arg32;
796795
struct fd f = fdget(fd);
797-
int error = -EBADF;
796+
int error;
797+
798798
if (!f.file)
799-
goto out;
799+
return -EBADF;
800800

801801
/* RED-PEN how should LSM module know it's handling 32bit? */
802802
error = security_file_ioctl(f.file, cmd, arg);
803803
if (error)
804-
goto out_fput;
804+
goto out;
805805

806806
switch (cmd) {
807-
/* these are never seen by ->ioctl(), no argument or int argument */
808-
case FIOCLEX:
809-
case FIONCLEX:
810-
case FIFREEZE:
811-
case FITHAW:
807+
/* FICLONE takes an int argument, so don't use compat_ptr() */
812808
case FICLONE:
813-
goto do_ioctl;
814-
/* these are never seen by ->ioctl(), pointer argument */
815-
case FIONBIO:
816-
case FIOASYNC:
817-
case FIOQSIZE:
818-
case FS_IOC_FIEMAP:
819-
case FIGETBSZ:
820-
case FICLONERANGE:
821-
case FIDEDUPERANGE:
822-
goto found_handler;
823-
/*
824-
* The next group is the stuff handled inside file_ioctl().
825-
* For regular files these never reach ->ioctl(); for
826-
* devices, sockets, etc. they do and one (FIONREAD) is
827-
* even accepted in some cases. In all those cases
828-
* argument has the same type, so we can handle these
829-
* here, shunting them towards do_vfs_ioctl().
830-
* ->compat_ioctl() will never see any of those.
831-
*/
832-
/* pointer argument, never actually handled by ->ioctl() */
833-
case FIBMAP:
834-
goto found_handler;
835-
/* handled by some ->ioctl(); always a pointer to int */
836-
case FIONREAD:
837-
goto found_handler;
838-
/* these get messy on amd64 due to alignment differences */
809+
error = ioctl_file_clone(f.file, arg, 0, 0, 0);
810+
break;
811+
839812
#if defined(CONFIG_X86_64)
813+
/* these get messy on amd64 due to alignment differences */
840814
case FS_IOC_RESVSP_32:
841815
case FS_IOC_RESVSP64_32:
842816
error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
843-
goto out_fput;
817+
break;
844818
case FS_IOC_UNRESVSP_32:
845819
case FS_IOC_UNRESVSP64_32:
846820
error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
847821
compat_ptr(arg));
848-
goto out_fput;
822+
break;
849823
case FS_IOC_ZERO_RANGE_32:
850824
error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
851825
compat_ptr(arg));
852-
goto out_fput;
853-
#else
854-
case FS_IOC_RESVSP:
855-
case FS_IOC_RESVSP64:
856-
case FS_IOC_UNRESVSP:
857-
case FS_IOC_UNRESVSP64:
858-
case FS_IOC_ZERO_RANGE:
859-
goto found_handler;
826+
break;
860827
#endif
861828

829+
/*
830+
* everything else in do_vfs_ioctl() takes either a compatible
831+
* pointer argument or no argument -- call it with a modified
832+
* argument.
833+
*/
862834
default:
863-
if (f.file->f_op->compat_ioctl) {
835+
error = do_vfs_ioctl(f.file, fd, cmd,
836+
(unsigned long)compat_ptr(arg));
837+
if (error != -ENOIOCTLCMD)
838+
break;
839+
840+
if (f.file->f_op->compat_ioctl)
864841
error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
865-
if (error != -ENOIOCTLCMD)
866-
goto out_fput;
867-
}
868-
error = -ENOTTY;
869-
goto out_fput;
842+
if (error == -ENOIOCTLCMD)
843+
error = -ENOTTY;
844+
break;
870845
}
871846

872-
found_handler:
873-
arg = (unsigned long)compat_ptr(arg);
874-
do_ioctl:
875-
error = do_vfs_ioctl(f.file, fd, cmd, arg);
876-
out_fput:
877-
fdput(f);
878847
out:
848+
fdput(f);
849+
879850
return error;
880851
}
881852
#endif

include/linux/falloc.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ struct space_resv_32 {
5151
#define FS_IOC_UNRESVSP64_32 _IOW ('X', 43, struct space_resv_32)
5252
#define FS_IOC_ZERO_RANGE_32 _IOW ('X', 57, struct space_resv_32)
5353

54-
int compat_ioctl_preallocate(struct file *, int, struct space_resv_32 __user *);
55-
5654
#endif
5755

5856
#endif /* _FALLOC_H_ */

include/linux/fs.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,10 +2552,6 @@ extern int finish_open(struct file *file, struct dentry *dentry,
25522552
int (*open)(struct inode *, struct file *));
25532553
extern int finish_no_open(struct file *file, struct dentry *dentry);
25542554

2555-
/* fs/ioctl.c */
2556-
2557-
extern int ioctl_preallocate(struct file *filp, int mode, void __user *argp);
2558-
25592555
/* fs/dcache.c */
25602556
extern void __init vfs_caches_init_early(void);
25612557
extern void __init vfs_caches_init(void);

0 commit comments

Comments
 (0)