All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/24] block, scsi: final compat_ioctl cleanup
@ 2019-12-11 20:42 ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, corbet, catalin.marinas,
	will, jdike, richard, anton.ivanov, fujita.tomonori, justin,
	efremov, tim, mst, jasowang, pbonzini, stefanha, boris.ostrovsky,
	jgross, sstabellini, konrad.wilk, roger.pau, bp, davem,
	john.garry, brking, intel-linux-scu, artur.paszkiewicz,
	jinpu.wang, dgilbert, Kai.Makisara, damien.lemoal, hare,
	linux-doc, linux-block, linux-arm-kernel, linux-um, linux-scsi,
	linux-ide, virtualization, xen-devel, linux-fsdevel

Hi Jens, James and Martin,

This series concludes the work I did for linux-5.5 on the compat_ioctl()
cleanup, killing off fs/compat_ioctl.c and block/compat_ioctl.c by moving
everything into drivers.

Overall this would be a reduction both in complexity and line count, but
as I'm also adding documentation the overall number of lines increases
in the end.

My plan was originally to keep the SCSI and block parts separate.
This did not work easily because of interdependencies: I cannot
do the final SCSI cleanup in a good way without first addressing the
CDROM ioctls, so this is one series that I hope could be merged through
either the block or the scsi git trees, or possibly both if you can
pull in the same branch.

The series comes in these steps:

1. clean up the sg v3 interface as suggested by Linus. I have
   talked about this with Doug Gilbert as well, and he would
   rebase his sg v4 patches on top of "compat: scsi: sg: fix v3
   compat read/write interface"

2. Four patches for missing block compat_ioctl handlers, to be
   backported into stable kernels. Separate patches because they
   are needed in different stable versions.

3. Actually moving handlers out of block/compat_ioctl.c and
   block/scsi_ioctl.c into drivers, mixed in with cleanup
   patches

4. Document how to do this right. I keep getting asked about this,
   and it helps to point to some documentation file.

The series is avaialable for testing at [1].

       Arnd

[1] https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=compat-ioctl-endgame

Arnd Bergmann (24):
  compat: ARM64: always include asm-generic/compat.h
  compat: scsi: sg: fix v3 compat read/write interface
  compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE
  compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES
  compat_ioctl: block: handle add zone open, close and finish ioctl
  compat_ioctl: block: handle Persistent Reservations
  compaT_ioctl: ubd, aoe: use blkdev_compat_ptr_ioctl
  compat_ioctl: move CDROM_SEND_PACKET handling into scsi
  compat_ioctl: move CDROMREADADIO to cdrom.c
  compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN
  compat_ioctl: block: handle cdrom compat ioctl in non-cdrom drivers
  compat_ioctl: add scsi_compat_ioctl
  compat_ioctl: bsg: add handler
  compat_ioctl: ide: floppy: add handler
  compat_ioctl: scsi: move ioctl handling into drivers
  compat_ioctl: move sys_compat_ioctl() to ioctl.c
  compat_ioctl: simplify the implementation
  compat_ioctl: move cdrom commands into cdrom.c
  compat_ioctl: scsi: handle HDIO commands from drivers
  compat_ioctl: move HDIO ioctl handling into drivers/ide
  compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
  compat_ioctl: block: simplify compat_blkpg_ioctl()
  compat_ioctl: simplify up block/ioctl.c
  Documentation: document ioctl interfaces better

 Documentation/core-api/index.rst       |   1 +
 Documentation/core-api/ioctl.rst       | 250 +++++++++++++++
 arch/arm64/include/asm/compat.h        |   5 +-
 arch/um/drivers/ubd_kern.c             |   1 +
 block/Makefile                         |   1 -
 block/bsg.c                            |   1 +
 block/compat_ioctl.c                   | 411 -------------------------
 block/ioctl.c                          | 319 +++++++++++++++----
 block/scsi_ioctl.c                     | 214 ++++++++-----
 drivers/ata/libata-scsi.c              |   9 +
 drivers/block/aoe/aoeblk.c             |   1 +
 drivers/block/floppy.c                 |   3 +
 drivers/block/paride/pcd.c             |   3 +
 drivers/block/paride/pd.c              |   1 +
 drivers/block/paride/pf.c              |   1 +
 drivers/block/pktcdvd.c                |  26 +-
 drivers/block/sunvdc.c                 |   1 +
 drivers/block/virtio_blk.c             |   3 +
 drivers/block/xen-blkfront.c           |   1 +
 drivers/cdrom/cdrom.c                  |  35 ++-
 drivers/cdrom/gdrom.c                  |   3 +
 drivers/ide/ide-cd.c                   |  40 +++
 drivers/ide/ide-disk.c                 |   3 +
 drivers/ide/ide-floppy.c               |   4 +
 drivers/ide/ide-floppy.h               |   2 +
 drivers/ide/ide-floppy_ioctl.c         |  35 +++
 drivers/ide/ide-gd.c                   |  14 +
 drivers/ide/ide-ioctls.c               |  47 ++-
 drivers/ide/ide-tape.c                 |  14 +
 drivers/scsi/aic94xx/aic94xx_init.c    |   3 +
 drivers/scsi/ch.c                      |   9 +-
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |   3 +
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |   3 +
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |   3 +
 drivers/scsi/ipr.c                     |   3 +
 drivers/scsi/isci/init.c               |   3 +
 drivers/scsi/mvsas/mv_init.c           |   3 +
 drivers/scsi/pm8001/pm8001_init.c      |   3 +
 drivers/scsi/scsi_ioctl.c              |  54 +++-
 drivers/scsi/sd.c                      |  50 ++-
 drivers/scsi/sg.c                      | 169 +++++-----
 drivers/scsi/sr.c                      |  53 +++-
 drivers/scsi/st.c                      |  51 +--
 fs/Makefile                            |   2 +-
 fs/compat_ioctl.c                      | 261 ----------------
 fs/internal.h                          |   6 -
 fs/ioctl.c                             | 131 +++++---
 include/linux/blkdev.h                 |   7 +
 include/linux/falloc.h                 |   2 -
 include/linux/fs.h                     |   4 -
 include/linux/ide.h                    |   2 +
 include/linux/libata.h                 |   6 +
 include/scsi/scsi_ioctl.h              |   1 +
 include/scsi/sg.h                      |  30 ++
 54 files changed, 1249 insertions(+), 1062 deletions(-)
 create mode 100644 Documentation/core-api/ioctl.rst
 delete mode 100644 block/compat_ioctl.c
 delete mode 100644 fs/compat_ioctl.c

-- 
2.20.0

Cc: corbet@lwn.net
Cc: catalin.marinas@arm.com
Cc: will@kernel.org
Cc: jdike@addtoit.com
Cc: richard@nod.at
Cc: anton.ivanov@cambridgegreys.com
Cc: fujita.tomonori@lab.ntt.co.jp
Cc: justin@coraid.com
Cc: efremov@linux.com
Cc: tim@cyberelk.net
Cc: mst@redhat.com
Cc: jasowang@redhat.com
Cc: pbonzini@redhat.com
Cc: stefanha@redhat.com
Cc: boris.ostrovsky@oracle.com
Cc: jgross@suse.com
Cc: sstabellini@kernel.org
Cc: konrad.wilk@oracle.com
Cc: roger.pau@citrix.com
Cc: bp@alien8.de
Cc: davem@davemloft.net
Cc: john.garry@huawei.com
Cc: brking@us.ibm.com
Cc: intel-linux-scu@intel.com
Cc: artur.paszkiewicz@intel.com
Cc: jinpu.wang@cloud.ionos.com
Cc: dgilbert@interlog.com
Cc: Kai.Makisara@kolumbus.fi
Cc: arnd@arndb.de
Cc: damien.lemoal@hgst.com
Cc: hare@suse.com
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-block@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-um@lists.infradead.org
Cc: linux-scsi@vger.kernel.org
Cc: linux-ide@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Cc: xen-devel@lists.xenproject.org
Cc: linux-fsdevel@vger.kernel.org

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 00/24] block, scsi: final compat_ioctl cleanup
@ 2019-12-11 20:42 ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: justin, mst, catalin.marinas, jasowang, Kai.Makisara, linux-ide,
	artur.paszkiewicz, will, tim, anton.ivanov, hare, sstabellini,
	linux-scsi, corbet, y2038, richard, linux-doc, dgilbert,
	xen-devel, jinpu.wang, intel-linux-scu, Arnd Bergmann,
	konrad.wilk, jdike, john.garry, linux-um, efremov, linux-block,
	brking, bp, stefanha, boris.ostrovsky, virtualization,
	linux-arm-kernel, jgross, linux-kernel, fujita.tomonori,
	damien.lemoal, linux-fsdevel, pbonzini, davem, roger.pau

Hi Jens, James and Martin,

This series concludes the work I did for linux-5.5 on the compat_ioctl()
cleanup, killing off fs/compat_ioctl.c and block/compat_ioctl.c by moving
everything into drivers.

Overall this would be a reduction both in complexity and line count, but
as I'm also adding documentation the overall number of lines increases
in the end.

My plan was originally to keep the SCSI and block parts separate.
This did not work easily because of interdependencies: I cannot
do the final SCSI cleanup in a good way without first addressing the
CDROM ioctls, so this is one series that I hope could be merged through
either the block or the scsi git trees, or possibly both if you can
pull in the same branch.

The series comes in these steps:

1. clean up the sg v3 interface as suggested by Linus. I have
   talked about this with Doug Gilbert as well, and he would
   rebase his sg v4 patches on top of "compat: scsi: sg: fix v3
   compat read/write interface"

2. Four patches for missing block compat_ioctl handlers, to be
   backported into stable kernels. Separate patches because they
   are needed in different stable versions.

3. Actually moving handlers out of block/compat_ioctl.c and
   block/scsi_ioctl.c into drivers, mixed in with cleanup
   patches

4. Document how to do this right. I keep getting asked about this,
   and it helps to point to some documentation file.

The series is avaialable for testing at [1].

       Arnd

[1] https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=compat-ioctl-endgame

Arnd Bergmann (24):
  compat: ARM64: always include asm-generic/compat.h
  compat: scsi: sg: fix v3 compat read/write interface
  compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE
  compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES
  compat_ioctl: block: handle add zone open, close and finish ioctl
  compat_ioctl: block: handle Persistent Reservations
  compaT_ioctl: ubd, aoe: use blkdev_compat_ptr_ioctl
  compat_ioctl: move CDROM_SEND_PACKET handling into scsi
  compat_ioctl: move CDROMREADADIO to cdrom.c
  compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN
  compat_ioctl: block: handle cdrom compat ioctl in non-cdrom drivers
  compat_ioctl: add scsi_compat_ioctl
  compat_ioctl: bsg: add handler
  compat_ioctl: ide: floppy: add handler
  compat_ioctl: scsi: move ioctl handling into drivers
  compat_ioctl: move sys_compat_ioctl() to ioctl.c
  compat_ioctl: simplify the implementation
  compat_ioctl: move cdrom commands into cdrom.c
  compat_ioctl: scsi: handle HDIO commands from drivers
  compat_ioctl: move HDIO ioctl handling into drivers/ide
  compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
  compat_ioctl: block: simplify compat_blkpg_ioctl()
  compat_ioctl: simplify up block/ioctl.c
  Documentation: document ioctl interfaces better

 Documentation/core-api/index.rst       |   1 +
 Documentation/core-api/ioctl.rst       | 250 +++++++++++++++
 arch/arm64/include/asm/compat.h        |   5 +-
 arch/um/drivers/ubd_kern.c             |   1 +
 block/Makefile                         |   1 -
 block/bsg.c                            |   1 +
 block/compat_ioctl.c                   | 411 -------------------------
 block/ioctl.c                          | 319 +++++++++++++++----
 block/scsi_ioctl.c                     | 214 ++++++++-----
 drivers/ata/libata-scsi.c              |   9 +
 drivers/block/aoe/aoeblk.c             |   1 +
 drivers/block/floppy.c                 |   3 +
 drivers/block/paride/pcd.c             |   3 +
 drivers/block/paride/pd.c              |   1 +
 drivers/block/paride/pf.c              |   1 +
 drivers/block/pktcdvd.c                |  26 +-
 drivers/block/sunvdc.c                 |   1 +
 drivers/block/virtio_blk.c             |   3 +
 drivers/block/xen-blkfront.c           |   1 +
 drivers/cdrom/cdrom.c                  |  35 ++-
 drivers/cdrom/gdrom.c                  |   3 +
 drivers/ide/ide-cd.c                   |  40 +++
 drivers/ide/ide-disk.c                 |   3 +
 drivers/ide/ide-floppy.c               |   4 +
 drivers/ide/ide-floppy.h               |   2 +
 drivers/ide/ide-floppy_ioctl.c         |  35 +++
 drivers/ide/ide-gd.c                   |  14 +
 drivers/ide/ide-ioctls.c               |  47 ++-
 drivers/ide/ide-tape.c                 |  14 +
 drivers/scsi/aic94xx/aic94xx_init.c    |   3 +
 drivers/scsi/ch.c                      |   9 +-
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |   3 +
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |   3 +
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |   3 +
 drivers/scsi/ipr.c                     |   3 +
 drivers/scsi/isci/init.c               |   3 +
 drivers/scsi/mvsas/mv_init.c           |   3 +
 drivers/scsi/pm8001/pm8001_init.c      |   3 +
 drivers/scsi/scsi_ioctl.c              |  54 +++-
 drivers/scsi/sd.c                      |  50 ++-
 drivers/scsi/sg.c                      | 169 +++++-----
 drivers/scsi/sr.c                      |  53 +++-
 drivers/scsi/st.c                      |  51 +--
 fs/Makefile                            |   2 +-
 fs/compat_ioctl.c                      | 261 ----------------
 fs/internal.h                          |   6 -
 fs/ioctl.c                             | 131 +++++---
 include/linux/blkdev.h                 |   7 +
 include/linux/falloc.h                 |   2 -
 include/linux/fs.h                     |   4 -
 include/linux/ide.h                    |   2 +
 include/linux/libata.h                 |   6 +
 include/scsi/scsi_ioctl.h              |   1 +
 include/scsi/sg.h                      |  30 ++
 54 files changed, 1249 insertions(+), 1062 deletions(-)
 create mode 100644 Documentation/core-api/ioctl.rst
 delete mode 100644 block/compat_ioctl.c
 delete mode 100644 fs/compat_ioctl.c

-- 
2.20.0

Cc: corbet@lwn.net
Cc: catalin.marinas@arm.com
Cc: will@kernel.org
Cc: jdike@addtoit.com
Cc: richard@nod.at
Cc: anton.ivanov@cambridgegreys.com
Cc: fujita.tomonori@lab.ntt.co.jp
Cc: justin@coraid.com
Cc: efremov@linux.com
Cc: tim@cyberelk.net
Cc: mst@redhat.com
Cc: jasowang@redhat.com
Cc: pbonzini@redhat.com
Cc: stefanha@redhat.com
Cc: boris.ostrovsky@oracle.com
Cc: jgross@suse.com
Cc: sstabellini@kernel.org
Cc: konrad.wilk@oracle.com
Cc: roger.pau@citrix.com
Cc: bp@alien8.de
Cc: davem@davemloft.net
Cc: john.garry@huawei.com
Cc: brking@us.ibm.com
Cc: intel-linux-scu@intel.com
Cc: artur.paszkiewicz@intel.com
Cc: jinpu.wang@cloud.ionos.com
Cc: dgilbert@interlog.com
Cc: Kai.Makisara@kolumbus.fi
Cc: arnd@arndb.de
Cc: damien.lemoal@hgst.com
Cc: hare@suse.com
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-block@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-um@lists.infradead.org
Cc: linux-scsi@vger.kernel.org
Cc: linux-ide@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Cc: xen-devel@lists.xenproject.org
Cc: linux-fsdevel@vger.kernel.org

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [Xen-devel] [PATCH 00/24] block, scsi: final compat_ioctl cleanup
@ 2019-12-11 20:42 ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: justin, mst, catalin.marinas, jasowang, Kai.Makisara, linux-ide,
	artur.paszkiewicz, will, tim, anton.ivanov, hare, sstabellini,
	linux-scsi, corbet, y2038, richard, linux-doc, dgilbert,
	xen-devel, jinpu.wang, intel-linux-scu, Arnd Bergmann,
	konrad.wilk, jdike, john.garry, linux-um, efremov, linux-block,
	brking, bp, stefanha, boris.ostrovsky, virtualization,
	linux-arm-kernel, jgross, linux-kernel, fujita.tomonori,
	damien.lemoal, linux-fsdevel, pbonzini, davem, roger.pau

Hi Jens, James and Martin,

This series concludes the work I did for linux-5.5 on the compat_ioctl()
cleanup, killing off fs/compat_ioctl.c and block/compat_ioctl.c by moving
everything into drivers.

Overall this would be a reduction both in complexity and line count, but
as I'm also adding documentation the overall number of lines increases
in the end.

My plan was originally to keep the SCSI and block parts separate.
This did not work easily because of interdependencies: I cannot
do the final SCSI cleanup in a good way without first addressing the
CDROM ioctls, so this is one series that I hope could be merged through
either the block or the scsi git trees, or possibly both if you can
pull in the same branch.

The series comes in these steps:

1. clean up the sg v3 interface as suggested by Linus. I have
   talked about this with Doug Gilbert as well, and he would
   rebase his sg v4 patches on top of "compat: scsi: sg: fix v3
   compat read/write interface"

2. Four patches for missing block compat_ioctl handlers, to be
   backported into stable kernels. Separate patches because they
   are needed in different stable versions.

3. Actually moving handlers out of block/compat_ioctl.c and
   block/scsi_ioctl.c into drivers, mixed in with cleanup
   patches

4. Document how to do this right. I keep getting asked about this,
   and it helps to point to some documentation file.

The series is avaialable for testing at [1].

       Arnd

[1] https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=compat-ioctl-endgame

Arnd Bergmann (24):
  compat: ARM64: always include asm-generic/compat.h
  compat: scsi: sg: fix v3 compat read/write interface
  compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE
  compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES
  compat_ioctl: block: handle add zone open, close and finish ioctl
  compat_ioctl: block: handle Persistent Reservations
  compaT_ioctl: ubd, aoe: use blkdev_compat_ptr_ioctl
  compat_ioctl: move CDROM_SEND_PACKET handling into scsi
  compat_ioctl: move CDROMREADADIO to cdrom.c
  compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN
  compat_ioctl: block: handle cdrom compat ioctl in non-cdrom drivers
  compat_ioctl: add scsi_compat_ioctl
  compat_ioctl: bsg: add handler
  compat_ioctl: ide: floppy: add handler
  compat_ioctl: scsi: move ioctl handling into drivers
  compat_ioctl: move sys_compat_ioctl() to ioctl.c
  compat_ioctl: simplify the implementation
  compat_ioctl: move cdrom commands into cdrom.c
  compat_ioctl: scsi: handle HDIO commands from drivers
  compat_ioctl: move HDIO ioctl handling into drivers/ide
  compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
  compat_ioctl: block: simplify compat_blkpg_ioctl()
  compat_ioctl: simplify up block/ioctl.c
  Documentation: document ioctl interfaces better

 Documentation/core-api/index.rst       |   1 +
 Documentation/core-api/ioctl.rst       | 250 +++++++++++++++
 arch/arm64/include/asm/compat.h        |   5 +-
 arch/um/drivers/ubd_kern.c             |   1 +
 block/Makefile                         |   1 -
 block/bsg.c                            |   1 +
 block/compat_ioctl.c                   | 411 -------------------------
 block/ioctl.c                          | 319 +++++++++++++++----
 block/scsi_ioctl.c                     | 214 ++++++++-----
 drivers/ata/libata-scsi.c              |   9 +
 drivers/block/aoe/aoeblk.c             |   1 +
 drivers/block/floppy.c                 |   3 +
 drivers/block/paride/pcd.c             |   3 +
 drivers/block/paride/pd.c              |   1 +
 drivers/block/paride/pf.c              |   1 +
 drivers/block/pktcdvd.c                |  26 +-
 drivers/block/sunvdc.c                 |   1 +
 drivers/block/virtio_blk.c             |   3 +
 drivers/block/xen-blkfront.c           |   1 +
 drivers/cdrom/cdrom.c                  |  35 ++-
 drivers/cdrom/gdrom.c                  |   3 +
 drivers/ide/ide-cd.c                   |  40 +++
 drivers/ide/ide-disk.c                 |   3 +
 drivers/ide/ide-floppy.c               |   4 +
 drivers/ide/ide-floppy.h               |   2 +
 drivers/ide/ide-floppy_ioctl.c         |  35 +++
 drivers/ide/ide-gd.c                   |  14 +
 drivers/ide/ide-ioctls.c               |  47 ++-
 drivers/ide/ide-tape.c                 |  14 +
 drivers/scsi/aic94xx/aic94xx_init.c    |   3 +
 drivers/scsi/ch.c                      |   9 +-
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |   3 +
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |   3 +
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |   3 +
 drivers/scsi/ipr.c                     |   3 +
 drivers/scsi/isci/init.c               |   3 +
 drivers/scsi/mvsas/mv_init.c           |   3 +
 drivers/scsi/pm8001/pm8001_init.c      |   3 +
 drivers/scsi/scsi_ioctl.c              |  54 +++-
 drivers/scsi/sd.c                      |  50 ++-
 drivers/scsi/sg.c                      | 169 +++++-----
 drivers/scsi/sr.c                      |  53 +++-
 drivers/scsi/st.c                      |  51 +--
 fs/Makefile                            |   2 +-
 fs/compat_ioctl.c                      | 261 ----------------
 fs/internal.h                          |   6 -
 fs/ioctl.c                             | 131 +++++---
 include/linux/blkdev.h                 |   7 +
 include/linux/falloc.h                 |   2 -
 include/linux/fs.h                     |   4 -
 include/linux/ide.h                    |   2 +
 include/linux/libata.h                 |   6 +
 include/scsi/scsi_ioctl.h              |   1 +
 include/scsi/sg.h                      |  30 ++
 54 files changed, 1249 insertions(+), 1062 deletions(-)
 create mode 100644 Documentation/core-api/ioctl.rst
 delete mode 100644 block/compat_ioctl.c
 delete mode 100644 fs/compat_ioctl.c

-- 
2.20.0

Cc: corbet@lwn.net
Cc: catalin.marinas@arm.com
Cc: will@kernel.org
Cc: jdike@addtoit.com
Cc: richard@nod.at
Cc: anton.ivanov@cambridgegreys.com
Cc: fujita.tomonori@lab.ntt.co.jp
Cc: justin@coraid.com
Cc: efremov@linux.com
Cc: tim@cyberelk.net
Cc: mst@redhat.com
Cc: jasowang@redhat.com
Cc: pbonzini@redhat.com
Cc: stefanha@redhat.com
Cc: boris.ostrovsky@oracle.com
Cc: jgross@suse.com
Cc: sstabellini@kernel.org
Cc: konrad.wilk@oracle.com
Cc: roger.pau@citrix.com
Cc: bp@alien8.de
Cc: davem@davemloft.net
Cc: john.garry@huawei.com
Cc: brking@us.ibm.com
Cc: intel-linux-scu@intel.com
Cc: artur.paszkiewicz@intel.com
Cc: jinpu.wang@cloud.ionos.com
Cc: dgilbert@interlog.com
Cc: Kai.Makisara@kolumbus.fi
Cc: arnd@arndb.de
Cc: damien.lemoal@hgst.com
Cc: hare@suse.com
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-block@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-um@lists.infradead.org
Cc: linux-scsi@vger.kernel.org
Cc: linux-ide@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Cc: xen-devel@lists.xenproject.org
Cc: linux-fsdevel@vger.kernel.org

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h
  2019-12-11 20:42 ` Arnd Bergmann
@ 2019-12-11 20:42   ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Catalin Marinas, Will Deacon
  Cc: linux-kernel, y2038, Arnd Bergmann, linux-arm-kernel

In order to use compat_* type defininitions in device drivers
outside of CONFIG_COMPAT, move the inclusion of asm-generic/compat.h
ahead of the #ifdef.

All other architectures already do this.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/arm64/include/asm/compat.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index b0d53a265f1d..7b4172ce497c 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -4,6 +4,9 @@
  */
 #ifndef __ASM_COMPAT_H
 #define __ASM_COMPAT_H
+
+#include <asm-generic/compat.h>
+
 #ifdef CONFIG_COMPAT
 
 /*
@@ -13,8 +16,6 @@
 #include <linux/sched.h>
 #include <linux/sched/task_stack.h>
 
-#include <asm-generic/compat.h>
-
 #define COMPAT_USER_HZ		100
 #ifdef __AARCH64EB__
 #define COMPAT_UTS_MACHINE	"armv8b\0\0"
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h
@ 2019-12-11 20:42   ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Catalin Marinas, Will Deacon
  Cc: y2038, linux-kernel, Arnd Bergmann, linux-arm-kernel

In order to use compat_* type defininitions in device drivers
outside of CONFIG_COMPAT, move the inclusion of asm-generic/compat.h
ahead of the #ifdef.

All other architectures already do this.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/arm64/include/asm/compat.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index b0d53a265f1d..7b4172ce497c 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -4,6 +4,9 @@
  */
 #ifndef __ASM_COMPAT_H
 #define __ASM_COMPAT_H
+
+#include <asm-generic/compat.h>
+
 #ifdef CONFIG_COMPAT
 
 /*
@@ -13,8 +16,6 @@
 #include <linux/sched.h>
 #include <linux/sched/task_stack.h>
 
-#include <asm-generic/compat.h>
-
 #define COMPAT_USER_HZ		100
 #ifdef __AARCH64EB__
 #define COMPAT_UTS_MACHINE	"armv8b\0\0"
-- 
2.20.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 02/24] compat: scsi: sg: fix v3 compat read/write interface
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (2 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-12 16:25   ` Christoph Hellwig
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Douglas Gilbert, Arnd Bergmann
  Cc: linux-kernel, y2038, Steffen Maier, linux-scsi,
	Chaitanya Kulkarni, Greg Kroah-Hartman, Thomas Gleixner,
	linux-block

In the v5.4 merge window, a cleanup patch from Al Viro conflicted
with my rework of the compat handling for sg.c read(). Linus Torvalds
did a correct merge but pointed out that the resulting code is still
unsatisfactory.

I later noticed that the sg_new_read() function still gets the compat
mode wrong, when the 'count' argument is large enough to pass a
compat_sg_io_hdr object, but not a nativ sg_io_hdr.

To address both of these, move the definition of compat_sg_io_hdr
into a scsi/sg.h to make it visible to sg.c and rewrite the logic
for reading req_pack_id as well as the size check to a simpler
version that gets the expected results.

Fixes: c35a5cfb4150 ("scsi: sg: sg_read(): simplify reading ->pack_id of userland sg_io_hdr_t")
Fixes: 98aaaec4a150 ("compat_ioctl: reimplement SG_IO handling")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/scsi_ioctl.c |  29 +----------
 drivers/scsi/sg.c  | 125 +++++++++++++++++++++------------------------
 include/scsi/sg.h  |  30 +++++++++++
 3 files changed, 89 insertions(+), 95 deletions(-)

diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 650bade5ea5a..b61dbf4d8443 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -20,6 +20,7 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/sg.h>
 
 struct blk_cmd_filter {
 	unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
@@ -550,34 +551,6 @@ static inline int blk_send_start_stop(struct request_queue *q,
 	return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
 }
 
-#ifdef CONFIG_COMPAT
-struct compat_sg_io_hdr {
-	compat_int_t interface_id;	/* [i] 'S' for SCSI generic (required) */
-	compat_int_t dxfer_direction;	/* [i] data transfer direction  */
-	unsigned char cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
-	unsigned char mx_sb_len;	/* [i] max length to write to sbp */
-	unsigned short iovec_count;	/* [i] 0 implies no scatter gather */
-	compat_uint_t dxfer_len;	/* [i] byte count of data transfer */
-	compat_uint_t dxferp;		/* [i], [*io] points to data transfer memory
-						or scatter gather list */
-	compat_uptr_t cmdp;		/* [i], [*i] points to command to perform */
-	compat_uptr_t sbp;		/* [i], [*o] points to sense_buffer memory */
-	compat_uint_t timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
-	compat_uint_t flags;		/* [i] 0 -> default, see SG_FLAG... */
-	compat_int_t pack_id;		/* [i->o] unused internally (normally) */
-	compat_uptr_t usr_ptr;		/* [i->o] unused internally */
-	unsigned char status;		/* [o] scsi status */
-	unsigned char masked_status;	/* [o] shifted, masked scsi status */
-	unsigned char msg_status;	/* [o] messaging level data (optional) */
-	unsigned char sb_len_wr;	/* [o] byte count actually written to sbp */
-	unsigned short host_status;	/* [o] errors from host adapter */
-	unsigned short driver_status;	/* [o] errors from software driver */
-	compat_int_t resid;		/* [o] dxfer_len - actual_transferred */
-	compat_uint_t duration;		/* [o] time taken by cmd (unit: millisec) */
-	compat_uint_t info;		/* [o] auxiliary information */
-};
-#endif
-
 int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp)
 {
 #ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 160748ad9c0f..985546aac236 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -198,6 +198,7 @@ static void sg_device_destroy(struct kref *kref);
 
 #define SZ_SG_HEADER sizeof(struct sg_header)
 #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
+#define SZ_COMPAT_SG_IO_HDR sizeof(struct compat_sg_io_hdr)
 #define SZ_SG_IOVEC sizeof(sg_iovec_t)
 #define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
 
@@ -405,6 +406,36 @@ sg_release(struct inode *inode, struct file *filp)
 	return 0;
 }
 
+static int get_sg_io_pack_id(int *pack_id, void __user *buf, size_t count)
+{
+	struct sg_header __user *old_hdr = buf;
+	int reply_len;
+
+	if (count < SZ_SG_HEADER)
+		goto unknown_id;
+
+	/* negative reply_len means v3 format, otherwise v1/v2 */
+	if (get_user(reply_len, &old_hdr->reply_len))
+		return -EFAULT;
+	if (reply_len >= 0)
+		return get_user(*pack_id, &old_hdr->pack_id);
+
+	if (in_compat_syscall() && count >= SZ_COMPAT_SG_IO_HDR) {
+		struct compat_sg_io_hdr __user *hp = buf;
+		return get_user(*pack_id, &hp->pack_id);
+	}
+
+	if (count >= SZ_SG_IO_HDR) {
+		struct sg_io_hdr __user *hp = buf;
+		return get_user(*pack_id, &hp->pack_id);
+	}
+
+unknown_id:
+	/* no valid header was passed, so ignore the pack_id */
+	*pack_id = -1;
+	return 0;
+}
+
 static ssize_t
 sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 {
@@ -413,8 +444,8 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 	Sg_request *srp;
 	int req_pack_id = -1;
 	sg_io_hdr_t *hp;
-	struct sg_header *old_hdr = NULL;
-	int retval = 0;
+	struct sg_header *old_hdr;
+	int retval;
 
 	/*
 	 * This could cause a response to be stranded. Close the associated
@@ -429,79 +460,34 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
 				      "sg_read: count=%d\n", (int) count));
 
-	if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
-		old_hdr = memdup_user(buf, SZ_SG_HEADER);
-		if (IS_ERR(old_hdr))
-			return PTR_ERR(old_hdr);
-		if (old_hdr->reply_len < 0) {
-			if (count >= SZ_SG_IO_HDR) {
-				/*
-				 * This is stupid.
-				 *
-				 * We're copying the whole sg_io_hdr_t from user
-				 * space just to get the 'pack_id' field. But the
-				 * field is at different offsets for the compat
-				 * case, so we'll use "get_sg_io_hdr()" to copy
-				 * the whole thing and convert it.
-				 *
-				 * We could do something like just calculating the
-				 * offset based of 'in_compat_syscall()', but the
-				 * 'compat_sg_io_hdr' definition is in the wrong
-				 * place for that.
-				 */
-				sg_io_hdr_t *new_hdr;
-				new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL);
-				if (!new_hdr) {
-					retval = -ENOMEM;
-					goto free_old_hdr;
-				}
-				retval = get_sg_io_hdr(new_hdr, buf);
-				req_pack_id = new_hdr->pack_id;
-				kfree(new_hdr);
-				if (retval) {
-					retval = -EFAULT;
-					goto free_old_hdr;
-				}
-			}
-		} else
-			req_pack_id = old_hdr->pack_id;
-	}
+	if (sfp->force_packid)
+		retval = get_sg_io_pack_id(&req_pack_id, buf, count);
+	if (retval)
+		return retval;
+
 	srp = sg_get_rq_mark(sfp, req_pack_id);
 	if (!srp) {		/* now wait on packet to arrive */
-		if (atomic_read(&sdp->detaching)) {
-			retval = -ENODEV;
-			goto free_old_hdr;
-		}
-		if (filp->f_flags & O_NONBLOCK) {
-			retval = -EAGAIN;
-			goto free_old_hdr;
-		}
+		if (atomic_read(&sdp->detaching))
+			return -ENODEV;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
 		retval = wait_event_interruptible(sfp->read_wait,
 			(atomic_read(&sdp->detaching) ||
 			(srp = sg_get_rq_mark(sfp, req_pack_id))));
-		if (atomic_read(&sdp->detaching)) {
-			retval = -ENODEV;
-			goto free_old_hdr;
-		}
-		if (retval) {
+		if (atomic_read(&sdp->detaching))
+			return -ENODEV;
+		if (retval)
 			/* -ERESTARTSYS as signal hit process */
-			goto free_old_hdr;
-		}
-	}
-	if (srp->header.interface_id != '\0') {
-		retval = sg_new_read(sfp, buf, count, srp);
-		goto free_old_hdr;
+			return retval;
 	}
+	if (srp->header.interface_id != '\0')
+		return sg_new_read(sfp, buf, count, srp);
 
 	hp = &srp->header;
-	if (old_hdr == NULL) {
-		old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL);
-		if (! old_hdr) {
-			retval = -ENOMEM;
-			goto free_old_hdr;
-		}
-	}
-	memset(old_hdr, 0, SZ_SG_HEADER);
+	old_hdr = kzalloc(SZ_SG_HEADER, GFP_KERNEL);
+	if (!old_hdr)
+		return -ENOMEM;
+
 	old_hdr->reply_len = (int) hp->timeout;
 	old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */
 	old_hdr->pack_id = hp->pack_id;
@@ -575,7 +561,12 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
 	int err = 0, err2;
 	int len;
 
-	if (count < SZ_SG_IO_HDR) {
+	if (in_compat_syscall()) {
+		if (count < SZ_COMPAT_SG_IO_HDR) {
+			err = -EINVAL;
+			goto err_out;
+		}
+	} else if (count < SZ_SG_IO_HDR) {
 		err = -EINVAL;
 		goto err_out;
 	}
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index f91bcca604e4..29c7ad04d2e2 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -68,6 +68,36 @@ typedef struct sg_io_hdr
     unsigned int info;          /* [o] auxiliary information */
 } sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
