block, scsi: final compat_ioctl cleanup

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. Actually moving handlers out of block/compat_ioctl.c and
    block/scsi_ioctl.c into drivers, mixed in with cleanup
    patches
 
 3. Document how to do this right. I keep getting asked about this,
    and it helps to point to some documentation file.
 
 The branch is based on another one that fixes a couple of bugs found
 during the creation of this series.
 
 Changes since v3:
   https://lore.kernel.org/lkml/20200102145552.1853992-1-arnd@arndb.de/
 
 - Move sr_compat_ioctl fixup to correct patch (Ben Hutchings)
 - Add Reviewed-by tags
 
 Changes since v2:
   https://lore.kernel.org/lkml/20191217221708.3730997-1-arnd@arndb.de/
 
 - Rebase to v5.5-rc4, which contains the earlier bugfixes
 - Fix sr_block_compat_ioctl() error handling bug found by
   Ben Hutchings
 - Fix idecd_locked_compat_ioctl() compat_ptr() bug
 - Don't try to handle HDIO_DRIVE_TASKFILE in drivers/ide
 - More documentation improvements
 
 Changes since v1:
   https://lore.kernel.org/lkml/20191211204306.1207817-1-arnd@arndb.de/
 
 - move out the bugfixes into a branch for itself
 - clean up scsi sg driver further as suggested by Christoph Hellwig
 - avoid some ifdefs by moving compat_ptr() out of asm/compat.h
 - split out the blkdev_compat_ptr_ioctl function; bug spotted by
   Ben Hutchings
 - Improve formatting of documentation
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJeDv8JAAoJEGCrR//JCVInh/oP/2BHdQvWONxwXXg2BLH7OJHm
 4PFoblxjNH/pwHm2PKh2uj8vUSgTHqID7NJChVgKZaZEJEJR7h26Sx60p+yTAepR
 /ysQiGameacJu2ZzKPYc4/S33Yu8cogQ5+DSz7mI9T5Yw0HSAE0JZ5xd9KIZ+/u8
 6k65ujd9kCxCgmtXrpx+7JFF0xb+urXKCvjdt2EfQ1ZmuMX5rDG/bTNg5JJ50shW
 vb7Z8hCpfW61ux8M/dgIh4WvUf0SA7FOy8WF1Km9gNhKGj41Arb2lmX1Jb4jDgjl
 DGsXQupyMVwigp5N37H3o1MamX/C8S49c16/zJQcJj64xX7WdxhE5kR8JIf+36Tf
 2l4wpaqVukXPvXkdv76Y472fKoOMZATF6kCoEPG3gXW9oxXDs5d2ofALfO3uNfLB
 PC4hzorw6bBlt67qAqERft2cxMMi9xSYfYZ8jD+eSF8WLL7xIcEazZqq8dKz7O00
 Qqx6+jzejT18av7cPfLjnupZg+mEcxDbPeuCgjrbhR8lcUI4DBu379RiTaQanvyR
 W00zwqCZWYnNJoha8u3AKsRcfL8eziF+/K9k+lCuhXeQBI4ipFJ03wAD4TWCigCS
 N7AikOdLzGVxE+2IfeCXPDKpdT6hFnjulnyDEgc/7jwHzcVF3MQBHwXiKhWHEUvT
 /AzAtKAiivp+uaMgAbzd
 =cddL
 -----END PGP SIGNATURE-----

Merge tag 'block-ioctl-cleanup-5.6' into 5.6/scsi-queue

Pull compat_ioctl cleanup from Arnd. Here's his description:

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. Actually moving handlers out of block/compat_ioctl.c and
   block/scsi_ioctl.c into drivers, mixed in with cleanup
   patches

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

The branch is based on another one that fixes a couple of bugs found
during the creation of this series.

Changes since v3:
  https://lore.kernel.org/lkml/20200102145552.1853992-1-arnd@arndb.de/

- Move sr_compat_ioctl fixup to correct patch (Ben Hutchings)
- Add Reviewed-by tags

Changes since v2:
  https://lore.kernel.org/lkml/20191217221708.3730997-1-arnd@arndb.de/

- Rebase to v5.5-rc4, which contains the earlier bugfixes
- Fix sr_block_compat_ioctl() error handling bug found by
  Ben Hutchings
- Fix idecd_locked_compat_ioctl() compat_ptr() bug
- Don't try to handle HDIO_DRIVE_TASKFILE in drivers/ide
- More documentation improvements

Changes since v1:
  https://lore.kernel.org/lkml/20191211204306.1207817-1-arnd@arndb.de/

- move out the bugfixes into a branch for itself
- clean up scsi sg driver further as suggested by Christoph Hellwig
- avoid some ifdefs by moving compat_ptr() out of asm/compat.h
- split out the blkdev_compat_ptr_ioctl function; bug spotted by
  Ben Hutchings
- Improve formatting of documentation

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Martin K. Petersen 2020-01-10 00:14:46 -05:00
commit 1c46a2cf2d
685 changed files with 8579 additions and 4706 deletions

View File

@ -152,6 +152,7 @@ Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com>
Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
Marc Zyngier <maz@kernel.org> <marc.zyngier@arm.com>
Marcin Nowakowski <marcin.nowakowski@mips.com> <marcin.nowakowski@imgtec.com>
@ -265,6 +266,7 @@ Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
Vivien Didelot <vivien.didelot@gmail.com> <vivien.didelot@savoirfairelinux.com>
Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>

View File

@ -1,4 +1,4 @@
What: /sys/bus/platform/devices/MLNXBF04:00/driver/lifecycle_state
What: /sys/bus/platform/devices/MLNXBF04:00/lifecycle_state
Date: Oct 2019
KernelVersion: 5.5
Contact: "Liming Sun <lsun@mellanox.com>"
@ -10,7 +10,7 @@ Description:
GA Non-Secured - Non-Secure chip and not able to change state
RMA - Return Merchandise Authorization
What: /sys/bus/platform/devices/MLNXBF04:00/driver/post_reset_wdog
What: /sys/bus/platform/devices/MLNXBF04:00/post_reset_wdog
Date: Oct 2019
KernelVersion: 5.5
Contact: "Liming Sun <lsun@mellanox.com>"
@ -19,7 +19,7 @@ Description:
to reboot the chip and recover it to the old state if the new
boot partition fails.
What: /sys/bus/platform/devices/MLNXBF04:00/driver/reset_action
What: /sys/bus/platform/devices/MLNXBF04:00/reset_action
Date: Oct 2019
KernelVersion: 5.5
Contact: "Liming Sun <lsun@mellanox.com>"
@ -30,7 +30,7 @@ Description:
emmc - boot from the onchip eMMC
emmc_legacy - boot from the onchip eMMC in legacy (slow) mode
What: /sys/bus/platform/devices/MLNXBF04:00/driver/second_reset_action
What: /sys/bus/platform/devices/MLNXBF04:00/second_reset_action
Date: Oct 2019
KernelVersion: 5.5
Contact: "Liming Sun <lsun@mellanox.com>"
@ -44,7 +44,7 @@ Description:
swap_emmc - swap the primary / secondary boot partition
none - cancel the action
What: /sys/bus/platform/devices/MLNXBF04:00/driver/secure_boot_fuse_state
What: /sys/bus/platform/devices/MLNXBF04:00/secure_boot_fuse_state
Date: Oct 2019
KernelVersion: 5.5
Contact: "Liming Sun <lsun@mellanox.com>"

View File

@ -181,14 +181,17 @@ When mounting an ext4 filesystem, the following option are accepted:
system after its metadata has been committed to the journal.
commit=nrsec (*)
Ext4 can be told to sync all its data and metadata every 'nrsec'
seconds. The default value is 5 seconds. This means that if you lose
your power, you will lose as much as the latest 5 seconds of work (your
filesystem will not be damaged though, thanks to the journaling). This
default value (or any low value) will hurt performance, but it's good
for data-safety. Setting it to 0 will have the same effect as leaving
it at the default (5 seconds). Setting it to very large values will
improve performance.
This setting limits the maximum age of the running transaction to
'nrsec' seconds. The default value is 5 seconds. This means that if
you lose your power, you will lose as much as the latest 5 seconds of
metadata changes (your filesystem will not be damaged though, thanks
to the journaling). This default value (or any low value) will hurt
performance, but it's good for data-safety. Setting it to 0 will have
the same effect as leaving it at the default (5 seconds). Setting it
to very large values will improve performance. Note that due to
delayed allocation even older data can be lost on power failure since
writeback of those data begins only after time set in
/proc/sys/vm/dirty_expire_centisecs.
barrier=<0|1(*)>, barrier(*), nobarrier
This enables/disables the use of write barriers in the jbd code.

View File

@ -253,7 +253,7 @@ The following sysctls are available for the XFS filesystem:
pool.
fs.xfs.speculative_prealloc_lifetime
(Units: seconds Min: 1 Default: 300 Max: 86400)
(Units: seconds Min: 1 Default: 300 Max: 86400)
The interval at which the background scanning for inodes
with unused speculative preallocation runs. The scan
removes unused preallocation from clean inodes and releases

