Skip to main content

ioctl

Version

  • Linux v5.8.13

Abstract

long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
  • sys_ioctl()
    • ksys_ioctl()
      • security_file_ioctl()
      • do_vfs_ioctl()

Arguments

Return

Definitions

sys_ioctl()

  • fs/ioctl.c
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
return ksys_ioctl(fd, cmd, arg);
}

ksys_ioctl()

  • fs/ioctl.c
int ksys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct fd f = fdget(fd);
int error;

if (!f.file)
return -EBADF;

error = security_file_ioctl(f.file, cmd, arg);
if (error)
goto out;

error = do_vfs_ioctl(f.file, fd, cmd, arg);
if (error == -ENOIOCTLCMD)
error = vfs_ioctl(f.file, cmd, arg);

out:
fdput(f);
return error;
}

do_vfs_ioctl()

  • fs/ioctl.c
/*
* do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
* It's just a simple helper for sys_ioctl and compat_sys_ioctl.
*
* When you add any new common ioctls to the switches above and below,
* please ensure they have compatible arguments in compat mode.
*/
static int do_vfs_ioctl(struct file *filp, unsigned int fd,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
struct inode *inode = file_inode(filp);

switch (cmd) {
case FIOCLEX:
set_close_on_exec(fd, 1);
return 0;

case FIONCLEX:
set_close_on_exec(fd, 0);
return 0;

case FIONBIO:
return ioctl_fionbio(filp, argp);

case FIOASYNC:
return ioctl_fioasync(fd, filp, argp);

case FIOQSIZE:
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
S_ISLNK(inode->i_mode)) {
loff_t res = inode_get_bytes(inode);
return copy_to_user(argp, &res, sizeof(res)) ?
-EFAULT : 0;
}

return -ENOTTY;

case FIFREEZE:
return ioctl_fsfreeze(filp);

case FITHAW:
return ioctl_fsthaw(filp);

case FS_IOC_FIEMAP:
return ioctl_fiemap(filp, argp);

case FIGETBSZ:
/* anon_bdev filesystems may not have a block size */
if (!inode->i_sb->s_blocksize)
return -EINVAL;

return put_user(inode->i_sb->s_blocksize, (int __user *)argp);

case FICLONE:
return ioctl_file_clone(filp, arg, 0, 0, 0);

case FICLONERANGE:
return ioctl_file_clone_range(filp, argp);

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);
break;
}

return -ENOIOCTLCMD;
}

わからない部分

KVM の VM 作成などに ioctl を使うが,sys_ioctl のコードを読んでも KVM_CREATE_VM の処理などは書かれていない.

モジュール用の ioctl のハンドラはそのモジュール内で定義されるが,どうやってそこに飛んでいるのか今のところわかっていない.

以下は KVM_CREATE_VM のマクロを追ったときのメモ.

#define KVMIO 0xAE

# define _IOC_NONE 0U

#define _IOC(dir,type,nr,size) \
(((dir) << 0+8+8+14) | \
((type) << 0+8) | \
((nr) << 0) | \
((size) << 0+8+8))

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)

#define KVM_CREATE_VM _IO(KVMIO, 0x01)
#define KVM_CREATE_VM   _IOC(0U,(0xAE),(0x01),0)
#define KVM_CREATE_VM   (((0)     << 30) | \
((0xAE) << 8) | \
((0x01) << 0) | \
((0) << 16))
0000 0000 0000 0000
1010 1110 0000 0000
0000 0000 0000 0001
0000 0000 0000 0000

0xAE01