+#if defined(__KERNEL__)
+#include <linux/compat.h>
+
+struct compat_sg_io_hdr {
+	compat_int_t interface_id;	/* [i] 'S' for SCSI generic (required) */
+	compat_int_t dxfer_direction;	/* [i] data transfer direction  */
+	unsigned char cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	unsigned char mx_sb_len;	/* [i] max length to write to sbp */
+	unsigned short iovec_count;	/* [i] 0 implies no scatter gather */
+	compat_uint_t dxfer_len;	/* [i] byte count of data transfer */
+	compat_uint_t dxferp;		/* [i], [*io] points to data transfer memory
+						or scatter gather list */
+	compat_uptr_t cmdp;		/* [i], [*i] points to command to perform */
+	compat_uptr_t sbp;		/* [i], [*o] points to sense_buffer memory */
+	compat_uint_t timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	compat_uint_t flags;		/* [i] 0 -> default, see SG_FLAG... */
+	compat_int_t pack_id;		/* [i->o] unused internally (normally) */
+	compat_uptr_t usr_ptr;		/* [i->o] unused internally */
+	unsigned char status;		/* [o] scsi status */
+	unsigned char masked_status;	/* [o] shifted, masked scsi status */
+	unsigned char msg_status;	/* [o] messaging level data (optional) */
+	unsigned char sb_len_wr;	/* [o] byte count actually written to sbp */
+	unsigned short host_status;	/* [o] errors from host adapter */
+	unsigned short driver_status;	/* [o] errors from software driver */
+	compat_int_t resid;		/* [o] dxfer_len - actual_transferred */
+	compat_uint_t duration;		/* [o] time taken by cmd (unit: millisec) */
+	compat_uint_t info;		/* [o] auxiliary information */
+};
+#endif
+
 #define SG_INTERFACE_ID_ORIG 'S'
 
 /* Use negative values to flag difference from original sg_header structure */
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 03/24] compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (3 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-12  1:20   ` Damien Le Moal
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jens Axboe, Hannes Reinecke, Damien Le Moal,
	Shaun Tancheff
  Cc: linux-kernel, y2038, Arnd Bergmann, stable, Shaun Tancheff,
	Christoph Hellwig, linux-block

These were added to blkdev_ioctl() but not blkdev_compat_ioctl,
so add them now.

Cc: <stable@vger.kernel.org> # v4.10+
Fixes: 3ed05a987e0f ("blk-zoned: implement ioctls")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 6ca015f92766..830f91e05fe3 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -354,6 +354,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	 * but we call blkdev_ioctl, which gets the lock for us
 	 */
 	case BLKRRPART:
+	case BLKREPORTZONE:
+	case BLKRESETZONE:
 		return blkdev_ioctl(bdev, mode, cmd,
 				(unsigned long)compat_ptr(arg));
 	case BLKBSZSET_32:
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 04/24] compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (4 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-12  1:20   ` Damien Le Moal
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Hannes Reinecke, Damien Le Moal
  Cc: linux-kernel, y2038, Arnd Bergmann, stable, Christoph Hellwig,
	linux-block

These were added to blkdev_ioctl() in v4.20 but not blkdev_compat_ioctl,
so add them now.

Cc: <stable@vger.kernel.org> # v4.20+
Fixes: 72cd87576d1d ("block: Introduce BLKGETZONESZ ioctl")
Fixes: 65e4e3eee83d ("block: Introduce BLKGETNRZONES ioctl")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 830f91e05fe3..f5c1140b8624 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -356,6 +356,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	case BLKRRPART:
 	case BLKREPORTZONE:
 	case BLKRESETZONE:
+	case BLKGETZONESZ:
+	case BLKGETNRZONES:
 		return blkdev_ioctl(bdev, mode, cmd,
 				(unsigned long)compat_ptr(arg));
 	case BLKBSZSET_32:
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 05/24] compat_ioctl: block: handle add zone open, close and finish ioctl
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (5 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-12  1:20   ` Damien Le Moal
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Javier González, Keith Busch, Hans Holmberg,
	Matias Bjorling
  Cc: linux-kernel, y2038, Arnd Bergmann, Christoph Hellwig,
	Ajay Joshi, Dmitry Fomichev, Damien Le Moal, linux-block

These were added to blkdev_ioctl() in linux-5.5 but not
blkdev_compat_ioctl, so add them now.

Fixes: e876df1fe0ad ("block: add zone open, close and finish ioctl support")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index f5c1140b8624..5b13e344229c 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -356,6 +356,9 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	case BLKRRPART:
 	case BLKREPORTZONE:
 	case BLKRESETZONE:
+	case BLKOPENZONE:
+	case BLKCLOSEZONE:
+	case BLKFINISHZONE:
 	case BLKGETZONESZ:
 	case BLKGETNRZONES:
 		return blkdev_ioctl(bdev, mode, cmd,
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 06/24] compat_ioctl: block: handle Persistent Reservations
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (6 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jens Axboe
  Cc: linux-kernel, y2038, Arnd Bergmann, stable, Christoph Hellwig,
	linux-block

These were added to blkdev_ioctl() in linux-5.5 but not
blkdev_compat_ioctl, so add them now.

Cc: <stable@vger.kernel.org> # v4.4+
Fixes: bbd3e064362e ("block: add an API for Persistent Reservations")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 5b13e344229c..f16ae92065d7 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -408,6 +408,14 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	case BLKTRACETEARDOWN: /* compatible */
 		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
 		return ret;
+	case IOC_PR_REGISTER:
+	case IOC_PR_RESERVE:
+	case IOC_PR_RELEASE:
+	case IOC_PR_PREEMPT:
+	case IOC_PR_PREEMPT_ABORT:
+	case IOC_PR_CLEAR:
+		return blkdev_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(arg));
 	default:
 		if (disk->fops->compat_ioctl)
 			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 07/24] compaT_ioctl: ubd, aoe: use blkdev_compat_ptr_ioctl
  2019-12-11 20:42 ` Arnd Bergmann
@ 2019-12-11 20:42   ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jeff Dike, Richard Weinberger, Anton Ivanov,
	Justin Sanders
  Cc: linux-kernel, y2038, Arnd Bergmann, Alex Dewar, Daniel Walter,
	Greg Kroah-Hartman, linux-um, linux-block

These drivers implement the HDIO_GET_IDENTITY and CDROMVOLREAD ioctl
commands, which are compatible between 32-bit and 64-bit user space and
traditionally handled by compat_blkdev_driver_ioctl().

As a prerequisite to removing that function, make both drivers use
blkdev_compat_ptr_ioctl() as their .compat_ioctl callback.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/um/drivers/ubd_kern.c | 1 +
 drivers/block/aoe/aoeblk.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 6627d7c30f37..582eb5b1f09b 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -113,6 +113,7 @@ static const struct block_device_operations ubd_blops = {
         .open		= ubd_open,
         .release	= ubd_release,
         .ioctl		= ubd_ioctl,
+        .compat_ioctl	= blkdev_compat_ptr_ioctl,
 	.getgeo		= ubd_getgeo,
 };
 
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index bd19f8af950b..7b32fb673375 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -329,6 +329,7 @@ static const struct block_device_operations aoe_bdops = {
 	.open = aoeblk_open,
 	.release = aoeblk_release,
 	.ioctl = aoeblk_ioctl,
+	.compat_ioctl = blkdev_compat_ptr_ioctl,
 	.getgeo = aoeblk_getgeo,
 	.owner = THIS_MODULE,
 };
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 07/24] compaT_ioctl: ubd, aoe: use blkdev_compat_ptr_ioctl
@ 2019-12-11 20:42   ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jeff Dike, Richard Weinberger, Anton Ivanov,
	Justin Sanders
  Cc: Arnd Bergmann, y2038, Greg Kroah-Hartman, linux-um, linux-kernel,
	linux-block, Daniel Walter, Alex Dewar

These drivers implement the HDIO_GET_IDENTITY and CDROMVOLREAD ioctl
commands, which are compatible between 32-bit and 64-bit user space and
traditionally handled by compat_blkdev_driver_ioctl().

As a prerequisite to removing that function, make both drivers use
blkdev_compat_ptr_ioctl() as their .compat_ioctl callback.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/um/drivers/ubd_kern.c | 1 +
 drivers/block/aoe/aoeblk.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 6627d7c30f37..582eb5b1f09b 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -113,6 +113,7 @@ static const struct block_device_operations ubd_blops = {
         .open		= ubd_open,
         .release	= ubd_release,
         .ioctl		= ubd_ioctl,
+        .compat_ioctl	= blkdev_compat_ptr_ioctl,
 	.getgeo		= ubd_getgeo,
 };
 
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index bd19f8af950b..7b32fb673375 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -329,6 +329,7 @@ static const struct block_device_operations aoe_bdops = {
 	.open = aoeblk_open,
 	.release = aoeblk_release,
 	.ioctl = aoeblk_ioctl,
+	.compat_ioctl = blkdev_compat_ptr_ioctl,
 	.getgeo = aoeblk_getgeo,
 	.owner = THIS_MODULE,
 };
-- 
2.20.0


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 08/24] compat_ioctl: move CDROM_SEND_PACKET handling into scsi
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (8 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-block
  Cc: linux-kernel, y2038, Arnd Bergmann, Chaitanya Kulkarni,
	Hannes Reinecke, Martin Wilck

There is only one implementation of this ioctl, so move the handling out
of the common block layer code into the place where it's actually needed.

It also gets called indirectly through pktcdvd, which needs to be aware
of this change.

As I noticed, the old implementation of the compat handler failed to
convert the structure on the way out, so the updated fields never got
written back to user space. This is either not important, or it has
never worked and should be fixed now.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c    |  47 +---------
 block/scsi_ioctl.c      | 185 ++++++++++++++++++++++++++++------------
 drivers/block/pktcdvd.c |   6 +-
 3 files changed, 135 insertions(+), 103 deletions(-)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index f16ae92065d7..578e04f94619 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -102,18 +102,6 @@ struct compat_cdrom_read_audio {
 	compat_caddr_t		buf;
 };
 
-struct compat_cdrom_generic_command {
-	unsigned char	cmd[CDROM_PACKET_SIZE];
-	compat_caddr_t	buffer;
-	compat_uint_t	buflen;
-	compat_int_t	stat;
-	compat_caddr_t	sense;
-	unsigned char	data_direction;
-	compat_int_t	quiet;
-	compat_int_t	timeout;
-	compat_caddr_t	reserved[1];
-};
-
 static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
 		unsigned int cmd, unsigned long arg)
 {
@@ -141,38 +129,6 @@ static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
 			(unsigned long)cdread_audio);
 }
 
-static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, unsigned long arg)
-{
-	struct cdrom_generic_command __user *cgc;
-	struct compat_cdrom_generic_command __user *cgc32;
-	u32 data;
-	unsigned char dir;
-	int itmp;
-
-	cgc = compat_alloc_user_space(sizeof(*cgc));
-	cgc32 = compat_ptr(arg);
-
-	if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
-	    get_user(data, &cgc32->buffer) ||
-	    put_user(compat_ptr(data), &cgc->buffer) ||
-	    copy_in_user(&cgc->buflen, &cgc32->buflen,
-			 (sizeof(unsigned int) + sizeof(int))) ||
-	    get_user(data, &cgc32->sense) ||
-	    put_user(compat_ptr(data), &cgc->sense) ||
-	    get_user(dir, &cgc32->data_direction) ||
-	    put_user(dir, &cgc->data_direction) ||
-	    get_user(itmp, &cgc32->quiet) ||
-	    put_user(itmp, &cgc->quiet) ||
-	    get_user(itmp, &cgc32->timeout) ||
-	    put_user(itmp, &cgc->timeout) ||
-	    get_user(data, &cgc32->reserved[0]) ||
-	    put_user(compat_ptr(data), &cgc->reserved[0]))
-		return -EFAULT;
-
-	return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
-}
-
 struct compat_blkpg_ioctl_arg {
 	compat_int_t op;
 	compat_int_t flags;
@@ -224,8 +180,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 		return compat_hdio_ioctl(bdev, mode, cmd, arg);
 	case CDROMREADAUDIO:
 		return compat_cdrom_read_audio(bdev, mode, cmd, arg);
-	case CDROM_SEND_PACKET:
-		return compat_cdrom_generic_command(bdev, mode, cmd, arg);
 
 	/*
 	 * No handler required for the ones below, we just need to
@@ -263,6 +217,7 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 	case CDROM_DISC_STATUS:
 	case CDROM_CHANGER_NSLOTS:
 	case CDROM_GET_CAPABILITY:
+	case CDROM_SEND_PACKET:
 	/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
 	 * not take a struct cdrom_read, instead they take a struct cdrom_msf
 	 * which is compatible.
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index b61dbf4d8443..b4e73d5dd5c2 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -639,6 +639,136 @@ int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp)
 }
 EXPORT_SYMBOL(get_sg_io_hdr);
 
+#ifdef CONFIG_COMPAT
+struct compat_cdrom_generic_command {
+	unsigned char	cmd[CDROM_PACKET_SIZE];
+	compat_caddr_t	buffer;
+	compat_uint_t	buflen;
+	compat_int_t	stat;
+	compat_caddr_t	sense;
+	unsigned char	data_direction;
+	compat_int_t	quiet;
+	compat_int_t	timeout;
+	compat_caddr_t	reserved[1];
+};
+#endif
+
+static int scsi_get_cdrom_generic_arg(struct cdrom_generic_command *cgc,
+				      const void __user *arg)
+{
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall()) {
+		struct compat_cdrom_generic_command cgc32;
+
+		if (copy_from_user(&cgc32, arg, sizeof(cgc32)))
+			return -EFAULT;
+
+		*cgc = (struct cdrom_generic_command) {
+			.buffer		= compat_ptr(cgc32.buffer),
+			.buflen		= cgc32.buflen,
+			.stat		= cgc32.stat,
+			.sense		= compat_ptr(cgc32.sense),
+			.data_direction	= cgc32.data_direction,
+			.quiet		= cgc32.quiet,
+			.timeout	= cgc32.timeout,
+			.reserved[0]	= compat_ptr(cgc32.reserved[0]),
+		};
+		memcpy(&cgc->cmd, &cgc32.cmd, CDROM_PACKET_SIZE);
+		return 0;
+	}
+#endif
+	if (copy_from_user(cgc, arg, sizeof(*cgc)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int scsi_put_cdrom_generic_arg(const struct cdrom_generic_command *cgc,
+				      void __user *arg)
+{
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall()) {
+		struct compat_cdrom_generic_command cgc32 = {
+			.buffer		= (uintptr_t)(cgc->buffer),
+			.buflen		= cgc->buflen,
+			.stat		= cgc->stat,
+			.sense		= (uintptr_t)(cgc->sense),
+			.data_direction	= cgc->data_direction,
+			.quiet		= cgc->quiet,
+			.timeout	= cgc->timeout,
+			.reserved[0]	= (uintptr_t)(cgc->reserved[0]),
+		};
+		memcpy(&cgc32.cmd, &cgc->cmd, CDROM_PACKET_SIZE);
+
+		if (copy_to_user(arg, &cgc32, sizeof(cgc32)))
+			return -EFAULT;
+
+		return 0;
+	}
+#endif
+	if (copy_to_user(arg, cgc, sizeof(*cgc)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int scsi_cdrom_send_packet(struct request_queue *q,
+				  struct gendisk *bd_disk,
+				  fmode_t mode, void __user *arg)
+{
+	struct cdrom_generic_command cgc;
+	struct sg_io_hdr hdr;
+	int err;
+
+	err = scsi_get_cdrom_generic_arg(&cgc, arg);
+	if (err)
+		return err;
+
+	cgc.timeout = clock_t_to_jiffies(cgc.timeout);
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.interface_id = 'S';
+	hdr.cmd_len = sizeof(cgc.cmd);
+	hdr.dxfer_len = cgc.buflen;
+	switch (cgc.data_direction) {
+		case CGC_DATA_UNKNOWN:
+			hdr.dxfer_direction = SG_DXFER_UNKNOWN;
+			break;
+		case CGC_DATA_WRITE:
+			hdr.dxfer_direction = SG_DXFER_TO_DEV;
+			break;
+		case CGC_DATA_READ:
+			hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+			break;
+		case CGC_DATA_NONE:
+			hdr.dxfer_direction = SG_DXFER_NONE;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	hdr.dxferp = cgc.buffer;
+	hdr.sbp = cgc.sense;
+	if (hdr.sbp)
+		hdr.mx_sb_len = sizeof(struct request_sense);
+	hdr.timeout = jiffies_to_msecs(cgc.timeout);
+	hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd;
+	hdr.cmd_len = sizeof(cgc.cmd);
+
+	err = sg_io(q, bd_disk, &hdr, mode);
+	if (err == -EFAULT)
+		return -EFAULT;
+
+	if (hdr.status)
+		return -EIO;
+
+	cgc.stat = err;
+	cgc.buflen = hdr.resid;
+	if (scsi_put_cdrom_generic_arg(&cgc, arg))
+		return -EFAULT;
+
+	return err;
+}
+
 int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode,
 		   unsigned int cmd, void __user *arg)
 {
@@ -689,60 +819,9 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
 				err = -EFAULT;
 			break;
 		}
-		case CDROM_SEND_PACKET: {
-			struct cdrom_generic_command cgc;
-			struct sg_io_hdr hdr;
-
-			err = -EFAULT;
-			if (copy_from_user(&cgc, arg, sizeof(cgc)))
-				break;
-			cgc.timeout = clock_t_to_jiffies(cgc.timeout);
-			memset(&hdr, 0, sizeof(hdr));
-			hdr.interface_id = 'S';
-			hdr.cmd_len = sizeof(cgc.cmd);
-			hdr.dxfer_len = cgc.buflen;
-			err = 0;
-			switch (cgc.data_direction) {
-				case CGC_DATA_UNKNOWN:
-					hdr.dxfer_direction = SG_DXFER_UNKNOWN;
-					break;
-				case CGC_DATA_WRITE:
-					hdr.dxfer_direction = SG_DXFER_TO_DEV;
-					break;
-				case CGC_DATA_READ:
-					hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-					break;
-				case CGC_DATA_NONE:
-					hdr.dxfer_direction = SG_DXFER_NONE;
-					break;
-				default:
-					err = -EINVAL;
-			}
-			if (err)
-				break;
-
-			hdr.dxferp = cgc.buffer;
-			hdr.sbp = cgc.sense;
-			if (hdr.sbp)
-				hdr.mx_sb_len = sizeof(struct request_sense);
-			hdr.timeout = jiffies_to_msecs(cgc.timeout);
-			hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd;
-			hdr.cmd_len = sizeof(cgc.cmd);
-
-			err = sg_io(q, bd_disk, &hdr, mode);
-			if (err == -EFAULT)
-				break;
-
-			if (hdr.status)
-				err = -EIO;
-
-			cgc.stat = err;
-			cgc.buflen = hdr.resid;
-			if (copy_to_user(arg, &cgc, sizeof(cgc)))
-				err = -EFAULT;
-
+		case CDROM_SEND_PACKET:
+			err = scsi_cdrom_send_packet(q, bd_disk, mode, arg);
 			break;
-		}
 
 		/*
 		 * old junk scsi send command ioctl
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 861fc65a1b75..ab4d3be4b646 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2671,15 +2671,13 @@ static int pkt_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned in
 	case CDROMEJECT:
 	case CDROMMULTISESSION:
 	case CDROMREADTOCENTRY:
+	case CDROM_SEND_PACKET: /* compat mode handled in scsi_cmd_ioctl */
 	case SCSI_IOCTL_SEND_COMMAND:
 		return pkt_ioctl(bdev, mode, cmd, (unsigned long)compat_ptr(arg));
 
-
 	/* FIXME: no handler so far */
-	case CDROM_LAST_WRITTEN:
-	/* handled in compat_blkdev_driver_ioctl */
-	case CDROM_SEND_PACKET:
 	default:
+	case CDROM_LAST_WRITTEN:
 		return -ENOIOCTLCMD;
 	}
 }
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 09/24] compat_ioctl: move CDROMREADADIO to cdrom.c
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (9 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, Jonathan Corbet,
	Mauro Carvalho Chehab, Diego Elio Pettenò,
	Guenter Roeck, linux-block

Again, there is only one file that needs this, so move the conversion
handler into the native implementation.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c  | 36 ------------------------------------
 drivers/cdrom/cdrom.c | 28 +++++++++++++++++++++++++---
 2 files changed, 25 insertions(+), 39 deletions(-)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 578e04f94619..cf136bc2c9fc 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -95,40 +95,6 @@ static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
 	return error;
 }
 
