QA@IT
«回答へ戻る

760
 
 The new way of ioctl()
 [http://lwn.net/Articles/119652/](http://lwn.net/Articles/119652/)
+
+**追記(2016/01/30)**
+HAVE_UNLOCKED_IOCTLの定義はinclude/linux/fs.hの中にあります。もし未定義ならunlocked_ioctl(新ioctl)対応ではないという話です。自分で定義はしないで下さい。
+
+include/linux/fs.h
+```c
+/* These macros are for out of kernel modules to test that
+ * the kernel supports the unlocked_ioctl and compat_ioctl
+ * fields in struct file_operations. */
+#define HAVE_COMPAT_IOCTL 1
+#define HAVE_UNLOCKED_IOCTL 1
+...
+struct file_operations {
+	...
+	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
+	...
+};
+```
+
+次に仕組みの話ですが、わかりやすい解説記事があったので、リンクを貼っておきます。
+
+[http://opensourceforu.efytimes.com/2011/08/io-control-in-linux/](http://opensourceforu.efytimes.com/2011/08/io-control-in-linux/)
+
+この記事では新旧ioctlを両方サポートしているので、LINUX_VERSION_CODEを見て切り替えていますが、HAVE_UNLOCKED_IOCTLを見て切り替える方法もあると思います。また古いカーネルをサポートする必要がないなら、新ioctl(unlocked_ioctl)のみでよいと思います。
+
+上の記事からの引用
+```c
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
+static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
+#else
+static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+#endif
+```
+
+記事だと初期化の方法がgammodlerさんの方法とは少し違いますが、それが影響するかどうかは私にはよくわかりません。たぶんgammodlerさんの方法でもよさそうな気がしますが...
+
+あとこれも関係するかどうかわかりませんが、カーネルが64ビットで、ユーザ空間のプログラムが32ビットだと引数の型の調整が必要になると思います。ioctlの引数に含まれるポインタおよびlongのサイズが異なる(4バイトか8バイトか)ためです。この話はcompat_ioctlの方と関係してきます。
+
+でも現象から見ると、カーネルにはmy_ioctlをunlocked_ioctl(新ioctl)として登録しているのに、my_ioctlの方には余計な第1引数(inode)があるせいで(旧ioctl仕様)、準拠している仕様に矛盾があって、そのため引数が1個ずれて参照されているように見えます。私が思いつく原因はそれ位しかないんですよね。

include/linux/fs.hのstruct file_operationsを見ると

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。

追記
ちなみに新ioctlについての説明はここにあります。

The new way of ioctl()
http://lwn.net/Articles/119652/

追記(2016/01/30)
HAVE_UNLOCKED_IOCTLの定義はinclude/linux/fs.hの中にあります。もし未定義ならunlocked_ioctl(新ioctl)対応ではないという話です。自分で定義はしないで下さい。

include/linux/fs.h

/* These macros are for out of kernel modules to test that
 * the kernel supports the unlocked_ioctl and compat_ioctl
 * fields in struct file_operations. */
#define HAVE_COMPAT_IOCTL 1
#define HAVE_UNLOCKED_IOCTL 1
...
struct file_operations {
    ...
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    ...
};

次に仕組みの話ですが、わかりやすい解説記事があったので、リンクを貼っておきます。

http://opensourceforu.efytimes.com/2011/08/io-control-in-linux/

この記事では新旧ioctlを両方サポートしているので、LINUX_VERSION_CODEを見て切り替えていますが、HAVE_UNLOCKED_IOCTLを見て切り替える方法もあると思います。また古いカーネルをサポートする必要がないなら、新ioctl(unlocked_ioctl)のみでよいと思います。

上の記事からの引用

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif

記事だと初期化の方法がgammodlerさんの方法とは少し違いますが、それが影響するかどうかは私にはよくわかりません。たぶんgammodlerさんの方法でもよさそうな気がしますが...

あとこれも関係するかどうかわかりませんが、カーネルが64ビットで、ユーザ空間のプログラムが32ビットだと引数の型の調整が必要になると思います。ioctlの引数に含まれるポインタおよびlongのサイズが異なる(4バイトか8バイトか)ためです。この話はcompat_ioctlの方と関係してきます。

でも現象から見ると、カーネルにはmy_ioctlをunlocked_ioctl(新ioctl)として登録しているのに、my_ioctlの方には余計な第1引数(inode)があるせいで(旧ioctl仕様)、準拠している仕様に矛盾があって、そのため引数が1個ずれて参照されているように見えます。私が思いつく原因はそれ位しかないんですよね。

include/linux/fs.hのstruct file_operationsを見ると

```c
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
```

になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。

**追記**
ちなみに新ioctlについての説明はここにあります。

The new way of ioctl()
[http://lwn.net/Articles/119652/](http://lwn.net/Articles/119652/)

**追記(2016/01/30)**
HAVE_UNLOCKED_IOCTLの定義はinclude/linux/fs.hの中にあります。もし未定義ならunlocked_ioctl(新ioctl)対応ではないという話です。自分で定義はしないで下さい。

include/linux/fs.h
```c
/* These macros are for out of kernel modules to test that
 * the kernel supports the unlocked_ioctl and compat_ioctl
 * fields in struct file_operations. */
#define HAVE_COMPAT_IOCTL 1
#define HAVE_UNLOCKED_IOCTL 1
...
struct file_operations {
	...
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	...
};
```

次に仕組みの話ですが、わかりやすい解説記事があったので、リンクを貼っておきます。

[http://opensourceforu.efytimes.com/2011/08/io-control-in-linux/](http://opensourceforu.efytimes.com/2011/08/io-control-in-linux/)

この記事では新旧ioctlを両方サポートしているので、LINUX_VERSION_CODEを見て切り替えていますが、HAVE_UNLOCKED_IOCTLを見て切り替える方法もあると思います。また古いカーネルをサポートする必要がないなら、新ioctl(unlocked_ioctl)のみでよいと思います。

上の記事からの引用
```c
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif
```

記事だと初期化の方法がgammodlerさんの方法とは少し違いますが、それが影響するかどうかは私にはよくわかりません。たぶんgammodlerさんの方法でもよさそうな気がしますが...

あとこれも関係するかどうかわかりませんが、カーネルが64ビットで、ユーザ空間のプログラムが32ビットだと引数の型の調整が必要になると思います。ioctlの引数に含まれるポインタおよびlongのサイズが異なる(4バイトか8バイトか)ためです。この話はcompat_ioctlの方と関係してきます。

でも現象から見ると、カーネルにはmy_ioctlをunlocked_ioctl(新ioctl)として登録しているのに、my_ioctlの方には余計な第1引数(inode)があるせいで(旧ioctl仕様)、準拠している仕様に矛盾があって、そのため引数が1個ずれて参照されているように見えます。私が思いつく原因はそれ位しかないんですよね。

760
 ```
 
 になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。
+
+**追記**
+ちなみに新ioctlについての説明はここにあります。
+
+The new way of ioctl()
+[http://lwn.net/Articles/119652/](http://lwn.net/Articles/119652/)

include/linux/fs.hのstruct file_operationsを見ると

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。

追記
ちなみに新ioctlについての説明はここにあります。

The new way of ioctl()
http://lwn.net/Articles/119652/

include/linux/fs.hのstruct file_operationsを見ると

```c
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
```

になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。

**追記**
ちなみに新ioctlについての説明はここにあります。

The new way of ioctl()
[http://lwn.net/Articles/119652/](http://lwn.net/Articles/119652/)

回答を投稿

include/linux/fs.hのstruct file_operationsを見ると

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。

include/linux/fs.hのstruct file_operationsを見ると

```c
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
```

になっているので、旧ioctlの先頭引数inodeがなくなったせいでしょうかね。