View File

@ -39,6 +39,7 @@ Core utilities
../RCU/index
gcc-plugins
symbol-namespaces
ioctl
Interfaces for kernel debugging

View File

@ -0,0 +1,253 @@
======================
ioctl based interfaces
======================
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: ``_IO``, ``_IOR``,
``_IOW``, and ``_IOWR``. These should be used for all new commands,
with the correct parameters:
_IO/_IOR/_IOW/_IOWR
The macro name specifies how the argument will be used.  It may be a
pointer to data to be passed into the kernel (_IOW), out of the kernel
(_IOR), or both (_IOWR).  _IO can indicate either commands with no
argument or those passing an integer value instead of a pointer.
It is recommended to only use _IO for commands without arguments,
and use pointers for passing data.
type
An 8-bit number, often a character literal, specific to a subsystem
or driver, and listed in :doc:`../userspace-api/ioctl/ioctl-number`
nr
An 8-bit number identifying the specific command, unique for a give
value of 'type'
data_type
The name of the data type pointed to by the argument, the command number
encodes the ``sizeof(data_type)`` 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(data_type) type into _IOR/_IOW/IOWR, as that
will lead to encoding sizeof(sizeof(data_type)), i.e. sizeof(size_t).
_IO does not have a data_type parameter.
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 ``struct __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 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
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
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 s390 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. The ``pahole`` tool can be used for checking the
alignment.
* On ARM OABI user space, structures are padded to multiples of 32-bit,
making some structs incompatible with modern EABI kernels if they
do not end on a 32-bit boundary.
* On the m68k architecture, struct members are not guaranteed to have an
alignment greater than 16-bit, which is a problem when relying on
implicit padding.
* 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.
For this reason (and for compat support) it is best to avoid any
implicit padding in data structures.  Where there is implicit padding
in an existing structure, kernel drivers must be careful to fully
initialize an instance of the structure before copying it to user
space.  This is usually done by calling memset() before assigning to
individual members.
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 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 adds a lot of complexity to the implementation.

View File

@ -203,12 +203,12 @@ Test Module
Kselftest tests the kernel from userspace. Sometimes things need
testing from within the kernel, one method of doing this is to create a
test module. We can tie the module into the kselftest framework by
using a shell script test runner. ``kselftest_module.sh`` is designed
using a shell script test runner. ``kselftest/module.sh`` is designed
to facilitate this process. There is also a header file provided to
assist writing kernel modules that are for use with kselftest:
- ``tools/testing/kselftest/kselftest_module.h``
- ``tools/testing/kselftest/kselftest_module.sh``
- ``tools/testing/kselftest/kselftest/module.sh``
How to use
----------
@ -247,7 +247,7 @@ A bare bones test module might look like this:
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "../tools/testing/selftests/kselftest_module.h"
#include "../tools/testing/selftests/kselftest/module.h"
KSTM_MODULE_GLOBALS();
@ -276,7 +276,7 @@ Example test script
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0+
$(dirname $0)/../kselftest_module.sh "foo" test_foo
$(dirname $0)/../kselftest/module.sh "foo" test_foo
Test Harness

View File

@ -9,6 +9,7 @@ KUnit - Unit Testing for the Linux Kernel
start
usage
kunit-tool
api/index
faq

View File

@ -0,0 +1,57 @@
.. SPDX-License-Identifier: GPL-2.0
=================
kunit_tool How-To
=================
What is kunit_tool?
===================
kunit_tool is a script (``tools/testing/kunit/kunit.py``) that aids in building
the Linux kernel as UML (`User Mode Linux
<http://user-mode-linux.sourceforge.net/>`_), running KUnit tests, parsing
the test results and displaying them in a user friendly manner.
What is a kunitconfig?
======================
It's just a defconfig that kunit_tool looks for in the base directory.
kunit_tool uses it to generate a .config as you might expect. In addition, it
verifies that the generated .config contains the CONFIG options in the
kunitconfig; the reason it does this is so that it is easy to be sure that a
CONFIG that enables a test actually ends up in the .config.
How do I use kunit_tool?
========================
If a kunitconfig is present at the root directory, all you have to do is:
.. code-block:: bash
./tools/testing/kunit/kunit.py run
However, you most likely want to use it with the following options:
.. code-block:: bash
./tools/testing/kunit/kunit.py run --timeout=30 --jobs=`nproc --all`
- ``--timeout`` sets a maximum amount of time to allow tests to run.
- ``--jobs`` sets the number of threads to use to build the kernel.
If you just want to use the defconfig that ships with the kernel, you can
append the ``--defconfig`` flag as well:
.. code-block:: bash
./tools/testing/kunit/kunit.py run --timeout=30 --jobs=`nproc --all` --defconfig
.. note::
This command is particularly helpful for getting started because it
just works. No kunitconfig needs to be present.
For a list of all the flags supported by kunit_tool, you can run:
.. code-block:: bash
./tools/testing/kunit/kunit.py run --help

View File

@ -19,21 +19,21 @@ The wrapper can be run with:
.. code-block:: bash
./tools/testing/kunit/kunit.py run
./tools/testing/kunit/kunit.py run --defconfig
Creating a kunitconfig
======================
The Python script is a thin wrapper around Kbuild as such, it needs to be
configured with a ``kunitconfig`` file. This file essentially contains the
For more information on this wrapper (also called kunit_tool) checkout the
:doc:`kunit-tool` page.
Creating a .kunitconfig
=======================
The Python script is a thin wrapper around Kbuild. As such, it needs to be
configured with a ``.kunitconfig`` file. This file essentially contains the
regular Kernel config, with the specific test targets as well.
.. code-block:: bash
git clone -b master https://kunit.googlesource.com/kunitconfig $PATH_TO_KUNITCONFIG_REPO
cd $PATH_TO_LINUX_REPO
ln -s $PATH_TO_KUNIT_CONFIG_REPO/kunitconfig kunitconfig
You may want to add kunitconfig to your local gitignore.
cp arch/um/configs/kunit_defconfig .kunitconfig
Verifying KUnit Works
---------------------
@ -59,8 +59,8 @@ If everything worked correctly, you should see the following:
followed by a list of tests that are run. All of them should be passing.
.. note::
Because it is building a lot of sources for the first time, the ``Building
kunit kernel`` step may take a while.
Because it is building a lot of sources for the first time, the
``Building KUnit kernel`` step may take a while.
Writing your first test
=======================
@ -148,7 +148,7 @@ and the following to ``drivers/misc/Makefile``:
obj-$(CONFIG_MISC_EXAMPLE_TEST) += example-test.o
Now add it to your ``kunitconfig``:
Now add it to your ``.kunitconfig``:
.. code-block:: none
@ -159,7 +159,7 @@ Now you can run the test:
.. code-block:: bash
./tools/testing/kunit/kunit.py
./tools/testing/kunit/kunit.py run
You should see the following failure:

View File

@ -16,7 +16,7 @@ Organization of this document
=============================
This document is organized into two main sections: Testing and Isolating
Behavior. The first covers what a unit test is and how to use KUnit to write
Behavior. The first covers what unit tests are and how to use KUnit to write
them. The second covers how to use KUnit to isolate code and make it possible
to unit test code that was otherwise un-unit-testable.
@ -174,13 +174,13 @@ Test Suites
~~~~~~~~~~~
Now obviously one unit test isn't very helpful; the power comes from having
many test cases covering all of your behaviors. Consequently it is common to
have many *similar* tests; in order to reduce duplication in these closely
related tests most unit testing frameworks provide the concept of a *test
suite*, in KUnit we call it a *test suite*; all it is is just a collection of
test cases for a unit of code with a set up function that gets invoked before
every test cases and then a tear down function that gets invoked after every
test case completes.
many test cases covering all of a unit's behaviors. Consequently it is common
to have many *similar* tests; in order to reduce duplication in these closely
related tests most unit testing frameworks - including KUnit - provide the
concept of a *test suite*. A *test suite* is just a collection of test cases
for a unit of code with a set up function that gets invoked before every test
case and then a tear down function that gets invoked after every test case
completes.
Example:
@ -211,7 +211,7 @@ KUnit test framework.
.. note::
A test case will only be run if it is associated with a test suite.
For a more information on these types of things see the :doc:`api/test`.
For more information on these types of things see the :doc:`api/test`.
Isolating Behavior
==================
@ -338,7 +338,7 @@ We can easily test this code by *faking out* the underlying EEPROM:
return count;
}
ssize_t fake_eeprom_write(struct eeprom *this, size_t offset, const char *buffer, size_t count)
ssize_t fake_eeprom_write(struct eeprom *parent, size_t offset, const char *buffer, size_t count)
{
struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);
@ -454,7 +454,7 @@ KUnit on non-UML architectures
By default KUnit uses UML as a way to provide dependencies for code under test.
Under most circumstances KUnit's usage of UML should be treated as an
implementation detail of how KUnit works under the hood. Nevertheless, there
are instances where being able to run architecture specific code, or test
are instances where being able to run architecture specific code or test
against real hardware is desirable. For these reasons KUnit supports running on
other architectures.
@ -557,7 +557,7 @@ run your tests on your hardware setup just by compiling for your architecture.
.. important::
Always prefer tests that run on UML to tests that only run under a particular
architecture, and always prefer tests that run under QEMU or another easy
(and monitarily free) to obtain software environment to a specific piece of
(and monetarily free) to obtain software environment to a specific piece of
hardware.
Nevertheless, there are still valid reasons to write an architecture or hardware