-struct compat_cdrom_read_audio {
-	union cdrom_addr	addr;
-	u8			addr_format;
-	compat_int_t		nframes;
-	compat_caddr_t		buf;
-};
-
-static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, unsigned long arg)
-{
-	struct cdrom_read_audio __user *cdread_audio;
-	struct compat_cdrom_read_audio __user *cdread_audio32;
-	__u32 data;
-	void __user *datap;
-
-	cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
-	cdread_audio32 = compat_ptr(arg);
-
-	if (copy_in_user(&cdread_audio->addr,
-			 &cdread_audio32->addr,
-			 (sizeof(*cdread_audio32) -
-			  sizeof(compat_caddr_t))))
-		return -EFAULT;
-
-	if (get_user(data, &cdread_audio32->buf))
-		return -EFAULT;
-	datap = compat_ptr(data);
-	if (put_user(datap, &cdread_audio->buf))
-		return -EFAULT;
-
-	return __blkdev_driver_ioctl(bdev, mode, cmd,
-			(unsigned long)cdread_audio);
-}
-
 struct compat_blkpg_ioctl_arg {
 	compat_int_t op;
 	compat_int_t flags;
@@ -178,8 +144,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 	case HDIO_GET_ADDRESS:
 	case HDIO_GET_BUSSTATE:
 		return compat_hdio_ioctl(bdev, mode, cmd, arg);
-	case CDROMREADAUDIO:
-		return compat_cdrom_read_audio(bdev, mode, cmd, arg);
 
 	/*
 	 * No handler required for the ones below, we just need to
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index eebdcbef0578..48095025e588 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -3017,9 +3017,31 @@ static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
 	struct cdrom_read_audio ra;
 	int lba;
 
-	if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
-			   sizeof(ra)))
-		return -EFAULT;
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall()) {
+		struct compat_cdrom_read_audio {
+			union cdrom_addr	addr;
+			u8			addr_format;
+			compat_int_t		nframes;
+			compat_caddr_t		buf;
+		} ra32;
+
+		if (copy_from_user(&ra32, arg, sizeof(ra32)))
+			return -EFAULT;
+
+		ra = (struct cdrom_read_audio) {
+			.addr		= ra32.addr,
+			.addr_format	= ra32.addr_format,
+			.nframes	= ra32.nframes,
+			.buf		= compat_ptr(ra32.buf),
+		};
+	} else
+#endif
+	{
+		if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
+				   sizeof(ra)))
+			return -EFAULT;
+	}
 
 	if (ra.addr_format == CDROM_MSF)
 		lba = msf_to_lba(ra.addr.msf.minute,
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 10/24] compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (10 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-17 15:20   ` [Y2038] " Ben Hutchings
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-block
  Cc: linux-kernel, y2038, Arnd Bergmann, Martin Wilck,
	Hannes Reinecke, Jonathan Corbet, Mauro Carvalho Chehab,
	Guenter Roeck, Diego Elio Pettenò

This is the only ioctl command that does not have a proper
compat handler. Making the normal implementation do the
right thing is actually very simply, so just do that by
using an in_compat_syscall() check to avoid the special
case in the pkcdvd driver.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/block/pktcdvd.c | 24 +-----------------------
 drivers/cdrom/cdrom.c   |  7 ++++---
 2 files changed, 5 insertions(+), 26 deletions(-)

diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index ab4d3be4b646..5f970a7d32c0 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2663,26 +2663,6 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
 	return ret;
 }
 
-#ifdef CONFIG_COMPAT
-static int pkt_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	/* compatible */
-	case CDROMEJECT:
-	case CDROMMULTISESSION:
-	case CDROMREADTOCENTRY:
-	case CDROM_SEND_PACKET: /* compat mode handled in scsi_cmd_ioctl */
-	case SCSI_IOCTL_SEND_COMMAND:
-		return pkt_ioctl(bdev, mode, cmd, (unsigned long)compat_ptr(arg));
-
-	/* FIXME: no handler so far */
-	default:
-	case CDROM_LAST_WRITTEN:
-		return -ENOIOCTLCMD;
-	}
-}
-#endif
-
 static unsigned int pkt_check_events(struct gendisk *disk,
 				     unsigned int clearing)
 {
@@ -2704,9 +2684,7 @@ static const struct block_device_operations pktcdvd_ops = {
 	.open =			pkt_open,
 	.release =		pkt_close,
 	.ioctl =		pkt_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl =		pkt_compat_ioctl,
-#endif
+	.compat_ioctl =		blkdev_compat_ptr_ioctl,
 	.check_events =		pkt_check_events,
 };
 
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 48095025e588..faca0f346fff 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -3293,9 +3293,10 @@ static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi,
 	ret = cdrom_get_last_written(cdi, &last);
 	if (ret)
 		return ret;
-	if (copy_to_user((long __user *)arg, &last, sizeof(last)))
-		return -EFAULT;
-	return 0;
+	if (in_compat_syscall())
+		return put_user(last, (__s32 __user *)arg);
+
+	return put_user(last, (long __user *)arg);
 }
 
 static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 11/24] compat_ioctl: block: handle cdrom compat ioctl in non-cdrom drivers
  2019-12-11 20:42 ` Arnd Bergmann
@ 2019-12-11 20:42   ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Denis Efremov, Tim Waugh, Boris Ostrovsky,
	Juergen Gross, Konrad Rzeszutek Wilk, Roger Pau Monné
  Cc: linux-kernel, y2038, Arnd Bergmann, Stefano Stabellini,
	Hannes Reinecke, Damien Le Moal, Bart Van Assche, linux-block,
	xen-devel

Various block drivers implement the CDROMMULTISESSION,
CDROM_GET_CAPABILITY, and CDROMEJECT ioctl commands, relying on the
block layer to handle compat_ioctl mode for them.

Move this into the drivers directly as a preparation for simplifying
the block layer later.

Since some of these commands need a compat_ptr() conversion,
introduce a blkdev_compat_ptr_ioctl() helper function that
can be used as the .compat_ioctl callback for those drivers
that only support compatible commands.

The actual CD-ROM drivers that call cdrom_ioctl() are
converted in a separate patch.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/ioctl.c                | 21 +++++++++++++++++++++
 drivers/block/floppy.c       |  3 +++
 drivers/block/paride/pd.c    |  1 +
 drivers/block/paride/pf.c    |  1 +
 drivers/block/sunvdc.c       |  1 +
 drivers/block/xen-blkfront.c |  1 +
 include/linux/blkdev.h       |  7 +++++++
 7 files changed, 35 insertions(+)

diff --git a/block/ioctl.c b/block/ioctl.c
index 5de98b97af2a..e728331d1a5b 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/capability.h>
+#include <linux/compat.h>
 #include <linux/blkdev.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
@@ -285,6 +286,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
  */
 EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
 
+#ifdef CONFIG_COMPAT
+/*
+ * This is the equivalent of compat_ptr_ioctl(), to be used by block
+ * drivers that implement only commands that are completely compatible
+ * between 32-bit and 64-bit user space
+ */
+int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
+			unsigned cmd, unsigned long arg)
+{
+	struct gendisk *disk = bdev->bd_disk;
+
+	if (disk->fops->ioctl)
+		return disk->fops->ioctl(bdev, mode, cmd,
+					 (unsigned long)compat_ptr(arg));
+
+	return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
+#endif
+
 static int blkdev_pr_register(struct block_device *bdev,
 		struct pr_registration __user *arg)
 {
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 485865fd0412..cd3612e4e2e1 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3879,6 +3879,9 @@ static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
 {
 	int drive = (long)bdev->bd_disk->private_data;
 	switch (cmd) {
+	case CDROMEJECT: /* CD-ROM eject */
+	case 0x6470:	 /* SunOS floppy eject */
+
 	case FDMSGON:
 	case FDMSGOFF:
 	case FDSETEMSGTRESH:
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 6f9ad3fc716f..c0967507d085 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -874,6 +874,7 @@ static const struct block_device_operations pd_fops = {
 	.open		= pd_open,
 	.release	= pd_release,
 	.ioctl		= pd_ioctl,
+	.compat_ioctl	= pd_ioctl,
 	.getgeo		= pd_getgeo,
 	.check_events	= pd_check_events,
 	.revalidate_disk= pd_revalidate
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 6b7d4cab3687..bb09f21ce21a 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -276,6 +276,7 @@ static const struct block_device_operations pf_fops = {
 	.open		= pf_open,
 	.release	= pf_release,
 	.ioctl		= pf_ioctl,
+	.compat_ioctl	= pf_ioctl,
 	.getgeo		= pf_getgeo,
 	.check_events	= pf_check_events,
 };
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 571612e233fe..39aeebc6837d 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -171,6 +171,7 @@ static const struct block_device_operations vdc_fops = {
 	.owner		= THIS_MODULE,
 	.getgeo		= vdc_getgeo,
 	.ioctl		= vdc_ioctl,
+	.compat_ioctl	= blkdev_compat_ptr_ioctl,
 };
 
 static void vdc_blk_queue_start(struct vdc_port *port)
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index a74d03913822..23c86350a5ab 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -2632,6 +2632,7 @@ static const struct block_device_operations xlvbd_block_fops =
 	.release = blkif_release,
 	.getgeo = blkif_getgeo,
 	.ioctl = blkif_ioctl,
+	.compat_ioctl = blkdev_compat_ptr_ioctl,
 };
 
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 47eb22a3b7f9..3e0408618da7 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1711,6 +1711,13 @@ struct block_device_operations {
 	const struct pr_ops *pr_ops;
 };
 
+#ifdef CONFIG_COMPAT
+extern int blkdev_compat_ptr_ioctl(struct block_device *, fmode_t,
+				      unsigned int, unsigned long);
+#else
+#define blkdev_compat_ptr_ioctl NULL
+#endif
+
 extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
 				 unsigned long);
 extern int bdev_read_page(struct block_device *, sector_t, struct page *);
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Xen-devel] [PATCH 11/24] compat_ioctl: block: handle cdrom compat ioctl in non-cdrom drivers
@ 2019-12-11 20:42   ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Denis Efremov, Tim Waugh, Boris Ostrovsky,
	Juergen Gross, Konrad Rzeszutek Wilk, Roger Pau Monné
  Cc: Damien Le Moal, Stefano Stabellini, Bart Van Assche,
	Arnd Bergmann, y2038, Hannes Reinecke, linux-kernel, linux-block,
	xen-devel

Various block drivers implement the CDROMMULTISESSION,
CDROM_GET_CAPABILITY, and CDROMEJECT ioctl commands, relying on the
block layer to handle compat_ioctl mode for them.

Move this into the drivers directly as a preparation for simplifying
the block layer later.

Since some of these commands need a compat_ptr() conversion,
introduce a blkdev_compat_ptr_ioctl() helper function that
can be used as the .compat_ioctl callback for those drivers
that only support compatible commands.

The actual CD-ROM drivers that call cdrom_ioctl() are
converted in a separate patch.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/ioctl.c                | 21 +++++++++++++++++++++
 drivers/block/floppy.c       |  3 +++
 drivers/block/paride/pd.c    |  1 +
 drivers/block/paride/pf.c    |  1 +
 drivers/block/sunvdc.c       |  1 +
 drivers/block/xen-blkfront.c |  1 +
 include/linux/blkdev.h       |  7 +++++++
 7 files changed, 35 insertions(+)

diff --git a/block/ioctl.c b/block/ioctl.c
index 5de98b97af2a..e728331d1a5b 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/capability.h>
+#include <linux/compat.h>
 #include <linux/blkdev.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
@@ -285,6 +286,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
  */
 EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
 
+#ifdef CONFIG_COMPAT
+/*
+ * This is the equivalent of compat_ptr_ioctl(), to be used by block
+ * drivers that implement only commands that are completely compatible
+ * between 32-bit and 64-bit user space
+ */
+int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
+			unsigned cmd, unsigned long arg)
+{
+	struct gendisk *disk = bdev->bd_disk;
+
+	if (disk->fops->ioctl)
+		return disk->fops->ioctl(bdev, mode, cmd,
+					 (unsigned long)compat_ptr(arg));
+
+	return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
+#endif
+
 static int blkdev_pr_register(struct block_device *bdev,
 		struct pr_registration __user *arg)
 {
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 485865fd0412..cd3612e4e2e1 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3879,6 +3879,9 @@ static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
 {
 	int drive = (long)bdev->bd_disk->private_data;
 	switch (cmd) {
+	case CDROMEJECT: /* CD-ROM eject */
+	case 0x6470:	 /* SunOS floppy eject */
+
 	case FDMSGON:
 	case FDMSGOFF:
 	case FDSETEMSGTRESH:
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 6f9ad3fc716f..c0967507d085 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -874,6 +874,7 @@ static const struct block_device_operations pd_fops = {
 	.open		= pd_open,
 	.release	= pd_release,
 	.ioctl		= pd_ioctl,
+	.compat_ioctl	= pd_ioctl,
 	.getgeo		= pd_getgeo,
 	.check_events	= pd_check_events,
 	.revalidate_disk= pd_revalidate
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 6b7d4cab3687..bb09f21ce21a 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -276,6 +276,7 @@ static const struct block_device_operations pf_fops = {
 	.open		= pf_open,
 	.release	= pf_release,
 	.ioctl		= pf_ioctl,
+	.compat_ioctl	= pf_ioctl,
 	.getgeo		= pf_getgeo,
 	.check_events	= pf_check_events,
 };
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 571612e233fe..39aeebc6837d 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -171,6 +171,7 @@ static const struct block_device_operations vdc_fops = {
 	.owner		= THIS_MODULE,
 	.getgeo		= vdc_getgeo,
 	.ioctl		= vdc_ioctl,
+	.compat_ioctl	= blkdev_compat_ptr_ioctl,
 };
 
 static void vdc_blk_queue_start(struct vdc_port *port)
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index a74d03913822..23c86350a5ab 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -2632,6 +2632,7 @@ static const struct block_device_operations xlvbd_block_fops =
 	.release = blkif_release,
 	.getgeo = blkif_getgeo,
 	.ioctl = blkif_ioctl,
+	.compat_ioctl = blkdev_compat_ptr_ioctl,
 };
 
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 47eb22a3b7f9..3e0408618da7 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1711,6 +1711,13 @@ struct block_device_operations {
 	const struct pr_ops *pr_ops;
 };
 
+#ifdef CONFIG_COMPAT
+extern int blkdev_compat_ptr_ioctl(struct block_device *, fmode_t,
+				      unsigned int, unsigned long);
+#else
+#define blkdev_compat_ptr_ioctl NULL
+#endif
+
 extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
 				 unsigned long);
 extern int bdev_read_page(struct block_device *, sector_t, struct page *);
-- 
2.20.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 12/24] compat_ioctl: add scsi_compat_ioctl
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (12 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, Hannes Reinecke, linux-scsi

In order to move the compat handling for SCSI ioctl commands out of
fs/compat_ioctl.c into the individual drivers, we need a helper function
first to match the native ioctl handler called by sd, sr, st, etc.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/scsi/scsi_ioctl.c | 54 +++++++++++++++++++++++++++++----------
 include/scsi/scsi_ioctl.h |  1 +
 2 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 57bcd05605bf..8f3af87b6bb0 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -189,17 +189,7 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
 }
 
 
-/**
- * scsi_ioctl - Dispatch ioctl to scsi device
- * @sdev: scsi device receiving ioctl
- * @cmd: which ioctl is it
- * @arg: data associated with ioctl
- *
- * Description: The scsi_ioctl() function differs from most ioctls in that it
- * does not take a major/minor number as the dev field.  Rather, it takes
- * a pointer to a &struct scsi_device.
- */
-int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+static int scsi_ioctl_common(struct scsi_device *sdev, int cmd, void __user *arg)
 {
 	char scsi_cmd[MAX_COMMAND_SIZE];
 	struct scsi_sense_hdr sense_hdr;
@@ -266,14 +256,50 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
                 return scsi_ioctl_get_pci(sdev, arg);
 	case SG_SCSI_RESET:
 		return scsi_ioctl_reset(sdev, arg);
-	default:
-		if (sdev->host->hostt->ioctl)
-			return sdev->host->hostt->ioctl(sdev, cmd, arg);
 	}
+	return -ENOIOCTLCMD;
+}
+
+/**
+ * scsi_ioctl - Dispatch ioctl to scsi device
+ * @sdev: scsi device receiving ioctl
+ * @cmd: which ioctl is it
+ * @arg: data associated with ioctl
+ *
+ * Description: The scsi_ioctl() function differs from most ioctls in that it
+ * does not take a major/minor number as the dev field.  Rather, it takes
+ * a pointer to a &struct scsi_device.
+ */
+int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	int ret = scsi_ioctl_common(sdev, cmd, arg);
+
+	if (ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (sdev->host->hostt->ioctl)
+		return sdev->host->hostt->ioctl(sdev, cmd, arg);
+
 	return -EINVAL;
 }
 EXPORT_SYMBOL(scsi_ioctl);
 
+#ifdef CONFIG_COMPAT
+int scsi_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	int ret = scsi_ioctl_common(sdev, cmd, arg);
+
+	if (ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (sdev->host->hostt->compat_ioctl)
+		return sdev->host->hostt->compat_ioctl(sdev, cmd, arg);
+
+	return ret;
+}
+EXPORT_SYMBOL(scsi_compat_ioctl);
+#endif
+
 /*
  * We can process a reset even when a device isn't fully operable.
  */
diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h
index 5101e987c0ef..4fe69d863b5d 100644
--- a/include/scsi/scsi_ioctl.h
+++ b/include/scsi/scsi_ioctl.h
@@ -44,6 +44,7 @@ typedef struct scsi_fctargaddress {
 int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev,
 		int cmd, bool ndelay);
 extern int scsi_ioctl(struct scsi_device *, int, void __user *);
+extern int scsi_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
 
 #endif /* __KERNEL__ */
 #endif /* _SCSI_IOCTL_H */
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 13/24] compat_ioctl: bsg: add handler
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (13 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, FUJITA Tomonori
  Cc: linux-kernel, y2038, Arnd Bergmann, Chaitanya Kulkarni,
	Benjamin Block, linux-scsi, linux-block

bsg_ioctl() calls into scsi_cmd_ioctl() for a couple of generic commands
and relies on fs/compat_ioctl.c to handle it correctly in compat mode.

Adding a private compat_ioctl() handler avoids that round-trip and lets
us get rid of the generic emulation once this is done.

Note that bsg implements an SG_IO command that is different from the
other drivers and does not need emulation.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/bsg.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/block/bsg.c b/block/bsg.c
index 833c44b3d458..d7bae94b64d9 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -382,6 +382,7 @@ static const struct file_operations bsg_fops = {
 	.open		=	bsg_open,
 	.release	=	bsg_release,
 	.unlocked_ioctl	=	bsg_ioctl,
+	.compat_ioctl	=	compat_ptr_ioctl,
 	.owner		=	THIS_MODULE,
 	.llseek		=	default_llseek,
 };
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 14/24] compat_ioctl: ide: floppy: add handler
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (14 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, David S. Miller
  Cc: linux-kernel, y2038, Arnd Bergmann, Gustavo A. R. Silva,
	Hannes Reinecke, Martin Wilck, Amol Surati, linux-ide

Rather than relying on fs/compat_ioctl.c, this adds support
for a compat_ioctl() callback in the ide-floppy driver directly,
which lets it translate the scsi commands.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/ide/ide-floppy.c       |  4 ++++
 drivers/ide/ide-floppy.h       |  2 ++
 drivers/ide/ide-floppy_ioctl.c | 36 ++++++++++++++++++++++++++++++++++
 drivers/ide/ide-gd.c           | 14 +++++++++++++
 include/linux/ide.h            |  2 ++
 5 files changed, 58 insertions(+)

diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 1ea2f9e82bf8..1fe1f9d37a51 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/compat.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
@@ -546,4 +547,7 @@ const struct ide_disk_ops ide_atapi_disk_ops = {
 	.set_doorlock	= ide_set_media_lock,
 	.do_request	= ide_floppy_do_request,
 	.ioctl		= ide_floppy_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= ide_floppy_compat_ioctl,
+#endif
 };
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
index 13c9b4b6d75e..8505a5f58f4e 100644
--- a/drivers/ide/ide-floppy.h
+++ b/drivers/ide/ide-floppy.h
@@ -26,6 +26,8 @@ void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
 /* ide-floppy_ioctl.c */
 int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
 		     unsigned int, unsigned long);
+int ide_floppy_compat_ioctl(ide_drive_t *, struct block_device *, fmode_t,
+			    unsigned int, unsigned long);
 
 #ifdef CONFIG_IDE_PROC_FS
 /* ide-floppy_proc.c */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
index 40a2ebe34e1d..4fd70f804d6f 100644
--- a/drivers/ide/ide-floppy_ioctl.c
+++ b/drivers/ide/ide-floppy_ioctl.c
@@ -5,6 +5,7 @@
 
 #include <linux/kernel.h>
 #include <linux/ide.h>
+#include <linux/compat.h>
 #include <linux/cdrom.h>
 #include <linux/mutex.h>
 
@@ -302,3 +303,38 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
 	mutex_unlock(&ide_floppy_ioctl_mutex);
 	return err;
 }
+
+#ifdef CONFIG_COMPAT
+int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
+			    fmode_t mode, unsigned int cmd, unsigned long arg)
+{
+	struct ide_atapi_pc pc;
+	void __user *argp = compat_ptr(arg);
+	int err;
+
+	mutex_lock(&ide_floppy_ioctl_mutex);
+	if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
+		err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
+		goto out;
+	}
+
+	err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
+	if (err != -ENOTTY)
+		goto out;
+
+	/*
+	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+	 * and CDROM_SEND_PACKET (legacy) ioctls
+	 */
+	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+		err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
+
+	/*
+	 * there is no generic_ide_compat_ioctl(), that is handled
+	 * through compat_blkdev_ioctl().
+	 */
+out:
+	mutex_unlock(&ide_floppy_ioctl_mutex);
+	return err;
+}
+#endif
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
index dba9ad5c97b3..1b0270efcce2 100644
--- a/drivers/ide/ide-gd.c
+++ b/drivers/ide/ide-gd.c
@@ -341,11 +341,25 @@ static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
 	return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
 }
 
+#ifdef CONFIG_COMPAT
+static int ide_gd_compat_ioctl(struct block_device *bdev, fmode_t mode,
+			       unsigned int cmd, unsigned long arg)
+{
+	struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
+	ide_drive_t *drive = idkp->drive;
+
+	return drive->disk_ops->compat_ioctl(drive, bdev, mode, cmd, arg);
+}
+#endif
+
 static const struct block_device_operations ide_gd_ops = {
 	.owner			= THIS_MODULE,
 	.open			= ide_gd_unlocked_open,
 	.release		= ide_gd_release,
 	.ioctl			= ide_gd_ioctl,
+#ifdef CONFIG_COMPAT
+	.ioctl			= ide_gd_compat_ioctl,
+#endif
 	.getgeo			= ide_gd_getgeo,
 	.check_events		= ide_gd_check_events,
 	.unlock_native_capacity	= ide_gd_unlock_native_capacity,
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 46b771d6999e..06dae6438557 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -413,6 +413,8 @@ struct ide_disk_ops {
 				      sector_t);
 	int		(*ioctl)(struct ide_drive_s *, struct block_device *,
 				 fmode_t, unsigned int, unsigned long);
+	int		(*compat_ioctl)(struct ide_drive_s *, struct block_device *,
+					fmode_t, unsigned int, unsigned long);
 };
 
 /* ATAPI device flags */
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (15 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-11 23:05   ` Michael S. Tsirkin
                     ` (2 more replies)
  -1 siblings, 3 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Michael S. Tsirkin, Jason Wang, Doug Gilbert,
	Kai Mäkisara
  Cc: linux-kernel, y2038, Arnd Bergmann, Paolo Bonzini,
	Stefan Hajnoczi, Bart Van Assche, Hannes Reinecke,
	Damien Le Moal, John Garry, virtualization, linux-block,
	linux-scsi, linux-fsdevel

Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
handler that implements the same commands by calling scsi_compat_ioctl().

The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
at this point, so any driver that calls those can do so for both native
and compat mode, with the argument passed through compat_ptr().

With this, we can remove the entries from fs/compat_ioctl.c.  The new
code is larger, but should be easier to maintain and keep updated with
newly added commands.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/block/virtio_blk.c |   3 +
 drivers/scsi/ch.c          |   9 ++-
 drivers/scsi/sd.c          |  50 ++++++--------
 drivers/scsi/sg.c          |  44 ++++++++-----
 drivers/scsi/sr.c          |  57 ++++++++++++++--
 drivers/scsi/st.c          |  51 ++++++++------
 fs/compat_ioctl.c          | 132 +------------------------------------
 7 files changed, 142 insertions(+), 204 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 7ffd719d89de..fbbf18ac1d5d 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 
 static const struct block_device_operations virtblk_fops = {
 	.ioctl  = virtblk_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = blkdev_compat_ptr_ioctl,
+#endif
 	.owner  = THIS_MODULE,
 	.getgeo = virtblk_getgeo,
 };
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 76751d6c7f0d..ed5f4a6ae270 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
 			    unsigned int cmd, unsigned long arg)
 {
 	scsi_changer *ch = file->private_data;
+	int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
+							file->f_flags & O_NDELAY);
+	if (retval)
+		return retval;
 
 	switch (cmd) {
 	case CHIOGPARAMS:
@@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
 	case CHIOINITELEM:
 	case CHIOSVOLTAG:
 		/* compatible */
-		return ch_ioctl(file, cmd, arg);
+		return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 	case CHIOGSTATUS32:
 	{
 		struct changer_element_status32 ces32;
@@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
 		return ch_gstatus(ch, ces32.ces_type, data);
 	}
 	default:
-		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
-		return -ENOIOCTLCMD;
+		return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
 
 	}
 }
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index cea625906440..5afb0046b12a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1465,13 +1465,12 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  *	Note: most ioctls are forward onto the block subsystem or further
  *	down in the scsi subsystem.
  **/
-static int sd_ioctl(struct block_device *bdev, fmode_t mode,
-		    unsigned int cmd, unsigned long arg)
+static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
+			   unsigned int cmd, void __user *p)
 {
 	struct gendisk *disk = bdev->bd_disk;
 	struct scsi_disk *sdkp = scsi_disk(disk);
 	struct scsi_device *sdp = sdkp->device;
-	void __user *p = (void __user *)arg;
 	int error;
     
 	SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
@@ -1507,9 +1506,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
 			break;
 		default:
 			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
-			if (error != -ENOTTY)
-				break;
-			error = scsi_ioctl(sdp, cmd, p);
 			break;
 	}
 out:
@@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
 	revalidate_disk(sdkp->disk);
 }
 
+static int sd_ioctl(struct block_device *bdev, fmode_t mode,
+		    unsigned int cmd, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	int ret;
+
+	ret = sd_ioctl_common(bdev, mode, cmd, p);
+	if (ret != -ENOTTY)
+		return ret;
+
+	return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
+}
 
 #ifdef CONFIG_COMPAT
-/* 
- * This gets directly called from VFS. When the ioctl 
- * is not recognized we go back to the other translation paths. 
- */
 static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
 			   unsigned int cmd, unsigned long arg)
 {
-	struct gendisk *disk = bdev->bd_disk;
-	struct scsi_disk *sdkp = scsi_disk(disk);
-	struct scsi_device *sdev = sdkp->device;
 	void __user *p = compat_ptr(arg);
-	int error;
-
-	error = scsi_verify_blk_ioctl(bdev, cmd);
-	if (error < 0)
-		return error;
+	int ret;
 
-	error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
-			(mode & FMODE_NDELAY) != 0);
-	if (error)
-		return error;
+	ret = sd_ioctl_common(bdev, mode, cmd, p);
+	if (ret != -ENOTTY)
+		return ret;
 
-	if (is_sed_ioctl(cmd))
-		return sed_ioctl(sdkp->opal_dev, cmd, p);
-	       
-	/* 
-	 * Let the static ioctl translation table take care of it.
-	 */
-	if (!sdev->host->hostt->compat_ioctl)
-		return -ENOIOCTLCMD; 
-	return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
+	return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
 }
 #endif
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 985546aac236..08efcee7a34d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -910,19 +910,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
 #endif
 
 static long
-sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
+		unsigned int cmd_in, void __user *p)
 {
-	void __user *p = (void __user *)arg;
 	int __user *ip = p;
 	int result, val, read_only;
-	Sg_device *sdp;
-	Sg_fd *sfp;
 	Sg_request *srp;
 	unsigned long iflags;
 
-	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
-		return -ENXIO;
-
 	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
 				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
 	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
@@ -1145,29 +1140,44 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 			cmd_in, filp->f_flags & O_NDELAY);
 	if (result)
 		return result;
+
+	return -ENOIOCTLCMD;
+}
+
+static long
+sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	int ret;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+
+	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
+	if (ret != -ENOIOCTLCMD)
+		return ret;
+
 	return scsi_ioctl(sdp->device, cmd_in, p);
 }
 
 #ifdef CONFIG_COMPAT
 static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 {
+	void __user *p = compat_ptr(arg);
 	Sg_device *sdp;
 	Sg_fd *sfp;
-	struct scsi_device *sdev;
+	int ret;
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 
-	sdev = sdp->device;
-	if (sdev->host->hostt->compat_ioctl) { 
-		int ret;
-
-		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
+	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
+	if (ret != -ENOIOCTLCMD)
 		return ret;
-	}
-	
-	return -ENOIOCTLCMD;
+
+	return scsi_compat_ioctl(sdp->device, cmd_in, p);
 }
 #endif
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 4664fdf75c0f..6033a886c42c 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -38,6 +38,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/bio.h>
+#include <linux/compat.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
@@ -598,6 +599,55 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
+			  unsigned long arg)
+{
+	struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
+	struct scsi_device *sdev = cd->device;
+	void __user *argp = compat_ptr(arg);
+	int ret;
+
+	mutex_lock(&sr_mutex);
+
+	ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
+			(mode & FMODE_NDELAY) != 0);
+	if (ret)
+		goto out;
+
+	scsi_autopm_get_device(sdev);
+
+	/*
+	 * Send SCSI addressing ioctls directly to mid level, send other
+	 * ioctls to cdrom/block level.
+	 */
+	switch (cmd) {
+	case SCSI_IOCTL_GET_IDLUN:
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+		ret = scsi_compat_ioctl(sdev, cmd, argp);
+		goto put;
+	}
+
+	/*
+	 * CDROM ioctls are handled in the block layer, but
+	 * do the scsi blk ioctls here.
+	 */
+	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
+	if (ret != -ENOTTY)
+		return ret;
+
+	ret = scsi_compat_ioctl(sdev, cmd, argp);
+
+put:
+	scsi_autopm_put_device(sdev);
+
+out:
+	mutex_unlock(&sr_mutex);
+	return ret;
+
+}
+#endif
+
 static unsigned int sr_block_check_events(struct gendisk *disk,
 					  unsigned int clearing)
 {
@@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
 	.open		= sr_block_open,
 	.release	= sr_block_release,
 	.ioctl		= sr_block_ioctl,
+#ifdef CONFIG_COMPAT
+	.ioctl		= sr_block_compat_ioctl,
+#endif
 	.check_events	= sr_block_check_events,
 	.revalidate_disk = sr_block_revalidate_disk,
-	/* 
-	 * No compat_ioctl for now because sr_block_ioctl never
-	 * seems to pass arbitrary ioctls down to host drivers.
-	 */
 };
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 9e3fff2de83e..393f3019ccac 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3501,7 +3501,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
 
 
 /* The ioctl command */
-static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
+static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p)
 {
 	int i, cmd_nr, cmd_type, bt;
 	int retval = 0;
@@ -3509,7 +3509,6 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 	struct scsi_tape *STp = file->private_data;
 	struct st_modedef *STm;
 	struct st_partstat *STps;
-	void __user *p = (void __user *)arg;
 
 	if (mutex_lock_interruptible(&STp->lock))
 		return -ERESTARTSYS;
@@ -3824,9 +3823,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 	}
 	mutex_unlock(&STp->lock);
 	switch (cmd_in) {
+		case SCSI_IOCTL_STOP_UNIT:
+			/* unload */
+			retval = scsi_ioctl(STp->device, cmd_in, p);
+			if (!retval) {
+				STp->rew_at_close = 0;
+				STp->ready = ST_NO_TAPE;
+			}
+			return retval;
+
 		case SCSI_IOCTL_GET_IDLUN:
 		case SCSI_IOCTL_GET_BUS_NUMBER:
 			break;
+
 		default:
 			if ((cmd_in == SG_IO ||
 			     cmd_in == SCSI_IOCTL_SEND_COMMAND ||
@@ -3840,42 +3849,46 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 				return i;
 			break;
 	}
-	retval = scsi_ioctl(STp->device, cmd_in, p);
-	if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
-		STp->rew_at_close = 0;
-		STp->ready = ST_NO_TAPE;
-	}
-	return retval;
+	return -ENOTTY;
 
  out:
 	mutex_unlock(&STp->lock);
 	return retval;
 }
 
+static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	struct scsi_tape *STp = file->private_data;
+	int ret;
+
+	ret = st_ioctl_common(file, cmd_in, p);
+	if (ret != -ENOTTY)
+		return ret;
+
+	return scsi_ioctl(STp->device, cmd_in, p);
+}
+
 #ifdef CONFIG_COMPAT
 static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 {
 	void __user *p = compat_ptr(arg);
 	struct scsi_tape *STp = file->private_data;
-	struct scsi_device *sdev = STp->device;
-	int ret = -ENOIOCTLCMD;
+	int ret;
 
 	/* argument conversion is handled using put_user_mtpos/put_user_mtget */
 	switch (cmd_in) {
-	case MTIOCTOP:
-		return st_ioctl(file, MTIOCTOP, (unsigned long)p);
 	case MTIOCPOS32:
-		return st_ioctl(file, MTIOCPOS, (unsigned long)p);
+		return st_ioctl_common(file, MTIOCPOS, p);
 	case MTIOCGET32:
-		return st_ioctl(file, MTIOCGET, (unsigned long)p);
+		return st_ioctl_common(file, MTIOCGET, p);
 	}
 
-	if (sdev->host->hostt->compat_ioctl) { 
+	ret = st_ioctl_common(file, cmd_in, p);
+	if (ret != -ENOTTY)
+		return ret;
 
-		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
-	}
-	return ret;
+	return scsi_compat_ioctl(STp->device, cmd_in, p);
 }
 #endif
 
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 358ea2ecf36b..ab4471f469e6 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -36,109 +36,11 @@
 
 #include "internal.h"
 
-#ifdef CONFIG_BLOCK
-#include <linux/cdrom.h>
-#include <linux/fd.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_ioctl.h>
-#include <scsi/sg.h>
-#endif
-
 #include <linux/uaccess.h>
 #include <linux/watchdog.h>
 
 #include <linux/hiddev.h>
 
-
-#include <linux/sort.h>
-
-/*
- * simple reversible transform to make our table more evenly
- * distributed after sorting.
- */
-#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
-
-#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
-static unsigned int ioctl_pointer[] = {
-#ifdef CONFIG_BLOCK
-/* Big S */
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
-COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
-COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
-#endif
-#ifdef CONFIG_BLOCK
-/* SG stuff */
-COMPATIBLE_IOCTL(SG_IO)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_EMULATED_HOST)
-COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
-COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
-COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
-COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
-COMPATIBLE_IOCTL(SG_SET_DEBUG)
-COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
-COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
-COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
-COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
-COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
-#endif
-};
-
-/*
- * Convert common ioctl arguments based on their command number
- *
- * Please do not add any code in here. Instead, implement
- * a compat_ioctl operation in the place that handleѕ the
- * ioctl for the native case.
- */
-static long do_ioctl_trans(unsigned int cmd,
-		 unsigned long arg, struct file *file)
-{
-	return -ENOIOCTLCMD;
-}
-
-static int compat_ioctl_check_table(unsigned int xcmd)
-{
-#ifdef CONFIG_BLOCK
-	int i;
-	const int max = ARRAY_SIZE(ioctl_pointer) - 1;
-
-	BUILD_BUG_ON(max >= (1 << 16));
-
-	/* guess initial offset into table, assuming a
-	   normalized distribution */
-	i = ((xcmd >> 16) * max) >> 16;
-
-	/* do linear search up first, until greater or equal */
-	while (ioctl_pointer[i] < xcmd && i < max)
-		i++;
-
-	/* then do linear search down */
-	while (ioctl_pointer[i] > xcmd && i > 0)
-		i--;
-
-	return ioctl_pointer[i] == xcmd;
-#else
-	return 0;
-#endif
-}
-
 COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 		       compat_ulong_t, arg32)
 {
@@ -216,19 +118,9 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 				goto out_fput;
 		}
 
-		if (!f.file->f_op->unlocked_ioctl)
-			goto do_ioctl;
-		break;
-	}
-
-	if (compat_ioctl_check_table(XFORM(cmd)))
-		goto found_handler;
-
-	error = do_ioctl_trans(cmd, arg, f.file);
-	if (error == -ENOIOCTLCMD)
 		error = -ENOTTY;
-
-	goto out_fput;
+		goto out_fput;
+	}
 
  found_handler:
 	arg = (unsigned long)compat_ptr(arg);
@@ -239,23 +131,3 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
  out:
 	return error;
 }
-
-static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
-{
-	unsigned int a, b;
-	a = *(unsigned int *)p;
-	b = *(unsigned int *)q;
-	if (a > b)
-		return 1;
-	if (a < b)
-		return -1;
-	return 0;
-}
-
-static int __init init_sys32_ioctl(void)
-{
-	sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
-		init_sys32_ioctl_cmp, NULL);
-	return 0;
-}
-__initcall(init_sys32_ioctl);
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (16 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Michael S. Tsirkin, Jason Wang, Doug Gilbert,
	Kai Mäkisara
  Cc: Hannes Reinecke, Bart Van Assche, Arnd Bergmann, y2038,
	Damien Le Moal, John Garry, linux-kernel, virtualization,
	linux-block, Stefan Hajnoczi, linux-scsi, linux-fsdevel,
	Paolo Bonzini

Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
handler that implements the same commands by calling scsi_compat_ioctl().

The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
at this point, so any driver that calls those can do so for both native
and compat mode, with the argument passed through compat_ptr().

With this, we can remove the entries from fs/compat_ioctl.c.  The new
code is larger, but should be easier to maintain and keep updated with
newly added commands.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/block/virtio_blk.c |   3 +
 drivers/scsi/ch.c          |   9 ++-
 drivers/scsi/sd.c          |  50 ++++++--------
 drivers/scsi/sg.c          |  44 ++++++++-----
 drivers/scsi/sr.c          |  57 ++++++++++++++--
 drivers/scsi/st.c          |  51 ++++++++------
 fs/compat_ioctl.c          | 132 +------------------------------------
 7 files changed, 142 insertions(+), 204 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 7ffd719d89de..fbbf18ac1d5d 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 
 static const struct block_device_operations virtblk_fops = {
 	.ioctl  = virtblk_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = blkdev_compat_ptr_ioctl,
+#endif
 	.owner  = THIS_MODULE,
 	.getgeo = virtblk_getgeo,
 };
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 76751d6c7f0d..ed5f4a6ae270 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
 			    unsigned int cmd, unsigned long arg)
 {
 	scsi_changer *ch = file->private_data;
+	int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
+							file->f_flags & O_NDELAY);
+	if (retval)
+		return retval;
 
 	switch (cmd) {
 	case CHIOGPARAMS:
@@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
 	case CHIOINITELEM:
 	case CHIOSVOLTAG:
 		/* compatible */
-		return ch_ioctl(file, cmd, arg);
+		return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 	case CHIOGSTATUS32:
 	{
 		struct changer_element_status32 ces32;
@@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
 		return ch_gstatus(ch, ces32.ces_type, data);
 	}
 	default:
-		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
-		return -ENOIOCTLCMD;
+		return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
 
 	}
 }
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index cea625906440..5afb0046b12a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1465,13 +1465,12 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  *	Note: most ioctls are forward onto the block subsystem or further
  *	down in the scsi subsystem.
  **/
-static int sd_ioctl(struct block_device *bdev, fmode_t mode,
-		    unsigned int cmd, unsigned long arg)
+static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
+			   unsigned int cmd, void __user *p)
 {
 	struct gendisk *disk = bdev->bd_disk;
 	struct scsi_disk *sdkp = scsi_disk(disk);
 	struct scsi_device *sdp = sdkp->device;
-	void __user *p = (void __user *)arg;
 	int error;
     
 	SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
@@ -1507,9 +1506,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
 			break;
 		default:
 			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
-			if (error != -ENOTTY)
-				break;
-			error = scsi_ioctl(sdp, cmd, p);
 			break;
 	}
 out:
@@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
 	revalidate_disk(sdkp->disk);
 }
 
+static int sd_ioctl(struct block_device *bdev, fmode_t mode,
+		    unsigned int cmd, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	int ret;
+
+	ret = sd_ioctl_common(bdev, mode, cmd, p);
+	if (ret != -ENOTTY)
+		return ret;
+
+	return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
+}
 
 #ifdef CONFIG_COMPAT
-/* 
- * This gets directly called from VFS. When the ioctl 
- * is not recognized we go back to the other translation paths. 
- */
 static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
 			   unsigned int cmd, unsigned long arg)
 {
-	struct gendisk *disk = bdev->bd_disk;
-	struct scsi_disk *sdkp = scsi_disk(disk);
-	struct scsi_device *sdev = sdkp->device;
 	void __user *p = compat_ptr(arg);
-	int error;
-
-	error = scsi_verify_blk_ioctl(bdev, cmd);
-	if (error < 0)
-		return error;
+	int ret;
 
-	error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
-			(mode & FMODE_NDELAY) != 0);
-	if (error)
-		return error;
+	ret = sd_ioctl_common(bdev, mode, cmd, p);
+	if (ret != -ENOTTY)
+		return ret;
 
-	if (is_sed_ioctl(cmd))
-		return sed_ioctl(sdkp->opal_dev, cmd, p);
-	       
-	/* 
-	 * Let the static ioctl translation table take care of it.
-	 */
-	if (!sdev->host->hostt->compat_ioctl)
-		return -ENOIOCTLCMD; 
-	return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
+	return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
 }
 #endif
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 985546aac236..08efcee7a34d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -910,19 +910,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
 #endif
 
 static long
-sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
+		unsigned int cmd_in, void __user *p)
 {
-	void __user *p = (void __user *)arg;
 	int __user *ip = p;
 	int result, val, read_only;
-	Sg_device *sdp;
-	Sg_fd *sfp;
 	Sg_request *srp;
 	unsigned long iflags;
 
-	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
-		return -ENXIO;
-
 	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
 				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
 	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
@@ -1145,29 +1140,44 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 			cmd_in, filp->f_flags & O_NDELAY);
 	if (result)
 		return result;
+
+	return -ENOIOCTLCMD;
+}
+
+static long
+sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	int ret;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+
+	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
+	if (ret != -ENOIOCTLCMD)
+		return ret;
+
 	return scsi_ioctl(sdp->device, cmd_in, p);
 }
 
 #ifdef CONFIG_COMPAT
 static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 {
+	void __user *p = compat_ptr(arg);
 	Sg_device *sdp;
 	Sg_fd *sfp;
-	struct scsi_device *sdev;
+	int ret;
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 
-	sdev = sdp->device;
-	if (sdev->host->hostt->compat_ioctl) { 
-		int ret;
-
-		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
+	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
+	if (ret != -ENOIOCTLCMD)
 		return ret;
-	}
-	
-	return -ENOIOCTLCMD;
+
+	return scsi_compat_ioctl(sdp->device, cmd_in, p);
 }
 #endif
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 4664fdf75c0f..6033a886c42c 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -38,6 +38,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/bio.h>
+#include <linux/compat.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
@@ -598,6 +599,55 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
+			  unsigned long arg)
+{
+	struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
+	struct scsi_device *sdev = cd->device;
+	void __user *argp = compat_ptr(arg);
+	int ret;
+
+	mutex_lock(&sr_mutex);
+
+	ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
+			(mode & FMODE_NDELAY) != 0);
+	if (ret)
+		goto out;
+
+	scsi_autopm_get_device(sdev);
+
+	/*
+	 * Send SCSI addressing ioctls directly to mid level, send other
+	 * ioctls to cdrom/block level.
+	 */
+	switch (cmd) {
+	case SCSI_IOCTL_GET_IDLUN:
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+		ret = scsi_compat_ioctl(sdev, cmd, argp);
+		goto put;
+	}
+
+	/*
+	 * CDROM ioctls are handled in the block layer, but
+	 * do the scsi blk ioctls here.
+	 */
+	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
+	if (ret != -ENOTTY)
+		return ret;
+
+	ret = scsi_compat_ioctl(sdev, cmd, argp);
+
+put:
+	scsi_autopm_put_device(sdev);
+
+out:
+	mutex_unlock(&sr_mutex);
+	return ret;
+
+}
+#endif
+
 static unsigned int sr_block_check_events(struct gendisk *disk,
 					  unsigned int clearing)
 {
@@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
 	.open		= sr_block_open,
 	.release	= sr_block_release,
 	.ioctl		= sr_block_ioctl,
+#ifdef CONFIG_COMPAT
+	.ioctl		= sr_block_compat_ioctl,
+#endif
 	.check_events	= sr_block_check_events,
 	.revalidate_disk = sr_block_revalidate_disk,
-	/* 
-	 * No compat_ioctl for now because sr_block_ioctl never
-	 * seems to pass arbitrary ioctls down to host drivers.
-	 */
 };
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 9e3fff2de83e..393f3019ccac 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3501,7 +3501,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
 
 
 /* The ioctl command */
-static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
+static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p)
 {
 	int i, cmd_nr, cmd_type, bt;
 	int retval = 0;
@@ -3509,7 +3509,6 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 	struct scsi_tape *STp = file->private_data;
 	struct st_modedef *STm;
 	struct st_partstat *STps;
-	void __user *p = (void __user *)arg;
 
 	if (mutex_lock_interruptible(&STp->lock))
 		return -ERESTARTSYS;
@@ -3824,9 +3823,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 	}
 	mutex_unlock(&STp->lock);
 	switch (cmd_in) {
+		case SCSI_IOCTL_STOP_UNIT:
+			/* unload */
+			retval = scsi_ioctl(STp->device, cmd_in, p);
+			if (!retval) {
+				STp->rew_at_close = 0;
+				STp->ready = ST_NO_TAPE;
+			}
+			return retval;
+
 		case SCSI_IOCTL_GET_IDLUN:
 		case SCSI_IOCTL_GET_BUS_NUMBER:
 			break;
+
 		default:
 			if ((cmd_in == SG_IO ||
 			     cmd_in == SCSI_IOCTL_SEND_COMMAND ||
@@ -3840,42 +3849,46 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 				return i;
 			break;
 	}
-	retval = scsi_ioctl(STp->device, cmd_in, p);
-	if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
-		STp->rew_at_close = 0;
-		STp->ready = ST_NO_TAPE;
-	}
-	return retval;
+	return -ENOTTY;
 
  out:
 	mutex_unlock(&STp->lock);
 	return retval;
 }
 
+static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	struct scsi_tape *STp = file->private_data;
+	int ret;
+
+	ret = st_ioctl_common(file, cmd_in, p);
+	if (ret != -ENOTTY)
+		return ret;
+
+	return scsi_ioctl(STp->device, cmd_in, p);
+}
+
 #ifdef CONFIG_COMPAT
 static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 {
 	void __user *p = compat_ptr(arg);
 	struct scsi_tape *STp = file->private_data;
-	struct scsi_device *sdev = STp->device;
-	int ret = -ENOIOCTLCMD;
+	int ret;
 
 	/* argument conversion is handled using put_user_mtpos/put_user_mtget */
 	switch (cmd_in) {
-	case MTIOCTOP:
-		return st_ioctl(file, MTIOCTOP, (unsigned long)p);
 	case MTIOCPOS32:
-		return st_ioctl(file, MTIOCPOS, (unsigned long)p);
+		return st_ioctl_common(file, MTIOCPOS, p);
 	case MTIOCGET32:
-		return st_ioctl(file, MTIOCGET, (unsigned long)p);
+		return st_ioctl_common(file, MTIOCGET, p);
 	}
 
-	if (sdev->host->hostt->compat_ioctl) { 
+	ret = st_ioctl_common(file, cmd_in, p);
+	if (ret != -ENOTTY)
+		return ret;
 
-		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
-	}
-	return ret;
+	return scsi_compat_ioctl(STp->device, cmd_in, p);
 }
 #endif
 
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 358ea2ecf36b..ab4471f469e6 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -36,109 +36,11 @@
 
 #include "internal.h"
 
-#ifdef CONFIG_BLOCK
-#include <linux/cdrom.h>
-#include <linux/fd.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_ioctl.h>
-#include <scsi/sg.h>
-#endif
-
 #include <linux/uaccess.h>
 #include <linux/watchdog.h>
 
 #include <linux/hiddev.h>
 
-
-#include <linux/sort.h>
-
-/*
- * simple reversible transform to make our table more evenly
- * distributed after sorting.
- */
-#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
-
-#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
-static unsigned int ioctl_pointer[] = {
-#ifdef CONFIG_BLOCK
-/* Big S */
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
-COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
-COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
-#endif
-#ifdef CONFIG_BLOCK
-/* SG stuff */
-COMPATIBLE_IOCTL(SG_IO)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_EMULATED_HOST)
-COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
-COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
-COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
-COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
-COMPATIBLE_IOCTL(SG_SET_DEBUG)
-COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
-COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
-COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
-COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
-COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
-#endif
-};
-
-/*
- * Convert common ioctl arguments based on their command number
- *
- * Please do not add any code in here. Instead, implement
- * a compat_ioctl operation in the place that handleѕ the
- * ioctl for the native case.
- */
-static long do_ioctl_trans(unsigned int cmd,
-		 unsigned long arg, struct file *file)
-{
-	return -ENOIOCTLCMD;
-}
-
-static int compat_ioctl_check_table(unsigned int xcmd)
-{
-#ifdef CONFIG_BLOCK
-	int i;
-	const int max = ARRAY_SIZE(ioctl_pointer) - 1;
-
-	BUILD_BUG_ON(max >= (1 << 16));
-
-	/* guess initial offset into table, assuming a
-	   normalized distribution */
-	i = ((xcmd >> 16) * max) >> 16;
-
-	/* do linear search up first, until greater or equal */
-	while (ioctl_pointer[i] < xcmd && i < max)
-		i++;
-
-	/* then do linear search down */
-	while (ioctl_pointer[i] > xcmd && i > 0)
-		i--;
-
-	return ioctl_pointer[i] == xcmd;
-#else
-	return 0;
-#endif
-}
-
 COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 		       compat_ulong_t, arg32)
 {
@@ -216,19 +118,9 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 				goto out_fput;
 		}
 
-		if (!f.file->f_op->unlocked_ioctl)
-			goto do_ioctl;
-		break;
-	}
-
-	if (compat_ioctl_check_table(XFORM(cmd)))
-		goto found_handler;
-
-	error = do_ioctl_trans(cmd, arg, f.file);
-	if (error == -ENOIOCTLCMD)
 		error = -ENOTTY;
-
-	goto out_fput;
+		goto out_fput;
+	}
 
  found_handler:
 	arg = (unsigned long)compat_ptr(arg);
@@ -239,23 +131,3 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
  out:
 	return error;
 }
-
-static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
-{
-	unsigned int a, b;
-	a = *(unsigned int *)p;
-	b = *(unsigned int *)q;
-	if (a > b)
-		return 1;
-	if (a < b)
-		return -1;
-	return 0;
-}
-
-static int __init init_sys32_ioctl(void)
-{
-	sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
-		init_sys32_ioctl_cmp, NULL);
-	return 0;
-}
-__initcall(init_sys32_ioctl);
-- 
2.20.0

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 16/24] compat_ioctl: move sys_compat_ioctl() to ioctl.c
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (17 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, David Howells,
	Theodore Ts'o, Darrick J. Wong, linux-fsdevel

The rest of the fs/compat_ioctl.c file is no longer useful now,
so move the actual syscall as planned.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/Makefile       |   2 +-
 fs/compat_ioctl.c | 133 ----------------------------------------------
 fs/ioctl.c        |  90 +++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 134 deletions(-)
 delete mode 100644 fs/compat_ioctl.c

diff --git a/fs/Makefile b/fs/Makefile
index 1148c555c4d3..98be354fdb61 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_FS_DAX)		+= dax.o
 obj-$(CONFIG_FS_ENCRYPTION)	+= crypto/
 obj-$(CONFIG_FS_VERITY)		+= verity/
 obj-$(CONFIG_FILE_LOCKING)      += locks.o
-obj-$(CONFIG_COMPAT)		+= compat.o compat_ioctl.o
+obj-$(CONFIG_COMPAT)		+= compat.o
 obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
 obj-$(CONFIG_BINFMT_EM86)	+= binfmt_em86.o
 obj-$(CONFIG_BINFMT_MISC)	+= binfmt_misc.o
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
deleted file mode 100644
index ab4471f469e6..000000000000
--- a/fs/compat_ioctl.c
+++ /dev/null
@@ -1,133 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
- *
- * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
- * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
- * Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
- *
- * These routines maintain argument size conversion between 32bit and 64bit
- * ioctls.
- */
-
-#include <linux/types.h>
-#include <linux/compat.h>
-#include <linux/kernel.h>
-#include <linux/capability.h>
-#include <linux/compiler.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/ioctl.h>
-#include <linux/if.h>
-#include <linux/raid/md_u.h>
-#include <linux/falloc.h>
-#include <linux/file.h>
-#include <linux/ppp-ioctl.h>
-#include <linux/if_pppox.h>
-#include <linux/tty.h>
-#include <linux/vt_kern.h>
-#include <linux/blkdev.h>
-#include <linux/serial.h>
-#include <linux/ctype.h>
-#include <linux/syscalls.h>
-#include <linux/gfp.h>
-#include <linux/cec.h>
-
-#include "internal.h"
-
-#include <linux/uaccess.h>
-#include <linux/watchdog.h>
-
-#include <linux/hiddev.h>
-
-COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
-		       compat_ulong_t, arg32)
-{
-	unsigned long arg = arg32;
-	struct fd f = fdget(fd);
-	int error = -EBADF;
-	if (!f.file)
-		goto out;
-
-	/* RED-PEN how should LSM module know it's handling 32bit? */
-	error = security_file_ioctl(f.file, cmd, arg);
-	if (error)
-		goto out_fput;
-
-	switch (cmd) {
-	/* these are never seen by ->ioctl(), no argument or int argument */
-	case FIOCLEX:
-	case FIONCLEX:
-	case FIFREEZE:
-	case FITHAW:
-	case FICLONE:
-		goto do_ioctl;
-	/* these are never seen by ->ioctl(), pointer argument */
-	case FIONBIO:
-	case FIOASYNC:
-	case FIOQSIZE:
-	case FS_IOC_FIEMAP:
-	case FIGETBSZ:
-	case FICLONERANGE:
-	case FIDEDUPERANGE:
-		goto found_handler;
-	/*
-	 * The next group is the stuff handled inside file_ioctl().
-	 * For regular files these never reach ->ioctl(); for
-	 * devices, sockets, etc. they do and one (FIONREAD) is
-	 * even accepted in some cases.  In all those cases
-	 * argument has the same type, so we can handle these
-	 * here, shunting them towards do_vfs_ioctl().
-	 * ->compat_ioctl() will never see any of those.
-	 */
-	/* pointer argument, never actually handled by ->ioctl() */
-	case FIBMAP:
-		goto found_handler;
-	/* handled by some ->ioctl(); always a pointer to int */
-	case FIONREAD:
-		goto found_handler;
-	/* these get messy on amd64 due to alignment differences */
-#if defined(CONFIG_X86_64)
-	case FS_IOC_RESVSP_32:
-	case FS_IOC_RESVSP64_32:
-		error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
-		goto out_fput;
-	case FS_IOC_UNRESVSP_32:
-	case FS_IOC_UNRESVSP64_32:
-		error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
-				compat_ptr(arg));
-		goto out_fput;
-	case FS_IOC_ZERO_RANGE_32:
-		error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
-				compat_ptr(arg));
-		goto out_fput;
-#else
-	case FS_IOC_RESVSP:
-	case FS_IOC_RESVSP64:
-	case FS_IOC_UNRESVSP:
-	case FS_IOC_UNRESVSP64:
-	case FS_IOC_ZERO_RANGE:
-		goto found_handler;
-#endif
-
-	default:
-		if (f.file->f_op->compat_ioctl) {
-			error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
-			if (error != -ENOIOCTLCMD)
-				goto out_fput;
-		}
-
-		error = -ENOTTY;
-		goto out_fput;
-	}
-
- found_handler:
-	arg = (unsigned long)compat_ptr(arg);
- do_ioctl:
-	error = do_vfs_ioctl(f.file, fd, cmd, arg);
- out_fput:
-	fdput(f);
- out:
-	return error;
-}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 2f5e4e5b97e1..8f22f7817edb 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -788,4 +788,94 @@ long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 }
 EXPORT_SYMBOL(compat_ptr_ioctl);
+
+COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
+		       compat_ulong_t, arg32)
+{
+	unsigned long arg = arg32;
+	struct fd f = fdget(fd);
+	int error = -EBADF;
+	if (!f.file)
+		goto out;
+
+	/* RED-PEN how should LSM module know it's handling 32bit? */
+	error = security_file_ioctl(f.file, cmd, arg);
+	if (error)
+		goto out_fput;
+
+	switch (cmd) {
+	/* these are never seen by ->ioctl(), no argument or int argument */
+	case FIOCLEX:
+	case FIONCLEX:
+	case FIFREEZE:
+	case FITHAW:
+	case FICLONE:
+		goto do_ioctl;
+	/* these are never seen by ->ioctl(), pointer argument */
+	case FIONBIO:
+	case FIOASYNC:
+	case FIOQSIZE:
+	case FS_IOC_FIEMAP:
+	case FIGETBSZ:
+	case FICLONERANGE:
+	case FIDEDUPERANGE:
+		goto found_handler;
+	/*
+	 * The next group is the stuff handled inside file_ioctl().
+	 * For regular files these never reach ->ioctl(); for
+	 * devices, sockets, etc. they do and one (FIONREAD) is
+	 * even accepted in some cases.  In all those cases
+	 * argument has the same type, so we can handle these
+	 * here, shunting them towards do_vfs_ioctl().
+	 * ->compat_ioctl() will never see any of those.
+	 */
+	/* pointer argument, never actually handled by ->ioctl() */
+	case FIBMAP:
+		goto found_handler;
+	/* handled by some ->ioctl(); always a pointer to int */
+	case FIONREAD:
+		goto found_handler;
+	/* these get messy on amd64 due to alignment differences */
+#if defined(CONFIG_X86_64)
+	case FS_IOC_RESVSP_32:
+	case FS_IOC_RESVSP64_32:
+		error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
+		goto out_fput;
+	case FS_IOC_UNRESVSP_32:
+	case FS_IOC_UNRESVSP64_32:
+		error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
+				compat_ptr(arg));
+		goto out_fput;
+	case FS_IOC_ZERO_RANGE_32:
+		error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
+				compat_ptr(arg));
+		goto out_fput;
+#else
+	case FS_IOC_RESVSP:
+	case FS_IOC_RESVSP64:
+	case FS_IOC_UNRESVSP:
+	case FS_IOC_UNRESVSP64:
+	case FS_IOC_ZERO_RANGE:
+		goto found_handler;
+#endif
+
+	default:
+		if (f.file->f_op->compat_ioctl) {
+			error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
+			if (error != -ENOIOCTLCMD)
+				goto out_fput;
+		}
+		error = -ENOTTY;
+		goto out_fput;
+	}
+
+ found_handler:
+	arg = (unsigned long)compat_ptr(arg);
+ do_ioctl:
+	error = do_vfs_ioctl(f.file, fd, cmd, arg);
+ out_fput:
+	fdput(f);
+ out:
+	return error;
+}
 #endif
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 17/24] compat_ioctl: simplify the implementation
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (18 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, Darrick J. Wong,
	David Howells, Andreas Gruenbacher, linux-fsdevel

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.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/internal.h          |   6 --
 fs/ioctl.c             | 157 +++++++++++++++++------------------------
 include/linux/falloc.h |   2 -
 include/linux/fs.h     |   4 --
 4 files changed, 64 insertions(+), 105 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 4a7da1df573d..d46247850ad7 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -180,11 +180,5 @@ extern void mnt_pin_kill(struct mount *m);
  */
 extern const struct dentry_operations ns_dentry_operations;
 
-/*
- * fs/ioctl.c
- */
-extern int do_vfs_ioctl(struct file *file, unsigned int fd, unsigned int cmd,
-		    unsigned long arg);
-
 /* direct-io.c: */
 int sb_init_dio_done_wq(struct super_block *sb);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8f22f7817edb..7c9a5df5a597 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -467,7 +467,7 @@ EXPORT_SYMBOL(generic_block_fiemap);
  * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
  * are used here, rest are ignored.
  */
-int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
+static int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
 {
 	struct inode *inode = file_inode(filp);
 	struct space_resv sr;
@@ -495,8 +495,8 @@ int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
 /* on ia32 l_start is on a 32-bit boundary */
 #if defined CONFIG_COMPAT && defined(CONFIG_X86_64)
 /* just account for different alignment */
-int compat_ioctl_preallocate(struct file *file, int mode,
-				struct space_resv_32 __user *argp)
+static int compat_ioctl_preallocate(struct file *file, int mode,
+				    struct space_resv_32 __user *argp)
 {
 	struct inode *inode = file_inode(file);
 	struct space_resv_32 sr;
@@ -521,11 +521,9 @@ int compat_ioctl_preallocate(struct file *file, int mode,
 }
 #endif
 
-static int file_ioctl(struct file *filp, unsigned int cmd,
-		unsigned long arg)
+static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p)
 {
 	struct inode *inode = file_inode(filp);
-	int __user *p = (int __user *)arg;
 
 	switch (cmd) {
 	case FIBMAP:
@@ -542,7 +540,7 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
 		return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
 	}
 
-	return vfs_ioctl(filp, cmd, arg);
+	return -ENOIOCTLCMD;
 }
 
 static int ioctl_fionbio(struct file *filp, int __user *argp)
@@ -661,53 +659,48 @@ static int ioctl_file_dedupe_range(struct file *file,
 }
 
 /*
- * When you add any new common ioctls to the switches above and below
- * please update compat_sys_ioctl() too.
- *
  * 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.
  */
-int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
-	     unsigned long arg)
+static int do_vfs_ioctl(struct file *filp, unsigned int fd,
+			unsigned int cmd, unsigned long arg)
 {
-	int error = 0;
 	void __user *argp = (void __user *)arg;
 	struct inode *inode = file_inode(filp);
 
 	switch (cmd) {
 	case FIOCLEX:
 		set_close_on_exec(fd, 1);
-		break;
+		return 0;
 
 	case FIONCLEX:
 		set_close_on_exec(fd, 0);
-		break;
+		return 0;
 
 	case FIONBIO:
-		error = ioctl_fionbio(filp, argp);
-		break;
+		return ioctl_fionbio(filp, argp);
 
 	case FIOASYNC:
-		error = ioctl_fioasync(fd, filp, argp);
-		break;
+		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);
-			error = copy_to_user(argp, &res, sizeof(res)) ?
-					-EFAULT : 0;
-		} else
-			error = -ENOTTY;
-		break;
+			return copy_to_user(argp, &res, sizeof(res)) ?
+					    -EFAULT : 0;
+		}
+
+		return -ENOTTY;
 
 	case FIFREEZE:
-		error = ioctl_fsfreeze(filp);
-		break;
+		return ioctl_fsfreeze(filp);
 
 	case FITHAW:
-		error = ioctl_fsthaw(filp);
-		break;
+		return ioctl_fsthaw(filp);
 
 	case FS_IOC_FIEMAP:
 		return ioctl_fiemap(filp, argp);
@@ -716,6 +709,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 		/* 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:
@@ -729,24 +723,30 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 
 	default:
 		if (S_ISREG(inode->i_mode))
-			error = file_ioctl(filp, cmd, arg);
-		else
-			error = vfs_ioctl(filp, cmd, arg);
+			return file_ioctl(filp, cmd, argp);
 		break;
 	}
-	return error;
+
+	return -ENOIOCTLCMD;
 }
 
 int ksys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	int error;
 	struct fd f = fdget(fd);
+	int error;
 
 	if (!f.file)
 		return -EBADF;
+
 	error = security_file_ioctl(f.file, cmd, arg);
-	if (!error)
-		error = do_vfs_ioctl(f.file, fd, 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;
 }
@@ -790,92 +790,63 @@ long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 EXPORT_SYMBOL(compat_ptr_ioctl);
 
 COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
-		       compat_ulong_t, arg32)
+		       compat_ulong_t, arg)
 {
-	unsigned long arg = arg32;
 	struct fd f = fdget(fd);
-	int error = -EBADF;
+	int error;
+
 	if (!f.file)
-		goto out;
+		return -EBADF;
 
 	/* RED-PEN how should LSM module know it's handling 32bit? */
 	error = security_file_ioctl(f.file, cmd, arg);
 	if (error)
-		goto out_fput;
+		goto out;
 
 	switch (cmd) {
-	/* these are never seen by ->ioctl(), no argument or int argument */
-	case FIOCLEX:
-	case FIONCLEX:
-	case FIFREEZE:
-	case FITHAW:
+	/* FICLONE takes an int argument, so don't use compat_ptr() */
 	case FICLONE:
-		goto do_ioctl;
-	/* these are never seen by ->ioctl(), pointer argument */
-	case FIONBIO:
-	case FIOASYNC:
-	case FIOQSIZE:
-	case FS_IOC_FIEMAP:
-	case FIGETBSZ:
-	case FICLONERANGE:
-	case FIDEDUPERANGE:
-		goto found_handler;
-	/*
-	 * The next group is the stuff handled inside file_ioctl().
-	 * For regular files these never reach ->ioctl(); for
-	 * devices, sockets, etc. they do and one (FIONREAD) is
-	 * even accepted in some cases.  In all those cases
-	 * argument has the same type, so we can handle these
-	 * here, shunting them towards do_vfs_ioctl().
-	 * ->compat_ioctl() will never see any of those.
-	 */
-	/* pointer argument, never actually handled by ->ioctl() */
-	case FIBMAP:
-		goto found_handler;
-	/* handled by some ->ioctl(); always a pointer to int */
-	case FIONREAD:
-		goto found_handler;
-	/* these get messy on amd64 due to alignment differences */
+		error = ioctl_file_clone(f.file, arg, 0, 0, 0);
+		break;
+
 #if defined(CONFIG_X86_64)
+	/* these get messy on amd64 due to alignment differences */
 	case FS_IOC_RESVSP_32:
 	case FS_IOC_RESVSP64_32:
 		error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
-		goto out_fput;
+		break;
 	case FS_IOC_UNRESVSP_32:
 	case FS_IOC_UNRESVSP64_32:
 		error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
 				compat_ptr(arg));
-		goto out_fput;
+		break;
 	case FS_IOC_ZERO_RANGE_32:
 		error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
 				compat_ptr(arg));
-		goto out_fput;
-#else
-	case FS_IOC_RESVSP:
-	case FS_IOC_RESVSP64:
-	case FS_IOC_UNRESVSP:
-	case FS_IOC_UNRESVSP64:
-	case FS_IOC_ZERO_RANGE:
-		goto found_handler;
+		break;
 #endif
 
+	/*
+	 * everything else in do_vfs_ioctl() takes either a compatible
+	 * pointer argument or no argument -- call it with a modified
+	 * argument.
+	 */
 	default:
-		if (f.file->f_op->compat_ioctl) {
+		error = do_vfs_ioctl(f.file, fd, cmd,
+				     (unsigned long)compat_ptr(arg));
+		if (error != -ENOIOCTLCMD)
+			break;
+
+		if (f.file->f_op->compat_ioctl)
 			error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
-			if (error != -ENOIOCTLCMD)
-				goto out_fput;
-		}
-		error = -ENOTTY;
-		goto out_fput;
+		if (error == -ENOIOCTLCMD)
+			error = -ENOTTY;
+		break;
 	}
 
- found_handler:
-	arg = (unsigned long)compat_ptr(arg);
- do_ioctl:
-	error = do_vfs_ioctl(f.file, fd, cmd, arg);
- out_fput:
-	fdput(f);
  out:
+	fdput(f);
+
 	return error;
 }
 #endif
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
index 8bf3d79f3e82..f3f0b97b1675 100644
--- a/include/linux/falloc.h
+++ b/include/linux/falloc.h
@@ -51,8 +51,6 @@ struct space_resv_32 {
 #define FS_IOC_UNRESVSP64_32	_IOW ('X', 43, struct space_resv_32)
 #define FS_IOC_ZERO_RANGE_32	_IOW ('X', 57, struct space_resv_32)
 
-int compat_ioctl_preallocate(struct file *, int, struct space_resv_32 __user *);
-
 #endif
 
 #endif /* _FALLOC_H_ */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 98e0349adb52..daf570bca42a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2552,10 +2552,6 @@ extern int finish_open(struct file *file, struct dentry *dentry,
 			int (*open)(struct inode *, struct file *));
 extern int finish_no_open(struct file *file, struct dentry *dentry);
 
-/* fs/ioctl.c */
-
-extern int ioctl_preallocate(struct file *filp, int mode, void __user *argp);
-
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);
 extern void __init vfs_caches_init(void);
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 18/24] compat_ioctl: move cdrom commands into cdrom.c
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (19 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Tim Waugh, Borislav Petkov, David S. Miller
  Cc: linux-kernel, y2038, Arnd Bergmann, Hannes Reinecke, linux-block,
	linux-ide, linux-scsi

There is no need for the special cases for the cdrom ioctls any more now,
so make sure that each cdrom driver has a .compat_ioctl() callback and
calls cdrom_compat_ioctl() directly there.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c       | 45 --------------------------------------
 drivers/block/paride/pcd.c |  3 +++
 drivers/cdrom/gdrom.c      |  3 +++
 drivers/ide/ide-cd.c       | 36 ++++++++++++++++++++++++++++++
 drivers/scsi/sr.c          | 10 +++------
 5 files changed, 45 insertions(+), 52 deletions(-)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index cf136bc2c9fc..7cb534d6e767 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -159,42 +159,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 	case HDIO_DRIVE_CMD:
 	/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
 	case 0x330:
-	/* CDROM stuff */
-	case CDROMPAUSE:
-	case CDROMRESUME:
-	case CDROMPLAYMSF:
-	case CDROMPLAYTRKIND:
-	case CDROMREADTOCHDR:
-	case CDROMREADTOCENTRY:
-	case CDROMSTOP:
-	case CDROMSTART:
-	case CDROMEJECT:
-	case CDROMVOLCTRL:
-	case CDROMSUBCHNL:
-	case CDROMMULTISESSION:
-	case CDROM_GET_MCN:
-	case CDROMRESET:
-	case CDROMVOLREAD:
-	case CDROMSEEK:
-	case CDROMPLAYBLK:
-	case CDROMCLOSETRAY:
-	case CDROM_DISC_STATUS:
-	case CDROM_CHANGER_NSLOTS:
-	case CDROM_GET_CAPABILITY:
-	case CDROM_SEND_PACKET:
-	/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
-	 * not take a struct cdrom_read, instead they take a struct cdrom_msf
-	 * which is compatible.
-	 */
-	case CDROMREADMODE2:
-	case CDROMREADMODE1:
-	case CDROMREADRAW:
-	case CDROMREADCOOKED:
-	case CDROMREADALL:
-	/* DVD ioctls */
-	case DVD_READ_STRUCT:
-	case DVD_WRITE_STRUCT:
-	case DVD_AUTH:
 		arg = (unsigned long)compat_ptr(arg);
 	/* These intepret arg as an unsigned long, not as a pointer,
 	 * so we must not do compat_ptr() conversion. */
@@ -210,15 +174,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 	case HDIO_SET_ACOUSTIC:
 	case HDIO_SET_BUSSTATE:
 	case HDIO_SET_ADDRESS:
-	case CDROMEJECT_SW:
-	case CDROM_SET_OPTIONS:
-	case CDROM_CLEAR_OPTIONS:
-	case CDROM_SELECT_SPEED:
-	case CDROM_SELECT_DISC:
-	case CDROM_MEDIA_CHANGED:
-	case CDROM_DRIVE_STATUS:
-	case CDROM_LOCKDOOR:
-	case CDROM_DEBUG:
 		break;
 	default:
 		/* unknown ioctl number */
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 636bfea2de6f..117cfc8cd05a 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -275,6 +275,9 @@ static const struct block_device_operations pcd_bdops = {
 	.open		= pcd_block_open,
 	.release	= pcd_block_release,
 	.ioctl		= pcd_block_ioctl,
+#ifdef CONFIG_COMPAT
+	.ioctl		= blkdev_compat_ptr_ioctl,
+#endif
 	.check_events	= pcd_block_check_events,
 };
 
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index 5b21dc421c94..886b2638c730 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -518,6 +518,9 @@ static const struct block_device_operations gdrom_bdops = {
 	.release		= gdrom_bdops_release,
 	.check_events		= gdrom_bdops_check_events,
 	.ioctl			= gdrom_bdops_ioctl,
+#ifdef CONFIG_COMPAT
+	.ioctl			= blkdev_compat_ptr_ioctl,
+#endif
 };
 
 static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 9d117936bee1..2de6e8ace957 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -25,6 +25,7 @@
 
 #define IDECD_VERSION "5.00"
 
+#include <linux/compat.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -1710,6 +1711,38 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
+			unsigned int cmd, unsigned long arg)
+{
+	struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
+	int err;
+
+	switch (cmd) {
+	case CDROMSETSPINDOWN:
+		return idecd_set_spindown(&info->devinfo, arg);
+	case CDROMGETSPINDOWN:
+		return idecd_get_spindown(&info->devinfo, arg);
+	default:
+		break;
+	}
+
+	return cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
+			   (unsigned long)compat_ptr(arg));
+}
+
+static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
+			     unsigned int cmd, unsigned long arg)
+{
+	int ret;
+
+	mutex_lock(&ide_cd_mutex);
+	ret = idecd_locked_compat_ioctl(bdev, mode, cmd, arg);
+	mutex_unlock(&ide_cd_mutex);
+
+	return ret;
+}
+#endif
 
 static unsigned int idecd_check_events(struct gendisk *disk,
 				       unsigned int clearing)
@@ -1732,6 +1765,9 @@ static const struct block_device_operations idecd_ops = {
 	.open			= idecd_open,
 	.release		= idecd_release,
 	.ioctl			= idecd_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= idecd_compat_ioctl,
+#endif
 	.check_events		= idecd_check_events,
 	.revalidate_disk	= idecd_revalidate_disk
 };
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 6033a886c42c..0fbb8fe6e521 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -628,13 +628,9 @@ static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsign
 		goto put;
 	}
 
-	/*
-	 * CDROM ioctls are handled in the block layer, but
-	 * do the scsi blk ioctls here.
-	 */
-	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-	if (ret != -ENOTTY)
-		return ret;
+	ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, (unsigned long)argp);
+	if (ret != -ENOSYS)
+		goto put;
 
 	ret = scsi_compat_ioctl(sdev, cmd, argp);
 
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 19/24] compat_ioctl: scsi: handle HDIO commands from drivers
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (20 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, John Garry, Brian King, Intel SCU Linux support,
	Artur Paszkiewicz, Jack Wang
  Cc: linux-kernel, y2038, Arnd Bergmann, Hannes Reinecke, linux-ide,
	linux-scsi

The ata_sas_scsi_ioctl() function implements a number of HDIO_* commands
for SCSI devices, it is used by all libata drivers as well as a few
drivers that support SAS attached SATA drives.

The only command that is not safe for compat ioctls here is
HDIO_GET_32BIT. Change the implementation to check for in_compat_syscall()
in order to do both cases correctly, and change all callers to use it
as both native and compat callback pointers, including the indirect
callers through sas_ioctl and ata_scsi_ioctl.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/ata/libata-scsi.c              | 9 +++++++++
 drivers/scsi/aic94xx/aic94xx_init.c    | 3 +++
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +++
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 3 +++
 drivers/scsi/ipr.c                     | 3 +++
 drivers/scsi/isci/init.c               | 3 +++
 drivers/scsi/mvsas/mv_init.c           | 3 +++
 drivers/scsi/pm8001/pm8001_init.c      | 3 +++
 include/linux/libata.h                 | 6 ++++++
 10 files changed, 39 insertions(+)

diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 58e09ffe8b9c..eb2eb599e602 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -17,6 +17,7 @@
  *  - http://www.t13.org/
  */
 
+#include <linux/compat.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
@@ -761,6 +762,10 @@ static int ata_ioc32(struct ata_port *ap)
 	return 0;
 }
 
+/*
+ * This handles both native and compat commands, so anything added
+ * here must have a compatible argument, or check in_compat_syscall()
+ */
 int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
 		     unsigned int cmd, void __user *arg)
 {
@@ -773,6 +778,10 @@ int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
 		spin_lock_irqsave(ap->lock, flags);
 		val = ata_ioc32(ap);
 		spin_unlock_irqrestore(ap->lock, flags);
+#ifdef CONFIG_COMPAT
+		if (in_compat_syscall())
+			return put_user(val, (compat_ulong_t __user *)arg);
+#endif
 		return put_user(val, (unsigned long __user *)arg);
 
 	case HDIO_SET_32BIT:
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index f5781e31f57c..d022407e5645 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -54,6 +54,9 @@ static struct scsi_host_template aic94xx_sht = {
 	.eh_target_reset_handler	= sas_eh_target_reset_handler,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sas_ioctl,
+#endif
 	.track_queue_depth	= 1,
 };
 
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 3af53cc42bd6..fa25766502a2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1772,6 +1772,9 @@ static struct scsi_host_template sht_v1_hw = {
 	.eh_target_reset_handler = sas_eh_target_reset_handler,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sas_ioctl,
+#endif
 	.shost_attrs		= host_attrs_v1_hw,
 	.host_reset             = hisi_sas_host_reset,
 };
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 61b1e2693b08..545eaff5f3ee 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -3551,6 +3551,9 @@ static struct scsi_host_template sht_v2_hw = {
 	.eh_target_reset_handler = sas_eh_target_reset_handler,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sas_ioctl,
+#endif
 	.shost_attrs		= host_attrs_v2_hw,
 	.host_reset		= hisi_sas_host_reset,
 };
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index bf5d5f138437..fa05e612d85a 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -3075,6 +3075,9 @@ static struct scsi_host_template sht_v3_hw = {
 	.eh_target_reset_handler = sas_eh_target_reset_handler,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sas_ioctl,
+#endif
 	.shost_attrs		= host_attrs_v3_hw,
 	.tag_alloc_policy	= BLK_TAG_ALLOC_RR,
 	.host_reset             = hisi_sas_host_reset,
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 079c04bc448a..ae45cbe98ae2 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -6727,6 +6727,9 @@ static struct scsi_host_template driver_template = {
 	.name = "IPR",
 	.info = ipr_ioa_info,
 	.ioctl = ipr_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = ipr_ioctl,
+#endif
 	.queuecommand = ipr_queuecommand,
 	.eh_abort_handler = ipr_eh_abort,
 	.eh_device_reset_handler = ipr_eh_dev_reset,
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 1727d0c71b12..b48aac8dfcb8 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -168,6 +168,9 @@ static struct scsi_host_template isci_sht = {
 	.eh_target_reset_handler        = sas_eh_target_reset_handler,
 	.target_destroy			= sas_target_destroy,
 	.ioctl				= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl			= sas_ioctl,
+#endif
 	.shost_attrs			= isci_host_attrs,
 	.track_queue_depth		= 1,
 };
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index da719b0694dc..7af9173c4925 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -47,6 +47,9 @@ static struct scsi_host_template mvs_sht = {
 	.eh_target_reset_handler = sas_eh_target_reset_handler,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sas_ioctl,
+#endif
 	.shost_attrs		= mvst_host_attrs,
 	.track_queue_depth	= 1,
 };
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index ff618ad80ebd..3c6076e4c6d2 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -101,6 +101,9 @@ static struct scsi_host_template pm8001_sht = {
 	.eh_target_reset_handler = sas_eh_target_reset_handler,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sas_ioctl,
+#endif
 	.shost_attrs		= pm8001_host_attrs,
 	.track_queue_depth	= 1,
 };
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d3bbfddf616a..e68d05febe5a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1109,6 +1109,11 @@ extern void ata_host_init(struct ata_host *, struct device *, struct ata_port_op
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, unsigned int cmd,
 			  void __user *arg);
+#ifdef CONFIG_COMPAT
+#define ATA_SCSI_COMPAT_IOCTL .compat_ioctl = ata_scsi_ioctl,
+#else
+#define ATA_SCSI_COMPAT_IOCTL /* empty */
+#endif
 extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
 			    unsigned int cmd, void __user *arg);
@@ -1340,6 +1345,7 @@ extern struct device_attribute *ata_common_sdev_attrs[];
 	.module			= THIS_MODULE,			\
 	.name			= drv_name,			\
 	.ioctl			= ata_scsi_ioctl,		\
+	ATA_SCSI_COMPAT_IOCTL					\
 	.queuecommand		= ata_scsi_queuecmd,		\
 	.can_queue		= ATA_DEF_QUEUE,		\
 	.tag_alloc_policy	= BLK_TAG_ALLOC_RR,		\
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 20/24] compat_ioctl: move HDIO ioctl handling into drivers/ide
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (21 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-12 16:29   ` Christoph Hellwig
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Borislav Petkov, David S. Miller
  Cc: linux-kernel, y2038, Arnd Bergmann, Hannes Reinecke,
	Heiko Carstens, linux-block, linux-ide