View File

@ -10,7 +10,6 @@ Required properties:
- #size-cells: 0
- spi-max-frequency: Maximum frequency of the SPI bus the chip can
operate at should be less than or equal to 18 MHz.
- device-wake-gpios: Wake up GPIO to wake up the TCAN device.
- interrupt-parent: the phandle to the interrupt controller which provides
the interrupt.
- interrupts: interrupt specification for data-ready.
@ -23,6 +22,7 @@ Optional properties:
reset.
- device-state-gpios: Input GPIO that indicates if the device is in
a sleep state or if the device is active.
- device-wake-gpios: Wake up GPIO to wake up the TCAN device.
Example:
tcan4x5x: tcan4x5x@0 {
@ -36,5 +36,5 @@ tcan4x5x: tcan4x5x@0 {
interrupts = <14 GPIO_ACTIVE_LOW>;
device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
};

View File

@ -347,6 +347,7 @@ allOf:
- st,spear600-gmac
then:
properties:
snps,tso:
$ref: /schemas/types.yaml#definitions/flag
description:

View File

@ -22,6 +22,6 @@ Example:
};
&ethernet_switch {
resets = <&reset>;
resets = <&reset 26>;
reset-names = "switch";
};

View File

@ -196,14 +196,11 @@ applicable everywhere (see syntax).
or equal to the first symbol and smaller than or equal to the second
symbol.
- help text: "help" or "---help---"
- help text: "help"
This defines a help text. The end of the help text is determined by
the indentation level, this means it ends at the first line which has
a smaller indentation than the first line of the help text.
"---help---" and "help" do not differ in behaviour, "---help---" is
used to help visually separate configuration logic from help within
the file as an aid to developers.
- misc options: "option" <symbol>[=<value>]

View File

@ -297,9 +297,19 @@ more details, with real examples.
If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (modular)
the corresponding obj- variable will be set, and kbuild will descend
down in the ext2 directory.
Kbuild only uses this information to decide that it needs to visit
the directory, it is the Makefile in the subdirectory that
specifies what is modular and what is built-in.
Kbuild uses this information not only to decide that it needs to visit
the directory, but also to decide whether or not to link objects from
the directory into vmlinux.
When Kbuild descends into the directory with 'y', all built-in objects
from that directory are combined into the built-in.a, which will be
eventually linked into vmlinux.
When Kbuild descends into the directory with 'm', in contrast, nothing
from that directory will be linked into vmlinux. If the Makefile in
that directory specifies obj-y, those objects will be left orphan.
It is very likely a bug of the Makefile or of dependencies in Kconfig.
It is good practice to use a `CONFIG_` variable when assigning directory
names. This allows kbuild to totally skip the directory if the

View File

@ -339,7 +339,7 @@ To claim an address following code example can be used:
.pgn = J1939_PGN_ADDRESS_CLAIMED,
.pgn_mask = J1939_PGN_PDU1_MAX,
}, {
.pgn = J1939_PGN_ADDRESS_REQUEST,
.pgn = J1939_PGN_REQUEST,
.pgn_mask = J1939_PGN_PDU1_MAX,
}, {
.pgn = J1939_PGN_ADDRESS_COMMANDED,

View File

@ -2272,6 +2272,7 @@ F: drivers/*/*s3c64xx*
F: drivers/*/*s5pv210*
F: drivers/memory/samsung/
F: drivers/soc/samsung/
F: drivers/tty/serial/samsung*
F: include/linux/soc/samsung/
F: Documentation/arm/samsung/
F: Documentation/devicetree/bindings/arm/samsung/
@ -5000,7 +5001,7 @@ F: include/linux/dma-mapping.h
F: include/linux/dma-noncoherent.h
DMC FREQUENCY DRIVER FOR SAMSUNG EXYNOS5422
M: Lukasz Luba <l.luba@partner.samsung.com>
M: Lukasz Luba <lukasz.luba@arm.com>
L: linux-pm@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org
S: Maintained
@ -6026,6 +6027,7 @@ M: Yash Shah <yash.shah@sifive.com>
L: linux-edac@vger.kernel.org
S: Supported
F: drivers/edac/sifive_edac.c
F: drivers/soc/sifive_l2_cache.c
EDAC-SKYLAKE
M: Tony Luck <tony.luck@intel.com>
@ -7032,6 +7034,7 @@ L: linux-acpi@vger.kernel.org
S: Maintained
F: Documentation/firmware-guide/acpi/gpio-properties.rst
F: drivers/gpio/gpiolib-acpi.c
F: drivers/gpio/gpiolib-acpi.h
GPIO IR Transmitter
M: Sean Young <sean@mess.org>
@ -9039,7 +9042,6 @@ F: include/linux/umh.h
KERNEL VIRTUAL MACHINE (KVM)
M: Paolo Bonzini <pbonzini@redhat.com>
M: Radim Krčmář <rkrcmar@redhat.com>
L: kvm@vger.kernel.org
W: http://www.linux-kvm.org
T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
@ -9074,9 +9076,9 @@ F: virt/kvm/arm/
F: include/kvm/arm_*
KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
M: James Hogan <jhogan@kernel.org>
L: linux-mips@vger.kernel.org
S: Supported
L: kvm@vger.kernel.org
S: Orphan
F: arch/mips/include/uapi/asm/kvm*
F: arch/mips/include/asm/kvm*
F: arch/mips/kvm/
@ -9111,7 +9113,6 @@ F: tools/testing/selftests/kvm/*/s390x/
KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
M: Paolo Bonzini <pbonzini@redhat.com>
M: Radim Krčmář <rkrcmar@redhat.com>
R: Sean Christopherson <sean.j.christopherson@intel.com>
R: Vitaly Kuznetsov <vkuznets@redhat.com>
R: Wanpeng Li <wanpengli@tencent.com>
@ -10109,6 +10110,7 @@ S: Maintained
F: drivers/media/radio/radio-maxiradio*
MCAN MMIO DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com>
M: Sriram Dash <sriram.dash@samsung.com>
L: linux-can@vger.kernel.org
S: Maintained
@ -13709,6 +13711,15 @@ L: linux-arm-msm@vger.kernel.org
S: Maintained
F: drivers/iommu/qcom_iommu.c
QUALCOMM RMNET DRIVER
M: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
M: Sean Tranchetti <stranche@codeaurora.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/qualcomm/rmnet/
F: Documentation/networking/device_drivers/qualcomm/rmnet.txt
F: include/linux/if_rmnet.h
QUALCOMM TSENS THERMAL DRIVER
M: Amit Kucheria <amit.kucheria@linaro.org>
L: linux-pm@vger.kernel.org
@ -16532,6 +16543,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes
F: sound/soc/codecs/tas571x*
TI TCAN4X5X DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com>
L: linux-can@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/can/tcan4x5x.txt
F: drivers/net/can/m_can/tcan4x5x.c
TI TRF7970A NFC DRIVER
M: Mark Greer <mgreer@animalcreek.com>
L: linux-wireless@vger.kernel.org

View File

@ -2,7 +2,7 @@
VERSION = 5
PATCHLEVEL = 5
SUBLEVEL = 0
EXTRAVERSION = -rc2
EXTRAVERSION = -rc4
NAME = Kleptomaniac Octopus
# *DOCUMENTATION*
@ -414,6 +414,7 @@ STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
OBJSIZE = $(CROSS_COMPILE)size
READELF = $(CROSS_COMPILE)readelf
PAHOLE = pahole
LEX = flex
YACC = bison
@ -472,7 +473,7 @@ GCC_PLUGINS_CFLAGS :=
CLANG_FLAGS :=
export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE PAHOLE LEX YACC AWK INSTALLKERNEL
export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF PAHOLE LEX YACC AWK INSTALLKERNEL
export PERL PYTHON PYTHON2 PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE

View File

@ -108,7 +108,7 @@
&cpsw_emac0 {
phy-handle = <&ethphy0>;
phy-mode = "rgmii-txid";
phy-mode = "rgmii-id";
};
&i2c0 {

View File

@ -86,7 +86,7 @@
};
lcd0: display {
compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
label = "lcd";
backlight = <&lcd_bl>;

View File

@ -42,7 +42,7 @@
};
lcd0: display {
compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
label = "lcd";
backlight = <&lcd_bl>;

View File

@ -174,8 +174,8 @@
mdio: mdio@18002000 {
compatible = "brcm,iproc-mdio";
reg = <0x18002000 0x8>;
#size-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
#address-cells = <1>;
status = "disabled";
gphy0: ethernet-phy@0 {

View File

@ -43,7 +43,7 @@
<0x7c000000 0x0 0xfc000000 0x02000000>,
<0x40000000 0x0 0xff800000 0x00800000>;
/* Emulate a contiguous 30-bit address range for DMA */
dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
/*
* This node is the provider for the enable-method for

View File

@ -37,7 +37,7 @@
trips {
cpu-crit {
temperature = <80000>;
temperature = <90000>;
hysteresis = <0>;
type = "critical";
};

View File

@ -353,8 +353,8 @@
mdio: mdio@18003000 {
compatible = "brcm,iproc-mdio";
reg = <0x18003000 0x8>;
#size-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
#address-cells = <1>;
};
mdio-bus-mux@18003000 {

View File

@ -265,11 +265,6 @@
regulator-name = "LDORTC1";
regulator-boot-on;
};
ldortc2_reg: LDORTC2 {
regulator-name = "LDORTC2";
regulator-boot-on;
};
};
};
};

View File

@ -30,14 +30,26 @@
enable-active-high;
};
reg_sensors: regulator-sensors {
reg_peri_3v3: regulator-peri-3v3 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sensors_reg>;
regulator-name = "sensors-supply";
pinctrl-0 = <&pinctrl_peri_3v3>;
regulator-name = "VPERI_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio5 2 GPIO_ACTIVE_LOW>;
/*
* If you want to want to make this dynamic please
* check schematics and test all affected peripherals:
*
* - sensors
* - ethernet phy
* - can
* - bluetooth
* - wm8960 audio codec
* - ov5640 camera
*/
regulator-always-on;
};
reg_can_3v3: regulator-can-3v3 {
@ -140,6 +152,7 @@
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <&ethphy0>;
phy-supply = <&reg_peri_3v3>;
status = "okay";
};
@ -148,6 +161,7 @@
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <&ethphy1>;
phy-supply = <&reg_peri_3v3>;
status = "okay";
mdio {
@ -193,8 +207,8 @@
magnetometer@e {
compatible = "fsl,mag3110";
reg = <0x0e>;
vdd-supply = <&reg_sensors>;
vddio-supply = <&reg_sensors>;
vdd-supply = <&reg_peri_3v3>;
vddio-supply = <&reg_peri_3v3>;
};
};
@ -227,7 +241,7 @@
flash0: n25q256a@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "micron,n25q256a";
compatible = "micron,n25q256a", "jedec,spi-nor";
spi-max-frequency = <29000000>;
spi-rx-bus-width = <4>;
spi-tx-bus-width = <4>;
@ -462,7 +476,7 @@
>;
};
pinctrl_sensors_reg: sensorsreggrp {
pinctrl_peri_3v3: peri3v3grp {
fsl,pins = <
MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b0
>;

View File

@ -350,6 +350,7 @@ CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_SOFTLOCKUP_DETECTOR=y
# CONFIG_DETECT_HUNG_TASK is not set

View File

@ -462,6 +462,7 @@ CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_PROVE_LOCKING=y
# CONFIG_DEBUG_BUGVERBOSE is not set

View File

@ -92,6 +92,7 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
CONFIG_NETFILTER=y
CONFIG_PHONET=m
CONFIG_NET_SWITCHDEV=y
CONFIG_CAN=m
CONFIG_CAN_C_CAN=m
CONFIG_CAN_C_CAN_PLATFORM=m
@ -181,6 +182,7 @@ CONFIG_SMSC911X=y
# CONFIG_NET_VENDOR_STMICRO is not set
CONFIG_TI_DAVINCI_EMAC=y
CONFIG_TI_CPSW=y
CONFIG_TI_CPSW_SWITCHDEV=y
CONFIG_TI_CPTS=y
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_NET_VENDOR_WIZNET is not set
@ -554,6 +556,6 @@ CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_SPLIT=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_TI_CPSW_SWITCHDEV=y

View File

@ -212,4 +212,5 @@ CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y

View File

@ -13,6 +13,7 @@ static const char * const bcm2711_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V7
"brcm,bcm2711",
#endif
NULL
};
DT_MACHINE_START(BCM2711, "BCM2711")

View File

@ -84,7 +84,7 @@ struct device * __init imx_soc_device_init(void)
const char *ocotp_compat = NULL;
struct soc_device *soc_dev;
struct device_node *root;
struct regmap *ocotp;
struct regmap *ocotp = NULL;
const char *soc_id;
u64 soc_uid = 0;
u32 val;
@ -148,11 +148,11 @@ struct device * __init imx_soc_device_init(void)
soc_id = "i.MX6UL";
break;
case MXC_CPU_IMX6ULL:
ocotp_compat = "fsl,imx6ul-ocotp";
ocotp_compat = "fsl,imx6ull-ocotp";
soc_id = "i.MX6ULL";
break;
case MXC_CPU_IMX6ULZ:
ocotp_compat = "fsl,imx6ul-ocotp";
ocotp_compat = "fsl,imx6ull-ocotp";
soc_id = "i.MX6ULZ";
break;
case MXC_CPU_IMX6SLL:
@ -175,7 +175,9 @@ struct device * __init imx_soc_device_init(void)
ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat);
if (IS_ERR(ocotp))
pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat);
}
if (!IS_ERR_OR_NULL(ocotp)) {
regmap_read(ocotp, OCOTP_UID_H, &val);
soc_uid = val;
regmap_read(ocotp, OCOTP_UID_L, &val);

View File

@ -17,9 +17,9 @@ extern void pxa168_clear_keypad_wakeup(void);
#include <linux/platform_data/keypad-pxa27x.h>
#include <linux/pxa168_eth.h>
#include <linux/platform_data/mv_usb.h>
#include <linux/soc/mmp/cputype.h>
#include "devices.h"
#include "cputype.h"
extern struct pxa_device_desc pxa168_device_uart1;
extern struct pxa_device_desc pxa168_device_uart2;

View File

@ -551,8 +551,9 @@ static struct clk *ve_spc_clk_register(struct device *cpu_dev)
static int __init ve_spc_clk_init(void)
{
int cpu;
int cpu, cluster;
struct clk *clk;
bool init_opp_table[MAX_CLUSTERS] = { false };
if (!info)
return 0; /* Continue only if SPC is initialised */
@ -578,8 +579,17 @@ static int __init ve_spc_clk_init(void)
continue;
}
cluster = topology_physical_package_id(cpu_dev->id);
if (init_opp_table[cluster])
continue;
if (ve_init_opp_table(cpu_dev))
pr_warn("failed to initialise cpu%d opp table\n", cpu);
else if (dev_pm_opp_set_sharing_cpus(cpu_dev,
topology_core_cpumask(cpu_dev->id)))
pr_warn("failed to mark OPPs shared for cpu%d\n", cpu);
else
init_opp_table[cluster] = true;
}
platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0);

View File

@ -88,7 +88,7 @@
reboot {
compatible ="syscon-reboot";
regmap = <&dcfg>;
regmap = <&rst>;
offset = <0xb0>;
mask = <0x02>;
};
@ -178,6 +178,12 @@
big-endian;
};
rst: syscon@1e60000 {
compatible = "syscon";
reg = <0x0 0x1e60000 0x0 0x10000>;
little-endian;
};
scfg: syscon@1fc0000 {
compatible = "fsl,ls1028a-scfg", "syscon";
reg = <0x0 0x1fc0000 0x0 0x10000>;
@ -584,7 +590,7 @@
0x00010004 0x0000003d
0x00010005 0x00000045
0x00010006 0x0000004d
0x00010007 0x00000045
0x00010007 0x00000055
0x00010008 0x0000005e
0x00010009 0x00000066
0x0001000a 0x0000006e

View File

@ -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"
@ -113,23 +114,6 @@ typedef u32 compat_sigset_word;
#define COMPAT_OFF_T_MAX 0x7fffffff
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
* appropriately converted them already.
*/
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
return (void __user *)(unsigned long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
#define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
#define COMPAT_MINSIGSTKSZ 2048

View File

@ -547,6 +547,7 @@ static const struct midr_range spectre_v2_safe_list[] = {
MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
{ /* sentinel */ }
};

View File

@ -2098,9 +2098,9 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu,
WARN_ON(1);
}
kvm_err("Unsupported guest CP%d access at: %08lx [%08lx]\n",
cp, *vcpu_pc(vcpu), *vcpu_cpsr(vcpu));
print_sys_reg_instr(params);
print_sys_reg_msg(params,
"Unsupported guest CP%d access at: %08lx [%08lx]\n",
cp, *vcpu_pc(vcpu), *vcpu_cpsr(vcpu));
kvm_inject_undefined(vcpu);
}
@ -2233,6 +2233,12 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
NULL, 0);
}
static bool is_imp_def_sys_reg(struct sys_reg_params *params)
{
// See ARM DDI 0487E.a, section D12.3.2
return params->Op0 == 3 && (params->CRn & 0b1011) == 0b1011;
}
static int emulate_sys_reg(struct kvm_vcpu *vcpu,
struct sys_reg_params *params)
{
@ -2248,10 +2254,12 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
if (likely(r)) {
perform_access(vcpu, params, r);
} else if (is_imp_def_sys_reg(params)) {
kvm_inject_undefined(vcpu);
} else {
kvm_err("Unsupported guest sys_reg access at: %lx [%08lx]\n",
*vcpu_pc(vcpu), *vcpu_cpsr(vcpu));
print_sys_reg_instr(params);
print_sys_reg_msg(params,
"Unsupported guest sys_reg access at: %lx [%08lx]\n",
*vcpu_pc(vcpu), *vcpu_cpsr(vcpu));
kvm_inject_undefined(vcpu);
}
return 1;
@ -2360,8 +2368,11 @@ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG)
return NULL;
if (!index_to_params(id, &params))
return NULL;
table = get_target_table(vcpu->arch.target, true, &num);
r = find_reg_by_id(id, &params, table, num);
r = find_reg(&params, table, num);
if (!r)
r = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));