Most of the HDIO ioctls are only used by the obsolete drivers/ide
subsystem, these can be handled by changing ide_cmd_ioctl() to be aware
of compat mode and doing the correct transformations in place and using
it as both native and compat handlers for all drivers.

The SCSI drivers implementing the same commands are already doing
this in the drivers, so the compat_blkdev_driver_ioctl() function
is no longer needed now.

The BLKSECTSET and HDIO_GETGEO_BIG ioctls are not implemented
in any driver any more and no longer need any conversion.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/compat_ioctl.c           | 75 ----------------------------------
 drivers/ide/ide-cd.c           |  8 +++-
 drivers/ide/ide-disk.c         |  3 ++
 drivers/ide/ide-floppy_ioctl.c |  7 ++--
 drivers/ide/ide-ioctls.c       | 47 +++++++++++++--------
 drivers/ide/ide-tape.c         | 14 +++++++
 6 files changed, 57 insertions(+), 97 deletions(-)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 7cb534d6e767..765aa5357655 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -77,24 +77,6 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
 	return ret;
 }
 
-static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, unsigned long arg)
-{
-	unsigned long __user *p;
-	int error;
-
-	p = compat_alloc_user_space(sizeof(unsigned long));
-	error = __blkdev_driver_ioctl(bdev, mode,
-				cmd, (unsigned long)p);
-	if (error == 0) {
-		unsigned int __user *uvp = compat_ptr(arg);
-		unsigned long v;
-		if (get_user(v, p) || put_user(v, uvp))
-			error = -EFAULT;
-	}
-	return error;
-}
-
 struct compat_blkpg_ioctl_arg {
 	compat_int_t op;
 	compat_int_t flags;
@@ -128,61 +110,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
 #define BLKBSZSET_32		_IOW(0x12, 113, int)
 #define BLKGETSIZE64_32		_IOR(0x12, 114, int)
 
-static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
-			unsigned cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case HDIO_GET_UNMASKINTR:
-	case HDIO_GET_MULTCOUNT:
-	case HDIO_GET_KEEPSETTINGS:
-	case HDIO_GET_32BIT:
-	case HDIO_GET_NOWERR:
-	case HDIO_GET_DMA:
-	case HDIO_GET_NICE:
-	case HDIO_GET_WCACHE:
-	case HDIO_GET_ACOUSTIC:
-	case HDIO_GET_ADDRESS:
-	case HDIO_GET_BUSSTATE:
-		return compat_hdio_ioctl(bdev, mode, cmd, arg);
-
-	/*
-	 * No handler required for the ones below, we just need to
-	 * convert arg to a 64 bit pointer.
-	 */
-	case BLKSECTSET:
-	/*
-	 * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
-	 *         Some need translations, these do not.
-	 */
-	case HDIO_GET_IDENTITY:
-	case HDIO_DRIVE_TASK:
-	case HDIO_DRIVE_CMD:
-	/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
-	case 0x330:
-		arg = (unsigned long)compat_ptr(arg);
-	/* These intepret arg as an unsigned long, not as a pointer,
-	 * so we must not do compat_ptr() conversion. */
-	case HDIO_SET_MULTCOUNT:
-	case HDIO_SET_UNMASKINTR:
-	case HDIO_SET_KEEPSETTINGS:
-	case HDIO_SET_32BIT:
-	case HDIO_SET_NOWERR:
-	case HDIO_SET_DMA:
-	case HDIO_SET_PIO_MODE:
-	case HDIO_SET_NICE:
-	case HDIO_SET_WCACHE:
-	case HDIO_SET_ACOUSTIC:
-	case HDIO_SET_BUSSTATE:
-	case HDIO_SET_ADDRESS:
-		break;
-	default:
-		/* unknown ioctl number */
-		return -ENOIOCTLCMD;
-	}
-
-	return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
-}
-
 /* Most of the generic ioctls are handled in the normal fallback path.
    This assumes the blkdev's low level compat_ioctl always returns
    ENOIOCTLCMD for unknown ioctls. */
@@ -293,8 +220,6 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	default:
 		if (disk->fops->compat_ioctl)
 			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
-		if (ret == -ENOIOCTLCMD)
-			ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
 		return ret;
 	}
 }
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 2de6e8ace957..521564da8707 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1727,8 +1727,12 @@ static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
 		break;
 	}
 
-	return cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
-			   (unsigned long)compat_ptr(arg));
+	err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
+	if (err == -EINVAL)
+		err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
+				  (unsigned long)compat_ptr(arg));
+
+	return err;
 }
 
 static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 197912af5c2f..27f1098e4bcd 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -794,4 +794,7 @@ const struct ide_disk_ops ide_ata_disk_ops = {
 	.set_doorlock		= ide_disk_set_doorlock,
 	.do_request		= ide_do_rw_disk,
 	.ioctl			= ide_disk_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= ide_disk_ioctl,
+#endif
 };
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
index 4fd70f804d6f..39a790ac6cc3 100644
--- a/drivers/ide/ide-floppy_ioctl.c
+++ b/drivers/ide/ide-floppy_ioctl.c
@@ -329,10 +329,9 @@ int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
 	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
 		err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
 
-	/*
-	 * there is no generic_ide_compat_ioctl(), that is handled
-	 * through compat_blkdev_ioctl().
-	 */
+	if (err == -ENOTTY)
+		err = generic_ide_ioctl(drive, bdev, cmd, arg);
+
 out:
 	mutex_unlock(&ide_floppy_ioctl_mutex);
 	return err;
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index d48c17003874..d97da46fdd79 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -3,11 +3,21 @@
  * IDE ioctls handling.
  */
 
+#include <linux/compat.h>
 #include <linux/export.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/slab.h>
 
+static int put_user_long(long val, unsigned long arg)
+{
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall())
+		return put_user(val, (compat_long_t __user *)compat_ptr(arg));
+#endif
+	return put_user(val, (long __user *)arg);
+}
+
 static const struct ide_ioctl_devset ide_ioctl_settings[] = {
 { HDIO_GET_32BIT,	 HDIO_SET_32BIT,	&ide_devset_io_32bit  },
 { HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS,	&ide_devset_keepsettings },
@@ -37,7 +47,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
 	mutex_lock(&ide_setting_mtx);
 	err = ds->get(drive);
 	mutex_unlock(&ide_setting_mtx);
-	return err >= 0 ? put_user(err, (long __user *)arg) : err;
+	return err >= 0 ? put_user_long(err, arg) : err;
 
 set_val:
 	if (bdev != bdev->bd_contains)
@@ -56,7 +66,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
 EXPORT_SYMBOL_GPL(ide_setting_ioctl);
 
 static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
-				  unsigned long arg)
+				  void __user *argp)
 {
 	u16 *id = NULL;
 	int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
@@ -77,7 +87,7 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
 	memcpy(id, drive->id, size);
 	ata_id_to_hd_driveid(id);
 
-	if (copy_to_user((void __user *)arg, id, size))
+	if (copy_to_user(argp, id, size))
 		rc = -EFAULT;
 
 	kfree(id);
@@ -87,10 +97,10 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
 
 static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
 {
-	return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
+	return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
 			 << IDE_NICE_DSC_OVERLAP) |
 			(!!(drive->dev_flags & IDE_DFLAG_NICE1)
-			 << IDE_NICE_1), (long __user *)arg);
+			 << IDE_NICE_1), arg);
 }
 
 static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
@@ -115,7 +125,7 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
 	return 0;
 }
 
-static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
+static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
 {
 	u8 *buf = NULL;
 	int bufsize = 0, err = 0;
@@ -123,7 +133,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
 	struct ide_cmd cmd;
 	struct ide_taskfile *tf = &cmd.tf;
 
-	if (NULL == (void *) arg) {
+	if (NULL == argp) {
 		struct request *rq;
 
 		rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
@@ -135,7 +145,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
 		return err;
 	}
 
-	if (copy_from_user(args, (void __user *)arg, 4))
+	if (copy_from_user(args, argp, 4))
 		return -EFAULT;
 
 	memset(&cmd, 0, sizeof(cmd));
@@ -181,19 +191,18 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
 	args[1] = tf->error;
 	args[2] = tf->nsect;
 abort:
-	if (copy_to_user((void __user *)arg, &args, 4))
+	if (copy_to_user(argp, &args, 4))
 		err = -EFAULT;
 	if (buf) {
-		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+		if (copy_to_user((argp + 4), buf, bufsize))
 			err = -EFAULT;
 		kfree(buf);
 	}
 	return err;
 }
 
-static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg)
+static int ide_task_ioctl(ide_drive_t *drive, void __user *p)
 {
-	void __user *p = (void __user *)arg;
 	int err = 0;
 	u8 args[7];
 	struct ide_cmd cmd;
@@ -237,6 +246,12 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
 		      unsigned int cmd, unsigned long arg)
 {
 	int err;
+	void __user *argp = (void __user *)arg;
+
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall())
+		argp = compat_ptr(arg);
+#endif
 
 	err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
 	if (err != -EOPNOTSUPP)
@@ -247,7 +262,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
 	case HDIO_GET_IDENTITY:
 		if (bdev != bdev->bd_contains)
 			return -EINVAL;
-		return ide_get_identity_ioctl(drive, cmd, arg);
+		return ide_get_identity_ioctl(drive, cmd, argp);
 	case HDIO_GET_NICE:
 		return ide_get_nice_ioctl(drive, arg);
 	case HDIO_SET_NICE:
@@ -265,11 +280,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
 	case HDIO_DRIVE_CMD:
 		if (!capable(CAP_SYS_RAWIO))
 			return -EACCES;
-		return ide_cmd_ioctl(drive, arg);
+		return ide_cmd_ioctl(drive, argp);
 	case HDIO_DRIVE_TASK:
 		if (!capable(CAP_SYS_RAWIO))
 			return -EACCES;
-		return ide_task_ioctl(drive, arg);
+		return ide_task_ioctl(drive, argp);
 	case HDIO_DRIVE_RESET:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
@@ -277,7 +292,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
 	case HDIO_GET_BUSSTATE:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
-		if (put_user(BUSSTATE_ON, (long __user *)arg))
+		if (put_user_long(BUSSTATE_ON, arg))
 			return -EFAULT;
 		return 0;
 	case HDIO_SET_BUSSTATE:
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 3e7482695f77..4c2a95a2f0b6 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1945,11 +1945,25 @@ static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
 	return err;
 }
 
+#ifdef CONFIG_COMPAT
+static int idetape_compat_ioctl(struct block_device *bdev, fmode_t mode,
+				unsigned int cmd, unsigned long arg)
+{
+        if (cmd == 0x0340 || cmd == 0x350)
+		arg = (unsigned long)compat_ptr(arg);
+
+	return idetape_ioctl(bdev, mode, cmd, arg);
+}
+#endif
+
 static const struct block_device_operations idetape_block_ops = {
 	.owner		= THIS_MODULE,
 	.open		= idetape_open,
 	.release	= idetape_release,
 	.ioctl		= idetape_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= idetape_compat_ioctl,
+#endif
 };
 
 static int ide_tape_probe(ide_drive_t *drive)
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 21/24] compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (22 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-12 16:30   ` Christoph Hellwig
  -1 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, Tejun Heo, Jan Kara,
	Chaitanya Kulkarni, Dmitry Fomichev, Ajay Joshi, linux-block

Having both in the same file allows a number of simplifications
to the compat path, and makes it more likely that changes to
the native path get applied to the compat version as well.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/Makefile       |   1 -
 block/compat_ioctl.c | 225 -------------------------------------------
 block/ioctl.c        | 219 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+), 226 deletions(-)
 delete mode 100644 block/compat_ioctl.c

diff --git a/block/Makefile b/block/Makefile
index 205a5f2fef17..1f70c73ea83d 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_MQ_IOSCHED_KYBER)	+= kyber-iosched.o
 bfq-y				:= bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
 obj-$(CONFIG_IOSCHED_BFQ)	+= bfq.o
 
-obj-$(CONFIG_BLOCK_COMPAT)	+= compat_ioctl.o
 obj-$(CONFIG_BLK_CMDLINE_PARSER)	+= cmdline-parser.o
 obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
 obj-$(CONFIG_BLK_MQ_PCI)	+= blk-mq-pci.o
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
deleted file mode 100644
index 765aa5357655..000000000000
--- a/block/compat_ioctl.c
+++ /dev/null
@@ -1,225 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/blktrace_api.h>
-#include <linux/cdrom.h>
-#include <linux/compat.h>
-#include <linux/elevator.h>
-#include <linux/hdreg.h>
-#include <linux/slab.h>
-#include <linux/syscalls.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-
-static int compat_put_ushort(unsigned long arg, unsigned short val)
-{
-	return put_user(val, (unsigned short __user *)compat_ptr(arg));
-}
-
-static int compat_put_int(unsigned long arg, int val)
-{
-	return put_user(val, (compat_int_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_uint(unsigned long arg, unsigned int val)
-{
-	return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_long(unsigned long arg, long val)
-{
-	return put_user(val, (compat_long_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
-{
-	return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_u64(unsigned long arg, u64 val)
-{
-	return put_user(val, (compat_u64 __user *)compat_ptr(arg));
-}
-
-struct compat_hd_geometry {
-	unsigned char heads;
-	unsigned char sectors;
-	unsigned short cylinders;
-	u32 start;
-};
-
-static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
-			struct compat_hd_geometry __user *ugeo)
-{
-	struct hd_geometry geo;
-	int ret;
-
-	if (!ugeo)
-		return -EINVAL;
-	if (!disk->fops->getgeo)
-		return -ENOTTY;
-
-	memset(&geo, 0, sizeof(geo));
-	/*
-	 * We need to set the startsect first, the driver may
-	 * want to override it.
-	 */
-	geo.start = get_start_sect(bdev);
-	ret = disk->fops->getgeo(bdev, &geo);
-	if (ret)
-		return ret;
-
-	ret = copy_to_user(ugeo, &geo, 4);
-	ret |= put_user(geo.start, &ugeo->start);
-	if (ret)
-		ret = -EFAULT;
-
-	return ret;
-}
-
-struct compat_blkpg_ioctl_arg {
-	compat_int_t op;
-	compat_int_t flags;
-	compat_int_t datalen;
-	compat_caddr_t data;
-};
-
-static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
-{
-	struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
-	compat_caddr_t udata;
-	compat_int_t n;
-	int err;
-
-	err = get_user(n, &ua32->op);
-	err |= put_user(n, &a->op);
-	err |= get_user(n, &ua32->flags);
-	err |= put_user(n, &a->flags);
-	err |= get_user(n, &ua32->datalen);
-	err |= put_user(n, &a->datalen);
-	err |= get_user(udata, &ua32->data);
-	err |= put_user(compat_ptr(udata), &a->data);
-	if (err)
-		return err;
-
-	return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
-}
-
-#define BLKBSZGET_32		_IOR(0x12, 112, int)
-#define BLKBSZSET_32		_IOW(0x12, 113, int)
-#define BLKGETSIZE64_32		_IOR(0x12, 114, int)
-
-/* Most of the generic ioctls are handled in the normal fallback path.
-   This assumes the blkdev's low level compat_ioctl always returns
-   ENOIOCTLCMD for unknown ioctls. */
-long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
-{
-	int ret = -ENOIOCTLCMD;
-	struct inode *inode = file->f_mapping->host;
-	struct block_device *bdev = inode->i_bdev;
-	struct gendisk *disk = bdev->bd_disk;
-	fmode_t mode = file->f_mode;
-	loff_t size;
-	unsigned int max_sectors;
-
-	/*
-	 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
-	 * to updated it before every ioctl.
-	 */
-	if (file->f_flags & O_NDELAY)
-		mode |= FMODE_NDELAY;
-	else
-		mode &= ~FMODE_NDELAY;
-
-	switch (cmd) {
-	case HDIO_GETGEO:
-		return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
-	case BLKPBSZGET:
-		return compat_put_uint(arg, bdev_physical_block_size(bdev));
-	case BLKIOMIN:
-		return compat_put_uint(arg, bdev_io_min(bdev));
-	case BLKIOOPT:
-		return compat_put_uint(arg, bdev_io_opt(bdev));
-	case BLKALIGNOFF:
-		return compat_put_int(arg, bdev_alignment_offset(bdev));
-	case BLKDISCARDZEROES:
-		return compat_put_uint(arg, 0);
-	case BLKFLSBUF:
-	case BLKROSET:
-	case BLKDISCARD:
-	case BLKSECDISCARD:
-	case BLKZEROOUT:
-	/*
-	 * the ones below are implemented in blkdev_locked_ioctl,
-	 * but we call blkdev_ioctl, which gets the lock for us
-	 */
-	case BLKRRPART:
-	case BLKREPORTZONE:
-	case BLKRESETZONE:
-	case BLKOPENZONE:
-	case BLKCLOSEZONE:
-	case BLKFINISHZONE:
-	case BLKGETZONESZ:
-	case BLKGETNRZONES:
-		return blkdev_ioctl(bdev, mode, cmd,
-				(unsigned long)compat_ptr(arg));
-	case BLKBSZSET_32:
-		return blkdev_ioctl(bdev, mode, BLKBSZSET,
-				(unsigned long)compat_ptr(arg));
-	case BLKPG:
-		return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
-	case BLKRAGET:
-	case BLKFRAGET:
-		if (!arg)
-			return -EINVAL;
-		return compat_put_long(arg,
-			       (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
-	case BLKROGET: /* compatible */
-		return compat_put_int(arg, bdev_read_only(bdev) != 0);
-	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
-		return compat_put_int(arg, block_size(bdev));
-	case BLKSSZGET: /* get block device hardware sector size */
-		return compat_put_int(arg, bdev_logical_block_size(bdev));
-	case BLKSECTGET:
-		max_sectors = min_t(unsigned int, USHRT_MAX,
-				    queue_max_sectors(bdev_get_queue(bdev)));
-		return compat_put_ushort(arg, max_sectors);
-	case BLKROTATIONAL:
-		return compat_put_ushort(arg,
-					 !blk_queue_nonrot(bdev_get_queue(bdev)));
-	case BLKRASET: /* compatible, but no compat_ptr (!) */
-	case BLKFRASET:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
-		return 0;
-	case BLKGETSIZE:
-		size = i_size_read(bdev->bd_inode);
-		if ((size >> 9) > ~0UL)
-			return -EFBIG;
-		return compat_put_ulong(arg, size >> 9);
-
-	case BLKGETSIZE64_32:
-		return compat_put_u64(arg, i_size_read(bdev->bd_inode));
-
-	case BLKTRACESETUP32:
-	case BLKTRACESTART: /* compatible */
-	case BLKTRACESTOP:  /* compatible */
-	case BLKTRACETEARDOWN: /* compatible */
-		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
-		return ret;
-	case IOC_PR_REGISTER:
-	case IOC_PR_RESERVE:
-	case IOC_PR_RELEASE:
-	case IOC_PR_PREEMPT:
-	case IOC_PR_PREEMPT_ABORT:
-	case IOC_PR_CLEAR:
-		return blkdev_ioctl(bdev, mode, cmd,
-				(unsigned long)compat_ptr(arg));
-	default:
-		if (disk->fops->compat_ioctl)
-			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
-		return ret;
-	}
-}
diff --git a/block/ioctl.c b/block/ioctl.c
index e728331d1a5b..f8c4e2649335 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -269,6 +269,38 @@ static int put_u64(unsigned long arg, u64 val)
 	return put_user(val, (u64 __user *)arg);
 }
 
+#ifdef CONFIG_COMPAT
+static int compat_put_ushort(unsigned long arg, unsigned short val)
+{
+	return put_user(val, (unsigned short __user *)compat_ptr(arg));
+}
+
+static int compat_put_int(unsigned long arg, int val)
+{
+	return put_user(val, (compat_int_t __user *)compat_ptr(arg));
+}
+
+static int compat_put_uint(unsigned long arg, unsigned int val)
+{
+	return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
+}
+
+static int compat_put_long(unsigned long arg, long val)
+{
+	return put_user(val, (compat_long_t __user *)compat_ptr(arg));
+}
+
+static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
+{
+	return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
+}
+
+static int compat_put_u64(unsigned long arg, u64 val)
+{
+	return put_user(val, (compat_u64 __user *)compat_ptr(arg));
+}
+#endif
+
 int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 			unsigned cmd, unsigned long arg)
 {
@@ -476,6 +508,44 @@ static int blkdev_getgeo(struct block_device *bdev,
 	return 0;
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_hd_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	u32 start;
+};
+
+static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
+			struct compat_hd_geometry __user *ugeo)
+{
+	struct hd_geometry geo;
+	int ret;
+
+	if (!ugeo)
+		return -EINVAL;
+	if (!disk->fops->getgeo)
+		return -ENOTTY;
+
+	memset(&geo, 0, sizeof(geo));
+	/*
+	 * We need to set the startsect first, the driver may
+	 * want to override it.
+	 */
+	geo.start = get_start_sect(bdev);
+	ret = disk->fops->getgeo(bdev, &geo);
+	if (ret)
+		return ret;
+
+	ret = copy_to_user(ugeo, &geo, 4);
+	ret |= put_user(geo.start, &ugeo->start);
+	if (ret)
+		ret = -EFAULT;
+
+	return ret;
+}
+#endif
+
 /* set the logical block size */
 static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
 		int __user *argp)
@@ -604,3 +674,152 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 	}
 }
 EXPORT_SYMBOL_GPL(blkdev_ioctl);
+
+#ifdef CONFIG_COMPAT
+struct compat_blkpg_ioctl_arg {
+	compat_int_t op;
+	compat_int_t flags;
+	compat_int_t datalen;
+	compat_caddr_t data;
+};
+
+static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
+		unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
+{
+	struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
+	compat_caddr_t udata;
+	compat_int_t n;
+	int err;
+
+	err = get_user(n, &ua32->op);
+	err |= put_user(n, &a->op);
+	err |= get_user(n, &ua32->flags);
+	err |= put_user(n, &a->flags);
+	err |= get_user(n, &ua32->datalen);
+	err |= put_user(n, &a->datalen);
+	err |= get_user(udata, &ua32->data);
+	err |= put_user(compat_ptr(udata), &a->data);
+	if (err)
+		return err;
+
+	return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
+}
+
+#define BLKBSZGET_32		_IOR(0x12, 112, int)
+#define BLKBSZSET_32		_IOW(0x12, 113, int)
+#define BLKGETSIZE64_32		_IOR(0x12, 114, int)
+
+/* Most of the generic ioctls are handled in the normal fallback path.
+   This assumes the blkdev's low level compat_ioctl always returns
+   ENOIOCTLCMD for unknown ioctls. */
+long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	int ret = -ENOIOCTLCMD;
+	struct inode *inode = file->f_mapping->host;
+	struct block_device *bdev = inode->i_bdev;
+	struct gendisk *disk = bdev->bd_disk;
+	fmode_t mode = file->f_mode;
+	loff_t size;
+	unsigned int max_sectors;
+
+	/*
+	 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
+	 * to updated it before every ioctl.
+	 */
+	if (file->f_flags & O_NDELAY)
+		mode |= FMODE_NDELAY;
+	else
+		mode &= ~FMODE_NDELAY;
+
+	switch (cmd) {
+	case HDIO_GETGEO:
+		return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
+	case BLKPBSZGET:
+		return compat_put_uint(arg, bdev_physical_block_size(bdev));
+	case BLKIOMIN:
+		return compat_put_uint(arg, bdev_io_min(bdev));
+	case BLKIOOPT:
+		return compat_put_uint(arg, bdev_io_opt(bdev));
+	case BLKALIGNOFF:
+		return compat_put_int(arg, bdev_alignment_offset(bdev));
+	case BLKDISCARDZEROES:
+		return compat_put_uint(arg, 0);
+	case BLKFLSBUF:
+	case BLKROSET:
+	case BLKDISCARD:
+	case BLKSECDISCARD:
+	case BLKZEROOUT:
+	/*
+	 * the ones below are implemented in blkdev_locked_ioctl,
+	 * but we call blkdev_ioctl, which gets the lock for us
+	 */
+	case BLKRRPART:
+	case BLKREPORTZONE:
+	case BLKRESETZONE:
+	case BLKOPENZONE:
+	case BLKCLOSEZONE:
+	case BLKFINISHZONE:
+	case BLKGETZONESZ:
+	case BLKGETNRZONES:
+		return blkdev_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(arg));
+	case BLKBSZSET_32:
+		return blkdev_ioctl(bdev, mode, BLKBSZSET,
+				(unsigned long)compat_ptr(arg));
+	case BLKPG:
+		return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
+	case BLKRAGET:
+	case BLKFRAGET:
+		if (!arg)
+			return -EINVAL;
+		return compat_put_long(arg,
+			       (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
+	case BLKROGET: /* compatible */
+		return compat_put_int(arg, bdev_read_only(bdev) != 0);
+	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
+		return compat_put_int(arg, block_size(bdev));
+	case BLKSSZGET: /* get block device hardware sector size */
+		return compat_put_int(arg, bdev_logical_block_size(bdev));
+	case BLKSECTGET:
+		max_sectors = min_t(unsigned int, USHRT_MAX,
+				    queue_max_sectors(bdev_get_queue(bdev)));
+		return compat_put_ushort(arg, max_sectors);
+	case BLKROTATIONAL:
+		return compat_put_ushort(arg,
+					 !blk_queue_nonrot(bdev_get_queue(bdev)));
+	case BLKRASET: /* compatible, but no compat_ptr (!) */
+	case BLKFRASET:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+		return 0;
+	case BLKGETSIZE:
+		size = i_size_read(bdev->bd_inode);
+		if ((size >> 9) > ~0UL)
+			return -EFBIG;
+		return compat_put_ulong(arg, size >> 9);
+
+	case BLKGETSIZE64_32:
+		return compat_put_u64(arg, i_size_read(bdev->bd_inode));
+
+	case BLKTRACESETUP32:
+	case BLKTRACESTART: /* compatible */
+	case BLKTRACESTOP:  /* compatible */
+	case BLKTRACETEARDOWN: /* compatible */
+		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
+		return ret;
+	case IOC_PR_REGISTER:
+	case IOC_PR_RESERVE:
+	case IOC_PR_RELEASE:
+	case IOC_PR_PREEMPT:
+	case IOC_PR_PREEMPT_ABORT:
+	case IOC_PR_CLEAR:
+		return blkdev_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(arg));
+	default:
+		if (disk->fops->compat_ioctl)
+			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
+		return ret;
+	}
+}
+#endif
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 22/24] compat_ioctl: block: simplify compat_blkpg_ioctl()
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (23 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, Jan Kara, Keith Busch,
	Hans Holmberg, Ajay Joshi, linux-block

There is no need to go through a compat_alloc_user_space()
copy any more, just wrap the function in a small helper that
works the same way for native and compat mode.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/ioctl.c | 74 ++++++++++++++++++++++++++-------------------------
 1 file changed, 38 insertions(+), 36 deletions(-)

diff --git a/block/ioctl.c b/block/ioctl.c
index f8c4e2649335..d6911a1149f5 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -12,12 +12,12 @@
 #include <linux/pr.h>
 #include <linux/uaccess.h>
 
-static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
+static int blkpg_do_ioctl(struct block_device *bdev,
+			  struct blkpg_partition __user *upart, int op)
 {
 	struct block_device *bdevp;
 	struct gendisk *disk;
 	struct hd_struct *part, *lpart;
-	struct blkpg_ioctl_arg a;
 	struct blkpg_partition p;
 	struct disk_part_iter piter;
 	long long start, length;
@@ -25,9 +25,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
-	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
-		return -EFAULT;
-	if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+	if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
 		return -EFAULT;
 	disk = bdev->bd_disk;
 	if (bdev != bdev->bd_contains)
@@ -35,7 +33,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
 	partno = p.pno;
 	if (partno <= 0)
 		return -EINVAL;
-	switch (a.op) {
+	switch (op) {
 		case BLKPG_ADD_PARTITION:
 			start = p.start >> 9;
 			length = p.length >> 9;
@@ -156,6 +154,39 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
 	}
 }
 
+static int blkpg_ioctl(struct block_device *bdev,
+		       struct blkpg_ioctl_arg __user *arg)
+{
+	struct blkpg_partition __user *udata;
+	int op;
+
+	if (get_user(op, &arg->op) || get_user(udata, &arg->data))
+		return -EFAULT;
+
+	return blkpg_do_ioctl(bdev, udata, op);
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_blkpg_ioctl_arg {
+	compat_int_t op;
+	compat_int_t flags;
+	compat_int_t datalen;
+	compat_caddr_t data;
+};
+
+static int compat_blkpg_ioctl(struct block_device *bdev,
+			      struct compat_blkpg_ioctl_arg __user *arg)
+{
+	compat_caddr_t udata;
+	int op;
+
+	if (get_user(op, &arg->op) || get_user(udata, &arg->data))
+		return -EFAULT;
+
+	return blkpg_do_ioctl(bdev, compat_ptr(udata), op);
+}
+#endif
+
 static int blkdev_reread_part(struct block_device *bdev)
 {
 	int ret;
@@ -676,35 +707,6 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 EXPORT_SYMBOL_GPL(blkdev_ioctl);
 
 #ifdef CONFIG_COMPAT
-struct compat_blkpg_ioctl_arg {
-	compat_int_t op;
-	compat_int_t flags;
-	compat_int_t datalen;
-	compat_caddr_t data;
-};
-
-static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
-{
-	struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
-	compat_caddr_t udata;
-	compat_int_t n;
-	int err;
-
-	err = get_user(n, &ua32->op);
-	err |= put_user(n, &a->op);
-	err |= get_user(n, &ua32->flags);
-	err |= put_user(n, &a->flags);
-	err |= get_user(n, &ua32->datalen);
-	err |= put_user(n, &a->datalen);
-	err |= get_user(udata, &ua32->data);
-	err |= put_user(compat_ptr(udata), &a->data);
-	if (err)
-		return err;
-
-	return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
-}
-
 #define BLKBSZGET_32		_IOR(0x12, 112, int)
 #define BLKBSZSET_32		_IOW(0x12, 113, int)
 #define BLKGETSIZE64_32		_IOR(0x12, 114, int)
@@ -767,7 +769,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 		return blkdev_ioctl(bdev, mode, BLKBSZSET,
 				(unsigned long)compat_ptr(arg));
 	case BLKPG:
-		return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
+		return compat_blkpg_ioctl(bdev, compat_ptr(arg));
 	case BLKRAGET:
 	case BLKFRAGET:
 		if (!arg)
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 23/24] compat_ioctl: simplify up block/ioctl.c
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (24 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen, Alexander Viro
  Cc: linux-kernel, y2038, Arnd Bergmann, Jan Kara, Chaitanya Kulkarni,
	Ajay Joshi, linux-block

Having separate implementations of blkdev_ioctl() often leads to these
getting out of sync, despite the comment at the top.

Since most of the ioctl commands are compatible, and we try very hard
not to add any new incompatible ones, move all the common bits into a
shared function and leave only the ones that are historically different
in separate functions for native/compat mode.

To deal with the compat_ptr() conversion, pass both the integer
argument and the pointer argument into the new blkdev_common_ioctl()
and make sure to always use the correct one of these.

blkdev_ioctl() is now only kept as a separate exported interfact
for drivers/char/raw.c, which lacks a compat_ioctl variant.
We should probably either move raw.c to staging if there are no
more users, or export blkdev_compat_ioctl() as well.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 block/ioctl.c | 269 ++++++++++++++++++++++----------------------------
 1 file changed, 117 insertions(+), 152 deletions(-)

diff --git a/block/ioctl.c b/block/ioctl.c
index d6911a1149f5..127194b9f9bd 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -270,65 +270,45 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
 			BLKDEV_ZERO_NOUNMAP);
 }
 
-static int put_ushort(unsigned long arg, unsigned short val)
+static int put_ushort(unsigned short __user *argp, unsigned short val)
 {
-	return put_user(val, (unsigned short __user *)arg);
+	return put_user(val, argp);
 }
 
-static int put_int(unsigned long arg, int val)
+static int put_int(int __user *argp, int val)
 {
-	return put_user(val, (int __user *)arg);
+	return put_user(val, argp);
 }
 
-static int put_uint(unsigned long arg, unsigned int val)
+static int put_uint(unsigned int __user *argp, unsigned int val)
 {
-	return put_user(val, (unsigned int __user *)arg);
+	return put_user(val, argp);
 }
 
-static int put_long(unsigned long arg, long val)
+static int put_long(long __user *argp, long val)
 {
-	return put_user(val, (long __user *)arg);
+	return put_user(val, argp);
 }
 
-static int put_ulong(unsigned long arg, unsigned long val)
+static int put_ulong(unsigned long __user *argp, unsigned long val)
 {
-	return put_user(val, (unsigned long __user *)arg);
+	return put_user(val, argp);
 }
 
-static int put_u64(unsigned long arg, u64 val)
+static int put_u64(u64 __user *argp, u64 val)
 {
-	return put_user(val, (u64 __user *)arg);
+	return put_user(val, argp);
 }
 
 #ifdef CONFIG_COMPAT
-static int compat_put_ushort(unsigned long arg, unsigned short val)
+static int compat_put_long(compat_long_t *argp, long val)
 {
-	return put_user(val, (unsigned short __user *)compat_ptr(arg));
+	return put_user(val, argp);
 }
 
-static int compat_put_int(unsigned long arg, int val)
+static int compat_put_ulong(compat_ulong_t *argp, compat_ulong_t val)
 {
-	return put_user(val, (compat_int_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_uint(unsigned long arg, unsigned int val)
-{
-	return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_long(unsigned long arg, long val)
-{
-	return put_user(val, (compat_long_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
-{
-	return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
-}
-
-static int compat_put_u64(unsigned long arg, u64 val)
-{
-	return put_user(val, (compat_u64 __user *)compat_ptr(arg));
+	return put_user(val, argp);
 }
 #endif
 
@@ -547,9 +527,10 @@ struct compat_hd_geometry {
 	u32 start;
 };
 
-static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
-			struct compat_hd_geometry __user *ugeo)
+static int compat_hdio_getgeo(struct block_device *bdev,
+			      struct compat_hd_geometry __user *ugeo)
 {
+	struct gendisk *disk = bdev->bd_disk;
 	struct hd_geometry geo;
 	int ret;
 
@@ -603,13 +584,13 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
 }
 
 /*
- * always keep this in sync with compat_blkdev_ioctl()
+ * Common commands that are handled the same way on native and compat
+ * user space. Note the separate arg/argp parameters that are needed
+ * to deal with the compat_ptr() conversion.
  */
-int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
-			unsigned long arg)
+static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
+				unsigned cmd, unsigned long arg, void __user *argp)
 {
-	void __user *argp = (void __user *)arg;
-	loff_t size;
 	unsigned int max_sectors;
 
 	switch (cmd) {
@@ -632,60 +613,39 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 	case BLKFINISHZONE:
 		return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
 	case BLKGETZONESZ:
-		return put_uint(arg, bdev_zone_sectors(bdev));
+		return put_uint(argp, bdev_zone_sectors(bdev));
 	case BLKGETNRZONES:
-		return put_uint(arg, blkdev_nr_zones(bdev->bd_disk));
-	case HDIO_GETGEO:
-		return blkdev_getgeo(bdev, argp);
-	case BLKRAGET:
-	case BLKFRAGET:
-		if (!arg)
-			return -EINVAL;
-		return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
+		return put_uint(argp, blkdev_nr_zones(bdev->bd_disk));
 	case BLKROGET:
-		return put_int(arg, bdev_read_only(bdev) != 0);
-	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
-		return put_int(arg, block_size(bdev));
+		return put_int(argp, bdev_read_only(bdev) != 0);
 	case BLKSSZGET: /* get block device logical block size */
-		return put_int(arg, bdev_logical_block_size(bdev));
+		return put_int(argp, bdev_logical_block_size(bdev));
 	case BLKPBSZGET: /* get block device physical block size */
-		return put_uint(arg, bdev_physical_block_size(bdev));
+		return put_uint(argp, bdev_physical_block_size(bdev));
 	case BLKIOMIN:
-		return put_uint(arg, bdev_io_min(bdev));
+		return put_uint(argp, bdev_io_min(bdev));
 	case BLKIOOPT:
-		return put_uint(arg, bdev_io_opt(bdev));
+		return put_uint(argp, bdev_io_opt(bdev));
 	case BLKALIGNOFF:
-		return put_int(arg, bdev_alignment_offset(bdev));
+		return put_int(argp, bdev_alignment_offset(bdev));
 	case BLKDISCARDZEROES:
-		return put_uint(arg, 0);
+		return put_uint(argp, 0);
 	case BLKSECTGET:
 		max_sectors = min_t(unsigned int, USHRT_MAX,
 				    queue_max_sectors(bdev_get_queue(bdev)));
-		return put_ushort(arg, max_sectors);
+		return put_ushort(argp, max_sectors);
 	case BLKROTATIONAL:
-		return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
+		return put_ushort(argp, !blk_queue_nonrot(bdev_get_queue(bdev)));
 	case BLKRASET:
 	case BLKFRASET:
 		if(!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
 		return 0;
-	case BLKBSZSET:
-		return blkdev_bszset(bdev, mode, argp);
-	case BLKPG:
-		return blkpg_ioctl(bdev, argp);
 	case BLKRRPART:
 		return blkdev_reread_part(bdev);
-	case BLKGETSIZE:
-		size = i_size_read(bdev->bd_inode);
-		if ((size >> 9) > ~0UL)
-			return -EFBIG;
-		return put_ulong(arg, size >> 9);
-	case BLKGETSIZE64:
-		return put_u64(arg, i_size_read(bdev->bd_inode));
 	case BLKTRACESTART:
 	case BLKTRACESTOP:
-	case BLKTRACESETUP:
 	case BLKTRACETEARDOWN:
 		return blk_trace_ioctl(bdev, cmd, argp);
 	case IOC_PR_REGISTER:
@@ -701,12 +661,67 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 	case IOC_PR_CLEAR:
 		return blkdev_pr_clear(bdev, argp);
 	default:
-		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+		return -ENOIOCTLCMD;
 	}
 }
-EXPORT_SYMBOL_GPL(blkdev_ioctl);
+
+/*
+ * Always keep this in sync with compat_blkdev_ioctl()
+ * to handle all incompatible commands in both functions.
+ *
+ * New commands must be compatible and go into blkdev_common_ioctl
+ */
+int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
+			unsigned long arg)
+{
+	int ret;
+	loff_t size;
+	void __user *argp = (void __user *)arg;
+
+	switch (cmd) {
+	/* These need separate implementations for the data structure */
+	case HDIO_GETGEO:
+		return blkdev_getgeo(bdev, argp);
+	case BLKPG:
+		return blkpg_ioctl(bdev, argp);
+
+	/* Compat mode returns 32-bit data instead of 'long' */
+	case BLKRAGET:
+	case BLKFRAGET:
+		if (!argp)
+			return -EINVAL;
+		return put_long(argp, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
+	case BLKGETSIZE:
+		size = i_size_read(bdev->bd_inode);
+		if ((size >> 9) > ~0UL)
+			return -EFBIG;
+		return put_ulong(argp, size >> 9);
+
+	/* The data is compatible, but the command number is different */
+	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
+		return put_int(argp, block_size(bdev));
+	case BLKBSZSET:
+		return blkdev_bszset(bdev, mode, argp);
+	case BLKGETSIZE64:
+		return put_u64(argp, i_size_read(bdev->bd_inode));
+
+	/* Incompatible alignment on i386 */
+	case BLKTRACESETUP:
+		return blk_trace_ioctl(bdev, cmd, argp);
+	default:
+		break;
+	}
+
+	ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
+	if (ret == -ENOIOCTLCMD)
+		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(blkdev_ioctl); /* for /dev/raw */
 
 #ifdef CONFIG_COMPAT
+
 #define BLKBSZGET_32		_IOR(0x12, 112, int)
 #define BLKBSZSET_32		_IOW(0x12, 113, int)
 #define BLKGETSIZE64_32		_IOR(0x12, 114, int)
@@ -716,13 +731,13 @@ EXPORT_SYMBOL_GPL(blkdev_ioctl);
    ENOIOCTLCMD for unknown ioctls. */
 long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
-	int ret = -ENOIOCTLCMD;
+	int ret;
+	void __user *argp = compat_ptr(arg);
 	struct inode *inode = file->f_mapping->host;
 	struct block_device *bdev = inode->i_bdev;
 	struct gendisk *disk = bdev->bd_disk;
 	fmode_t mode = file->f_mode;
 	loff_t size;
-	unsigned int max_sectors;
 
 	/*
 	 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
@@ -734,94 +749,44 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 		mode &= ~FMODE_NDELAY;
 
 	switch (cmd) {
+	/* These need separate implementations for the data structure */
 	case HDIO_GETGEO:
-		return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
-	case BLKPBSZGET:
-		return compat_put_uint(arg, bdev_physical_block_size(bdev));
-	case BLKIOMIN:
-		return compat_put_uint(arg, bdev_io_min(bdev));
-	case BLKIOOPT:
-		return compat_put_uint(arg, bdev_io_opt(bdev));
-	case BLKALIGNOFF:
-		return compat_put_int(arg, bdev_alignment_offset(bdev));
-	case BLKDISCARDZEROES:
-		return compat_put_uint(arg, 0);
-	case BLKFLSBUF:
-	case BLKROSET:
-	case BLKDISCARD:
-	case BLKSECDISCARD:
-	case BLKZEROOUT:
-	/*
-	 * the ones below are implemented in blkdev_locked_ioctl,
-	 * but we call blkdev_ioctl, which gets the lock for us
-	 */
-	case BLKRRPART:
-	case BLKREPORTZONE:
-	case BLKRESETZONE:
-	case BLKOPENZONE:
-	case BLKCLOSEZONE:
-	case BLKFINISHZONE:
-	case BLKGETZONESZ:
-	case BLKGETNRZONES:
-		return blkdev_ioctl(bdev, mode, cmd,
-				(unsigned long)compat_ptr(arg));
-	case BLKBSZSET_32:
-		return blkdev_ioctl(bdev, mode, BLKBSZSET,
-				(unsigned long)compat_ptr(arg));
+		return compat_hdio_getgeo(bdev, argp);
 	case BLKPG:
-		return compat_blkpg_ioctl(bdev, compat_ptr(arg));
+		return compat_blkpg_ioctl(bdev, argp);
+
+	/* Compat mode returns 32-bit data instead of 'long' */
 	case BLKRAGET:
 	case BLKFRAGET:
-		if (!arg)
+		if (!argp)
 			return -EINVAL;
-		return compat_put_long(arg,
+		return compat_put_long(argp,
 			       (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
-	case BLKROGET: /* compatible */
-		return compat_put_int(arg, bdev_read_only(bdev) != 0);
-	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
-		return compat_put_int(arg, block_size(bdev));
-	case BLKSSZGET: /* get block device hardware sector size */
-		return compat_put_int(arg, bdev_logical_block_size(bdev));
-	case BLKSECTGET:
-		max_sectors = min_t(unsigned int, USHRT_MAX,
-				    queue_max_sectors(bdev_get_queue(bdev)));
-		return compat_put_ushort(arg, max_sectors);
-	case BLKROTATIONAL:
-		return compat_put_ushort(arg,
-					 !blk_queue_nonrot(bdev_get_queue(bdev)));
-	case BLKRASET: /* compatible, but no compat_ptr (!) */
-	case BLKFRASET:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
-		return 0;
 	case BLKGETSIZE:
 		size = i_size_read(bdev->bd_inode);
 		if ((size >> 9) > ~0UL)
 			return -EFBIG;
-		return compat_put_ulong(arg, size >> 9);
+		return compat_put_ulong(argp, size >> 9);
 
+	/* The data is compatible, but the command number is different */
+	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
+		return put_int(argp, bdev_logical_block_size(bdev));
+	case BLKBSZSET_32:
+		return blkdev_bszset(bdev, mode, argp);
 	case BLKGETSIZE64_32:
-		return compat_put_u64(arg, i_size_read(bdev->bd_inode));
+		return put_u64(argp, i_size_read(bdev->bd_inode));
 
+	/* Incompatible alignment on i386 */
 	case BLKTRACESETUP32:
-	case BLKTRACESTART: /* compatible */
-	case BLKTRACESTOP:  /* compatible */
-	case BLKTRACETEARDOWN: /* compatible */
-		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
-		return ret;
-	case IOC_PR_REGISTER:
-	case IOC_PR_RESERVE:
-	case IOC_PR_RELEASE:
-	case IOC_PR_PREEMPT:
-	case IOC_PR_PREEMPT_ABORT:
-	case IOC_PR_CLEAR:
-		return blkdev_ioctl(bdev, mode, cmd,
-				(unsigned long)compat_ptr(arg));
+		return blk_trace_ioctl(bdev, cmd, argp);
 	default:
-		if (disk->fops->compat_ioctl)
-			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
-		return ret;
+		break;
 	}
+
+	ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
+	if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
+		ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
+
+	return ret;
 }
 #endif
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 24/24] Documentation: document ioctl interfaces better
  2019-12-11 20:42 ` Arnd Bergmann
                   ` (25 preceding siblings ...)
  (?)
@ 2019-12-11 20:42 ` Arnd Bergmann
  2019-12-11 21:05   ` Jonathan Corbet
  2019-12-12  8:16   ` Geert Uytterhoeven
  -1 siblings, 2 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-11 20:42 UTC (permalink / raw)
  To: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jonathan Corbet
  Cc: linux-kernel, y2038, Arnd Bergmann, Mauro Carvalho Chehab,
	Jonathan Neuschäfer, Masahiro Yamada, Vladimir Oltean,
	Kent Overstreet, linux-doc

Documentation/process/botching-up-ioctls.rst was orignally
written as a blog post for DRM driver writers, so it it misses
some points while going into a lot of detail on others.

Try to provide a replacement that addresses typical issues
across a wider range of subsystems, and follows the style of
the core-api documentation better.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 Documentation/core-api/index.rst |   1 +
 Documentation/core-api/ioctl.rst | 250 +++++++++++++++++++++++++++++++
 2 files changed, 251 insertions(+)
 create mode 100644 Documentation/core-api/ioctl.rst

diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
index ab0eae1c153a..3f28b2f668be 100644
--- a/Documentation/core-api/index.rst
+++ b/Documentation/core-api/index.rst
@@ -39,6 +39,7 @@ Core utilities
    ../RCU/index
    gcc-plugins
    symbol-namespaces
+   ioctl
 
 
 Interfaces for kernel debugging
diff --git a/Documentation/core-api/ioctl.rst b/Documentation/core-api/ioctl.rst
new file mode 100644
index 000000000000..cb2c86ae63e7
--- /dev/null
+++ b/Documentation/core-api/ioctl.rst
@@ -0,0 +1,250 @@
+======================
+ioctl based interfaces
+======================
+
+:c:func:`ioctl` is the most common way for applications to interface
+with device drivers. It is flexible and easily extended by adding new
+commands and can be passed through character devices, block devices as
+well as sockets and other special file descriptors.
+
+However, it is also very easy to get ioctl command definitions wrong,
+and hard to fix them later without breaking existing applications,
+so this documentation tries to help developers get it right.
+
+Command number definitions
+==========================
+
+The command number, or request number, is the second argument passed to
+the ioctl system call. While this can be any 32-bit number that uniquely
+identifies an action for a particular driver, there are a number of
+conventions around defining them.
+
+``include/uapi/asm-generic/ioctl.h`` provides four macros for defining
+ioctl commands that follow modern conventions: ``_IOC``, ``_IOR``,
+``_IOW``, and ``_IORW``. These should be used for all new commands,
+with the correct parameters:
+
+_IO/_IOR/_IOW/_IOWR
+   The macro name determines whether the argument is used for passing
+   data into kernel (_IOW), from the kernel (_IOR), both (_IOWR) or is
+   not a pointer (_IOC). It is possible but not recommended to pass an
+   integer value instead of a pointer with _IOC.
+
+type
+   An 8-bit number, often a character literal, specific to a subsystem
+   or driver, and listed in :doc:`../ioctl/ioctl-number`
+
+nr
+  An 8-bit number identifying the specific command, unique for a give
+  value of 'type'
+
+size
+  The name of the data type pointed to by the argument, the command
+  number encodes the ``sizeof(size)`` value in a 13-bit or 14-bit integer,
+  leading to a limit of 8191 bytes for the maximum size of the argument.
+  Note: do not pass sizeof(type) type into _IOR/IOW, as that will lead
+  to encoding sizeof(sizeof(type)), i.e. sizeof(size_t).
+
+
+Interface versions
+==================
+
+Some subsystems use version numbers in data structures to overload
+commands with different interpretations of the argument.
+
+This is generally a bad idea, since changes to existing commands tend
+to break existing applications.
+
+A better approach is to add a new ioctl command with a new number. The
+old command still needs to be implemented in the kernel for compatibility,
+but this can be a wrapper around the new implementation.
+
+Return code
+===========
+
+ioctl commands can return negative error codes as documented in errno(3),
+these get turned into errno values in user space. On success, the return
+code should be zero. It is also possible but not recommended to return
+a positive 'long' value.
+
+When the ioctl callback is called with an unknown command number, the
+handler returns either -ENOTTY or -ENOIOCTLCMD, which also results in
+-ENOTTY being returned from the system call. Some subsystems return
+-ENOSYS or -EINVAL here for historic reasons, but this is wrong.
+
+Prior to Linux-5.5, compat_ioctl handlers were required to return
+-ENOIOCTLCMD in order to use the fallback conversion into native
+commands. As all subsystems are now responsible for handling compat
+mode themselves, this is no longer needed, but it may be important to
+consider when backporting bug fixes to older kernels.
+
+Timestamps
+==========
+
+Traditionally, timestamps and timeout values are passed as ``struct
+timespec`` or ``struct timeval``, but these are problematic because of
+incompatible definitions of these structures in user space after the
+move to 64-bit time_t.
+
+The __kernel_timespec type can be used instead to be embedded in other
+data structures when separate second/nanosecond values are desired,
+or passed to user space directly. This is still not ideal though,
+as the structure matches neither the kernel's timespec64 nor the user
+space timespec exactly. The get_timespec64() and put_timespec64() helper
+functions canbe used to ensure that the layout remains compatible with
+user space and the padding is treated correctly.
+
+As it is cheap to convert seconds to nanoseconds, but the opposite
+requires an expensive 64-bit division, a simple __u64 nanosecond value
+can be simpler and more efficient.
+
+Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
+as returned by ``ktime_get_ns()`` or ``ktime_get_ts64()``.  Unlike
+CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
+or forwards due to leap second adjustments and clock_settime() calls.
+
+``ktime_get_real_ns()`` can be used for CLOCK_REALTIME timestamps that
+may be required for timestamps that need to be persistent across a reboot
+or between multiple machines.
+
+32-bit compat mode
+==================
+
+In order to support 32-bit user space running on a 64-bit machine, each
+subsystem or driver that implements an ioctl callback handler must also
+implement the corresponding compat_ioctl handler.
+
+As long as all the rules for data structures are followed, this is as
+easy as setting the .compat_ioctl pointer to a helper function such as
+``compat_ptr_ioctl()`` or ``blkdev_compat_ptr_ioctl``.
+
+compat_ptr()
+------------
+
+On the s/390 architecture, 31-bit user space has ambiguous representations
+for data pointers, with the upper bit being ignored. When running such
+a process in compat mode, the ``compat_ptr()`` helper must be used to
+clear the upper bit of a compat_uptr_t and turn it into a valid 64-bit
+pointer.  On other architectures, this macro only performs a cast to a
+``void __user *`` pointer.
+
+In an compat_ioctl() callback, the last argument is an unsigned long,
+which can be interpreted as either a pointer or a scalar depending on
+the command. If it is a scalar, then compat_ptr() must not be used, to
+ensure that the 64-bit kernel behaves the same way as a 32-bit kernel
+for arguments with the upper bit set.
+
+The compat_ptr_ioctl() helper can be used in place of a custom
+compat_ioctl file operation for drivers that only take arguments that
+are pointers to compatible data structures.
+
+Structure layout
+----------------
+
+Compatible data structures have the same layout on all architectures,
+avoiding all problematic members:
+
+* ``long`` and ``unsigned long`` are the size of a register, so
+  they can be either 32 bit or 64 bit wide and cannot be used in portable
+  data structures. Fixed-length replacements are ``__s32``, ``__u32``,
+  ``__s64`` and ``__u64``.
+
+* Pointers have the same problem, in addition to requiring the
+  use of ``compat_ptr()``. The best workaround is to use ``__u64``
+  in place of pointers, which requires a cast to ``uintptr_t`` in user
+  space, and the use of ``u64_to_user_ptr()`` in the kernel to convert
+  it back into a user pointer.
+
+* On the x86-32 (i386) architecture, the alignment of 64-bit variables
+  is only 32 bit, but they are naturally aligned on most other
+  architectures including x86-64. This means a structure like
+
+  ::
+
+    struct foo {
+        __u32 a;
+        __u64 b;
+        __u32 c;
+    };
+
+  has four bytes of padding between a and b on x86-64, plus another four
+  bytes of padding at the end, but no padding on i386, and it needs a
+  compat_ioctl conversion handler to translate between the two formats.
+
+  To avoid this problem, all structures should have their members
+  naturally aligned, or explicit reserved fields added in place of the
+  implicit padding.
+
+* On ARM OABI user space, 16-bit member variables have 32-bit
+  alignment, making them incompatible with modern EABI kernels.
+  Conversely, on the m68k architecture, all struct members have at most
+  16-bit alignment. These rarely cause problems as neither ARM-OABI nor
+  m68k are supported by any compat mode, but for consistency, it is best
+  to completely avoid 16-bit member variables.
+
+
+* Bitfields and enums generally work as one would expect them to,
+  but some properties of them are implementation-defined, so it is better
+  to avoid them completely in ioctl interfaces.
+
+* ``char`` members can be either signed or unsigned, depending on
+  the architecture, so the __u8 and __s8 types should be used for 8-bit
+  integer values, though char arrays are clearer for fixed-length strings.
+
+Information leaks
+=================
+
+Uninitialized data must not be copied back to user space, as this can
+cause an information leak, which can be used to defeat kernel address
+space layout randomization (KASLR), helping in an attack.
+
+As explained for the compat mode, it is best to not avoid any padding in
+data structures, but if there is already padding in existing structures,
+the kernel driver must be careful to zero out the padding using
+``memset()`` or similar before copying it to user space.
+
+Subsystem abstractions
+======================
+
+While some device drivers implement their own ioctl function, most
+subsystems implement the same command for multiple drivers.  Ideally the
+subsystem has an .ioctl() handler that copies the arguments from and
+to user space, passing them into subsystem specific callback functions
+through normal kernel pointers.
+
+This helps in various ways:
+
+* Applications written for one driver are more likely to work for
+  another one in the same subsystem if there are no subtle differences
+  in the user space ABI.
+
+* The complexity of user space access and data structure layout at done
+  in one place, reducing the potential for implementation bugs.
+
+* It is more likely to be reviewed by experienced developers
+  that can spot problems in the interface when the ioctl is shared
+  between multiple drivers than when it is only used in a single driver.
+
+Alternatives to ioctl
+=====================
+
+There are many cases in which ioctl is not the best solution for a
+problem. Alternatives include
+
+* System calls are a better choice for a system-wide feature that
+  is not tied to a physical device or constrained by the file system
+  permissions of a character device node
+
+* netlink is the preferred way of configuring any network related
+  objects through sockets.
+
+* debugfs is used for ad-hoc interfaces for debugging functionality
+  that does not need to be exposed as a stable interface to applications.
+
+* sysfs is a good way to expose the state of an in-kernel object
+  that is not tied to a file descriptor.
+
+* configfs can be used for more complex configuration than sysfs
+
+* A custom file system can provide extra flexibility with a simple
+  user interface but add a lot of complexity in the implementation.
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* Re: [PATCH 24/24] Documentation: document ioctl interfaces better
  2019-12-11 20:42 ` [PATCH 24/24] Documentation: document ioctl interfaces better Arnd Bergmann
@ 2019-12-11 21:05   ` Jonathan Corbet
  2019-12-12 10:56     ` Arnd Bergmann
  2019-12-12  8:16   ` Geert Uytterhoeven
  1 sibling, 1 reply; 64+ messages in thread
From: Jonathan Corbet @ 2019-12-11 21:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-kernel, y2038, Mauro Carvalho Chehab,
	Jonathan Neuschäfer, Masahiro Yamada, Vladimir Oltean,
	Kent Overstreet, linux-doc

On Wed, 11 Dec 2019 21:42:58 +0100
Arnd Bergmann <arnd@arndb.de> wrote:

> Documentation/process/botching-up-ioctls.rst was orignally
> written as a blog post for DRM driver writers, so it it misses
> some points while going into a lot of detail on others.
> 
> Try to provide a replacement that addresses typical issues
> across a wider range of subsystems, and follows the style of
> the core-api documentation better.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Thanks for improving the docs!  I have a few nits outside of the content
itself.

>  Documentation/core-api/index.rst |   1 +
>  Documentation/core-api/ioctl.rst | 250 +++++++++++++++++++++++++++++++
>  2 files changed, 251 insertions(+)
>  create mode 100644 Documentation/core-api/ioctl.rst

So you left the old document in place; was that intentional?

> diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
> index ab0eae1c153a..3f28b2f668be 100644
> --- a/Documentation/core-api/index.rst
> +++ b/Documentation/core-api/index.rst
> @@ -39,6 +39,7 @@ Core utilities
>     ../RCU/index
>     gcc-plugins
>     symbol-namespaces
> +   ioctl
>  
>  
>  Interfaces for kernel debugging
> diff --git a/Documentation/core-api/ioctl.rst b/Documentation/core-api/ioctl.rst
> new file mode 100644
> index 000000000000..cb2c86ae63e7
> --- /dev/null
> +++ b/Documentation/core-api/ioctl.rst
> @@ -0,0 +1,250 @@
> +======================
> +ioctl based interfaces
> +======================
> +
> +:c:func:`ioctl` is the most common way for applications to interface

Please don't use :c:func: anymore.  If you just say "ioctl()" the right
thing will happen (which is nothing here, since there isn't anything that
makes sense to link to in the internal kernel context).

We need a checkpatch rule for :c:func: I guess.

Similarly, later on you have:

> +Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
> +as returned by ``ktime_get_ns()`` or ``ktime_get_ts64()``.  Unlike
> +CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
> +or forwards due to leap second adjustments and clock_settime() calls.

Making those functions ``literal`` will defeat the automatic
cross-referencing.  Better to just say ktime_get_ns() without quotes.

[...]

> +* On the x86-32 (i386) architecture, the alignment of 64-bit variables
> +  is only 32 bit, but they are naturally aligned on most other
> +  architectures including x86-64. This means a structure like
> +
> +  ::

You don't need the extra lines here; just say "...a structure like::"

> +    struct foo {
> +        __u32 a;
> +        __u64 b;
> +        __u32 c;
> +    };
> +

Thanks,

jon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 20:42 ` [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers Arnd Bergmann
@ 2019-12-11 23:05   ` Michael S. Tsirkin
  2019-12-12  0:28     ` Paolo Bonzini
  2019-12-12  0:28     ` Paolo Bonzini
  2019-12-11 23:05   ` Michael S. Tsirkin
  2019-12-12 10:25     ` Michael S. Tsirkin
  2 siblings, 2 replies; 64+ messages in thread
From: Michael S. Tsirkin @ 2019-12-11 23:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jason Wang, Doug Gilbert, Kai Mäkisara,
	linux-kernel, y2038, Paolo Bonzini, Stefan Hajnoczi,
	Bart Van Assche, Hannes Reinecke, Damien Le Moal, John Garry,
	virtualization, linux-block, linux-scsi, linux-fsdevel

On Wed, Dec 11, 2019 at 09:42:49PM +0100, Arnd Bergmann wrote:
> Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
> handler that implements the same commands by calling scsi_compat_ioctl().
> 
> The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
> at this point, so any driver that calls those can do so for both native
> and compat mode, with the argument passed through compat_ptr().
> 
> With this, we can remove the entries from fs/compat_ioctl.c.  The new
> code is larger, but should be easier to maintain and keep updated with
> newly added commands.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/block/virtio_blk.c |   3 +
>  drivers/scsi/ch.c          |   9 ++-
>  drivers/scsi/sd.c          |  50 ++++++--------
>  drivers/scsi/sg.c          |  44 ++++++++-----
>  drivers/scsi/sr.c          |  57 ++++++++++++++--
>  drivers/scsi/st.c          |  51 ++++++++------
>  fs/compat_ioctl.c          | 132 +------------------------------------
>  7 files changed, 142 insertions(+), 204 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 7ffd719d89de..fbbf18ac1d5d 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
>  
>  static const struct block_device_operations virtblk_fops = {
>  	.ioctl  = virtblk_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
> +#endif
>  	.owner  = THIS_MODULE,
>  	.getgeo = virtblk_getgeo,
>  };

Hmm - is virtio blk lumped in with scsi things intentionally?

-- 
MST


^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 20:42 ` [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers Arnd Bergmann
  2019-12-11 23:05   ` Michael S. Tsirkin
@ 2019-12-11 23:05   ` Michael S. Tsirkin
  2019-12-12 10:25     ` Michael S. Tsirkin
  2 siblings, 0 replies; 64+ messages in thread
From: Michael S. Tsirkin @ 2019-12-11 23:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, Hannes Reinecke, Bart Van Assche, Martin K. Petersen,
	y2038, Damien Le Moal, James E.J. Bottomley, John Garry,
	linux-kernel, Kai Mäkisara, linux-block, Alexander Viro,
	Stefan Hajnoczi, Doug Gilbert, linux-fsdevel, Paolo Bonzini,
	virtualization, linux-scsi

On Wed, Dec 11, 2019 at 09:42:49PM +0100, Arnd Bergmann wrote:
> Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
> handler that implements the same commands by calling scsi_compat_ioctl().
> 
> The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
> at this point, so any driver that calls those can do so for both native
> and compat mode, with the argument passed through compat_ptr().
> 
> With this, we can remove the entries from fs/compat_ioctl.c.  The new
> code is larger, but should be easier to maintain and keep updated with
> newly added commands.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/block/virtio_blk.c |   3 +
>  drivers/scsi/ch.c          |   9 ++-
>  drivers/scsi/sd.c          |  50 ++++++--------
>  drivers/scsi/sg.c          |  44 ++++++++-----
>  drivers/scsi/sr.c          |  57 ++++++++++++++--
>  drivers/scsi/st.c          |  51 ++++++++------
>  fs/compat_ioctl.c          | 132 +------------------------------------
>  7 files changed, 142 insertions(+), 204 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 7ffd719d89de..fbbf18ac1d5d 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
>  
>  static const struct block_device_operations virtblk_fops = {
>  	.ioctl  = virtblk_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
> +#endif
>  	.owner  = THIS_MODULE,
>  	.getgeo = virtblk_getgeo,
>  };

Hmm - is virtio blk lumped in with scsi things intentionally?

-- 
MST

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 23:05   ` Michael S. Tsirkin
  2019-12-12  0:28     ` Paolo Bonzini
@ 2019-12-12  0:28     ` Paolo Bonzini
  2019-12-12  9:17       ` Arnd Bergmann
                         ` (5 more replies)
  1 sibling, 6 replies; 64+ messages in thread
From: Paolo Bonzini @ 2019-12-12  0:28 UTC (permalink / raw)
  To: Michael S. Tsirkin, Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jason Wang, Doug Gilbert, Kai Mäkisara,
	linux-kernel, y2038, Stefan Hajnoczi, Bart Van Assche,
	Hannes Reinecke, Damien Le Moal, John Garry, virtualization,
	linux-block, linux-scsi, linux-fsdevel

On 12/12/19 00:05, Michael S. Tsirkin wrote:
>> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
>>  
>>  static const struct block_device_operations virtblk_fops = {
>>  	.ioctl  = virtblk_ioctl,
>> +#ifdef CONFIG_COMPAT
>> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
>> +#endif
>>  	.owner  = THIS_MODULE,
>>  	.getgeo = virtblk_getgeo,
>>  };
> Hmm - is virtio blk lumped in with scsi things intentionally?

I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
sense to lump it in with scsi, but I wouldn't mind getting rid of
CONFIG_VIRTIO_BLK_SCSI altogether.

Paolo


^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 23:05   ` Michael S. Tsirkin
@ 2019-12-12  0:28     ` Paolo Bonzini
  2019-12-12  0:28     ` Paolo Bonzini
  1 sibling, 0 replies; 64+ messages in thread
From: Paolo Bonzini @ 2019-12-12  0:28 UTC (permalink / raw)
  To: Michael S. Tsirkin, Arnd Bergmann
  Cc: Jens Axboe, Hannes Reinecke, Bart Van Assche, Martin K. Petersen,
	y2038, Damien Le Moal, James E.J. Bottomley, John Garry,
	linux-kernel, Kai Mäkisara, linux-block, Alexander Viro,
	Stefan Hajnoczi, Doug Gilbert, linux-fsdevel, virtualization,
	linux-scsi

On 12/12/19 00:05, Michael S. Tsirkin wrote:
>> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
>>  
>>  static const struct block_device_operations virtblk_fops = {
>>  	.ioctl  = virtblk_ioctl,
>> +#ifdef CONFIG_COMPAT
>> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
>> +#endif
>>  	.owner  = THIS_MODULE,
>>  	.getgeo = virtblk_getgeo,
>>  };
> Hmm - is virtio blk lumped in with scsi things intentionally?

I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
sense to lump it in with scsi, but I wouldn't mind getting rid of
CONFIG_VIRTIO_BLK_SCSI altogether.

Paolo

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/24] compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE
  2019-12-11 20:42 ` [PATCH 03/24] compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE Arnd Bergmann
@ 2019-12-12  1:20   ` Damien Le Moal
  0 siblings, 0 replies; 64+ messages in thread