View File

@ -62,11 +62,24 @@ struct sys_reg_desc {
#define REG_HIDDEN_USER (1 << 0) /* hidden from userspace ioctls */
#define REG_HIDDEN_GUEST (1 << 1) /* hidden from guest */
static __printf(2, 3)
inline void print_sys_reg_msg(const struct sys_reg_params *p,
char *fmt, ...)
{
va_list va;
va_start(va, fmt);
/* Look, we even formatted it for you to paste into the table! */
kvm_pr_unimpl("%pV { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
&(struct va_format){ fmt, &va },
p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
va_end(va);
}
static inline void print_sys_reg_instr(const struct sys_reg_params *p)
{
/* Look, we even formatted it for you to paste into the table! */
kvm_pr_unimpl(" { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
/* GCC warns on an empty format string */
print_sys_reg_msg(p, "%s", "");
}
static inline bool ignore_write(struct kvm_vcpu *vcpu,

View File

@ -100,24 +100,6 @@ typedef u32 compat_sigset_word;
#define COMPAT_OFF_T_MAX 0x7fffffff
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
* appropriately converted them already.
*/
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
/* cast to a __user pointer via "unsigned long" makes sparse happy */
return (void __user *)(unsigned long)(long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = (struct pt_regs *)

View File

@ -604,6 +604,7 @@ static void emit_const_to_reg(struct jit_ctx *ctx, int dst, u64 value)
static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx)
{
int off, b_off;
int tcc_reg;
ctx->flags |= EBPF_SEEN_TC;
/*
@ -616,14 +617,14 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx)
b_off = b_imm(this_idx + 1, ctx);
emit_instr(ctx, bne, MIPS_R_AT, MIPS_R_ZERO, b_off);
/*
* if (--TCC < 0)
* if (TCC-- < 0)
* goto out;
*/
/* Delay slot */
emit_instr(ctx, daddiu, MIPS_R_T5,
(ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4, -1);
tcc_reg = (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4;
emit_instr(ctx, daddiu, MIPS_R_T5, tcc_reg, -1);
b_off = b_imm(this_idx + 1, ctx);
emit_instr(ctx, bltz, MIPS_R_T5, b_off);
emit_instr(ctx, bltz, tcc_reg, b_off);
/*
* prog = array->ptrs[index];
* if (prog == NULL)

View File

@ -44,8 +44,14 @@ __xchg(unsigned long x, __volatile__ void *ptr, int size)
** if (((unsigned long)p & 0xf) == 0)
** return __ldcw(p);
*/
#define xchg(ptr, x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
#define xchg(ptr, x) \
({ \
__typeof__(*(ptr)) __ret; \
__typeof__(*(ptr)) _x_ = (x); \
__ret = (__typeof__(*(ptr))) \
__xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \
__ret; \
})
/* bug catcher for when unsupported size is used - won't link */
extern void __cmpxchg_called_with_bad_pointer(void);

View File

@ -173,23 +173,6 @@ struct compat_shmid64_ds {
#define COMPAT_ELF_NGREG 80
typedef compat_ulong_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
* appropriately converted them already.
*/
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
return (void __user *)(unsigned long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
static __inline__ void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = &current->thread.regs;

View File

@ -2,8 +2,6 @@
#ifndef _ASM_PARISC_KEXEC_H
#define _ASM_PARISC_KEXEC_H
#ifdef CONFIG_KEXEC
/* Maximum physical address we can use pages from */
#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
/* Maximum address we can reach in physical address mode */
@ -32,6 +30,4 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_KEXEC */
#endif /* _ASM_PARISC_KEXEC_H */

View File

@ -37,5 +37,5 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KEXEC) += kexec.o relocate_kernel.o
obj-$(CONFIG_KEXEC_CORE) += kexec.o relocate_kernel.o
obj-$(CONFIG_KEXEC_FILE) += kexec_file.o

View File

@ -810,7 +810,7 @@ EXPORT_SYMBOL(device_to_hwpath);
static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
struct device *parent);
static void walk_lower_bus(struct parisc_device *dev)
static void __init walk_lower_bus(struct parisc_device *dev)
{
unsigned long io_io_low, io_io_high;

View File

@ -327,8 +327,7 @@ static int pdt_mainloop(void *unused)
((pde & PDT_ADDR_SINGLE_ERR) == 0))
memory_failure(pde >> PAGE_SHIFT, 0);
else
soft_offline_page(
pfn_to_page(pde >> PAGE_SHIFT), 0);
soft_offline_page(pde >> PAGE_SHIFT, 0);
#else
pr_crit("PDT: memory error at 0x%lx ignored.\n"
"Rebuild kernel with CONFIG_MEMORY_FAILURE=y "

View File

@ -96,23 +96,6 @@ typedef u32 compat_sigset_word;
#define COMPAT_OFF_T_MAX 0x7fffffff
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
* appropriately converted them already.
*/
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
return (void __user *)(unsigned long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = current->thread.regs;

View File

@ -36,10 +36,12 @@
#endif
#ifdef CONFIG_PPC_PSERIES
DECLARE_STATIC_KEY_FALSE(shared_processor);
#define vcpu_is_preempted vcpu_is_preempted
static inline bool vcpu_is_preempted(int cpu)
{
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
if (!static_branch_unlikely(&shared_processor))
return false;
return !!(be32_to_cpu(lppaca_of(cpu).yield_count) & 1);
}
@ -110,13 +112,8 @@ static inline void splpar_rw_yield(arch_rwlock_t *lock) {};
static inline bool is_shared_processor(void)
{
/*
* LPPACA is only available on Pseries so guard anything LPPACA related to
* allow other platforms (which include this common header) to compile.
*/
#ifdef CONFIG_PPC_PSERIES
return (IS_ENABLED(CONFIG_PPC_SPLPAR) &&
lppaca_shared_proc(local_paca->lppaca_ptr));
#ifdef CONFIG_PPC_SPLPAR
return static_branch_unlikely(&shared_processor);
#else
return false;
#endif

View File

@ -401,7 +401,7 @@ copy_to_user_mcsafe(void __user *to, const void *from, unsigned long n)
return n;
}
extern unsigned long __clear_user(void __user *addr, unsigned long size);
unsigned long __arch_clear_user(void __user *addr, unsigned long size);
static inline unsigned long clear_user(void __user *addr, unsigned long size)
{
@ -409,12 +409,17 @@ static inline unsigned long clear_user(void __user *addr, unsigned long size)
might_fault();
if (likely(access_ok(addr, size))) {
allow_write_to_user(addr, size);
ret = __clear_user(addr, size);
ret = __arch_clear_user(addr, size);
prevent_write_to_user(addr, size);
}
return ret;
}
static inline unsigned long __clear_user(void __user *addr, unsigned long size)
{
return clear_user(addr, size);
}
extern long strncpy_from_user(char *dst, const char __user *src, long count);
extern __must_check long strnlen_user(const char __user *str, long n);

View File

@ -619,8 +619,6 @@ void __do_irq(struct pt_regs *regs)
trace_irq_entry(regs);
check_stack_overflow();
/*
* Query the platform PIC for the interrupt & ack it.
*
@ -652,6 +650,8 @@ void do_IRQ(struct pt_regs *regs)
irqsp = hardirq_ctx[raw_smp_processor_id()];
sirqsp = softirq_ctx[raw_smp_processor_id()];
check_stack_overflow();
/* Already there ? */
if (unlikely(cursp == irqsp || cursp == sirqsp)) {
__do_irq(regs);

View File

@ -4983,7 +4983,8 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
if (nesting_enabled(kvm))
kvmhv_release_all_nested(kvm);
kvm->arch.process_table = 0;
uv_svm_terminate(kvm->arch.lpid);
if (kvm->arch.secure_guest)
uv_svm_terminate(kvm->arch.lpid);
kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
}

View File

@ -1117,7 +1117,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
ld r7, VCPU_GPR(R7)(r4)
bne ret_to_ultra
lwz r0, VCPU_CR(r4)
ld r0, VCPU_CR(r4)
mtcr r0
ld r0, VCPU_GPR(R0)(r4)
@ -1137,7 +1137,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
* R3 = UV_RETURN
*/
ret_to_ultra:
lwz r0, VCPU_CR(r4)
ld r0, VCPU_CR(r4)
mtcr r0
ld r0, VCPU_GPR(R3)(r4)

View File

@ -17,7 +17,7 @@ CACHELINE_BYTES = L1_CACHE_BYTES
LG_CACHELINE_BYTES = L1_CACHE_SHIFT
CACHELINE_MASK = (L1_CACHE_BYTES-1)
_GLOBAL(__clear_user)
_GLOBAL(__arch_clear_user)
/*
* Use dcbz on the complete cache lines in the destination
* to set them to zero. This requires that the destination
@ -87,4 +87,4 @@ _GLOBAL(__clear_user)
EX_TABLE(8b, 91b)
EX_TABLE(9b, 91b)
EXPORT_SYMBOL(__clear_user)
EXPORT_SYMBOL(__arch_clear_user)

View File

@ -17,7 +17,7 @@ PPC64_CACHES:
.section ".text"
/**
* __clear_user: - Zero a block of memory in user space, with less checking.
* __arch_clear_user: - Zero a block of memory in user space, with less checking.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
@ -58,7 +58,7 @@ err3; stb r0,0(r3)
mr r3,r4
blr
_GLOBAL_TOC(__clear_user)
_GLOBAL_TOC(__arch_clear_user)
cmpdi r4,32
neg r6,r3
li r0,0
@ -181,4 +181,4 @@ err1; dcbz 0,r3
cmpdi r4,32
blt .Lshort_clear
b .Lmedium_clear
EXPORT_SYMBOL(__clear_user)
EXPORT_SYMBOL(__arch_clear_user)

View File

@ -289,6 +289,14 @@ void __init mem_init(void)
BUILD_BUG_ON(MMU_PAGE_COUNT > 16);
#ifdef CONFIG_SWIOTLB
/*
* Some platforms (e.g. 85xx) limit DMA-able memory way below
* 4G. We force memblock to bottom-up mode to ensure that the
* memory allocated in swiotlb_init() is DMA-able.
* As it's the last memblock allocation, no need to reset it
* back to to-down.
*/
memblock_set_bottom_up(true);
swiotlb_init(0);
#endif

View File

@ -103,7 +103,7 @@ static void mmu_patch_addis(s32 *site, long simm)
patch_instruction_site(site, instr);
}
void __init mmu_mapin_ram_chunk(unsigned long offset, unsigned long top, pgprot_t prot)
static void mmu_mapin_ram_chunk(unsigned long offset, unsigned long top, pgprot_t prot)
{
unsigned long s = offset;
unsigned long v = PAGE_OFFSET + s;

View File

@ -9,7 +9,7 @@
#include <linux/sched.h>
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/compat.h>
#include <linux/compat.h>
#include <asm/oprofile_impl.h>
#define STACK_SP(STACK) *(STACK)

View File

@ -539,6 +539,16 @@ static int cmm_migratepage(struct balloon_dev_info *b_dev_info,
/* balloon page list reference */
get_page(newpage);
/*
* When we migrate a page to a different zone, we have to fixup the
* count of both involved zones as we adjusted the managed page count
* when inflating.
*/
if (page_zone(page) != page_zone(newpage)) {
adjust_managed_page_count(page, 1);
adjust_managed_page_count(newpage, -1);
}
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
balloon_page_insert(b_dev_info, newpage);
balloon_page_delete(page);

View File

@ -74,6 +74,9 @@
#include "pseries.h"
#include "../../../../drivers/pci/pci.h"
DEFINE_STATIC_KEY_FALSE(shared_processor);
EXPORT_SYMBOL_GPL(shared_processor);
int CMO_PrPSP = -1;
int CMO_SecPSP = -1;
unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K);
@ -758,6 +761,10 @@ static void __init pSeries_setup_arch(void)
if (firmware_has_feature(FW_FEATURE_LPAR)) {
vpa_init(boot_cpuid);
if (lppaca_shared_proc(get_lppaca()))
static_branch_enable(&shared_processor);
ppc_md.power_save = pseries_lpar_idle;
ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
#ifdef CONFIG_PCI_IOV

View File

@ -154,7 +154,7 @@ config GENERIC_HWEIGHT
def_bool y
config FIX_EARLYCON_MEM
def_bool CONFIG_MMU
def_bool MMU
config PGTABLE_LEVELS
int

View File

@ -90,6 +90,27 @@ extern pgd_t swapper_pg_dir[];
#define __S110 PAGE_SHARED_EXEC
#define __S111 PAGE_SHARED_EXEC
#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
#define VMALLOC_END (PAGE_OFFSET - 1)
#define VMALLOC_START (PAGE_OFFSET - VMALLOC_SIZE)
/*
* Roughly size the vmemmap space to be large enough to fit enough
* struct pages to map half the virtual address space. Then
* position vmemmap directly below the VMALLOC region.
*/
#define VMEMMAP_SHIFT \
(CONFIG_VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)
#define VMEMMAP_SIZE BIT(VMEMMAP_SHIFT)
#define VMEMMAP_END (VMALLOC_START - 1)
#define VMEMMAP_START (VMALLOC_START - VMEMMAP_SIZE)
/*
* Define vmemmap for pfn_to_page & page_to_pfn calls. Needed if kernel
* is configured with CONFIG_SPARSEMEM_VMEMMAP enabled.
*/
#define vmemmap ((struct page *)VMEMMAP_START)
static inline int pmd_present(pmd_t pmd)
{
return (pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROT_NONE));
@ -400,23 +421,6 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
#define VMALLOC_END (PAGE_OFFSET - 1)
#define VMALLOC_START (PAGE_OFFSET - VMALLOC_SIZE)
/*
* Roughly size the vmemmap space to be large enough to fit enough
* struct pages to map half the virtual address space. Then
* position vmemmap directly below the VMALLOC region.
*/
#define VMEMMAP_SHIFT \
(CONFIG_VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)
#define VMEMMAP_SIZE BIT(VMEMMAP_SHIFT)
#define VMEMMAP_END (VMALLOC_START - 1)
#define VMEMMAP_START (VMALLOC_START - VMEMMAP_SIZE)
#define vmemmap ((struct page *)VMEMMAP_START)
#define PCI_IO_SIZE SZ_16M
#define PCI_IO_END VMEMMAP_START
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)

View File

@ -246,6 +246,7 @@ check_syscall_nr:
*/
li t1, -1
beq a7, t1, ret_from_syscall_rejected
blt a7, t1, 1f
/* Call syscall */
la s0, sys_call_table
slli t0, a7, RISCV_LGPTR

View File

@ -246,7 +246,7 @@ ENTRY(reset_regs)
li t4, 0
li t5, 0
li t6, 0
csrw sscratch, 0
csrw CSR_SCRATCH, 0
#ifdef CONFIG_FPU
csrr t0, CSR_MISA

View File

@ -9,8 +9,5 @@
/*
* Assembly functions that may be used (directly or indirectly) by modules
*/
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(__asm_copy_to_user);
EXPORT_SYMBOL(__asm_copy_from_user);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);

View File

@ -1,4 +1,5 @@
#include <linux/linkage.h>
#include <asm-generic/export.h>
#include <asm/asm.h>
#include <asm/csr.h>
@ -66,6 +67,8 @@ ENTRY(__asm_copy_from_user)
j 3b
ENDPROC(__asm_copy_to_user)
ENDPROC(__asm_copy_from_user)
EXPORT_SYMBOL(__asm_copy_to_user)
EXPORT_SYMBOL(__asm_copy_from_user)
ENTRY(__clear_user)
@ -108,6 +111,7 @@ ENTRY(__clear_user)
bltu a0, a3, 5b
j 3b
ENDPROC(__clear_user)
EXPORT_SYMBOL(__clear_user)
.section .fixup,"ax"
.balign 4

View File

@ -10,7 +10,6 @@ obj-y += extable.o
obj-$(CONFIG_MMU) += fault.o
obj-y += cacheflush.o
obj-y += context.o
obj-y += sifive_l2_cache.o
ifeq ($(CONFIG_MMU),y)
obj-$(CONFIG_SMP) += tlbflush.o

View File

@ -22,6 +22,7 @@ void flush_icache_all(void)
else
on_each_cpu(ipi_remote_fence_i, NULL, 1);
}
EXPORT_SYMBOL(flush_icache_all);
/*
* Performs an icache flush for the given MM context. RISC-V has no direct

View File

@ -631,14 +631,14 @@ static int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx)
return -1;
emit(rv_bgeu(RV_REG_A2, RV_REG_T1, off >> 1), ctx);
/* if (--TCC < 0)
/* if (TCC-- < 0)
* goto out;
*/
emit(rv_addi(RV_REG_T1, tcc, -1), ctx);
off = (tc_ninsn - (ctx->ninsns - start_insn)) << 2;
if (is_13b_check(off, insn))
return -1;
emit(rv_blt(RV_REG_T1, RV_REG_ZERO, off >> 1), ctx);
emit(rv_blt(tcc, RV_REG_ZERO, off >> 1), ctx);
/* prog = array->ptrs[index];
* if (!prog)

View File

@ -177,11 +177,7 @@ static inline void __user *compat_ptr(compat_uptr_t uptr)
{
return (void __user *)(unsigned long)(uptr & 0x7fffffffUL);
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
#define compat_ptr(uptr) compat_ptr(uptr)
#ifdef CONFIG_COMPAT

View File

@ -194,9 +194,9 @@ static inline unsigned long long get_tod_clock_monotonic(void)
{
unsigned long long tod;
preempt_disable();
preempt_disable_notrace();
tod = get_tod_clock() - *(unsigned long long *) &tod_clock_base[1];
preempt_enable();
preempt_enable_notrace();
return tod;
}

View File

@ -35,6 +35,7 @@ EXPORT_SYMBOL(_mcount)
ENTRY(ftrace_caller)
.globl ftrace_regs_caller
.set ftrace_regs_caller,ftrace_caller
stg %r14,(__SF_GPRS+8*8)(%r15) # save traced function caller
lgr %r1,%r15
#if !(defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT))
aghi %r0,MCOUNT_RETURN_FIXUP

View File

@ -36,10 +36,17 @@ static bool update_stack_info(struct unwind_state *state, unsigned long sp)
return true;
}
static inline bool is_task_pt_regs(struct unwind_state *state,
struct pt_regs *regs)
static inline bool is_final_pt_regs(struct unwind_state *state,
struct pt_regs *regs)
{
return task_pt_regs(state->task) == regs;
/* user mode or kernel thread pt_regs at the bottom of task stack */
if (task_pt_regs(state->task) == regs)
return true;
/* user mode pt_regs at the bottom of irq stack */
return state->stack_info.type == STACK_TYPE_IRQ &&
state->stack_info.end - sizeof(struct pt_regs) == (unsigned long)regs &&
READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE;
}
bool unwind_next_frame(struct unwind_state *state)
@ -80,7 +87,7 @@ bool unwind_next_frame(struct unwind_state *state)
if (!on_stack(info, sp, sizeof(struct pt_regs)))
goto out_err;
regs = (struct pt_regs *) sp;
if (is_task_pt_regs(state, regs))
if (is_final_pt_regs(state, regs))
goto out_stop;
ip = READ_ONCE_NOCHECK(regs->psw.addr);
sp = READ_ONCE_NOCHECK(regs->gprs[15]);

View File

@ -1,3 +1,4 @@
purgatory
purgatory.chk
purgatory.lds
purgatory.ro

View File

@ -4,7 +4,7 @@ OBJECT_FILES_NON_STANDARD := y
purgatory-y := head.o purgatory.o string.o sha256.o mem.o
targets += $(purgatory-y) purgatory.lds purgatory purgatory.ro
targets += $(purgatory-y) purgatory.lds purgatory purgatory.chk purgatory.ro
PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
$(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE
@ -15,8 +15,10 @@ CFLAGS_sha256.o := -D__DISABLE_EXPORTS
$(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S FORCE
$(call if_changed_rule,as_o_S)
$(obj)/string.o: $(srctree)/arch/s390/lib/string.c FORCE
$(call if_changed_rule,cc_o_c)
KCOV_INSTRUMENT := n
GCOV_PROFILE := n
UBSAN_SANITIZE := n
KASAN_SANITIZE := n
KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes
KBUILD_CFLAGS += -Wno-pointer-sign -Wno-sign-compare
@ -26,15 +28,22 @@ KBUILD_CFLAGS += $(CLANG_FLAGS)
KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
KBUILD_AFLAGS := $(filter-out -DCC_USING_EXPOLINE,$(KBUILD_AFLAGS))
LDFLAGS_purgatory := -r --no-undefined -nostdlib -z nodefaultlib -T
# Since we link purgatory with -r unresolved symbols are not checked, so we
# also link a purgatory.chk binary without -r to check for unresolved symbols.
PURGATORY_LDFLAGS := -nostdlib -z nodefaultlib
LDFLAGS_purgatory := -r $(PURGATORY_LDFLAGS) -T
LDFLAGS_purgatory.chk := -e purgatory_start $(PURGATORY_LDFLAGS)
$(obj)/purgatory: $(obj)/purgatory.lds $(PURGATORY_OBJS) FORCE
$(call if_changed,ld)
$(obj)/purgatory.chk: $(obj)/purgatory FORCE
$(call if_changed,ld)
OBJCOPYFLAGS_purgatory.ro := -O elf64-s390
OBJCOPYFLAGS_purgatory.ro += --remove-section='*debug*'
OBJCOPYFLAGS_purgatory.ro += --remove-section='.comment'
OBJCOPYFLAGS_purgatory.ro += --remove-section='.note.*'
$(obj)/purgatory.ro: $(obj)/purgatory FORCE
$(obj)/purgatory.ro: $(obj)/purgatory $(obj)/purgatory.chk FORCE
$(call if_changed,objcopy)
$(obj)/kexec-purgatory.o: $(obj)/kexec-purgatory.S $(obj)/purgatory.ro FORCE

View File

@ -0,0 +1,3 @@
// SPDX-License-Identifier: GPL-2.0
#define __HAVE_ARCH_MEMCMP /* arch function */
#include "../lib/string.c"

View File

@ -125,23 +125,6 @@ typedef u32 compat_sigset_word;
#define COMPAT_OFF_T_MAX 0x7fffffff
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
* appropriately converted them already.
*/
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
return (void __user *)(unsigned long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
#ifdef CONFIG_COMPAT
static inline void __user *arch_compat_alloc_user_space(long len)
{

View File

@ -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,
};

View File

@ -103,7 +103,7 @@ vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
quiet_cmd_check_data_rel = DATAREL $@
define cmd_check_data_rel
for obj in $(filter %.o,$^); do \
${CROSS_COMPILE}readelf -S $$obj | grep -qF .rel.local && { \
$(READELF) -S $$obj | grep -qF .rel.local && { \
echo "error: $$obj has data relocations!" >&2; \
exit 1; \
} || true; \

View File

@ -376,7 +376,7 @@ int x86_add_exclusive(unsigned int what)
* LBR and BTS are still mutually exclusive.
*/
if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt)
return 0;
goto out;
if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
mutex_lock(&pmc_reserve_mutex);
@ -388,6 +388,7 @@ int x86_add_exclusive(unsigned int what)
mutex_unlock(&pmc_reserve_mutex);
}
out:
atomic_inc(&active_events);
return 0;
@ -398,11 +399,15 @@ fail_unlock:
void x86_del_exclusive(unsigned int what)
{
atomic_dec(&active_events);
/*
* See the comment in x86_add_exclusive().
*/
if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt)
return;
atomic_dec(&x86_pmu.lbr_exclusive[what]);
atomic_dec(&active_events);
}
int x86_setup_perfctr(struct perf_event *event)
@ -1642,9 +1647,12 @@ static struct attribute_group x86_pmu_format_group __ro_after_init = {
ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, char *page)
{
struct perf_pmu_events_attr *pmu_attr = \
struct perf_pmu_events_attr *pmu_attr =
container_of(attr, struct perf_pmu_events_attr, attr);
u64 config = x86_pmu.event_map(pmu_attr->id);
u64 config = 0;
if (pmu_attr->id < x86_pmu.max_events)
config = x86_pmu.event_map(pmu_attr->id);
/* string trumps id */
if (pmu_attr->event_str)
@ -1713,6 +1721,9 @@ is_visible(struct kobject *kobj, struct attribute *attr, int idx)
{
struct perf_pmu_events_attr *pmu_attr;
if (idx >= x86_pmu.max_events)
return 0;
pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
/* str trumps id */
return pmu_attr->event_str || x86_pmu.event_map(idx) ? attr->mode : 0;

View File

@ -63,9 +63,17 @@ struct bts_buffer {
static struct pmu bts_pmu;
static int buf_nr_pages(struct page *page)
{
if (!PagePrivate(page))
return 1;
return 1 << page_private(page);
}
static size_t buf_size(struct page *page)
{
return 1 << (PAGE_SHIFT + page_private(page));
return buf_nr_pages(page) * PAGE_SIZE;
}
static void *
@ -83,9 +91,7 @@ bts_buffer_setup_aux(struct perf_event *event, void **pages,
/* count all the high order buffers */
for (pg = 0, nbuf = 0; pg < nr_pages;) {
page = virt_to_page(pages[pg]);
if (WARN_ON_ONCE(!PagePrivate(page) && nr_pages > 1))
return NULL;
pg += 1 << page_private(page);
pg += buf_nr_pages(page);
nbuf++;
}
@ -109,7 +115,7 @@ bts_buffer_setup_aux(struct perf_event *event, void **pages,
unsigned int __nr_pages;
page = virt_to_page(pages[pg]);
__nr_pages = PagePrivate(page) ? 1 << page_private(page) : 1;
__nr_pages = buf_nr_pages(page);
buf->buf[nbuf].page = page;
buf->buf[nbuf].offset = offset;
buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0);

View File

@ -177,23 +177,6 @@ typedef struct user_regs_struct compat_elf_gregset_t;
(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
#endif
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
* appropriately converted them already.
*/
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
return (void __user *)(unsigned long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
{
return (u32)(unsigned long)uptr;
}
static inline void __user *arch_compat_alloc_user_space(long len)
{
compat_uptr_t sp;

View File

@ -266,10 +266,10 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
smca_set_misc_banks_map(bank, cpu);
/* Return early if this bank was already initialized. */
if (smca_banks[bank].hwid)
if (smca_banks[bank].hwid && smca_banks[bank].hwid->hwid_mcatype != 0)
return;
if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
if (rdmsr_safe(MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
pr_warn("Failed to read MCA_IPID for bank %d\n", bank);
return;
}

View File

@ -819,8 +819,8 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
if (quirk_no_way_out)
quirk_no_way_out(i, m, regs);
m->bank = i;
if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
m->bank = i;
mce_read_aux(m, i);
*msg = tmp;
return 1;

View File

@ -710,8 +710,12 @@ static struct chipset early_qrk[] __initdata = {
*/
{ PCI_VENDOR_ID_INTEL, 0x0f00,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
{ PCI_VENDOR_ID_INTEL, 0x3e20,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
{ PCI_VENDOR_ID_INTEL, 0x3ec4,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
{ PCI_VENDOR_ID_INTEL, 0x8a12,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
{ PCI_VENDOR_ID_BROADCOM, 0x4331,
PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset},
{}

View File

@ -402,7 +402,8 @@ static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index)
entry->edx |= F(SPEC_CTRL);
if (boot_cpu_has(X86_FEATURE_STIBP))
entry->edx |= F(INTEL_STIBP);
if (boot_cpu_has(X86_FEATURE_SSBD))
if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
boot_cpu_has(X86_FEATURE_AMD_SSBD))
entry->edx |= F(SPEC_CTRL_SSBD);
/*
* We emulate ARCH_CAPABILITIES in software even
@ -759,7 +760,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 function,
entry->ebx |= F(AMD_IBRS);
if (boot_cpu_has(X86_FEATURE_STIBP))
entry->ebx |= F(AMD_STIBP);
if (boot_cpu_has(X86_FEATURE_SSBD))
if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
boot_cpu_has(X86_FEATURE_AMD_SSBD))
entry->ebx |= F(AMD_SSBD);
if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
entry->ebx |= F(AMD_SSB_NO);

View File

@ -260,10 +260,6 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
return;
}
/* No need to reserve regions that will never be freed. */
if (md.attribute & EFI_MEMORY_RUNTIME)
return;
size += addr % EFI_PAGE_SIZE;
size = round_up(size, EFI_PAGE_SIZE);
addr = round_down(addr, EFI_PAGE_SIZE);
@ -293,6 +289,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
early_memunmap(new, new_size);
efi_memmap_install(new_phys, num_entries);
e820__range_update(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED);
e820__update_table(e820_table);
}
/*

View File

@ -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

View File

@ -885,11 +885,14 @@ generic_make_request_checks(struct bio *bio)
}
/*
* For a REQ_NOWAIT based request, return -EOPNOTSUPP
* if queue is not a request based queue.
* Non-mq queues do not honor REQ_NOWAIT, so complete a bio
* with BLK_STS_AGAIN status in order to catch -EAGAIN and
* to give a chance to the caller to repeat request gracefully.
*/
if ((bio->bi_opf & REQ_NOWAIT) && !queue_is_mq(q))
goto not_supported;
if ((bio->bi_opf & REQ_NOWAIT) && !queue_is_mq(q)) {
status = BLK_STS_AGAIN;
goto end_io;
}
if (should_fail_bio(bio))
goto end_io;

View File

@ -69,6 +69,7 @@
#include <linux/blkdev.h>
#include <linux/gfp.h>
#include <linux/blk-mq.h>
#include <linux/lockdep.h>
#include "blk.h"
#include "blk-mq.h"
@ -505,6 +506,9 @@ struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
INIT_LIST_HEAD(&fq->flush_queue[1]);
INIT_LIST_HEAD(&fq->flush_data_in_flight);
lockdep_register_key(&fq->key);
lockdep_set_class(&fq->mq_flush_lock, &fq->key);
return fq;
fail_rq:
@ -519,6 +523,7 @@ void blk_free_flush_queue(struct blk_flush_queue *fq)
if (!fq)
return;
lockdep_unregister_key(&fq->key);
kfree(fq->flush_rq);
kfree(fq);
}

View File

@ -1212,7 +1212,7 @@ static enum hrtimer_restart iocg_waitq_timer_fn(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
static void iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
{
struct ioc *ioc = iocg->ioc;
struct blkcg_gq *blkg = iocg_to_blkg(iocg);
@ -1229,11 +1229,11 @@ static void iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
/* clear or maintain depending on the overage */
if (time_before_eq64(vtime, now->vnow)) {
blkcg_clear_delay(blkg);
return;
return false;
}
if (!atomic_read(&blkg->use_delay) &&
time_before_eq64(vtime, now->vnow + vmargin))
return;
return false;
/* use delay */
if (cost) {
@ -1250,10 +1250,11 @@ static void iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
oexpires = ktime_to_ns(hrtimer_get_softexpires(&iocg->delay_timer));
if (hrtimer_is_queued(&iocg->delay_timer) &&
abs(oexpires - expires) <= margin_ns / 4)
return;
return true;
hrtimer_start_range_ns(&iocg->delay_timer, ns_to_ktime(expires),
margin_ns / 4, HRTIMER_MODE_ABS);
return true;
}
static enum hrtimer_restart iocg_delay_timer_fn(struct hrtimer *timer)
@ -1739,7 +1740,9 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio)
*/
if (bio_issue_as_root_blkg(bio) || fatal_signal_pending(current)) {
atomic64_add(abs_cost, &iocg->abs_vdebt);
iocg_kick_delay(iocg, &now, cost);
if (iocg_kick_delay(iocg, &now, cost))
blkcg_schedule_throttle(rqos->q,
(bio->bi_opf & REQ_SWAP) == REQ_SWAP);
return;
}

View File

@ -151,7 +151,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
return 0;
unmap_rq:
__blk_rq_unmap_user(bio);
blk_rq_unmap_user(bio);
fail:
rq->bio = NULL;
return ret;

View File

@ -30,6 +30,7 @@ struct blk_flush_queue {
* at the same time
*/
struct request *orig_rq;
struct lock_class_key key;
spinlock_t mq_flush_lock;
};

View File

@ -266,7 +266,7 @@ static blk_status_t bsg_queue_rq(struct blk_mq_hw_ctx *hctx,
struct request *req = bd->rq;
struct bsg_set *bset =
container_of(q->tag_set, struct bsg_set, tag_set);
int sts = BLK_STS_IOERR;
blk_status_t sts = BLK_STS_IOERR;
int ret;
blk_mq_start_request(req);

View File

@ -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,
};

View File

@ -1,411 +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;
}
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_cdrom_read_audio {
union cdrom_addr addr;
u8 addr_format;
compat_int_t nframes;
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)
{
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);
}
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;
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)
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);
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
* 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:
/* 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:
/* 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. */
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:
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 */
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. */
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:
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;
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;
}
}

View File

@ -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>
@ -11,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;
@ -24,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)
@ -34,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;
@ -155,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;
@ -238,36 +270,48 @@ 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_long(compat_long_t *argp, long val)
{
return put_user(val, argp);
}
static int compat_put_ulong(compat_ulong_t *argp, compat_ulong_t val)
{
return put_user(val, argp);
}
#endif
int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
@ -285,6 +329,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)
{
@ -455,6 +519,45 @@ 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 block_device *bdev,
struct compat_hd_geometry __user *ugeo)
{
struct gendisk *disk = bdev->bd_disk;
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)
@ -481,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) {
@ -510,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:
@ -579,7 +661,132 @@ 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)
/* 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;
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;
/*
* 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) {
/* These need separate implementations for the data structure */
case HDIO_GETGEO:
return compat_hdio_getgeo(bdev, argp);
case BLKPG:
return compat_blkpg_ioctl(bdev, argp);
/* Compat mode returns 32-bit data instead of 'long' */
case BLKRAGET:
case BLKFRAGET:
if (!argp)
return -EINVAL;
return compat_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 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 put_u64(argp, i_size_read(bdev->bd_inode));
/* Incompatible alignment on i386 */
case BLKTRACESETUP32:
return blk_trace_ioctl(bdev, cmd, argp);
default:
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

View File

@ -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
@ -666,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)
{
@ -716,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

Some files were not shown because too many files have changed in this diff Show More