From: Damien Le Moal @ 2019-12-12  1:20 UTC (permalink / raw)
  To: Arnd Bergmann, Jens Axboe, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, Jens Axboe, Hannes Reinecke,
	Shaun Tancheff
  Cc: linux-kernel, y2038, stable, Shaun Tancheff, Christoph Hellwig,
	linux-block

On 2019/12/12 5:44, Arnd Bergmann wrote:
> These were added to blkdev_ioctl() but not blkdev_compat_ioctl,
> so add them now.
> 
> Cc: <stable@vger.kernel.org> # v4.10+
> Fixes: 3ed05a987e0f ("blk-zoned: implement ioctls")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  block/compat_ioctl.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
> index 6ca015f92766..830f91e05fe3 100644
> --- a/block/compat_ioctl.c
> +++ b/block/compat_ioctl.c
> @@ -354,6 +354,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
>  	 * but we call blkdev_ioctl, which gets the lock for us
>  	 */
>  	case BLKRRPART:
> +	case BLKREPORTZONE:
> +	case BLKRESETZONE:
>  		return blkdev_ioctl(bdev, mode, cmd,
>  				(unsigned long)compat_ptr(arg));
>  	case BLKBSZSET_32:
> 

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>

-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 04/24] compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES
  2019-12-11 20:42 ` [PATCH 04/24] compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES Arnd Bergmann
@ 2019-12-12  1:20   ` Damien Le Moal
  0 siblings, 0 replies; 64+ messages in thread
From: Damien Le Moal @ 2019-12-12  1:20 UTC (permalink / raw)
  To: Arnd Bergmann, Jens Axboe, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, Hannes Reinecke
  Cc: linux-kernel, y2038, stable, Christoph Hellwig, linux-block

On 2019/12/12 5:44, Arnd Bergmann wrote:
> These were added to blkdev_ioctl() in v4.20 but not blkdev_compat_ioctl,
> so add them now.
> 
> Cc: <stable@vger.kernel.org> # v4.20+
> Fixes: 72cd87576d1d ("block: Introduce BLKGETZONESZ ioctl")
> Fixes: 65e4e3eee83d ("block: Introduce BLKGETNRZONES ioctl")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  block/compat_ioctl.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
> index 830f91e05fe3..f5c1140b8624 100644
> --- a/block/compat_ioctl.c
> +++ b/block/compat_ioctl.c
> @@ -356,6 +356,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
>  	case BLKRRPART:
>  	case BLKREPORTZONE:
>  	case BLKRESETZONE:
> +	case BLKGETZONESZ:
> +	case BLKGETNRZONES:
>  		return blkdev_ioctl(bdev, mode, cmd,
>  				(unsigned long)compat_ptr(arg));
>  	case BLKBSZSET_32:
> 

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>

-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 05/24] compat_ioctl: block: handle add zone open, close and finish ioctl
  2019-12-11 20:42 ` [PATCH 05/24] compat_ioctl: block: handle add zone open, close and finish ioctl Arnd Bergmann
@ 2019-12-12  1:20   ` Damien Le Moal
  0 siblings, 0 replies; 64+ messages in thread
From: Damien Le Moal @ 2019-12-12  1:20 UTC (permalink / raw)
  To: Arnd Bergmann, Jens Axboe, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, Javier González,
	Keith Busch, Hans Holmberg, Matias Bjorling
  Cc: linux-kernel, y2038, Christoph Hellwig, Ajay Joshi,
	Dmitry Fomichev, linux-block

On 2019/12/12 5:45, Arnd Bergmann wrote:
> These were added to blkdev_ioctl() in linux-5.5 but not
> blkdev_compat_ioctl, so add them now.
> 
> Fixes: e876df1fe0ad ("block: add zone open, close and finish ioctl support")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  block/compat_ioctl.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
> index f5c1140b8624..5b13e344229c 100644
> --- a/block/compat_ioctl.c
> +++ b/block/compat_ioctl.c
> @@ -356,6 +356,9 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
>  	case BLKRRPART:
>  	case BLKREPORTZONE:
>  	case BLKRESETZONE:
> +	case BLKOPENZONE:
> +	case BLKCLOSEZONE:
> +	case BLKFINISHZONE:
>  	case BLKGETZONESZ:
>  	case BLKGETNRZONES:
>  		return blkdev_ioctl(bdev, mode, cmd,
> 

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>

-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 24/24] Documentation: document ioctl interfaces better
  2019-12-11 20:42 ` [PATCH 24/24] Documentation: document ioctl interfaces better Arnd Bergmann
  2019-12-11 21:05   ` Jonathan Corbet
@ 2019-12-12  8:16   ` Geert Uytterhoeven
  2019-12-12 11:04     ` Arnd Bergmann
  1 sibling, 1 reply; 64+ messages in thread
From: Geert Uytterhoeven @ 2019-12-12  8:16 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jonathan Corbet, Linux Kernel Mailing List,
	y2038 Mailman List, Mauro Carvalho Chehab,
	Jonathan Neuschäfer, Masahiro Yamada, Vladimir Oltean,
	Kent Overstreet, open list:DOCUMENTATION

Hi Arnd,

On Wed, Dec 11, 2019 at 9:53 PM Arnd Bergmann <arnd@arndb.de> wrote:
> Documentation/process/botching-up-ioctls.rst was orignally
> written as a blog post for DRM driver writers, so it it misses
> some points while going into a lot of detail on others.
>
> Try to provide a replacement that addresses typical issues
> across a wider range of subsystems, and follows the style of
> the core-api documentation better.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Thanks for your patch!

> --- /dev/null
> +++ b/Documentation/core-api/ioctl.rst
> @@ -0,0 +1,250 @@
> +======================
> +ioctl based interfaces
> +======================
> +
> +:c:func:`ioctl` is the most common way for applications to interface
> +with device drivers. It is flexible and easily extended by adding new
> +commands and can be passed through character devices, block devices as
> +well as sockets and other special file descriptors.
> +
> +However, it is also very easy to get ioctl command definitions wrong,
> +and hard to fix them later without breaking existing applications,
> +so this documentation tries to help developers get it right.
> +
> +Command number definitions
> +==========================
> +
> +The command number, or request number, is the second argument passed to
> +the ioctl system call. While this can be any 32-bit number that uniquely
> +identifies an action for a particular driver, there are a number of
> +conventions around defining them.

Interesting. I never realized the action is 32-bit in the kernel, but
unsigned long in userspace...

> +
> +``include/uapi/asm-generic/ioctl.h`` provides four macros for defining
> +ioctl commands that follow modern conventions: ``_IOC``, ``_IOR``,
> +``_IOW``, and ``_IORW``. These should be used for all new commands,
> +with the correct parameters:
> +
> +_IO/_IOR/_IOW/_IOWR

This says _IO....

> +   The macro name determines whether the argument is used for passing
> +   data into kernel (_IOW), from the kernel (_IOR), both (_IOWR) or is

into the kernel
, or is

> +   not a pointer (_IOC). It is possible but not recommended to pass an
> +   integer value instead of a pointer with _IOC.

...which is not explained here, but _IOC is?

> +
> +type
> +   An 8-bit number, often a character literal, specific to a subsystem
> +   or driver, and listed in :doc:`../ioctl/ioctl-number`
> +
> +nr
> +  An 8-bit number identifying the specific command, unique for a give
> +  value of 'type'
> +
> +size
> +  The name of the data type pointed to by the argument, the command
> +  number encodes the ``sizeof(size)`` value in a 13-bit or 14-bit integer,
> +  leading to a limit of 8191 bytes for the maximum size of the argument.
> +  Note: do not pass sizeof(type) type into _IOR/IOW, as that will lead
> +  to encoding sizeof(sizeof(type)), i.e. sizeof(size_t).

Looks like "size" could be renamed, to make this more obvious?

> +Timestamps
> +==========
> +
> +Traditionally, timestamps and timeout values are passed as ``struct
> +timespec`` or ``struct timeval``, but these are problematic because of
> +incompatible definitions of these structures in user space after the
> +move to 64-bit time_t.
> +
> +The __kernel_timespec type can be used instead to be embedded in other
> +data structures when separate second/nanosecond values are desired,
> +or passed to user space directly. This is still not ideal though,
> +as the structure matches neither the kernel's timespec64 nor the user
> +space timespec exactly. The get_timespec64() and put_timespec64() helper
> +functions canbe used to ensure that the layout remains compatible with

can be

> +user space and the padding is treated correctly.
> +
> +As it is cheap to convert seconds to nanoseconds, but the opposite
> +requires an expensive 64-bit division, a simple __u64 nanosecond value
> +can be simpler and more efficient.
> +
> +Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
> +as returned by ``ktime_get_ns()`` or ``ktime_get_ts64()``.  Unlike
> +CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
> +or forwards due to leap second adjustments and clock_settime() calls.
> +
> +``ktime_get_real_ns()`` can be used for CLOCK_REALTIME timestamps that
> +may be required for timestamps that need to be persistent across a reboot

Drop "may be required for timestamps that"?

> +or between multiple machines.

> +Structure layout
> +----------------
> +
> +Compatible data structures have the same layout on all architectures,
> +avoiding all problematic members:
> +
> +* ``long`` and ``unsigned long`` are the size of a register, so
> +  they can be either 32 bit or 64 bit wide and cannot be used in portable

32-bit or 64-bit (for consistency with the rest of the document)

> +  data structures. Fixed-length replacements are ``__s32``, ``__u32``,
> +  ``__s64`` and ``__u64``.
> +
> +* Pointers have the same problem, in addition to requiring the
> +  use of ``compat_ptr()``. The best workaround is to use ``__u64``
> +  in place of pointers, which requires a cast to ``uintptr_t`` in user
> +  space, and the use of ``u64_to_user_ptr()`` in the kernel to convert
> +  it back into a user pointer.
> +
> +* On the x86-32 (i386) architecture, the alignment of 64-bit variables
> +  is only 32 bit, but they are naturally aligned on most other

32-bit

> +  architectures including x86-64. This means a structure like
> +
> +  ::
> +
> +    struct foo {
> +        __u32 a;
> +        __u64 b;
> +        __u32 c;
> +    };
> +
> +  has four bytes of padding between a and b on x86-64, plus another four
> +  bytes of padding at the end, but no padding on i386, and it needs a
> +  compat_ioctl conversion handler to translate between the two formats.
> +
> +  To avoid this problem, all structures should have their members
> +  naturally aligned, or explicit reserved fields added in place of the
> +  implicit padding.
> +
> +* On ARM OABI user space, 16-bit member variables have 32-bit
> +  alignment, making them incompatible with modern EABI kernels.
> +  Conversely, on the m68k architecture, all struct members have at most
> +  16-bit alignment. These rarely cause problems as neither ARM-OABI nor

"have at most 16-bit alignment" sounds a bit weird to me, as a member
may have a greater alignment.
"struct members are not guaranteed to have an alignment greater than 16-bit"?

> +  m68k are supported by any compat mode, but for consistency, it is best
> +  to completely avoid 16-bit member variables.
> +
> +
> +* Bitfields and enums generally work as one would expect them to,
> +  but some properties of them are implementation-defined, so it is better
> +  to avoid them completely in ioctl interfaces.
> +
> +* ``char`` members can be either signed or unsigned, depending on
> +  the architecture, so the __u8 and __s8 types should be used for 8-bit
> +  integer values, though char arrays are clearer for fixed-length strings.
> +
> +Information leaks
> +=================
> +
> +Uninitialized data must not be copied back to user space, as this can
> +cause an information leak, which can be used to defeat kernel address
> +space layout randomization (KASLR), helping in an attack.
> +
> +As explained for the compat mode, it is best to not avoid any padding in

best to avoid any implicit padding?

> +data structures, but if there is already padding in existing structures,
> +the kernel driver must be careful to zero out the padding using
> +``memset()`` or similar before copying it to user space.
> +
> +Subsystem abstractions
> +======================
> +
> +While some device drivers implement their own ioctl function, most
> +subsystems implement the same command for multiple drivers.  Ideally the
> +subsystem has an .ioctl() handler that copies the arguments from and
> +to user space, passing them into subsystem specific callback functions
> +through normal kernel pointers.
> +
> +This helps in various ways:
> +
> +* Applications written for one driver are more likely to work for
> +  another one in the same subsystem if there are no subtle differences
> +  in the user space ABI.
> +
> +* The complexity of user space access and data structure layout at done

is done

> +  in one place, reducing the potential for implementation bugs.
> +
> +* It is more likely to be reviewed by experienced developers
> +  that can spot problems in the interface when the ioctl is shared
> +  between multiple drivers than when it is only used in a single driver.
> +
> +Alternatives to ioctl
> +=====================
> +
> +There are many cases in which ioctl is not the best solution for a
> +problem. Alternatives include

:

> +
> +* System calls are a better choice for a system-wide feature that
> +  is not tied to a physical device or constrained by the file system
> +  permissions of a character device node
> +
> +* netlink is the preferred way of configuring any network related
> +  objects through sockets.
> +
> +* debugfs is used for ad-hoc interfaces for debugging functionality
> +  that does not need to be exposed as a stable interface to applications.
> +
> +* sysfs is a good way to expose the state of an in-kernel object
> +  that is not tied to a file descriptor.
> +
> +* configfs can be used for more complex configuration than sysfs
> +
> +* A custom file system can provide extra flexibility with a simple
> +  user interface but add a lot of complexity in the implementation.

adds ... to

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12  0:28     ` Paolo Bonzini
  2019-12-12  9:17       ` Arnd Bergmann
@ 2019-12-12  9:17       ` Arnd Bergmann
  2019-12-12 10:27       ` Michael S. Tsirkin
                         ` (3 subsequent siblings)
  5 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12  9:17 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Michael S. Tsirkin, Jens Axboe, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, Jason Wang, Doug Gilbert,
	Kai Mäkisara, linux-kernel, y2038 Mailman List,
	Stefan Hajnoczi, Bart Van Assche, Hannes Reinecke,
	Damien Le Moal, John Garry, virtualization, linux-block,
	linux-scsi, Linux FS-devel Mailing List

On Thu, Dec 12, 2019 at 1:28 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 12/12/19 00:05, Michael S. Tsirkin wrote:
> >> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
> >>
> >>  static const struct block_device_operations virtblk_fops = {
> >>      .ioctl  = virtblk_ioctl,
> >> +#ifdef CONFIG_COMPAT
> >> +    .compat_ioctl = blkdev_compat_ptr_ioctl,
> >> +#endif
> >>      .owner  = THIS_MODULE,
> >>      .getgeo = virtblk_getgeo,
> >>  };
> > Hmm - is virtio blk lumped in with scsi things intentionally?
>
> I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
> sense to lump it in with scsi, but I wouldn't mind getting rid of
> CONFIG_VIRTIO_BLK_SCSI altogether.

It currently calls scsi_cmd_blk_ioctl(), which implements a bunch of ioctl
commands, including some that are unrelated to SG_IO:

                case SG_GET_VERSION_NUM:
                case SCSI_IOCTL_GET_IDLUN:
                case SCSI_IOCTL_GET_BUS_NUMBER:
                case SG_SET_TIMEOUT:
                case SG_GET_TIMEOUT:
                case SG_GET_RESERVED_SIZE:
                case SG_SET_RESERVED_SIZE:
                case SG_EMULATED_HOST:
                case SG_IO: {
                case CDROM_SEND_PACKET:
                case SCSI_IOCTL_SEND_COMMAND:
                case CDROMCLOSETRAY:
                case CDROMEJECT:

My patch changes all callers of this function, and the idea is
to preserve the existing behavior through my series, so I think
it makes sense to keep my patch as is.

I would assume that calling scsi_cmd_blk_ioctl() is harmless
here, but if you want to remove it or limit the set of supported
commands, that should be independent of my change.

       Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12  0:28     ` Paolo Bonzini
@ 2019-12-12  9:17       ` Arnd Bergmann
  2019-12-12  9:17       ` Arnd Bergmann
                         ` (4 subsequent siblings)
  5 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12  9:17 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Jens Axboe, Hannes Reinecke, Bart Van Assche, Martin K. Petersen,
	Michael S. Tsirkin, y2038 Mailman List, Damien Le Moal,
	James E.J. Bottomley, John Garry, linux-kernel,
	Kai Mäkisara, linux-block, Alexander Viro, Stefan Hajnoczi,
	Doug Gilbert, Linux FS-devel Mailing List, virtualization,
	linux-scsi

On Thu, Dec 12, 2019 at 1:28 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 12/12/19 00:05, Michael S. Tsirkin wrote:
> >> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
> >>
> >>  static const struct block_device_operations virtblk_fops = {
> >>      .ioctl  = virtblk_ioctl,
> >> +#ifdef CONFIG_COMPAT
> >> +    .compat_ioctl = blkdev_compat_ptr_ioctl,
> >> +#endif
> >>      .owner  = THIS_MODULE,
> >>      .getgeo = virtblk_getgeo,
> >>  };
> > Hmm - is virtio blk lumped in with scsi things intentionally?
>
> I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
> sense to lump it in with scsi, but I wouldn't mind getting rid of
> CONFIG_VIRTIO_BLK_SCSI altogether.

It currently calls scsi_cmd_blk_ioctl(), which implements a bunch of ioctl
commands, including some that are unrelated to SG_IO:

                case SG_GET_VERSION_NUM:
                case SCSI_IOCTL_GET_IDLUN:
                case SCSI_IOCTL_GET_BUS_NUMBER:
                case SG_SET_TIMEOUT:
                case SG_GET_TIMEOUT:
                case SG_GET_RESERVED_SIZE:
                case SG_SET_RESERVED_SIZE:
                case SG_EMULATED_HOST:
                case SG_IO: {
                case CDROM_SEND_PACKET:
                case SCSI_IOCTL_SEND_COMMAND:
                case CDROMCLOSETRAY:
                case CDROMEJECT:

My patch changes all callers of this function, and the idea is
to preserve the existing behavior through my series, so I think
it makes sense to keep my patch as is.

I would assume that calling scsi_cmd_blk_ioctl() is harmless
here, but if you want to remove it or limit the set of supported
commands, that should be independent of my change.

       Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h
  2019-12-11 20:42   ` Arnd Bergmann
@ 2019-12-12 10:16     ` Will Deacon
  -1 siblings, 0 replies; 64+ messages in thread
From: Will Deacon @ 2019-12-12 10:16 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Catalin Marinas, linux-kernel, y2038,
	linux-arm-kernel

On Wed, Dec 11, 2019 at 09:42:35PM +0100, Arnd Bergmann wrote:
> In order to use compat_* type defininitions in device drivers
> outside of CONFIG_COMPAT, move the inclusion of asm-generic/compat.h
> ahead of the #ifdef.
> 
> All other architectures already do this.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  arch/arm64/include/asm/compat.h | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)

Acked-by: Will Deacon <will@kernel.org>

(Please let me know if you'd prefer this patch to be routed via the arm64
tree).

Will

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h
@ 2019-12-12 10:16     ` Will Deacon
  0 siblings, 0 replies; 64+ messages in thread
From: Will Deacon @ 2019-12-12 10:16 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, Martin K. Petersen, y2038, Catalin Marinas,
	James E.J. Bottomley, linux-kernel, Alexander Viro,
	linux-arm-kernel

On Wed, Dec 11, 2019 at 09:42:35PM +0100, Arnd Bergmann wrote:
> In order to use compat_* type defininitions in device drivers
> outside of CONFIG_COMPAT, move the inclusion of asm-generic/compat.h
> ahead of the #ifdef.
> 
> All other architectures already do this.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  arch/arm64/include/asm/compat.h | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)

Acked-by: Will Deacon <will@kernel.org>

(Please let me know if you'd prefer this patch to be routed via the arm64
tree).

Will

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-11 20:42 ` [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers Arnd Bergmann
@ 2019-12-12 10:25     ` Michael S. Tsirkin
  2019-12-11 23:05   ` Michael S. Tsirkin
  2019-12-12 10:25     ` Michael S. Tsirkin
  2 siblings, 0 replies; 64+ messages in thread
From: Michael S. Tsirkin @ 2019-12-12 10:25 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jason Wang, Doug Gilbert, Kai Mäkisara,
	linux-kernel, y2038, Paolo Bonzini, Stefan Hajnoczi,
	Bart Van Assche, Hannes Reinecke, Damien Le Moal, John Garry,
	virtualization, linux-block, linux-scsi, linux-fsdevel

On Wed, Dec 11, 2019 at 09:42:49PM +0100, Arnd Bergmann wrote:
> Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
> handler that implements the same commands by calling scsi_compat_ioctl().
> 
> The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
> at this point, so any driver that calls those can do so for both native
> and compat mode, with the argument passed through compat_ptr().
> 
> With this, we can remove the entries from fs/compat_ioctl.c.  The new
> code is larger, but should be easier to maintain and keep updated with
> newly added commands.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/block/virtio_blk.c |   3 +
>  drivers/scsi/ch.c          |   9 ++-
>  drivers/scsi/sd.c          |  50 ++++++--------
>  drivers/scsi/sg.c          |  44 ++++++++-----
>  drivers/scsi/sr.c          |  57 ++++++++++++++--
>  drivers/scsi/st.c          |  51 ++++++++------
>  fs/compat_ioctl.c          | 132 +------------------------------------
>  7 files changed, 142 insertions(+), 204 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 7ffd719d89de..fbbf18ac1d5d 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
>  
>  static const struct block_device_operations virtblk_fops = {
>  	.ioctl  = virtblk_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
> +#endif
>  	.owner  = THIS_MODULE,
>  	.getgeo = virtblk_getgeo,
>  };


virtio part:

Acked-by: Michael S. Tsirkin <mst@redhat.com>

> diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
> index 76751d6c7f0d..ed5f4a6ae270 100644
> --- a/drivers/scsi/ch.c
> +++ b/drivers/scsi/ch.c
> @@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
>  			    unsigned int cmd, unsigned long arg)
>  {
>  	scsi_changer *ch = file->private_data;
> +	int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
> +							file->f_flags & O_NDELAY);
> +	if (retval)
> +		return retval;
>  
>  	switch (cmd) {
>  	case CHIOGPARAMS:
> @@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
>  	case CHIOINITELEM:
>  	case CHIOSVOLTAG:
>  		/* compatible */
> -		return ch_ioctl(file, cmd, arg);
> +		return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
>  	case CHIOGSTATUS32:
>  	{
>  		struct changer_element_status32 ces32;
> @@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
>  		return ch_gstatus(ch, ces32.ces_type, data);
>  	}
>  	default:
> -		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
> -		return -ENOIOCTLCMD;
> +		return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
>  
>  	}
>  }
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index cea625906440..5afb0046b12a 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -1465,13 +1465,12 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
>   *	Note: most ioctls are forward onto the block subsystem or further
>   *	down in the scsi subsystem.
>   **/
> -static int sd_ioctl(struct block_device *bdev, fmode_t mode,
> -		    unsigned int cmd, unsigned long arg)
> +static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
> +			   unsigned int cmd, void __user *p)
>  {
>  	struct gendisk *disk = bdev->bd_disk;
>  	struct scsi_disk *sdkp = scsi_disk(disk);
>  	struct scsi_device *sdp = sdkp->device;
> -	void __user *p = (void __user *)arg;
>  	int error;
>      
>  	SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
> @@ -1507,9 +1506,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
>  			break;
>  		default:
>  			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
> -			if (error != -ENOTTY)
> -				break;
> -			error = scsi_ioctl(sdp, cmd, p);
>  			break;
>  	}
>  out:
> @@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
>  	revalidate_disk(sdkp->disk);
>  }
>  
> +static int sd_ioctl(struct block_device *bdev, fmode_t mode,
> +		    unsigned int cmd, unsigned long arg)
> +{
> +	void __user *p = (void __user *)arg;
> +	int ret;
> +
> +	ret = sd_ioctl_common(bdev, mode, cmd, p);
> +	if (ret != -ENOTTY)
> +		return ret;
> +
> +	return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
> +}
>  
>  #ifdef CONFIG_COMPAT
> -/* 
> - * This gets directly called from VFS. When the ioctl 
> - * is not recognized we go back to the other translation paths. 
> - */
>  static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
>  			   unsigned int cmd, unsigned long arg)
>  {
> -	struct gendisk *disk = bdev->bd_disk;
> -	struct scsi_disk *sdkp = scsi_disk(disk);
> -	struct scsi_device *sdev = sdkp->device;
>  	void __user *p = compat_ptr(arg);
> -	int error;
> -
> -	error = scsi_verify_blk_ioctl(bdev, cmd);
> -	if (error < 0)
> -		return error;
> +	int ret;
>  
> -	error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
> -			(mode & FMODE_NDELAY) != 0);
> -	if (error)
> -		return error;
> +	ret = sd_ioctl_common(bdev, mode, cmd, p);
> +	if (ret != -ENOTTY)
> +		return ret;
>  
> -	if (is_sed_ioctl(cmd))
> -		return sed_ioctl(sdkp->opal_dev, cmd, p);
> -	       
> -	/* 
> -	 * Let the static ioctl translation table take care of it.
> -	 */
> -	if (!sdev->host->hostt->compat_ioctl)
> -		return -ENOIOCTLCMD; 
> -	return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
> +	return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
>  }
>  #endif
>  
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 985546aac236..08efcee7a34d 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -910,19 +910,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
>  #endif
>  
>  static long
> -sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
> +sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
> +		unsigned int cmd_in, void __user *p)
>  {
> -	void __user *p = (void __user *)arg;
>  	int __user *ip = p;
>  	int result, val, read_only;
> -	Sg_device *sdp;
> -	Sg_fd *sfp;
>  	Sg_request *srp;
>  	unsigned long iflags;
>  
> -	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
> -		return -ENXIO;
> -
>  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
>  				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
>  	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
> @@ -1145,29 +1140,44 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
>  			cmd_in, filp->f_flags & O_NDELAY);
>  	if (result)
>  		return result;
> +
> +	return -ENOIOCTLCMD;
> +}
> +
> +static long
> +sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
> +{
> +	void __user *p = (void __user *)arg;
> +	Sg_device *sdp;
> +	Sg_fd *sfp;
> +	int ret;
> +
> +	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
> +		return -ENXIO;
> +
> +	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
> +	if (ret != -ENOIOCTLCMD)
> +		return ret;
> +
>  	return scsi_ioctl(sdp->device, cmd_in, p);
>  }
>  
>  #ifdef CONFIG_COMPAT
>  static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
>  {
> +	void __user *p = compat_ptr(arg);
>  	Sg_device *sdp;
>  	Sg_fd *sfp;
> -	struct scsi_device *sdev;
> +	int ret;
>  
>  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
>  		return -ENXIO;
>  
> -	sdev = sdp->device;
> -	if (sdev->host->hostt->compat_ioctl) { 
> -		int ret;
> -
> -		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
> -
> +	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
> +	if (ret != -ENOIOCTLCMD)
>  		return ret;
> -	}
> -	
> -	return -ENOIOCTLCMD;
> +
> +	return scsi_compat_ioctl(sdp->device, cmd_in, p);
>  }
>  #endif
>  
> diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
> index 4664fdf75c0f..6033a886c42c 100644
> --- a/drivers/scsi/sr.c
> +++ b/drivers/scsi/sr.c
> @@ -38,6 +38,7 @@
>  #include <linux/kernel.h>
>  #include <linux/mm.h>
>  #include <linux/bio.h>
> +#include <linux/compat.h>
>  #include <linux/string.h>
>  #include <linux/errno.h>
>  #include <linux/cdrom.h>
> @@ -598,6 +599,55 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
>  	return ret;
>  }
>  
> +#ifdef CONFIG_COMPAT
> +static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
> +			  unsigned long arg)
> +{
> +	struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
> +	struct scsi_device *sdev = cd->device;
> +	void __user *argp = compat_ptr(arg);
> +	int ret;
> +
> +	mutex_lock(&sr_mutex);
> +
> +	ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
> +			(mode & FMODE_NDELAY) != 0);
> +	if (ret)
> +		goto out;
> +
> +	scsi_autopm_get_device(sdev);
> +
> +	/*
> +	 * Send SCSI addressing ioctls directly to mid level, send other
> +	 * ioctls to cdrom/block level.
> +	 */
> +	switch (cmd) {
> +	case SCSI_IOCTL_GET_IDLUN:
> +	case SCSI_IOCTL_GET_BUS_NUMBER:
> +		ret = scsi_compat_ioctl(sdev, cmd, argp);
> +		goto put;
> +	}
> +
> +	/*
> +	 * CDROM ioctls are handled in the block layer, but
> +	 * do the scsi blk ioctls here.
> +	 */
> +	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
> +	if (ret != -ENOTTY)
> +		return ret;
> +
> +	ret = scsi_compat_ioctl(sdev, cmd, argp);
> +
> +put:
> +	scsi_autopm_put_device(sdev);
> +
> +out:
> +	mutex_unlock(&sr_mutex);
> +	return ret;
> +
> +}
> +#endif
> +
>  static unsigned int sr_block_check_events(struct gendisk *disk,
>  					  unsigned int clearing)
>  {
> @@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
>  	.open		= sr_block_open,
>  	.release	= sr_block_release,
>  	.ioctl		= sr_block_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.ioctl		= sr_block_compat_ioctl,
> +#endif
>  	.check_events	= sr_block_check_events,
>  	.revalidate_disk = sr_block_revalidate_disk,
> -	/* 
> -	 * No compat_ioctl for now because sr_block_ioctl never
> -	 * seems to pass arbitrary ioctls down to host drivers.
> -	 */
>  };
>  
>  static int sr_open(struct cdrom_device_info *cdi, int purpose)
> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> index 9e3fff2de83e..393f3019ccac 100644
> --- a/drivers/scsi/st.c
> +++ b/drivers/scsi/st.c
> @@ -3501,7 +3501,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
>  
>  
>  /* The ioctl command */
> -static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
> +static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p)
>  {
>  	int i, cmd_nr, cmd_type, bt;
>  	int retval = 0;
> @@ -3509,7 +3509,6 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  	struct scsi_tape *STp = file->private_data;
>  	struct st_modedef *STm;
>  	struct st_partstat *STps;
> -	void __user *p = (void __user *)arg;
>  
>  	if (mutex_lock_interruptible(&STp->lock))
>  		return -ERESTARTSYS;
> @@ -3824,9 +3823,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  	}
>  	mutex_unlock(&STp->lock);
>  	switch (cmd_in) {
> +		case SCSI_IOCTL_STOP_UNIT:
> +			/* unload */
> +			retval = scsi_ioctl(STp->device, cmd_in, p);
> +			if (!retval) {
> +				STp->rew_at_close = 0;
> +				STp->ready = ST_NO_TAPE;
> +			}
> +			return retval;
> +
>  		case SCSI_IOCTL_GET_IDLUN:
>  		case SCSI_IOCTL_GET_BUS_NUMBER:
>  			break;
> +
>  		default:
>  			if ((cmd_in == SG_IO ||
>  			     cmd_in == SCSI_IOCTL_SEND_COMMAND ||
> @@ -3840,42 +3849,46 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  				return i;
>  			break;
>  	}
> -	retval = scsi_ioctl(STp->device, cmd_in, p);
> -	if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
> -		STp->rew_at_close = 0;
> -		STp->ready = ST_NO_TAPE;
> -	}
> -	return retval;
> +	return -ENOTTY;
>  
>   out:
>  	mutex_unlock(&STp->lock);
>  	return retval;
>  }
>  
> +static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
> +{
> +	void __user *p = (void __user *)arg;
> +	struct scsi_tape *STp = file->private_data;
> +	int ret;
> +
> +	ret = st_ioctl_common(file, cmd_in, p);
> +	if (ret != -ENOTTY)
> +		return ret;
> +
> +	return scsi_ioctl(STp->device, cmd_in, p);
> +}
> +
>  #ifdef CONFIG_COMPAT
>  static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  {
>  	void __user *p = compat_ptr(arg);
>  	struct scsi_tape *STp = file->private_data;
> -	struct scsi_device *sdev = STp->device;
> -	int ret = -ENOIOCTLCMD;
> +	int ret;
>  
>  	/* argument conversion is handled using put_user_mtpos/put_user_mtget */
>  	switch (cmd_in) {
> -	case MTIOCTOP:
> -		return st_ioctl(file, MTIOCTOP, (unsigned long)p);
>  	case MTIOCPOS32:
> -		return st_ioctl(file, MTIOCPOS, (unsigned long)p);
> +		return st_ioctl_common(file, MTIOCPOS, p);
>  	case MTIOCGET32:
> -		return st_ioctl(file, MTIOCGET, (unsigned long)p);
> +		return st_ioctl_common(file, MTIOCGET, p);
>  	}
>  
> -	if (sdev->host->hostt->compat_ioctl) { 
> +	ret = st_ioctl_common(file, cmd_in, p);
> +	if (ret != -ENOTTY)
> +		return ret;
>  
> -		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
> -
> -	}
> -	return ret;
> +	return scsi_compat_ioctl(STp->device, cmd_in, p);
>  }
>  #endif
>  
> diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
> index 358ea2ecf36b..ab4471f469e6 100644
> --- a/fs/compat_ioctl.c
> +++ b/fs/compat_ioctl.c
> @@ -36,109 +36,11 @@
>  
>  #include "internal.h"
>  
> -#ifdef CONFIG_BLOCK
> -#include <linux/cdrom.h>
> -#include <linux/fd.h>
> -#include <scsi/scsi.h>
> -#include <scsi/scsi_ioctl.h>
> -#include <scsi/sg.h>
> -#endif
> -
>  #include <linux/uaccess.h>
>  #include <linux/watchdog.h>
>  
>  #include <linux/hiddev.h>
>  
> -
> -#include <linux/sort.h>
> -
> -/*
> - * simple reversible transform to make our table more evenly
> - * distributed after sorting.
> - */
> -#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
> -
> -#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
> -static unsigned int ioctl_pointer[] = {
> -#ifdef CONFIG_BLOCK
> -/* Big S */
> -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
> -#endif
> -#ifdef CONFIG_BLOCK
> -/* SG stuff */
> -COMPATIBLE_IOCTL(SG_IO)
> -COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
> -COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
> -COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
> -COMPATIBLE_IOCTL(SG_EMULATED_HOST)
> -COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
> -COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
> -COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
> -COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
> -COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
> -COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
> -COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
> -COMPATIBLE_IOCTL(SG_GET_PACK_ID)
> -COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
> -COMPATIBLE_IOCTL(SG_SET_DEBUG)
> -COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
> -COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
> -COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
> -COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
> -COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
> -COMPATIBLE_IOCTL(SG_SCSI_RESET)
> -COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
> -COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
> -COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
> -#endif
> -};
> -
> -/*
> - * Convert common ioctl arguments based on their command number
> - *
> - * Please do not add any code in here. Instead, implement
> - * a compat_ioctl operation in the place that handleѕ the
> - * ioctl for the native case.
> - */
> -static long do_ioctl_trans(unsigned int cmd,
> -		 unsigned long arg, struct file *file)
> -{
> -	return -ENOIOCTLCMD;
> -}
> -
> -static int compat_ioctl_check_table(unsigned int xcmd)
> -{
> -#ifdef CONFIG_BLOCK
> -	int i;
> -	const int max = ARRAY_SIZE(ioctl_pointer) - 1;
> -
> -	BUILD_BUG_ON(max >= (1 << 16));
> -
> -	/* guess initial offset into table, assuming a
> -	   normalized distribution */
> -	i = ((xcmd >> 16) * max) >> 16;
> -
> -	/* do linear search up first, until greater or equal */
> -	while (ioctl_pointer[i] < xcmd && i < max)
> -		i++;
> -
> -	/* then do linear search down */
> -	while (ioctl_pointer[i] > xcmd && i > 0)
> -		i--;
> -
> -	return ioctl_pointer[i] == xcmd;
> -#else
> -	return 0;
> -#endif
> -}
> -
>  COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>  		       compat_ulong_t, arg32)
>  {
> @@ -216,19 +118,9 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>  				goto out_fput;
>  		}
>  
> -		if (!f.file->f_op->unlocked_ioctl)
> -			goto do_ioctl;
> -		break;
> -	}
> -
> -	if (compat_ioctl_check_table(XFORM(cmd)))
> -		goto found_handler;
> -
> -	error = do_ioctl_trans(cmd, arg, f.file);
> -	if (error == -ENOIOCTLCMD)
>  		error = -ENOTTY;
> -
> -	goto out_fput;
> +		goto out_fput;
> +	}
>  
>   found_handler:
>  	arg = (unsigned long)compat_ptr(arg);
> @@ -239,23 +131,3 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>   out:
>  	return error;
>  }
> -
> -static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
> -{
> -	unsigned int a, b;
> -	a = *(unsigned int *)p;
> -	b = *(unsigned int *)q;
> -	if (a > b)
> -		return 1;
> -	if (a < b)
> -		return -1;
> -	return 0;
> -}
> -
> -static int __init init_sys32_ioctl(void)
> -{
> -	sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
> -		init_sys32_ioctl_cmp, NULL);
> -	return 0;
> -}
> -__initcall(init_sys32_ioctl);
> -- 
> 2.20.0


^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
@ 2019-12-12 10:25     ` Michael S. Tsirkin
  0 siblings, 0 replies; 64+ messages in thread
From: Michael S. Tsirkin @ 2019-12-12 10:25 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, Hannes Reinecke, Bart Van Assche, Martin K. Petersen,
	y2038, Damien Le Moal, James E.J. Bottomley, John Garry,
	linux-kernel, Kai Mäkisara, linux-block, Alexander Viro,
	Stefan Hajnoczi, Doug Gilbert, linux-fsdevel, Paolo Bonzini,
	virtualization, linux-scsi

On Wed, Dec 11, 2019 at 09:42:49PM +0100, Arnd Bergmann wrote:
> Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
> handler that implements the same commands by calling scsi_compat_ioctl().
> 
> The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
> at this point, so any driver that calls those can do so for both native
> and compat mode, with the argument passed through compat_ptr().
> 
> With this, we can remove the entries from fs/compat_ioctl.c.  The new
> code is larger, but should be easier to maintain and keep updated with
> newly added commands.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/block/virtio_blk.c |   3 +
>  drivers/scsi/ch.c          |   9 ++-
>  drivers/scsi/sd.c          |  50 ++++++--------
>  drivers/scsi/sg.c          |  44 ++++++++-----
>  drivers/scsi/sr.c          |  57 ++++++++++++++--
>  drivers/scsi/st.c          |  51 ++++++++------
>  fs/compat_ioctl.c          | 132 +------------------------------------
>  7 files changed, 142 insertions(+), 204 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 7ffd719d89de..fbbf18ac1d5d 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
>  
>  static const struct block_device_operations virtblk_fops = {
>  	.ioctl  = virtblk_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
> +#endif
>  	.owner  = THIS_MODULE,
>  	.getgeo = virtblk_getgeo,
>  };


virtio part:

Acked-by: Michael S. Tsirkin <mst@redhat.com>

> diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
> index 76751d6c7f0d..ed5f4a6ae270 100644
> --- a/drivers/scsi/ch.c
> +++ b/drivers/scsi/ch.c
> @@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
>  			    unsigned int cmd, unsigned long arg)
>  {
>  	scsi_changer *ch = file->private_data;
> +	int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
> +							file->f_flags & O_NDELAY);
> +	if (retval)
> +		return retval;
>  
>  	switch (cmd) {
>  	case CHIOGPARAMS:
> @@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
>  	case CHIOINITELEM:
>  	case CHIOSVOLTAG:
>  		/* compatible */
> -		return ch_ioctl(file, cmd, arg);
> +		return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
>  	case CHIOGSTATUS32:
>  	{
>  		struct changer_element_status32 ces32;
> @@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
>  		return ch_gstatus(ch, ces32.ces_type, data);
>  	}
>  	default:
> -		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
> -		return -ENOIOCTLCMD;
> +		return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
>  
>  	}
>  }
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index cea625906440..5afb0046b12a 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -1465,13 +1465,12 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
>   *	Note: most ioctls are forward onto the block subsystem or further
>   *	down in the scsi subsystem.
>   **/
> -static int sd_ioctl(struct block_device *bdev, fmode_t mode,
> -		    unsigned int cmd, unsigned long arg)
> +static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
> +			   unsigned int cmd, void __user *p)
>  {
>  	struct gendisk *disk = bdev->bd_disk;
>  	struct scsi_disk *sdkp = scsi_disk(disk);
>  	struct scsi_device *sdp = sdkp->device;
> -	void __user *p = (void __user *)arg;
>  	int error;
>      
>  	SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
> @@ -1507,9 +1506,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
>  			break;
>  		default:
>  			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
> -			if (error != -ENOTTY)
> -				break;
> -			error = scsi_ioctl(sdp, cmd, p);
>  			break;
>  	}
>  out:
> @@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
>  	revalidate_disk(sdkp->disk);
>  }
>  
> +static int sd_ioctl(struct block_device *bdev, fmode_t mode,
> +		    unsigned int cmd, unsigned long arg)
> +{
> +	void __user *p = (void __user *)arg;
> +	int ret;
> +
> +	ret = sd_ioctl_common(bdev, mode, cmd, p);
> +	if (ret != -ENOTTY)
> +		return ret;
> +
> +	return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
> +}
>  
>  #ifdef CONFIG_COMPAT
> -/* 
> - * This gets directly called from VFS. When the ioctl 
> - * is not recognized we go back to the other translation paths. 
> - */
>  static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
>  			   unsigned int cmd, unsigned long arg)
>  {
> -	struct gendisk *disk = bdev->bd_disk;
> -	struct scsi_disk *sdkp = scsi_disk(disk);
> -	struct scsi_device *sdev = sdkp->device;
>  	void __user *p = compat_ptr(arg);
> -	int error;
> -
> -	error = scsi_verify_blk_ioctl(bdev, cmd);
> -	if (error < 0)
> -		return error;
> +	int ret;
>  
> -	error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
> -			(mode & FMODE_NDELAY) != 0);
> -	if (error)
> -		return error;
> +	ret = sd_ioctl_common(bdev, mode, cmd, p);
> +	if (ret != -ENOTTY)
> +		return ret;
>  
> -	if (is_sed_ioctl(cmd))
> -		return sed_ioctl(sdkp->opal_dev, cmd, p);
> -	       
> -	/* 
> -	 * Let the static ioctl translation table take care of it.
> -	 */
> -	if (!sdev->host->hostt->compat_ioctl)
> -		return -ENOIOCTLCMD; 
> -	return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
> +	return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
>  }
>  #endif
>  
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 985546aac236..08efcee7a34d 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -910,19 +910,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
>  #endif
>  
>  static long
> -sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
> +sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
> +		unsigned int cmd_in, void __user *p)
>  {
> -	void __user *p = (void __user *)arg;
>  	int __user *ip = p;
>  	int result, val, read_only;
> -	Sg_device *sdp;
> -	Sg_fd *sfp;
>  	Sg_request *srp;
>  	unsigned long iflags;
>  
> -	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
> -		return -ENXIO;
> -
>  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
>  				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
>  	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
> @@ -1145,29 +1140,44 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
>  			cmd_in, filp->f_flags & O_NDELAY);
>  	if (result)
>  		return result;
> +
> +	return -ENOIOCTLCMD;
> +}
> +
> +static long
> +sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
> +{
> +	void __user *p = (void __user *)arg;
> +	Sg_device *sdp;
> +	Sg_fd *sfp;
> +	int ret;
> +
> +	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
> +		return -ENXIO;
> +
> +	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
> +	if (ret != -ENOIOCTLCMD)
> +		return ret;
> +
>  	return scsi_ioctl(sdp->device, cmd_in, p);
>  }
>  
>  #ifdef CONFIG_COMPAT
>  static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
>  {
> +	void __user *p = compat_ptr(arg);
>  	Sg_device *sdp;
>  	Sg_fd *sfp;
> -	struct scsi_device *sdev;
> +	int ret;
>  
>  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
>  		return -ENXIO;
>  
> -	sdev = sdp->device;
> -	if (sdev->host->hostt->compat_ioctl) { 
> -		int ret;
> -
> -		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
> -
> +	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
> +	if (ret != -ENOIOCTLCMD)
>  		return ret;
> -	}
> -	
> -	return -ENOIOCTLCMD;
> +
> +	return scsi_compat_ioctl(sdp->device, cmd_in, p);
>  }
>  #endif
>  
> diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
> index 4664fdf75c0f..6033a886c42c 100644
> --- a/drivers/scsi/sr.c
> +++ b/drivers/scsi/sr.c
> @@ -38,6 +38,7 @@
>  #include <linux/kernel.h>
>  #include <linux/mm.h>
>  #include <linux/bio.h>
> +#include <linux/compat.h>
>  #include <linux/string.h>
>  #include <linux/errno.h>
>  #include <linux/cdrom.h>
> @@ -598,6 +599,55 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
>  	return ret;
>  }
>  
> +#ifdef CONFIG_COMPAT
> +static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
> +			  unsigned long arg)
> +{
> +	struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
> +	struct scsi_device *sdev = cd->device;
> +	void __user *argp = compat_ptr(arg);
> +	int ret;
> +
> +	mutex_lock(&sr_mutex);
> +
> +	ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
> +			(mode & FMODE_NDELAY) != 0);
> +	if (ret)
> +		goto out;
> +
> +	scsi_autopm_get_device(sdev);
> +
> +	/*
> +	 * Send SCSI addressing ioctls directly to mid level, send other
> +	 * ioctls to cdrom/block level.
> +	 */
> +	switch (cmd) {
> +	case SCSI_IOCTL_GET_IDLUN:
> +	case SCSI_IOCTL_GET_BUS_NUMBER:
> +		ret = scsi_compat_ioctl(sdev, cmd, argp);
> +		goto put;
> +	}
> +
> +	/*
> +	 * CDROM ioctls are handled in the block layer, but
> +	 * do the scsi blk ioctls here.
> +	 */
> +	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
> +	if (ret != -ENOTTY)
> +		return ret;
> +
> +	ret = scsi_compat_ioctl(sdev, cmd, argp);
> +
> +put:
> +	scsi_autopm_put_device(sdev);
> +
> +out:
> +	mutex_unlock(&sr_mutex);
> +	return ret;
> +
> +}
> +#endif
> +
>  static unsigned int sr_block_check_events(struct gendisk *disk,
>  					  unsigned int clearing)
>  {
> @@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
>  	.open		= sr_block_open,
>  	.release	= sr_block_release,
>  	.ioctl		= sr_block_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.ioctl		= sr_block_compat_ioctl,
> +#endif
>  	.check_events	= sr_block_check_events,
>  	.revalidate_disk = sr_block_revalidate_disk,
> -	/* 
> -	 * No compat_ioctl for now because sr_block_ioctl never
> -	 * seems to pass arbitrary ioctls down to host drivers.
> -	 */
>  };
>  
>  static int sr_open(struct cdrom_device_info *cdi, int purpose)
> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> index 9e3fff2de83e..393f3019ccac 100644
> --- a/drivers/scsi/st.c
> +++ b/drivers/scsi/st.c
> @@ -3501,7 +3501,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
>  
>  
>  /* The ioctl command */
> -static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
> +static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p)
>  {
>  	int i, cmd_nr, cmd_type, bt;
>  	int retval = 0;
> @@ -3509,7 +3509,6 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  	struct scsi_tape *STp = file->private_data;
>  	struct st_modedef *STm;
>  	struct st_partstat *STps;
> -	void __user *p = (void __user *)arg;
>  
>  	if (mutex_lock_interruptible(&STp->lock))
>  		return -ERESTARTSYS;
> @@ -3824,9 +3823,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  	}
>  	mutex_unlock(&STp->lock);
>  	switch (cmd_in) {
> +		case SCSI_IOCTL_STOP_UNIT:
> +			/* unload */
> +			retval = scsi_ioctl(STp->device, cmd_in, p);
> +			if (!retval) {
> +				STp->rew_at_close = 0;
> +				STp->ready = ST_NO_TAPE;
> +			}
> +			return retval;
> +
>  		case SCSI_IOCTL_GET_IDLUN:
>  		case SCSI_IOCTL_GET_BUS_NUMBER:
>  			break;
> +
>  		default:
>  			if ((cmd_in == SG_IO ||
>  			     cmd_in == SCSI_IOCTL_SEND_COMMAND ||
> @@ -3840,42 +3849,46 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  				return i;
>  			break;
>  	}
> -	retval = scsi_ioctl(STp->device, cmd_in, p);
> -	if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
> -		STp->rew_at_close = 0;
> -		STp->ready = ST_NO_TAPE;
> -	}
> -	return retval;
> +	return -ENOTTY;
>  
>   out:
>  	mutex_unlock(&STp->lock);
>  	return retval;
>  }
>  
> +static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
> +{
> +	void __user *p = (void __user *)arg;
> +	struct scsi_tape *STp = file->private_data;
> +	int ret;
> +
> +	ret = st_ioctl_common(file, cmd_in, p);
> +	if (ret != -ENOTTY)
> +		return ret;
> +
> +	return scsi_ioctl(STp->device, cmd_in, p);
> +}
> +
>  #ifdef CONFIG_COMPAT
>  static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
>  {
>  	void __user *p = compat_ptr(arg);
>  	struct scsi_tape *STp = file->private_data;
> -	struct scsi_device *sdev = STp->device;
> -	int ret = -ENOIOCTLCMD;
> +	int ret;
>  
>  	/* argument conversion is handled using put_user_mtpos/put_user_mtget */
>  	switch (cmd_in) {
> -	case MTIOCTOP:
> -		return st_ioctl(file, MTIOCTOP, (unsigned long)p);
>  	case MTIOCPOS32:
> -		return st_ioctl(file, MTIOCPOS, (unsigned long)p);
> +		return st_ioctl_common(file, MTIOCPOS, p);
>  	case MTIOCGET32:
> -		return st_ioctl(file, MTIOCGET, (unsigned long)p);
> +		return st_ioctl_common(file, MTIOCGET, p);
>  	}
>  
> -	if (sdev->host->hostt->compat_ioctl) { 
> +	ret = st_ioctl_common(file, cmd_in, p);
> +	if (ret != -ENOTTY)
> +		return ret;
>  
> -		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
> -
> -	}
> -	return ret;
> +	return scsi_compat_ioctl(STp->device, cmd_in, p);
>  }
>  #endif
>  
> diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
> index 358ea2ecf36b..ab4471f469e6 100644
> --- a/fs/compat_ioctl.c
> +++ b/fs/compat_ioctl.c
> @@ -36,109 +36,11 @@
>  
>  #include "internal.h"
>  
> -#ifdef CONFIG_BLOCK
> -#include <linux/cdrom.h>
> -#include <linux/fd.h>
> -#include <scsi/scsi.h>
> -#include <scsi/scsi_ioctl.h>
> -#include <scsi/sg.h>
> -#endif
> -
>  #include <linux/uaccess.h>
>  #include <linux/watchdog.h>
>  
>  #include <linux/hiddev.h>
>  
> -
> -#include <linux/sort.h>
> -
> -/*
> - * simple reversible transform to make our table more evenly
> - * distributed after sorting.
> - */
> -#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
> -
> -#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
> -static unsigned int ioctl_pointer[] = {
> -#ifdef CONFIG_BLOCK
> -/* Big S */
> -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
> -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
> -#endif
> -#ifdef CONFIG_BLOCK
> -/* SG stuff */
> -COMPATIBLE_IOCTL(SG_IO)
> -COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
> -COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
> -COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
> -COMPATIBLE_IOCTL(SG_EMULATED_HOST)
> -COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
> -COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
> -COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
> -COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
> -COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
> -COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
> -COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
> -COMPATIBLE_IOCTL(SG_GET_PACK_ID)
> -COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
> -COMPATIBLE_IOCTL(SG_SET_DEBUG)
> -COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
> -COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
> -COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
> -COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
> -COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
> -COMPATIBLE_IOCTL(SG_SCSI_RESET)
> -COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
> -COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
> -COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
> -#endif
> -};
> -
> -/*
> - * Convert common ioctl arguments based on their command number
> - *
> - * Please do not add any code in here. Instead, implement
> - * a compat_ioctl operation in the place that handleѕ the
> - * ioctl for the native case.
> - */
> -static long do_ioctl_trans(unsigned int cmd,
> -		 unsigned long arg, struct file *file)
> -{
> -	return -ENOIOCTLCMD;
> -}
> -
> -static int compat_ioctl_check_table(unsigned int xcmd)
> -{
> -#ifdef CONFIG_BLOCK
> -	int i;
> -	const int max = ARRAY_SIZE(ioctl_pointer) - 1;
> -
> -	BUILD_BUG_ON(max >= (1 << 16));
> -
> -	/* guess initial offset into table, assuming a
> -	   normalized distribution */
> -	i = ((xcmd >> 16) * max) >> 16;
> -
> -	/* do linear search up first, until greater or equal */
> -	while (ioctl_pointer[i] < xcmd && i < max)
> -		i++;
> -
> -	/* then do linear search down */
> -	while (ioctl_pointer[i] > xcmd && i > 0)
> -		i--;
> -
> -	return ioctl_pointer[i] == xcmd;
> -#else
> -	return 0;
> -#endif
> -}
> -
>  COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>  		       compat_ulong_t, arg32)
>  {
> @@ -216,19 +118,9 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>  				goto out_fput;
>  		}
>  
> -		if (!f.file->f_op->unlocked_ioctl)
> -			goto do_ioctl;
> -		break;
> -	}
> -
> -	if (compat_ioctl_check_table(XFORM(cmd)))
> -		goto found_handler;
> -
> -	error = do_ioctl_trans(cmd, arg, f.file);
> -	if (error == -ENOIOCTLCMD)
>  		error = -ENOTTY;
> -
> -	goto out_fput;
> +		goto out_fput;
> +	}
>  
>   found_handler:
>  	arg = (unsigned long)compat_ptr(arg);
> @@ -239,23 +131,3 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>   out:
>  	return error;
>  }
> -
> -static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
> -{
> -	unsigned int a, b;
> -	a = *(unsigned int *)p;
> -	b = *(unsigned int *)q;
> -	if (a > b)
> -		return 1;
> -	if (a < b)
> -		return -1;
> -	return 0;
> -}
> -
> -static int __init init_sys32_ioctl(void)
> -{
> -	sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
> -		init_sys32_ioctl_cmp, NULL);
> -	return 0;
> -}
> -__initcall(init_sys32_ioctl);
> -- 
> 2.20.0

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12  0:28     ` Paolo Bonzini
                         ` (2 preceding siblings ...)
  2019-12-12 10:27       ` Michael S. Tsirkin
@ 2019-12-12 10:27       ` Michael S. Tsirkin
  2019-12-12 16:27       ` Christoph Hellwig
  2019-12-12 16:27       ` Christoph Hellwig
  5 siblings, 0 replies; 64+ messages in thread
From: Michael S. Tsirkin @ 2019-12-12 10:27 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Arnd Bergmann, Jens Axboe, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, Jason Wang, Doug Gilbert,
	Kai Mäkisara, linux-kernel, y2038, Stefan Hajnoczi,
	Bart Van Assche, Hannes Reinecke, Damien Le Moal, John Garry,
	virtualization, linux-block, linux-scsi, linux-fsdevel

On Thu, Dec 12, 2019 at 01:28:08AM +0100, Paolo Bonzini wrote:
> On 12/12/19 00:05, Michael S. Tsirkin wrote:
> >> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
> >>  
> >>  static const struct block_device_operations virtblk_fops = {
> >>  	.ioctl  = virtblk_ioctl,
> >> +#ifdef CONFIG_COMPAT
> >> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
> >> +#endif
> >>  	.owner  = THIS_MODULE,
> >>  	.getgeo = virtblk_getgeo,
> >>  };
> > Hmm - is virtio blk lumped in with scsi things intentionally?
> 
> I think it's because the only ioctl for virtio-blk is SG_IO.

Oh right, I forgot about that one ...

>  It makes
> sense to lump it in with scsi, but I wouldn't mind getting rid of
> CONFIG_VIRTIO_BLK_SCSI altogether.
> 
> Paolo


^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12  0:28     ` Paolo Bonzini
  2019-12-12  9:17       ` Arnd Bergmann
  2019-12-12  9:17       ` Arnd Bergmann
@ 2019-12-12 10:27       ` Michael S. Tsirkin
  2019-12-12 10:27       ` Michael S. Tsirkin
                         ` (2 subsequent siblings)
  5 siblings, 0 replies; 64+ messages in thread
From: Michael S. Tsirkin @ 2019-12-12 10:27 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Jens Axboe, Hannes Reinecke, Arnd Bergmann, Martin K. Petersen,
	y2038, Damien Le Moal, James E.J. Bottomley, John Garry,
	linux-kernel, Kai Mäkisara, linux-block, Alexander Viro,
	Stefan Hajnoczi, Doug Gilbert, linux-fsdevel, virtualization,
	linux-scsi, Bart Van Assche

On Thu, Dec 12, 2019 at 01:28:08AM +0100, Paolo Bonzini wrote:
> On 12/12/19 00:05, Michael S. Tsirkin wrote:
> >> @@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
> >>  
> >>  static const struct block_device_operations virtblk_fops = {
> >>  	.ioctl  = virtblk_ioctl,
> >> +#ifdef CONFIG_COMPAT
> >> +	.compat_ioctl = blkdev_compat_ptr_ioctl,
> >> +#endif
> >>  	.owner  = THIS_MODULE,
> >>  	.getgeo = virtblk_getgeo,
> >>  };
> > Hmm - is virtio blk lumped in with scsi things intentionally?
> 
> I think it's because the only ioctl for virtio-blk is SG_IO.

Oh right, I forgot about that one ...

>  It makes
> sense to lump it in with scsi, but I wouldn't mind getting rid of
> CONFIG_VIRTIO_BLK_SCSI altogether.
> 
> Paolo

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h
  2019-12-12 10:16     ` Will Deacon
@ 2019-12-12 10:41       ` Arnd Bergmann
  -1 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 10:41 UTC (permalink / raw)
  To: Will Deacon
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Catalin Marinas, linux-kernel,
	y2038 Mailman List, Linux ARM

On Thu, Dec 12, 2019 at 11:17 AM Will Deacon <will@kernel.org> wrote:
>
> On Wed, Dec 11, 2019 at 09:42:35PM +0100, Arnd Bergmann wrote:
> > In order to use compat_* type defininitions in device drivers
> > outside of CONFIG_COMPAT, move the inclusion of asm-generic/compat.h
> > ahead of the #ifdef.
> >
> > All other architectures already do this.
> >
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> >  arch/arm64/include/asm/compat.h | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
>
> Acked-by: Will Deacon <will@kernel.org>

Thanks!

> (Please let me know if you'd prefer this patch to be routed via the arm64
> tree).

No, it needs to stay together with patch 02/24. The later patches in the
series are independent of those two though.

     Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h
@ 2019-12-12 10:41       ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 10:41 UTC (permalink / raw)
  To: Will Deacon
  Cc: Jens Axboe, Martin K. Petersen, y2038 Mailman List,
	Catalin Marinas, James E.J. Bottomley, linux-kernel,
	Alexander Viro, Linux ARM

On Thu, Dec 12, 2019 at 11:17 AM Will Deacon <will@kernel.org> wrote:
>
> On Wed, Dec 11, 2019 at 09:42:35PM +0100, Arnd Bergmann wrote:
> > In order to use compat_* type defininitions in device drivers
> > outside of CONFIG_COMPAT, move the inclusion of asm-generic/compat.h
> > ahead of the #ifdef.
> >
> > All other architectures already do this.
> >
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> >  arch/arm64/include/asm/compat.h | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
>
> Acked-by: Will Deacon <will@kernel.org>

Thanks!

> (Please let me know if you'd prefer this patch to be routed via the arm64
> tree).

No, it needs to stay together with patch 02/24. The later patches in the
series are independent of those two though.

     Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 24/24] Documentation: document ioctl interfaces better
  2019-12-11 21:05   ` Jonathan Corbet
@ 2019-12-12 10:56     ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 10:56 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-kernel, y2038 Mailman List,
	Mauro Carvalho Chehab, Jonathan Neuschäfer, Masahiro Yamada,
	Vladimir Oltean, Kent Overstreet, open list:DOCUMENTATION,
	Geert Uytterhoeven, Daniel Vetter

On Wed, Dec 11, 2019 at 10:05 PM Jonathan Corbet <corbet@lwn.net> wrote:
>
> On Wed, 11 Dec 2019 21:42:58 +0100
> Arnd Bergmann <arnd@arndb.de> wrote:
>
> > Documentation/process/botching-up-ioctls.rst was orignally
> > written as a blog post for DRM driver writers, so it it misses
> > some points while going into a lot of detail on others.
> >
> > Try to provide a replacement that addresses typical issues
> > across a wider range of subsystems, and follows the style of
> > the core-api documentation better.
> >
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>
> Thanks for improving the docs!  I have a few nits outside of the content
> itself.
>
> >  Documentation/core-api/index.rst |   1 +
> >  Documentation/core-api/ioctl.rst | 250 +++++++++++++++++++++++++++++++
> >  2 files changed, 251 insertions(+)
> >  create mode 100644 Documentation/core-api/ioctl.rst
>
> So you left the old document in place; was that intentional?

I wasn't quite sure what to do with it. It does have some points that
are relevant for drivers/gpu/drm that I did not cover in the new document.

Maybe Daniel has an idea for how the two documents can be combined
now, or the overlap reduced.

> > diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
> > index ab0eae1c153a..3f28b2f668be 100644
> > --- a/Documentation/core-api/index.rst
> > +++ b/Documentation/core-api/index.rst
> > @@ -39,6 +39,7 @@ Core utilities
> >     ../RCU/index
> >     gcc-plugins
> >     symbol-namespaces
> > +   ioctl
> >
> >
> >  Interfaces for kernel debugging
> > diff --git a/Documentation/core-api/ioctl.rst b/Documentation/core-api/ioctl.rst
> > new file mode 100644
> > index 000000000000..cb2c86ae63e7
> > --- /dev/null
> > +++ b/Documentation/core-api/ioctl.rst
> > @@ -0,0 +1,250 @@
> > +======================
> > +ioctl based interfaces
> > +======================
> > +
> > +:c:func:`ioctl` is the most common way for applications to interface
>
> Please don't use :c:func: anymore.  If you just say "ioctl()" the right
> thing will happen (which is nothing here, since there isn't anything that
> makes sense to link to in the internal kernel context).
>
> We need a checkpatch rule for :c:func: I guess.

Ok, fixed.

> Similarly, later on you have:
>
> > +Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
> > +as returned by ``ktime_get_ns()`` or ``ktime_get_ts64()``.  Unlike
> > +CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
> > +or forwards due to leap second adjustments and clock_settime() calls.
>
> Making those functions ``literal`` will defeat the automatic
> cross-referencing.  Better to just say ktime_get_ns() without quotes.

Ok, done.

Does this only work for function names, or should I also use a different way to
write ``include/uapi/asm-generic/ioctl.h`` or ``sizeof(size)`` and
``unsigned long``

> [...]
>
> > +* On the x86-32 (i386) architecture, the alignment of 64-bit variables
> > +  is only 32 bit, but they are naturally aligned on most other
> > +  architectures including x86-64. This means a structure like
> > +
> > +  ::
>
> You don't need the extra lines here; just say "...a structure like::"

Done. See below for changes I did relative to the feedback so far,
now squashed into the latest version.

Thanks for the review,

         Arnd

8<-----------
diff --git a/Documentation/core-api/ioctl.rst b/Documentation/core-api/ioctl.rst
index cb2c86ae63e7..2e70d3633883 100644
--- a/Documentation/core-api/ioctl.rst
+++ b/Documentation/core-api/ioctl.rst
@@ -2,7 +2,7 @@
 ioctl based interfaces
 ======================

-:c:func:`ioctl` is the most common way for applications to interface
+ioctl() is the most common way for applications to interface
 with device drivers. It is flexible and easily extended by adding new
 commands and can be passed through character devices, block devices as
 well as sockets and other special file descriptors.
@@ -20,19 +20,19 @@ identifies an action for a particular driver,
there are a number of
 conventions around defining them.

 ``include/uapi/asm-generic/ioctl.h`` provides four macros for defining
-ioctl commands that follow modern conventions: ``_IOC``, ``_IOR``,
+ioctl commands that follow modern conventions: ``_IO``, ``_IOR``,
 ``_IOW``, and ``_IORW``. These should be used for all new commands,
 with the correct parameters:

 _IO/_IOR/_IOW/_IOWR
    The macro name determines whether the argument is used for passing
    data into kernel (_IOW), from the kernel (_IOR), both (_IOWR) or is
-   not a pointer (_IOC). It is possible but not recommended to pass an
-   integer value instead of a pointer with _IOC.
+   not a pointer (_IO). It is possible but not recommended to pass an
+   integer value instead of a pointer with _IO.

 type
    An 8-bit number, often a character literal, specific to a subsystem
-   or driver, and listed in :doc:`../ioctl/ioctl-number`
+   or driver, and listed in :doc:`../userspace-api/ioctl/ioctl-number`

 nr
   An 8-bit number identifying the specific command, unique for a give
@@ -91,7 +91,7 @@ data structures when separate second/nanosecond
values are desired,
 or passed to user space directly. This is still not ideal though,
 as the structure matches neither the kernel's timespec64 nor the user
 space timespec exactly. The get_timespec64() and put_timespec64() helper
-functions canbe used to ensure that the layout remains compatible with
+functions can be used to ensure that the layout remains compatible with
 user space and the padding is treated correctly.

 As it is cheap to convert seconds to nanoseconds, but the opposite
@@ -99,13 +99,12 @@ requires an expensive 64-bit division, a simple
__u64 nanosecond value
 can be simpler and more efficient.

 Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
-as returned by ``ktime_get_ns()`` or ``ktime_get_ts64()``.  Unlike
+as returned by ktime_get_ns() or ktime_get_ts64().  Unlike
 CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
 or forwards due to leap second adjustments and clock_settime() calls.

-``ktime_get_real_ns()`` can be used for CLOCK_REALTIME timestamps that
-may be required for timestamps that need to be persistent across a reboot
-or between multiple machines.
+ktime_get_real_ns() can be used for CLOCK_REALTIME timestamps that
+need to be persistent across a reboot or between multiple machines.

 32-bit compat mode
 ==================
@@ -116,14 +115,14 @@ implement the corresponding compat_ioctl handler.

 As long as all the rules for data structures are followed, this is as
 easy as setting the .compat_ioctl pointer to a helper function such as
-``compat_ptr_ioctl()`` or ``blkdev_compat_ptr_ioctl``.
+compat_ptr_ioctl() or blkdev_compat_ptr_ioctl().

 compat_ptr()
 ------------

 On the s/390 architecture, 31-bit user space has ambiguous representations
 for data pointers, with the upper bit being ignored. When running such
-a process in compat mode, the ``compat_ptr()`` helper must be used to
+a process in compat mode, the compat_ptr() helper must be used to
 clear the upper bit of a compat_uptr_t and turn it into a valid 64-bit
 pointer.  On other architectures, this macro only performs a cast to a
 ``void __user *`` pointer.
@@ -150,16 +149,14 @@ avoiding all problematic members:
   ``__s64`` and ``__u64``.

 * Pointers have the same problem, in addition to requiring the
-  use of ``compat_ptr()``. The best workaround is to use ``__u64``
+  use of compat_ptr(). The best workaround is to use ``__u64``
   in place of pointers, which requires a cast to ``uintptr_t`` in user
-  space, and the use of ``u64_to_user_ptr()`` in the kernel to convert
+  space, and the use of u64_to_user_ptr() in the kernel to convert
   it back into a user pointer.

 * On the x86-32 (i386) architecture, the alignment of 64-bit variables
-  is only 32 bit, but they are naturally aligned on most other
-  architectures including x86-64. This means a structure like
-
-  ::
+  is only 32-bit, but they are naturally aligned on most other
+  architectures including x86-64. This means a structure like::

     struct foo {
         __u32 a;
@@ -177,9 +174,10 @@ avoiding all problematic members:

 * On ARM OABI user space, 16-bit member variables have 32-bit
   alignment, making them incompatible with modern EABI kernels.
-  Conversely, on the m68k architecture, all struct members have at most
-  16-bit alignment. These rarely cause problems as neither ARM-OABI nor
-  m68k are supported by any compat mode, but for consistency, it is best
+  Conversely, on the m68k architecture, struct members are not
+  guaranteed to have an alignment greater than 16-bit.
+  These rarely cause problems as neither ARM-OABI nor m68k are
+  supported by any compat mode, but for consistency, it is best
   to completely avoid 16-bit member variables.


@@ -198,10 +196,10 @@ Uninitialized data must not be copied back to
user space, as this can
 cause an information leak, which can be used to defeat kernel address
 space layout randomization (KASLR), helping in an attack.

-As explained for the compat mode, it is best to not avoid any padding in
-data structures, but if there is already padding in existing structures,
-the kernel driver must be careful to zero out the padding using
-``memset()`` or similar before copying it to user space.
+As explained for the compat mode, it is best to not avoid any implicit
+padding in data structures, but if there is already padding in existing
+structures, the kernel driver must be careful to zero out the padding
+using memset() or similar before copying it to user space.

 Subsystem abstractions
 ======================
@@ -218,7 +216,7 @@ This helps in various ways:
   another one in the same subsystem if there are no subtle differences
   in the user space ABI.

-* The complexity of user space access and data structure layout at done
+* The complexity of user space access and data structure layout is done
   in one place, reducing the potential for implementation bugs.

 * It is more likely to be reviewed by experienced developers
@@ -247,4 +245,4 @@ problem. Alternatives include
 * configfs can be used for more complex configuration than sysfs

 * A custom file system can provide extra flexibility with a simple
-  user interface but add a lot of complexity in the implementation.
+  user interface but add a lot of complexity to the implementation.

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* Re: [PATCH 24/24] Documentation: document ioctl interfaces better
  2019-12-12  8:16   ` Geert Uytterhoeven
@ 2019-12-12 11:04     ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 11:04 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Jonathan Corbet, Linux Kernel Mailing List,
	y2038 Mailman List, Mauro Carvalho Chehab,
	Jonathan Neuschäfer, Masahiro Yamada, Vladimir Oltean,
	Kent Overstreet, open list:DOCUMENTATION

On Thu, Dec 12, 2019 at 9:16 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Wed, Dec 11, 2019 at 9:53 PM Arnd Bergmann <arnd@arndb.de> wrote:
> > +``include/uapi/asm-generic/ioctl.h`` provides four macros for defining
> > +ioctl commands that follow modern conventions: ``_IOC``, ``_IOR``,
> > +``_IOW``, and ``_IORW``. These should be used for all new commands,
> > +with the correct parameters:
> > +
> > +_IO/_IOR/_IOW/_IOWR
>
> This says _IO....
>
> > +   The macro name determines whether the argument is used for passing
> > +   data into kernel (_IOW), from the kernel (_IOR), both (_IOWR) or is
>
> into the kernel
> , or is
>
> > +   not a pointer (_IOC). It is possible but not recommended to pass an
> > +   integer value instead of a pointer with _IOC.
>
> ...which is not explained here, but _IOC is?

I mean _IO() everywhere, I would consider _IOC an implementation
detail and not document that here.

s/_IOC/_IO/ throughout the document now.

> > +size
> > +  The name of the data type pointed to by the argument, the command
> > +  number encodes the ``sizeof(size)`` value in a 13-bit or 14-bit integer,
> > +  leading to a limit of 8191 bytes for the maximum size of the argument.
> > +  Note: do not pass sizeof(type) type into _IOR/IOW, as that will lead
> > +  to encoding sizeof(sizeof(type)), i.e. sizeof(size_t).
>
> Looks like "size" could be renamed, to make this more obvious?

Changed to data_type now, which is what I found in some other
documentation.


> > +space timespec exactly. The get_timespec64() and put_timespec64() helper
> > +functions canbe used to ensure that the layout remains compatible with
>
> can be

done.

> > +
> > +``ktime_get_real_ns()`` can be used for CLOCK_REALTIME timestamps that
> > +may be required for timestamps that need to be persistent across a reboot
>
> Drop "may be required for timestamps that"?

done.

> > +* ``long`` and ``unsigned long`` are the size of a register, so
> > +  they can be either 32 bit or 64 bit wide and cannot be used in portable
>
> 32-bit or 64-bit (for consistency with the rest of the document)

The convention I was trying to follow is to write

"32-bit userspace" or "32-bit processor"

but

"this type is 32 bit wide"

I wasn't consistent though, changed it now as you suggested.

> > +
> > +* On ARM OABI user space, 16-bit member variables have 32-bit
> > +  alignment, making them incompatible with modern EABI kernels.
> > +  Conversely, on the m68k architecture, all struct members have at most
> > +  16-bit alignment. These rarely cause problems as neither ARM-OABI nor
>
> "have at most 16-bit alignment" sounds a bit weird to me, as a member
> may have a greater alignment.
> "struct members are not guaranteed to have an alignment greater than 16-bit"?

done.

> > +
> > +As explained for the compat mode, it is best to not avoid any padding in
>
> best to avoid any implicit padding?

done.

> > +
> > +* The complexity of user space access and data structure layout at done
>
> is done

changed

> > +There are many cases in which ioctl is not the best solution for a
> > +problem. Alternatives include
>
> :

done

> > +* System calls are a better choice for a system-wide feature that
> > +  is not tied to a physical device or constrained by the file system
> > +  permissions of a character device node
> > +
> > +* netlink is the preferred way of configuring any network related
> > +  objects through sockets.
> > +
> > +* debugfs is used for ad-hoc interfaces for debugging functionality
> > +  that does not need to be exposed as a stable interface to applications.
> > +
> > +* sysfs is a good way to expose the state of an in-kernel object
> > +  that is not tied to a file descriptor.
> > +
> > +* configfs can be used for more complex configuration than sysfs
> > +
> > +* A custom file system can provide extra flexibility with a simple
> > +  user interface but add a lot of complexity in the implementation.
>
> adds ... to

done.

Thanks for all the suggestions!

      Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 02/24] compat: scsi: sg: fix v3 compat read/write interface
  2019-12-11 20:42 ` [PATCH 02/24] compat: scsi: sg: fix v3 compat read/write interface Arnd Bergmann
@ 2019-12-12 16:25   ` Christoph Hellwig
  2019-12-12 17:34     ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Christoph Hellwig @ 2019-12-12 16:25 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Douglas Gilbert, linux-kernel, y2038,
	Steffen Maier, linux-scsi, Chaitanya Kulkarni,
	Greg Kroah-Hartman, Thomas Gleixner, linux-block

On Wed, Dec 11, 2019 at 09:42:36PM +0100, Arnd Bergmann wrote:
> In the v5.4 merge window, a cleanup patch from Al Viro conflicted
> with my rework of the compat handling for sg.c read(). Linus Torvalds
> did a correct merge but pointed out that the resulting code is still
> unsatisfactory.
> 
> I later noticed that the sg_new_read() function still gets the compat
> mode wrong, when the 'count' argument is large enough to pass a
> compat_sg_io_hdr object, but not a nativ sg_io_hdr.
> 
> To address both of these, move the definition of compat_sg_io_hdr
> into a scsi/sg.h to make it visible to sg.c and rewrite the logic
> for reading req_pack_id as well as the size check to a simpler
> version that gets the expected results.
> 
> Fixes: c35a5cfb4150 ("scsi: sg: sg_read(): simplify reading ->pack_id of userland sg_io_hdr_t")
> Fixes: 98aaaec4a150 ("compat_ioctl: reimplement SG_IO handling")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  block/scsi_ioctl.c |  29 +----------
>  drivers/scsi/sg.c  | 125 +++++++++++++++++++++------------------------
>  include/scsi/sg.h  |  30 +++++++++++
>  3 files changed, 89 insertions(+), 95 deletions(-)
> 
> diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
> index 650bade5ea5a..b61dbf4d8443 100644
> --- a/block/scsi_ioctl.c
> +++ b/block/scsi_ioctl.c
> @@ -20,6 +20,7 @@
>  #include <scsi/scsi.h>
>  #include <scsi/scsi_ioctl.h>
>  #include <scsi/scsi_cmnd.h>
> +#include <scsi/sg.h>
>  
>  struct blk_cmd_filter {
>  	unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
> @@ -550,34 +551,6 @@ static inline int blk_send_start_stop(struct request_queue *q,
>  	return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
>  }
>  
> -#ifdef CONFIG_COMPAT
> -struct compat_sg_io_hdr {
> -	compat_int_t interface_id;	/* [i] 'S' for SCSI generic (required) */
> -	compat_int_t dxfer_direction;	/* [i] data transfer direction  */
> -	unsigned char cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
> -	unsigned char mx_sb_len;	/* [i] max length to write to sbp */
> -	unsigned short iovec_count;	/* [i] 0 implies no scatter gather */
> -	compat_uint_t dxfer_len;	/* [i] byte count of data transfer */
> -	compat_uint_t dxferp;		/* [i], [*io] points to data transfer memory
> -						or scatter gather list */
> -	compat_uptr_t cmdp;		/* [i], [*i] points to command to perform */
> -	compat_uptr_t sbp;		/* [i], [*o] points to sense_buffer memory */
> -	compat_uint_t timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
> -	compat_uint_t flags;		/* [i] 0 -> default, see SG_FLAG... */
> -	compat_int_t pack_id;		/* [i->o] unused internally (normally) */
> -	compat_uptr_t usr_ptr;		/* [i->o] unused internally */
> -	unsigned char status;		/* [o] scsi status */
> -	unsigned char masked_status;	/* [o] shifted, masked scsi status */
> -	unsigned char msg_status;	/* [o] messaging level data (optional) */
> -	unsigned char sb_len_wr;	/* [o] byte count actually written to sbp */
> -	unsigned short host_status;	/* [o] errors from host adapter */
> -	unsigned short driver_status;	/* [o] errors from software driver */
> -	compat_int_t resid;		/* [o] dxfer_len - actual_transferred */
> -	compat_uint_t duration;		/* [o] time taken by cmd (unit: millisec) */
> -	compat_uint_t info;		/* [o] auxiliary information */
> -};
> -#endif
> -
>  int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp)
>  {
>  #ifdef CONFIG_COMPAT
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 160748ad9c0f..985546aac236 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -198,6 +198,7 @@ static void sg_device_destroy(struct kref *kref);
>  
>  #define SZ_SG_HEADER sizeof(struct sg_header)
>  #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
> +#define SZ_COMPAT_SG_IO_HDR sizeof(struct compat_sg_io_hdr)

I'd rather not add more defines like this.  The raw sizeof is
much more readable and obvious.

>  
> +	if (count < SZ_SG_HEADER)
> +		goto unknown_id;
> +
> +	/* negative reply_len means v3 format, otherwise v1/v2 */
> +	if (get_user(reply_len, &old_hdr->reply_len))
> +		return -EFAULT;
> +	if (reply_len >= 0)
> +		return get_user(*pack_id, &old_hdr->pack_id);
> +
> +	if (in_compat_syscall() && count >= SZ_COMPAT_SG_IO_HDR) {
> +		struct compat_sg_io_hdr __user *hp = buf;
> +		return get_user(*pack_id, &hp->pack_id);
> +	}
> +
> +	if (count >= SZ_SG_IO_HDR) {
> +		struct sg_io_hdr __user *hp = buf;
> +		return get_user(*pack_id, &hp->pack_id);
> +	}
> +
> +unknown_id:
> +	/* no valid header was passed, so ignore the pack_id */
> +	*pack_id = -1;
> +	return 0;
> +}

I find the structure here a little confusing, as it doesn't follow
the normal flow.  What do you think of:

	if (count >= SZ_SG_HEADER) {
		if (get_user(reply_len, &old_hdr->reply_len))
			return -EFAULT;

		/* negative reply_len means v3 format, otherwise v1/v2 */
		if (reply_len >= 0)
			return get_user(*pack_id, &old_hdr->pack_id);

		if (in_compat_syscall() {
			if (count >= SZ_COMPAT_SG_IO_HDR) {
				struct compat_sg_io_hdr __user *hp = buf;

				return get_user(*pack_id, &hp->pack_id);
			}
		} else {
			if (count >= SZ_SG_IO_HDR) {
				struct sg_io_hdr __user *hp = buf;

				return get_user(*pack_id, &hp->pack_id);
			}
		}
	}

	/* no valid header was passed, so ignore the pack_id */
	*pack_id = -1;
	return 0;
}

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12  0:28     ` Paolo Bonzini
                         ` (3 preceding siblings ...)
  2019-12-12 10:27       ` Michael S. Tsirkin
@ 2019-12-12 16:27       ` Christoph Hellwig
  2019-12-12 16:35         ` Jens Axboe
  2019-12-12 16:35         ` Jens Axboe
  2019-12-12 16:27       ` Christoph Hellwig
  5 siblings, 2 replies; 64+ messages in thread
From: Christoph Hellwig @ 2019-12-12 16:27 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Michael S. Tsirkin, Arnd Bergmann, Jens Axboe,
	James E.J. Bottomley, Martin K. Petersen, Alexander Viro,
	Jason Wang, Doug Gilbert, Kai Mäkisara, linux-kernel, y2038,
	Stefan Hajnoczi, Bart Van Assche, Hannes Reinecke,
	Damien Le Moal, John Garry, virtualization, linux-block,
	linux-scsi, linux-fsdevel

On Thu, Dec 12, 2019 at 01:28:08AM +0100, Paolo Bonzini wrote:
> I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
> sense to lump it in with scsi, but I wouldn't mind getting rid of
> CONFIG_VIRTIO_BLK_SCSI altogether.

CONFIG_VIRTIO_BLK_SCSI has been broken for about two years, as it
never set the QUEUE_FLAG_SCSI_PASSTHROUGH flag after that was
introduced.  I actually have a patch that I plan to send to remove
this support as it was a really idea to start with (speaking as
the person who had that idea back in the day).

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12  0:28     ` Paolo Bonzini
                         ` (4 preceding siblings ...)
  2019-12-12 16:27       ` Christoph Hellwig
@ 2019-12-12 16:27       ` Christoph Hellwig
  5 siblings, 0 replies; 64+ messages in thread
From: Christoph Hellwig @ 2019-12-12 16:27 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Jens Axboe, Hannes Reinecke, Arnd Bergmann, Martin K. Petersen,
	Michael S. Tsirkin, y2038, Damien Le Moal, James E.J. Bottomley,
	John Garry, linux-kernel, Kai Mäkisara, linux-block,
	Alexander Viro, Stefan Hajnoczi, Doug Gilbert, linux-fsdevel,
	virtualization, linux-scsi, Bart Van Assche

On Thu, Dec 12, 2019 at 01:28:08AM +0100, Paolo Bonzini wrote:
> I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
> sense to lump it in with scsi, but I wouldn't mind getting rid of
> CONFIG_VIRTIO_BLK_SCSI altogether.

CONFIG_VIRTIO_BLK_SCSI has been broken for about two years, as it
never set the QUEUE_FLAG_SCSI_PASSTHROUGH flag after that was
introduced.  I actually have a patch that I plan to send to remove
this support as it was a really idea to start with (speaking as
the person who had that idea back in the day).

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 20/24] compat_ioctl: move HDIO ioctl handling into drivers/ide
  2019-12-11 20:42 ` [PATCH 20/24] compat_ioctl: move HDIO ioctl handling into drivers/ide Arnd Bergmann
@ 2019-12-12 16:29   ` Christoph Hellwig
  2019-12-12 17:21     ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Christoph Hellwig @ 2019-12-12 16:29 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Borislav Petkov, David S. Miller, linux-kernel,
	y2038, Hannes Reinecke, Heiko Carstens, linux-block, linux-ide

> +static int put_user_long(long val, unsigned long arg)
> +{
> +#ifdef CONFIG_COMPAT
> +	if (in_compat_syscall())
> +		return put_user(val, (compat_long_t __user *)compat_ptr(arg));
> +#endif
> +	return put_user(val, (long __user *)arg);
> +}

We had this

#ifdef CONFIG_COMPAT
	if (in_compat_syscall())
		...
	...
#endif

patter quite frequently.  Can we define a in_compat_syscall stub
and make sure compat_ptr and the compat_* types are available available
to clean this up a bit?

> -	if (NULL == (void *) arg) {
> +	if (NULL == argp) {

	if (!argp) {

?

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 21/24] compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
  2019-12-11 20:42 ` [PATCH 21/24] compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c Arnd Bergmann
@ 2019-12-12 16:30   ` Christoph Hellwig
  2019-12-12 17:24     ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Christoph Hellwig @ 2019-12-12 16:30 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-kernel, y2038, Tejun Heo, Jan Kara,
	Chaitanya Kulkarni, Dmitry Fomichev, Ajay Joshi, linux-block

> +#ifdef CONFIG_COMPAT
> +static int compat_put_ushort(unsigned long arg, unsigned short val)
> +{
> +	return put_user(val, (unsigned short __user *)compat_ptr(arg));
> +}
> +
> +static int compat_put_int(unsigned long arg, int val)
> +{
> +	return put_user(val, (compat_int_t __user *)compat_ptr(arg));
> +}
> +
> +static int compat_put_uint(unsigned long arg, unsigned int val)
> +{
> +	return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
> +}
> +
> +static int compat_put_long(unsigned long arg, long val)
> +{
> +	return put_user(val, (compat_long_t __user *)compat_ptr(arg));
> +}
> +
> +static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
> +{
> +	return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
> +}
> +
> +static int compat_put_u64(unsigned long arg, u64 val)
> +{
> +	return put_user(val, (compat_u64 __user *)compat_ptr(arg));
> +}
> +#endif

Can we lift these helpers to compat.h instead?

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12 16:27       ` Christoph Hellwig
  2019-12-12 16:35         ` Jens Axboe
@ 2019-12-12 16:35         ` Jens Axboe
  1 sibling, 0 replies; 64+ messages in thread
From: Jens Axboe @ 2019-12-12 16:35 UTC (permalink / raw)
  To: Christoph Hellwig, Paolo Bonzini
  Cc: Michael S. Tsirkin, Arnd Bergmann, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, Jason Wang, Doug Gilbert,
	Kai Mäkisara, linux-kernel, y2038, Stefan Hajnoczi,
	Bart Van Assche, Hannes Reinecke, Damien Le Moal, John Garry,
	virtualization, linux-block, linux-scsi, linux-fsdevel

On 12/12/19 9:27 AM, Christoph Hellwig wrote:
> On Thu, Dec 12, 2019 at 01:28:08AM +0100, Paolo Bonzini wrote:
>> I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
>> sense to lump it in with scsi, but I wouldn't mind getting rid of
>> CONFIG_VIRTIO_BLK_SCSI altogether.
> 
> CONFIG_VIRTIO_BLK_SCSI has been broken for about two years, as it
> never set the QUEUE_FLAG_SCSI_PASSTHROUGH flag after that was
> introduced.  I actually have a patch that I plan to send to remove
> this support as it was a really idea to start with (speaking as
> the person who had that idea back in the day).

We had this very discussion two years ago, and we never got it removed.
Let's please get it done.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers
  2019-12-12 16:27       ` Christoph Hellwig
@ 2019-12-12 16:35         ` Jens Axboe
  2019-12-12 16:35         ` Jens Axboe
  1 sibling, 0 replies; 64+ messages in thread
From: Jens Axboe @ 2019-12-12 16:35 UTC (permalink / raw)
  To: Christoph Hellwig, Paolo Bonzini
  Cc: Hannes Reinecke, Arnd Bergmann, Martin K. Petersen,
	Michael S. Tsirkin, y2038, Damien Le Moal, John Garry,
	linux-kernel, Kai Mäkisara, linux-block, Alexander Viro,
	Stefan Hajnoczi, Doug Gilbert, linux-fsdevel, virtualization,
	linux-scsi, James E.J. Bottomley, Bart Van Assche

On 12/12/19 9:27 AM, Christoph Hellwig wrote:
> On Thu, Dec 12, 2019 at 01:28:08AM +0100, Paolo Bonzini wrote:
>> I think it's because the only ioctl for virtio-blk is SG_IO.  It makes
>> sense to lump it in with scsi, but I wouldn't mind getting rid of
>> CONFIG_VIRTIO_BLK_SCSI altogether.
> 
> CONFIG_VIRTIO_BLK_SCSI has been broken for about two years, as it
> never set the QUEUE_FLAG_SCSI_PASSTHROUGH flag after that was
> introduced.  I actually have a patch that I plan to send to remove
> this support as it was a really idea to start with (speaking as
> the person who had that idea back in the day).

We had this very discussion two years ago, and we never got it removed.
Let's please get it done.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 20/24] compat_ioctl: move HDIO ioctl handling into drivers/ide
  2019-12-12 16:29   ` Christoph Hellwig
@ 2019-12-12 17:21     ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 17:21 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Borislav Petkov, David S. Miller, linux-kernel,
	y2038 Mailman List, Hannes Reinecke, Heiko Carstens, linux-block,
	IDE-ML

On Thu, Dec 12, 2019 at 5:29 PM Christoph Hellwig <hch@infradead.org> wrote:
>
> > +static int put_user_long(long val, unsigned long arg)
> > +{
> > +#ifdef CONFIG_COMPAT
> > +     if (in_compat_syscall())
> > +             return put_user(val, (compat_long_t __user *)compat_ptr(arg));
> > +#endif
> > +     return put_user(val, (long __user *)arg);
> > +}
>
> We had this
>
> #ifdef CONFIG_COMPAT
>         if (in_compat_syscall())
>                 ...
>         ...
> #endif
>
> patter quite frequently.  Can we define a in_compat_syscall stub
> and make sure compat_ptr and the compat_* types are available available
> to clean this up a bit?

in_compat_syscall() already has a reasonable stub, what was missing
when I created this series is the compat_long_t definition and
the compat_ptr() helper.

With patch 01/24, we can rely on the types, but I still need to add
a generic compat_ptr() implementation for non-s390 to remove the
#ifdef here.

That is probably a good idea anyway, it just needs a bit of testing.
The last time I tried this, I ran into problems with the order of compat
header inclusions on some architectures.

I've made a prototype now, will see how it goes.

> > -     if (NULL == (void *) arg) {
> > +     if (NULL == argp) {
>
>         if (!argp) {
>
> ?

changed now.

      Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 21/24] compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
  2019-12-12 16:30   ` Christoph Hellwig
@ 2019-12-12 17:24     ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 17:24 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-kernel, y2038 Mailman List, Tejun Heo,
	Jan Kara, Chaitanya Kulkarni, Dmitry Fomichev, Ajay Joshi,
	linux-block

On Thu, Dec 12, 2019 at 5:30 PM Christoph Hellwig <hch@infradead.org> wrote:
>
> > +#ifdef CONFIG_COMPAT
> > +static int compat_put_ushort(unsigned long arg, unsigned short val)
> > +{
> > +     return put_user(val, (unsigned short __user *)compat_ptr(arg));
> > +}
> > +
> > +static int compat_put_int(unsigned long arg, int val)
> > +{
> > +     return put_user(val, (compat_int_t __user *)compat_ptr(arg));
> > +}
> > +
> > +static int compat_put_uint(unsigned long arg, unsigned int val)
> > +{
> > +     return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
> > +}
> > +
> > +static int compat_put_long(unsigned long arg, long val)
> > +{
> > +     return put_user(val, (compat_long_t __user *)compat_ptr(arg));
> > +}
> > +
> > +static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
> > +{
> > +     return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
> > +}
> > +
> > +static int compat_put_u64(unsigned long arg, u64 val)
> > +{
> > +     return put_user(val, (compat_u64 __user *)compat_ptr(arg));
> > +}
> > +#endif
>
> Can we lift these helpers to compat.h instead?

Nothing else uses them, and it's usually more readable to just
use put_user directly.

Note that the next patch removes most of them anyway, but
we could have another cleanup that removes the
put_int()/put_long()/etc from block/ioctl.c altogether.

       Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 02/24] compat: scsi: sg: fix v3 compat read/write interface
  2019-12-12 16:25   ` Christoph Hellwig
@ 2019-12-12 17:34     ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-12 17:34 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, Douglas Gilbert, linux-kernel,
	y2038 Mailman List, Steffen Maier, linux-scsi,
	Chaitanya Kulkarni, Greg Kroah-Hartman, Thomas Gleixner,
	linux-block

On Thu, Dec 12, 2019 at 5:25 PM Christoph Hellwig <hch@infradead.org> wrote:
> On Wed, Dec 11, 2019 at 09:42:36PM +0100, Arnd Bergmann wrote:

> > --- a/drivers/scsi/sg.c
> > +++ b/drivers/scsi/sg.c
> > @@ -198,6 +198,7 @@ static void sg_device_destroy(struct kref *kref);
> >
> >  #define SZ_SG_HEADER sizeof(struct sg_header)
> >  #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
> > +#define SZ_COMPAT_SG_IO_HDR sizeof(struct compat_sg_io_hdr)
>
> I'd rather not add more defines like this.  The raw sizeof is
> much more readable and obvious.

Done. I actually had it that way in the previous submission and then changed
it for consistency. I considered removing SZ_SG_IO_HDR as well,
but decided not to make Doug's life harder than necessary -- he has nother
50 or so patches on top of this that he needs to rebase.

> I find the structure here a little confusing, as it doesn't follow
> the normal flow.  What do you think of:
>
>         if (count >= SZ_SG_HEADER) {
>                 if (get_user(reply_len, &old_hdr->reply_len))
>                         return -EFAULT;

I don't see much benefit either way. Changed it now it as you suggested.

Thanks for the review!

      Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Y2038] [PATCH 10/24] compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN
  2019-12-11 20:42 ` [PATCH 10/24] compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN Arnd Bergmann
@ 2019-12-17 15:20   ` Ben Hutchings
  2019-12-17 21:38     ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Ben Hutchings @ 2019-12-17 15:20 UTC (permalink / raw)
  To: Arnd Bergmann, Jens Axboe, James E.J. Bottomley,
	Martin K. Petersen, Alexander Viro, linux-block
  Cc: Jonathan Corbet, y2038, linux-kernel, Diego Elio Pettenò,
	Hannes Reinecke, Mauro Carvalho Chehab, Martin Wilck,
	Guenter Roeck

On Wed, 2019-12-11 at 21:42 +0100, Arnd Bergmann wrote:
> This is the only ioctl command that does not have a proper
> compat handler. Making the normal implementation do the
> right thing is actually very simply, so just do that by
> using an in_compat_syscall() check to avoid the special
> case in the pkcdvd driver.
[...]

Since this uses blkdev_compat_ptr_ioctl() it needs to be moved after
the following patch.

Ben.

-- 
Ben Hutchings, Software Developer                         Codethink Ltd
https://www.codethink.co.uk/                 Dale House, 35 Dale Street
                                     Manchester, M1 2HF, United Kingdom


^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Y2038] [PATCH 10/24] compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN
  2019-12-17 15:20   ` [Y2038] " Ben Hutchings
@ 2019-12-17 21:38     ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2019-12-17 21:38 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: Jens Axboe, James E.J. Bottomley, Martin K. Petersen,
	Alexander Viro, linux-block, Jonathan Corbet, y2038 Mailman List,
	linux-kernel, Diego Elio Pettenò,
	Hannes Reinecke, Mauro Carvalho Chehab, Martin Wilck,
	Guenter Roeck

On Tue, Dec 17, 2019 at 4:20 PM Ben Hutchings
<ben.hutchings@codethink.co.uk> wrote:
>
> On Wed, 2019-12-11 at 21:42 +0100, Arnd Bergmann wrote:
> > This is the only ioctl command that does not have a proper
> > compat handler. Making the normal implementation do the
> > right thing is actually very simply, so just do that by
> > using an in_compat_syscall() check to avoid the special
> > case in the pkcdvd driver.
> [...]
>
> Since this uses blkdev_compat_ptr_ioctl() it needs to be moved after
> the following patch.
>

Ah right, I obviously reshuffled my patches too much to end up
with the most reasonable order and avoid introducing something
that would be removed again later.

I'll split out the addition of blkdev_compat_ptr_ioctl() into a separate
patch and move that all in front, as I'm no longer sure if there
was another dependency in the other way.

Thanks!

        Arnd

^ permalink raw reply	[flat|nested] 64+ messages in thread

end of thread, other threads:[~2019-12-17 21:39 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-11 20:42 [PATCH 00/24] block, scsi: final compat_ioctl cleanup Arnd Bergmann
2019-12-11 20:42 ` [Xen-devel] " Arnd Bergmann
2019-12-11 20:42 ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 01/24] compat: ARM64: always include asm-generic/compat.h Arnd Bergmann
2019-12-11 20:42   ` Arnd Bergmann
2019-12-12 10:16   ` Will Deacon
2019-12-12 10:16     ` Will Deacon
2019-12-12 10:41     ` Arnd Bergmann
2019-12-12 10:41       ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 02/24] compat: scsi: sg: fix v3 compat read/write interface Arnd Bergmann
2019-12-12 16:25   ` Christoph Hellwig
2019-12-12 17:34     ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 03/24] compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE Arnd Bergmann
2019-12-12  1:20   ` Damien Le Moal
2019-12-11 20:42 ` [PATCH 04/24] compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES Arnd Bergmann
2019-12-12  1:20   ` Damien Le Moal
2019-12-11 20:42 ` [PATCH 05/24] compat_ioctl: block: handle add zone open, close and finish ioctl Arnd Bergmann
2019-12-12  1:20   ` Damien Le Moal
2019-12-11 20:42 ` [PATCH 06/24] compat_ioctl: block: handle Persistent Reservations Arnd Bergmann
2019-12-11 20:42 ` [PATCH 07/24] compaT_ioctl: ubd, aoe: use blkdev_compat_ptr_ioctl Arnd Bergmann
2019-12-11 20:42   ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 08/24] compat_ioctl: move CDROM_SEND_PACKET handling into scsi Arnd Bergmann
2019-12-11 20:42 ` [PATCH 09/24] compat_ioctl: move CDROMREADADIO to cdrom.c Arnd Bergmann
2019-12-11 20:42 ` [PATCH 10/24] compat_ioctl: cdrom: handle CDROM_LAST_WRITTEN Arnd Bergmann
2019-12-17 15:20   ` [Y2038] " Ben Hutchings
2019-12-17 21:38     ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 11/24] compat_ioctl: block: handle cdrom compat ioctl in non-cdrom drivers Arnd Bergmann
2019-12-11 20:42   ` [Xen-devel] " Arnd Bergmann
2019-12-11 20:42 ` [PATCH 12/24] compat_ioctl: add scsi_compat_ioctl Arnd Bergmann
2019-12-11 20:42 ` [PATCH 13/24] compat_ioctl: bsg: add handler Arnd Bergmann
2019-12-11 20:42 ` [PATCH 14/24] compat_ioctl: ide: floppy: " Arnd Bergmann
2019-12-11 20:42 ` [PATCH 15/24] compat_ioctl: scsi: move ioctl handling into drivers Arnd Bergmann
2019-12-11 23:05   ` Michael S. Tsirkin
2019-12-12  0:28     ` Paolo Bonzini
2019-12-12  0:28     ` Paolo Bonzini
2019-12-12  9:17       ` Arnd Bergmann
2019-12-12  9:17       ` Arnd Bergmann
2019-12-12 10:27       ` Michael S. Tsirkin
2019-12-12 10:27       ` Michael S. Tsirkin
2019-12-12 16:27       ` Christoph Hellwig
2019-12-12 16:35         ` Jens Axboe
2019-12-12 16:35         ` Jens Axboe
2019-12-12 16:27       ` Christoph Hellwig
2019-12-11 23:05   ` Michael S. Tsirkin
2019-12-12 10:25   ` Michael S. Tsirkin
2019-12-12 10:25     ` Michael S. Tsirkin
2019-12-11 20:42 ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 16/24] compat_ioctl: move sys_compat_ioctl() to ioctl.c Arnd Bergmann
2019-12-11 20:42 ` [PATCH 17/24] compat_ioctl: simplify the implementation Arnd Bergmann
2019-12-11 20:42 ` [PATCH 18/24] compat_ioctl: move cdrom commands into cdrom.c Arnd Bergmann
2019-12-11 20:42 ` [PATCH 19/24] compat_ioctl: scsi: handle HDIO commands from drivers Arnd Bergmann
2019-12-11 20:42 ` [PATCH 20/24] compat_ioctl: move HDIO ioctl handling into drivers/ide Arnd Bergmann
2019-12-12 16:29   ` Christoph Hellwig
2019-12-12 17:21     ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 21/24] compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c Arnd Bergmann
2019-12-12 16:30   ` Christoph Hellwig
2019-12-12 17:24     ` Arnd Bergmann
2019-12-11 20:42 ` [PATCH 22/24] compat_ioctl: block: simplify compat_blkpg_ioctl() Arnd Bergmann
2019-12-11 20:42 ` [PATCH 23/24] compat_ioctl: simplify up block/ioctl.c Arnd Bergmann
2019-12-11 20:42 ` [PATCH 24/24] Documentation: document ioctl interfaces better Arnd Bergmann
2019-12-11 21:05   ` Jonathan Corbet
2019-12-12 10:56     ` Arnd Bergmann
2019-12-12  8:16   ` Geert Uytterhoeven
2019-12-12 11:04     ` Arnd Bergmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.