Merge tag 'nfs-for-5.17-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 8 Feb 2022 20:03:07 +0000 (12:03 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 8 Feb 2022 20:03:07 +0000 (12:03 -0800)
Pull NFS client fixes from Anna Schumaker:
 "Stable Fixes:

   - Fix initialization of nfs_client cl_flags

  Other Fixes:

   - Fix performance issues with uncached readdir calls

   - Fix potential pointer dereferences in rpcrdma_ep_create

   - Fix nfs4_proc_get_locations() kernel-doc comment

   - Fix locking during sunrpc sysfs reads

   - Update my email address in the MAINTAINERS file to my new
     kernel.org email"

* tag 'nfs-for-5.17-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  SUNRPC: lock against ->sock changing during sysfs read
  MAINTAINERS: Update my email address
  NFS: Fix nfs4_proc_get_locations() kernel-doc comment
  xprtrdma: fix pointer derefs in error cases of rpcrdma_ep_create
  NFS: Fix initialisation of nfs_client cl_flags field
  NFS: Avoid duplicate uncached readdir calls on eof
  NFS: Don't skip directory entries when doing uncached readdir
  NFS: Don't overfill uncached readdir pages

395 files changed:
.mailmap
Documentation/arm64/silicon-errata.rst
Documentation/dev-tools/kselftest.rst
Documentation/devicetree/bindings/net/qcom,ipa.yaml
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
Documentation/filesystems/netfs_library.rst
Documentation/gpu/todo.rst
Documentation/userspace-api/ioctl/ioctl-number.rst
MAINTAINERS
Makefile
arch/arm/crypto/blake2s-shash.c
arch/arm64/Kconfig
arch/arm64/kernel/cpu_errata.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/tools/cpucaps
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/kvm/mips.c
arch/mips/kvm/vz.c
arch/riscv/kvm/vcpu.c
arch/riscv/kvm/vcpu_sbi_base.c
arch/x86/crypto/blake2s-shash.c
arch/x86/events/intel/core.c
arch/x86/events/intel/pt.c
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kvm/cpuid.c
arch/x86/kvm/lapic.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/smp_pv.c
block/bio-integrity.c
block/fops.c
crypto/blake2s_generic.c
drivers/acpi/Kconfig
drivers/ata/libata-core.c
drivers/char/random.c
drivers/dma-buf/dma-heap.c
drivers/edac/altera_edac.c
drivers/edac/xgene_edac.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/i915/display/intel_overlay.c
drivers/gpu/drm/i915/display/intel_tc.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gt/uc/intel_guc.h
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/kmb/kmb_plane.c
drivers/gpu/drm/mxsfb/mxsfb_kms.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/hfi1/ipoib.h
drivers/infiniband/hw/hfi1/ipoib_main.c
drivers/infiniband/hw/hfi1/ipoib_tx.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/siw/siw.h
drivers/infiniband/sw/siw/siw_qp_rx.c
drivers/infiniband/sw/siw/siw_verbs.c
drivers/input/touchscreen/wm97xx-core.c
drivers/iommu/amd/init.c
drivers/iommu/intel/irq_remapping.c
drivers/iommu/ioasid.c
drivers/iommu/iommu.c
drivers/iommu/omap-iommu.c
drivers/md/md.c
drivers/mmc/core/sd.c
drivers/mmc/host/moxart-mmc.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sh_mmcif.c
drivers/net/dsa/Kconfig
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/google/gve/gve_adminq.c
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bond.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h
drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
drivers/net/ethernet/mellanox/mlx5/core/port.c
drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/ca8210.c
drivers/net/ieee802154/mac802154_hwsim.c
drivers/net/ieee802154/mcr20a.c
drivers/net/ipa/ipa_power.c
drivers/net/ipa/ipa_power.h
drivers/net/ipa/ipa_uc.c
drivers/net/macsec.c
drivers/net/phy/at803x.c
drivers/net/usb/ipheth.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/pci/controller/cadence/pci-j721e.c
drivers/pci/controller/dwc/pcie-kirin.c
drivers/pci/msi/msi.c
drivers/pinctrl/Makefile
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/pinctrl-microchip-sgpio.c
drivers/pinctrl/pinctrl-thunderbay.c
drivers/pinctrl/pinctrl-zynqmp.c
drivers/pinctrl/sunxi/pinctrl-sun50i-h616.c
drivers/platform/surface/Kconfig
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/asus-tf103c-dock.c
drivers/platform/x86/intel/crystal_cove_charger.c
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/platform/x86/x86-android-tablets.c
drivers/regulator/max20086-regulator.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/scsi_scan.c
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-stm32.c
drivers/spi/spi-uniphier.c
drivers/video/console/Kconfig
drivers/video/fbdev/core/bitblit.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbcon.h
drivers/video/fbdev/core/fbcon_ccw.c
drivers/video/fbdev/core/fbcon_cw.c
drivers/video/fbdev/core/fbcon_rotate.h
drivers/video/fbdev/core/fbcon_ud.c
drivers/video/fbdev/core/tileblit.c
drivers/video/fbdev/skeletonfb.c
fs/9p/fid.c
fs/Kconfig
fs/Makefile
fs/btrfs/block-group.c
fs/btrfs/ctree.h
fs/btrfs/ioctl.c
fs/btrfs/qgroup.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/cachefiles/io.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c
fs/cifs/sess.c
fs/erofs/data.c
fs/erofs/zdata.c
fs/erofs/zmap.c
fs/ext4/acl.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/fast_commit.c
fs/ext4/hash.c
fs/ext4/indirect.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/namei.c
fs/ext4/orphan.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/xattr.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/hash.c
fs/f2fs/namei.c
fs/f2fs/recovery.c
fs/f2fs/super.c
fs/f2fs/sysfs.c
fs/iomap/buffered-io.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/ksmbd/auth.c
fs/ksmbd/smb2pdu.c
fs/ksmbd/smb_common.c
fs/ksmbd/transport_rdma.c
fs/ksmbd/vfs.h
fs/libfs.c
fs/lockd/svcsubs.c
fs/nfsd/nfs4state.c
fs/notify/fanotify/fanotify_user.c
fs/overlayfs/copy_up.c
fs/quota/dquot.c
fs/super.c
fs/sync.c
fs/unicode/Kconfig
fs/unicode/Makefile
fs/xfs/xfs_aops.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_super.c
include/crypto/internal/blake2s.h
include/linux/ata.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
include/linux/fb.h
include/linux/fs.h
include/linux/if_vlan.h
include/linux/iomap.h
include/linux/jbd2.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/netfs.h
include/linux/page_table_check.h
include/linux/pgtable.h
include/linux/sched.h
include/net/ax25.h
include/net/neighbour.h
include/sound/pcm.h
include/uapi/linux/kvm.h
include/uapi/linux/perf_event.h
include/uapi/linux/smc_diag.h
include/uapi/sound/asound.h
include/uapi/xen/gntdev.h
include/xen/xenbus_dev.h
ipc/sem.c
kernel/async.c
kernel/audit.c
kernel/bpf/bpf_lsm.c
kernel/bpf/ringbuf.c
kernel/bpf/trampoline.c
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cpuset.c
kernel/events/core.c
kernel/module.c
kernel/printk/sysctl.c
kernel/stackleak.c
lib/crypto/blake2s.c
mm/debug_vm_pgtable.c
mm/gup.c
mm/khugepaged.c
mm/kmemleak.c
mm/page_isolation.c
mm/page_table_check.c
net/ax25/af_ax25.c
net/ax25/ax25_dev.c
net/ax25/ax25_route.c
net/bridge/netfilter/nft_reject_bridge.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/messenger_v1.c
net/ceph/messenger_v2.c
net/core/neighbour.c
net/core/rtnetlink.c
net/ieee802154/nl802154.c
net/ipv4/netfilter/Kconfig
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/nf_flow_table_ipv6.c [deleted file]
net/netfilter/nf_tables_api.c
net/netfilter/nft_byteorder.c
net/netfilter/nft_ct.c
net/packet/af_packet.c
net/sched/cls_api.c
net/smc/af_smc.c
net/smc/smc.h
net/smc/smc_diag.c
security/integrity/digsig_asymmetric.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c
security/integrity/integrity_audit.c
security/selinux/ss/conditional.c
sound/core/pcm_native.c
sound/hda/intel-sdw-acpi.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/patch_realtek.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/codecs/cpcap.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/max9759.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/wcd938x.c
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/generic/simple-card.c
sound/soc/mediatek/Kconfig
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/soc-acpi.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/xilinx/xlnx_formatter_pcm.c
sound/usb/mixer.c
sound/usb/quirks-table.h
tools/arch/x86/include/asm/cpufeatures.h
tools/bpf/resolve_btfids/Makefile
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/lirc.h [deleted file]
tools/include/uapi/linux/perf_event.h
tools/include/uapi/linux/prctl.h
tools/include/uapi/sound/asound.h
tools/lib/perf/mmap.c
tools/lib/perf/tests/test-evsel.c
tools/objtool/check.c
tools/perf/builtin-ftrace.c
tools/perf/trace/beauty/prctl_option.sh
tools/perf/util/annotate.c
tools/perf/util/bpf_counter_cgroup.c
tools/perf/util/machine.c
tools/perf/util/map_symbol.h
tools/perf/util/perf_event_attr_fprintf.c
tools/perf/util/session.c
tools/perf/util/sort.c
tools/perf/util/stat-display.c
tools/perf/util/synthetic-events.c
tools/scripts/Makefile.include
tools/testing/kunit/kunit_kernel.py
tools/testing/selftests/bpf/test_lirc_mode2_user.c
tools/testing/selftests/cpufreq/main.sh
tools/testing/selftests/exec/Makefile
tools/testing/selftests/futex/Makefile
tools/testing/selftests/kselftest_harness.h
tools/testing/selftests/mincore/mincore_selftest.c
tools/testing/selftests/netfilter/nft_concat_range.sh
tools/testing/selftests/netfilter/nft_nat.sh
tools/testing/selftests/netfilter/nft_zones_many.sh
tools/testing/selftests/openat2/Makefile
tools/testing/selftests/openat2/helpers.h
tools/testing/selftests/openat2/openat2_test.c
tools/testing/selftests/perf_events/sigtrap_threads.c
tools/testing/selftests/rtc/settings
tools/testing/selftests/vDSO/vdso_test_abi.c
tools/testing/selftests/vm/userfaultfd.c
tools/testing/selftests/zram/zram.sh
tools/testing/selftests/zram/zram01.sh
tools/testing/selftests/zram/zram02.sh
tools/testing/selftests/zram/zram_lib.sh

index b76e520..8cd44b0 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -80,6 +80,9 @@ Chris Chiu <chris.chiu@canonical.com> <chiu@endlessos.org>
 Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
 Christian Borntraeger <borntraeger@linux.ibm.com> <cborntra@de.ibm.com>
 Christian Borntraeger <borntraeger@linux.ibm.com> <borntrae@de.ibm.com>
+Christian Brauner <brauner@kernel.org> <christian@brauner.io>
+Christian Brauner <brauner@kernel.org> <christian.brauner@canonical.com>
+Christian Brauner <brauner@kernel.org> <christian.brauner@ubuntu.com>
 Christophe Ricard <christophe.ricard@gmail.com>
 Christoph Hellwig <hch@lst.de>
 Colin Ian King <colin.king@intel.com> <colin.king@canonical.com>
index 0ec7b7f..ea281dd 100644 (file)
@@ -100,6 +100,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A510     | #2051678        | ARM64_ERRATUM_2051678       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2077057        | ARM64_ERRATUM_2077057       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2119858        | ARM64_ERRATUM_2119858       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2054223        | ARM64_ERRATUM_2054223       |
index dcefee7..a833ecf 100644 (file)
@@ -7,6 +7,14 @@ directory. These are intended to be small tests to exercise individual code
 paths in the kernel. Tests are intended to be run after building, installing
 and booting a kernel.
 
+Kselftest from mainline can be run on older stable kernels. Running tests
+from mainline offers the best coverage. Several test rings run mainline
+kselftest suite on stable releases. The reason is that when a new test
+gets added to test existing code to regression test a bug, we should be
+able to run that test on an older kernel. Hence, it is important to keep
+code that can still test an older kernel and make sure it skips the test
+gracefully on newer releases.
+
 You can find additional information on Kselftest framework, how to
 write new tests using the framework on Kselftest wiki:
 
index b86edf6..58ecc62 100644 (file)
@@ -107,6 +107,10 @@ properties:
           - const: imem
           - const: config
 
+  qcom,qmp:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the AOSS side-channel message RAM
+
   qcom,smem-states:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: State bits used in by the AP to signal the modem.
@@ -222,6 +226,8 @@ examples:
                                      "imem",
                                      "config";
 
+                qcom,qmp = <&aoss_qmp>;
+
                 qcom,smem-states = <&ipa_smp2p_out 0>,
                                    <&ipa_smp2p_out 1>;
                 qcom,smem-state-names = "ipa-clock-enabled-valid",
index 5dd2092..3ec2d7b 100644 (file)
@@ -23,8 +23,9 @@ properties:
     minItems: 1
     maxItems: 256
     items:
-      minimum: 0
-      maximum: 256
+      items:
+        - minimum: 0
+          maximum: 256
     description:
       Chip select used by the device.
 
index 136f8da..4f373a8 100644 (file)
@@ -462,6 +462,10 @@ operation table looks like the following::
                             struct iov_iter *iter,
                             netfs_io_terminated_t term_func,
                             void *term_func_priv);
+
+               int (*query_occupancy)(struct netfs_cache_resources *cres,
+                                      loff_t start, size_t len, size_t granularity,
+                                      loff_t *_data_start, size_t *_data_len);
        };
 
 With a termination handler function pointer::
@@ -536,6 +540,18 @@ The methods defined in the table are:
    indicating whether the termination is definitely happening in the caller's
    context.
 
+ * ``query_occupancy()``
+
+   [Required] Called to find out where the next piece of data is within a
+   particular region of the cache.  The start and length of the region to be
+   queried are passed in, along with the granularity to which the answer needs
+   to be aligned.  The function passes back the start and length of the data,
+   if any, available within that region.  Note that there may be a hole at the
+   front.
+
+   It returns 0 if some data was found, -ENODATA if there was no usable data
+   within the region or -ENOBUFS if there is no caching on this file.
+
 Note that these methods are passed a pointer to the cache resource structure,
 not the read request structure as they could be used in other situations where
 there isn't a read request structure as well, such as writing dirty data to the
index da138dd..a1212b5 100644 (file)
@@ -300,30 +300,6 @@ Contact: Daniel Vetter, Noralf Tronnes
 
 Level: Advanced
 
-Garbage collect fbdev scrolling acceleration
---------------------------------------------
-
-Scroll acceleration has been disabled in fbcon. Now it works as the old
-SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was
-removed from fbcon_ops.
-Remaining tasks:
-
-- a bunch of the hooks in fbcon_ops could be removed or simplified by calling
-  directly instead of the function table (with a switch on p->rotate)
-
-- fb_copyarea is unused after this, and can be deleted from all drivers
-
-- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as
-  well as cfb_copyarea
-
-Note that not all acceleration code can be deleted, since clearing and cursor
-support is still accelerated, which might be good candidates for further
-deletion projects.
-
-Contact: Daniel Vetter
-
-Level: Intermediate
-
 idr_init_base()
 ---------------
 
index 687efcf..e6fce2c 100644 (file)
@@ -115,6 +115,7 @@ Code  Seq#    Include File                                           Comments
 'B'   00-1F  linux/cciss_ioctl.h                                     conflict!
 'B'   00-0F  include/linux/pmu.h                                     conflict!
 'B'   C0-FF  advanced bbus                                           <mailto:maassen@uni-freiburg.de>
+'B'   00-0F  xen/xenbus_dev.h                                        conflict!
 'C'   all    linux/soundcard.h                                       conflict!
 'C'   01-2F  linux/capi.h                                            conflict!
 'C'   F0-FF  drivers/net/wan/cosa.h                                  conflict!
@@ -134,6 +135,7 @@ Code  Seq#    Include File                                           Comments
 'F'   80-8F  linux/arcfb.h                                           conflict!
 'F'   DD     video/sstfb.h                                           conflict!
 'G'   00-3F  drivers/misc/sgi-gru/grulib.h                           conflict!
+'G'   00-0F  xen/gntalloc.h, xen/gntdev.h                            conflict!
 'H'   00-7F  linux/hiddev.h                                          conflict!
 'H'   00-0F  linux/hidraw.h                                          conflict!
 'H'   01     linux/mei.h                                             conflict!
@@ -176,6 +178,7 @@ Code  Seq#    Include File                                           Comments
 'P'   60-6F  sound/sscape_ioctl.h                                    conflict!
 'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
 'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
+'P'   00-0F  xen/privcmd.h                                           conflict!
 'Q'   all    linux/soundcard.h
 'R'   00-1F  linux/random.h                                          conflict!
 'R'   01     linux/rfkill.h                                          conflict!
index afff786..3e461db 100644 (file)
@@ -4157,9 +4157,8 @@ N:        csky
 K:     csky
 
 CA8210 IEEE-802.15.4 RADIO DRIVER
-M:     Harry Morris <h.morris@cascoda.com>
 L:     linux-wpan@vger.kernel.org
-S:     Maintained
+S:     Orphan
 W:     https://github.com/Cascoda/ca8210-linux.git
 F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
 F:     drivers/net/ieee802154/ca8210.c
@@ -10880,6 +10879,12 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/pata_arasan_cf.c
 F:     include/linux/pata_arasan_cf_data.h
 
+LIBATA PATA DRIVERS
+R:     Sergey Shtylyov <s.shtylyov@omp.ru>
+L:     linux-ide@vger.kernel.org
+F:     drivers/ata/ata_*.c
+F:     drivers/ata/pata_*.c
+
 LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-ide@vger.kernel.org
@@ -12400,7 +12405,7 @@ F:      include/uapi/linux/membarrier.h
 F:     kernel/sched/membarrier.c
 
 MEMBLOCK
-M:     Mike Rapoport <rppt@linux.ibm.com>
+M:     Mike Rapoport <rppt@kernel.org>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     Documentation/core-api/boot-time-mm.rst
@@ -16469,6 +16474,14 @@ F:     Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
 F:     drivers/i2c/busses/i2c-rcar.c
 F:     drivers/i2c/busses/i2c-sh_mobile.c
 
+RENESAS R-CAR SATA DRIVER
+R:     Sergey Shtylyov <s.shtylyov@omp.ru>
+S:     Supported
+L:     linux-ide@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+F:     Documentation/devicetree/bindings/ata/renesas,rcar-sata.yaml
+F:     drivers/ata/sata_rcar.c
+
 RENESAS R-CAR THERMAL DRIVERS
 M:     Niklas Söderlund <niklas.soderlund@ragnatech.se>
 L:     linux-renesas-soc@vger.kernel.org
index 1fc3491..ceb987e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 17
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc3
 NAME = Gobble Gobble
 
 # *DOCUMENTATION*
index 17c1c3b..763c73b 100644 (file)
 static int crypto_blake2s_update_arm(struct shash_desc *desc,
                                     const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress);
+       return crypto_blake2s_update(desc, in, inlen, false);
 }
 
 static int crypto_blake2s_final_arm(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress);
+       return crypto_blake2s_final(desc, out, false);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index f2b5a4a..cbcd42d 100644 (file)
@@ -680,6 +680,22 @@ config ARM64_ERRATUM_2051678
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2077057
+       bool "Cortex-A510: 2077057: workaround software-step corrupting SPSR_EL2"
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2077057.
+         Affected Cortex-A510 may corrupt SPSR_EL2 when the a step exception is
+         expected, but a Pointer Authentication trap is taken instead. The
+         erratum causes SPSR_EL1 to be copied to SPSR_EL2, which could allow
+         EL1 to cause a return to EL2 with a guest controlled ELR_EL2.
+
+         This can only happen when EL2 is stepping EL1.
+
+         When these conditions occur, the SPSR_EL2 value is unchanged from the
+         previous guest entry, and can be restored from the in-memory copy.
+
+         If unsure, say Y.
+
 config ARM64_ERRATUM_2119858
        bool "Cortex-A710/X2: 2119858: workaround TRBE overwriting trace data in FILL mode"
        default y
index 0660981..b217941 100644 (file)
@@ -600,6 +600,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                CAP_MIDR_RANGE_LIST(trbe_write_out_of_range_cpus),
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_2077057
+       {
+               .desc = "ARM erratum 2077057",
+               .capability = ARM64_WORKAROUND_2077057,
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2),
+       },
+#endif
 #ifdef CONFIG_ARM64_ERRATUM_2064142
        {
                .desc = "ARM erratum 2064142",
index a4a0063..ecc5958 100644 (file)
@@ -797,6 +797,24 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret)
                        xfer_to_guest_mode_work_pending();
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static int noinstr kvm_arm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_enter_irqoff();
+       ret = kvm_call_hyp_ret(__kvm_vcpu_run, vcpu);
+       guest_state_exit_irqoff();
+
+       return ret;
+}
+
 /**
  * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
  * @vcpu:      The VCPU pointer
@@ -881,9 +899,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                 * Enter the guest
                 */
                trace_kvm_entry(*vcpu_pc(vcpu));
-               guest_enter_irqoff();
+               guest_timing_enter_irqoff();
 
-               ret = kvm_call_hyp_ret(__kvm_vcpu_run, vcpu);
+               ret = kvm_arm_vcpu_enter_exit(vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                vcpu->stat.exits++;
@@ -918,26 +936,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                kvm_arch_vcpu_ctxsync_fp(vcpu);
 
                /*
-                * We may have taken a host interrupt in HYP mode (ie
-                * while executing the guest). This interrupt is still
-                * pending, as we haven't serviced it yet!
+                * We must ensure that any pending interrupts are taken before
+                * we exit guest timing so that timer ticks are accounted as
+                * guest time. Transiently unmask interrupts so that any
+                * pending interrupts are taken.
                 *
-                * We're now back in SVC mode, with interrupts
-                * disabled.  Enabling the interrupts now will have
-                * the effect of taking the interrupt again, in SVC
-                * mode this time.
+                * Per ARM DDI 0487G.b section D1.13.4, an ISB (or other
+                * context synchronization event) is necessary to ensure that
+                * pending interrupts are taken.
                 */
                local_irq_enable();
+               isb();
+               local_irq_disable();
+
+               guest_timing_exit_irqoff();
+
+               local_irq_enable();
 
-               /*
-                * We do local_irq_enable() before calling guest_exit() so
-                * that if a timer interrupt hits while running the guest we
-                * account that tick as being spent in the guest.  We enable
-                * preemption after calling guest_exit() so that if we get
-                * preempted we make sure ticks after that is not counted as
-                * guest time.
-                */
-               guest_exit();
                trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
 
                /* Exit types that need handling before we can be preempted */
index fd2dd26..e3140ab 100644 (file)
@@ -228,6 +228,14 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
 {
        struct kvm_run *run = vcpu->run;
 
+       if (ARM_SERROR_PENDING(exception_index)) {
+               /*
+                * The SError is handled by handle_exit_early(). If the guest
+                * survives it will re-execute the original instruction.
+                */
+               return 1;
+       }
+
        exception_index = ARM_EXCEPTION_CODE(exception_index);
 
        switch (exception_index) {
index 58e14f8..701cfb9 100644 (file)
@@ -402,6 +402,24 @@ static inline bool kvm_hyp_handle_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        return false;
 }
 
+static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu, u64 *exit_code)
+{
+       /*
+        * Check for the conditions of Cortex-A510's #2077057. When these occur
+        * SPSR_EL2 can't be trusted, but isn't needed either as it is
+        * unchanged from the value in vcpu_gp_regs(vcpu)->pstate.
+        * Are we single-stepping the guest, and took a PAC exception from the
+        * active-not-pending state?
+        */
+       if (cpus_have_final_cap(ARM64_WORKAROUND_2077057)               &&
+           vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP                 &&
+           *vcpu_cpsr(vcpu) & DBG_SPSR_SS                              &&
+           ESR_ELx_EC(read_sysreg_el2(SYS_ESR)) == ESR_ELx_EC_PAC)
+               write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
+
+       vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+}
+
 /*
  * Return true when we were able to fixup the guest exit and should return to
  * the guest, false when we should restore the host state and return to the
@@ -413,7 +431,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
         * Save PSTATE early so that we can evaluate the vcpu mode
         * early on.
         */
-       vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+       synchronize_vcpu_pstate(vcpu, exit_code);
 
        /*
         * Check whether we want to repaint the state one way or
@@ -424,7 +442,8 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
                vcpu->arch.fault.esr_el2 = read_sysreg_el2(SYS_ESR);
 
-       if (ARM_SERROR_PENDING(*exit_code)) {
+       if (ARM_SERROR_PENDING(*exit_code) &&
+           ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ) {
                u8 esr_ec = kvm_vcpu_trap_get_class(vcpu);
 
                /*
index e7719e8..9c65b1e 100644 (file)
@@ -55,9 +55,10 @@ WORKAROUND_1418040
 WORKAROUND_1463225
 WORKAROUND_1508412
 WORKAROUND_1542419
-WORKAROUND_2064142
-WORKAROUND_2038923
 WORKAROUND_1902691
+WORKAROUND_2038923
+WORKAROUND_2064142
+WORKAROUND_2077057
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
 WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
index 0a515cd..25860fb 100644 (file)
@@ -74,7 +74,7 @@
 #define EXC(inst_reg,addr,handler)             \
 9:     inst_reg, addr;                         \
        .section __ex_table,"a";                \
-       PTR     9b, handler;                    \
+       PTR_WD  9b, handler;                    \
        .previous
 
 /*
index e59cb62..a25e0b7 100644 (file)
@@ -414,6 +414,24 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        return -ENOIOCTLCMD;
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static int noinstr kvm_mips_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_enter_irqoff();
+       ret = kvm_mips_callbacks->vcpu_run(vcpu);
+       guest_state_exit_irqoff();
+
+       return ret;
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        int r = -EINTR;
@@ -434,7 +452,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
        lose_fpu(1);
 
        local_irq_disable();
-       guest_enter_irqoff();
+       guest_timing_enter_irqoff();
        trace_kvm_enter(vcpu);
 
        /*
@@ -445,10 +463,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
         */
        smp_store_mb(vcpu->mode, IN_GUEST_MODE);
 
-       r = kvm_mips_callbacks->vcpu_run(vcpu);
+       r = kvm_mips_vcpu_enter_exit(vcpu);
+
+       /*
+        * We must ensure that any pending interrupts are taken before
+        * we exit guest timing so that timer ticks are accounted as
+        * guest time. Transiently unmask interrupts so that any
+        * pending interrupts are taken.
+        *
+        * TODO: is there a barrier which ensures that pending interrupts are
+        * recognised? Currently this just hopes that the CPU takes any pending
+        * interrupts between the enable and disable.
+        */
+       local_irq_enable();
+       local_irq_disable();
 
        trace_kvm_out(vcpu);
-       guest_exit_irqoff();
+       guest_timing_exit_irqoff();
        local_irq_enable();
 
 out:
@@ -1168,7 +1199,7 @@ static void kvm_mips_set_c0_status(void)
 /*
  * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
  */
-int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
+static int __kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
        u32 cause = vcpu->arch.host_cp0_cause;
@@ -1357,6 +1388,17 @@ int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
        return ret;
 }
 
+int noinstr kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_exit_irqoff();
+       ret = __kvm_mips_handle_exit(vcpu);
+       guest_state_enter_irqoff();
+
+       return ret;
+}
+
 /* Enable FPU for guest and restore context */
 void kvm_own_fpu(struct kvm_vcpu *vcpu)
 {
index 4adca5a..c706f58 100644 (file)
@@ -458,8 +458,8 @@ void kvm_vz_acquire_htimer(struct kvm_vcpu *vcpu)
 /**
  * _kvm_vz_save_htimer() - Switch to software emulation of guest timer.
  * @vcpu:      Virtual CPU.
- * @compare:   Pointer to write compare value to.
- * @cause:     Pointer to write cause value to.
+ * @out_compare: Pointer to write compare value to.
+ * @out_cause: Pointer to write cause value to.
  *
  * Save VZ guest timer state and switch to software emulation of guest CP0
  * timer. The hard timer must already be in use, so preemption should be
@@ -1541,11 +1541,14 @@ static int kvm_trap_vz_handle_guest_exit(struct kvm_vcpu *vcpu)
 }
 
 /**
- * kvm_trap_vz_handle_cop_unusuable() - Guest used unusable coprocessor.
+ * kvm_trap_vz_handle_cop_unusable() - Guest used unusable coprocessor.
  * @vcpu:      Virtual CPU context.
  *
  * Handle when the guest attempts to use a coprocessor which hasn't been allowed
  * by the root context.
+ *
+ * Return: value indicating whether to resume the host or the guest
+ *        (RESUME_HOST or RESUME_GUEST)
  */
 static int kvm_trap_vz_handle_cop_unusable(struct kvm_vcpu *vcpu)
 {
@@ -1592,6 +1595,9 @@ static int kvm_trap_vz_handle_cop_unusable(struct kvm_vcpu *vcpu)
  *
  * Handle when the guest attempts to use MSA when it is disabled in the root
  * context.
+ *
+ * Return: value indicating whether to resume the host or the guest
+ *        (RESUME_HOST or RESUME_GUEST)
  */
 static int kvm_trap_vz_handle_msa_disabled(struct kvm_vcpu *vcpu)
 {
index 0c5239e..6241660 100644 (file)
@@ -90,6 +90,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
 int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *cntx;
+       struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
 
        /* Mark this VCPU never ran */
        vcpu->arch.ran_atleast_once = false;
@@ -106,6 +107,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        cntx->hstatus |= HSTATUS_SPVP;
        cntx->hstatus |= HSTATUS_SPV;
 
+       /* By default, make CY, TM, and IR counters accessible in VU mode */
+       reset_csr->scounteren = 0x7;
+
        /* Setup VCPU timer */
        kvm_riscv_vcpu_timer_init(vcpu);
 
@@ -699,6 +703,20 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
        csr_write(CSR_HVIP, csr->hvip);
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       guest_state_enter_irqoff();
+       __kvm_riscv_switch_to(&vcpu->arch);
+       guest_state_exit_irqoff();
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        int ret;
@@ -790,9 +808,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                        continue;
                }
 
-               guest_enter_irqoff();
+               guest_timing_enter_irqoff();
 
-               __kvm_riscv_switch_to(&vcpu->arch);
+               kvm_riscv_vcpu_enter_exit(vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                vcpu->stat.exits++;
@@ -812,25 +830,21 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                kvm_riscv_vcpu_sync_interrupts(vcpu);
 
                /*
-                * We may have taken a host interrupt in VS/VU-mode (i.e.
-                * while executing the guest). This interrupt is still
-                * pending, as we haven't serviced it yet!
+                * We must ensure that any pending interrupts are taken before
+                * we exit guest timing so that timer ticks are accounted as
+                * guest time. Transiently unmask interrupts so that any
+                * pending interrupts are taken.
                 *
-                * We're now back in HS-mode with interrupts disabled
-                * so enabling the interrupts now will have the effect
-                * of taking the interrupt again, in HS-mode this time.
+                * There's no barrier which ensures that pending interrupts are
+                * recognised, so we just hope that the CPU takes any pending
+                * interrupts between the enable and disable.
                 */
                local_irq_enable();
+               local_irq_disable();
 
-               /*
-                * We do local_irq_enable() before calling guest_exit() so
-                * that if a timer interrupt hits while running the guest
-                * we account that tick as being spent in the guest. We
-                * enable preemption after calling guest_exit() so that if
-                * we get preempted we make sure ticks after that is not
-                * counted as guest time.
-                */
-               guest_exit();
+               guest_timing_exit_irqoff();
+
+               local_irq_enable();
 
                preempt_enable();
 
index 4ecf377..48f4310 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/version.h>
 #include <asm/csr.h>
 #include <asm/sbi.h>
 #include <asm/kvm_vcpu_timer.h>
@@ -32,7 +33,7 @@ static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
                *out_val = KVM_SBI_IMPID;
                break;
        case SBI_EXT_BASE_GET_IMP_VERSION:
-               *out_val = 0;
+               *out_val = LINUX_VERSION_CODE;
                break;
        case SBI_EXT_BASE_PROBE_EXT:
                if ((cp->a0 >= SBI_EXT_EXPERIMENTAL_START &&
index f9e2fec..59ae28a 100644 (file)
 static int crypto_blake2s_update_x86(struct shash_desc *desc,
                                     const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress);
+       return crypto_blake2s_update(desc, in, inlen, false);
 }
 
 static int crypto_blake2s_final_x86(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress);
+       return crypto_blake2s_final(desc, out, false);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index c914340..a3c7ca8 100644 (file)
@@ -4703,6 +4703,19 @@ static __initconst const struct x86_pmu intel_pmu = {
        .lbr_read               = intel_pmu_lbr_read_64,
        .lbr_save               = intel_pmu_lbr_save,
        .lbr_restore            = intel_pmu_lbr_restore,
+
+       /*
+        * SMM has access to all 4 rings and while traditionally SMM code only
+        * ran in CPL0, 2021-era firmware is starting to make use of CPL3 in SMM.
+        *
+        * Since the EVENTSEL.{USR,OS} CPL filtering makes no distinction
+        * between SMM or not, this results in what should be pure userspace
+        * counters including SMM data.
+        *
+        * This is a clear privilege issue, therefore globally disable
+        * counting SMM by default.
+        */
+       .attr_freeze_on_smi     = 1,
 };
 
 static __init void intel_clovertown_quirk(void)
index 7f406c1..2d33bba 100644 (file)
@@ -897,8 +897,9 @@ static void pt_handle_status(struct pt *pt)
                 * means we are already losing data; need to let the decoder
                 * know.
                 */
-               if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
-                   buf->output_off == pt_buffer_region_size(buf)) {
+               if (!buf->single &&
+                   (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
+                    buf->output_off == pt_buffer_region_size(buf))) {
                        perf_aux_output_flag(&pt->handle,
                                             PERF_AUX_FLAG_TRUNCATED);
                        advance++;
index 631d504..d39e0de 100644 (file)
@@ -82,7 +82,7 @@ KVM_X86_OP_NULL(guest_apic_has_interrupt)
 KVM_X86_OP(load_eoi_exitmap)
 KVM_X86_OP(set_virtual_apic_mode)
 KVM_X86_OP_NULL(set_apic_access_page_addr)
-KVM_X86_OP(deliver_posted_interrupt)
+KVM_X86_OP(deliver_interrupt)
 KVM_X86_OP_NULL(sync_pir_to_irr)
 KVM_X86_OP(set_tss_addr)
 KVM_X86_OP(set_identity_map_addr)
index 6e7c545..6dcccb3 100644 (file)
@@ -1410,7 +1410,8 @@ struct kvm_x86_ops {
        void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
        void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
        void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu);
-       int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
+       void (*deliver_interrupt)(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector);
        int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu);
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr);
index 1bf2ad3..16f548a 100644 (file)
@@ -43,20 +43,6 @@ static inline uint32_t xen_cpuid_base(void)
        return hypervisor_cpuid_base("XenVMMXenVMM", 2);
 }
 
-#ifdef CONFIG_XEN
-extern bool __init xen_hvm_need_lapic(void);
-
-static inline bool __init xen_x2apic_para_available(void)
-{
-       return xen_hvm_need_lapic();
-}
-#else
-static inline bool __init xen_x2apic_para_available(void)
-{
-       return (xen_cpuid_base() != 0);
-}
-#endif
-
 struct pci_dev;
 
 #ifdef CONFIG_XEN_PV_DOM0
index 28be02a..494d4d3 100644 (file)
@@ -554,12 +554,13 @@ void kvm_set_cpu_caps(void)
        );
 
        kvm_cpu_cap_mask(CPUID_7_0_EBX,
-               F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
-               F(BMI2) | F(ERMS) | F(INVPCID) | F(RTM) | 0 /*MPX*/ | F(RDSEED) |
-               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
-               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
-               F(SHA_NI) | F(AVX512BW) | F(AVX512VL) | 0 /*INTEL_PT*/
-       );
+               F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) |
+               F(FDP_EXCPTN_ONLY) | F(SMEP) | F(BMI2) | F(ERMS) | F(INVPCID) |
+               F(RTM) | F(ZERO_FCS_FDS) | 0 /*MPX*/ | F(AVX512F) |
+               F(AVX512DQ) | F(RDSEED) | F(ADX) | F(SMAP) | F(AVX512IFMA) |
+               F(CLFLUSHOPT) | F(CLWB) | 0 /*INTEL_PT*/ | F(AVX512PF) |
+               F(AVX512ER) | F(AVX512CD) | F(SHA_NI) | F(AVX512BW) |
+               F(AVX512VL));
 
        kvm_cpu_cap_mask(CPUID_7_ECX,
                F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ | F(RDPID) |
index 4662469..d7e6fde 100644 (file)
@@ -1096,14 +1096,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                                                       apic->regs + APIC_TMR);
                }
 
-               if (static_call(kvm_x86_deliver_posted_interrupt)(vcpu, vector)) {
-                       kvm_lapic_set_irr(vector, apic);
-                       kvm_make_request(KVM_REQ_EVENT, vcpu);
-                       kvm_vcpu_kick(vcpu);
-               } else {
-                       trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
-                                                  trig_mode, vector);
-               }
+               static_call(kvm_x86_deliver_interrupt)(apic, delivery_mode,
+                                                      trig_mode, vector);
                break;
 
        case APIC_DM_REMRD:
index 6d97629..a290efb 100644 (file)
@@ -3291,6 +3291,21 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
                SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
 
+static void svm_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector)
+{
+       struct kvm_vcpu *vcpu = apic->vcpu;
+
+       if (svm_deliver_avic_intr(vcpu, vector)) {
+               kvm_lapic_set_irr(vector, apic);
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
+               kvm_vcpu_kick(vcpu);
+       } else {
+               trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
+                                          trig_mode, vector);
+       }
+}
+
 static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -3615,7 +3630,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        unsigned long vmcb_pa = svm->current_vmcb->pa;
 
-       kvm_guest_enter_irqoff();
+       guest_state_enter_irqoff();
 
        if (sev_es_guest(vcpu->kvm)) {
                __svm_sev_es_vcpu_run(vmcb_pa);
@@ -3635,7 +3650,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
                vmload(__sme_page_pa(sd->save_area));
        }
 
-       kvm_guest_exit_irqoff();
+       guest_state_exit_irqoff();
 }
 
 static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
@@ -4545,7 +4560,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .pmu_ops = &amd_pmu_ops,
        .nested_ops = &svm_nested_ops,
 
-       .deliver_posted_interrupt = svm_deliver_avic_intr,
+       .deliver_interrupt = svm_deliver_interrupt,
        .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt,
        .update_pi_irte = svm_update_pi_irte,
        .setup_mce = svm_setup_mce,
index aca3ae2..6c27bd0 100644 (file)
@@ -4041,6 +4041,21 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
        return 0;
 }
 
+static void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector)
+{
+       struct kvm_vcpu *vcpu = apic->vcpu;
+
+       if (vmx_deliver_posted_interrupt(vcpu, vector)) {
+               kvm_lapic_set_irr(vector, apic);
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
+               kvm_vcpu_kick(vcpu);
+       } else {
+               trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
+                                          trig_mode, vector);
+       }
+}
+
 /*
  * Set up the vmcs's constant host-state fields, i.e., host-state fields that
  * will not change in the lifetime of the guest.
@@ -6754,7 +6769,7 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                                        struct vcpu_vmx *vmx)
 {
-       kvm_guest_enter_irqoff();
+       guest_state_enter_irqoff();
 
        /* L1D Flush includes CPU buffer clear to mitigate MDS */
        if (static_branch_unlikely(&vmx_l1d_should_flush))
@@ -6770,7 +6785,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 
        vcpu->arch.cr2 = native_read_cr2();
 
-       kvm_guest_exit_irqoff();
+       guest_state_exit_irqoff();
 }
 
 static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
@@ -7768,7 +7783,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .hwapic_isr_update = vmx_hwapic_isr_update,
        .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
        .sync_pir_to_irr = vmx_sync_pir_to_irr,
-       .deliver_posted_interrupt = vmx_deliver_posted_interrupt,
+       .deliver_interrupt = vmx_deliver_interrupt,
        .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
 
        .set_tss_addr = vmx_set_tss_addr,
index 74b53a1..7131d73 100644 (file)
@@ -90,6 +90,8 @@
 u64 __read_mostly kvm_mce_cap_supported = MCG_CTL_P | MCG_SER_P;
 EXPORT_SYMBOL_GPL(kvm_mce_cap_supported);
 
+#define  ERR_PTR_USR(e)  ((void __user *)ERR_PTR(e))
+
 #define emul_to_vcpu(ctxt) \
        ((struct kvm_vcpu *)(ctxt)->vcpu)
 
@@ -4340,7 +4342,7 @@ static inline void __user *kvm_get_attr_addr(struct kvm_device_attr *attr)
        void __user *uaddr = (void __user*)(unsigned long)attr->addr;
 
        if ((u64)(unsigned long)uaddr != attr->addr)
-               return ERR_PTR(-EFAULT);
+               return ERR_PTR_USR(-EFAULT);
        return uaddr;
 }
 
@@ -10041,6 +10043,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                set_debugreg(0, 7);
        }
 
+       guest_timing_enter_irqoff();
+
        for (;;) {
                /*
                 * Assert that vCPU vs. VM APICv state is consistent.  An APICv
@@ -10125,7 +10129,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
         * of accounting via context tracking, but the loss of accuracy is
         * acceptable for all known use cases.
         */
-       vtime_account_guest_exit();
+       guest_timing_exit_irqoff();
 
        if (lapic_in_kernel(vcpu)) {
                s64 delta = vcpu->arch.apic->lapic_timer.advance_expire_delta;
@@ -11639,8 +11643,6 @@ void kvm_arch_sync_events(struct kvm *kvm)
        kvm_free_pit(kvm);
 }
 
-#define  ERR_PTR_USR(e)  ((void __user *)ERR_PTR(e))
-
 /**
  * __x86_set_memory_region: Setup KVM internal memory slot
  *
index 635b75f..767ec7f 100644 (file)
 
 void kvm_spurious_fault(void);
 
-static __always_inline void kvm_guest_enter_irqoff(void)
-{
-       /*
-        * VMENTER enables interrupts (host state), but the kernel state is
-        * interrupts disabled when this is invoked. Also tell RCU about
-        * it. This is the same logic as for exit_to_user_mode().
-        *
-        * This ensures that e.g. latency analysis on the host observes
-        * guest mode as interrupt enabled.
-        *
-        * guest_enter_irqoff() informs context tracking about the
-        * transition to guest mode and if enabled adjusts RCU state
-        * accordingly.
-        */
-       instrumentation_begin();
-       trace_hardirqs_on_prepare();
-       lockdep_hardirqs_on_prepare(CALLER_ADDR0);
-       instrumentation_end();
-
-       guest_enter_irqoff();
-       lockdep_hardirqs_on(CALLER_ADDR0);
-}
-
-static __always_inline void kvm_guest_exit_irqoff(void)
-{
-       /*
-        * VMEXIT disables interrupts (host state), but tracing and lockdep
-        * have them in state 'on' as recorded before entering guest mode.
-        * Same as enter_from_user_mode().
-        *
-        * context_tracking_guest_exit() restores host context and reinstates
-        * RCU if enabled and required.
-        *
-        * This needs to be done immediately after VM-Exit, before any code
-        * that might contain tracepoints or call out to the greater world,
-        * e.g. before x86_spec_ctrl_restore_host().
-        */
-       lockdep_hardirqs_off(CALLER_ADDR0);
-       context_tracking_guest_exit();
-
-       instrumentation_begin();
-       trace_hardirqs_off_finish();
-       instrumentation_end();
-}
-
 #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check)                \
 ({                                                                     \
        bool failed = (consistency_check);                              \
index 4230094..6448c50 100644 (file)
@@ -9,6 +9,7 @@
 #include <xen/events.h>
 #include <xen/interface/memory.h>
 
+#include <asm/apic.h>
 #include <asm/cpu.h>
 #include <asm/smp.h>
 #include <asm/io_apic.h>
@@ -242,15 +243,9 @@ static __init int xen_parse_no_vector_callback(char *arg)
 }
 early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
 
-bool __init xen_hvm_need_lapic(void)
+static __init bool xen_x2apic_available(void)
 {
-       if (xen_pv_domain())
-               return false;
-       if (!xen_hvm_domain())
-               return false;
-       if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
-               return false;
-       return true;
+       return x2apic_supported();
 }
 
 static __init void xen_hvm_guest_late_init(void)
@@ -312,7 +307,7 @@ struct hypervisor_x86 x86_hyper_xen_hvm __initdata = {
        .detect                 = xen_platform_hvm,
        .type                   = X86_HYPER_XEN_HVM,
        .init.init_platform     = xen_hvm_guest_init,
-       .init.x2apic_available  = xen_x2apic_para_available,
+       .init.x2apic_available  = xen_x2apic_available,
        .init.init_mem_mapping  = xen_hvm_init_mem_mapping,
        .init.guest_late_init   = xen_hvm_guest_late_init,
        .runtime.pin_vcpu       = xen_pin_vcpu,
index 5004feb..d47c3d1 100644 (file)
@@ -1341,10 +1341,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
                xen_acpi_sleep_register();
 
-               /* Avoid searching for BIOS MP tables */
-               x86_init.mpparse.find_smp_config = x86_init_noop;
-               x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-
                xen_boot_params_init_edd();
 
 #ifdef CONFIG_ACPI
index 6a8f3b5..4a60192 100644 (file)
@@ -148,28 +148,12 @@ int xen_smp_intr_init_pv(unsigned int cpu)
        return rc;
 }
 
-static void __init xen_fill_possible_map(void)
-{
-       int i, rc;
-
-       if (xen_initial_domain())
-               return;
-
-       for (i = 0; i < nr_cpu_ids; i++) {
-               rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
-               if (rc >= 0) {
-                       num_processors++;
-                       set_cpu_possible(i, true);
-               }
-       }
-}
-
-static void __init xen_filter_cpu_maps(void)
+static void __init _get_smp_config(unsigned int early)
 {
        int i, rc;
        unsigned int subtract = 0;
 
-       if (!xen_initial_domain())
+       if (early)
                return;
 
        num_processors = 0;
@@ -210,7 +194,6 @@ static void __init xen_pv_smp_prepare_boot_cpu(void)
                 * sure the old memory can be recycled. */
                make_lowmem_page_readwrite(xen_initial_gdt);
 
-       xen_filter_cpu_maps();
        xen_setup_vcpu_info_placement();
 
        /*
@@ -476,5 +459,8 @@ static const struct smp_ops xen_smp_ops __initconst = {
 void __init xen_smp_init(void)
 {
        smp_ops = xen_smp_ops;
-       xen_fill_possible_map();
+
+       /* Avoid searching for BIOS MP tables */
+       x86_init.mpparse.find_smp_config = x86_init_noop;
+       x86_init.mpparse.get_smp_config = _get_smp_config;
 }
index d251147..0827b19 100644 (file)
@@ -373,7 +373,7 @@ void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
        struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
        unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
 
-       bip->bip_iter.bi_sector += bytes_done >> 9;
+       bip->bip_iter.bi_sector += bio_integrity_intervals(bi, bytes_done >> 9);
        bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes);
 }
 
index 26bf15c..4f59e0f 100644 (file)
@@ -566,34 +566,37 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct block_device *bdev = iocb->ki_filp->private_data;
        loff_t size = bdev_nr_bytes(bdev);
-       size_t count = iov_iter_count(to);
        loff_t pos = iocb->ki_pos;
        size_t shorted = 0;
        ssize_t ret = 0;
+       size_t count;
 
-       if (unlikely(pos + count > size)) {
+       if (unlikely(pos + iov_iter_count(to) > size)) {
                if (pos >= size)
                        return 0;
                size -= pos;
-               if (count > size) {
-                       shorted = count - size;
-                       iov_iter_truncate(to, size);
-               }
+               shorted = iov_iter_count(to) - size;
+               iov_iter_truncate(to, size);
        }
 
+       count = iov_iter_count(to);
+       if (!count)
+               goto reexpand; /* skip atime */
+
        if (iocb->ki_flags & IOCB_DIRECT) {
                struct address_space *mapping = iocb->ki_filp->f_mapping;
 
                if (iocb->ki_flags & IOCB_NOWAIT) {
-                       if (filemap_range_needs_writeback(mapping, iocb->ki_pos,
-                                               iocb->ki_pos + count - 1))
-                               return -EAGAIN;
+                       if (filemap_range_needs_writeback(mapping, pos,
+                                                         pos + count - 1)) {
+                               ret = -EAGAIN;
+                               goto reexpand;
+                       }
                } else {
-                       ret = filemap_write_and_wait_range(mapping,
-                                               iocb->ki_pos,
-                                               iocb->ki_pos + count - 1);
+                       ret = filemap_write_and_wait_range(mapping, pos,
+                                                          pos + count - 1);
                        if (ret < 0)
-                               return ret;
+                               goto reexpand;
                }
 
                file_accessed(iocb->ki_filp);
@@ -603,12 +606,14 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
                        iocb->ki_pos += ret;
                        count -= ret;
                }
+               iov_iter_revert(to, count - iov_iter_count(to));
                if (ret < 0 || !count)
-                       return ret;
+                       goto reexpand;
        }
 
        ret = filemap_read(iocb, to, ret);
 
+reexpand:
        if (unlikely(shorted))
                iov_iter_reexpand(to, iov_iter_count(to) + shorted);
        return ret;
index 72fe480..5f96a21 100644 (file)
 static int crypto_blake2s_update_generic(struct shash_desc *desc,
                                         const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress_generic);
+       return crypto_blake2s_update(desc, in, inlen, true);
 }
 
 static int crypto_blake2s_final_generic(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress_generic);
+       return crypto_blake2s_final(desc, out, true);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index ba45541..273741d 100644 (file)
@@ -11,6 +11,7 @@ menuconfig ACPI
        depends on ARCH_SUPPORTS_ACPI
        select PNP
        select NLS
+       select CRC32
        default y if X86
        help
          Advanced Configuration and Power Interface (ACPI) support for 
index 67f8802..ba9273f 100644 (file)
@@ -2007,6 +2007,9 @@ static bool ata_log_supported(struct ata_device *dev, u8 log)
 {
        struct ata_port *ap = dev->link->ap;
 
+       if (dev->horkage & ATA_HORKAGE_NO_LOG_DIR)
+               return false;
+
        if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1))
                return false;
        return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
@@ -2445,23 +2448,21 @@ static void ata_dev_config_cpr(struct ata_device *dev)
        struct ata_cpr_log *cpr_log = NULL;
        u8 *desc, *buf = NULL;
 
-       if (!ata_identify_page_supported(dev,
-                                ATA_LOG_CONCURRENT_POSITIONING_RANGES))
+       if (ata_id_major_version(dev->id) < 11 ||
+           !ata_log_supported(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES))
                goto out;
 
        /*
-        * Read IDENTIFY DEVICE data log, page 0x47
-        * (concurrent positioning ranges). We can have at most 255 32B range
-        * descriptors plus a 64B header.
+        * Read the concurrent positioning ranges log (0x47). We can have at
+        * most 255 32B range descriptors plus a 64B header.
         */
        buf_len = (64 + 255 * 32 + 511) & ~511;
        buf = kzalloc(buf_len, GFP_KERNEL);
        if (!buf)
                goto out;
 
-       err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
-                                    ATA_LOG_CONCURRENT_POSITIONING_RANGES,
-                                    buf, buf_len >> 9);
+       err_mask = ata_read_log_page(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES,
+                                    0, buf, buf_len >> 9);
        if (err_mask)
                goto out;
 
@@ -4073,6 +4074,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "WDC WD3000JD-*",             NULL,   ATA_HORKAGE_WD_BROKEN_LPM },
        { "WDC WD3200JD-*",             NULL,   ATA_HORKAGE_WD_BROKEN_LPM },
 
+       /*
+        * This sata dom device goes on a walkabout when the ATA_LOG_DIRECTORY
+        * log page is accessed. Ensure we never ask for this log page with
+        * these devices.
+        */
+       { "SATADOM-ML 3ME",             NULL,   ATA_HORKAGE_NO_LOG_DIR },
+
        /* End Marker */
        { }
 };
index 68613f0..3404a91 100644 (file)
@@ -762,7 +762,7 @@ static bool crng_init_try_arch(struct crng_state *crng)
        return arch_init;
 }
 
-static bool __init crng_init_try_arch_early(struct crng_state *crng)
+static bool __init crng_init_try_arch_early(void)
 {
        int i;
        bool arch_init = true;
@@ -774,7 +774,7 @@ static bool __init crng_init_try_arch_early(struct crng_state *crng)
                        rv = random_get_entropy();
                        arch_init = false;
                }
-               crng->state[i] ^= rv;
+               primary_crng.state[i] ^= rv;
        }
 
        return arch_init;
@@ -788,22 +788,20 @@ static void crng_initialize_secondary(struct crng_state *crng)
        crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
 }
 
-static void __init crng_initialize_primary(struct crng_state *crng)
+static void __init crng_initialize_primary(void)
 {
-       _extract_entropy(&crng->state[4], sizeof(u32) * 12);
-       if (crng_init_try_arch_early(crng) && trust_cpu && crng_init < 2) {
+       _extract_entropy(&primary_crng.state[4], sizeof(u32) * 12);
+       if (crng_init_try_arch_early() && trust_cpu && crng_init < 2) {
                invalidate_batched_entropy();
                numa_crng_init();
                crng_init = 2;
                pr_notice("crng init done (trusting CPU's manufacturer)\n");
        }
-       crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
+       primary_crng.init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
 }
 
-static void crng_finalize_init(struct crng_state *crng)
+static void crng_finalize_init(void)
 {
-       if (crng != &primary_crng || crng_init >= 2)
-               return;
        if (!system_wq) {
                /* We can't call numa_crng_init until we have workqueues,
                 * so mark this for processing later. */
@@ -814,6 +812,7 @@ static void crng_finalize_init(struct crng_state *crng)
        invalidate_batched_entropy();
        numa_crng_init();
        crng_init = 2;
+       crng_need_final_init = false;
        process_random_ready_list();
        wake_up_interruptible(&crng_init_wait);
        kill_fasync(&fasync, SIGIO, POLL_IN);
@@ -980,7 +979,8 @@ static void crng_reseed(struct crng_state *crng, bool use_input_pool)
        memzero_explicit(&buf, sizeof(buf));
        WRITE_ONCE(crng->init_time, jiffies);
        spin_unlock_irqrestore(&crng->lock, flags);
-       crng_finalize_init(crng);
+       if (crng == &primary_crng && crng_init < 2)
+               crng_finalize_init();
 }
 
 static void _extract_crng(struct crng_state *crng, u8 out[CHACHA_BLOCK_SIZE])
@@ -1697,8 +1697,8 @@ int __init rand_initialize(void)
 {
        init_std_data();
        if (crng_need_final_init)
-               crng_finalize_init(&primary_crng);
-       crng_initialize_primary(&primary_crng);
+               crng_finalize_init();
+       crng_initialize_primary();
        crng_global_init_time = jiffies;
        if (ratelimit_disable) {
                urandom_warning.interval = 0;
@@ -1856,7 +1856,10 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                 */
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               input_pool.entropy_count = 0;
+               if (xchg(&input_pool.entropy_count, 0) && random_write_wakeup_bits) {
+                       wake_up_interruptible(&random_write_wait);
+                       kill_fasync(&fasync, SIGIO, POLL_OUT);
+               }
                return 0;
        case RNDRESEEDCRNG:
                if (!capable(CAP_SYS_ADMIN))
@@ -2205,13 +2208,15 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
                        return;
        }
 
-       /* Suspend writing if we're above the trickle threshold.
+       /* Throttle writing if we're above the trickle threshold.
         * We'll be woken up again once below random_write_wakeup_thresh,
-        * or when the calling thread is about to terminate.
+        * when the calling thread is about to terminate, or once
+        * CRNG_RESEED_INTERVAL has lapsed.
         */
-       wait_event_interruptible(random_write_wait,
+       wait_event_interruptible_timeout(random_write_wait,
                        !system_wq || kthread_should_stop() ||
-                       POOL_ENTROPY_BITS() <= random_write_wakeup_bits);
+                       POOL_ENTROPY_BITS() <= random_write_wakeup_bits,
+                       CRNG_RESEED_INTERVAL);
        mix_pool_bytes(buffer, count);
        credit_entropy_bits(entropy);
 }
index 56bf5ad..8f5848a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/xarray.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <linux/uaccess.h>
 #include <linux/syscalls.h>
 #include <linux/dma-heap.h>
@@ -135,6 +136,7 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
        if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds))
                return -EINVAL;
 
+       nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds));
        /* Get the kernel ioctl cmd that matches */
        kcmd = dma_heap_ioctl_cmds[nr];
 
index 3a6d241..5dd2978 100644 (file)
@@ -350,7 +350,7 @@ static int altr_sdram_probe(struct platform_device *pdev)
        if (irq < 0) {
                edac_printk(KERN_ERR, EDAC_MC,
                            "No irq %d in DT\n", irq);
-               return -ENODEV;
+               return irq;
        }
 
        /* Arria10 has a 2nd IRQ */
index 2ccd1db..7197f9f 100644 (file)
@@ -1919,7 +1919,7 @@ static int xgene_edac_probe(struct platform_device *pdev)
                        irq = platform_get_irq_optional(pdev, i);
                        if (irq < 0) {
                                dev_err(&pdev->dev, "No IRQ resource\n");
-                               rc = -EINVAL;
+                               rc = irq;
                                goto out_err;
                        }
                        rc = devm_request_irq(&pdev->dev, irq,
index d8b854f..9a53a4d 100644 (file)
@@ -1408,12 +1408,10 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta
 int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
 
 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
 void amdgpu_acpi_detect(void);
 #else
 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
-static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
 static inline void amdgpu_acpi_detect(void) { }
 static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; }
 static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
@@ -1422,6 +1420,14 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev,
                                                 enum amdgpu_ss ss_state) { return 0; }
 #endif
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
+bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
+bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
+#else
+static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
+static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; }
+#endif
+
 int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
                           uint64_t addr, struct amdgpu_bo **bo,
                           struct amdgpu_bo_va_mapping **mapping);
index 4811b0f..0e12315 100644 (file)
@@ -1031,6 +1031,20 @@ void amdgpu_acpi_detect(void)
        }
 }
 
+#if IS_ENABLED(CONFIG_SUSPEND)
+/**
+ * amdgpu_acpi_is_s3_active
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * returns true if supported, false if not.
+ */
+bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
+{
+       return !(adev->flags & AMD_IS_APU) ||
+               (pm_suspend_target_state == PM_SUSPEND_MEM);
+}
+
 /**
  * amdgpu_acpi_is_s0ix_active
  *
@@ -1040,11 +1054,24 @@ void amdgpu_acpi_detect(void)
  */
 bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
 {
-#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND)
-       if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) {
-               if (adev->flags & AMD_IS_APU)
-                       return pm_suspend_target_state == PM_SUSPEND_TO_IDLE;
+       if (!(adev->flags & AMD_IS_APU) ||
+           (pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
+               return false;
+
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
+               dev_warn_once(adev->dev,
+                             "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
+                             "To use suspend-to-idle change the sleep mode in BIOS setup.\n");
+               return false;
        }
-#endif
+
+#if !IS_ENABLED(CONFIG_AMD_PMC)
+       dev_warn_once(adev->dev,
+                     "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
        return false;
+#else
+       return true;
+#endif /* CONFIG_AMD_PMC */
 }
+
+#endif /* CONFIG_SUSPEND */
index 4c83f1d..63a0899 100644 (file)
@@ -2246,13 +2246,20 @@ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work)
 static int amdgpu_pmops_prepare(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(drm_dev);
 
        /* Return a positive number here so
         * DPM_FLAG_SMART_SUSPEND works properly
         */
        if (amdgpu_device_supports_boco(drm_dev))
-               return pm_runtime_suspended(dev) &&
-                       pm_suspend_via_firmware();
+               return pm_runtime_suspended(dev);
+
+       /* if we will not support s3 or s2i for the device
+        *  then skip suspend
+        */
+       if (!amdgpu_acpi_is_s0ix_active(adev) &&
+           !amdgpu_acpi_is_s3_active(adev))
+               return 1;
 
        return 0;
 }
index 5c3f240..4655702 100644 (file)
@@ -1904,7 +1904,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
        unsigned i;
        int r;
 
-       if (direct_submit && !ring->sched.ready) {
+       if (!direct_submit && !ring->sched.ready) {
                DRM_ERROR("Trying to move memory with ring turned off.\n");
                return -EINVAL;
        }
index 38bb427..a2f8ed0 100644 (file)
@@ -1140,6 +1140,9 @@ static void gmc_v10_0_get_clockgating_state(void *handle, u32 *flags)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 3))
+               return;
+
        adev->mmhub.funcs->get_clockgating(adev, flags);
 
        if (adev->ip_versions[ATHUB_HWIP][0] >= IP_VERSION(2, 1, 0))
index 48005de..bc4ddc3 100644 (file)
@@ -570,32 +570,32 @@ static struct wm_table lpddr5_wm_table = {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 7.95,
-                       .sr_enter_plus_exit_time_us = 9,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.82,
-                       .sr_enter_plus_exit_time_us = 11.196,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.89,
-                       .sr_enter_plus_exit_time_us = 11.24,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.748,
-                       .sr_enter_plus_exit_time_us = 11.102,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
        }
index 4162ce4..9d17c5a 100644 (file)
@@ -329,38 +329,38 @@ static struct clk_bw_params dcn31_bw_params = {
 
 };
 
-static struct wm_table ddr4_wm_table = {
+static struct wm_table ddr5_wm_table = {
        .entries = {
                {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 6.09,
-                       .sr_enter_plus_exit_time_us = 7.14,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
        }
@@ -687,7 +687,7 @@ void dcn31_clk_mgr_construct(
                if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
                        dcn31_bw_params.wm_table = lpddr5_wm_table;
                } else {
-                       dcn31_bw_params.wm_table = ddr4_wm_table;
+                       dcn31_bw_params.wm_table = ddr5_wm_table;
                }
                /* Saved clocks configured at boot for debug purposes */
                 dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
index 4c3ab25..61b8f29 100644 (file)
@@ -5597,6 +5597,26 @@ static bool retrieve_link_cap(struct dc_link *link)
                dp_hw_fw_revision.ieee_fw_rev,
                sizeof(dp_hw_fw_revision.ieee_fw_rev));
 
+       /* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */
+       {
+               uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
+               uint8_t fwrev_mbp_2018[] = { 7, 4 };
+               uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
+
+               /* We also check for the firmware revision as 16,1 models have an
+                * identical device id and are incorrectly quirked otherwise.
+                */
+               if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+                   !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
+                            sizeof(str_mbp_2018)) &&
+                   (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
+                            sizeof(fwrev_mbp_2018)) ||
+                   !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
+                            sizeof(fwrev_mbp_2018_vega)))) {
+                       link->reported_link_cap.link_rate = LINK_RATE_RBR2;
+               }
+       }
+
        memset(&link->dpcd_caps.dsc_caps, '\0',
                        sizeof(link->dpcd_caps.dsc_caps));
        memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
index f3ff141..26ec69b 100644 (file)
@@ -1608,11 +1608,6 @@ static enum dc_status apply_single_controller_ctx_to_hw(
                        pipe_ctx->stream_res.stream_enc,
                        pipe_ctx->stream_res.tg->inst);
 
-       if (dc_is_embedded_signal(pipe_ctx->stream->signal) &&
-               pipe_ctx->stream_res.stream_enc->funcs->reset_fifo)
-               pipe_ctx->stream_res.stream_enc->funcs->reset_fifo(
-                       pipe_ctx->stream_res.stream_enc);
-
        if (dc_is_dp_signal(pipe_ctx->stream->signal))
                dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
 
index bf4436d..b0c08ee 100644 (file)
@@ -902,19 +902,6 @@ void enc1_stream_encoder_stop_dp_info_packets(
 
 }
 
-void enc1_stream_encoder_reset_fifo(
-       struct stream_encoder *enc)
-{
-       struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
-
-       /* set DIG_START to 0x1 to reset FIFO */
-       REG_UPDATE(DIG_FE_CNTL, DIG_START, 1);
-       udelay(100);
-
-       /* write 0 to take the FIFO out of reset */
-       REG_UPDATE(DIG_FE_CNTL, DIG_START, 0);
-}
-
 void enc1_stream_encoder_dp_blank(
        struct dc_link *link,
        struct stream_encoder *enc)
@@ -1600,8 +1587,6 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
                enc1_stream_encoder_send_immediate_sdp_message,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index a146a41..687d7e4 100644 (file)
@@ -626,9 +626,6 @@ void enc1_stream_encoder_send_immediate_sdp_message(
 void enc1_stream_encoder_stop_dp_info_packets(
        struct stream_encoder *enc);
 
-void enc1_stream_encoder_reset_fifo(
-       struct stream_encoder *enc);
-
 void enc1_stream_encoder_dp_blank(
        struct dc_link *link,
        struct stream_encoder *enc);
index 8a70f92..aab25ca 100644 (file)
@@ -593,8 +593,6 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
                enc1_stream_encoder_send_immediate_sdp_message,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index 8daa127..a04ca4a 100644 (file)
@@ -789,8 +789,6 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = {
                enc3_stream_encoder_update_dp_info_packets,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index 073f8b6..c88e113 100644 (file)
@@ -164,10 +164,6 @@ struct stream_encoder_funcs {
        void (*stop_dp_info_packets)(
                struct stream_encoder *enc);
 
-       void (*reset_fifo)(
-               struct stream_encoder *enc
-       );
-
        void (*dp_blank)(
                struct dc_link *link,
                struct stream_encoder *enc);
index 777f717..a420729 100644 (file)
@@ -3696,14 +3696,14 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
 
 static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu)
 {
-       struct smu_table_context *table_context = &smu->smu_table;
-       PPTable_t *smc_pptable = table_context->driver_pptable;
+       uint16_t *mgpu_fan_boost_limit_rpm;
 
+       GET_PPTABLE_MEMBER(MGpuFanBoostLimitRpm, &mgpu_fan_boost_limit_rpm);
        /*
         * Skip the MGpuFanBoost setting for those ASICs
         * which do not support it
         */
-       if (!smc_pptable->MGpuFanBoostLimitRpm)
+       if (*mgpu_fan_boost_limit_rpm == 0)
                return 0;
 
        return smu_cmn_send_smc_msg_with_param(smu,
index 1a376e9..d610e48 100644 (file)
@@ -959,6 +959,9 @@ static int check_overlay_dst(struct intel_overlay *overlay,
        const struct intel_crtc_state *pipe_config =
                overlay->crtc->config;
 
+       if (rec->dst_height == 0 || rec->dst_width == 0)
+               return -EINVAL;
+
        if (rec->dst_x < pipe_config->pipe_src_w &&
            rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
            rec->dst_y < pipe_config->pipe_src_h &&
index 40faa18..dbd7d0d 100644 (file)
@@ -345,10 +345,11 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port)
 static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
        struct intel_uncore *uncore = &i915->uncore;
        u32 val;
 
-       val = intel_uncore_read(uncore, TCSS_DDI_STATUS(dig_port->tc_phy_fia_idx));
+       val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port));
        if (val == 0xffffffff) {
                drm_dbg_kms(&i915->drm,
                            "Port %s: PHY in TCCOLD, assuming not complete\n",
index 3a5b247..1736efa 100644 (file)
@@ -2505,9 +2505,14 @@ static int eb_pin_timeline(struct i915_execbuffer *eb, struct intel_context *ce,
                                      timeout) < 0) {
                        i915_request_put(rq);
 
-                       tl = intel_context_timeline_lock(ce);
+                       /*
+                        * Error path, cannot use intel_context_timeline_lock as
+                        * that is user interruptable and this clean up step
+                        * must be done.
+                        */
+                       mutex_lock(&ce->timeline->mutex);
                        intel_context_exit(ce);
-                       intel_context_timeline_unlock(tl);
+                       mutex_unlock(&ce->timeline->mutex);
 
                        if (nonblock)
                                return -EWOULDBLOCK;
index f9240d4..3aabe16 100644 (file)
@@ -206,6 +206,11 @@ struct intel_guc {
                 * context usage for overflows.
                 */
                struct delayed_work work;
+
+               /**
+                * @shift: Right shift value for the gpm timestamp
+                */
+               u32 shift;
        } timestamp;
 
 #ifdef CONFIG_DRM_I915_SELFTEST
index e751720..154ad72 100644 (file)
@@ -1113,6 +1113,19 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
        if (new_start == lower_32_bits(*prev_start))
                return;
 
+       /*
+        * When gt is unparked, we update the gt timestamp and start the ping
+        * worker that updates the gt_stamp every POLL_TIME_CLKS. As long as gt
+        * is unparked, all switched in contexts will have a start time that is
+        * within +/- POLL_TIME_CLKS of the most recent gt_stamp.
+        *
+        * If neither gt_stamp nor new_start has rolled over, then the
+        * gt_stamp_hi does not need to be adjusted, however if one of them has
+        * rolled over, we need to adjust gt_stamp_hi accordingly.
+        *
+        * The below conditions address the cases of new_start rollover and
+        * gt_stamp_last rollover respectively.
+        */
        if (new_start < gt_stamp_last &&
            (new_start - gt_stamp_last) <= POLL_TIME_CLKS)
                gt_stamp_hi++;
@@ -1124,17 +1137,45 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
        *prev_start = ((u64)gt_stamp_hi << 32) | new_start;
 }
 
-static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
+/*
+ * GuC updates shared memory and KMD reads it. Since this is not synchronized,
+ * we run into a race where the value read is inconsistent. Sometimes the
+ * inconsistency is in reading the upper MSB bytes of the last_in value when
+ * this race occurs. 2 types of cases are seen - upper 8 bits are zero and upper
+ * 24 bits are zero. Since these are non-zero values, it is non-trivial to
+ * determine validity of these values. Instead we read the values multiple times
+ * until they are consistent. In test runs, 3 attempts results in consistent
+ * values. The upper bound is set to 6 attempts and may need to be tuned as per
+ * any new occurences.
+ */
+static void __get_engine_usage_record(struct intel_engine_cs *engine,
+                                     u32 *last_in, u32 *id, u32 *total)
 {
        struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine);
+       int i = 0;
+
+       do {
+               *last_in = READ_ONCE(rec->last_switch_in_stamp);
+               *id = READ_ONCE(rec->current_context_index);
+               *total = READ_ONCE(rec->total_runtime);
+
+               if (READ_ONCE(rec->last_switch_in_stamp) == *last_in &&
+                   READ_ONCE(rec->current_context_index) == *id &&
+                   READ_ONCE(rec->total_runtime) == *total)
+                       break;
+       } while (++i < 6);
+}
+
+static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
+{
        struct intel_engine_guc_stats *stats = &engine->stats.guc;
        struct intel_guc *guc = &engine->gt->uc.guc;
-       u32 last_switch = rec->last_switch_in_stamp;
-       u32 ctx_id = rec->current_context_index;
-       u32 total = rec->total_runtime;
+       u32 last_switch, ctx_id, total;
 
        lockdep_assert_held(&guc->timestamp.lock);
 
+       __get_engine_usage_record(engine, &last_switch, &ctx_id, &total);
+
        stats->running = ctx_id != ~0U && last_switch;
        if (stats->running)
                __extend_last_switch(guc, &stats->start_gt_clk, last_switch);
@@ -1149,23 +1190,51 @@ static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
        }
 }
 
-static void guc_update_pm_timestamp(struct intel_guc *guc,
-                                   struct intel_engine_cs *engine,
-                                   ktime_t *now)
+static u32 gpm_timestamp_shift(struct intel_gt *gt)
+{
+       intel_wakeref_t wakeref;
+       u32 reg, shift;
+
+       with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+               reg = intel_uncore_read(gt->uncore, RPM_CONFIG0);
+
+       shift = (reg & GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >>
+               GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT;
+
+       return 3 - shift;
+}
+
+static u64 gpm_timestamp(struct intel_gt *gt)
+{
+       u32 lo, hi, old_hi, loop = 0;
+
+       hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
+       do {
+               lo = intel_uncore_read(gt->uncore, MISC_STATUS0);
+               old_hi = hi;
+               hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
+       } while (old_hi != hi && loop++ < 2);
+
+       return ((u64)hi << 32) | lo;
+}
+
+static void guc_update_pm_timestamp(struct intel_guc *guc, ktime_t *now)
 {
-       u32 gt_stamp_now, gt_stamp_hi;
+       struct intel_gt *gt = guc_to_gt(guc);
+       u32 gt_stamp_lo, gt_stamp_hi;
+       u64 gpm_ts;
 
        lockdep_assert_held(&guc->timestamp.lock);
 
        gt_stamp_hi = upper_32_bits(guc->timestamp.gt_stamp);
-       gt_stamp_now = intel_uncore_read(engine->uncore,
-                                        RING_TIMESTAMP(engine->mmio_base));
+       gpm_ts = gpm_timestamp(gt) >> guc->timestamp.shift;
+       gt_stamp_lo = lower_32_bits(gpm_ts);
        *now = ktime_get();
 
-       if (gt_stamp_now < lower_32_bits(guc->timestamp.gt_stamp))
+       if (gt_stamp_lo < lower_32_bits(guc->timestamp.gt_stamp))
                gt_stamp_hi++;
 
-       guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_now;
+       guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_lo;
 }
 
 /*
@@ -1208,8 +1277,12 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now)
        if (!in_reset && intel_gt_pm_get_if_awake(gt)) {
                stats_saved = *stats;
                gt_stamp_saved = guc->timestamp.gt_stamp;
+               /*
+                * Update gt_clks, then gt timestamp to simplify the 'gt_stamp -
+                * start_gt_clk' calculation below for active engines.
+                */
                guc_update_engine_gt_clks(engine);
-               guc_update_pm_timestamp(guc, engine, now);
+               guc_update_pm_timestamp(guc, now);
                intel_gt_pm_put_async(gt);
                if (i915_reset_count(gpu_error) != reset_count) {
                        *stats = stats_saved;
@@ -1241,8 +1314,8 @@ static void __reset_guc_busyness_stats(struct intel_guc *guc)
 
        spin_lock_irqsave(&guc->timestamp.lock, flags);
 
+       guc_update_pm_timestamp(guc, &unused);
        for_each_engine(engine, gt, id) {
-               guc_update_pm_timestamp(guc, engine, &unused);
                guc_update_engine_gt_clks(engine);
                engine->stats.guc.prev_total = 0;
        }
@@ -1259,10 +1332,11 @@ static void __update_guc_busyness_stats(struct intel_guc *guc)
        ktime_t unused;
 
        spin_lock_irqsave(&guc->timestamp.lock, flags);
-       for_each_engine(engine, gt, id) {
-               guc_update_pm_timestamp(guc, engine, &unused);
+
+       guc_update_pm_timestamp(guc, &unused);
+       for_each_engine(engine, gt, id)
                guc_update_engine_gt_clks(engine);
-       }
+
        spin_unlock_irqrestore(&guc->timestamp.lock, flags);
 }
 
@@ -1335,10 +1409,15 @@ void intel_guc_busyness_park(struct intel_gt *gt)
 void intel_guc_busyness_unpark(struct intel_gt *gt)
 {
        struct intel_guc *guc = &gt->uc.guc;
+       unsigned long flags;
+       ktime_t unused;
 
        if (!guc_submission_initialized(guc))
                return;
 
+       spin_lock_irqsave(&guc->timestamp.lock, flags);
+       guc_update_pm_timestamp(guc, &unused);
+       spin_unlock_irqrestore(&guc->timestamp.lock, flags);
        mod_delayed_work(system_highpri_wq, &guc->timestamp.work,
                         guc->timestamp.ping_delay);
 }
@@ -1783,6 +1862,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
        spin_lock_init(&guc->timestamp.lock);
        INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping);
        guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ;
+       guc->timestamp.shift = gpm_timestamp_shift(gt);
 
        return 0;
 }
index 5ae812d..0633888 100644 (file)
@@ -1522,7 +1522,7 @@ capture_engine(struct intel_engine_cs *engine,
        struct i915_request *rq = NULL;
        unsigned long flags;
 
-       ee = intel_engine_coredump_alloc(engine, GFP_KERNEL);
+       ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL);
        if (!ee)
                return NULL;
 
index c32420c..c2bb33f 100644 (file)
@@ -2684,7 +2684,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   RING_WAIT            (1 << 11) /* gen3+, PRBx_CTL */
 #define   RING_WAIT_SEMAPHORE  (1 << 10) /* gen6+ */
 
-#define GUCPMTIMESTAMP          _MMIO(0xC3E8)
+#define MISC_STATUS0           _MMIO(0xA500)
+#define MISC_STATUS1           _MMIO(0xA504)
 
 /* There are 16 64-bit CS General Purpose Registers per-engine on Gen8+ */
 #define GEN8_RING_CS_GPR(base, n)      _MMIO((base) + 0x600 + (n) * 8)
index 00404ba..2735b8e 100644 (file)
@@ -158,12 +158,6 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane,
        case LAYER_1:
                kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE;
                break;
-       case LAYER_2:
-               kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL1_ENABLE;
-               break;
-       case LAYER_3:
-               kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL2_ENABLE;
-               break;
        }
 
        kmb->plane_status[plane_id].disable = true;
index 0655582..4cfb6c0 100644 (file)
@@ -361,7 +361,11 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
                bridge_state =
                        drm_atomic_get_new_bridge_state(state,
                                                        mxsfb->bridge);
-               bus_format = bridge_state->input_bus_cfg.format;
+               if (!bridge_state)
+                       bus_format = MEDIA_BUS_FMT_FIXED;
+               else
+                       bus_format = bridge_state->input_bus_cfg.format;
+
                if (bus_format == MEDIA_BUS_FMT_FIXED) {
                        dev_warn_once(drm->dev,
                                      "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
index d0f52d5..64e423d 100644 (file)
@@ -38,7 +38,7 @@ nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size)
                *addr += bios->imaged_addr;
        }
 
-       if (unlikely(*addr + size >= bios->size)) {
+       if (unlikely(*addr + size > bios->size)) {
                nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr);
                return false;
        }
index c903b74..35f0d5e 100644 (file)
@@ -3322,7 +3322,7 @@ static int cm_lap_handler(struct cm_work *work)
        ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av);
        if (ret) {
                rdma_destroy_ah_attr(&ah_attr);
-               return -EINVAL;
+               goto deref;
        }
 
        spin_lock_irq(&cm_id_priv->lock);
index 27a00ce..c447526 100644 (file)
@@ -67,8 +67,8 @@ static const char * const cma_events[] = {
        [RDMA_CM_EVENT_TIMEWAIT_EXIT]    = "timewait exit",
 };
 
-static void cma_set_mgid(struct rdma_id_private *id_priv, struct sockaddr *addr,
-                        union ib_gid *mgid);
+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
+                             enum ib_gid_type gid_type);
 
 const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event)
 {
@@ -1846,17 +1846,19 @@ static void destroy_mc(struct rdma_id_private *id_priv,
                if (dev_addr->bound_dev_if)
                        ndev = dev_get_by_index(dev_addr->net,
                                                dev_addr->bound_dev_if);
-               if (ndev) {
+               if (ndev && !send_only) {
+                       enum ib_gid_type gid_type;
                        union ib_gid mgid;
 
-                       cma_set_mgid(id_priv, (struct sockaddr *)&mc->addr,
-                                    &mgid);
-
-                       if (!send_only)
-                               cma_igmp_send(ndev, &mgid, false);
-
-                       dev_put(ndev);
+                       gid_type = id_priv->cma_dev->default_gid_type
+                                          [id_priv->id.port_num -
+                                           rdma_start_port(
+                                                   id_priv->cma_dev->device)];
+                       cma_iboe_set_mgid((struct sockaddr *)&mc->addr, &mgid,
+                                         gid_type);
+                       cma_igmp_send(ndev, &mgid, false);
                }
+               dev_put(ndev);
 
                cancel_work_sync(&mc->iboe_join.work);
        }
index 2b72c4f..9d6ac9d 100644 (file)
@@ -95,6 +95,7 @@ struct ucma_context {
        u64                     uid;
 
        struct list_head        list;
+       struct list_head        mc_list;
        struct work_struct      close_work;
 };
 
@@ -105,6 +106,7 @@ struct ucma_multicast {
 
        u64                     uid;
        u8                      join_state;
+       struct list_head        list;
        struct sockaddr_storage addr;
 };
 
@@ -198,6 +200,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
 
        INIT_WORK(&ctx->close_work, ucma_close_id);
        init_completion(&ctx->comp);
+       INIT_LIST_HEAD(&ctx->mc_list);
        /* So list_del() will work if we don't do ucma_finish_ctx() */
        INIT_LIST_HEAD(&ctx->list);
        ctx->file = file;
@@ -484,19 +487,19 @@ err1:
 
 static void ucma_cleanup_multicast(struct ucma_context *ctx)
 {
-       struct ucma_multicast *mc;
-       unsigned long index;
+       struct ucma_multicast *mc, *tmp;
 
-       xa_for_each(&multicast_table, index, mc) {
-               if (mc->ctx != ctx)
-                       continue;
+       xa_lock(&multicast_table);
+       list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
+               list_del(&mc->list);
                /*
                 * At this point mc->ctx->ref is 0 so the mc cannot leave the
                 * lock on the reader and this is enough serialization
                 */
-               xa_erase(&multicast_table, index);
+               __xa_erase(&multicast_table, mc->id);
                kfree(mc);
        }
+       xa_unlock(&multicast_table);
 }
 
 static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
@@ -1469,12 +1472,16 @@ static ssize_t ucma_process_join(struct ucma_file *file,
        mc->uid = cmd->uid;
        memcpy(&mc->addr, addr, cmd->addr_size);
 
-       if (xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
+       xa_lock(&multicast_table);
+       if (__xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
                     GFP_KERNEL)) {
                ret = -ENOMEM;
                goto err_free_mc;
        }
 
+       list_add_tail(&mc->list, &ctx->mc_list);
+       xa_unlock(&multicast_table);
+
        mutex_lock(&ctx->mutex);
        ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
                                  join_state, mc);
@@ -1500,8 +1507,11 @@ err_leave_multicast:
        mutex_unlock(&ctx->mutex);
        ucma_cleanup_mc_events(mc);
 err_xa_erase:
-       xa_erase(&multicast_table, mc->id);
+       xa_lock(&multicast_table);
+       list_del(&mc->list);
+       __xa_erase(&multicast_table, mc->id);
 err_free_mc:
+       xa_unlock(&multicast_table);
        kfree(mc);
 err_put_ctx:
        ucma_put_ctx(ctx);
@@ -1569,15 +1579,17 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
                mc = ERR_PTR(-EINVAL);
        else if (!refcount_inc_not_zero(&mc->ctx->ref))
                mc = ERR_PTR(-ENXIO);
-       else
-               __xa_erase(&multicast_table, mc->id);
-       xa_unlock(&multicast_table);
 
        if (IS_ERR(mc)) {
+               xa_unlock(&multicast_table);
                ret = PTR_ERR(mc);
                goto out;
        }
 
+       list_del(&mc->list);
+       __xa_erase(&multicast_table, mc->id);
+       xa_unlock(&multicast_table);
+
        mutex_lock(&mc->ctx->mutex);
        rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr);
        mutex_unlock(&mc->ctx->mutex);
index 9091229..aec60d4 100644 (file)
@@ -55,7 +55,7 @@ union hfi1_ipoib_flow {
  */
 struct ipoib_txreq {
        struct sdma_txreq           txreq;
-       struct hfi1_sdma_header     sdma_hdr;
+       struct hfi1_sdma_header     *sdma_hdr;
        int                         sdma_status;
        int                         complete;
        struct hfi1_ipoib_dev_priv *priv;
index e1a2b02..5d814af 100644 (file)
@@ -22,26 +22,35 @@ static int hfi1_ipoib_dev_init(struct net_device *dev)
        int ret;
 
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+       if (!dev->tstats)
+               return -ENOMEM;
 
        ret = priv->netdev_ops->ndo_init(dev);
        if (ret)
-               return ret;
+               goto out_ret;
 
        ret = hfi1_netdev_add_data(priv->dd,
                                   qpn_from_mac(priv->netdev->dev_addr),
                                   dev);
        if (ret < 0) {
                priv->netdev_ops->ndo_uninit(dev);
-               return ret;
+               goto out_ret;
        }
 
        return 0;
+out_ret:
+       free_percpu(dev->tstats);
+       dev->tstats = NULL;
+       return ret;
 }
 
 static void hfi1_ipoib_dev_uninit(struct net_device *dev)
 {
        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 
+       free_percpu(dev->tstats);
+       dev->tstats = NULL;
+
        hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr));
 
        priv->netdev_ops->ndo_uninit(dev);
@@ -166,12 +175,7 @@ static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
        hfi1_ipoib_rxq_deinit(priv->netdev);
 
        free_percpu(dev->tstats);
-}
-
-static void hfi1_ipoib_free_rdma_netdev(struct net_device *dev)
-{
-       hfi1_ipoib_netdev_dtor(dev);
-       free_netdev(dev);
+       dev->tstats = NULL;
 }
 
 static void hfi1_ipoib_set_id(struct net_device *dev, int id)
@@ -211,24 +215,23 @@ static int hfi1_ipoib_setup_rn(struct ib_device *device,
        priv->port_num = port_num;
        priv->netdev_ops = netdev->netdev_ops;
 
-       netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
-
        ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);
 
        rc = hfi1_ipoib_txreq_init(priv);
        if (rc) {
                dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
-               hfi1_ipoib_free_rdma_netdev(netdev);
                return rc;
        }
 
        rc = hfi1_ipoib_rxq_init(netdev);
        if (rc) {
                dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
-               hfi1_ipoib_free_rdma_netdev(netdev);
+               hfi1_ipoib_txreq_deinit(priv);
                return rc;
        }
 
+       netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
+
        netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
        netdev->needs_free_netdev = true;
 
index f401089..d6bbdb8 100644 (file)
@@ -122,7 +122,7 @@ static void hfi1_ipoib_free_tx(struct ipoib_txreq *tx, int budget)
                dd_dev_warn(priv->dd,
                            "%s: Status = 0x%x pbc 0x%llx txq = %d sde = %d\n",
                            __func__, tx->sdma_status,
-                           le64_to_cpu(tx->sdma_hdr.pbc), tx->txq->q_idx,
+                           le64_to_cpu(tx->sdma_hdr->pbc), tx->txq->q_idx,
                            tx->txq->sde->this_idx);
        }
 
@@ -231,7 +231,7 @@ static int hfi1_ipoib_build_tx_desc(struct ipoib_txreq *tx,
 {
        struct hfi1_devdata *dd = txp->dd;
        struct sdma_txreq *txreq = &tx->txreq;
-       struct hfi1_sdma_header *sdma_hdr = &tx->sdma_hdr;
+       struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr;
        u16 pkt_bytes =
                sizeof(sdma_hdr->pbc) + (txp->hdr_dwords << 2) + tx->skb->len;
        int ret;
@@ -256,7 +256,7 @@ static void hfi1_ipoib_build_ib_tx_headers(struct ipoib_txreq *tx,
                                           struct ipoib_txparms *txp)
 {
        struct hfi1_ipoib_dev_priv *priv = tx->txq->priv;
-       struct hfi1_sdma_header *sdma_hdr = &tx->sdma_hdr;
+       struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr;
        struct sk_buff *skb = tx->skb;
        struct hfi1_pportdata *ppd = ppd_from_ibp(txp->ibp);
        struct rdma_ah_attr *ah_attr = txp->ah_attr;
@@ -483,7 +483,7 @@ static int hfi1_ipoib_send_dma_single(struct net_device *dev,
        if (likely(!ret)) {
 tx_ok:
                trace_sdma_output_ibhdr(txq->priv->dd,
-                                       &tx->sdma_hdr.hdr,
+                                       &tx->sdma_hdr->hdr,
                                        ib_is_sc5(txp->flow.sc5));
                hfi1_ipoib_check_queue_depth(txq);
                return NETDEV_TX_OK;
@@ -547,7 +547,7 @@ static int hfi1_ipoib_send_dma_list(struct net_device *dev,
        hfi1_ipoib_check_queue_depth(txq);
 
        trace_sdma_output_ibhdr(txq->priv->dd,
-                               &tx->sdma_hdr.hdr,
+                               &tx->sdma_hdr->hdr,
                                ib_is_sc5(txp->flow.sc5));
 
        if (!netdev_xmit_more())
@@ -683,7 +683,8 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
 {
        struct net_device *dev = priv->netdev;
        u32 tx_ring_size, tx_item_size;
-       int i;
+       struct hfi1_ipoib_circ_buf *tx_ring;
+       int i, j;
 
        /*
         * Ring holds 1 less than tx_ring_size
@@ -701,7 +702,9 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
 
        for (i = 0; i < dev->num_tx_queues; i++) {
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
+               struct ipoib_txreq *tx;
 
+               tx_ring = &txq->tx_ring;
                iowait_init(&txq->wait,
                            0,
                            hfi1_ipoib_flush_txq,
@@ -725,14 +728,19 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
                                             priv->dd->node);
 
                txq->tx_ring.items =
-                       kcalloc_node(tx_ring_size, tx_item_size,
-                                    GFP_KERNEL, priv->dd->node);
+                       kvzalloc_node(array_size(tx_ring_size, tx_item_size),
+                                     GFP_KERNEL, priv->dd->node);
                if (!txq->tx_ring.items)
                        goto free_txqs;
 
                txq->tx_ring.max_items = tx_ring_size;
-               txq->tx_ring.shift = ilog2(tx_ring_size);
+               txq->tx_ring.shift = ilog2(tx_item_size);
                txq->tx_ring.avail = hfi1_ipoib_ring_hwat(txq);
+               tx_ring = &txq->tx_ring;
+               for (j = 0; j < tx_ring_size; j++)
+                       hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr =
+                               kzalloc_node(sizeof(*tx->sdma_hdr),
+                                            GFP_KERNEL, priv->dd->node);
 
                netif_tx_napi_add(dev, &txq->napi,
                                  hfi1_ipoib_poll_tx_ring,
@@ -746,7 +754,10 @@ free_txqs:
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
 
                netif_napi_del(&txq->napi);
-               kfree(txq->tx_ring.items);
+               tx_ring = &txq->tx_ring;
+               for (j = 0; j < tx_ring_size; j++)
+                       kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr);
+               kvfree(tx_ring->items);
        }
 
        kfree(priv->txqs);
@@ -780,17 +791,20 @@ static void hfi1_ipoib_drain_tx_list(struct hfi1_ipoib_txq *txq)
 
 void hfi1_ipoib_txreq_deinit(struct hfi1_ipoib_dev_priv *priv)
 {
-       int i;
+       int i, j;
 
        for (i = 0; i < priv->netdev->num_tx_queues; i++) {
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
+               struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring;
 
                iowait_cancel_work(&txq->wait);
                iowait_sdma_drain(&txq->wait);
                hfi1_ipoib_drain_tx_list(txq);
                netif_napi_del(&txq->napi);
                hfi1_ipoib_drain_tx_ring(txq);
-               kfree(txq->tx_ring.items);
+               for (j = 0; j < tx_ring->max_items; j++)
+                       kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr);
+               kvfree(tx_ring->items);
        }
 
        kfree(priv->txqs);
index 1c3d972..93b1650 100644 (file)
@@ -3237,7 +3237,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
        case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
                ew = kmalloc(sizeof *ew, GFP_ATOMIC);
                if (!ew)
-                       break;
+                       return;
 
                INIT_WORK(&ew->work, handle_port_mgmt_change_event);
                memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
index 3305f27..ae50b56 100644 (file)
@@ -3073,6 +3073,8 @@ do_write:
        case IB_WR_ATOMIC_FETCH_AND_ADD:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
                        goto inv_err;
+               if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1)))
+                       goto inv_err;
                if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
                                          wqe->atomic_wr.remote_addr,
                                          wqe->atomic_wr.rkey,
index 368959a..df03d84 100644 (file)
@@ -644,14 +644,9 @@ static inline struct siw_sqe *orq_get_current(struct siw_qp *qp)
        return &qp->orq[qp->orq_get % qp->attrs.orq_size];
 }
 
-static inline struct siw_sqe *orq_get_tail(struct siw_qp *qp)
-{
-       return &qp->orq[qp->orq_put % qp->attrs.orq_size];
-}
-
 static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
 {
-       struct siw_sqe *orq_e = orq_get_tail(qp);
+       struct siw_sqe *orq_e = &qp->orq[qp->orq_put % qp->attrs.orq_size];
 
        if (READ_ONCE(orq_e->flags) == 0)
                return orq_e;
index 60116f2..875ea6f 100644 (file)
@@ -1153,11 +1153,12 @@ static int siw_check_tx_fence(struct siw_qp *qp)
 
        spin_lock_irqsave(&qp->orq_lock, flags);
 
-       rreq = orq_get_current(qp);
-
        /* free current orq entry */
+       rreq = orq_get_current(qp);
        WRITE_ONCE(rreq->flags, 0);
 
+       qp->orq_get++;
+
        if (qp->tx_ctx.orq_fence) {
                if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) {
                        pr_warn("siw: [QP %u]: fence resume: bad status %d\n",
@@ -1165,10 +1166,12 @@ static int siw_check_tx_fence(struct siw_qp *qp)
                        rv = -EPROTO;
                        goto out;
                }
-               /* resume SQ processing */
+               /* resume SQ processing, if possible */
                if (tx_waiting->sqe.opcode == SIW_OP_READ ||
                    tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
-                       rreq = orq_get_tail(qp);
+
+                       /* SQ processing was stopped because of a full ORQ */
+                       rreq = orq_get_free(qp);
                        if (unlikely(!rreq)) {
                                pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp));
                                rv = -EPROTO;
@@ -1181,15 +1184,14 @@ static int siw_check_tx_fence(struct siw_qp *qp)
                        resume_tx = 1;
 
                } else if (siw_orq_empty(qp)) {
+                       /*
+                        * SQ processing was stopped by fenced work request.
+                        * Resume since all previous Read's are now completed.
+                        */
                        qp->tx_ctx.orq_fence = 0;
                        resume_tx = 1;
-               } else {
-                       pr_warn("siw: [QP %u]: fence resume: orq idx: %d:%d\n",
-                               qp_id(qp), qp->orq_get, qp->orq_put);
-                       rv = -EPROTO;
                }
        }
-       qp->orq_get++;
 out:
        spin_unlock_irqrestore(&qp->orq_lock, flags);
 
index a3dd2cb..54ef367 100644 (file)
@@ -313,7 +313,8 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
 
        if (atomic_inc_return(&sdev->num_qp) > SIW_MAX_QP) {
                siw_dbg(base_dev, "too many QP's\n");
-               return -ENOMEM;
+               rv = -ENOMEM;
+               goto err_atomic;
        }
        if (attrs->qp_type != IB_QPT_RC) {
                siw_dbg(base_dev, "only RC QP's supported\n");
index 78d2ee9..1b58611 100644 (file)
@@ -615,10 +615,9 @@ static int wm97xx_register_touch(struct wm97xx *wm)
         * extensions)
         */
        wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
-       if (!wm->touch_dev) {
-               ret = -ENOMEM;
-               goto touch_err;
-       }
+       if (!wm->touch_dev)
+               return -ENOMEM;
+
        platform_set_drvdata(wm->touch_dev, wm);
        wm->touch_dev->dev.parent = wm->dev;
        wm->touch_dev->dev.platform_data = pdata;
@@ -629,9 +628,6 @@ static int wm97xx_register_touch(struct wm97xx *wm)
        return 0;
 touch_reg_err:
        platform_device_put(wm->touch_dev);
-touch_err:
-       input_unregister_device(wm->input_dev);
-       wm->input_dev = NULL;
 
        return ret;
 }
@@ -639,8 +635,6 @@ touch_err:
 static void wm97xx_unregister_touch(struct wm97xx *wm)
 {
        platform_device_unregister(wm->touch_dev);
-       input_unregister_device(wm->input_dev);
-       wm->input_dev = NULL;
 }
 
 static int _wm97xx_probe(struct wm97xx *wm)
index dc338ac..b10fb52 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/export.h>
 #include <linux/kmemleak.h>
 #include <linux/cc_platform.h>
+#include <linux/iopoll.h>
 #include <asm/pci-direct.h>
 #include <asm/iommu.h>
 #include <asm/apic.h>
@@ -834,6 +835,7 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)
                status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
                if (status & (MMIO_STATUS_GALOG_RUN_MASK))
                        break;
+               udelay(10);
        }
 
        if (WARN_ON(i >= LOOP_TIMEOUT))
index f912fe4..a673195 100644 (file)
@@ -569,9 +569,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
                                            fn, &intel_ir_domain_ops,
                                            iommu);
        if (!iommu->ir_domain) {
-               irq_domain_free_fwnode(fn);
                pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
-               goto out_free_bitmap;
+               goto out_free_fwnode;
        }
        iommu->ir_msi_domain =
                arch_create_remap_msi_irq_domain(iommu->ir_domain,
@@ -595,7 +594,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
                if (dmar_enable_qi(iommu)) {
                        pr_err("Failed to enable queued invalidation\n");
-                       goto out_free_bitmap;
+                       goto out_free_ir_domain;
                }
        }
 
@@ -619,6 +618,14 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
        return 0;
 
+out_free_ir_domain:
+       if (iommu->ir_msi_domain)
+               irq_domain_remove(iommu->ir_msi_domain);
+       iommu->ir_msi_domain = NULL;
+       irq_domain_remove(iommu->ir_domain);
+       iommu->ir_domain = NULL;
+out_free_fwnode:
+       irq_domain_free_fwnode(fn);
 out_free_bitmap:
        bitmap_free(bitmap);
 out_free_pages:
index 50ee27b..06fee74 100644 (file)
@@ -349,6 +349,7 @@ EXPORT_SYMBOL_GPL(ioasid_alloc);
 
 /**
  * ioasid_get - obtain a reference to the IOASID
+ * @ioasid: the ID to get
  */
 void ioasid_get(ioasid_t ioasid)
 {
index 8b86406..107dcf5 100644 (file)
@@ -207,9 +207,14 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
 
 static void dev_iommu_free(struct device *dev)
 {
-       iommu_fwspec_free(dev);
-       kfree(dev->iommu);
+       struct dev_iommu *param = dev->iommu;
+
        dev->iommu = NULL;
+       if (param->fwspec) {
+               fwnode_handle_put(param->fwspec->iommu_fwnode);
+               kfree(param->fwspec);
+       }
+       kfree(param);
 }
 
 static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
@@ -980,17 +985,6 @@ static int iommu_group_device_count(struct iommu_group *group)
        return ret;
 }
 
-/**
- * iommu_group_for_each_dev - iterate over each device in the group
- * @group: the group
- * @data: caller opaque data to be passed to callback function
- * @fn: caller supplied callback function
- *
- * This function is called by group users to iterate over group devices.
- * Callers should hold a reference count to the group during callback.
- * The group->mutex is held across callbacks, which will block calls to
- * iommu_group_add/remove_device.
- */
 static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
                                      int (*fn)(struct device *, void *))
 {
@@ -1005,7 +999,17 @@ static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
        return ret;
 }
 
-
+/**
+ * iommu_group_for_each_dev - iterate over each device in the group
+ * @group: the group
+ * @data: caller opaque data to be passed to callback function
+ * @fn: caller supplied callback function
+ *
+ * This function is called by group users to iterate over group devices.
+ * Callers should hold a reference count to the group during callback.
+ * The group->mutex is held across callbacks, which will block calls to
+ * iommu_group_add/remove_device.
+ */
 int iommu_group_for_each_dev(struct iommu_group *group, void *data,
                             int (*fn)(struct device *, void *))
 {
@@ -3032,6 +3036,7 @@ EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);
  * iommu_sva_bind_device() - Bind a process address space to a device
  * @dev: the device
  * @mm: the mm to bind, caller must hold a reference to it
+ * @drvdata: opaque data pointer to pass to bind callback
  *
  * Create a bond between device and address space, allowing the device to access
  * the mm using the returned PASID. If a bond already exists between @device and
index 9174965..980e4af 100644 (file)
@@ -1085,7 +1085,7 @@ static __maybe_unused int omap_iommu_runtime_resume(struct device *dev)
 }
 
 /**
- * omap_iommu_suspend_prepare - prepare() dev_pm_ops implementation
+ * omap_iommu_prepare - prepare() dev_pm_ops implementation
  * @dev:       iommu device
  *
  * This function performs the necessary checks to determine if the IOMMU
index 5881d05..4d38bd7 100644 (file)
@@ -5869,10 +5869,6 @@ int md_run(struct mddev *mddev)
                nowait = nowait && blk_queue_nowait(bdev_get_queue(rdev->bdev));
        }
 
-       /* Set the NOWAIT flags if all underlying devices support it */
-       if (nowait)
-               blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
-
        if (!bioset_initialized(&mddev->bio_set)) {
                err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
                if (err)
@@ -6010,6 +6006,10 @@ int md_run(struct mddev *mddev)
                else
                        blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
                blk_queue_flag_set(QUEUE_FLAG_IO_STAT, mddev->queue);
+
+               /* Set the NOWAIT flags if all underlying devices support it */
+               if (nowait)
+                       blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
        }
        if (pers->sync_request) {
                if (mddev->kobj.sd &&
index 45f5787..bd87012 100644 (file)
@@ -67,7 +67,7 @@ static const unsigned int sd_au_size[] = {
                __res & __mask;                                         \
        })
 
-#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 2000
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 1000
 #define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000
 
 struct sd_busy_data {
@@ -1664,6 +1664,12 @@ static int sd_poweroff_notify(struct mmc_card *card)
                goto out;
        }
 
+       /* Find out when the command is completed. */
+       err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+                               MMC_BUSY_EXTR_SINGLE);
+       if (err)
+               goto out;
+
        cb_data.card = card;
        cb_data.reg_buf = reg_buf;
        err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
index 16d1c7a..b6eb75f 100644 (file)
@@ -705,12 +705,12 @@ static int moxart_remove(struct platform_device *pdev)
        if (!IS_ERR_OR_NULL(host->dma_chan_rx))
                dma_release_channel(host->dma_chan_rx);
        mmc_remove_host(mmc);
-       mmc_free_host(mmc);
 
        writel(0, host->base + REG_INTERRUPT_MASK);
        writel(0, host->base + REG_POWER_CONTROL);
        writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
               host->base + REG_CLOCK_CONTROL);
+       mmc_free_host(mmc);
 
        return 0;
 }
index a593b1f..0f3658b 100644 (file)
@@ -524,12 +524,16 @@ static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
 
 static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
+       int ret;
        u32 value;
        struct device *dev = mmc_dev(host->mmc);
 
        if (of_device_is_compatible(dev->of_node, "fsl,ls1043a-esdhc") ||
-           of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc"))
-               dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+           of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc")) {
+               ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+               if (ret)
+                       return ret;
+       }
 
        value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
 
index bcc595c..104dcd7 100644 (file)
@@ -405,6 +405,9 @@ static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
        struct dma_slave_config cfg = { 0, };
 
        res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        cfg.direction = direction;
 
        if (direction == DMA_DEV_TO_MEM) {
index 7b1457a..c0c9144 100644 (file)
@@ -36,6 +36,7 @@ config NET_DSA_LANTIQ_GSWIP
 config NET_DSA_MT7530
        tristate "MediaTek MT753x and MT7621 Ethernet switch support"
        select NET_DSA_TAG_MTK
+       select MEDIATEK_GE_PHY
        help
          This enables support for the MediaTek MT7530, MT7531, and MT7621
          Ethernet switch chips.
index 492ac38..a359329 100644 (file)
@@ -721,7 +721,9 @@ static void xgbe_stop_timers(struct xgbe_prv_data *pdata)
                if (!channel->tx_ring)
                        break;
 
+               /* Deactivate the Tx timer */
                del_timer_sync(&channel->tx_timer);
+               channel->tx_timer_active = 0;
        }
 }
 
@@ -2550,6 +2552,14 @@ read_again:
                        buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
                        len += buf2_len;
 
+                       if (buf2_len > rdata->rx.buf.dma_len) {
+                               /* Hardware inconsistency within the descriptors
+                                * that has resulted in a length underflow.
+                                */
+                               error = 1;
+                               goto skip_data;
+                       }
+
                        if (!skb) {
                                skb = xgbe_create_skb(pdata, napi, rdata,
                                                      buf1_len);
@@ -2579,8 +2589,10 @@ skip_data:
                if (!last || context_next)
                        goto read_again;
 
-               if (!skb)
+               if (!skb || error) {
+                       dev_kfree_skb(skb);
                        goto next_packet;
+               }
 
                /* Be sure we don't exceed the configured MTU */
                max_len = netdev->mtu + ETH_HLEN;
index 2ad7f57..f7621ab 100644 (file)
@@ -301,7 +301,7 @@ static int gve_adminq_parse_err(struct gve_priv *priv, u32 status)
  */
 static int gve_adminq_kick_and_wait(struct gve_priv *priv)
 {
-       u32 tail, head;
+       int tail, head;
        int i;
 
        tail = ioread32be(&priv->reg_bar0->adminq_event_counter);
index c3def0e..8d06c9d 100644 (file)
@@ -115,7 +115,8 @@ enum e1000_boards {
        board_pch_lpt,
        board_pch_spt,
        board_pch_cnp,
-       board_pch_tgp
+       board_pch_tgp,
+       board_pch_adp
 };
 
 struct e1000_ps_page {
@@ -502,6 +503,7 @@ extern const struct e1000_info e1000_pch_lpt_info;
 extern const struct e1000_info e1000_pch_spt_info;
 extern const struct e1000_info e1000_pch_cnp_info;
 extern const struct e1000_info e1000_pch_tgp_info;
+extern const struct e1000_info e1000_pch_adp_info;
 extern const struct e1000_info e1000_es2_info;
 
 void e1000e_ptp_init(struct e1000_adapter *adapter);
index 5e4fc9b..c908c84 100644 (file)
@@ -6021,3 +6021,23 @@ const struct e1000_info e1000_pch_tgp_info = {
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &spt_nvm_ops,
 };
+
+const struct e1000_info e1000_pch_adp_info = {
+       .mac                    = e1000_pch_adp,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_APME_IN_WUC,
+       .flags2                 = FLAG2_HAS_PHY_STATS
+                                 | FLAG2_HAS_EEE,
+       .pba                    = 26,
+       .max_hw_frame_size      = 9022,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &spt_nvm_ops,
+};
index 635a959..a42aeb5 100644 (file)
@@ -52,6 +52,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_pch_spt]         = &e1000_pch_spt_info,
        [board_pch_cnp]         = &e1000_pch_cnp_info,
        [board_pch_tgp]         = &e1000_pch_tgp_info,
+       [board_pch_adp]         = &e1000_pch_adp_info,
 };
 
 struct e1000_reg_info {
@@ -6341,7 +6342,8 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter)
        u32 mac_data;
        u16 phy_data;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
                /* Request ME configure the device for S0ix */
                mac_data = er32(H2ME);
                mac_data |= E1000_H2ME_START_DPG;
@@ -6490,7 +6492,8 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter)
        u16 phy_data;
        u32 i = 0;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
                /* Request ME unconfigure the device from S0ix */
                mac_data = er32(H2ME);
                mac_data &= ~E1000_H2ME_START_DPG;
@@ -7898,22 +7901,22 @@ static const struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_tgp },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_tgp },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM19), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V19), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_tgp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM19), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V19), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_adp },
 
        { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
 };
index 2e02cc6..80c5cec 100644 (file)
@@ -144,6 +144,7 @@ enum i40e_state_t {
        __I40E_VIRTCHNL_OP_PENDING,
        __I40E_RECOVERY_MODE,
        __I40E_VF_RESETS_DISABLED,      /* disable resets during i40e_remove */
+       __I40E_IN_REMOVE,
        __I40E_VFS_RELEASING,
        /* This must be last as it determines the size of the BITMAP */
        __I40E_STATE_SIZE__,
index f70c478..0c4b7df 100644 (file)
@@ -5372,7 +5372,15 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
        /* There is no need to reset BW when mqprio mode is on.  */
        if (pf->flags & I40E_FLAG_TC_MQPRIO)
                return 0;
-       if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+
+       if (!vsi->mqprio_qopt.qopt.hw) {
+               if (pf->flags & I40E_FLAG_DCB_ENABLED)
+                       goto skip_reset;
+
+               if (IS_ENABLED(CONFIG_I40E_DCB) &&
+                   i40e_dcb_hw_get_num_tc(&pf->hw) == 1)
+                       goto skip_reset;
+
                ret = i40e_set_bw_limit(vsi, vsi->seid, 0);
                if (ret)
                        dev_info(&pf->pdev->dev,
@@ -5380,6 +5388,8 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
                                 vsi->seid);
                return ret;
        }
+
+skip_reset:
        memset(&bw_data, 0, sizeof(bw_data));
        bw_data.tc_valid_bits = enabled_tc;
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
@@ -10853,6 +10863,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit,
                                   bool lock_acquired)
 {
        int ret;
+
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return;
        /* Now we wait for GRST to settle out.
         * We don't have to delete the VEBs or VSIs from the hw switch
         * because the reset will make them disappear.
@@ -12212,6 +12225,8 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
 
                vsi->req_queue_pairs = queue_count;
                i40e_prep_for_reset(pf);
+               if (test_bit(__I40E_IN_REMOVE, pf->state))
+                       return pf->alloc_rss_size;
 
                pf->alloc_rss_size = new_rss_size;
 
@@ -13038,6 +13053,10 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog,
        if (need_reset)
                i40e_prep_for_reset(pf);
 
+       /* VSI shall be deleted in a moment, just return EINVAL */
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return -EINVAL;
+
        old_prog = xchg(&vsi->xdp_prog, prog);
 
        if (need_reset) {
@@ -15928,8 +15947,13 @@ static void i40e_remove(struct pci_dev *pdev)
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
-       while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
+       /* Grab __I40E_RESET_RECOVERY_PENDING and set __I40E_IN_REMOVE
+        * flags, once they are set, i40e_rebuild should not be called as
+        * i40e_prep_for_reset always returns early.
+        */
+       while (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
                usleep_range(1000, 2000);
+       set_bit(__I40E_IN_REMOVE, pf->state);
 
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
@@ -16128,6 +16152,9 @@ static void i40e_pci_error_reset_done(struct pci_dev *pdev)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
 
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return;
+
        i40e_reset_and_rebuild(pf, false, false);
 }
 
index 812e681..c14e06c 100644 (file)
@@ -224,7 +224,7 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
        struct mlx5_wqe_eth_seg  eth;
-       struct mlx5_wqe_data_seg data[0];
+       struct mlx5_wqe_data_seg data[];
 };
 
 struct mlx5e_rx_wqe_ll {
@@ -241,8 +241,8 @@ struct mlx5e_umr_wqe {
        struct mlx5_wqe_umr_ctrl_seg   uctrl;
        struct mlx5_mkey_seg           mkc;
        union {
-               struct mlx5_mtt inline_mtts[0];
-               struct mlx5_klm inline_klms[0];
+               DECLARE_FLEX_ARRAY(struct mlx5_mtt, inline_mtts);
+               DECLARE_FLEX_ARRAY(struct mlx5_klm, inline_klms);
        };
 };
 
index 00449df..c1e0749 100644 (file)
@@ -570,7 +570,8 @@ static int mlx5e_htb_convert_rate(struct mlx5e_priv *priv, u64 rate,
 
 static void mlx5e_htb_convert_ceil(struct mlx5e_priv *priv, u64 ceil, u32 *max_average_bw)
 {
-       *max_average_bw = div_u64(ceil, BYTES_IN_MBIT);
+       /* Hardware treats 0 as "unlimited", set at least 1. */
+       *max_average_bw = max_t(u32, div_u64(ceil, BYTES_IN_MBIT), 1);
 
        qos_dbg(priv->mdev, "Convert: ceil %llu -> max_average_bw %u\n",
                ceil, *max_average_bw);
index 9c076aa..b6f5c1b 100644 (file)
@@ -183,18 +183,7 @@ void mlx5e_rep_bond_unslave(struct mlx5_eswitch *esw,
 
 static bool mlx5e_rep_is_lag_netdev(struct net_device *netdev)
 {
-       struct mlx5e_rep_priv *rpriv;
-       struct mlx5e_priv *priv;
-
-       /* A given netdev is not a representor or not a slave of LAG configuration */
-       if (!mlx5e_eswitch_rep(netdev) || !netif_is_lag_port(netdev))
-               return false;
-
-       priv = netdev_priv(netdev);
-       rpriv = priv->ppriv;
-
-       /* Egress acl forward to vport is supported only non-uplink representor */
-       return rpriv->rep->vport != MLX5_VPORT_UPLINK;
+       return netif_is_lag_port(netdev) && mlx5e_eswitch_vf_rep(netdev);
 }
 
 static void mlx5e_rep_changelowerstate_event(struct net_device *netdev, void *ptr)
@@ -210,9 +199,6 @@ static void mlx5e_rep_changelowerstate_event(struct net_device *netdev, void *pt
        u16 fwd_vport_num;
        int err;
 
-       if (!mlx5e_rep_is_lag_netdev(netdev))
-               return;
-
        info = ptr;
        lag_info = info->lower_state_info;
        /* This is not an event of a representor becoming active slave */
@@ -266,9 +252,6 @@ static void mlx5e_rep_changeupper_event(struct net_device *netdev, void *ptr)
        struct net_device *lag_dev;
        struct mlx5e_priv *priv;
 
-       if (!mlx5e_rep_is_lag_netdev(netdev))
-               return;
-
        priv = netdev_priv(netdev);
        rpriv = priv->ppriv;
        lag_dev = info->upper_dev;
@@ -293,6 +276,19 @@ static int mlx5e_rep_esw_bond_netevent(struct notifier_block *nb,
                                       unsigned long event, void *ptr)
 {
        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+       struct mlx5e_rep_priv *rpriv;
+       struct mlx5e_rep_bond *bond;
+       struct mlx5e_priv *priv;
+
+       if (!mlx5e_rep_is_lag_netdev(netdev))
+               return NOTIFY_DONE;
+
+       bond = container_of(nb, struct mlx5e_rep_bond, nb);
+       priv = netdev_priv(netdev);
+       rpriv = mlx5_eswitch_get_uplink_priv(priv->mdev->priv.eswitch, REP_ETH);
+       /* Verify VF representor is on the same device of the bond handling the netevent. */
+       if (rpriv->uplink_priv.bond != bond)
+               return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_CHANGELOWERSTATE:
index c6d2f8c..48dc121 100644 (file)
@@ -491,7 +491,7 @@ void mlx5e_rep_bridge_init(struct mlx5e_priv *priv)
        }
 
        br_offloads->netdev_nb.notifier_call = mlx5_esw_bridge_switchdev_port_event;
-       err = register_netdevice_notifier(&br_offloads->netdev_nb);
+       err = register_netdevice_notifier_net(&init_net, &br_offloads->netdev_nb);
        if (err) {
                esw_warn(mdev, "Failed to register bridge offloads netdevice notifier (err=%d)\n",
                         err);
@@ -509,7 +509,9 @@ err_register_swdev_blk:
 err_register_swdev:
        destroy_workqueue(br_offloads->wq);
 err_alloc_wq:
+       rtnl_lock();
        mlx5_esw_bridge_cleanup(esw);
+       rtnl_unlock();
 }
 
 void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
@@ -524,7 +526,7 @@ void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
                return;
 
        cancel_delayed_work_sync(&br_offloads->update_work);
-       unregister_netdevice_notifier(&br_offloads->netdev_nb);
+       unregister_netdevice_notifier_net(&init_net, &br_offloads->netdev_nb);
        unregister_switchdev_blocking_notifier(&br_offloads->nb_blk);
        unregister_switchdev_notifier(&br_offloads->nb);
        destroy_workqueue(br_offloads->wq);
index 4cdf8e5..b789af0 100644 (file)
@@ -167,6 +167,11 @@ static inline u16 mlx5e_txqsq_get_next_pi(struct mlx5e_txqsq *sq, u16 size)
        return pi;
 }
 
+static inline u16 mlx5e_shampo_get_cqe_header_index(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
+{
+       return be16_to_cpu(cqe->shampo.header_entry_index) & (rq->mpwqe.shampo->hd_per_wq - 1);
+}
+
 struct mlx5e_shampo_umr {
        u16 len;
 };
index 338d65e..56e10c8 100644 (file)
@@ -341,8 +341,10 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
 
        /* copy the inline part if required */
        if (sq->min_inline_mode != MLX5_INLINE_MODE_NONE) {
-               memcpy(eseg->inline_hdr.start, xdptxd->data, MLX5E_XDP_MIN_INLINE);
+               memcpy(eseg->inline_hdr.start, xdptxd->data, sizeof(eseg->inline_hdr.start));
                eseg->inline_hdr.sz = cpu_to_be16(MLX5E_XDP_MIN_INLINE);
+               memcpy(dseg, xdptxd->data + sizeof(eseg->inline_hdr.start),
+                      MLX5E_XDP_MIN_INLINE - sizeof(eseg->inline_hdr.start));
                dma_len  -= MLX5E_XDP_MIN_INLINE;
                dma_addr += MLX5E_XDP_MIN_INLINE;
                dseg++;
index 2db9573..b56fea1 100644 (file)
@@ -157,11 +157,20 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
        /* Tunnel mode */
        if (mode == XFRM_MODE_TUNNEL) {
                eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
-               eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
                if (xo->proto == IPPROTO_IPV6)
                        eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
-               if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP)
+
+               switch (xo->inner_ipproto) {
+               case IPPROTO_UDP:
                        eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+                       fallthrough;
+               case IPPROTO_TCP:
+                       /* IP | ESP | IP | [TCP | UDP] */
+                       eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
+                       break;
+               default:
+                       break;
+               }
                return;
        }
 
index b98db50..428881e 100644 (file)
@@ -131,14 +131,17 @@ static inline bool
 mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                                  struct mlx5_wqe_eth_seg *eseg)
 {
-       struct xfrm_offload *xo = xfrm_offload(skb);
+       u8 inner_ipproto;
 
        if (!mlx5e_ipsec_eseg_meta(eseg))
                return false;
 
        eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
-       if (xo->inner_ipproto) {
-               eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM | MLX5_ETH_WQE_L3_INNER_CSUM;
+       inner_ipproto = xfrm_offload(skb)->inner_ipproto;
+       if (inner_ipproto) {
+               eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM;
+               if (inner_ipproto == IPPROTO_TCP || inner_ipproto == IPPROTO_UDP)
+                       eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
        } else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
                eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
                sq->stats->csum_partial_inner++;
index e86ccc2..ee0a8f5 100644 (file)
@@ -1117,7 +1117,7 @@ static void mlx5e_shampo_update_ipv6_udp_hdr(struct mlx5e_rq *rq, struct ipv6hdr
 static void mlx5e_shampo_update_fin_psh_flags(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
                                              struct tcphdr *skb_tcp_hd)
 {
-       u16 header_index = be16_to_cpu(cqe->shampo.header_entry_index);
+       u16 header_index = mlx5e_shampo_get_cqe_header_index(rq, cqe);
        struct tcphdr *last_tcp_hd;
        void *last_hd_addr;
 
@@ -1871,7 +1871,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
        return skb;
 }
 
-static void
+static struct sk_buff *
 mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                          struct mlx5_cqe64 *cqe, u16 header_index)
 {
@@ -1895,7 +1895,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size);
 
                if (unlikely(!skb))
-                       return;
+                       return NULL;
 
                /* queue up for recycling/reuse */
                page_ref_inc(head->page);
@@ -1907,7 +1907,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                                     ALIGN(head_size, sizeof(long)));
                if (unlikely(!skb)) {
                        rq->stats->buff_alloc_err++;
-                       return;
+                       return NULL;
                }
 
                prefetchw(skb->data);
@@ -1918,9 +1918,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                skb->tail += head_size;
                skb->len  += head_size;
        }
-       rq->hw_gro_data->skb = skb;
-       NAPI_GRO_CB(skb)->count = 1;
-       skb_shinfo(skb)->gso_size = mpwrq_get_cqe_byte_cnt(cqe) - head_size;
+       return skb;
 }
 
 static void
@@ -1973,13 +1971,14 @@ mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index)
 static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
        u16 data_bcnt           = mpwrq_get_cqe_byte_cnt(cqe) - cqe->shampo.header_size;
-       u16 header_index        = be16_to_cpu(cqe->shampo.header_entry_index);
+       u16 header_index        = mlx5e_shampo_get_cqe_header_index(rq, cqe);
        u32 wqe_offset          = be32_to_cpu(cqe->shampo.data_offset);
        u16 cstrides            = mpwrq_get_cqe_consumed_strides(cqe);
        u32 data_offset         = wqe_offset & (PAGE_SIZE - 1);
        u32 cqe_bcnt            = mpwrq_get_cqe_byte_cnt(cqe);
        u16 wqe_id              = be16_to_cpu(cqe->wqe_id);
        u32 page_idx            = wqe_offset >> PAGE_SHIFT;
+       u16 head_size           = cqe->shampo.header_size;
        struct sk_buff **skb    = &rq->hw_gro_data->skb;
        bool flush              = cqe->shampo.flush;
        bool match              = cqe->shampo.match;
@@ -2011,9 +2010,16 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
        }
 
        if (!*skb) {
-               mlx5e_skb_from_cqe_shampo(rq, wi, cqe, header_index);
+               if (likely(head_size))
+                       *skb = mlx5e_skb_from_cqe_shampo(rq, wi, cqe, header_index);
+               else
+                       *skb = mlx5e_skb_from_cqe_mpwrq_nonlinear(rq, wi, cqe_bcnt, data_offset,
+                                                                 page_idx);
                if (unlikely(!*skb))
                        goto free_hd_entry;
+
+               NAPI_GRO_CB(*skb)->count = 1;
+               skb_shinfo(*skb)->gso_size = cqe_bcnt - head_size;
        } else {
                NAPI_GRO_CB(*skb)->count++;
                if (NAPI_GRO_CB(*skb)->count == 2 &&
@@ -2027,8 +2033,10 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
                }
        }
 
-       di = &wi->umr.dma_info[page_idx];
-       mlx5e_fill_skb_data(*skb, rq, di, data_bcnt, data_offset);
+       if (likely(head_size)) {
+               di = &wi->umr.dma_info[page_idx];
+               mlx5e_fill_skb_data(*skb, rq, di, data_bcnt, data_offset);
+       }
 
        mlx5e_shampo_complete_rx_cqe(rq, cqe, cqe_bcnt, *skb);
        if (flush)
index 3d908a7..2022fa4 100644 (file)
@@ -1414,7 +1414,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                if (err)
                        goto err_out;
 
-               if (!attr->chain && esw_attr->int_port) {
+               if (!attr->chain && esw_attr->int_port &&
+                   attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
                        /* If decap route device is internal port, change the
                         * source vport value in reg_c0 back to uplink just in
                         * case the rule performs goto chain > 0. If we have a miss
@@ -3191,6 +3192,18 @@ actions_match_supported(struct mlx5e_priv *priv,
                return false;
        }
 
+       if (!(~actions &
+             (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+               NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action");
+               return false;
+       }
+
+       if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+           actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
+               NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
+               return false;
+       }
+
        if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
            !modify_header_match_supported(priv, &parse_attr->spec, flow_action,
                                           actions, ct_flow, ct_clear, extack))
index 7fd33b3..ee7ecb8 100644 (file)
@@ -208,7 +208,7 @@ static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)
        int cpy1_sz = 2 * ETH_ALEN;
        int cpy2_sz = ihs - cpy1_sz;
 
-       memcpy(vhdr, skb->data, cpy1_sz);
+       memcpy(&vhdr->addrs, skb->data, cpy1_sz);
        vhdr->h_vlan_proto = skb->vlan_proto;
        vhdr->h_vlan_TCI = cpu_to_be16(skb_vlan_tag_get(skb));
        memcpy(&vhdr->h_vlan_encapsulated_proto, skb->data + cpy1_sz, cpy2_sz);
index f690f43..05e08ce 100644 (file)
@@ -1574,6 +1574,8 @@ struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw)
 {
        struct mlx5_esw_bridge_offloads *br_offloads;
 
+       ASSERT_RTNL();
+
        br_offloads = kvzalloc(sizeof(*br_offloads), GFP_KERNEL);
        if (!br_offloads)
                return ERR_PTR(-ENOMEM);
@@ -1590,6 +1592,8 @@ void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw)
 {
        struct mlx5_esw_bridge_offloads *br_offloads = esw->br_offloads;
 
+       ASSERT_RTNL();
+
        if (!br_offloads)
                return;
 
index 3401188..51ac24e 100644 (file)
@@ -21,7 +21,7 @@ DECLARE_EVENT_CLASS(mlx5_esw_bridge_fdb_template,
                            __field(unsigned int, used)
                            ),
                    TP_fast_assign(
-                           strncpy(__entry->dev_name,
+                           strscpy(__entry->dev_name,
                                    netdev_name(fdb->dev),
                                    IFNAMSIZ);
                            memcpy(__entry->addr, fdb->key.addr, ETH_ALEN);
index 0b0234f..84dbe46 100644 (file)
@@ -132,7 +132,7 @@ static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev)
 {
        struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
 
-       del_timer(&fw_reset->timer);
+       del_timer_sync(&fw_reset->timer);
 }
 
 static void mlx5_sync_reset_clear_reset_requested(struct mlx5_core_dev *dev, bool poll_health)
index d5e4763..df58cba 100644 (file)
@@ -121,12 +121,13 @@ u32 mlx5_chains_get_nf_ft_chain(struct mlx5_fs_chains *chains)
 
 u32 mlx5_chains_get_prio_range(struct mlx5_fs_chains *chains)
 {
-       if (!mlx5_chains_prios_supported(chains))
-               return 1;
-
        if (mlx5_chains_ignore_flow_level_supported(chains))
                return UINT_MAX;
 
+       if (!chains->dev->priv.eswitch ||
+           chains->dev->priv.eswitch->mode != MLX5_ESWITCH_OFFLOADS)
+               return 1;
+
        /* We should get here only for eswitch case */
        return FDB_TC_MAX_PRIO;
 }
@@ -211,7 +212,7 @@ static int
 create_chain_restore(struct fs_chain *chain)
 {
        struct mlx5_eswitch *esw = chain->chains->dev->priv.eswitch;
-       char modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)];
+       u8 modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
        struct mlx5_fs_chains *chains = chain->chains;
        enum mlx5e_tc_attr_to_reg chain_to_reg;
        struct mlx5_modify_hdr *mod_hdr;
index 1ef2b6a..7b16a11 100644 (file)
@@ -406,23 +406,24 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 
        switch (module_id) {
        case MLX5_MODULE_ID_SFP:
-               mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &query.offset);
+               mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
                break;
        case MLX5_MODULE_ID_QSFP:
        case MLX5_MODULE_ID_QSFP_PLUS:
        case MLX5_MODULE_ID_QSFP28:
-               mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &query.offset);
+               mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
                break;
        default:
                mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
                return -EINVAL;
        }
 
-       if (query.offset + size > MLX5_EEPROM_PAGE_LENGTH)
+       if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
                /* Cross pages read, read until offset 256 in low page */
-               size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
+               size = MLX5_EEPROM_PAGE_LENGTH - offset;
 
        query.size = size;
+       query.offset = offset;
 
        return mlx5_query_mcia(dev, &query, data);
 }
index dc7e5ea..148d431 100644 (file)
@@ -145,9 +145,9 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
        skb_put(skb, byte_cnt - ETH_FCS_LEN);
        eth_skb_pad(skb);
        skb->protocol = eth_type_trans(skb, netdev);
-       netif_rx(skb);
        netdev->stats.rx_bytes += skb->len;
        netdev->stats.rx_packets++;
+       netif_rx(skb);
 }
 
 static int sparx5_inject(struct sparx5 *sparx5,
index dd6f69c..fc9cef9 100644 (file)
@@ -1648,7 +1648,7 @@ static int smc911x_ethtool_geteeprom(struct net_device *dev,
                        return ret;
                if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)
                        return ret;
-               }
+       }
        memcpy(data, eebuf+eeprom->offset, eeprom->len);
        return 0;
 }
@@ -1667,11 +1667,11 @@ static int smc911x_ethtool_seteeprom(struct net_device *dev,
                        return ret;
                /* write byte */
                if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)
-                        return ret;
+                       return ret;
                if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)
                        return ret;
-               }
-        return 0;
+       }
+       return 0;
 }
 
 static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
index dde5b77..c3f10a9 100644 (file)
@@ -49,13 +49,15 @@ struct visconti_eth {
        void __iomem *reg;
        u32 phy_intf_sel;
        struct clk *phy_ref_clk;
+       struct device *dev;
        spinlock_t lock; /* lock to protect register update */
 };
 
 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
 {
        struct visconti_eth *dwmac = priv;
-       unsigned int val, clk_sel_val;
+       struct net_device *netdev = dev_get_drvdata(dwmac->dev);
+       unsigned int val, clk_sel_val = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&dwmac->lock, flags);
@@ -85,7 +87,9 @@ static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
                break;
        default:
                /* No bit control */
-               break;
+               netdev_err(netdev, "Unsupported speed request (%d)", speed);
+               spin_unlock_irqrestore(&dwmac->lock, flags);
+               return;
        }
 
        writel(val, dwmac->reg + MAC_CTRL_REG);
@@ -229,6 +233,7 @@ static int visconti_eth_dwmac_probe(struct platform_device *pdev)
 
        spin_lock_init(&dwmac->lock);
        dwmac->reg = stmmac_res.addr;
+       dwmac->dev = &pdev->dev;
        plat_dat->bsp_priv = dwmac;
        plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
 
index 1914ad6..acd70b9 100644 (file)
 
 #define NUM_DWMAC100_DMA_REGS  9
 #define NUM_DWMAC1000_DMA_REGS 23
+#define NUM_DWMAC4_DMA_REGS    27
 
 void dwmac_enable_dma_transmission(void __iomem *ioaddr);
 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
index 164dff5..abfb3cd 100644 (file)
 #include "dwxgmac2.h"
 
 #define REG_SPACE_SIZE 0x1060
+#define GMAC4_REG_SPACE_SIZE   0x116C
 #define MAC100_ETHTOOL_NAME    "st_mac100"
 #define GMAC_ETHTOOL_NAME      "st_gmac"
 #define XGMAC_ETHTOOL_NAME     "st_xgmac"
 
+/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h
+ *
+ * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the
+ * same time due to the conflicting macro names.
+ */
+#define GMAC4_DMA_CHAN_BASE_ADDR  0x00001100
+
 #define ETHTOOL_DMA_OFFSET     55
 
 struct stmmac_stats {
@@ -434,6 +442,8 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
 
        if (priv->plat->has_xgmac)
                return XGMAC_REGSIZE * 4;
+       else if (priv->plat->has_gmac4)
+               return GMAC4_REG_SPACE_SIZE;
        return REG_SPACE_SIZE;
 }
 
@@ -446,8 +456,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
        stmmac_dump_mac_regs(priv, priv->hw, reg_space);
        stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space);
 
-       if (!priv->plat->has_xgmac) {
-               /* Copy DMA registers to where ethtool expects them */
+       /* Copy DMA registers to where ethtool expects them */
+       if (priv->plat->has_gmac4) {
+               /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */
+               memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
+                      &reg_space[GMAC4_DMA_CHAN_BASE_ADDR / 4],
+                      NUM_DWMAC4_DMA_REGS * 4);
+       } else if (!priv->plat->has_xgmac) {
                memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
                       &reg_space[DMA_BUS_MODE / 4],
                       NUM_DWMAC1000_DMA_REGS * 4);
index 074e2cd..a7ec9f4 100644 (file)
@@ -145,15 +145,20 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
 
 static void get_systime(void __iomem *ioaddr, u64 *systime)
 {
-       u64 ns;
-
-       /* Get the TSSS value */
-       ns = readl(ioaddr + PTP_STNSR);
-       /* Get the TSS and convert sec time value to nanosecond */
-       ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
+       u64 ns, sec0, sec1;
+
+       /* Get the TSS value */
+       sec1 = readl_relaxed(ioaddr + PTP_STSR);
+       do {
+               sec0 = sec1;
+               /* Get the TSSS value */
+               ns = readl_relaxed(ioaddr + PTP_STNSR);
+               /* Get the TSS value */
+               sec1 = readl_relaxed(ioaddr + PTP_STSR);
+       } while (sec0 != sec1);
 
        if (systime)
-               *systime = ns;
+               *systime = ns + (sec1 * 1000000000ULL);
 }
 
 static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
index 639a753..bde76ea 100644 (file)
@@ -7252,6 +7252,10 @@ int stmmac_dvr_remove(struct device *dev)
 
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
+       pm_runtime_get_sync(dev);
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
+
        stmmac_stop_all_dma(priv);
        stmmac_mac_set(priv, priv->ioaddr, false);
        netif_carrier_off(ndev);
@@ -7270,8 +7274,6 @@ int stmmac_dvr_remove(struct device *dev)
        if (priv->plat->stmmac_rst)
                reset_control_assert(priv->plat->stmmac_rst);
        reset_control_assert(priv->plat->stmmac_ahb_rst);
-       pm_runtime_put(dev);
-       pm_runtime_disable(dev);
        if (priv->hw->pcs != STMMAC_PCS_TBI &&
            priv->hw->pcs != STMMAC_PCS_RTBI)
                stmmac_mdio_unregister(ndev);
index 7d67f41..4f5ef8a 100644 (file)
@@ -100,6 +100,7 @@ struct at86rf230_local {
        unsigned long cal_timeout;
        bool is_tx;
        bool is_tx_from_off;
+       bool was_tx;
        u8 tx_retry;
        struct sk_buff *tx_skb;
        struct at86rf230_state_change tx;
@@ -343,7 +344,11 @@ at86rf230_async_error_recover_complete(void *context)
        if (ctx->free)
                kfree(ctx);
 
-       ieee802154_wake_queue(lp->hw);
+       if (lp->was_tx) {
+               lp->was_tx = 0;
+               dev_kfree_skb_any(lp->tx_skb);
+               ieee802154_wake_queue(lp->hw);
+       }
 }
 
 static void
@@ -352,7 +357,11 @@ at86rf230_async_error_recover(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
 
-       lp->is_tx = 0;
+       if (lp->is_tx) {
+               lp->was_tx = 1;
+               lp->is_tx = 0;
+       }
+
        at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
                                     at86rf230_async_error_recover_complete);
 }
index ece6ff6..f3438d3 100644 (file)
@@ -1771,6 +1771,7 @@ static int ca8210_async_xmit_complete(
                        status
                );
                if (status != MAC_TRANSACTION_OVERFLOW) {
+                       dev_kfree_skb_any(priv->tx_skb);
                        ieee802154_wake_queue(priv->hw);
                        return 0;
                }
index 8caa61e..36f1c5a 100644 (file)
@@ -786,6 +786,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
                goto err_pib;
        }
 
+       pib->channel = 13;
        rcu_assign_pointer(phy->pib, pib);
        phy->idx = idx;
        INIT_LIST_HEAD(&phy->edges);
index 8dc04e2..383231b 100644 (file)
@@ -976,8 +976,8 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
        dev_dbg(printdev(lp), "%s\n", __func__);
 
        phy->symbol_duration = 16;
-       phy->lifs_period = 40;
-       phy->sifs_period = 12;
+       phy->lifs_period = 40 * phy->symbol_duration;
+       phy->sifs_period = 12 * phy->symbol_duration;
 
        hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
                        IEEE802154_HW_AFILT |
index b1c6c0f..f2989aa 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/bitops.h>
 
+#include "linux/soc/qcom/qcom_aoss.h"
+
 #include "ipa.h"
 #include "ipa_power.h"
 #include "ipa_endpoint.h"
@@ -64,6 +66,7 @@ enum ipa_power_flag {
  * struct ipa_power - IPA power management information
  * @dev:               IPA device pointer
  * @core:              IPA core clock
+ * @qmp:               QMP handle for AOSS communication
  * @spinlock:          Protects modem TX queue enable/disable
  * @flags:             Boolean state flags
  * @interconnect_count:        Number of elements in interconnect[]
@@ -72,6 +75,7 @@ enum ipa_power_flag {
 struct ipa_power {
        struct device *dev;
        struct clk *core;
+       struct qmp *qmp;
        spinlock_t spinlock;    /* used with STOPPED/STARTED power flags */
        DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT);
        u32 interconnect_count;
@@ -382,6 +386,47 @@ void ipa_power_modem_queue_active(struct ipa *ipa)
        clear_bit(IPA_POWER_FLAG_STARTED, ipa->power->flags);
 }
 
+static int ipa_power_retention_init(struct ipa_power *power)
+{
+       struct qmp *qmp = qmp_get(power->dev);
+
+       if (IS_ERR(qmp)) {
+               if (PTR_ERR(qmp) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               /* We assume any other error means it's not defined/needed */
+               qmp = NULL;
+       }
+       power->qmp = qmp;
+
+       return 0;
+}
+
+static void ipa_power_retention_exit(struct ipa_power *power)
+{
+       qmp_put(power->qmp);
+       power->qmp = NULL;
+}
+
+/* Control register retention on power collapse */
+void ipa_power_retention(struct ipa *ipa, bool enable)
+{
+       static const char fmt[] = "{ class: bcm, res: ipa_pc, val: %c }";
+       struct ipa_power *power = ipa->power;
+       char buf[36];   /* Exactly enough for fmt[]; size a multiple of 4 */
+       int ret;
+
+       if (!power->qmp)
+               return;         /* Not needed on this platform */
+
+       (void)snprintf(buf, sizeof(buf), fmt, enable ? '1' : '0');
+
+       ret = qmp_send(power->qmp, buf, sizeof(buf));
+       if (ret)
+               dev_err(power->dev, "error %d sending QMP %sable request\n",
+                       ret, enable ? "en" : "dis");
+}
+
 int ipa_power_setup(struct ipa *ipa)
 {
        int ret;
@@ -438,12 +483,18 @@ ipa_power_init(struct device *dev, const struct ipa_power_data *data)
        if (ret)
                goto err_kfree;
 
+       ret = ipa_power_retention_init(power);
+       if (ret)
+               goto err_interconnect_exit;
+
        pm_runtime_set_autosuspend_delay(dev, IPA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(dev);
        pm_runtime_enable(dev);
 
        return power;
 
+err_interconnect_exit:
+       ipa_interconnect_exit(power);
 err_kfree:
        kfree(power);
 err_clk_put:
@@ -460,6 +511,7 @@ void ipa_power_exit(struct ipa_power *power)
 
        pm_runtime_disable(dev);
        pm_runtime_dont_use_autosuspend(dev);
+       ipa_power_retention_exit(power);
        ipa_interconnect_exit(power);
        kfree(power);
        clk_put(clk);
index 2151805..6f84f05 100644 (file)
@@ -40,6 +40,13 @@ void ipa_power_modem_queue_wake(struct ipa *ipa);
  */
 void ipa_power_modem_queue_active(struct ipa *ipa);
 
+/**
+ * ipa_power_retention() - Control register retention on power collapse
+ * @ipa:       IPA pointer
+ * @enable:    Whether retention should be enabled or disabled
+ */
+void ipa_power_retention(struct ipa *ipa, bool enable);
+
 /**
  * ipa_power_setup() - Set up IPA power management
  * @ipa:       IPA pointer
index 856e55a..fe11910 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "ipa.h"
 #include "ipa_uc.h"
+#include "ipa_power.h"
 
 /**
  * DOC:  The IPA embedded microcontroller
@@ -154,6 +155,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
        case IPA_UC_RESPONSE_INIT_COMPLETED:
                if (ipa->uc_powered) {
                        ipa->uc_loaded = true;
+                       ipa_power_retention(ipa, true);
                        pm_runtime_mark_last_busy(dev);
                        (void)pm_runtime_put_autosuspend(dev);
                        ipa->uc_powered = false;
@@ -184,6 +186,9 @@ void ipa_uc_deconfig(struct ipa *ipa)
 
        ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
        ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
+       if (ipa->uc_loaded)
+               ipa_power_retention(ipa, false);
+
        if (!ipa->uc_powered)
                return;
 
index 16aa3a4..3d08743 100644 (file)
@@ -3870,6 +3870,18 @@ static void macsec_common_dellink(struct net_device *dev, struct list_head *head
        struct macsec_dev *macsec = macsec_priv(dev);
        struct net_device *real_dev = macsec->real_dev;
 
+       /* If h/w offloading is available, propagate to the device */
+       if (macsec_is_offloaded(macsec)) {
+               const struct macsec_ops *ops;
+               struct macsec_context ctx;
+
+               ops = macsec_get_ops(netdev_priv(dev), &ctx);
+               if (ops) {
+                       ctx.secy = &macsec->secy;
+                       macsec_offload(ops->mdo_del_secy, &ctx);
+               }
+       }
+
        unregister_netdevice_queue(dev, head);
        list_del_rcu(&macsec->secys);
        macsec_del_dev(macsec);
@@ -3884,18 +3896,6 @@ static void macsec_dellink(struct net_device *dev, struct list_head *head)
        struct net_device *real_dev = macsec->real_dev;
        struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
 
-       /* If h/w offloading is available, propagate to the device */
-       if (macsec_is_offloaded(macsec)) {
-               const struct macsec_ops *ops;
-               struct macsec_context ctx;
-
-               ops = macsec_get_ops(netdev_priv(dev), &ctx);
-               if (ops) {
-                       ctx.secy = &macsec->secy;
-                       macsec_offload(ops->mdo_del_secy, &ctx);
-               }
-       }
-
        macsec_common_dellink(dev, head);
 
        if (list_empty(&rxd->secys)) {
@@ -4018,6 +4018,15 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
            !macsec_check_offload(macsec->offload, macsec))
                return -EOPNOTSUPP;
 
+       /* send_sci must be set to true when transmit sci explicitly is set */
+       if ((data && data[IFLA_MACSEC_SCI]) &&
+           (data && data[IFLA_MACSEC_INC_SCI])) {
+               u8 send_sci = !!nla_get_u8(data[IFLA_MACSEC_INC_SCI]);
+
+               if (!send_sci)
+                       return -EINVAL;
+       }
+
        if (data && data[IFLA_MACSEC_ICV_LEN])
                icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
        mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
index 5b6c0d1..29aa811 100644 (file)
@@ -1688,19 +1688,19 @@ static int qca808x_read_status(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
-       if (phydev->link && phydev->speed == SPEED_2500)
-               phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-       else
-               phydev->interface = PHY_INTERFACE_MODE_SMII;
-
-       /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-        * except for master/slave configuration fault detected.
-        * the reason for not putting this code into the function link_change_notify is
-        * the corner case where the link partner is also the qca8081 PHY and the seed
-        * value is configured as the same value, the link can't be up and no link change
-        * occurs.
-        */
-       if (!phydev->link) {
+       if (phydev->link) {
+               if (phydev->speed == SPEED_2500)
+                       phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+               else
+                       phydev->interface = PHY_INTERFACE_MODE_SGMII;
+       } else {
+               /* generate seed as a lower random value to make PHY linked as SLAVE easily,
+                * except for master/slave configuration fault detected.
+                * the reason for not putting this code into the function link_change_notify is
+                * the corner case where the link partner is also the qca8081 PHY and the seed
+                * value is configured as the same value, the link can't be up and no link change
+                * occurs.
+                */
                if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) {
                        qca808x_phy_ms_seed_enable(phydev, false);
                } else {
index cd33955..6a769df 100644 (file)
@@ -121,7 +121,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
        if (tx_buf == NULL)
                goto free_rx_urb;
 
-       rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
+       rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
                                    GFP_KERNEL, &rx_urb->transfer_dma);
        if (rx_buf == NULL)
                goto free_tx_buf;
@@ -146,7 +146,7 @@ error_nomem:
 
 static void ipheth_free_urbs(struct ipheth_device *iphone)
 {
-       usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
+       usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
                          iphone->rx_urb->transfer_dma);
        usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
                          iphone->tx_urb->transfer_dma);
@@ -317,7 +317,7 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
 
        usb_fill_bulk_urb(dev->rx_urb, udev,
                          usb_rcvbulkpipe(udev, dev->bulk_in),
-                         dev->rx_buf, IPHETH_BUF_SIZE,
+                         dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
                          ipheth_rcvbulk_callback,
                          dev);
        dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
index 5e0bfda..961a5f8 100644 (file)
@@ -4253,7 +4253,14 @@ static void nvme_async_event_work(struct work_struct *work)
                container_of(work, struct nvme_ctrl, async_event_work);
 
        nvme_aen_uevent(ctrl);
-       ctrl->ops->submit_async_event(ctrl);
+
+       /*
+        * The transport drivers must guarantee AER submission here is safe by
+        * flushing ctrl async_event_work after changing the controller state
+        * from LIVE and before freeing the admin queue.
+       */
+       if (ctrl->state == NVME_CTRL_LIVE)
+               ctrl->ops->submit_async_event(ctrl);
 }
 
 static bool nvme_ctrl_pp_status(struct nvme_ctrl *ctrl)
index c3203ff..1e3a09c 100644 (file)
@@ -170,6 +170,7 @@ nvmf_ctlr_matches_baseopts(struct nvme_ctrl *ctrl,
                        struct nvmf_ctrl_options *opts)
 {
        if (ctrl->state == NVME_CTRL_DELETING ||
+           ctrl->state == NVME_CTRL_DELETING_NOIO ||
            ctrl->state == NVME_CTRL_DEAD ||
            strcmp(opts->subsysnqn, ctrl->opts->subsysnqn) ||
            strcmp(opts->host->nqn, ctrl->opts->host->nqn) ||
index 850f84d..9c55e4b 100644 (file)
@@ -1200,6 +1200,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
                        struct nvme_rdma_ctrl, err_work);
 
        nvme_stop_keep_alive(&ctrl->ctrl);
+       flush_work(&ctrl->ctrl.async_event_work);
        nvme_rdma_teardown_io_queues(ctrl, false);
        nvme_start_queues(&ctrl->ctrl);
        nvme_rdma_teardown_admin_queue(ctrl, false);
index 4ceb286..01e24b5 100644 (file)
@@ -2096,6 +2096,7 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
        struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
 
        nvme_stop_keep_alive(ctrl);
+       flush_work(&ctrl->async_event_work);
        nvme_tcp_teardown_io_queues(ctrl, false);
        /* unquiesce to fail fast pending requests */
        nvme_start_queues(ctrl);
index 489586a..768d33f 100644 (file)
@@ -356,8 +356,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
        const struct j721e_pcie_data *data;
        struct cdns_pcie *cdns_pcie;
        struct j721e_pcie *pcie;
-       struct cdns_pcie_rc *rc;
-       struct cdns_pcie_ep *ep;
+       struct cdns_pcie_rc *rc = NULL;
+       struct cdns_pcie_ep *ep = NULL;
        struct gpio_desc *gpiod;
        void __iomem *base;
        struct clk *clk;
@@ -376,6 +376,46 @@ static int j721e_pcie_probe(struct platform_device *pdev)
        if (!pcie)
                return -ENOMEM;
 
+       switch (mode) {
+       case PCI_MODE_RC:
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST))
+                       return -ENODEV;
+
+               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+               if (!bridge)
+                       return -ENOMEM;
+
+               if (!data->byte_access_allowed)
+                       bridge->ops = &cdns_ti_pcie_host_ops;
+               rc = pci_host_bridge_priv(bridge);
+               rc->quirk_retrain_flag = data->quirk_retrain_flag;
+               rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
+               cdns_pcie = &rc->pcie;
+               cdns_pcie->dev = dev;
+               cdns_pcie->ops = &j721e_pcie_ops;
+               pcie->cdns_pcie = cdns_pcie;
+               break;
+       case PCI_MODE_EP:
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP))
+                       return -ENODEV;
+
+               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+               if (!ep)
+                       return -ENOMEM;
+
+               ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
+               cdns_pcie = &ep->pcie;
+               cdns_pcie->dev = dev;
+               cdns_pcie->ops = &j721e_pcie_ops;
+               pcie->cdns_pcie = cdns_pcie;
+               break;
+       default:
+               dev_err(dev, "INVALID device type %d\n", mode);
+               return 0;
+       }
+
        pcie->mode = mode;
        pcie->linkdown_irq_regfield = data->linkdown_irq_regfield;
 
@@ -426,28 +466,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
        switch (mode) {
        case PCI_MODE_RC:
-               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
-                       ret = -ENODEV;
-                       goto err_get_sync;
-               }
-
-               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
-               if (!bridge) {
-                       ret = -ENOMEM;
-                       goto err_get_sync;
-               }
-
-               if (!data->byte_access_allowed)
-                       bridge->ops = &cdns_ti_pcie_host_ops;
-               rc = pci_host_bridge_priv(bridge);
-               rc->quirk_retrain_flag = data->quirk_retrain_flag;
-               rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
-
-               cdns_pcie = &rc->pcie;
-               cdns_pcie->dev = dev;
-               cdns_pcie->ops = &j721e_pcie_ops;
-               pcie->cdns_pcie = cdns_pcie;
-
                gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
                if (IS_ERR(gpiod)) {
                        ret = PTR_ERR(gpiod);
@@ -497,23 +515,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
                break;
        case PCI_MODE_EP:
-               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
-                       ret = -ENODEV;
-                       goto err_get_sync;
-               }
-
-               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
-               if (!ep) {
-                       ret = -ENOMEM;
-                       goto err_get_sync;
-               }
-               ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
-
-               cdns_pcie = &ep->pcie;
-               cdns_pcie->dev = dev;
-               cdns_pcie->ops = &j721e_pcie_ops;
-               pcie->cdns_pcie = cdns_pcie;
-
                ret = cdns_pcie_init_phy(dev, cdns_pcie);
                if (ret) {
                        dev_err(dev, "Failed to init phy\n");
@@ -525,8 +526,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
                        goto err_pcie_setup;
 
                break;
-       default:
-               dev_err(dev, "INVALID device type %d\n", mode);
        }
 
        return 0;
index fa6886d..c625fc6 100644 (file)
@@ -756,22 +756,28 @@ static int __exit kirin_pcie_remove(struct platform_device *pdev)
        return 0;
 }
 
+struct kirin_pcie_data {
+       enum pcie_kirin_phy_type        phy_type;
+};
+
+static const struct kirin_pcie_data kirin_960_data = {
+       .phy_type = PCIE_KIRIN_INTERNAL_PHY,
+};
+
+static const struct kirin_pcie_data kirin_970_data = {
+       .phy_type = PCIE_KIRIN_EXTERNAL_PHY,
+};
+
 static const struct of_device_id kirin_pcie_match[] = {
-       {
-               .compatible = "hisilicon,kirin960-pcie",
-               .data = (void *)PCIE_KIRIN_INTERNAL_PHY
-       },
-       {
-               .compatible = "hisilicon,kirin970-pcie",
-               .data = (void *)PCIE_KIRIN_EXTERNAL_PHY
-       },
+       { .compatible = "hisilicon,kirin960-pcie", .data = &kirin_960_data },
+       { .compatible = "hisilicon,kirin970-pcie", .data = &kirin_970_data },
        {},
 };
 
 static int kirin_pcie_probe(struct platform_device *pdev)
 {
-       enum pcie_kirin_phy_type phy_type;
        struct device *dev = &pdev->dev;
+       const struct kirin_pcie_data *data;
        struct kirin_pcie *kirin_pcie;
        struct dw_pcie *pci;
        int ret;
@@ -781,13 +787,12 @@ static int kirin_pcie_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       phy_type = (long)of_device_get_match_data(dev);
-       if (!phy_type) {
+       data = of_device_get_match_data(dev);
+       if (!data) {
                dev_err(dev, "OF data missing\n");
                return -EINVAL;
        }
 
-
        kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
        if (!kirin_pcie)
                return -ENOMEM;
@@ -800,7 +805,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
        pci->ops = &kirin_dw_pcie_ops;
        pci->pp.ops = &kirin_pcie_host_ops;
        kirin_pcie->pci = pci;
-       kirin_pcie->type = phy_type;
+       kirin_pcie->type = data->phy_type;
 
        ret = kirin_pcie_get_resource(kirin_pcie, pdev);
        if (ret)
index c19c7ca..9037a78 100644 (file)
@@ -1111,7 +1111,8 @@ const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
        if (!desc)
                return cpu_possible_mask;
 
-       if (WARN_ON_ONCE(!desc->affinity))
+       /* MSI[X] interrupts can be allocated without affinity descriptor */
+       if (!desc->affinity)
                return NULL;
 
        /*
index 08c364d..f64d29f 100644 (file)
@@ -42,9 +42,9 @@ obj-$(CONFIG_PINCTRL_PISTACHIO)       += pinctrl-pistachio.o
 obj-$(CONFIG_PINCTRL_RK805)    += pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
+obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_STARFIVE) += pinctrl-starfive.o
 obj-$(CONFIG_PINCTRL_STMFX)    += pinctrl-stmfx.o
-obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_SX150X)   += pinctrl-sx150x.o
 obj-$(CONFIG_PINCTRL_TB10X)    += pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_THUNDERBAY) += pinctrl-thunderbay.o
index 5123f4c..ac1e400 100644 (file)
@@ -35,6 +35,7 @@ config PINCTRL_BCM63XX
        select PINCONF
        select GENERIC_PINCONF
        select GPIOLIB
+       select REGMAP
        select GPIO_REGMAP
 
 config PINCTRL_BCM6318
index c4ebfa8..47e433e 100644 (file)
@@ -1269,16 +1269,18 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
                                     sizeof(*girq->parents),
                                     GFP_KERNEL);
        if (!girq->parents) {
-               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out_remove;
        }
 
        if (is_7211) {
                pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
                                            sizeof(*pc->wake_irq),
                                            GFP_KERNEL);
-               if (!pc->wake_irq)
-                       return -ENOMEM;
+               if (!pc->wake_irq) {
+                       err = -ENOMEM;
+                       goto out_remove;
+               }
        }
 
        /*
@@ -1306,8 +1308,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
 
                len = strlen(dev_name(pc->dev)) + 16;
                name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
-               if (!name)
-                       return -ENOMEM;
+               if (!name) {
+                       err = -ENOMEM;
+                       goto out_remove;
+               }
 
                snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
 
@@ -1326,11 +1330,14 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
        err = gpiochip_add_data(&pc->gpio_chip, pc);
        if (err) {
                dev_err(dev, "could not add GPIO chip\n");
-               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
-               return err;
+               goto out_remove;
        }
 
        return 0;
+
+out_remove:
+       pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+       return err;
 }
 
 static struct platform_driver bcm2835_pinctrl_driver = {
index abffda1..1d58182 100644 (file)
@@ -1471,8 +1471,9 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
 
                offset = cctx->intr_lines[intr_line];
                if (offset == CHV_INVALID_HWIRQ) {
-                       dev_err(dev, "interrupt on unused interrupt line %u\n", intr_line);
-                       continue;
+                       dev_warn_once(dev, "interrupt on unmapped interrupt line %u\n", intr_line);
+                       /* Some boards expect hwirq 0 to trigger in this case */
+                       offset = 0;
                }
 
                generic_handle_domain_irq(gc->irq.domain, offset);
index 8575097..826d494 100644 (file)
@@ -451,8 +451,8 @@ static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
        value &= ~PADCFG0_PMODE_MASK;
        value |= PADCFG0_PMODE_GPIO;
 
-       /* Disable input and output buffers */
-       value |= PADCFG0_GPIORXDIS;
+       /* Disable TX buffer and enable RX (this will be input) */
+       value &= ~PADCFG0_GPIORXDIS;
        value |= PADCFG0_GPIOTXDIS;
 
        /* Disable SCI/SMI/NMI generation */
@@ -497,9 +497,6 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
 
        intel_gpio_set_gpio_mode(padcfg0);
 
-       /* Disable TX buffer and enable RX (this will be input) */
-       __intel_gpio_set_direction(padcfg0, true);
-
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
@@ -1115,9 +1112,6 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned int type)
 
        intel_gpio_set_gpio_mode(reg);
 
-       /* Disable TX buffer and enable RX (this will be input) */
-       __intel_gpio_set_direction(reg, true);
-
        value = readl(reg);
 
        value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
@@ -1216,6 +1210,39 @@ static irqreturn_t intel_gpio_irq(int irq, void *data)
        return IRQ_RETVAL(ret);
 }
 
+static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
+{
+       int i;
+
+       for (i = 0; i < pctrl->ncommunities; i++) {
+               const struct intel_community *community;
+               void __iomem *base;
+               unsigned int gpp;
+
+               community = &pctrl->communities[i];
+               base = community->regs;
+
+               for (gpp = 0; gpp < community->ngpps; gpp++) {
+                       /* Mask and clear all interrupts */
+                       writel(0, base + community->ie_offset + gpp * 4);
+                       writel(0xffff, base + community->is_offset + gpp * 4);
+               }
+       }
+}
+
+static int intel_gpio_irq_init_hw(struct gpio_chip *gc)
+{
+       struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
+
+       /*
+        * Make sure the interrupt lines are in a proper state before
+        * further configuration.
+        */
+       intel_gpio_irq_init(pctrl);
+
+       return 0;
+}
+
 static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl,
                                const struct intel_community *community)
 {
@@ -1320,6 +1347,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
        girq->num_parents = 0;
        girq->default_type = IRQ_TYPE_NONE;
        girq->handler = handle_bad_irq;
+       girq->init_hw = intel_gpio_irq_init_hw;
 
        ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
        if (ret) {
@@ -1695,26 +1723,6 @@ int intel_pinctrl_suspend_noirq(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq);
 
-static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
-{
-       size_t i;
-
-       for (i = 0; i < pctrl->ncommunities; i++) {
-               const struct intel_community *community;
-               void __iomem *base;
-               unsigned int gpp;
-
-               community = &pctrl->communities[i];
-               base = community->regs;
-
-               for (gpp = 0; gpp < community->ngpps; gpp++) {
-                       /* Mask and clear all interrupts */
-                       writel(0, base + community->ie_offset + gpp * 4);
-                       writel(0xffff, base + community->is_offset + gpp * 4);
-               }
-       }
-}
-
 static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
 {
        u32 curr, updated;
index 8e081c9..639f113 100644 (file)
@@ -137,7 +137,8 @@ static inline int sgpio_addr_to_pin(struct sgpio_priv *priv, int port, int bit)
 
 static inline u32 sgpio_get_addr(struct sgpio_priv *priv, u32 rno, u32 off)
 {
-       return priv->properties->regoff[rno] + off;
+       return (priv->properties->regoff[rno] + off) *
+               regmap_get_reg_stride(priv->regs);
 }
 
 static u32 sgpio_readl(struct sgpio_priv *priv, u32 rno, u32 off)
index b5b47f4..79d44bc 100644 (file)
@@ -773,63 +773,42 @@ static int thunderbay_build_groups(struct thunderbay_pinctrl *tpc)
 
 static int thunderbay_add_functions(struct thunderbay_pinctrl *tpc, struct function_desc *funcs)
 {
-       struct function_desc *function = funcs;
        int i;
 
        /* Assign the groups for each function */
-       for (i = 0; i < tpc->soc->npins; i++) {
-               const struct pinctrl_pin_desc *pin_info = thunderbay_pins + i;
-               struct thunderbay_mux_desc *pin_mux = pin_info->drv_data;
-
-               while (pin_mux->name) {
-                       const char **grp;
-                       int j, grp_num, match = 0;
-                       size_t grp_size;
-                       struct function_desc *func;
-
-                       for (j = 0; j < tpc->nfuncs; j++) {
-                               if (!strcmp(pin_mux->name, function[j].name)) {
-                                       match = 1;
-                                       break;
-                               }
-                       }
-
-                       if (!match)
-                               return -EINVAL;
-
-                       func = function + j;
-                       grp_num = func->num_group_names;
-                       grp_size = sizeof(*func->group_names);
-
-                       if (!func->group_names) {
-                               func->group_names = devm_kcalloc(tpc->dev,
-                                                                grp_num,
-                                                                grp_size,
-                                                                GFP_KERNEL);
-                               if (!func->group_names) {
-                                       kfree(func);
-                                       return -ENOMEM;
-                               }
+       for (i = 0; i < tpc->nfuncs; i++) {
+               struct function_desc *func = &funcs[i];
+               const char **group_names;
+               unsigned int grp_idx = 0;
+               int j;
+
+               group_names = devm_kcalloc(tpc->dev, func->num_group_names,
+                                          sizeof(*group_names), GFP_KERNEL);
+               if (!group_names)
+                       return -ENOMEM;
+
+               for (j = 0; j < tpc->soc->npins; j++) {
+                       const struct pinctrl_pin_desc *pin_info = &thunderbay_pins[j];
+                       struct thunderbay_mux_desc *pin_mux;
+
+                       for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) {
+                               if (!strcmp(pin_mux->name, func->name))
+                                       group_names[grp_idx++] = pin_info->name;
                        }
-
-                       grp = func->group_names;
-                       while (*grp)
-                               grp++;
-
-                       *grp = pin_info->name;
-                       pin_mux++;
                }
+
+               func->group_names = group_names;
        }
 
        /* Add all functions */
        for (i = 0; i < tpc->nfuncs; i++) {
                pinmux_generic_add_function(tpc->pctrl,
-                                           function[i].name,
-                                           function[i].group_names,
-                                           function[i].num_group_names,
-                                           function[i].data);
+                                           funcs[i].name,
+                                           funcs[i].group_names,
+                                           funcs[i].num_group_names,
+                                           funcs[i].data);
        }
-       kfree(function);
+       kfree(funcs);
        return 0;
 }
 
@@ -839,27 +818,30 @@ static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc)
        void *ptr;
        int pin;
 
-       /* Total number of functions is unknown at this point. Allocate first. */
+       /*
+        * Allocate maximum possible number of functions. Assume every pin
+        * being part of 8 (hw maximum) globally unique muxes.
+        */
        tpc->nfuncs = 0;
        thunderbay_funcs = kcalloc(tpc->soc->npins * 8,
                                   sizeof(*thunderbay_funcs), GFP_KERNEL);
        if (!thunderbay_funcs)
                return -ENOMEM;
 
-       /* Find total number of functions and each's properties */
+       /* Setup 1 function for each unique mux */
        for (pin = 0; pin < tpc->soc->npins; pin++) {
                const struct pinctrl_pin_desc *pin_info = thunderbay_pins + pin;
-               struct thunderbay_mux_desc *pin_mux = pin_info->drv_data;
+               struct thunderbay_mux_desc *pin_mux;
 
-               while (pin_mux->name) {
-                       struct function_desc *func = thunderbay_funcs;
+               for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) {
+                       struct function_desc *func;
 
-                       while (func->name) {
+                       /* Check if we already have function for this mux */
+                       for (func = thunderbay_funcs; func->name; func++) {
                                if (!strcmp(pin_mux->name, func->name)) {
                                        func->num_group_names++;
                                        break;
                                }
-                               func++;
                        }
 
                        if (!func->name) {
@@ -868,8 +850,6 @@ static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc)
                                func->data = (int *)&pin_mux->mode;
                                tpc->nfuncs++;
                        }
-
-                       pin_mux++;
                }
        }
 
index 42da6bd..e140122 100644 (file)
@@ -809,7 +809,6 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
                                           unsigned int *npins)
 {
        struct pinctrl_pin_desc *pins, *pin;
-       char **pin_names;
        int ret;
        int i;
 
@@ -821,14 +820,13 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
        if (!pins)
                return -ENOMEM;
 
-       pin_names = devm_kasprintf_strarray(dev, ZYNQMP_PIN_PREFIX, *npins);
-       if (IS_ERR(pin_names))
-               return PTR_ERR(pin_names);
-
        for (i = 0; i < *npins; i++) {
                pin = &pins[i];
                pin->number = i;
-               pin->name = pin_names[i];
+               pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+                                          ZYNQMP_PIN_PREFIX, i);
+               if (!pin->name)
+                       return -ENOMEM;
        }
 
        *zynqmp_pins = pins;
index ce1917e..152b712 100644 (file)
@@ -363,16 +363,16 @@ static const struct sunxi_desc_pin h616_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DO0 */
+                 SUNXI_FUNCTION(0x3, "i2s3_dout0"),    /* DO0 */
                  SUNXI_FUNCTION(0x4, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x5, "i2s3"),  /* DI1 */
+                 SUNXI_FUNCTION(0x5, "i2s3_din1"),     /* DI1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 6, 8)),  /* PH_EINT8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DI0 */
+                 SUNXI_FUNCTION(0x3, "i2s3_din0"),     /* DI0 */
                  SUNXI_FUNCTION(0x4, "spi1"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DO1 */
+                 SUNXI_FUNCTION(0x5, "i2s3_dout1"),    /* DO1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 6, 9)),  /* PH_EINT9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 5f0578e..463f1ec 100644 (file)
@@ -5,6 +5,7 @@
 
 menuconfig SURFACE_PLATFORMS
        bool "Microsoft Surface Platform-Specific Device Drivers"
+       depends on ARM64 || X86 || COMPILE_TEST
        default y
        help
          Say Y here to get to see options for platform-specific device drivers
index f794343..4c72ba6 100644 (file)
@@ -124,9 +124,10 @@ struct amd_pmc_dev {
        u32 cpu_id;
        u32 active_ips;
 /* SMU version information */
-       u16 major;
-       u16 minor;
-       u16 rev;
+       u8 smu_program;
+       u8 major;
+       u8 minor;
+       u8 rev;
        struct device *dev;
        struct pci_dev *rdev;
        struct mutex lock; /* generic mutex lock */
@@ -180,11 +181,13 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
        if (rc)
                return rc;
 
-       dev->major = (val >> 16) & GENMASK(15, 0);
+       dev->smu_program = (val >> 24) & GENMASK(7, 0);
+       dev->major = (val >> 16) & GENMASK(7, 0);
        dev->minor = (val >> 8) & GENMASK(7, 0);
        dev->rev = (val >> 0) & GENMASK(7, 0);
 
-       dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev);
+       dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n",
+               dev->smu_program, dev->major, dev->minor, dev->rev);
 
        return 0;
 }
@@ -226,7 +229,7 @@ static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-const struct file_operations amd_pmc_stb_debugfs_fops = {
+static const struct file_operations amd_pmc_stb_debugfs_fops = {
        .owner = THIS_MODULE,
        .open = amd_pmc_stb_debugfs_open,
        .read = amd_pmc_stb_debugfs_read,
index d4ef8f3..6fd0c9f 100644 (file)
@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
        return 0;
 }
 
-struct hid_ll_driver tf103c_dock_hid_ll_driver = {
+static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
        .parse = tf103c_dock_hid_parse,
        .start = tf103c_dock_hid_start,
        .stop = tf103c_dock_hid_stop,
@@ -921,7 +921,7 @@ static int __maybe_unused tf103c_dock_resume(struct device *dev)
        return 0;
 }
 
-SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
+static SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
 
 static const struct acpi_device_id tf103c_dock_acpi_match[] = {
        {"NPCE69A"},
index 0374bc7..e4299cf 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/regmap.h>
 
 #define CHGRIRQ_REG                                    0x0a
+#define MCHGRIRQ_REG                                   0x17
 
 struct crystal_cove_charger_data {
        struct mutex buslock; /* irq_bus_lock */
@@ -25,8 +26,8 @@ struct crystal_cove_charger_data {
        struct irq_domain *irq_domain;
        int irq;
        int charger_irq;
-       bool irq_enabled;
-       bool irq_is_enabled;
+       u8 mask;
+       u8 new_mask;
 };
 
 static irqreturn_t crystal_cove_charger_irq(int irq, void *data)
@@ -53,13 +54,9 @@ static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       if (charger->irq_is_enabled != charger->irq_enabled) {
-               if (charger->irq_enabled)
-                       enable_irq(charger->irq);
-               else
-                       disable_irq(charger->irq);
-
-               charger->irq_is_enabled = charger->irq_enabled;
+       if (charger->mask != charger->new_mask) {
+               regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
+               charger->mask = charger->new_mask;
        }
 
        mutex_unlock(&charger->buslock);
@@ -69,14 +66,14 @@ static void crystal_cove_charger_irq_unmask(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       charger->irq_enabled = true;
+       charger->new_mask &= ~BIT(data->hwirq);
 }
 
 static void crystal_cove_charger_irq_mask(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       charger->irq_enabled = false;
+       charger->new_mask |= BIT(data->hwirq);
 }
 
 static void crystal_cove_charger_rm_irq_domain(void *data)
@@ -130,10 +127,13 @@ static int crystal_cove_charger_probe(struct platform_device *pdev)
        irq_set_nested_thread(charger->charger_irq, true);
        irq_set_noprobe(charger->charger_irq);
 
+       /* Mask the single 2nd level IRQ before enabling the 1st level IRQ */
+       charger->mask = charger->new_mask = BIT(0);
+       regmap_write(charger->regmap, MCHGRIRQ_REG, charger->mask);
+
        ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL,
                                        crystal_cove_charger_irq,
-                                       IRQF_ONESHOT | IRQF_NO_AUTOEN,
-                                       KBUILD_MODNAME, charger);
+                                       IRQF_ONESHOT, KBUILD_MODNAME, charger);
        if (ret)
                return dev_err_probe(&pdev->dev, ret, "requesting irq\n");
 
index c9a85eb..e8424e7 100644 (file)
@@ -596,7 +596,10 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
        return ret;
 }
 
-static DEFINE_MUTEX(punit_misc_dev_lock);
+/* Lock to prevent module registration when already opened by user space */
+static DEFINE_MUTEX(punit_misc_dev_open_lock);
+/* Lock to allow one share misc device for all ISST interace */
+static DEFINE_MUTEX(punit_misc_dev_reg_lock);
 static int misc_usage_count;
 static int misc_device_ret;
 static int misc_device_open;
@@ -606,7 +609,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
        int i, ret = 0;
 
        /* Fail open, if a module is going away */
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
        for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
                struct isst_if_cmd_cb *cb = &punit_callbacks[i];
 
@@ -628,7 +631,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
        } else {
                misc_device_open++;
        }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
        return ret;
 }
@@ -637,7 +640,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
 {
        int i;
 
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
        misc_device_open--;
        for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
                struct isst_if_cmd_cb *cb = &punit_callbacks[i];
@@ -645,7 +648,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
                if (cb->registered)
                        module_put(cb->owner);
        }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
        return 0;
 }
@@ -662,6 +665,43 @@ static struct miscdevice isst_if_char_driver = {
        .fops           = &isst_if_char_driver_ops,
 };
 
+static int isst_misc_reg(void)
+{
+       mutex_lock(&punit_misc_dev_reg_lock);
+       if (misc_device_ret)
+               goto unlock_exit;
+
+       if (!misc_usage_count) {
+               misc_device_ret = isst_if_cpu_info_init();
+               if (misc_device_ret)
+                       goto unlock_exit;
+
+               misc_device_ret = misc_register(&isst_if_char_driver);
+               if (misc_device_ret) {
+                       isst_if_cpu_info_exit();
+                       goto unlock_exit;
+               }
+       }
+       misc_usage_count++;
+
+unlock_exit:
+       mutex_unlock(&punit_misc_dev_reg_lock);
+
+       return misc_device_ret;
+}
+
+static void isst_misc_unreg(void)
+{
+       mutex_lock(&punit_misc_dev_reg_lock);
+       if (misc_usage_count)
+               misc_usage_count--;
+       if (!misc_usage_count && !misc_device_ret) {
+               misc_deregister(&isst_if_char_driver);
+               isst_if_cpu_info_exit();
+       }
+       mutex_unlock(&punit_misc_dev_reg_lock);
+}
+
 /**
  * isst_if_cdev_register() - Register callback for IOCTL
  * @device_type: The device type this callback handling.
@@ -679,38 +719,31 @@ static struct miscdevice isst_if_char_driver = {
  */
 int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
 {
-       if (misc_device_ret)
-               return misc_device_ret;
+       int ret;
 
        if (device_type >= ISST_IF_DEV_MAX)
                return -EINVAL;
 
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
+       /* Device is already open, we don't want to add new callbacks */
        if (misc_device_open) {
-               mutex_unlock(&punit_misc_dev_lock);
+               mutex_unlock(&punit_misc_dev_open_lock);
                return -EAGAIN;
        }
-       if (!misc_usage_count) {
-               int ret;
-
-               misc_device_ret = misc_register(&isst_if_char_driver);
-               if (misc_device_ret)
-                       goto unlock_exit;
-
-               ret = isst_if_cpu_info_init();
-               if (ret) {
-                       misc_deregister(&isst_if_char_driver);
-                       misc_device_ret = ret;
-                       goto unlock_exit;
-               }
-       }
        memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
        punit_callbacks[device_type].registered = 1;
-       misc_usage_count++;
-unlock_exit:
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
-       return misc_device_ret;
+       ret = isst_misc_reg();
+       if (ret) {
+               /*
+                * No need of mutex as the misc device register failed
+                * as no one can open device yet. Hence no contention.
+                */
+               punit_callbacks[device_type].registered = 0;
+               return ret;
+       }
+       return 0;
 }
 EXPORT_SYMBOL_GPL(isst_if_cdev_register);
 
@@ -725,16 +758,12 @@ EXPORT_SYMBOL_GPL(isst_if_cdev_register);
  */
 void isst_if_cdev_unregister(int device_type)
 {
-       mutex_lock(&punit_misc_dev_lock);
-       misc_usage_count--;
+       isst_misc_unreg();
+       mutex_lock(&punit_misc_dev_open_lock);
        punit_callbacks[device_type].registered = 0;
        if (device_type == ISST_IF_DEV_MBOX)
                isst_delete_hash();
-       if (!misc_usage_count && !misc_device_ret) {
-               misc_deregister(&isst_if_char_driver);
-               isst_if_cpu_info_exit();
-       }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 }
 EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
 
index 098180f..bd04548 100644 (file)
@@ -8679,9 +8679,10 @@ static const struct attribute_group fan_driver_attr_group = {
        .attrs = fan_driver_attributes,
 };
 
-#define TPACPI_FAN_Q1  0x0001          /* Unitialized HFSP */
-#define TPACPI_FAN_2FAN        0x0002          /* EC 0x31 bit 0 selects fan2 */
-#define TPACPI_FAN_2CTL        0x0004          /* selects fan2 control */
+#define TPACPI_FAN_Q1          0x0001          /* Uninitialized HFSP */
+#define TPACPI_FAN_2FAN                0x0002          /* EC 0x31 bit 0 selects fan2 */
+#define TPACPI_FAN_2CTL                0x0004          /* selects fan2 control */
+#define TPACPI_FAN_NOFAN       0x0008          /* no fan available */
 
 static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
@@ -8702,6 +8703,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (4nd gen) */
        TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL),  /* P15 (1st gen) / P15v (1st gen) */
        TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL),  /* X1 Carbon (9th gen) */
+       TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
 };
 
 static int __init fan_init(struct ibm_init_struct *iibm)
@@ -8730,6 +8732,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
        quirks = tpacpi_check_quirks(fan_quirk_table,
                                     ARRAY_SIZE(fan_quirk_table));
 
+       if (quirks & TPACPI_FAN_NOFAN) {
+               pr_info("No integrated ThinkPad fan available\n");
+               return -ENODEV;
+       }
+
        if (gfan_handle) {
                /* 570, 600e/x, 770e, 770x */
                fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
@@ -10112,6 +10119,9 @@ static struct ibm_struct proxsensor_driver_data = {
 #define DYTC_CMD_MMC_GET      8 /* To get current MMC function and mode */
 #define DYTC_CMD_RESET    0x1ff /* To reset back to default */
 
+#define DYTC_CMD_FUNC_CAP     3 /* To get DYTC capabilities */
+#define DYTC_FC_MMC           27 /* MMC Mode supported */
+
 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
 
@@ -10324,6 +10334,15 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        if (dytc_version < 5)
                return -ENODEV;
 
+       /* Check what capabilities are supported. Currently MMC is needed */
+       err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
+       if (err)
+               return err;
+       if (!(output & BIT(DYTC_FC_MMC))) {
+               dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
+               return -ENODEV;
+       }
+
        dbg_printk(TPACPI_DBG_INIT,
                        "DYTC version %d: thermal mode available\n", dytc_version);
        /*
index 494f230..bc97bfa 100644 (file)
@@ -770,6 +770,21 @@ static const struct ts_dmi_data predia_basic_data = {
        .properties     = predia_basic_props,
 };
 
+static const struct property_entry rwc_nanote_p8_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 46),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-p8.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       { }
+};
+
+static const struct ts_dmi_data rwc_nanote_p8_data = {
+       .acpi_name = "MSSL1680:00",
+       .properties = rwc_nanote_p8_props,
+};
+
 static const struct property_entry schneider_sct101ctm_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
@@ -1394,6 +1409,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"),
                },
        },
+       {
+               /* RWC NANOTE P8 */
+               .driver_data = (void *)&rwc_nanote_p8_data,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Default string"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AY07J"),
+                       DMI_MATCH(DMI_PRODUCT_SKU, "0001")
+               },
+       },
        {
                /* Schneider SCT101CTM */
                .driver_data = (void *)&schneider_sct101ctm_data,
index 3ba63ad..9360a8a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/string.h>
 /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
 #include "../../gpio/gpiolib.h"
+#include "../../gpio/gpiolib-acpi.h"
 
 /*
  * Helper code to get Linux IRQ numbers given a description of the IRQ source
@@ -47,7 +48,7 @@ struct x86_acpi_irq_data {
        int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
 };
 
-static int x86_acpi_irq_helper_gpiochip_find(struct gpio_chip *gc, void *data)
+static int gpiochip_find_match_label(struct gpio_chip *gc, void *data)
 {
        return gc->label && !strcmp(gc->label, data);
 }
@@ -73,7 +74,7 @@ static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
                return irq;
        case X86_ACPI_IRQ_TYPE_GPIOINT:
                /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
-               chip = gpiochip_find(data->chip, x86_acpi_irq_helper_gpiochip_find);
+               chip = gpiochip_find(data->chip, gpiochip_find_match_label);
                if (!chip) {
                        pr_err("error cannot find GPIO chip %s\n", data->chip);
                        return -ENODEV;
@@ -143,14 +144,17 @@ struct x86_serdev_info {
 };
 
 struct x86_dev_info {
+       char *invalid_aei_gpiochip;
        const char * const *modules;
-       struct gpiod_lookup_table **gpiod_lookup_tables;
+       struct gpiod_lookup_table * const *gpiod_lookup_tables;
        const struct x86_i2c_client_info *i2c_client_info;
        const struct platform_device_info *pdev_info;
        const struct x86_serdev_info *serdev_info;
        int i2c_client_count;
        int pdev_count;
        int serdev_count;
+       int (*init)(void);
+       void (*exit)(void);
 };
 
 /* Generic / shared bq24190 settings */
@@ -187,8 +191,8 @@ static struct bq24190_platform_data bq24190_pdata = {
 };
 
 static const char * const bq24190_modules[] __initconst = {
-       "crystal_cove_charger", /* For the bq24190 IRQ */
-       "bq24190_charger",      /* For the Vbus regulator for intel-int3496 */
+       "intel_crystal_cove_charger", /* For the bq24190 IRQ */
+       "bq24190_charger",            /* For the Vbus regulator for intel-int3496 */
        NULL
 };
 
@@ -302,7 +306,7 @@ static struct gpiod_lookup_table asus_me176c_goodix_gpios = {
        },
 };
 
-static struct gpiod_lookup_table *asus_me176c_gpios[] = {
+static struct gpiod_lookup_table * const asus_me176c_gpios[] = {
        &int3496_gpo2_pin22_gpios,
        &asus_me176c_goodix_gpios,
        NULL
@@ -317,6 +321,7 @@ static const struct x86_dev_info asus_me176c_info __initconst = {
        .serdev_count = ARRAY_SIZE(asus_me176c_serdevs),
        .gpiod_lookup_tables = asus_me176c_gpios,
        .modules = bq24190_modules,
+       .invalid_aei_gpiochip = "INT33FC:02",
 };
 
 /* Asus TF103C tablets have an Android factory img with everything hardcoded */
@@ -405,7 +410,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
        },
 };
 
-static struct gpiod_lookup_table *asus_tf103c_gpios[] = {
+static struct gpiod_lookup_table * const asus_tf103c_gpios[] = {
        &int3496_gpo2_pin22_gpios,
        NULL
 };
@@ -417,6 +422,7 @@ static const struct x86_dev_info asus_tf103c_info __initconst = {
        .pdev_count = ARRAY_SIZE(int3496_pdevs),
        .gpiod_lookup_tables = asus_tf103c_gpios,
        .modules = bq24190_modules,
+       .invalid_aei_gpiochip = "INT33FC:02",
 };
 
 /*
@@ -490,6 +496,39 @@ static const struct x86_dev_info chuwi_hi8_info __initconst = {
        .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
 };
 
+#define CZC_EC_EXTRA_PORT      0x68
+#define CZC_EC_ANDROID_KEYS    0x63
+
+static int __init czc_p10t_init(void)
+{
+       /*
+        * The device boots up in "Windows 7" mode, when the home button sends a
+        * Windows specific key sequence (Left Meta + D) and the second button
+        * sends an unknown one while also toggling the Radio Kill Switch.
+        * This is a surprising behavior when the second button is labeled "Back".
+        *
+        * The vendor-supplied Android-x86 build switches the device to a "Android"
+        * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
+        * set bit 6 on address 0x96 in the EC region; switching the bit directly
+        * seems to achieve the same result. It uses a "p10t_switcher" to do the
+        * job. It doesn't seem to be able to do anything else, and no other use
+        * of the port 0x68 is known.
+        *
+        * In the Android mode, the home button sends just a single scancode,
+        * which can be handled in Linux userspace more reasonably and the back
+        * button only sends a scancode without toggling the kill switch.
+        * The scancode can then be mapped either to Back or RF Kill functionality
+        * in userspace, depending on how the button is labeled on that particular
+        * model.
+        */
+       outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
+       return 0;
+}
+
+static const struct x86_dev_info czc_p10t __initconst = {
+       .init = czc_p10t_init,
+};
+
 /*
  * Whitelabel (sold as various brands) TM800A550L tablets.
  * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
@@ -559,7 +598,7 @@ static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
        },
 };
 
-static struct gpiod_lookup_table *whitelabel_tm800a550l_gpios[] = {
+static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
        &whitelabel_tm800a550l_goodix_gpios,
        NULL
 };
@@ -641,6 +680,24 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
                },
                .driver_data = (void *)&chuwi_hi8_info,
        },
+       {
+               /* CZC P10T */
+               .ident = "CZC ODEON TPC-10 (\"P10T\")",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CZC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ODEON*TPC-10"),
+               },
+               .driver_data = (void *)&czc_p10t,
+       },
+       {
+               /* A variant of CZC P10T */
+               .ident = "ViewSonic ViewPad 10",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ViewSonic"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "VPAD10"),
+               },
+               .driver_data = (void *)&czc_p10t,
+       },
        {
                /* Whitelabel (sold as various brands) TM800A550L */
                .matches = {
@@ -669,7 +726,8 @@ static int serdev_count;
 static struct i2c_client **i2c_clients;
 static struct platform_device **pdevs;
 static struct serdev_device **serdevs;
-static struct gpiod_lookup_table **gpiod_lookup_tables;
+static struct gpiod_lookup_table * const *gpiod_lookup_tables;
+static void (*exit_handler)(void);
 
 static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info,
                                             int idx)
@@ -787,6 +845,9 @@ static void x86_android_tablet_cleanup(void)
 
        kfree(i2c_clients);
 
+       if (exit_handler)
+               exit_handler();
+
        for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
                gpiod_remove_lookup_table(gpiod_lookup_tables[i]);
 }
@@ -795,6 +856,7 @@ static __init int x86_android_tablet_init(void)
 {
        const struct x86_dev_info *dev_info;
        const struct dmi_system_id *id;
+       struct gpio_chip *chip;
        int i, ret = 0;
 
        id = dmi_first_match(x86_android_tablet_ids);
@@ -803,6 +865,20 @@ static __init int x86_android_tablet_init(void)
 
        dev_info = id->driver_data;
 
+       /*
+        * The broken DSDTs on these devices often also include broken
+        * _AEI (ACPI Event Interrupt) handlers, disable these.
+        */
+       if (dev_info->invalid_aei_gpiochip) {
+               chip = gpiochip_find(dev_info->invalid_aei_gpiochip,
+                                    gpiochip_find_match_label);
+               if (!chip) {
+                       pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip);
+                       return -ENODEV;
+               }
+               acpi_gpiochip_free_interrupts(chip);
+       }
+
        /*
         * Since this runs from module_init() it cannot use -EPROBE_DEFER,
         * instead pre-load any modules which are listed as requirements.
@@ -814,6 +890,15 @@ static __init int x86_android_tablet_init(void)
        for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
                gpiod_add_lookup_table(gpiod_lookup_tables[i]);
 
+       if (dev_info->init) {
+               ret = dev_info->init();
+               if (ret < 0) {
+                       x86_android_tablet_cleanup();
+                       return ret;
+               }
+               exit_handler = dev_info->exit;
+       }
+
        i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
        if (!i2c_clients) {
                x86_android_tablet_cleanup();
@@ -865,6 +950,6 @@ static __init int x86_android_tablet_init(void)
 module_init(x86_android_tablet_init);
 module_exit(x86_android_tablet_cleanup);
 
-MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");
 MODULE_LICENSE("GPL");
index fbc56b0..b8bf76c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
@@ -140,7 +141,7 @@ static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on)
        node = of_get_child_by_name(chip->dev->of_node, "regulators");
        if (!node) {
                dev_err(chip->dev, "regulators node not found\n");
-               return PTR_ERR(node);
+               return -ENODEV;
        }
 
        for (i = 0; i < chip->info->num_outputs; ++i)
index 9be273c..a826456 100644 (file)
@@ -508,7 +508,8 @@ static int bnx2fc_l2_rcv_thread(void *arg)
 
 static void bnx2fc_recv_frame(struct sk_buff *skb)
 {
-       u32 fr_len;
+       u64 crc_err;
+       u32 fr_len, fr_crc;
        struct fc_lport *lport;
        struct fcoe_rcv_info *fr;
        struct fc_stats *stats;
@@ -542,6 +543,11 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
        skb_pull(skb, sizeof(struct fcoe_hdr));
        fr_len = skb->len - sizeof(struct fcoe_crc_eof);
 
+       stats = per_cpu_ptr(lport->stats, get_cpu());
+       stats->RxFrames++;
+       stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+       put_cpu();
+
        fp = (struct fc_frame *)skb;
        fc_frame_init(fp);
        fr_dev(fp) = lport;
@@ -624,16 +630,15 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
                return;
        }
 
-       stats = per_cpu_ptr(lport->stats, smp_processor_id());
-       stats->RxFrames++;
-       stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+       fr_crc = le32_to_cpu(fr_crc(fp));
 
-       if (le32_to_cpu(fr_crc(fp)) !=
-                       ~crc32(~0, skb->data, fr_len)) {
-               if (stats->InvalidCRCCount < 5)
+       if (unlikely(fr_crc != ~crc32(~0, skb->data, fr_len))) {
+               stats = per_cpu_ptr(lport->stats, get_cpu());
+               crc_err = (stats->InvalidCRCCount++);
+               put_cpu();
+               if (crc_err < 5)
                        printk(KERN_WARNING PFX "dropping frame with "
                               "CRC error\n");
-               stats->InvalidCRCCount++;
                kfree_skb(skb);
                return;
        }
index 2f53a2e..ebf5ec3 100644 (file)
@@ -400,8 +400,7 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
                           struct hisi_sas_slot *slot,
                           struct hisi_sas_dq *dq,
                           struct hisi_sas_device *sas_dev,
-                          struct hisi_sas_internal_abort *abort,
-                          struct hisi_sas_tmf_task *tmf)
+                          struct hisi_sas_internal_abort *abort)
 {
        struct hisi_sas_cmd_hdr *cmd_hdr_base;
        int dlvry_queue_slot, dlvry_queue;
@@ -427,8 +426,6 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
        cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
        slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
 
-       slot->tmf = tmf;
-       slot->is_internal = tmf;
        task->lldd_task = slot;
 
        memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
@@ -587,7 +584,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
        slot->is_internal = tmf;
 
        /* protect task_prep and start_delivery sequence */
-       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf);
+       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL);
 
        return 0;
 
@@ -1380,12 +1377,13 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
        struct device *dev = hisi_hba->dev;
        int s = sizeof(struct host_to_dev_fis);
+       struct hisi_sas_tmf_task tmf = {};
 
        ata_for_each_link(link, ap, EDGE) {
                int pmp = sata_srst_pmp(link);
 
                hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
-               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL);
+               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf);
                if (rc != TMF_RESP_FUNC_COMPLETE)
                        break;
        }
@@ -1396,7 +1394,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
 
                        hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis);
                        rc = hisi_sas_exec_internal_tmf_task(device, fis,
-                                                            s, NULL);
+                                                            s, &tmf);
                        if (rc != TMF_RESP_FUNC_COMPLETE)
                                dev_err(dev, "ata disk %016llx de-reset failed\n",
                                        SAS_ADDR(device->sas_addr));
@@ -2067,7 +2065,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
        slot->port = port;
        slot->is_internal = true;
 
-       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL);
+       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort);
 
        return 0;
 
index c814e50..9ec310b 100644 (file)
@@ -2692,7 +2692,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
        u32 tag = le32_to_cpu(psataPayload->tag);
        u32 port_id = le32_to_cpu(psataPayload->port_id);
        u32 dev_id = le32_to_cpu(psataPayload->device_id);
-       unsigned long flags;
 
        if (event)
                pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
@@ -2724,8 +2723,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DATA_OVERRUN;
                ts->residual = 0;
-               if (pm8001_dev)
-                       atomic_dec(&pm8001_dev->running_req);
                break;
        case IO_XFER_ERROR_BREAK:
                pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
@@ -2767,7 +2764,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                                IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
                        ts->resp = SAS_TASK_COMPLETE;
                        ts->stat = SAS_QUEUE_FULL;
-                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
                        return;
                }
                break;
@@ -2853,20 +2849,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
-       t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
-       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
-       t->task_state_flags |= SAS_TASK_STATE_DONE;
-       if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_dbg(pm8001_ha, FAIL,
-                          "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
-                          t, event, ts->resp, ts->stat);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-       } else {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-       }
 }
 
 /*See the comments for mpi_ssp_completion */
index 160ee8b..32edda3 100644 (file)
@@ -769,8 +769,13 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
                res = -TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
                if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+                       struct pm8001_ccb_info *ccb = task->lldd_task;
+
                        pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n",
                                   tmf->tmf);
+
+                       if (ccb)
+                               ccb->task = NULL;
                        goto ex_err;
                }
 
index 2530d13..9d20f80 100644 (file)
@@ -2185,9 +2185,9 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                pm8001_dbg(pm8001_ha, FAIL,
                           "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
                           t, status, ts->resp, ts->stat);
+               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                if (t->slow_task)
                        complete(&t->slow_task->completion);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
@@ -2794,9 +2794,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
                pm8001_dbg(pm8001_ha, FAIL,
                           "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
                           t, status, ts->resp, ts->stat);
+               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                if (t->slow_task)
                        complete(&t->slow_task->completion);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
                spin_unlock_irqrestore(&circularQ->oq_lock,
@@ -2821,7 +2821,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
        u32 tag = le32_to_cpu(psataPayload->tag);
        u32 port_id = le32_to_cpu(psataPayload->port_id);
        u32 dev_id = le32_to_cpu(psataPayload->device_id);
-       unsigned long flags;
 
        if (event)
                pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
@@ -2854,8 +2853,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DATA_OVERRUN;
                ts->residual = 0;
-               if (pm8001_dev)
-                       atomic_dec(&pm8001_dev->running_req);
                break;
        case IO_XFER_ERROR_BREAK:
                pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
@@ -2904,11 +2901,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                                IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
                        ts->resp = SAS_TASK_COMPLETE;
                        ts->stat = SAS_QUEUE_FULL;
-                       spin_unlock_irqrestore(&circularQ->oq_lock,
-                                       circularQ->lock_flags);
-                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-                       spin_lock_irqsave(&circularQ->oq_lock,
-                                       circularQ->lock_flags);
                        return;
                }
                break;
@@ -3008,24 +3000,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
-       t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
-       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
-       t->task_state_flags |= SAS_TASK_STATE_DONE;
-       if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_dbg(pm8001_ha, FAIL,
-                          "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
-                          t, event, ts->resp, ts->stat);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-       } else {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               spin_unlock_irqrestore(&circularQ->oq_lock,
-                               circularQ->lock_flags);
-               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-               spin_lock_irqsave(&circularQ->oq_lock,
-                               circularQ->lock_flags);
-       }
 }
 
 /*See the comments for mpi_ssp_completion */
@@ -3931,6 +3905,7 @@ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha,
 /**
  * process_one_iomb - process one outbound Queue memory block
  * @pm8001_ha: our hba card information
+ * @circularQ: outbound circular queue
  * @piomb: IO message buffer
  */
 static void process_one_iomb(struct pm8001_hba_info *pm8001_ha,
index 3520b93..f4e6c68 100644 (file)
@@ -214,6 +214,48 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
                         SCSI_TIMEOUT, 3, NULL);
 }
 
+static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
+                                       unsigned int depth)
+{
+       int new_shift = sbitmap_calculate_shift(depth);
+       bool need_alloc = !sdev->budget_map.map;
+       bool need_free = false;
+       int ret;
+       struct sbitmap sb_backup;
+
+       /*
+        * realloc if new shift is calculated, which is caused by setting
+        * up one new default queue depth after calling ->slave_configure
+        */
+       if (!need_alloc && new_shift != sdev->budget_map.shift)
+               need_alloc = need_free = true;
+
+       if (!need_alloc)
+               return 0;
+
+       /*
+        * Request queue has to be frozen for reallocating budget map,
+        * and here disk isn't added yet, so freezing is pretty fast
+        */
+       if (need_free) {
+               blk_mq_freeze_queue(sdev->request_queue);
+               sb_backup = sdev->budget_map;
+       }
+       ret = sbitmap_init_node(&sdev->budget_map,
+                               scsi_device_max_queue_depth(sdev),
+                               new_shift, GFP_KERNEL,
+                               sdev->request_queue->node, false, true);
+       if (need_free) {
+               if (ret)
+                       sdev->budget_map = sb_backup;
+               else
+                       sbitmap_free(&sb_backup);
+               ret = 0;
+               blk_mq_unfreeze_queue(sdev->request_queue);
+       }
+       return ret;
+}
+
 /**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
  * @starget: which target to allocate a &scsi_device for
@@ -306,11 +348,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
         * default device queue depth to figure out sbitmap shift
         * since we use this queue depth most of times.
         */
-       if (sbitmap_init_node(&sdev->budget_map,
-                               scsi_device_max_queue_depth(sdev),
-                               sbitmap_calculate_shift(depth),
-                               GFP_KERNEL, sdev->request_queue->node,
-                               false, true)) {
+       if (scsi_realloc_sdev_budget_map(sdev, depth)) {
                put_device(&starget->dev);
                kfree(sdev);
                goto out;
@@ -1017,6 +1055,13 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                        }
                        return SCSI_SCAN_NO_RESPONSE;
                }
+
+               /*
+                * The queue_depth is often changed in ->slave_configure.
+                * Set up budget map again since memory consumption of
+                * the map depends on actual queue depth.
+                */
+               scsi_realloc_sdev_budget_map(sdev, sdev->queue_depth);
        }
 
        if (sdev->scsi_level >= SCSI_3)
index c9a769b..86c7621 100644 (file)
@@ -585,7 +585,7 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
        u32 rd = 0;
        u32 wr = 0;
 
-       if (qspi->base[CHIP_SELECT]) {
+       if (cs >= 0 && qspi->base[CHIP_SELECT]) {
                rd = bcm_qspi_read(qspi, CHIP_SELECT, 0);
                wr = (rd & ~0xff) | (1 << cs);
                if (rd == wr)
index c208efe..0bc7daa 100644 (file)
@@ -693,6 +693,11 @@ static int meson_spicc_probe(struct platform_device *pdev)
        writel_relaxed(0, spicc->base + SPICC_INTREG);
 
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto out_master;
+       }
+
        ret = devm_request_irq(&pdev->dev, irq, meson_spicc_irq,
                               0, NULL, spicc);
        if (ret) {
index a15de10..753bd31 100644 (file)
@@ -624,7 +624,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
        else
                mdata->state = MTK_SPI_IDLE;
 
-       if (!master->can_dma(master, master->cur_msg->spi, trans)) {
+       if (!master->can_dma(master, NULL, trans)) {
                if (trans->rx_buf) {
                        cnt = mdata->xfer_len / 4;
                        ioread32_rep(mdata->base + SPI_RX_DATA_REG,
index 514337c..ffdc55f 100644 (file)
@@ -688,7 +688,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        struct resource *res;
        int ret, irq;
 
-       ctrl = spi_alloc_master(dev, sizeof(*qspi));
+       ctrl = devm_spi_alloc_master(dev, sizeof(*qspi));
        if (!ctrl)
                return -ENOMEM;
 
@@ -697,58 +697,46 @@ static int stm32_qspi_probe(struct platform_device *pdev)
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
        qspi->io_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->io_base)) {
-               ret = PTR_ERR(qspi->io_base);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->io_base))
+               return PTR_ERR(qspi->io_base);
 
        qspi->phys_base = res->start;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
        qspi->mm_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->mm_base)) {
-               ret = PTR_ERR(qspi->mm_base);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->mm_base))
+               return PTR_ERR(qspi->mm_base);
 
        qspi->mm_size = resource_size(res);
-       if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) {
-               ret = -EINVAL;
-               goto err_master_put;
-       }
+       if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ)
+               return -EINVAL;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               ret = irq;
-               goto err_master_put;
-       }
+       if (irq < 0)
+               return irq;
 
        ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
                               dev_name(dev), qspi);
        if (ret) {
                dev_err(dev, "failed to request irq\n");
-               goto err_master_put;
+               return ret;
        }
 
        init_completion(&qspi->data_completion);
        init_completion(&qspi->match_completion);
 
        qspi->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(qspi->clk)) {
-               ret = PTR_ERR(qspi->clk);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->clk))
+               return PTR_ERR(qspi->clk);
 
        qspi->clk_rate = clk_get_rate(qspi->clk);
-       if (!qspi->clk_rate) {
-               ret = -EINVAL;
-               goto err_master_put;
-       }
+       if (!qspi->clk_rate)
+               return -EINVAL;
 
        ret = clk_prepare_enable(qspi->clk);
        if (ret) {
                dev_err(dev, "can not enable the clock\n");
-               goto err_master_put;
+               return ret;
        }
 
        rstc = devm_reset_control_get_exclusive(dev, NULL);
@@ -784,7 +772,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
        pm_runtime_get_noresume(dev);
 
-       ret = devm_spi_register_master(dev, ctrl);
+       ret = spi_register_master(ctrl);
        if (ret)
                goto err_pm_runtime_free;
 
@@ -806,8 +794,6 @@ err_dma_free:
        stm32_qspi_dma_free(qspi);
 err_clk_disable:
        clk_disable_unprepare(qspi->clk);
-err_master_put:
-       spi_master_put(qspi->ctrl);
 
        return ret;
 }
@@ -817,6 +803,7 @@ static int stm32_qspi_remove(struct platform_device *pdev)
        struct stm32_qspi *qspi = platform_get_drvdata(pdev);
 
        pm_runtime_get_sync(qspi->dev);
+       spi_unregister_master(qspi->ctrl);
        /* disable qspi */
        writel_relaxed(0, qspi->io_base + QSPI_CR);
        stm32_qspi_dma_free(qspi);
index 9bd3fd1..7fc2450 100644 (file)
@@ -221,7 +221,6 @@ struct stm32_spi;
  * time between frames (if driver has this functionality)
  * @set_number_of_data: optional routine to configure registers to desired
  * number of data (if driver has this functionality)
- * @can_dma: routine to determine if the transfer is eligible for DMA use
  * @transfer_one_dma_start: routine to start transfer a single spi_transfer
  * using DMA
  * @dma_rx_cb: routine to call after DMA RX channel operation is complete
@@ -232,7 +231,7 @@ struct stm32_spi;
  * @baud_rate_div_min: minimum baud rate divisor
  * @baud_rate_div_max: maximum baud rate divisor
  * @has_fifo: boolean to know if fifo is used for driver
- * @has_startbit: boolean to know if start bit is used to start transfer
+ * @flags: compatible specific SPI controller flags used at registration time
  */
 struct stm32_spi_cfg {
        const struct stm32_spi_regspec *regs;
@@ -253,6 +252,7 @@ struct stm32_spi_cfg {
        unsigned int baud_rate_div_min;
        unsigned int baud_rate_div_max;
        bool has_fifo;
+       u16 flags;
 };
 
 /**
@@ -1722,6 +1722,7 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = {
        .baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN,
        .baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX,
        .has_fifo = false,
+       .flags = SPI_MASTER_MUST_TX,
 };
 
 static const struct stm32_spi_cfg stm32h7_spi_cfg = {
@@ -1854,7 +1855,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
        master->prepare_message = stm32_spi_prepare_msg;
        master->transfer_one = stm32_spi_transfer_one;
        master->unprepare_message = stm32_spi_unprepare_msg;
-       master->flags = SPI_MASTER_MUST_TX;
+       master->flags = spi->cfg->flags;
 
        spi->dma_tx = dma_request_chan(spi->dev, "tx");
        if (IS_ERR(spi->dma_tx)) {
index 342ee8d..cc0da48 100644 (file)
@@ -726,7 +726,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n",
                                ret);
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                dma_tx_burst = caps.max_burst;
        }
@@ -735,7 +735,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
        if (IS_ERR_OR_NULL(master->dma_rx)) {
                if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
                        ret = -EPROBE_DEFER;
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                master->dma_rx = NULL;
                dma_rx_burst = INT_MAX;
@@ -744,7 +744,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n",
                                ret);
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                dma_rx_burst = caps.max_burst;
        }
@@ -753,10 +753,20 @@ static int uniphier_spi_probe(struct platform_device *pdev)
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret)
-               goto out_disable_clk;
+               goto out_release_dma;
 
        return 0;
 
+out_release_dma:
+       if (!IS_ERR_OR_NULL(master->dma_rx)) {
+               dma_release_channel(master->dma_rx);
+               master->dma_rx = NULL;
+       }
+       if (!IS_ERR_OR_NULL(master->dma_tx)) {
+               dma_release_channel(master->dma_tx);
+               master->dma_tx = NULL;
+       }
+
 out_disable_clk:
        clk_disable_unprepare(priv->clk);
 
index 840d981..fcc4638 100644 (file)
@@ -78,6 +78,26 @@ config FRAMEBUFFER_CONSOLE
        help
          Low-level framebuffer-based console driver.
 
+config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       bool "Enable legacy fbcon hardware acceleration code"
+       depends on FRAMEBUFFER_CONSOLE
+       default y if PARISC
+       default n
+       help
+         This option enables the fbcon (framebuffer text-based) hardware
+         acceleration for graphics drivers which were written for the fbdev
+         graphics interface.
+
+         On modern machines, on mainstream machines (like x86-64) or when
+         using a modern Linux distribution those fbdev drivers usually aren't used.
+         So enabling this option wouldn't have any effect, which is why you want
+         to disable this option on such newer machines.
+
+         If you compile this kernel for older machines which still require the
+         fbdev drivers, you may want to say Y.
+
+         If unsure, select n.
+
 config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
        bool "Map the console to the primary display device"
        depends on FRAMEBUFFER_CONSOLE
index 01fae2c..f98e8f2 100644 (file)
@@ -43,6 +43,21 @@ static void update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width)
+{
+       struct fb_copyarea area;
+
+       area.sx = sx * vc->vc_font.width;
+       area.sy = sy * vc->vc_font.height;
+       area.dx = dx * vc->vc_font.width;
+       area.dy = dy * vc->vc_font.height;
+       area.height = height * vc->vc_font.height;
+       area.width = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int height, int width)
 {
@@ -378,6 +393,7 @@ static int bit_update_start(struct fb_info *info)
 
 void fbcon_set_bitops(struct fbcon_ops *ops)
 {
+       ops->bmove = bit_bmove;
        ops->clear = bit_clear;
        ops->putcs = bit_putcs;
        ops->clear_margins = bit_clear_margins;
index 99ecd9a..f36829e 100644 (file)
@@ -173,6 +173,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
                        int count, int ypos, int xpos);
 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
 static void fbcon_cursor(struct vc_data *vc, int mode);
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+                       int height, int width);
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
 static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
@@ -180,8 +182,16 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
 /*
  *  Internal routines
  */
+static __inline__ void ywrap_up(struct vc_data *vc, int count);
+static __inline__ void ywrap_down(struct vc_data *vc, int count);
+static __inline__ void ypan_up(struct vc_data *vc, int count);
+static __inline__ void ypan_down(struct vc_data *vc, int count);
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+                           int dy, int dx, int height, int width, u_int y_break);
 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
                           int unit);
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+                             int line, int count, int dy);
 static void fbcon_modechanged(struct fb_info *info);
 static void fbcon_set_all_vcs(struct fb_info *info);
 static void fbcon_start(void);
@@ -1015,7 +1025,7 @@ static void fbcon_init(struct vc_data *vc, int init)
        struct vc_data *svc = *default_mode;
        struct fbcon_display *t, *p = &fb_display[vc->vc_num];
        int logo = 1, new_rows, new_cols, rows, cols;
-       int ret;
+       int cap, ret;
 
        if (WARN_ON(info_idx == -1))
            return;
@@ -1024,6 +1034,7 @@ static void fbcon_init(struct vc_data *vc, int init)
                con2fb_map[vc->vc_num] = info_idx;
 
        info = registered_fb[con2fb_map[vc->vc_num]];
+       cap = info->flags;
 
        if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
                logo_shown = FBCON_LOGO_DONTSHOW;
@@ -1125,6 +1136,14 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        ops->graphics = 0;
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       if ((cap & FBINFO_HWACCEL_COPYAREA) &&
+           !(cap & FBINFO_HWACCEL_DISABLED))
+               p->scrollmode = SCROLL_MOVE;
+       else /* default to something safe */
+               p->scrollmode = SCROLL_REDRAW;
+#endif
+
        /*
         *  ++guenther: console.c:vc_allocate() relies on initializing
         *  vc_{cols,rows}, but we must not set those if we are only
@@ -1211,13 +1230,14 @@ finished:
  *  This system is now divided into two levels because of complications
  *  caused by hardware scrolling. Top level functions:
  *
- *     fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
+ *     fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
  *
  *  handles y values in range [0, scr_height-1] that correspond to real
  *  screen positions. y_wrap shift means that first line of bitmap may be
  *  anywhere on this display. These functions convert lineoffsets to
  *  bitmap offsets and deal with the wrap-around case by splitting blits.
  *
+ *     fbcon_bmove_physical_8()    -- These functions fast implementations
  *     fbcon_clear_physical_8()    -- of original fbcon_XXX fns.
  *     fbcon_putc_physical_8()     -- (font width != 8) may be added later
  *
@@ -1390,6 +1410,224 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
        }
 }
 
+static __inline__ void ywrap_up(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll += count;
+       if (p->yscroll >= p->vrows)     /* Deal with wrap */
+               p->yscroll -= p->vrows;
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ywrap_down(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll -= count;
+       if (p->yscroll < 0)     /* Deal with wrap */
+               p->yscroll += p->vrows;
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_up(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       p->yscroll += count;
+       if (p->yscroll > p->vrows - vc->vc_rows) {
+               ops->bmove(vc, info, p->vrows - vc->vc_rows,
+                           0, 0, 0, vc->vc_rows, vc->vc_cols);
+               p->yscroll -= p->vrows - vc->vc_rows;
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll += count;
+
+       if (p->yscroll > p->vrows - vc->vc_rows) {
+               p->yscroll -= p->vrows - vc->vc_rows;
+               fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_down(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       p->yscroll -= count;
+       if (p->yscroll < 0) {
+               ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+                           0, vc->vc_rows, vc->vc_cols);
+               p->yscroll += p->vrows - vc->vc_rows;
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll -= count;
+
+       if (p->yscroll < 0) {
+               p->yscroll += p->vrows - vc->vc_rows;
+               fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+                             int line, int count, int dy)
+{
+       unsigned short *s = (unsigned short *)
+               (vc->vc_origin + vc->vc_size_row * line);
+
+       while (count--) {
+               unsigned short *start = s;
+               unsigned short *le = advance_row(s, 1);
+               unsigned short c;
+               int x = 0;
+               unsigned short attr = 1;
+
+               do {
+                       c = scr_readw(s);
+                       if (attr != (c & 0xff00)) {
+                               attr = c & 0xff00;
+                               if (s > start) {
+                                       fbcon_putcs(vc, start, s - start,
+                                                   dy, x);
+                                       x += s - start;
+                                       start = s;
+                               }
+                       }
+                       console_conditional_schedule();
+                       s++;
+               } while (s < le);
+               if (s > start)
+                       fbcon_putcs(vc, start, s - start, dy, x);
+               console_conditional_schedule();
+               dy++;
+       }
+}
+
+static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+                       struct fbcon_display *p, int line, int count, int ycount)
+{
+       int offset = ycount * vc->vc_cols;
+       unsigned short *d = (unsigned short *)
+           (vc->vc_origin + vc->vc_size_row * line);
+       unsigned short *s = d + offset;
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       while (count--) {
+               unsigned short *start = s;
+               unsigned short *le = advance_row(s, 1);
+               unsigned short c;
+               int x = 0;
+
+               do {
+                       c = scr_readw(s);
+
+                       if (c == scr_readw(d)) {
+                               if (s > start) {
+                                       ops->bmove(vc, info, line + ycount, x,
+                                                  line, x, 1, s-start);
+                                       x += s - start + 1;
+                                       start = s + 1;
+                               } else {
+                                       x++;
+                                       start++;
+                               }
+                       }
+
+                       scr_writew(c, d);
+                       console_conditional_schedule();
+                       s++;
+                       d++;
+               } while (s < le);
+               if (s > start)
+                       ops->bmove(vc, info, line + ycount, x, line, x, 1,
+                                  s-start);
+               console_conditional_schedule();
+               if (ycount > 0)
+                       line++;
+               else {
+                       line--;
+                       /* NOTE: We subtract two lines from these pointers */
+                       s -= vc->vc_size_row;
+                       d -= vc->vc_size_row;
+               }
+       }
+}
+
 static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
                         int line, int count, int offset)
 {
@@ -1450,6 +1688,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_display *p = &fb_display[vc->vc_num];
+       int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
 
        if (fbcon_is_inactive(vc, info))
                return true;
@@ -1466,32 +1705,291 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
        case SM_UP:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               fbcon_redraw(vc, p, t, b - t - count,
-                            count * vc->vc_cols);
-               fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
-               scr_memsetw((unsigned short *) (vc->vc_origin +
-                                               vc->vc_size_row *
-                                               (b - count)),
-                           vc->vc_video_erase_char,
-                           vc->vc_size_row * count);
-               return true;
+               if (logo_shown >= 0)
+                       goto redraw_up;
+               switch (fb_scrollmode(p)) {
+               case SCROLL_MOVE:
+                       fbcon_redraw_blit(vc, info, p, t, b - t - count,
+                                    count);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       (b - count)),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+
+               case SCROLL_WRAP_MOVE:
+                       if (b - t - count > 3 * vc->vc_rows >> 2) {
+                               if (t > 0)
+                                       fbcon_bmove(vc, 0, 0, count, 0, t,
+                                                   vc->vc_cols);
+                               ywrap_up(vc, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b - count, 0, b, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t + count, 0, t, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_up;
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_REDRAW:
+                       if ((p->yscroll + count <=
+                            2 * (p->vrows - vc->vc_rows))
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (t > 0)
+                                       fbcon_redraw_move(vc, p, 0, t, count);
+                               ypan_up_redraw(vc, t, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_redraw_move(vc, p, b,
+                                                         vc->vc_rows - b, b);
+                       } else
+                               fbcon_redraw_move(vc, p, t + count, b - t - count, t);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_MOVE:
+                       if ((p->yscroll + count <=
+                            2 * (p->vrows - vc->vc_rows))
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (t > 0)
+                                       fbcon_bmove(vc, 0, 0, count, 0, t,
+                                                   vc->vc_cols);
+                               ypan_up(vc, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b - count, 0, b, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t + count, 0, t, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_up;
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_REDRAW:
+                     redraw_up:
+                       fbcon_redraw(vc, p, t, b - t - count,
+                                    count * vc->vc_cols);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       (b - count)),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+               }
+               break;
 
        case SM_DOWN:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               fbcon_redraw(vc, p, b - 1, b - t - count,
-                            -count * vc->vc_cols);
-               fbcon_clear(vc, t, 0, count, vc->vc_cols);
-               scr_memsetw((unsigned short *) (vc->vc_origin +
-                                               vc->vc_size_row *
-                                               t),
-                           vc->vc_video_erase_char,
-                           vc->vc_size_row * count);
-               return true;
+               if (logo_shown >= 0)
+                       goto redraw_down;
+               switch (fb_scrollmode(p)) {
+               case SCROLL_MOVE:
+                       fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+                                    -count);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       t),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+
+               case SCROLL_WRAP_MOVE:
+                       if (b - t - count > 3 * vc->vc_rows >> 2) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b, 0, b - count, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                               ywrap_down(vc, count);
+                               if (t > 0)
+                                       fbcon_bmove(vc, count, 0, 0, 0, t,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t, 0, t + count, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_down;
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_MOVE:
+                       if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b, 0, b - count, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                               ypan_down(vc, count);
+                               if (t > 0)
+                                       fbcon_bmove(vc, count, 0, 0, 0, t,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t, 0, t + count, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_down;
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_REDRAW:
+                       if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
+                                                         b - count);
+                               ypan_down_redraw(vc, t, count);
+                               if (t > 0)
+                                       fbcon_redraw_move(vc, p, count, t, 0);
+                       } else
+                               fbcon_redraw_move(vc, p, t, b - t - count, t + count);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_REDRAW:
+                     redraw_down:
+                       fbcon_redraw(vc, p, b - 1, b - t - count,
+                                    -count * vc->vc_cols);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       t),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+               }
        }
        return false;
 }
 
+
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+                       int height, int width)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       if (fbcon_is_inactive(vc, info))
+               return;
+
+       if (!width || !height)
+               return;
+
+       /*  Split blits that cross physical y_wrap case.
+        *  Pathological case involves 4 blits, better to use recursive
+        *  code rather than unrolled case
+        *
+        *  Recursive invocations don't need to erase the cursor over and
+        *  over again, so we use fbcon_bmove_rec()
+        */
+       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
+                       p->vrows - p->yscroll);
+}
+
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+                           int dy, int dx, int height, int width, u_int y_break)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       u_int b;
+
+       if (sy < y_break && sy + height > y_break) {
+               b = y_break - sy;
+               if (dy < sy) {  /* Avoid trashing self */
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+               } else {
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+               }
+               return;
+       }
+
+       if (dy < y_break && dy + height > y_break) {
+               b = y_break - dy;
+               if (dy < sy) {  /* Avoid trashing self */
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+               } else {
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+               }
+               return;
+       }
+       ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+                  height, width);
+}
+
+static void updatescrollmode_accel(struct fbcon_display *p,
+                                       struct fb_info *info,
+                                       struct vc_data *vc)
+{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       struct fbcon_ops *ops = info->fbcon_par;
+       int cap = info->flags;
+       u16 t = 0;
+       int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+                                 info->fix.xpanstep);
+       int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+       int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+                                  info->var.xres_virtual);
+       int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+               divides(ypan, vc->vc_font.height) && vyres > yres;
+       int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+               divides(ywrap, vc->vc_font.height) &&
+               divides(vc->vc_font.height, vyres) &&
+               divides(vc->vc_font.height, yres);
+       int reading_fast = cap & FBINFO_READS_FAST;
+       int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+       int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+
+       if (good_wrap || good_pan) {
+               if (reading_fast || fast_copyarea)
+                       p->scrollmode = good_wrap ?
+                               SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+               else
+                       p->scrollmode = good_wrap ? SCROLL_REDRAW :
+                               SCROLL_PAN_REDRAW;
+       } else {
+               if (reading_fast || (fast_copyarea && !fast_imageblit))
+                       p->scrollmode = SCROLL_MOVE;
+               else
+                       p->scrollmode = SCROLL_REDRAW;
+       }
+#endif
+}
+
 static void updatescrollmode(struct fbcon_display *p,
                                        struct fb_info *info,
                                        struct vc_data *vc)
@@ -1507,6 +2005,9 @@ static void updatescrollmode(struct fbcon_display *p,
                p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
        if ((yres % fh) && (vyres % fh < yres % fh))
                p->vrows--;
+
+       /* update scrollmode in case hardware acceleration is used */
+       updatescrollmode_accel(p, info, vc);
 }
 
 #define PITCH(w) (((w) + 7) >> 3)
@@ -1664,7 +2165,21 @@ static int fbcon_switch(struct vc_data *vc)
 
        updatescrollmode(p, info, vc);
 
-       scrollback_phys_max = 0;
+       switch (fb_scrollmode(p)) {
+       case SCROLL_WRAP_MOVE:
+               scrollback_phys_max = p->vrows - vc->vc_rows;
+               break;
+       case SCROLL_PAN_MOVE:
+       case SCROLL_PAN_REDRAW:
+               scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
+               if (scrollback_phys_max < 0)
+                       scrollback_phys_max = 0;
+               break;
+       default:
+               scrollback_phys_max = 0;
+               break;
+       }
+
        scrollback_max = 0;
        scrollback_current = 0;
 
index a00603b..969d41e 100644 (file)
@@ -29,6 +29,9 @@ struct fbcon_display {
     /* Filled in by the low-level console driver */
     const u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+    u_short scrollmode;             /* Scroll Method, use fb_scrollmode() */
+#endif
     u_short inverse;                /* != 0 text black on white as default */
     short yscroll;                  /* Hardware scrolling */
     int vrows;                      /* number of virtual rows */
@@ -51,6 +54,8 @@ struct fbcon_display {
 };
 
 struct fbcon_ops {
+       void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width);
        void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int height, int width);
        void (*putcs)(struct vc_data *vc, struct fb_info *info,
@@ -149,6 +154,73 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
 #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
 #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
 
+    /*
+     *  Scroll Method
+     */
+
+/* There are several methods fbcon can use to move text around the screen:
+ *
+ *                     Operation   Pan    Wrap
+ *---------------------------------------------
+ * SCROLL_MOVE         copyarea    No     No
+ * SCROLL_PAN_MOVE     copyarea    Yes    No
+ * SCROLL_WRAP_MOVE    copyarea    No     Yes
+ * SCROLL_REDRAW       imageblit   No     No
+ * SCROLL_PAN_REDRAW   imageblit   Yes    No
+ * SCROLL_WRAP_REDRAW  imageblit   No     Yes
+ *
+ * (SCROLL_WRAP_REDRAW is not implemented yet)
+ *
+ * In general, fbcon will choose the best scrolling
+ * method based on the rule below:
+ *
+ * Pan/Wrap > accel imageblit > accel copyarea >
+ * soft imageblit > (soft copyarea)
+ *
+ * Exception to the rule: Pan + accel copyarea is
+ * preferred over Pan + accel imageblit.
+ *
+ * The above is typical for PCI/AGP cards. Unless
+ * overridden, fbcon will never use soft copyarea.
+ *
+ * If you need to override the above rule, set the
+ * appropriate flags in fb_info->flags.  For example,
+ * to prefer copyarea over imageblit, set
+ * FBINFO_READS_FAST.
+ *
+ * Other notes:
+ * + use the hardware engine to move the text
+ *    (hw-accelerated copyarea() and fillrect())
+ * + use hardware-supported panning on a large virtual screen
+ * + amifb can not only pan, but also wrap the display by N lines
+ *    (i.e. visible line i = physical line (i+N) % yres).
+ * + read what's already rendered on the screen and
+ *     write it in a different place (this is cfb_copyarea())
+ * + re-render the text to the screen
+ *
+ * Whether to use wrapping or panning can only be figured out at
+ * runtime (when we know whether our font height is a multiple
+ * of the pan/wrap step)
+ *
+ */
+
+#define SCROLL_MOVE       0x001
+#define SCROLL_PAN_MOVE           0x002
+#define SCROLL_WRAP_MOVE   0x003
+#define SCROLL_REDRAW     0x004
+#define SCROLL_PAN_REDRAW  0x005
+
+static inline u_short fb_scrollmode(struct fbcon_display *fb)
+{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       return fb->scrollmode;
+#else
+       /* hardcoded to SCROLL_REDRAW if acceleration was disabled. */
+       return SCROLL_REDRAW;
+#endif
+}
+
+
 #ifdef CONFIG_FB_TILEBLITTING
 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
 #endif
index ffa7893..2789ace 100644 (file)
@@ -59,12 +59,31 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(ops->p, info);
+
+       area.sx = sy * vc->vc_font.height;
+       area.sy = vyres - ((sx + width) * vc->vc_font.width);
+       area.dx = dy * vc->vc_font.height;
+       area.dy = vyres - ((dx + width) * vc->vc_font.width);
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = sy * vc->vc_font.height;
@@ -121,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
        u32 cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -210,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -368,7 +387,7 @@ static int ccw_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
        u32 yoffset;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
        int err;
 
        yoffset = (vyres - info->var.yres) - ops->var.xoffset;
@@ -383,6 +402,7 @@ static int ccw_update_start(struct fb_info *info)
 
 void fbcon_rotate_ccw(struct fbcon_ops *ops)
 {
+       ops->bmove = ccw_bmove;
        ops->clear = ccw_clear;
        ops->putcs = ccw_putcs;
        ops->clear_margins = ccw_clear_margins;
index 92e5b7f..86a254c 100644 (file)
@@ -44,12 +44,31 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vxres = GETVXRES(ops->p, info);
+
+       area.sx = vxres - ((sy + height) * vc->vc_font.height);
+       area.sy = sx * vc->vc_font.width;
+       area.dx = vxres - ((dy + height) * vc->vc_font.height);
+       area.dy = dx * vc->vc_font.width;
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -106,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
        u32 cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -193,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -350,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 static int cw_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
        u32 xoffset;
        int err;
 
@@ -366,6 +385,7 @@ static int cw_update_start(struct fb_info *info)
 
 void fbcon_rotate_cw(struct fbcon_ops *ops)
 {
+       ops->bmove = cw_bmove;
        ops->clear = cw_clear;
        ops->putcs = cw_putcs;
        ops->clear_margins = cw_clear_margins;
index b528b2e..01cbe30 100644 (file)
 #ifndef _FBCON_ROTATE_H
 #define _FBCON_ROTATE_H
 
+#define GETVYRES(s,i) ({                           \
+        (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE) ? \
+        (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({                           \
+        (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+        (i)->var.xres : (i)->var.xres_virtual; })
+
+
 static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
 {
        u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
index 09619bd..23bc045 100644 (file)
@@ -44,13 +44,33 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
+
+       area.sy = vyres - ((sy + height) * vc->vc_font.height);
+       area.sx = vxres - ((sx + width) * vc->vc_font.width);
+       area.dy = vyres - ((dy + height) * vc->vc_font.height);
+       area.dx = vxres - ((dx + width) * vc->vc_font.width);
+       area.height = height * vc->vc_font.height;
+       area.width  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -142,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
        u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -239,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -390,8 +410,8 @@ static int ud_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
        int xoffset, yoffset;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
        int err;
 
        xoffset = vxres - info->var.xres - ops->var.xoffset;
@@ -409,6 +429,7 @@ static int ud_update_start(struct fb_info *info)
 
 void fbcon_rotate_ud(struct fbcon_ops *ops)
 {
+       ops->bmove = ud_bmove;
        ops->clear = ud_clear;
        ops->putcs = ud_putcs;
        ops->clear_margins = ud_clear_margins;
index 72af950..2768eff 100644 (file)
 #include <asm/types.h>
 #include "fbcon.h"
 
+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                      int sx, int dy, int dx, int height, int width)
+{
+       struct fb_tilearea area;
+
+       area.sx = sx;
+       area.sy = sy;
+       area.dx = dx;
+       area.dy = dy;
+       area.height = height;
+       area.width = width;
+
+       info->tileops->fb_tilecopy(info, &area);
+}
+
 static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
                       int sx, int height, int width)
 {
@@ -118,6 +133,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
        struct fb_tilemap map;
        struct fbcon_ops *ops = info->fbcon_par;
 
+       ops->bmove = tile_bmove;
        ops->clear = tile_clear;
        ops->putcs = tile_putcs;
        ops->clear_margins = tile_clear_margins;
index 0fe922f..bcacfb6 100644 (file)
@@ -505,15 +505,15 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
 }
 
 /**
- *      xxxfb_copyarea - OBSOLETE function.
+ *      xxxfb_copyarea - REQUIRED function. Can use generic routines if
+ *                       non acclerated hardware and packed pixel based.
  *                       Copies one area of the screen to another area.
- *                       Will be deleted in a future version
  *
  *      @info: frame buffer structure that represents a single frame buffer
  *      @area: Structure providing the data to copy the framebuffer contents
  *            from one region to another.
  *
- *      This drawing operation copied a rectangular area from one area of the
+ *      This drawing operation copies a rectangular area from one area of the
  *     screen to another area.
  */
 void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 
@@ -645,9 +645,9 @@ static const struct fb_ops xxxfb_ops = {
        .fb_setcolreg   = xxxfb_setcolreg,
        .fb_blank       = xxxfb_blank,
        .fb_pan_display = xxxfb_pan_display,
-       .fb_fillrect    = xxxfb_fillrect,       /* Needed !!!   */
-       .fb_copyarea    = xxxfb_copyarea,       /* Obsolete     */
-       .fb_imageblit   = xxxfb_imageblit,      /* Needed !!!   */
+       .fb_fillrect    = xxxfb_fillrect,       /* Needed !!! */
+       .fb_copyarea    = xxxfb_copyarea,       /* Needed !!! */
+       .fb_imageblit   = xxxfb_imageblit,      /* Needed !!! */
        .fb_cursor      = xxxfb_cursor,         /* Optional !!! */
        .fb_sync        = xxxfb_sync,
        .fb_ioctl       = xxxfb_ioctl,
index 6aab046..79df61f 100644 (file)
@@ -96,12 +96,8 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
                 dentry, dentry, from_kuid(&init_user_ns, uid),
                 any);
        ret = NULL;
-
-       if (d_inode(dentry))
-               ret = v9fs_fid_find_inode(d_inode(dentry), uid);
-
        /* we'll recheck under lock if there's anything to look in */
-       if (!ret && dentry->d_fsdata) {
+       if (dentry->d_fsdata) {
                struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;
 
                spin_lock(&dentry->d_lock);
@@ -113,6 +109,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
                        }
                }
                spin_unlock(&dentry->d_lock);
+       } else {
+               if (dentry->d_inode)
+                       ret = v9fs_fid_find_inode(dentry->d_inode, uid);
        }
 
        return ret;
index 7a2b11c..6c7dc13 100644 (file)
@@ -369,8 +369,8 @@ source "fs/ksmbd/Kconfig"
 
 config SMBFS_COMMON
        tristate
-       default y if CIFS=y
-       default m if CIFS=m
+       default y if CIFS=y || SMB_SERVER=y
+       default m if CIFS=m || SMB_SERVER=m
 
 source "fs/coda/Kconfig"
 source "fs/afs/Kconfig"
index dab324a..208a74e 100644 (file)
@@ -96,7 +96,7 @@ obj-$(CONFIG_EXPORTFS)                += exportfs/
 obj-$(CONFIG_NFSD)             += nfsd/
 obj-$(CONFIG_LOCKD)            += lockd/
 obj-$(CONFIG_NLS)              += nls/
-obj-$(CONFIG_UNICODE)          += unicode/
+obj-y                          += unicode/
 obj-$(CONFIG_SYSV_FS)          += sysv/
 obj-$(CONFIG_SMBFS_COMMON)     += smbfs_common/
 obj-$(CONFIG_CIFS)             += cifs/
index 1db24e6..8202ad6 100644 (file)
@@ -124,7 +124,16 @@ void btrfs_put_block_group(struct btrfs_block_group *cache)
 {
        if (refcount_dec_and_test(&cache->refs)) {
                WARN_ON(cache->pinned > 0);
-               WARN_ON(cache->reserved > 0);
+               /*
+                * If there was a failure to cleanup a log tree, very likely due
+                * to an IO failure on a writeback attempt of one or more of its
+                * extent buffers, we could not do proper (and cheap) unaccounting
+                * of their reserved space, so don't warn on reserved > 0 in that
+                * case.
+                */
+               if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+                   !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
+                       WARN_ON(cache->reserved > 0);
 
                /*
                 * A block_group shouldn't be on the discard_list anymore.
@@ -2544,6 +2553,19 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
        int ret;
        bool dirty_bg_running;
 
+       /*
+        * This can only happen when we are doing read-only scrub on read-only
+        * mount.
+        * In that case we should not start a new transaction on read-only fs.
+        * Thus here we skip all chunk allocations.
+        */
+       if (sb_rdonly(fs_info->sb)) {
+               mutex_lock(&fs_info->ro_block_group_mutex);
+               ret = inc_block_group_ro(cache, 0);
+               mutex_unlock(&fs_info->ro_block_group_mutex);
+               return ret;
+       }
+
        do {
                trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
@@ -3974,9 +3996,22 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                 * important and indicates a real bug if this happens.
                 */
                if (WARN_ON(space_info->bytes_pinned > 0 ||
-                           space_info->bytes_reserved > 0 ||
                            space_info->bytes_may_use > 0))
                        btrfs_dump_space_info(info, space_info, 0, 0);
+
+               /*
+                * If there was a failure to cleanup a log tree, very likely due
+                * to an IO failure on a writeback attempt of one or more of its
+                * extent buffers, we could not do proper (and cheap) unaccounting
+                * of their reserved space, so don't warn on bytes_reserved > 0 in
+                * that case.
+                */
+               if (!(space_info->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+                   !BTRFS_FS_LOG_CLEANUP_ERROR(info)) {
+                       if (WARN_ON(space_info->bytes_reserved > 0))
+                               btrfs_dump_space_info(info, space_info, 0, 0);
+               }
+
                WARN_ON(space_info->reclaim_size > 0);
                list_del(&space_info->list);
                btrfs_sysfs_remove_space_info(space_info);
index b4a9b1c..8992e00 100644 (file)
@@ -145,6 +145,9 @@ enum {
        BTRFS_FS_STATE_DUMMY_FS_INFO,
 
        BTRFS_FS_STATE_NO_CSUMS,
+
+       /* Indicates there was an error cleaning up a log tree. */
+       BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
 };
 
 #define BTRFS_BACKREF_REV_MAX          256
@@ -3593,6 +3596,9 @@ do {                                                              \
 
 #define BTRFS_FS_ERROR(fs_info)        (unlikely(test_bit(BTRFS_FS_STATE_ERROR, \
                                                   &(fs_info)->fs_state)))
+#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info)                            \
+       (unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,            \
+                          &(fs_info)->fs_state)))
 
 __printf(5, 6)
 __cold
index d8af662..33eda39 100644 (file)
@@ -805,10 +805,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
                goto fail;
        }
 
-       spin_lock(&fs_info->trans_lock);
-       list_add(&pending_snapshot->list,
-                &trans->transaction->pending_snapshots);
-       spin_unlock(&fs_info->trans_lock);
+       trans->pending_snapshot = pending_snapshot;
 
        ret = btrfs_commit_transaction(trans);
        if (ret)
@@ -3354,7 +3351,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        struct block_device *bdev = NULL;
        fmode_t mode;
        int ret;
-       bool cancel;
+       bool cancel = false;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
index 8928275..f12dc68 100644 (file)
@@ -1185,9 +1185,24 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        struct btrfs_trans_handle *trans = NULL;
        int ret = 0;
 
+       /*
+        * We need to have subvol_sem write locked, to prevent races between
+        * concurrent tasks trying to disable quotas, because we will unlock
+        * and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
+        */
+       lockdep_assert_held_write(&fs_info->subvol_sem);
+
        mutex_lock(&fs_info->qgroup_ioctl_lock);
        if (!fs_info->quota_root)
                goto out;
+
+       /*
+        * Request qgroup rescan worker to complete and wait for it. This wait
+        * must be done before transaction start for quota disable since it may
+        * deadlock with transaction by the qgroup rescan worker.
+        */
+       clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+       btrfs_qgroup_wait_for_completion(fs_info, false);
        mutex_unlock(&fs_info->qgroup_ioctl_lock);
 
        /*
@@ -1205,14 +1220,13 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                trans = NULL;
+               set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
                goto out;
        }
 
        if (!fs_info->quota_root)
                goto out;
 
-       clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
-       btrfs_qgroup_wait_for_completion(fs_info, false);
        spin_lock(&fs_info->qgroup_lock);
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
@@ -3383,6 +3397,9 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
                        btrfs_warn(fs_info,
                        "qgroup rescan init failed, qgroup is not enabled");
                        ret = -EINVAL;
+               } else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
+                       /* Quota disable is in progress */
+                       ret = -EBUSY;
                }
 
                if (ret) {
index 03de89b..c43bbc7 100644 (file)
@@ -2000,6 +2000,27 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
                btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
 }
 
+/*
+ * Add a pending snapshot associated with the given transaction handle to the
+ * respective handle. This must be called after the transaction commit started
+ * and while holding fs_info->trans_lock.
+ * This serves to guarantee a caller of btrfs_commit_transaction() that it can
+ * safely free the pending snapshot pointer in case btrfs_commit_transaction()
+ * returns an error.
+ */
+static void add_pending_snapshot(struct btrfs_trans_handle *trans)
+{
+       struct btrfs_transaction *cur_trans = trans->transaction;
+
+       if (!trans->pending_snapshot)
+               return;
+
+       lockdep_assert_held(&trans->fs_info->trans_lock);
+       ASSERT(cur_trans->state >= TRANS_STATE_COMMIT_START);
+
+       list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
+}
+
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
@@ -2073,6 +2094,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
        if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
                enum btrfs_trans_state want_state = TRANS_STATE_COMPLETED;
 
+               add_pending_snapshot(trans);
+
                spin_unlock(&fs_info->trans_lock);
                refcount_inc(&cur_trans->use_count);
 
@@ -2163,6 +2186,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
         * COMMIT_DOING so make sure to wait for num_writers to == 1 again.
         */
        spin_lock(&fs_info->trans_lock);
+       add_pending_snapshot(trans);
        cur_trans->state = TRANS_STATE_COMMIT_DOING;
        spin_unlock(&fs_info->trans_lock);
        wait_event(cur_trans->writer_wait,
index 1852ed9..9402d8d 100644 (file)
@@ -123,6 +123,8 @@ struct btrfs_trans_handle {
        struct btrfs_transaction *transaction;
        struct btrfs_block_rsv *block_rsv;
        struct btrfs_block_rsv *orig_rsv;
+       /* Set by a task that wants to create a snapshot. */
+       struct btrfs_pending_snapshot *pending_snapshot;
        refcount_t use_count;
        unsigned int type;
        /*
index 72e1c94..9fd145f 100644 (file)
@@ -965,6 +965,7 @@ static int check_dev_item(struct extent_buffer *leaf,
                          struct btrfs_key *key, int slot)
 {
        struct btrfs_dev_item *ditem;
+       const u32 item_size = btrfs_item_size(leaf, slot);
 
        if (unlikely(key->objectid != BTRFS_DEV_ITEMS_OBJECTID)) {
                dev_item_err(leaf, slot,
@@ -972,6 +973,13 @@ static int check_dev_item(struct extent_buffer *leaf,
                             key->objectid, BTRFS_DEV_ITEMS_OBJECTID);
                return -EUCLEAN;
        }
+
+       if (unlikely(item_size != sizeof(*ditem))) {
+               dev_item_err(leaf, slot, "invalid item size: has %u expect %zu",
+                            item_size, sizeof(*ditem));
+               return -EUCLEAN;
+       }
+
        ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item);
        if (unlikely(btrfs_device_id(leaf, ditem) != key->offset)) {
                dev_item_err(leaf, slot,
@@ -1007,6 +1015,7 @@ static int check_inode_item(struct extent_buffer *leaf,
        struct btrfs_inode_item *iitem;
        u64 super_gen = btrfs_super_generation(fs_info->super_copy);
        u32 valid_mask = (S_IFMT | S_ISUID | S_ISGID | S_ISVTX | 0777);
+       const u32 item_size = btrfs_item_size(leaf, slot);
        u32 mode;
        int ret;
        u32 flags;
@@ -1016,6 +1025,12 @@ static int check_inode_item(struct extent_buffer *leaf,
        if (unlikely(ret < 0))
                return ret;
 
+       if (unlikely(item_size != sizeof(*iitem))) {
+               generic_err(leaf, slot, "invalid item size: has %u expect %zu",
+                           item_size, sizeof(*iitem));
+               return -EUCLEAN;
+       }
+
        iitem = btrfs_item_ptr(leaf, slot, struct btrfs_inode_item);
 
        /* Here we use super block generation + 1 to handle log tree */
index c1ddbe8..3ee014c 100644 (file)
@@ -3414,6 +3414,29 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
        if (log->node) {
                ret = walk_log_tree(trans, log, &wc);
                if (ret) {
+                       /*
+                        * We weren't able to traverse the entire log tree, the
+                        * typical scenario is getting an -EIO when reading an
+                        * extent buffer of the tree, due to a previous writeback
+                        * failure of it.
+                        */
+                       set_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
+                               &log->fs_info->fs_state);
+
+                       /*
+                        * Some extent buffers of the log tree may still be dirty
+                        * and not yet written back to storage, because we may
+                        * have updates to a log tree without syncing a log tree,
+                        * such as during rename and link operations. So flush
+                        * them out and wait for their writeback to complete, so
+                        * that we properly cleanup their state and pages.
+                        */
+                       btrfs_write_marked_extents(log->fs_info,
+                                                  &log->dirty_log_pages,
+                                                  EXTENT_DIRTY | EXTENT_NEW);
+                       btrfs_wait_tree_log_extents(log,
+                                                   EXTENT_DIRTY | EXTENT_NEW);
+
                        if (trans)
                                btrfs_abort_transaction(trans, ret);
                        else
index 04eb527..753986e 100644 (file)
@@ -191,6 +191,64 @@ presubmission_error:
        return ret;
 }
 
+/*
+ * Query the occupancy of the cache in a region, returning where the next chunk
+ * of data starts and how long it is.
+ */
+static int cachefiles_query_occupancy(struct netfs_cache_resources *cres,
+                                     loff_t start, size_t len, size_t granularity,
+                                     loff_t *_data_start, size_t *_data_len)
+{
+       struct cachefiles_object *object;
+       struct file *file;
+       loff_t off, off2;
+
+       *_data_start = -1;
+       *_data_len = 0;
+
+       if (!fscache_wait_for_operation(cres, FSCACHE_WANT_READ))
+               return -ENOBUFS;
+
+       object = cachefiles_cres_object(cres);
+       file = cachefiles_cres_file(cres);
+       granularity = max_t(size_t, object->volume->cache->bsize, granularity);
+
+       _enter("%pD,%li,%llx,%zx/%llx",
+              file, file_inode(file)->i_ino, start, len,
+              i_size_read(file_inode(file)));
+
+       off = cachefiles_inject_read_error();
+       if (off == 0)
+               off = vfs_llseek(file, start, SEEK_DATA);
+       if (off == -ENXIO)
+               return -ENODATA; /* Beyond EOF */
+       if (off < 0 && off >= (loff_t)-MAX_ERRNO)
+               return -ENOBUFS; /* Error. */
+       if (round_up(off, granularity) >= start + len)
+               return -ENODATA; /* No data in range */
+
+       off2 = cachefiles_inject_read_error();
+       if (off2 == 0)
+               off2 = vfs_llseek(file, off, SEEK_HOLE);
+       if (off2 == -ENXIO)
+               return -ENODATA; /* Beyond EOF */
+       if (off2 < 0 && off2 >= (loff_t)-MAX_ERRNO)
+               return -ENOBUFS; /* Error. */
+
+       /* Round away partial blocks */
+       off = round_up(off, granularity);
+       off2 = round_down(off2, granularity);
+       if (off2 <= off)
+               return -ENODATA;
+
+       *_data_start = off;
+       if (off2 > start + len)
+               *_data_len = len;
+       else
+               *_data_len = off2 - off;
+       return 0;
+}
+
 /*
  * Handle completion of a write to the cache.
  */
@@ -545,6 +603,7 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
        .write                  = cachefiles_write,
        .prepare_read           = cachefiles_prepare_read,
        .prepare_write          = cachefiles_prepare_write,
+       .query_occupancy        = cachefiles_query_occupancy,
 };
 
 /*
index 11a22a3..0b742bd 100644 (file)
@@ -162,7 +162,7 @@ static void cifs_resolve_server(struct work_struct *work)
        mutex_unlock(&server->srv_mutex);
 }
 
-/**
+/*
  * Mark all sessions and tcons for reconnect.
  *
  * @server needs to be previously set to CifsNeedReconnect.
@@ -1831,13 +1831,9 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
                int i;
 
                for (i = 1; i < chan_count; i++) {
-                       /*
-                        * note: for now, we're okay accessing ses->chans
-                        * without chan_lock. But when chans can go away, we'll
-                        * need to introduce ref counting to make sure that chan
-                        * is not freed from under us.
-                        */
+                       spin_unlock(&ses->chan_lock);
                        cifs_put_tcp_session(ses->chans[i].server, 0);
+                       spin_lock(&ses->chan_lock);
                        ses->chans[i].server = NULL;
                }
        }
@@ -1981,6 +1977,19 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
                }
        }
 
+       ctx->workstation_name = kstrdup(ses->workstation_name, GFP_KERNEL);
+       if (!ctx->workstation_name) {
+               cifs_dbg(FYI, "Unable to allocate memory for workstation_name\n");
+               rc = -ENOMEM;
+               kfree(ctx->username);
+               ctx->username = NULL;
+               kfree_sensitive(ctx->password);
+               ctx->password = NULL;
+               kfree(ctx->domainname);
+               ctx->domainname = NULL;
+               goto out_key_put;
+       }
+
 out_key_put:
        up_read(&key->sem);
        key_put(key);
index 59334be..e7af802 100644 (file)
@@ -4269,8 +4269,6 @@ cifs_readv_complete(struct work_struct *work)
        for (i = 0; i < rdata->nr_pages; i++) {
                struct page *page = rdata->pages[i];
 
-               lru_cache_add(page);
-
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes)) {
                        flush_dcache_page(page);
@@ -4278,12 +4276,12 @@ cifs_readv_complete(struct work_struct *work)
                } else
                        SetPageError(page);
 
-               unlock_page(page);
-
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes))
                        cifs_readpage_to_fscache(rdata->mapping->host, page);
 
+               unlock_page(page);
+
                got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
 
                put_page(page);
@@ -4340,7 +4338,6 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                         * fill them until the writes are flushed.
                         */
                        zero_user(page, 0, PAGE_SIZE);
-                       lru_cache_add(page);
                        flush_dcache_page(page);
                        SetPageUptodate(page);
                        unlock_page(page);
@@ -4350,7 +4347,6 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                        continue;
                } else {
                        /* no need to hold page hostage */
-                       lru_cache_add(page);
                        unlock_page(page);
                        put_page(page);
                        rdata->pages[i] = NULL;
@@ -4393,92 +4389,20 @@ cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
        return readpages_fill_pages(server, rdata, iter, iter->count);
 }
 
-static int
-readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
-                   unsigned int rsize, struct list_head *tmplist,
-                   unsigned int *nr_pages, loff_t *offset, unsigned int *bytes)
-{
-       struct page *page, *tpage;
-       unsigned int expected_index;
-       int rc;
-       gfp_t gfp = readahead_gfp_mask(mapping);
-
-       INIT_LIST_HEAD(tmplist);
-
-       page = lru_to_page(page_list);
-
-       /*
-        * Lock the page and put it in the cache. Since no one else
-        * should have access to this page, we're safe to simply set
-        * PG_locked without checking it first.
-        */
-       __SetPageLocked(page);
-       rc = add_to_page_cache_locked(page, mapping,
-                                     page->index, gfp);
-
-       /* give up if we can't stick it in the cache */
-       if (rc) {
-               __ClearPageLocked(page);
-               return rc;
-       }
-
-       /* move first page to the tmplist */
-       *offset = (loff_t)page->index << PAGE_SHIFT;
-       *bytes = PAGE_SIZE;
-       *nr_pages = 1;
-       list_move_tail(&page->lru, tmplist);
-
-       /* now try and add more pages onto the request */
-       expected_index = page->index + 1;
-       list_for_each_entry_safe_reverse(page, tpage, page_list, lru) {
-               /* discontinuity ? */
-               if (page->index != expected_index)
-                       break;
-
-               /* would this page push the read over the rsize? */
-               if (*bytes + PAGE_SIZE > rsize)
-                       break;
-
-               __SetPageLocked(page);
-               rc = add_to_page_cache_locked(page, mapping, page->index, gfp);
-               if (rc) {
-                       __ClearPageLocked(page);
-                       break;
-               }
-               list_move_tail(&page->lru, tmplist);
-               (*bytes) += PAGE_SIZE;
-               expected_index++;
-               (*nr_pages)++;
-       }
-       return rc;
-}
-
-static int cifs_readpages(struct file *file, struct address_space *mapping,
-       struct list_head *page_list, unsigned num_pages)
+static void cifs_readahead(struct readahead_control *ractl)
 {
        int rc;
-       int err = 0;
-       struct list_head tmplist;
-       struct cifsFileInfo *open_file = file->private_data;
-       struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+       struct cifsFileInfo *open_file = ractl->file->private_data;
+       struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(ractl->file);
        struct TCP_Server_Info *server;
        pid_t pid;
-       unsigned int xid;
+       unsigned int xid, nr_pages, last_batch_size = 0, cache_nr_pages = 0;
+       pgoff_t next_cached = ULONG_MAX;
+       bool caching = fscache_cookie_enabled(cifs_inode_cookie(ractl->mapping->host)) &&
+               cifs_inode_cookie(ractl->mapping->host)->cache_priv;
+       bool check_cache = caching;
 
        xid = get_xid();
-       /*
-        * Reads as many pages as possible from fscache. Returns -ENOBUFS
-        * immediately if the cookie is negative
-        *
-        * After this point, every page in the list might have PG_fscache set,
-        * so we will need to clean that up off of every page we don't use.
-        */
-       rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
-                                        &num_pages);
-       if (rc == 0) {
-               free_xid(xid);
-               return rc;
-       }
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
                pid = open_file->pid;
@@ -4489,39 +4413,73 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses);
 
        cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n",
-                __func__, file, mapping, num_pages);
+                __func__, ractl->file, ractl->mapping, readahead_count(ractl));
 
        /*
-        * Start with the page at end of list and move it to private
-        * list. Do the same with any following pages until we hit
-        * the rsize limit, hit an index discontinuity, or run out of
-        * pages. Issue the async read and then start the loop again
-        * until the list is empty.
-        *
-        * Note that list order is important. The page_list is in
-        * the order of declining indexes. When we put the pages in
-        * the rdata->pages, then we want them in increasing order.
+        * Chop the readahead request up into rsize-sized read requests.
         */
-       while (!list_empty(page_list) && !err) {
-               unsigned int i, nr_pages, bytes, rsize;
-               loff_t offset;
-               struct page *page, *tpage;
+       while ((nr_pages = readahead_count(ractl) - last_batch_size)) {
+               unsigned int i, got, rsize;
+               struct page *page;
                struct cifs_readdata *rdata;
                struct cifs_credits credits_on_stack;
                struct cifs_credits *credits = &credits_on_stack;
+               pgoff_t index = readahead_index(ractl) + last_batch_size;
+
+               /*
+                * Find out if we have anything cached in the range of
+                * interest, and if so, where the next chunk of cached data is.
+                */
+               if (caching) {
+                       if (check_cache) {
+                               rc = cifs_fscache_query_occupancy(
+                                       ractl->mapping->host, index, nr_pages,
+                                       &next_cached, &cache_nr_pages);
+                               if (rc < 0)
+                                       caching = false;
+                               check_cache = false;
+                       }
+
+                       if (index == next_cached) {
+                               /*
+                                * TODO: Send a whole batch of pages to be read
+                                * by the cache.
+                                */
+                               page = readahead_page(ractl);
+                               last_batch_size = 1 << thp_order(page);
+                               if (cifs_readpage_from_fscache(ractl->mapping->host,
+                                                              page) < 0) {
+                                       /*
+                                        * TODO: Deal with cache read failure
+                                        * here, but for the moment, delegate
+                                        * that to readpage.
+                                        */
+                                       caching = false;
+                               }
+                               unlock_page(page);
+                               next_cached++;
+                               cache_nr_pages--;
+                               if (cache_nr_pages == 0)
+                                       check_cache = true;
+                               continue;
+                       }
+               }
 
                if (open_file->invalidHandle) {
                        rc = cifs_reopen_file(open_file, true);
-                       if (rc == -EAGAIN)
-                               continue;
-                       else if (rc)
+                       if (rc) {
+                               if (rc == -EAGAIN)
+                                       continue;
                                break;
+                       }
                }
 
                rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
                                                   &rsize, credits);
                if (rc)
                        break;
+               nr_pages = min_t(size_t, rsize / PAGE_SIZE, readahead_count(ractl));
+               nr_pages = min_t(size_t, nr_pages, next_cached - index);
 
                /*
                 * Give up immediately if rsize is too small to read an entire
@@ -4529,16 +4487,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                 * reach this point however since we set ra_pages to 0 when the
                 * rsize is smaller than a cache page.
                 */
-               if (unlikely(rsize < PAGE_SIZE)) {
-                       add_credits_and_wake_if(server, credits, 0);
-                       free_xid(xid);
-                       return 0;
-               }
-
-               nr_pages = 0;
-               err = readpages_get_pages(mapping, page_list, rsize, &tmplist,
-                                        &nr_pages, &offset, &bytes);
-               if (!nr_pages) {
+               if (unlikely(!nr_pages)) {
                        add_credits_and_wake_if(server, credits, 0);
                        break;
                }
@@ -4546,36 +4495,31 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete);
                if (!rdata) {
                        /* best to give up if we're out of mem */
-                       list_for_each_entry_safe(page, tpage, &tmplist, lru) {
-                               list_del(&page->lru);
-                               lru_cache_add(page);
-                               unlock_page(page);
-                               put_page(page);
-                       }
-                       rc = -ENOMEM;
                        add_credits_and_wake_if(server, credits, 0);
                        break;
                }
 
-               rdata->cfile = cifsFileInfo_get(open_file);
-               rdata->server = server;
-               rdata->mapping = mapping;
-               rdata->offset = offset;
-               rdata->bytes = bytes;
-               rdata->pid = pid;
-               rdata->pagesz = PAGE_SIZE;
-               rdata->tailsz = PAGE_SIZE;
+               got = __readahead_batch(ractl, rdata->pages, nr_pages);
+               if (got != nr_pages) {
+                       pr_warn("__readahead_batch() returned %u/%u\n",
+                               got, nr_pages);
+                       nr_pages = got;
+               }
+
+               rdata->nr_pages = nr_pages;
+               rdata->bytes    = readahead_batch_length(ractl);
+               rdata->cfile    = cifsFileInfo_get(open_file);
+               rdata->server   = server;
+               rdata->mapping  = ractl->mapping;
+               rdata->offset   = readahead_pos(ractl);
+               rdata->pid      = pid;
+               rdata->pagesz   = PAGE_SIZE;
+               rdata->tailsz   = PAGE_SIZE;
                rdata->read_into_pages = cifs_readpages_read_into_pages;
                rdata->copy_into_pages = cifs_readpages_copy_into_pages;
-               rdata->credits = credits_on_stack;
-
-               list_for_each_entry_safe(page, tpage, &tmplist, lru) {
-                       list_del(&page->lru);
-                       rdata->pages[rdata->nr_pages++] = page;
-               }
+               rdata->credits  = credits_on_stack;
 
                rc = adjust_credits(server, &rdata->credits, rdata->bytes);
-
                if (!rc) {
                        if (rdata->cfile->invalidHandle)
                                rc = -EAGAIN;
@@ -4587,7 +4531,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        add_credits_and_wake_if(server, &rdata->credits, 0);
                        for (i = 0; i < rdata->nr_pages; i++) {
                                page = rdata->pages[i];
-                               lru_cache_add(page);
                                unlock_page(page);
                                put_page(page);
                        }
@@ -4597,10 +4540,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                }
 
                kref_put(&rdata->refcount, cifs_readdata_release);
+               last_batch_size = nr_pages;
        }
 
        free_xid(xid);
-       return rc;
 }
 
 /*
@@ -4924,7 +4867,7 @@ oplock_break_done:
  * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests
  * so this method should never be called.
  *
- * Direct IO is not yet supported in the cached mode. 
+ * Direct IO is not yet supported in the cached mode.
  */
 static ssize_t
 cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter)
@@ -5006,7 +4949,7 @@ static int cifs_set_page_dirty(struct page *page)
 
 const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
-       .readpages = cifs_readpages,
+       .readahead = cifs_readahead,
        .writepage = cifs_writepage,
        .writepages = cifs_writepages,
        .write_begin = cifs_write_begin,
index efaac4d..33af72e 100644 (file)
@@ -134,37 +134,127 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
        }
 }
 
+static inline void fscache_end_operation(struct netfs_cache_resources *cres)
+{
+       const struct netfs_cache_ops *ops = fscache_operation_valid(cres);
+
+       if (ops)
+               ops->end_operation(cres);
+}
+
 /*
- * Retrieve a page from FS-Cache
+ * Fallback page reading interface.
  */
-int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+static int fscache_fallback_read_page(struct inode *inode, struct page *page)
 {
-       cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
-                __func__, CIFS_I(inode)->fscache, page, inode);
-       return -ENOBUFS; // Needs conversion to using netfslib
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       struct iov_iter iter;
+       struct bio_vec bvec[1];
+       int ret;
+
+       memset(&cres, 0, sizeof(cres));
+       bvec[0].bv_page         = page;
+       bvec[0].bv_offset       = 0;
+       bvec[0].bv_len          = PAGE_SIZE;
+       iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+
+       ret = fscache_begin_read_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
+                          NULL, NULL);
+       fscache_end_operation(&cres);
+       return ret;
 }
 
 /*
- * Retrieve a set of pages from FS-Cache
+ * Fallback page writing interface.
  */
-int __cifs_readpages_from_fscache(struct inode *inode,
-                               struct address_space *mapping,
-                               struct list_head *pages,
-                               unsigned *nr_pages)
+static int fscache_fallback_write_page(struct inode *inode, struct page *page,
+                                      bool no_space_allocated_yet)
 {
-       cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
-                __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
-       return -ENOBUFS; // Needs conversion to using netfslib
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       struct iov_iter iter;
+       struct bio_vec bvec[1];
+       loff_t start = page_offset(page);
+       size_t len = PAGE_SIZE;
+       int ret;
+
+       memset(&cres, 0, sizeof(cres));
+       bvec[0].bv_page         = page;
+       bvec[0].bv_offset       = 0;
+       bvec[0].bv_len          = PAGE_SIZE;
+       iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+
+       ret = fscache_begin_write_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
+                                     no_space_allocated_yet);
+       if (ret == 0)
+               ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
+       fscache_end_operation(&cres);
+       return ret;
 }
 
-void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+/*
+ * Retrieve a page from FS-Cache
+ */
+int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
-       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       int ret;
 
-       WARN_ON(!cifsi->fscache);
+       cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
+                __func__, cifs_inode_cookie(inode), page, inode);
 
+       ret = fscache_fallback_read_page(inode, page);
+       if (ret < 0)
+               return ret;
+
+       /* Read completed synchronously */
+       SetPageUptodate(page);
+       return 0;
+}
+
+void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+{
        cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
-                __func__, cifsi->fscache, page, inode);
+                __func__, cifs_inode_cookie(inode), page, inode);
+
+       fscache_fallback_write_page(inode, page, true);
+}
+
+/*
+ * Query the cache occupancy.
+ */
+int __cifs_fscache_query_occupancy(struct inode *inode,
+                                  pgoff_t first, unsigned int nr_pages,
+                                  pgoff_t *_data_first,
+                                  unsigned int *_data_nr_pages)
+{
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       loff_t start, data_start;
+       size_t len, data_len;
+       int ret;
 
-       // Needs conversion to using netfslib
+       ret = fscache_begin_read_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       start = first * PAGE_SIZE;
+       len = nr_pages * PAGE_SIZE;
+       ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
+                                       &data_start, &data_len);
+       if (ret == 0) {
+               *_data_first = data_start / PAGE_SIZE;
+               *_data_nr_pages = len / PAGE_SIZE;
+       }
+
+       fscache_end_operation(&cres);
+       return ret;
 }
index c6ca49a..5512990 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef _CIFS_FSCACHE_H
 #define _CIFS_FSCACHE_H
 
+#include <linux/swap.h>
 #include <linux/fscache.h>
 
 #include "cifsglob.h"
@@ -58,14 +59,6 @@ void cifs_fscache_fill_coherency(struct inode *inode,
 }
 
 
-extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
-extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
-extern int __cifs_readpages_from_fscache(struct inode *,
-                                        struct address_space *,
-                                        struct list_head *,
-                                        unsigned *);
-extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
-
 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode)
 {
        return CIFS_I(inode)->fscache;
@@ -80,33 +73,52 @@ static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags
                           i_size_read(inode), flags);
 }
 
-static inline int cifs_readpage_from_fscache(struct inode *inode,
-                                            struct page *page)
-{
-       if (CIFS_I(inode)->fscache)
-               return __cifs_readpage_from_fscache(inode, page);
+extern int __cifs_fscache_query_occupancy(struct inode *inode,
+                                         pgoff_t first, unsigned int nr_pages,
+                                         pgoff_t *_data_first,
+                                         unsigned int *_data_nr_pages);
 
-       return -ENOBUFS;
+static inline int cifs_fscache_query_occupancy(struct inode *inode,
+                                              pgoff_t first, unsigned int nr_pages,
+                                              pgoff_t *_data_first,
+                                              unsigned int *_data_nr_pages)
+{
+       if (!cifs_inode_cookie(inode))
+               return -ENOBUFS;
+       return __cifs_fscache_query_occupancy(inode, first, nr_pages,
+                                             _data_first, _data_nr_pages);
 }
 
-static inline int cifs_readpages_from_fscache(struct inode *inode,
-                                             struct address_space *mapping,
-                                             struct list_head *pages,
-                                             unsigned *nr_pages)
+extern int __cifs_readpage_from_fscache(struct inode *pinode, struct page *ppage);
+extern void __cifs_readpage_to_fscache(struct inode *pinode, struct page *ppage);
+
+
+static inline int cifs_readpage_from_fscache(struct inode *inode,
+                                            struct page *page)
 {
-       if (CIFS_I(inode)->fscache)
-               return __cifs_readpages_from_fscache(inode, mapping, pages,
-                                                    nr_pages);
+       if (cifs_inode_cookie(inode))
+               return __cifs_readpage_from_fscache(inode, page);
        return -ENOBUFS;
 }
 
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                                            struct page *page)
 {
-       if (PageFsCache(page))
+       if (cifs_inode_cookie(inode))
                __cifs_readpage_to_fscache(inode, page);
 }
 
+static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       if (PageFsCache(page)) {
+               if (current_is_kswapd() || !(gfp & __GFP_FS))
+                       return false;
+               wait_on_page_fscache(page);
+               fscache_note_page_release(cifs_inode_cookie(page->mapping->host));
+       }
+       return true;
+}
+
 #else /* CONFIG_CIFS_FSCACHE */
 static inline
 void cifs_fscache_fill_coherency(struct inode *inode,
@@ -123,22 +135,29 @@ static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool upd
 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; }
 static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {}
 
-static inline int
-cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+static inline int cifs_fscache_query_occupancy(struct inode *inode,
+                                              pgoff_t first, unsigned int nr_pages,
+                                              pgoff_t *_data_first,
+                                              unsigned int *_data_nr_pages)
 {
+       *_data_first = ULONG_MAX;
+       *_data_nr_pages = 0;
        return -ENOBUFS;
 }
 
-static inline int cifs_readpages_from_fscache(struct inode *inode,
-                                             struct address_space *mapping,
-                                             struct list_head *pages,
-                                             unsigned *nr_pages)
+static inline int
+cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
        return -ENOBUFS;
 }
 
-static inline void cifs_readpage_to_fscache(struct inode *inode,
-                       struct page *page) {}
+static inline
+void cifs_readpage_to_fscache(struct inode *inode, struct page *page) {}
+
+static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       return true; /* May release page */
+}
 
 #endif /* CONFIG_CIFS_FSCACHE */
 
index 7d8b3ce..60d853c 100644 (file)
@@ -83,6 +83,7 @@ static void cifs_set_ops(struct inode *inode)
 static void
 cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
 {
+       struct cifs_fscache_inode_coherency_data cd;
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
 
        cifs_dbg(FYI, "%s: revalidating inode %llu\n",
@@ -113,6 +114,9 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n",
                 __func__, cifs_i->uniqueid);
        set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags);
+       /* Invalidate fscache cookie */
+       cifs_fscache_fill_coherency(&cifs_i->vfs_inode, &cd);
+       fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
 }
 
 /*
@@ -2261,8 +2265,6 @@ cifs_dentry_needs_reval(struct dentry *dentry)
 int
 cifs_invalidate_mapping(struct inode *inode)
 {
-       struct cifs_fscache_inode_coherency_data cd;
-       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        int rc = 0;
 
        if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
@@ -2272,8 +2274,6 @@ cifs_invalidate_mapping(struct inode *inode)
                                 __func__, inode);
        }
 
-       cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd);
-       fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
        return rc;
 }
 
index dc3b16d..5723d50 100644 (file)
@@ -713,7 +713,11 @@ static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
        else
                sz += sizeof(__le16);
 
-       sz += sizeof(__le16) * strnlen(ses->workstation_name, CIFS_MAX_WORKSTATION_LEN);
+       if (ses->workstation_name)
+               sz += sizeof(__le16) * strnlen(ses->workstation_name,
+                       CIFS_MAX_WORKSTATION_LEN);
+       else
+               sz += sizeof(__le16);
 
        return sz;
 }
index fa7ddb7..226a57c 100644 (file)
@@ -252,12 +252,10 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
                return ret;
 
        iomap->offset = map.m_la;
-       if (flags & IOMAP_DAX) {
+       if (flags & IOMAP_DAX)
                iomap->dax_dev = mdev.m_daxdev;
-               iomap->offset += mdev.m_dax_part_off;
-       } else {
+       else
                iomap->bdev = mdev.m_bdev;
-       }
        iomap->length = map.m_llen;
        iomap->flags = 0;
        iomap->private = NULL;
@@ -284,6 +282,8 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
        } else {
                iomap->type = IOMAP_MAPPED;
                iomap->addr = mdev.m_pa;
+               if (flags & IOMAP_DAX)
+                       iomap->addr += mdev.m_dax_part_off;
        }
        return 0;
 }
index 498b766..423bc1a 100644 (file)
@@ -810,68 +810,11 @@ static bool z_erofs_get_sync_decompress_policy(struct erofs_sb_info *sbi,
        return false;
 }
 
-static void z_erofs_decompressqueue_work(struct work_struct *work);
-static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
-                                      bool sync, int bios)
-{
-       struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
-
-       /* wake up the caller thread for sync decompression */
-       if (sync) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&io->u.wait.lock, flags);
-               if (!atomic_add_return(bios, &io->pending_bios))
-                       wake_up_locked(&io->u.wait);
-               spin_unlock_irqrestore(&io->u.wait.lock, flags);
-               return;
-       }
-
-       if (atomic_add_return(bios, &io->pending_bios))
-               return;
-       /* Use workqueue and sync decompression for atomic contexts only */
-       if (in_atomic() || irqs_disabled()) {
-               queue_work(z_erofs_workqueue, &io->u.work);
-               /* enable sync decompression for readahead */
-               if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
-                       sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
-               return;
-       }
-       z_erofs_decompressqueue_work(&io->u.work);
-}
-
 static bool z_erofs_page_is_invalidated(struct page *page)
 {
        return !page->mapping && !z_erofs_is_shortlived_page(page);
 }
 
-static void z_erofs_decompressqueue_endio(struct bio *bio)
-{
-       tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
-       struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
-       blk_status_t err = bio->bi_status;
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               struct page *page = bvec->bv_page;
-
-               DBG_BUGON(PageUptodate(page));
-               DBG_BUGON(z_erofs_page_is_invalidated(page));
-
-               if (err)
-                       SetPageError(page);
-
-               if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
-                       if (!err)
-                               SetPageUptodate(page);
-                       unlock_page(page);
-               }
-       }
-       z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
-       bio_put(bio);
-}
-
 static int z_erofs_decompress_pcluster(struct super_block *sb,
                                       struct z_erofs_pcluster *pcl,
                                       struct page **pagepool)
@@ -1123,6 +1066,35 @@ static void z_erofs_decompressqueue_work(struct work_struct *work)
        kvfree(bgq);
 }
 
+static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
+                                      bool sync, int bios)
+{
+       struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
+
+       /* wake up the caller thread for sync decompression */
+       if (sync) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&io->u.wait.lock, flags);
+               if (!atomic_add_return(bios, &io->pending_bios))
+                       wake_up_locked(&io->u.wait);
+               spin_unlock_irqrestore(&io->u.wait.lock, flags);
+               return;
+       }
+
+       if (atomic_add_return(bios, &io->pending_bios))
+               return;
+       /* Use workqueue and sync decompression for atomic contexts only */
+       if (in_atomic() || irqs_disabled()) {
+               queue_work(z_erofs_workqueue, &io->u.work);
+               /* enable sync decompression for readahead */
+               if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
+                       sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
+               return;
+       }
+       z_erofs_decompressqueue_work(&io->u.work);
+}
+
 static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
                                               unsigned int nr,
                                               struct page **pagepool,
@@ -1300,6 +1272,33 @@ static void move_to_bypass_jobqueue(struct z_erofs_pcluster *pcl,
        qtail[JQ_BYPASS] = &pcl->next;
 }
 
+static void z_erofs_decompressqueue_endio(struct bio *bio)
+{
+       tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
+       struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
+       blk_status_t err = bio->bi_status;
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all) {
+               struct page *page = bvec->bv_page;
+
+               DBG_BUGON(PageUptodate(page));
+               DBG_BUGON(z_erofs_page_is_invalidated(page));
+
+               if (err)
+                       SetPageError(page);
+
+               if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
+                       if (!err)
+                               SetPageUptodate(page);
+                       unlock_page(page);
+               }
+       }
+       z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
+       bio_put(bio);
+}
+
 static void z_erofs_submit_queue(struct super_block *sb,
                                 struct z_erofs_decompress_frontend *f,
                                 struct page **pagepool,
index 18d7fd1..361b1d6 100644 (file)
@@ -630,6 +630,13 @@ static int z_erofs_do_map_blocks(struct inode *inode,
                if (endoff >= m.clusterofs) {
                        m.headtype = m.type;
                        map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+                       /*
+                        * For ztailpacking files, in order to inline data more
+                        * effectively, special EOF lclusters are now supported
+                        * which can have three parts at most.
+                        */
+                       if (ztailpacking && end > inode->i_size)
+                               end = inode->i_size;
                        break;
                }
                /* m.lcn should be >= 1 if endoff < m.clusterofs */
index 5a35768..57e82e2 100644 (file)
@@ -139,7 +139,7 @@ fail:
 /*
  * Inode operation get_posix_acl().
  *
- * inode->i_mutex: don't care
+ * inode->i_rwsem: don't care
  */
 struct posix_acl *
 ext4_get_acl(struct inode *inode, int type, bool rcu)
@@ -183,7 +183,7 @@ ext4_get_acl(struct inode *inode, int type, bool rcu)
 /*
  * Set the access or default ACL of an inode.
  *
- * inode->i_mutex: down unless called from ext4_new_inode
+ * inode->i_rwsem: down unless called from ext4_new_inode
  */
 static int
 __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
@@ -271,8 +271,8 @@ out_stop:
 /*
  * Initialize the ACLs of a new inode. Called from ext4_new_inode.
  *
- * dir->i_mutex: down
- * inode->i_mutex: up (access to inode is still exclusive)
+ * dir->i_rwsem: down
+ * inode->i_rwsem: up (access to inode is still exclusive)
  */
 int
 ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
index 71a3cdc..bcd3b9b 100644 (file)
@@ -1028,7 +1028,7 @@ struct ext4_inode_info {
 
        /*
         * Extended attributes can be read independently of the main file
-        * data. Taking i_mutex even when reading would cause contention
+        * data. Taking i_rwsem even when reading would cause contention
         * between readers of EAs and writers of regular file data, so
         * instead we synchronize on xattr_sem when reading or changing
         * EAs.
@@ -1750,6 +1750,7 @@ struct ext4_sb_info {
        spinlock_t s_fc_lock;
        struct buffer_head *s_fc_bh;
        struct ext4_fc_stats s_fc_stats;
+       tid_t s_fc_ineligible_tid;
 #ifdef CONFIG_EXT4_DEBUG
        int s_fc_debug_max_replay;
 #endif
@@ -1795,10 +1796,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 enum {
        EXT4_MF_MNTDIR_SAMPLED,
        EXT4_MF_FS_ABORTED,     /* Fatal error detected */
-       EXT4_MF_FC_INELIGIBLE,  /* Fast commit ineligible */
-       EXT4_MF_FC_COMMITTING   /* File system underoing a fast
-                                * commit.
-                                */
+       EXT4_MF_FC_INELIGIBLE   /* Fast commit ineligible */
 };
 
 static inline void ext4_set_mount_flag(struct super_block *sb, int bit)
@@ -2485,7 +2483,7 @@ struct ext4_filename {
 #ifdef CONFIG_FS_ENCRYPTION
        struct fscrypt_str crypto_buf;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct fscrypt_str cf_name;
 #endif
 };
@@ -2721,7 +2719,7 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
                                              struct ext4_group_desc *gdp);
 ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern int ext4_fname_setup_ci_filename(struct inode *dir,
                                         const struct qstr *iname,
                                         struct ext4_filename *fname);
@@ -2754,7 +2752,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
 
        ext4_fname_from_fscrypt_name(fname, &name);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, iname, fname);
 #endif
        return err;
@@ -2773,7 +2771,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
 
        ext4_fname_from_fscrypt_name(fname, &name);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
 #endif
        return err;
@@ -2790,7 +2788,7 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
        fname->usr_fname = NULL;
        fname->disk_name.name = NULL;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        kfree(fname->cf_name.name);
        fname->cf_name.name = NULL;
 #endif
@@ -2806,7 +2804,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
        fname->disk_name.name = (unsigned char *) iname->name;
        fname->disk_name.len = iname->len;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, iname, fname);
 #endif
 
@@ -2822,7 +2820,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
 
 static inline void ext4_fname_free_filename(struct ext4_filename *fname)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        kfree(fname->cf_name.name);
        fname->cf_name.name = NULL;
 #endif
@@ -2926,7 +2924,7 @@ void __ext4_fc_track_create(handle_t *handle, struct inode *inode,
                            struct dentry *dentry);
 void ext4_fc_track_create(handle_t *handle, struct dentry *dentry);
 void ext4_fc_track_inode(handle_t *handle, struct inode *inode);
-void ext4_fc_mark_ineligible(struct super_block *sb, int reason);
+void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handle);
 void ext4_fc_start_update(struct inode *inode);
 void ext4_fc_stop_update(struct inode *inode);
 void ext4_fc_del(struct inode *inode);
@@ -2935,6 +2933,9 @@ void ext4_fc_replay_cleanup(struct super_block *sb);
 int ext4_fc_commit(journal_t *journal, tid_t commit_tid);
 int __init ext4_fc_init_dentry_cache(void);
 void ext4_fc_destroy_dentry_cache(void);
+int ext4_fc_record_regions(struct super_block *sb, int ino,
+                          ext4_lblk_t lblk, ext4_fsblk_t pblk,
+                          int len, int replay);
 
 /* mballoc.c */
 extern const struct seq_operations ext4_mb_seq_groups_ops;
@@ -3407,7 +3408,7 @@ do {                                                              \
 #define EXT4_FREECLUSTERS_WATERMARK 0
 #endif
 
-/* Update i_disksize. Requires i_mutex to avoid races with truncate */
+/* Update i_disksize. Requires i_rwsem to avoid races with truncate */
 static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
 {
        WARN_ON_ONCE(S_ISREG(inode->i_mode) &&
@@ -3418,7 +3419,7 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
        up_write(&EXT4_I(inode)->i_data_sem);
 }
 
-/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
+/* Update i_size, i_disksize. Requires i_rwsem to avoid races with truncate */
 static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
 {
        int changed = 0;
index 0e4fa64..db2ae4a 100644 (file)
@@ -491,7 +491,7 @@ static inline int ext4_free_data_revoke_credits(struct inode *inode, int blocks)
 /*
  * This function controls whether or not we should try to go down the
  * dioread_nolock code paths, which makes it safe to avoid taking
- * i_mutex for direct I/O reads.  This only works for extent-based
+ * i_rwsem for direct I/O reads.  This only works for extent-based
  * files, and it doesn't work if data journaling is enabled, since the
  * dioread_nolock code uses b_private to pass information back to the
  * I/O completion handler, and this conflicts with the jbd's use of
index 74c91da..c0f3f83 100644 (file)
@@ -97,7 +97,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
         * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
-        * i_mutex. So we can safely drop the i_data_sem here.
+        * i_rwsem. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        ext4_discard_preallocations(inode, 0);
@@ -4572,7 +4572,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
 
        flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        /* Preallocate the range including the unaligned edges */
@@ -4738,7 +4738,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
                        goto out;
        }
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);
@@ -5334,7 +5334,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
                ret = PTR_ERR(handle);
                goto out_mmap;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
 
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode, 0);
@@ -5474,7 +5474,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                ret = PTR_ERR(handle);
                goto out_mmap;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
 
        /* Expand file to avoid data loss if there is error while shifting */
        inode->i_size += len;
@@ -5571,7 +5571,7 @@ out_mutex:
  * stuff such as page-cache locking consistency, bh mapping consistency or
  * extent's data copying must be performed by caller.
  * Locking:
- *             i_mutex is held for both inodes
+ *             i_rwsem is held for both inodes
  *             i_data_sem is locked for write for both inodes
  * Assumptions:
  *             All pages from requested range are locked for both inodes
@@ -6091,11 +6091,15 @@ int ext4_ext_clear_bb(struct inode *inode)
 
                                        ext4_mb_mark_bb(inode->i_sb,
                                                        path[j].p_block, 1, 0);
+                                       ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+                                                       0, path[j].p_block, 1, 1);
                                }
                                ext4_ext_drop_refs(path);
                                kfree(path);
                        }
                        ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, 0);
+                       ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+                                       map.m_lblk, map.m_pblk, map.m_len, 1);
                }
                cur = cur + map.m_len;
        }
index 5ae8026..7964ee3 100644 (file)
@@ -300,18 +300,32 @@ restart:
 }
 
 /*
- * Mark file system as fast commit ineligible. This means that next commit
- * operation would result in a full jbd2 commit.
+ * Mark file system as fast commit ineligible, and record latest
+ * ineligible transaction tid. This means until the recorded
+ * transaction, commit operation would result in a full jbd2 commit.
  */
-void ext4_fc_mark_ineligible(struct super_block *sb, int reason)
+void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handle)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
+       tid_t tid;
 
        if (!test_opt2(sb, JOURNAL_FAST_COMMIT) ||
            (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
                return;
 
        ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       if (handle && !IS_ERR(handle))
+               tid = handle->h_transaction->t_tid;
+       else {
+               read_lock(&sbi->s_journal->j_state_lock);
+               tid = sbi->s_journal->j_running_transaction ?
+                               sbi->s_journal->j_running_transaction->t_tid : 0;
+               read_unlock(&sbi->s_journal->j_state_lock);
+       }
+       spin_lock(&sbi->s_fc_lock);
+       if (sbi->s_fc_ineligible_tid < tid)
+               sbi->s_fc_ineligible_tid = tid;
+       spin_unlock(&sbi->s_fc_lock);
        WARN_ON(reason >= EXT4_FC_REASON_MAX);
        sbi->s_fc_stats.fc_ineligible_reason_count[reason]++;
 }
@@ -361,7 +375,8 @@ static int ext4_fc_track_template(
        spin_lock(&sbi->s_fc_lock);
        if (list_empty(&EXT4_I(inode)->i_fc_list))
                list_add_tail(&EXT4_I(inode)->i_fc_list,
-                               (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING)) ?
+                               (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING ||
+                                sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) ?
                                &sbi->s_fc_q[FC_Q_STAGING] :
                                &sbi->s_fc_q[FC_Q_MAIN]);
        spin_unlock(&sbi->s_fc_lock);
@@ -387,7 +402,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
        mutex_unlock(&ei->i_fc_lock);
        node = kmem_cache_alloc(ext4_fc_dentry_cachep, GFP_NOFS);
        if (!node) {
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
                mutex_lock(&ei->i_fc_lock);
                return -ENOMEM;
        }
@@ -400,7 +415,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
                if (!node->fcd_name.name) {
                        kmem_cache_free(ext4_fc_dentry_cachep, node);
                        ext4_fc_mark_ineligible(inode->i_sb,
-                               EXT4_FC_REASON_NOMEM);
+                               EXT4_FC_REASON_NOMEM, NULL);
                        mutex_lock(&ei->i_fc_lock);
                        return -ENOMEM;
                }
@@ -414,7 +429,8 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
        node->fcd_name.len = dentry->d_name.len;
 
        spin_lock(&sbi->s_fc_lock);
-       if (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING))
+       if (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING ||
+               sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING)
                list_add_tail(&node->fcd_list,
                                &sbi->s_fc_dentry_q[FC_Q_STAGING]);
        else
@@ -502,7 +518,7 @@ void ext4_fc_track_inode(handle_t *handle, struct inode *inode)
 
        if (ext4_should_journal_data(inode)) {
                ext4_fc_mark_ineligible(inode->i_sb,
-                                       EXT4_FC_REASON_INODE_JOURNAL_DATA);
+                                       EXT4_FC_REASON_INODE_JOURNAL_DATA, handle);
                return;
        }
 
@@ -879,7 +895,6 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
        int ret = 0;
 
        spin_lock(&sbi->s_fc_lock);
-       ext4_set_mount_flag(sb, EXT4_MF_FC_COMMITTING);
        list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {
                ext4_set_inode_state(&ei->vfs_inode, EXT4_STATE_FC_COMMITTING);
                while (atomic_read(&ei->i_fc_updates)) {
@@ -1179,7 +1194,7 @@ fallback:
  * Fast commit cleanup routine. This is called after every fast commit and
  * full commit. full is true if we are called after a full commit.
  */
-static void ext4_fc_cleanup(journal_t *journal, int full)
+static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid)
 {
        struct super_block *sb = journal->j_private;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -1197,7 +1212,8 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
                list_del_init(&iter->i_fc_list);
                ext4_clear_inode_state(&iter->vfs_inode,
                                       EXT4_STATE_FC_COMMITTING);
-               ext4_fc_reset_inode(&iter->vfs_inode);
+               if (iter->i_sync_tid <= tid)
+                       ext4_fc_reset_inode(&iter->vfs_inode);
                /* Make sure EXT4_STATE_FC_COMMITTING bit is clear */
                smp_mb();
 #if (BITS_PER_LONG < 64)
@@ -1226,8 +1242,10 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
        list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
                                &sbi->s_fc_q[FC_Q_MAIN]);
 
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       if (tid >= sbi->s_fc_ineligible_tid) {
+               sbi->s_fc_ineligible_tid = 0;
+               ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       }
 
        if (full)
                sbi->s_fc_bytes = 0;
@@ -1392,14 +1410,15 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino)
                if (state->fc_modified_inodes[i] == ino)
                        return 0;
        if (state->fc_modified_inodes_used == state->fc_modified_inodes_size) {
-               state->fc_modified_inodes_size +=
-                       EXT4_FC_REPLAY_REALLOC_INCREMENT;
                state->fc_modified_inodes = krealloc(
-                                       state->fc_modified_inodes, sizeof(int) *
-                                       state->fc_modified_inodes_size,
-                                       GFP_KERNEL);
+                               state->fc_modified_inodes,
+                               sizeof(int) * (state->fc_modified_inodes_size +
+                               EXT4_FC_REPLAY_REALLOC_INCREMENT),
+                               GFP_KERNEL);
                if (!state->fc_modified_inodes)
                        return -ENOMEM;
+               state->fc_modified_inodes_size +=
+                       EXT4_FC_REPLAY_REALLOC_INCREMENT;
        }
        state->fc_modified_inodes[state->fc_modified_inodes_used++] = ino;
        return 0;
@@ -1431,7 +1450,9 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
        }
        inode = NULL;
 
-       ext4_fc_record_modified_inode(sb, ino);
+       ret = ext4_fc_record_modified_inode(sb, ino);
+       if (ret)
+               goto out;
 
        raw_fc_inode = (struct ext4_inode *)
                (val + offsetof(struct ext4_fc_inode, fc_raw_inode));
@@ -1563,16 +1584,23 @@ out:
 }
 
 /*
- * Record physical disk regions which are in use as per fast commit area. Our
- * simple replay phase allocator excludes these regions from allocation.
+ * Record physical disk regions which are in use as per fast commit area,
+ * and used by inodes during replay phase. Our simple replay phase
+ * allocator excludes these regions from allocation.
  */
-static int ext4_fc_record_regions(struct super_block *sb, int ino,
-               ext4_lblk_t lblk, ext4_fsblk_t pblk, int len)
+int ext4_fc_record_regions(struct super_block *sb, int ino,
+               ext4_lblk_t lblk, ext4_fsblk_t pblk, int len, int replay)
 {
        struct ext4_fc_replay_state *state;
        struct ext4_fc_alloc_region *region;
 
        state = &EXT4_SB(sb)->s_fc_replay_state;
+       /*
+        * during replay phase, the fc_regions_valid may not same as
+        * fc_regions_used, update it when do new additions.
+        */
+       if (replay && state->fc_regions_used != state->fc_regions_valid)
+               state->fc_regions_used = state->fc_regions_valid;
        if (state->fc_regions_used == state->fc_regions_size) {
                state->fc_regions_size +=
                        EXT4_FC_REPLAY_REALLOC_INCREMENT;
@@ -1590,6 +1618,9 @@ static int ext4_fc_record_regions(struct super_block *sb, int ino,
        region->pblk = pblk;
        region->len = len;
 
+       if (replay)
+               state->fc_regions_valid++;
+
        return 0;
 }
 
@@ -1621,6 +1652,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
        }
 
        ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
+       if (ret)
+               goto out;
 
        start = le32_to_cpu(ex->ee_block);
        start_pblk = ext4_ext_pblock(ex);
@@ -1638,18 +1671,14 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                map.m_pblk = 0;
                ret = ext4_map_blocks(NULL, inode, &map, 0);
 
-               if (ret < 0) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret < 0)
+                       goto out;
 
                if (ret == 0) {
                        /* Range is not mapped */
                        path = ext4_find_extent(inode, cur, NULL, 0);
-                       if (IS_ERR(path)) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (IS_ERR(path))
+                               goto out;
                        memset(&newex, 0, sizeof(newex));
                        newex.ee_block = cpu_to_le32(cur);
                        ext4_ext_store_pblock(
@@ -1663,10 +1692,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        up_write((&EXT4_I(inode)->i_data_sem));
                        ext4_ext_drop_refs(path);
                        kfree(path);
-                       if (ret) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (ret)
+                               goto out;
                        goto next;
                }
 
@@ -1679,10 +1706,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
                                        ext4_ext_is_unwritten(ex),
                                        start_pblk + cur - start);
-                       if (ret) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (ret)
+                               goto out;
                        /*
                         * Mark the old blocks as free since they aren't used
                         * anymore. We maintain an array of all the modified
@@ -1702,10 +1727,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        ext4_ext_is_unwritten(ex), map.m_pblk);
                ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
                                        ext4_ext_is_unwritten(ex), map.m_pblk);
-               if (ret) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret)
+                       goto out;
                /*
                 * We may have split the extent tree while toggling the state.
                 * Try to shrink the extent tree now.
@@ -1717,6 +1740,7 @@ next:
        }
        ext4_ext_replay_shrink_inode(inode, i_size_read(inode) >>
                                        sb->s_blocksize_bits);
+out:
        iput(inode);
        return 0;
 }
@@ -1746,6 +1770,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
        }
 
        ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
+       if (ret)
+               goto out;
 
        jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
                        inode->i_ino, le32_to_cpu(lrange.fc_lblk),
@@ -1755,10 +1781,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
                map.m_len = remaining;
 
                ret = ext4_map_blocks(NULL, inode, &map, 0);
-               if (ret < 0) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret < 0)
+                       goto out;
                if (ret > 0) {
                        remaining -= ret;
                        cur += ret;
@@ -1770,18 +1794,17 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
        }
 
        down_write(&EXT4_I(inode)->i_data_sem);
-       ret = ext4_ext_remove_space(inode, lrange.fc_lblk,
-                               lrange.fc_lblk + lrange.fc_len - 1);
+       ret = ext4_ext_remove_space(inode, le32_to_cpu(lrange.fc_lblk),
+                               le32_to_cpu(lrange.fc_lblk) +
+                               le32_to_cpu(lrange.fc_len) - 1);
        up_write(&EXT4_I(inode)->i_data_sem);
-       if (ret) {
-               iput(inode);
-               return 0;
-       }
+       if (ret)
+               goto out;
        ext4_ext_replay_shrink_inode(inode,
                i_size_read(inode) >> sb->s_blocksize_bits);
        ext4_mark_inode_dirty(NULL, inode);
+out:
        iput(inode);
-
        return 0;
 }
 
@@ -1937,7 +1960,7 @@ static int ext4_fc_replay_scan(journal_t *journal,
                        ret = ext4_fc_record_regions(sb,
                                le32_to_cpu(ext.fc_ino),
                                le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex),
-                               ext4_ext_get_actual_len(ex));
+                               ext4_ext_get_actual_len(ex), 0);
                        if (ret < 0)
                                break;
                        ret = JBD2_FC_REPLAY_CONTINUE;
index f34f417..147b524 100644 (file)
@@ -290,7 +290,7 @@ static int __ext4fs_dirhash(const struct inode *dir, const char *name, int len,
 int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
                   struct dx_hash_info *hinfo)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        const struct unicode_map *um = dir->i_sb->s_encoding;
        int r, dlen;
        unsigned char *buff;
index 89efa78..07a8c75 100644 (file)
@@ -696,7 +696,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
         * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
-        * i_mutex. So we can safely drop the i_data_sem here.
+        * i_rwsem. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        ext4_discard_preallocations(inode, 0);
index 635bcf6..e429418 100644 (file)
@@ -911,7 +911,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
                                    struct page **pagep,
                                    void **fsdata)
 {
-       int ret, inline_size;
+       int ret;
        handle_t *handle;
        struct page *page;
        struct ext4_iloc iloc;
@@ -928,14 +928,9 @@ retry_journal:
                goto out;
        }
 
-       inline_size = ext4_get_max_inline_size(inode);
-
-       ret = -ENOSPC;
-       if (inline_size >= pos + len) {
-               ret = ext4_prepare_inline_data(handle, inode, pos + len);
-               if (ret && ret != -ENOSPC)
-                       goto out_journal;
-       }
+       ret = ext4_prepare_inline_data(handle, inode, pos + len);
+       if (ret && ret != -ENOSPC)
+               goto out_journal;
 
        /*
         * We cannot recurse into the filesystem as the transaction
@@ -1133,7 +1128,15 @@ static void ext4_restore_inline_data(handle_t *handle, struct inode *inode,
                                     struct ext4_iloc *iloc,
                                     void *buf, int inline_size)
 {
-       ext4_create_inline_data(handle, inode, inline_size);
+       int ret;
+
+       ret = ext4_create_inline_data(handle, inode, inline_size);
+       if (ret) {
+               ext4_msg(inode->i_sb, KERN_EMERG,
+                       "error restoring inline_data for inode -- potential data loss! (inode %lu, error %d)",
+                       inode->i_ino, ret);
+               return;
+       }
        ext4_write_inline_data(inode, iloc, buf, 0, inline_size);
        ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
 }
index 5f79d26..01c9e4f 100644 (file)
@@ -338,7 +338,7 @@ stop_handle:
        return;
 no_delete:
        if (!list_empty(&EXT4_I(inode)->i_fc_list))
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
 }
 
@@ -1224,7 +1224,7 @@ retry_journal:
                /*
                 * __block_write_begin may have instantiated a few blocks
                 * outside i_size.  Trim these off again. Don't need
-                * i_size_read because we hold i_mutex.
+                * i_size_read because we hold i_rwsem.
                 *
                 * Add inode to orphan list in case we crash before
                 * truncate finishes
@@ -3979,7 +3979,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 
        }
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        /*
@@ -4129,7 +4129,7 @@ int ext4_truncate(struct inode *inode)
        /*
         * There is a possibility that we're either freeing the inode
         * or it's a completely new inode. In those cases we might not
-        * have i_mutex locked because it's not necessary.
+        * have i_rwsem locked because it's not necessary.
         */
        if (!(inode->i_state & (I_NEW|I_FREEING)))
                WARN_ON(!inode_is_locked(inode));
@@ -5271,7 +5271,7 @@ static void ext4_wait_for_tail_page_commit(struct inode *inode)
  * transaction are already on disk (truncate waits for pages under
  * writeback).
  *
- * Called with inode->i_mutex down.
+ * Called with inode->i_rwsem down.
  */
 int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                 struct iattr *attr)
@@ -5983,7 +5983,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
                return PTR_ERR(handle);
 
        ext4_fc_mark_ineligible(inode->i_sb,
-               EXT4_FC_REASON_JOURNAL_FLAG_CHANGE);
+               EXT4_FC_REASON_JOURNAL_FLAG_CHANGE, handle);
        err = ext4_mark_inode_dirty(handle, inode);
        ext4_handle_sync(handle);
        ext4_journal_stop(handle);
index bbbedf2..a8022c2 100644 (file)
@@ -411,7 +411,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
                err = -EINVAL;
                goto err_out;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT, handle);
 
        /* Protect extent tree against block allocations via delalloc */
        ext4_double_down_write_data_sem(inode, inode_bl);
@@ -1373,7 +1373,7 @@ mext_out:
 
                err = ext4_resize_fs(sb, n_blocks_count);
                if (EXT4_SB(sb)->s_journal) {
-                       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE);
+                       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE, NULL);
                        jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
                        err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal, 0);
                        jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
index 9f86dd9..67ac95c 100644 (file)
@@ -5753,7 +5753,8 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
        struct super_block *sb = ar->inode->i_sb;
        ext4_group_t group;
        ext4_grpblk_t blkoff;
-       int i = sb->s_blocksize;
+       ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb);
+       ext4_grpblk_t i = 0;
        ext4_fsblk_t goal, block;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 
@@ -5775,19 +5776,26 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
                ext4_get_group_no_and_offset(sb,
                        max(ext4_group_first_block_no(sb, group), goal),
                        NULL, &blkoff);
-               i = mb_find_next_zero_bit(bitmap_bh->b_data, sb->s_blocksize,
+               while (1) {
+                       i = mb_find_next_zero_bit(bitmap_bh->b_data, max,
                                                blkoff);
+                       if (i >= max)
+                               break;
+                       if (ext4_fc_replay_check_excluded(sb,
+                               ext4_group_first_block_no(sb, group) + i)) {
+                               blkoff = i + 1;
+                       } else
+                               break;
+               }
                brelse(bitmap_bh);
-               if (i >= sb->s_blocksize)
-                       continue;
-               if (ext4_fc_replay_check_excluded(sb,
-                       ext4_group_first_block_no(sb, group) + i))
-                       continue;
-               break;
+               if (i < max)
+                       break;
        }
 
-       if (group >= ext4_get_groups_count(sb) && i >= sb->s_blocksize)
+       if (group >= ext4_get_groups_count(sb) || i >= max) {
+               *errp = -ENOSPC;
                return 0;
+       }
 
        block = ext4_group_first_block_no(sb, group) + i;
        ext4_mb_mark_bb(sb, block, 1, 1);
index ff8916e..7a5353a 100644 (file)
@@ -485,7 +485,7 @@ int ext4_ext_migrate(struct inode *inode)
         * when we add extents we extent the journal
         */
        /*
-        * Even though we take i_mutex we can still cause block
+        * Even though we take i_rwsem we can still cause block
         * allocation via mmap write to holes. If we have allocated
         * new blocks we fail migrate.  New block allocation will
         * clear EXT4_STATE_EXT_MIGRATE flag.  The flag is updated
index 52c9bd1..8cf0a92 100644 (file)
@@ -1317,7 +1317,7 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
        dx_set_count(entries, count + 1);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.  If quick is set, assume the name being looked up
@@ -1428,7 +1428,7 @@ static bool ext4_match(struct inode *parent,
        f.crypto_buf = fname->crypto_buf;
 #endif
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
            (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
                if (fname->cf_name.name) {
@@ -1800,7 +1800,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                }
        }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (!inode && IS_CASEFOLDED(dir)) {
                /* Eventually we want to call d_add_ci(dentry, NULL)
                 * for negative dentries in the encoding case as
@@ -2308,7 +2308,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        if (fscrypt_is_nokey_name(dentry))
                return -ENOKEY;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
            sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
                return -EINVAL;
@@ -3126,7 +3126,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
        ext4_fc_track_unlink(handle, dentry);
        retval = ext4_mark_inode_dirty(handle, dir);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
@@ -3231,7 +3231,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
        retval = __ext4_unlink(handle, dir, &dentry->d_name, d_inode(dentry));
        if (!retval)
                ext4_fc_track_unlink(handle, dentry);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
@@ -3889,7 +3889,7 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                 * dirents in directories.
                 */
                ext4_fc_mark_ineligible(old.inode->i_sb,
-                       EXT4_FC_REASON_RENAME_DIR);
+                       EXT4_FC_REASON_RENAME_DIR, handle);
        } else {
                if (new.inode)
                        ext4_fc_track_unlink(handle, new.dentry);
@@ -4049,7 +4049,7 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlikely(retval))
                goto end_rename;
        ext4_fc_mark_ineligible(new.inode->i_sb,
-                               EXT4_FC_REASON_CROSS_RENAME);
+                               EXT4_FC_REASON_CROSS_RENAME, handle);
        if (old.dir_bh) {
                retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
                if (retval)
index 53adc8f..7de0612 100644 (file)
@@ -93,7 +93,7 @@ static int ext4_orphan_file_add(handle_t *handle, struct inode *inode)
  * At filesystem recovery time, we walk this list deleting unlinked
  * inodes and truncating linked inodes in ext4_orphan_cleanup().
  *
- * Orphan list manipulation functions must be called under i_mutex unless
+ * Orphan list manipulation functions must be called under i_rwsem unless
  * we are just creating the inode or deleting it.
  */
 int ext4_orphan_add(handle_t *handle, struct inode *inode)
@@ -119,7 +119,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        /*
         * Orphan handling is only valid for files with data blocks
         * being truncated, or files being unlinked. Note that we either
-        * hold i_mutex, or the inode can not be referenced from outside,
+        * hold i_rwsem, or the inode can not be referenced from outside,
         * so i_nlink should not be bumped due to race
         */
        ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
index eee0d9e..c5021ca 100644 (file)
@@ -1301,7 +1301,7 @@ static void ext4_put_super(struct super_block *sb)
        kfree(sbi->s_blockgroup_lock);
        fs_put_dax(sbi->s_daxdev);
        fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
@@ -1961,7 +1961,7 @@ static const struct mount_opts {
        {Opt_err, 0, 0}
 };
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 static const struct ext4_sb_encodings {
        __u16 magic;
        char *name;
@@ -3606,7 +3606,7 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly)
                return 0;
        }
 
-#ifndef CONFIG_UNICODE
+#if !IS_ENABLED(CONFIG_UNICODE)
        if (ext4_has_feature_casefold(sb)) {
                ext4_msg(sb, KERN_ERR,
                         "Filesystem with casefold feature cannot be "
@@ -4610,7 +4610,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
        if (err < 0)
                goto failed_mount;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (ext4_has_feature_casefold(sb) && !sb->s_encoding) {
                const struct ext4_sb_encodings *encoding_info;
                struct unicode_map *encoding;
@@ -5082,7 +5082,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
        INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]);
        sbi->s_fc_bytes = 0;
        ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
+       sbi->s_fc_ineligible_tid = 0;
        spin_lock_init(&sbi->s_fc_lock);
        memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats));
        sbi->s_fc_replay_state.fc_regions = NULL;
@@ -5514,7 +5514,7 @@ failed_mount:
        if (sbi->s_chksum_driver)
                crypto_free_shash(sbi->s_chksum_driver);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
 
@@ -5540,7 +5540,7 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
 
        sbi = ext4_alloc_sbi(sb);
        if (!sbi)
-               ret = -ENOMEM;
+               return -ENOMEM;
 
        fc->s_fs_info = sbi;
 
index f61e65a..d233c24 100644 (file)
@@ -309,7 +309,7 @@ EXT4_ATTR_FEATURE(meta_bg_resize);
 EXT4_ATTR_FEATURE(encryption);
 EXT4_ATTR_FEATURE(test_dummy_encryption_v2);
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 EXT4_ATTR_FEATURE(casefold);
 #endif
 #ifdef CONFIG_FS_VERITY
@@ -317,7 +317,7 @@ EXT4_ATTR_FEATURE(verity);
 #endif
 EXT4_ATTR_FEATURE(metadata_csum_seed);
 EXT4_ATTR_FEATURE(fast_commit);
-#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
 EXT4_ATTR_FEATURE(encrypted_casefold);
 #endif
 
@@ -329,7 +329,7 @@ static struct attribute *ext4_feat_attrs[] = {
        ATTR_LIST(encryption),
        ATTR_LIST(test_dummy_encryption_v2),
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(casefold),
 #endif
 #ifdef CONFIG_FS_VERITY
@@ -337,7 +337,7 @@ static struct attribute *ext4_feat_attrs[] = {
 #endif
        ATTR_LIST(metadata_csum_seed),
        ATTR_LIST(fast_commit),
-#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
        ATTR_LIST(encrypted_casefold),
 #endif
        NULL,
index 1e0fc1e..0423253 100644 (file)
@@ -2408,7 +2408,7 @@ retry_inode:
                if (IS_SYNC(inode))
                        ext4_handle_sync(handle);
        }
-       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle);
 
 cleanup:
        brelse(is.iloc.bh);
@@ -2486,7 +2486,7 @@ retry:
                if (error == 0)
                        error = error2;
        }
-       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, NULL);
 
        return error;
 }
@@ -2920,7 +2920,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
                                         error);
                        goto cleanup;
                }
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle);
        }
        error = 0;
 cleanup:
index 1820e9c..166f086 100644 (file)
@@ -16,7 +16,7 @@
 #include "xattr.h"
 #include <trace/events/f2fs.h>
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern struct kmem_cache *f2fs_cf_name_slab;
 #endif
 
@@ -79,7 +79,7 @@ unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de)
 int f2fs_init_casefolded_name(const struct inode *dir,
                              struct f2fs_filename *fname)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct super_block *sb = dir->i_sb;
 
        if (IS_CASEFOLDED(dir)) {
@@ -174,7 +174,7 @@ void f2fs_free_filename(struct f2fs_filename *fname)
        kfree(fname->crypto_buf.name);
        fname->crypto_buf.name = NULL;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (fname->cf_name.name) {
                kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
                fname->cf_name.name = NULL;
@@ -208,7 +208,7 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
        return f2fs_find_target_dentry(&d, fname, max_slots);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.
@@ -266,7 +266,7 @@ static inline int f2fs_match_name(const struct inode *dir,
 {
        struct fscrypt_name f;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (fname->cf_name.name) {
                struct qstr cf = FSTR_TO_QSTR(&fname->cf_name);
 
index eb22fa9..68b4401 100644 (file)
@@ -488,7 +488,7 @@ struct f2fs_filename {
         */
        struct fscrypt_str crypto_buf;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /*
         * For casefolded directories: the casefolded name, but it's left NULL
         * if the original name is not valid Unicode, if the directory is both
index e3beac5..3cb1e7a 100644 (file)
@@ -105,7 +105,7 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
                return;
        }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (IS_CASEFOLDED(dir)) {
                /*
                 * If the casefolded name is provided, hash it instead of the
index a728a0a..5f213f0 100644 (file)
@@ -561,7 +561,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
                goto out_iput;
        }
 out_splice:
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (!inode && IS_CASEFOLDED(dir)) {
                /* Eventually we want to call d_add_ci(dentry, NULL)
                 * for negative dentries in the encoding case as
@@ -622,7 +622,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
                goto fail;
        }
        f2fs_delete_entry(de, page, dir, inode);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
index 9683c80..79773d3 100644 (file)
@@ -46,7 +46,7 @@
 
 static struct kmem_cache *fsync_entry_slab;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern struct kmem_cache *f2fs_cf_name_slab;
 #endif
 
@@ -149,7 +149,7 @@ static int init_recovered_filename(const struct inode *dir,
                if (err)
                        return err;
                f2fs_hash_filename(dir, fname);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
                /* Case-sensitive match is fine for recovery */
                kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
                fname->cf_name.name = NULL;
index 76e6a3d..baefd39 100644 (file)
@@ -257,7 +257,7 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
        va_end(args);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 static const struct f2fs_sb_encodings {
        __u16 magic;
        char *name;
@@ -1259,7 +1259,7 @@ default_check:
                return -EINVAL;
        }
 #endif
-#ifndef CONFIG_UNICODE
+#if !IS_ENABLED(CONFIG_UNICODE)
        if (f2fs_sb_has_casefold(sbi)) {
                f2fs_err(sbi,
                        "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
@@ -1619,7 +1619,7 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_destroy_iostat(sbi);
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
@@ -3903,7 +3903,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 
 static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) {
                const struct f2fs_sb_encodings *encoding_info;
                struct unicode_map *encoding;
@@ -4458,7 +4458,7 @@ free_bio_info:
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
        sb->s_encoding = NULL;
 #endif
index df406c1..8ac5066 100644 (file)
@@ -201,7 +201,7 @@ static ssize_t unusable_show(struct f2fs_attr *a,
 static ssize_t encoding_show(struct f2fs_attr *a,
                struct f2fs_sb_info *sbi, char *buf)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct super_block *sb = sbi->sb;
 
        if (f2fs_sb_has_casefold(sbi))
@@ -778,7 +778,7 @@ F2FS_GENERAL_RO_ATTR(avg_vblocks);
 #ifdef CONFIG_FS_ENCRYPTION
 F2FS_FEATURE_RO_ATTR(encryption);
 F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 F2FS_FEATURE_RO_ATTR(encrypted_casefold);
 #endif
 #endif /* CONFIG_FS_ENCRYPTION */
@@ -797,7 +797,7 @@ F2FS_FEATURE_RO_ATTR(lost_found);
 F2FS_FEATURE_RO_ATTR(verity);
 #endif
 F2FS_FEATURE_RO_ATTR(sb_checksum);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 F2FS_FEATURE_RO_ATTR(casefold);
 #endif
 F2FS_FEATURE_RO_ATTR(readonly);
@@ -910,7 +910,7 @@ static struct attribute *f2fs_feat_attrs[] = {
 #ifdef CONFIG_FS_ENCRYPTION
        ATTR_LIST(encryption),
        ATTR_LIST(test_dummy_encryption_v2),
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(encrypted_casefold),
 #endif
 #endif /* CONFIG_FS_ENCRYPTION */
@@ -929,7 +929,7 @@ static struct attribute *f2fs_feat_attrs[] = {
        ATTR_LIST(verity),
 #endif
        ATTR_LIST(sb_checksum),
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(casefold),
 #endif
        ATTR_LIST(readonly),
index c938bba..6c51a75 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "../internal.h"
 
+#define IOEND_BATCH_SIZE       4096
+
 /*
  * Structure allocated for each folio when block size < folio size
  * to track sub-folio uptodate status and I/O completions.
@@ -1039,7 +1041,7 @@ static void iomap_finish_folio_write(struct inode *inode, struct folio *folio,
  * state, release holds on bios, and finally free up memory.  Do not use the
  * ioend after this.
  */
-static void
+static u32
 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 {
        struct inode *inode = ioend->io_inode;
@@ -1048,6 +1050,7 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
        u64 start = bio->bi_iter.bi_sector;
        loff_t offset = ioend->io_offset;
        bool quiet = bio_flagged(bio, BIO_QUIET);
+       u32 folio_count = 0;
 
        for (bio = &ioend->io_inline_bio; bio; bio = next) {
                struct folio_iter fi;
@@ -1062,9 +1065,11 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
                        next = bio->bi_private;
 
                /* walk all folios in bio, ending page IO on them */
-               bio_for_each_folio_all(fi, bio)
+               bio_for_each_folio_all(fi, bio) {
                        iomap_finish_folio_write(inode, fi.folio, fi.length,
                                        error);
+                       folio_count++;
+               }
                bio_put(bio);
        }
        /* The ioend has been freed by bio_put() */
@@ -1074,20 +1079,36 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 "%s: writeback error on inode %lu, offset %lld, sector %llu",
                        inode->i_sb->s_id, inode->i_ino, offset, start);
        }
+       return folio_count;
 }
 
+/*
+ * Ioend completion routine for merged bios. This can only be called from task
+ * contexts as merged ioends can be of unbound length. Hence we have to break up
+ * the writeback completions into manageable chunks to avoid long scheduler
+ * holdoffs. We aim to keep scheduler holdoffs down below 10ms so that we get
+ * good batch processing throughput without creating adverse scheduler latency
+ * conditions.
+ */
 void
 iomap_finish_ioends(struct iomap_ioend *ioend, int error)
 {
        struct list_head tmp;
+       u32 completions;
+
+       might_sleep();
 
        list_replace_init(&ioend->io_list, &tmp);
-       iomap_finish_ioend(ioend, error);
+       completions = iomap_finish_ioend(ioend, error);
 
        while (!list_empty(&tmp)) {
+               if (completions > IOEND_BATCH_SIZE * 8) {
+                       cond_resched();
+                       completions = 0;
+               }
                ioend = list_first_entry(&tmp, struct iomap_ioend, io_list);
                list_del_init(&ioend->io_list);
-               iomap_finish_ioend(ioend, error);
+               completions += iomap_finish_ioend(ioend, error);
        }
 }
 EXPORT_SYMBOL_GPL(iomap_finish_ioends);
@@ -1108,6 +1129,18 @@ iomap_ioend_can_merge(struct iomap_ioend *ioend, struct iomap_ioend *next)
                return false;
        if (ioend->io_offset + ioend->io_size != next->io_offset)
                return false;
+       /*
+        * Do not merge physically discontiguous ioends. The filesystem
+        * completion functions will have to iterate the physical
+        * discontiguities even if we merge the ioends at a logical level, so
+        * we don't gain anything by merging physical discontiguities here.
+        *
+        * We cannot use bio->bi_iter.bi_sector here as it is modified during
+        * submission so does not point to the start sector of the bio at
+        * completion.
+        */
+       if (ioend->io_sector + (ioend->io_size >> 9) != next->io_sector)
+               return false;
        return true;
 }
 
@@ -1209,8 +1242,10 @@ iomap_alloc_ioend(struct inode *inode, struct iomap_writepage_ctx *wpc,
        ioend->io_flags = wpc->iomap.flags;
        ioend->io_inode = inode;
        ioend->io_size = 0;
+       ioend->io_folios = 0;
        ioend->io_offset = offset;
        ioend->io_bio = bio;
+       ioend->io_sector = sector;
        return ioend;
 }
 
@@ -1251,6 +1286,13 @@ iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t offset,
                return false;
        if (sector != bio_end_sector(wpc->ioend->io_bio))
                return false;
+       /*
+        * Limit ioend bio chain lengths to minimise IO completion latency. This
+        * also prevents long tight loops ending page writeback on all the
+        * folios in the ioend.
+        */
+       if (wpc->ioend->io_folios >= IOEND_BATCH_SIZE)
+               return false;
        return true;
 }
 
@@ -1335,6 +1377,8 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
                                 &submit_list);
                count++;
        }
+       if (count)
+               wpc->ioend->io_folios++;
 
        WARN_ON_ONCE(!wpc->ioend && !list_empty(&submit_list));
        WARN_ON_ONCE(!folio_test_locked(folio));
index 3cc4ab2..5b9408e 100644 (file)
@@ -484,22 +484,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        stats.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
                                              stats.run.rs_locked);
 
-       spin_lock(&commit_transaction->t_handle_lock);
-       while (atomic_read(&commit_transaction->t_updates)) {
-               DEFINE_WAIT(wait);
+       // waits for any t_updates to finish
+       jbd2_journal_wait_updates(journal);
 
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-               if (atomic_read(&commit_transaction->t_updates)) {
-                       spin_unlock(&commit_transaction->t_handle_lock);
-                       write_unlock(&journal->j_state_lock);
-                       schedule();
-                       write_lock(&journal->j_state_lock);
-                       spin_lock(&commit_transaction->t_handle_lock);
-               }
-               finish_wait(&journal->j_wait_updates, &wait);
-       }
-       spin_unlock(&commit_transaction->t_handle_lock);
        commit_transaction->t_state = T_SWITCH;
        write_unlock(&journal->j_state_lock);
 
@@ -817,7 +804,7 @@ start_journal_io:
        commit_transaction->t_state = T_COMMIT_DFLUSH;
        write_unlock(&journal->j_state_lock);
 
-       /* 
+       /*
         * If the journal is not located on the file system device,
         * then we must flush the file system device before we issue
         * the commit record
@@ -1170,7 +1157,7 @@ restart_loop:
        if (journal->j_commit_callback)
                journal->j_commit_callback(journal, commit_transaction);
        if (journal->j_fc_cleanup_callback)
-               journal->j_fc_cleanup_callback(journal, 1);
+               journal->j_fc_cleanup_callback(journal, 1, commit_transaction->t_tid);
 
        trace_jbd2_end_commit(journal, commit_transaction);
        jbd_debug(1, "JBD2: commit %d complete, head %d\n",
index bf108d4..c2cf74b 100644 (file)
@@ -771,7 +771,7 @@ static int __jbd2_fc_end_commit(journal_t *journal, tid_t tid, bool fallback)
 {
        jbd2_journal_unlock_updates(journal);
        if (journal->j_fc_cleanup_callback)
-               journal->j_fc_cleanup_callback(journal, 0);
+               journal->j_fc_cleanup_callback(journal, 0, tid);
        write_lock(&journal->j_state_lock);
        journal->j_flags &= ~JBD2_FAST_COMMIT_ONGOING;
        if (fallback)
@@ -1287,6 +1287,8 @@ static int jbd2_min_tag_size(void)
 
 /**
  * jbd2_journal_shrink_scan()
+ * @shrink: shrinker to work on
+ * @sc: reclaim request to process
  *
  * Scan the checkpointed buffer on the checkpoint list and release the
  * journal_head.
@@ -1312,6 +1314,8 @@ static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink,
 
 /**
  * jbd2_journal_shrink_count()
+ * @shrink: shrinker to work on
+ * @sc: reclaim request to process
  *
  * Count the number of checkpoint buffers on the checkpoint list.
  */
index 6a3caed..8e2f827 100644 (file)
@@ -449,7 +449,7 @@ repeat:
        }
 
        /* OK, account for the buffers that this operation expects to
-        * use and add the handle to the running transaction. 
+        * use and add the handle to the running transaction.
         */
        update_t_max_wait(transaction, ts);
        handle->h_transaction = transaction;
@@ -836,6 +836,35 @@ int jbd2_journal_restart(handle_t *handle, int nblocks)
 }
 EXPORT_SYMBOL(jbd2_journal_restart);
 
+/*
+ * Waits for any outstanding t_updates to finish.
+ * This is called with write j_state_lock held.
+ */
+void jbd2_journal_wait_updates(journal_t *journal)
+{
+       transaction_t *commit_transaction = journal->j_running_transaction;
+
+       if (!commit_transaction)
+               return;
+
+       spin_lock(&commit_transaction->t_handle_lock);
+       while (atomic_read(&commit_transaction->t_updates)) {
+               DEFINE_WAIT(wait);
+
+               prepare_to_wait(&journal->j_wait_updates, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+               if (atomic_read(&commit_transaction->t_updates)) {
+                       spin_unlock(&commit_transaction->t_handle_lock);
+                       write_unlock(&journal->j_state_lock);
+                       schedule();
+                       write_lock(&journal->j_state_lock);
+                       spin_lock(&commit_transaction->t_handle_lock);
+               }
+               finish_wait(&journal->j_wait_updates, &wait);
+       }
+       spin_unlock(&commit_transaction->t_handle_lock);
+}
+
 /**
  * jbd2_journal_lock_updates () - establish a transaction barrier.
  * @journal:  Journal to establish a barrier on.
@@ -863,27 +892,9 @@ void jbd2_journal_lock_updates(journal_t *journal)
                write_lock(&journal->j_state_lock);
        }
 
-       /* Wait until there are no running updates */
-       while (1) {
-               transaction_t *transaction = journal->j_running_transaction;
-
-               if (!transaction)
-                       break;
+       /* Wait until there are no running t_updates */
+       jbd2_journal_wait_updates(journal);
 
-               spin_lock(&transaction->t_handle_lock);
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               if (!atomic_read(&transaction->t_updates)) {
-                       spin_unlock(&transaction->t_handle_lock);
-                       finish_wait(&journal->j_wait_updates, &wait);
-                       break;
-               }
-               spin_unlock(&transaction->t_handle_lock);
-               write_unlock(&journal->j_state_lock);
-               schedule();
-               finish_wait(&journal->j_wait_updates, &wait);
-               write_lock(&journal->j_state_lock);
-       }
        write_unlock(&journal->j_state_lock);
 
        /*
index dc3d061..911444d 100644 (file)
@@ -29,6 +29,7 @@
 #include "mgmt/user_config.h"
 #include "crypto_ctx.h"
 #include "transport_ipc.h"
+#include "../smbfs_common/arc4.h"
 
 /*
  * Fixed format data defining GSS header and fixed string
@@ -336,6 +337,29 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
                                nt_len - CIFS_ENCPWD_SIZE,
                                domain_name, conn->ntlmssp.cryptkey);
        kfree(domain_name);
+
+       /* The recovered secondary session key */
+       if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
+               struct arc4_ctx *ctx_arc4;
+               unsigned int sess_key_off, sess_key_len;
+
+               sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset);
+               sess_key_len = le16_to_cpu(authblob->SessionKey.Length);
+
+               if (blob_len < (u64)sess_key_off + sess_key_len)
+                       return -EINVAL;
+
+               ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
+               if (!ctx_arc4)
+                       return -ENOMEM;
+
+               cifs_arc4_setkey(ctx_arc4, sess->sess_key,
+                                SMB2_NTLMV2_SESSKEY_SIZE);
+               cifs_arc4_crypt(ctx_arc4, sess->sess_key,
+                               (char *)authblob + sess_key_off, sess_key_len);
+               kfree_sensitive(ctx_arc4);
+       }
+
        return ret;
 }
 
@@ -408,6 +432,9 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
            (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
                flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 
+       if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH)
+               flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
+
        chgblob->NegotiateFlags = cpu_to_le32(flags);
        len = strlen(ksmbd_netbios_name());
        name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
index 1866c81..67e8e28 100644 (file)
@@ -2688,7 +2688,7 @@ int smb2_open(struct ksmbd_work *work)
                                        (struct create_posix *)context;
                                if (le16_to_cpu(context->DataOffset) +
                                    le32_to_cpu(context->DataLength) <
-                                   sizeof(struct create_posix)) {
+                                   sizeof(struct create_posix) - 4) {
                                        rc = -EINVAL;
                                        goto err_out1;
                                }
@@ -3422,9 +3422,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
                goto free_conv_name;
        }
 
-       struct_sz = readdir_info_level_struct_sz(info_level);
-       next_entry_offset = ALIGN(struct_sz - 1 + conv_len,
-                                 KSMBD_DIR_INFO_ALIGNMENT);
+       struct_sz = readdir_info_level_struct_sz(info_level) - 1 + conv_len;
+       next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT);
+       d_info->last_entry_off_align = next_entry_offset - struct_sz;
 
        if (next_entry_offset > d_info->out_buf_len) {
                d_info->out_buf_len = 0;
@@ -3976,6 +3976,7 @@ int smb2_query_dir(struct ksmbd_work *work)
                ((struct file_directory_info *)
                ((char *)rsp->Buffer + d_info.last_entry_offset))
                ->NextEntryOffset = 0;
+               d_info.data_count -= d_info.last_entry_off_align;
 
                rsp->StructureSize = cpu_to_le16(9);
                rsp->OutputBufferOffset = cpu_to_le16(72);
@@ -6126,13 +6127,26 @@ static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work,
                                        __le16 ChannelInfoOffset,
                                        __le16 ChannelInfoLength)
 {
+       unsigned int i, ch_count;
+
        if (work->conn->dialect == SMB30_PROT_ID &&
            Channel != SMB2_CHANNEL_RDMA_V1)
                return -EINVAL;
 
-       if (ChannelInfoOffset == 0 ||
-           le16_to_cpu(ChannelInfoLength) < sizeof(*desc))
+       ch_count = le16_to_cpu(ChannelInfoLength) / sizeof(*desc);
+       if (ksmbd_debug_types & KSMBD_DEBUG_RDMA) {
+               for (i = 0; i < ch_count; i++) {
+                       pr_info("RDMA r/w request %#x: token %#x, length %#x\n",
+                               i,
+                               le32_to_cpu(desc[i].token),
+                               le32_to_cpu(desc[i].length));
+               }
+       }
+       if (ch_count != 1) {
+               ksmbd_debug(RDMA, "RDMA multiple buffer descriptors %d are not supported yet\n",
+                           ch_count);
                return -EINVAL;
+       }
 
        work->need_invalidate_rkey =
                (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
@@ -6185,9 +6199,15 @@ int smb2_read(struct ksmbd_work *work)
 
        if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||
            req->Channel == SMB2_CHANNEL_RDMA_V1) {
+               unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset);
+
+               if (ch_offset < offsetof(struct smb2_read_req, Buffer)) {
+                       err = -EINVAL;
+                       goto out;
+               }
                err = smb2_set_remote_key_for_rdma(work,
                                                   (struct smb2_buffer_desc_v1 *)
-                                                  &req->Buffer[0],
+                                                  ((char *)req + ch_offset),
                                                   req->Channel,
                                                   req->ReadChannelInfoOffset,
                                                   req->ReadChannelInfoLength);
@@ -6428,11 +6448,16 @@ int smb2_write(struct ksmbd_work *work)
 
        if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||
            req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) {
-               if (req->Length != 0 || req->DataOffset != 0)
-                       return -EINVAL;
+               unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset);
+
+               if (req->Length != 0 || req->DataOffset != 0 ||
+                   ch_offset < offsetof(struct smb2_write_req, Buffer)) {
+                       err = -EINVAL;
+                       goto out;
+               }
                err = smb2_set_remote_key_for_rdma(work,
                                                   (struct smb2_buffer_desc_v1 *)
-                                                  &req->Buffer[0],
+                                                  ((char *)req + ch_offset),
                                                   req->Channel,
                                                   req->WriteChannelInfoOffset,
                                                   req->WriteChannelInfoLength);
index ef7f42b..9a7e211 100644 (file)
@@ -308,14 +308,17 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
        for (i = 0; i < 2; i++) {
                struct kstat kstat;
                struct ksmbd_kstat ksmbd_kstat;
+               struct dentry *dentry;
 
                if (!dir->dot_dotdot[i]) { /* fill dot entry info */
                        if (i == 0) {
                                d_info->name = ".";
                                d_info->name_len = 1;
+                               dentry = dir->filp->f_path.dentry;
                        } else {
                                d_info->name = "..";
                                d_info->name_len = 2;
+                               dentry = dir->filp->f_path.dentry->d_parent;
                        }
 
                        if (!match_pattern(d_info->name, d_info->name_len,
@@ -327,7 +330,7 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
                        ksmbd_kstat.kstat = &kstat;
                        ksmbd_vfs_fill_dentry_attrs(work,
                                                    user_ns,
-                                                   dir->filp->f_path.dentry->d_parent,
+                                                   dentry,
                                                    &ksmbd_kstat);
                        rc = fn(conn, info_level, d_info, &ksmbd_kstat);
                        if (rc)
index 3c1ec1a..ba5a22b 100644 (file)
@@ -80,7 +80,7 @@ static int smb_direct_max_fragmented_recv_size = 1024 * 1024;
 /*  The maximum single-message size which can be received */
 static int smb_direct_max_receive_size = 8192;
 
-static int smb_direct_max_read_write_size = 1048512;
+static int smb_direct_max_read_write_size = 524224;
 
 static int smb_direct_max_outstanding_rw_ops = 8;
 
index adf94a4..8c37aaf 100644 (file)
@@ -47,6 +47,7 @@ struct ksmbd_dir_info {
        int             last_entry_offset;
        bool            hide_dot_file;
        int             flags;
+       int             last_entry_off_align;
 };
 
 struct ksmbd_readdir_data {
index ba7438a..9741252 100644 (file)
@@ -1379,7 +1379,7 @@ bool is_empty_dir_inode(struct inode *inode)
                (inode->i_op == &empty_dir_inode_operations);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Determine if the name of a dentry should be casefolded.
  *
@@ -1473,7 +1473,7 @@ static const struct dentry_operations generic_encrypted_dentry_ops = {
 };
 #endif
 
-#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_UNICODE)
+#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
 static const struct dentry_operations generic_encrypted_ci_dentry_ops = {
        .d_hash = generic_ci_d_hash,
        .d_compare = generic_ci_d_compare,
@@ -1508,10 +1508,10 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
 #ifdef CONFIG_FS_ENCRYPTION
        bool needs_encrypt_ops = dentry->d_flags & DCACHE_NOKEY_NAME;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        bool needs_ci_ops = dentry->d_sb->s_encoding;
 #endif
-#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_UNICODE)
+#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
        if (needs_encrypt_ops && needs_ci_ops) {
                d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops);
                return;
@@ -1523,7 +1523,7 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
                return;
        }
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (needs_ci_ops) {
                d_set_d_op(dentry, &generic_ci_dentry_ops);
                return;
index cb3a751..0a22a2f 100644 (file)
@@ -179,19 +179,21 @@ nlm_delete_file(struct nlm_file *file)
 static int nlm_unlock_files(struct nlm_file *file)
 {
        struct file_lock lock;
-       struct file *f;
 
+       locks_init_lock(&lock);
        lock.fl_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
-       for (f = file->f_file[0]; f <= file->f_file[1]; f++) {
-               if (f && vfs_lock_file(f, F_SETLK, &lock, NULL) < 0) {
-                       pr_warn("lockd: unlock failure in %s:%d\n",
-                               __FILE__, __LINE__);
-                       return 1;
-               }
-       }
+       if (file->f_file[O_RDONLY] &&
+           vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
+               goto out_err;
+       if (file->f_file[O_WRONLY] &&
+           vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL))
+               goto out_err;
        return 0;
+out_err:
+       pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__);
+       return 1;
 }
 
 /*
index 72900b8..3206373 100644 (file)
@@ -4130,8 +4130,10 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfserr_clid_inuse;
                        if (client_has_state(old)
                                        && !same_creds(&unconf->cl_cred,
-                                                       &old->cl_cred))
+                                                       &old->cl_cred)) {
+                               old = NULL;
                                goto out;
+                       }
                        status = mark_client_expired_locked(old);
                        if (status) {
                                old = NULL;
index 1026f67..2ff6bd8 100644 (file)
@@ -701,9 +701,6 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
        if (fanotify_is_perm_event(event->mask))
                FANOTIFY_PERM(event)->fd = fd;
 
-       if (f)
-               fd_install(fd, f);
-
        if (info_mode) {
                ret = copy_info_records_to_user(event, info, info_mode, pidfd,
                                                buf, count);
@@ -711,6 +708,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
                        goto out_close_fd;
        }
 
+       if (f)
+               fd_install(fd, f);
+
        return metadata.event_len;
 
 out_close_fd:
index b193d08..e040970 100644 (file)
@@ -145,7 +145,7 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
                if (err == -ENOTTY || err == -EINVAL)
                        return 0;
                pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n",
-                       old, err);
+                       old->dentry, err);
                return err;
        }
 
@@ -157,7 +157,9 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
         */
        if (oldfa.flags & OVL_PROT_FS_FLAGS_MASK) {
                err = ovl_set_protattr(inode, new->dentry, &oldfa);
-               if (err)
+               if (err == -EPERM)
+                       pr_warn_once("copying fileattr: no xattr on upper\n");
+               else if (err)
                        return err;
        }
 
@@ -167,8 +169,16 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
 
        err = ovl_real_fileattr_get(new, &newfa);
        if (err) {
+               /*
+                * Returning an error if upper doesn't support fileattr will
+                * result in a regression, so revert to the old behavior.
+                */
+               if (err == -ENOTTY || err == -EINVAL) {
+                       pr_warn_once("copying fileattr: no support on upper\n");
+                       return 0;
+               }
                pr_warn("failed to retrieve upper fileattr (%pd2, err=%i)\n",
-                       new, err);
+                       new->dentry, err);
                return err;
        }
 
index 22d904b..a74aef9 100644 (file)
@@ -690,9 +690,14 @@ int dquot_quota_sync(struct super_block *sb, int type)
        /* This is not very clever (and fast) but currently I don't know about
         * any other simple way of getting quota data to disk and we must get
         * them there for userspace to be visible... */
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
-       sync_blockdev(sb->s_bdev);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 1);
+               if (ret)
+                       return ret;
+       }
+       ret = sync_blockdev(sb->s_bdev);
+       if (ret)
+               return ret;
 
        /*
         * Now when everything is written we can discard the pagecache so
index 7af820b..f1d4a19 100644 (file)
@@ -1616,11 +1616,9 @@ static void lockdep_sb_freeze_acquire(struct super_block *sb)
                percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
 }
 
-static void sb_freeze_unlock(struct super_block *sb)
+static void sb_freeze_unlock(struct super_block *sb, int level)
 {
-       int level;
-
-       for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
+       for (level--; level >= 0; level--)
                percpu_up_write(sb->s_writers.rw_sem + level);
 }
 
@@ -1691,7 +1689,14 @@ int freeze_super(struct super_block *sb)
        sb_wait_write(sb, SB_FREEZE_PAGEFAULT);
 
        /* All writers are done so after syncing there won't be dirty data */
-       sync_filesystem(sb);
+       ret = sync_filesystem(sb);
+       if (ret) {
+               sb->s_writers.frozen = SB_UNFROZEN;
+               sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
+               wake_up(&sb->s_writers.wait_unfrozen);
+               deactivate_locked_super(sb);
+               return ret;
+       }
 
        /* Now wait for internal filesystem counter */
        sb->s_writers.frozen = SB_FREEZE_FS;
@@ -1703,7 +1708,7 @@ int freeze_super(struct super_block *sb)
                        printk(KERN_ERR
                                "VFS:Filesystem freeze failed\n");
                        sb->s_writers.frozen = SB_UNFROZEN;
-                       sb_freeze_unlock(sb);
+                       sb_freeze_unlock(sb, SB_FREEZE_FS);
                        wake_up(&sb->s_writers.wait_unfrozen);
                        deactivate_locked_super(sb);
                        return ret;
@@ -1748,7 +1753,7 @@ static int thaw_super_locked(struct super_block *sb)
        }
 
        sb->s_writers.frozen = SB_UNFROZEN;
-       sb_freeze_unlock(sb);
+       sb_freeze_unlock(sb, SB_FREEZE_FS);
 out:
        wake_up(&sb->s_writers.wait_unfrozen);
        deactivate_locked_super(sb);
index 3ce8e21..c769001 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -29,7 +29,7 @@
  */
 int sync_filesystem(struct super_block *sb)
 {
-       int ret;
+       int ret = 0;
 
        /*
         * We need to be protected against the filesystem going from
@@ -52,15 +52,21 @@ int sync_filesystem(struct super_block *sb)
         * at a time.
         */
        writeback_inodes_sb(sb, WB_REASON_SYNC);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 0);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 0);
+               if (ret)
+                       return ret;
+       }
        ret = sync_blockdev_nowait(sb->s_bdev);
-       if (ret < 0)
+       if (ret)
                return ret;
 
        sync_inodes_sb(sb);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 1);
+               if (ret)
+                       return ret;
+       }
        return sync_blockdev(sb->s_bdev);
 }
 EXPORT_SYMBOL(sync_filesystem);
index 610d7bc..da786a6 100644 (file)
@@ -3,21 +3,13 @@
 # UTF-8 normalization
 #
 config UNICODE
-       bool "UTF-8 normalization and casefolding support"
+       tristate "UTF-8 normalization and casefolding support"
        help
          Say Y here to enable UTF-8 NFD normalization and NFD+CF casefolding
-         support.
-
-config UNICODE_UTF8_DATA
-       tristate "UTF-8 normalization and casefolding tables"
-       depends on UNICODE
-       default UNICODE
-       help
-         This contains a large table of case foldings, which can be loaded as
-         a separate module if you say M here.  To be on the safe side stick
-         to the default of Y.  Saying N here makes no sense, if you do not want
-         utf8 casefolding support, disable CONFIG_UNICODE instead.
+         support.  If you say M here the large table of case foldings will
+         be a separate loadable module that gets requested only when a file
+         system actually use it.
 
 config UNICODE_NORMALIZATION_SELFTEST
        tristate "Test UTF-8 normalization support"
-       depends on UNICODE_UTF8_DATA
+       depends on UNICODE
index 2f9d918..0cc8742 100644 (file)
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_UNICODE) += unicode.o
+ifneq ($(CONFIG_UNICODE),)
+obj-y                  += unicode.o
+endif
+obj-$(CONFIG_UNICODE)  += utf8data.o
 obj-$(CONFIG_UNICODE_NORMALIZATION_SELFTEST) += utf8-selftest.o
-obj-$(CONFIG_UNICODE_UTF8_DATA) += utf8data.o
 
 unicode-y := utf8-norm.o utf8-core.o
 
index 2705f91..9d6a67c 100644 (file)
@@ -136,7 +136,20 @@ done:
        memalloc_nofs_restore(nofs_flag);
 }
 
-/* Finish all pending io completions. */
+/*
+ * Finish all pending IO completions that require transactional modifications.
+ *
+ * We try to merge physical and logically contiguous ioends before completion to
+ * minimise the number of transactions we need to perform during IO completion.
+ * Both unwritten extent conversion and COW remapping need to iterate and modify
+ * one physical extent at a time, so we gain nothing by merging physically
+ * discontiguous extents here.
+ *
+ * The ioend chain length that we can be processing here is largely unbound in
+ * length and we may have to perform significant amounts of work on each ioend
+ * to complete it. Hence we have to be careful about holding the CPU for too
+ * long in this loop.
+ */
 void
 xfs_end_io(
        struct work_struct      *work)
@@ -157,6 +170,7 @@ xfs_end_io(
                list_del_init(&ioend->io_list);
                iomap_ioend_try_merge(ioend, &tmp);
                xfs_end_ioend(ioend);
+               cond_resched();
        }
 }
 
index d4a387d..eb2e387 100644 (file)
@@ -850,9 +850,6 @@ xfs_alloc_file_space(
                        rblocks = 0;
                }
 
-               /*
-                * Allocate and setup the transaction.
-                */
                error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
                                dblocks, rblocks, false, &tp);
                if (error)
@@ -869,9 +866,9 @@ xfs_alloc_file_space(
                if (error)
                        goto error;
 
-               /*
-                * Complete the transaction
-                */
+               ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
                error = xfs_trans_commit(tp);
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
                if (error)
index 22ad207..5bddb1e 100644 (file)
@@ -66,40 +66,6 @@ xfs_is_falloc_aligned(
        return !((pos | len) & mask);
 }
 
-int
-xfs_update_prealloc_flags(
-       struct xfs_inode        *ip,
-       enum xfs_prealloc_flags flags)
-{
-       struct xfs_trans        *tp;
-       int                     error;
-
-       error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid,
-                       0, 0, 0, &tp);
-       if (error)
-               return error;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       if (!(flags & XFS_PREALLOC_INVISIBLE)) {
-               VFS_I(ip)->i_mode &= ~S_ISUID;
-               if (VFS_I(ip)->i_mode & S_IXGRP)
-                       VFS_I(ip)->i_mode &= ~S_ISGID;
-               xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       }
-
-       if (flags & XFS_PREALLOC_SET)
-               ip->i_diflags |= XFS_DIFLAG_PREALLOC;
-       if (flags & XFS_PREALLOC_CLEAR)
-               ip->i_diflags &= ~XFS_DIFLAG_PREALLOC;
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       if (flags & XFS_PREALLOC_SYNC)
-               xfs_trans_set_sync(tp);
-       return xfs_trans_commit(tp);
-}
-
 /*
  * Fsync operations on directories are much simpler than on regular files,
  * as there is no file data to flush, and thus also no need for explicit
@@ -895,6 +861,21 @@ xfs_break_layouts(
        return error;
 }
 
+/* Does this file, inode, or mount want synchronous writes? */
+static inline bool xfs_file_sync_writes(struct file *filp)
+{
+       struct xfs_inode        *ip = XFS_I(file_inode(filp));
+
+       if (xfs_has_wsync(ip->i_mount))
+               return true;
+       if (filp->f_flags & (__O_SYNC | O_DSYNC))
+               return true;
+       if (IS_SYNC(file_inode(filp)))
+               return true;
+
+       return false;
+}
+
 #define        XFS_FALLOC_FL_SUPPORTED                                         \
                (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |           \
                 FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |      \
@@ -910,7 +891,6 @@ xfs_file_fallocate(
        struct inode            *inode = file_inode(file);
        struct xfs_inode        *ip = XFS_I(inode);
        long                    error;
-       enum xfs_prealloc_flags flags = 0;
        uint                    iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
        loff_t                  new_size = 0;
        bool                    do_file_insert = false;
@@ -955,6 +935,10 @@ xfs_file_fallocate(
                        goto out_unlock;
        }
 
+       error = file_modified(file);
+       if (error)
+               goto out_unlock;
+
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                error = xfs_free_file_space(ip, offset, len);
                if (error)
@@ -1004,8 +988,6 @@ xfs_file_fallocate(
                }
                do_file_insert = true;
        } else {
-               flags |= XFS_PREALLOC_SET;
-
                if (!(mode & FALLOC_FL_KEEP_SIZE) &&
                    offset + len > i_size_read(inode)) {
                        new_size = offset + len;
@@ -1057,13 +1039,6 @@ xfs_file_fallocate(
                }
        }
 
-       if (file->f_flags & O_DSYNC)
-               flags |= XFS_PREALLOC_SYNC;
-
-       error = xfs_update_prealloc_flags(ip, flags);
-       if (error)
-               goto out_unlock;
-
        /* Change file size if needed */
        if (new_size) {
                struct iattr iattr;
@@ -1082,8 +1057,14 @@ xfs_file_fallocate(
         * leave shifted extents past EOF and hence losing access to
         * the data that is contained within them.
         */
-       if (do_file_insert)
+       if (do_file_insert) {
                error = xfs_insert_file_space(ip, offset, len);
+               if (error)
+                       goto out_unlock;
+       }
+
+       if (xfs_file_sync_writes(file))
+               error = xfs_log_force_inode(ip);
 
 out_unlock:
        xfs_iunlock(ip, iolock);
@@ -1115,21 +1096,6 @@ xfs_file_fadvise(
        return ret;
 }
 
-/* Does this file, inode, or mount want synchronous writes? */
-static inline bool xfs_file_sync_writes(struct file *filp)
-{
-       struct xfs_inode        *ip = XFS_I(file_inode(filp));
-
-       if (xfs_has_wsync(ip->i_mount))
-               return true;
-       if (filp->f_flags & (__O_SYNC | O_DSYNC))
-               return true;
-       if (IS_SYNC(file_inode(filp)))
-               return true;
-
-       return false;
-}
-
 STATIC loff_t
 xfs_file_remap_range(
        struct file             *file_in,
index c447bf0..b7e8f14 100644 (file)
@@ -462,15 +462,6 @@ xfs_itruncate_extents(
 }
 
 /* from xfs_file.c */
-enum xfs_prealloc_flags {
-       XFS_PREALLOC_SET        = (1 << 1),
-       XFS_PREALLOC_CLEAR      = (1 << 2),
-       XFS_PREALLOC_SYNC       = (1 << 3),
-       XFS_PREALLOC_INVISIBLE  = (1 << 4),
-};
-
-int    xfs_update_prealloc_flags(struct xfs_inode *ip,
-                                 enum xfs_prealloc_flags flags);
 int    xfs_break_layouts(struct inode *inode, uint *iolock,
                enum layout_break_reason reason);
 
index 03a6198..2515fe8 100644 (file)
@@ -1464,7 +1464,7 @@ xfs_ioc_getbmap(
 
        if (bmx.bmv_count < 2)
                return -EINVAL;
-       if (bmx.bmv_count > ULONG_MAX / recsize)
+       if (bmx.bmv_count >= INT_MAX / recsize)
                return -ENOMEM;
 
        buf = kvcalloc(bmx.bmv_count, sizeof(*buf), GFP_KERNEL);
index d6334ab..4abe173 100644 (file)
@@ -70,6 +70,40 @@ xfs_fs_get_uuid(
        return 0;
 }
 
+/*
+ * We cannot use file based VFS helpers such as file_modified() to update
+ * inode state as we modify the data/metadata in the inode here. Hence we have
+ * to open code the timestamp updates and SUID/SGID stripping. We also need
+ * to set the inode prealloc flag to ensure that the extents we allocate are not
+ * removed if the inode is reclaimed from memory before xfs_fs_block_commit()
+ * is from the client to indicate that data has been written and the file size
+ * can be extended.
+ */
+static int
+xfs_fs_map_update_inode(
+       struct xfs_inode        *ip)
+{
+       struct xfs_trans        *tp;
+       int                     error;
+
+       error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid,
+                       0, 0, 0, &tp);
+       if (error)
+               return error;
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       VFS_I(ip)->i_mode &= ~S_ISUID;
+       if (VFS_I(ip)->i_mode & S_IXGRP)
+               VFS_I(ip)->i_mode &= ~S_ISGID;
+       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       return xfs_trans_commit(tp);
+}
+
 /*
  * Get a layout for the pNFS client.
  */
@@ -164,10 +198,12 @@ xfs_fs_map_blocks(
                 * that the blocks allocated and handed out to the client are
                 * guaranteed to be present even after a server crash.
                 */
-               error = xfs_update_prealloc_flags(ip,
-                               XFS_PREALLOC_SET | XFS_PREALLOC_SYNC);
+               error = xfs_fs_map_update_inode(ip);
+               if (!error)
+                       error = xfs_log_force_inode(ip);
                if (error)
                        goto out_unlock;
+
        } else {
                xfs_iunlock(ip, lock_flags);
        }
@@ -255,7 +291,7 @@ xfs_fs_commit_blocks(
                length = end - start;
                if (!length)
                        continue;
-       
+
                /*
                 * Make sure reads through the pagecache see the new data.
                 */
index e8f37bd..4c0dee7 100644 (file)
@@ -735,6 +735,7 @@ xfs_fs_sync_fs(
        int                     wait)
 {
        struct xfs_mount        *mp = XFS_M(sb);
+       int                     error;
 
        trace_xfs_fs_sync_fs(mp, __return_address);
 
@@ -744,7 +745,10 @@ xfs_fs_sync_fs(
        if (!wait)
                return 0;
 
-       xfs_log_force(mp, XFS_LOG_SYNC);
+       error = xfs_log_force(mp, XFS_LOG_SYNC);
+       if (error)
+               return error;
+
        if (laptop_mode) {
                /*
                 * The disk must be active because we're syncing.
index d39cfa0..52363ee 100644 (file)
@@ -24,14 +24,11 @@ static inline void blake2s_set_lastblock(struct blake2s_state *state)
        state->f[0] = -1;
 }
 
-typedef void (*blake2s_compress_t)(struct blake2s_state *state,
-                                  const u8 *block, size_t nblocks, u32 inc);
-
 /* Helper functions for BLAKE2s shared by the library and shash APIs */
 
-static inline void __blake2s_update(struct blake2s_state *state,
-                                   const u8 *in, size_t inlen,
-                                   blake2s_compress_t compress)
+static __always_inline void
+__blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen,
+                bool force_generic)
 {
        const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
 
@@ -39,7 +36,12 @@ static inline void __blake2s_update(struct blake2s_state *state,
                return;
        if (inlen > fill) {
                memcpy(state->buf + state->buflen, in, fill);
-               (*compress)(state, state->buf, 1, BLAKE2S_BLOCK_SIZE);
+               if (force_generic)
+                       blake2s_compress_generic(state, state->buf, 1,
+                                                BLAKE2S_BLOCK_SIZE);
+               else
+                       blake2s_compress(state, state->buf, 1,
+                                        BLAKE2S_BLOCK_SIZE);
                state->buflen = 0;
                in += fill;
                inlen -= fill;
@@ -47,7 +49,12 @@ static inline void __blake2s_update(struct blake2s_state *state,
        if (inlen > BLAKE2S_BLOCK_SIZE) {
                const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
                /* Hash one less (full) block than strictly possible */
-               (*compress)(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
+               if (force_generic)
+                       blake2s_compress_generic(state, in, nblocks - 1,
+                                                BLAKE2S_BLOCK_SIZE);
+               else
+                       blake2s_compress(state, in, nblocks - 1,
+                                        BLAKE2S_BLOCK_SIZE);
                in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
                inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
        }
@@ -55,13 +62,16 @@ static inline void __blake2s_update(struct blake2s_state *state,
        state->buflen += inlen;
 }
 
-static inline void __blake2s_final(struct blake2s_state *state, u8 *out,
-                                  blake2s_compress_t compress)
+static __always_inline void
+__blake2s_final(struct blake2s_state *state, u8 *out, bool force_generic)
 {
        blake2s_set_lastblock(state);
        memset(state->buf + state->buflen, 0,
               BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
-       (*compress)(state, state->buf, 1, state->buflen);
+       if (force_generic)
+               blake2s_compress_generic(state, state->buf, 1, state->buflen);
+       else
+               blake2s_compress(state, state->buf, 1, state->buflen);
        cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
        memcpy(out, state->h, state->outlen);
 }
@@ -99,20 +109,20 @@ static inline int crypto_blake2s_init(struct shash_desc *desc)
 
 static inline int crypto_blake2s_update(struct shash_desc *desc,
                                        const u8 *in, unsigned int inlen,
-                                       blake2s_compress_t compress)
+                                       bool force_generic)
 {
        struct blake2s_state *state = shash_desc_ctx(desc);
 
-       __blake2s_update(state, in, inlen, compress);
+       __blake2s_update(state, in, inlen, force_generic);
        return 0;
 }
 
 static inline int crypto_blake2s_final(struct shash_desc *desc, u8 *out,
-                                      blake2s_compress_t compress)
+                                      bool force_generic)
 {
        struct blake2s_state *state = shash_desc_ctx(desc);
 
-       __blake2s_final(state, out, compress);
+       __blake2s_final(state, out, force_generic);
        return 0;
 }
 
index 199e47e..21292b5 100644 (file)
@@ -324,12 +324,12 @@ enum {
        ATA_LOG_NCQ_NON_DATA    = 0x12,
        ATA_LOG_NCQ_SEND_RECV   = 0x13,
        ATA_LOG_IDENTIFY_DEVICE = 0x30,
+       ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
 
        /* Identify device log pages: */
        ATA_LOG_SECURITY          = 0x06,
        ATA_LOG_SATA_SETTINGS     = 0x08,
        ATA_LOG_ZONED_INFORMATION = 0x09,
-       ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
 
        /* Identify device SATA settings log:*/
        ATA_LOG_DEVSLP_OFFSET     = 0x30,
index 6a89ea4..edf62ea 100644 (file)
@@ -35,6 +35,7 @@
 #define CEPH_OPT_TCP_NODELAY      (1<<4) /* TCP_NODELAY on TCP sockets */
 #define CEPH_OPT_NOMSGSIGN        (1<<5) /* don't sign msgs (msgr1) */
 #define CEPH_OPT_ABORT_ON_FULL    (1<<6) /* abort w/ ENOSPC when full */
+#define CEPH_OPT_RXBOUNCE         (1<<7) /* double-buffer read data */
 
 #define CEPH_OPT_DEFAULT   (CEPH_OPT_TCP_NODELAY)
 
index ff99ce0..e7f2fb2 100644 (file)
@@ -383,6 +383,10 @@ struct ceph_connection_v2_info {
        struct ceph_gcm_nonce in_gcm_nonce;
        struct ceph_gcm_nonce out_gcm_nonce;
 
+       struct page **in_enc_pages;
+       int in_enc_page_cnt;
+       int in_enc_resid;
+       int in_enc_i;
        struct page **out_enc_pages;
        int out_enc_page_cnt;
        int out_enc_resid;
@@ -457,6 +461,7 @@ struct ceph_connection {
        struct ceph_msg *out_msg;        /* sending message (== tail of
                                            out_sent) */
 
+       struct page *bounce_page;
        u32 in_front_crc, in_middle_crc, in_data_crc;  /* calculated crc */
 
        struct timespec64 last_keepalive_ack; /* keepalive2 ack stamp */
index 3da9584..02f362c 100644 (file)
@@ -262,7 +262,7 @@ struct fb_ops {
 
        /* Draws a rectangle */
        void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
-       /* Copy data from area to another. Obsolete. */
+       /* Copy data from area to another */
        void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
        /* Draws a image to the display */
        void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
index f3daaea..e2d892b 100644 (file)
@@ -1483,7 +1483,7 @@ struct super_block {
 #ifdef CONFIG_FS_VERITY
        const struct fsverity_operations *s_vop;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct unicode_map *s_encoding;
        __u16 s_encoding_flags;
 #endif
index 8420fe5..2be4dd7 100644 (file)
@@ -46,8 +46,10 @@ struct vlan_hdr {
  *     @h_vlan_encapsulated_proto: packet type ID or len
  */
 struct vlan_ethhdr {
-       unsigned char   h_dest[ETH_ALEN];
-       unsigned char   h_source[ETH_ALEN];
+       struct_group(addrs,
+               unsigned char   h_dest[ETH_ALEN];
+               unsigned char   h_source[ETH_ALEN];
+       );
        __be16          h_vlan_proto;
        __be16          h_vlan_TCI;
        __be16          h_vlan_encapsulated_proto;
index b55bd49..97a3a2e 100644 (file)
@@ -263,9 +263,11 @@ struct iomap_ioend {
        struct list_head        io_list;        /* next ioend in chain */
        u16                     io_type;
        u16                     io_flags;       /* IOMAP_F_* */
+       u32                     io_folios;      /* folios added to ioend */
        struct inode            *io_inode;      /* file being written to */
        size_t                  io_size;        /* size of the extent */
        loff_t                  io_offset;      /* offset in the file */
+       sector_t                io_sector;      /* start sector of ioend */
        struct bio              *io_bio;        /* bio being built */
        struct bio              io_inline_bio;  /* MUST BE LAST! */
 };
index fd933c4..9c3ada7 100644 (file)
@@ -594,7 +594,7 @@ struct transaction_s
         */
        unsigned long           t_log_start;
 
-       /* 
+       /*
         * Number of buffers on the t_buffers list [j_list_lock, no locks
         * needed for jbd2 thread]
         */
@@ -1295,7 +1295,7 @@ struct journal_s
         * Clean-up after fast commit or full commit. JBD2 calls this function
         * after every commit operation.
         */
-       void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
+       void (*j_fc_cleanup_callback)(struct journal_s *journal, int full, tid_t tid);
 
        /**
         * @j_fc_replay_callback:
@@ -1419,9 +1419,7 @@ extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *);
 extern bool __jbd2_journal_refile_buffer(struct journal_head *);
 extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *);
 extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
-extern void __journal_free_buffer(struct journal_head *bh);
 extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
-extern void __journal_clean_data_list(transaction_t *transaction);
 static inline void jbd2_file_log_bh(struct list_head *head, struct buffer_head *bh)
 {
        list_add_tail(&bh->b_assoc_buffers, head);
@@ -1486,9 +1484,6 @@ extern int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
                                              struct buffer_head **bh_out,
                                              sector_t blocknr);
 
-/* Transaction locking */
-extern void            __wait_on_journal (journal_t *);
-
 /* Transaction cache support */
 extern void jbd2_journal_destroy_transaction_cache(void);
 extern int __init jbd2_journal_init_transaction_cache(void);
@@ -1543,6 +1538,8 @@ extern int         jbd2_journal_flush(journal_t *journal, unsigned int flags);
 extern void     jbd2_journal_lock_updates (journal_t *);
 extern void     jbd2_journal_unlock_updates (journal_t *);
 
+void jbd2_journal_wait_updates(journal_t *);
+
 extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
                                struct block_device *fs_dev,
                                unsigned long long start, int len, int bsize);
@@ -1774,8 +1771,6 @@ static inline unsigned long jbd2_log_space_left(journal_t *journal)
 #define BJ_Reserved    4       /* Buffer is reserved for access by journal */
 #define BJ_Types       5
 
-extern int jbd_blocks_per_page(struct inode *inode);
-
 /* JBD uses a CRC32 checksum */
 #define JBD_MAX_CHECKSUM_SIZE 4
 
index 06912d6..f110399 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/refcount.h>
 #include <linux/nospec.h>
 #include <linux/notifier.h>
+#include <linux/ftrace.h>
 #include <linux/hashtable.h>
+#include <linux/instrumentation.h>
 #include <linux/interval_tree.h>
 #include <linux/rbtree.h>
 #include <linux/xarray.h>
@@ -368,8 +370,11 @@ struct kvm_vcpu {
        u64 last_used_slot_gen;
 };
 
-/* must be called with irqs disabled */
-static __always_inline void guest_enter_irqoff(void)
+/*
+ * Start accounting time towards a guest.
+ * Must be called before entering guest context.
+ */
+static __always_inline void guest_timing_enter_irqoff(void)
 {
        /*
         * This is running in ioctl context so its safe to assume that it's the
@@ -378,7 +383,18 @@ static __always_inline void guest_enter_irqoff(void)
        instrumentation_begin();
        vtime_account_guest_enter();
        instrumentation_end();
+}
 
+/*
+ * Enter guest context and enter an RCU extended quiescent state.
+ *
+ * Between guest_context_enter_irqoff() and guest_context_exit_irqoff() it is
+ * unsafe to use any code which may directly or indirectly use RCU, tracing
+ * (including IRQ flag tracing), or lockdep. All code in this period must be
+ * non-instrumentable.
+ */
+static __always_inline void guest_context_enter_irqoff(void)
+{
        /*
         * KVM does not hold any references to rcu protected data when it
         * switches CPU into a guest mode. In fact switching to a guest mode
@@ -394,16 +410,79 @@ static __always_inline void guest_enter_irqoff(void)
        }
 }
 
-static __always_inline void guest_exit_irqoff(void)
+/*
+ * Deprecated. Architectures should move to guest_timing_enter_irqoff() and
+ * guest_state_enter_irqoff().
+ */
+static __always_inline void guest_enter_irqoff(void)
+{
+       guest_timing_enter_irqoff();
+       guest_context_enter_irqoff();
+}
+
+/**
+ * guest_state_enter_irqoff - Fixup state when entering a guest
+ *
+ * Entry to a guest will enable interrupts, but the kernel state is interrupts
+ * disabled when this is invoked. Also tell RCU about it.
+ *
+ * 1) Trace interrupts on state
+ * 2) Invoke context tracking if enabled to adjust RCU state
+ * 3) Tell lockdep that interrupts are enabled
+ *
+ * Invoked from architecture specific code before entering a guest.
+ * Must be called with interrupts disabled and the caller must be
+ * non-instrumentable.
+ * The caller has to invoke guest_timing_enter_irqoff() before this.
+ *
+ * Note: this is analogous to exit_to_user_mode().
+ */
+static __always_inline void guest_state_enter_irqoff(void)
+{
+       instrumentation_begin();
+       trace_hardirqs_on_prepare();
+       lockdep_hardirqs_on_prepare(CALLER_ADDR0);
+       instrumentation_end();
+
+       guest_context_enter_irqoff();
+       lockdep_hardirqs_on(CALLER_ADDR0);
+}
+
+/*
+ * Exit guest context and exit an RCU extended quiescent state.
+ *
+ * Between guest_context_enter_irqoff() and guest_context_exit_irqoff() it is
+ * unsafe to use any code which may directly or indirectly use RCU, tracing
+ * (including IRQ flag tracing), or lockdep. All code in this period must be
+ * non-instrumentable.
+ */
+static __always_inline void guest_context_exit_irqoff(void)
 {
        context_tracking_guest_exit();
+}
 
+/*
+ * Stop accounting time towards a guest.
+ * Must be called after exiting guest context.
+ */
+static __always_inline void guest_timing_exit_irqoff(void)
+{
        instrumentation_begin();
        /* Flush the guest cputime we spent on the guest */
        vtime_account_guest_exit();
        instrumentation_end();
 }
 
+/*
+ * Deprecated. Architectures should move to guest_state_exit_irqoff() and
+ * guest_timing_exit_irqoff().
+ */
+static __always_inline void guest_exit_irqoff(void)
+{
+       guest_context_exit_irqoff();
+       guest_timing_exit_irqoff();
+}
+
 static inline void guest_exit(void)
 {
        unsigned long flags;
@@ -413,6 +492,33 @@ static inline void guest_exit(void)
        local_irq_restore(flags);
 }
 
+/**
+ * guest_state_exit_irqoff - Establish state when returning from guest mode
+ *
+ * Entry from a guest disables interrupts, but guest mode is traced as
+ * interrupts enabled. Also with NO_HZ_FULL RCU might be idle.
+ *
+ * 1) Tell lockdep that interrupts are disabled
+ * 2) Invoke context tracking if enabled to reactivate RCU
+ * 3) Trace interrupts off state
+ *
+ * Invoked from architecture specific code after exiting a guest.
+ * Must be invoked with interrupts disabled and the caller must be
+ * non-instrumentable.
+ * The caller has to invoke guest_timing_exit_irqoff() after this.
+ *
+ * Note: this is analogous to enter_from_user_mode().
+ */
+static __always_inline void guest_state_exit_irqoff(void)
+{
+       lockdep_hardirqs_off(CALLER_ADDR0);
+       guest_context_exit_irqoff();
+
+       instrumentation_begin();
+       trace_hardirqs_off_finish();
+       instrumentation_end();
+}
+
 static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
 {
        /*
index 605756f..7f99b4d 100644 (file)
@@ -380,6 +380,7 @@ enum {
        ATA_HORKAGE_MAX_TRIM_128M = (1 << 26),  /* Limit max trim size to 128M */
        ATA_HORKAGE_NO_NCQ_ON_ATI = (1 << 27),  /* Disable NCQ on ATI chipset */
        ATA_HORKAGE_NO_ID_DEV_LOG = (1 << 28),  /* Identify device log missing */
+       ATA_HORKAGE_NO_LOG_DIR  = (1 << 29),    /* Do not read log directory */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index b46c39d..614f222 100644 (file)
@@ -244,6 +244,13 @@ struct netfs_cache_ops {
        int (*prepare_write)(struct netfs_cache_resources *cres,
                             loff_t *_start, size_t *_len, loff_t i_size,
                             bool no_space_allocated_yet);
+
+       /* Query the occupancy of the cache in a region, returning where the
+        * next chunk of data starts and how long it is.
+        */
+       int (*query_occupancy)(struct netfs_cache_resources *cres,
+                              loff_t start, size_t len, size_t granularity,
+                              loff_t *_data_start, size_t *_data_len);
 };
 
 struct readahead_control;
index 38cace1..01e16c7 100644 (file)
@@ -26,6 +26,9 @@ void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd);
 void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud);
+void __page_table_check_pte_clear_range(struct mm_struct *mm,
+                                       unsigned long addr,
+                                       pmd_t pmd);
 
 static inline void page_table_check_alloc(struct page *page, unsigned int order)
 {
@@ -100,6 +103,16 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
        __page_table_check_pud_set(mm, addr, pudp, pud);
 }
 
+static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
+                                                   unsigned long addr,
+                                                   pmd_t pmd)
+{
+       if (static_branch_likely(&page_table_check_disabled))
+               return;
+
+       __page_table_check_pte_clear_range(mm, addr, pmd);
+}
+
 #else
 
 static inline void page_table_check_alloc(struct page *page, unsigned int order)
@@ -143,5 +156,11 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
 {
 }
 
+static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
+                                                   unsigned long addr,
+                                                   pmd_t pmd)
+{
+}
+
 #endif /* CONFIG_PAGE_TABLE_CHECK */
 #endif /* __LINUX_PAGE_TABLE_CHECK_H */
index bc8713a..f4f4077 100644 (file)
@@ -62,6 +62,7 @@ static inline unsigned long pte_index(unsigned long address)
 {
        return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 }
+#define pte_index pte_index
 
 #ifndef pmd_index
 static inline unsigned long pmd_index(unsigned long address)
index f5b2be3..75ba8aa 100644 (file)
@@ -1680,7 +1680,6 @@ extern struct pid *cad_pid;
 #define PF_MEMALLOC            0x00000800      /* Allocating memory */
 #define PF_NPROC_EXCEEDED      0x00001000      /* set_user() noticed that RLIMIT_NPROC was exceeded */
 #define PF_USED_MATH           0x00002000      /* If unset the fpu must be initialized before use */
-#define PF_USED_ASYNC          0x00004000      /* Used async_schedule*(), used by module init */
 #define PF_NOFREEZE            0x00008000      /* This thread should not be frozen */
 #define PF_FROZEN              0x00010000      /* Frozen for system suspend */
 #define PF_KSWAPD              0x00020000      /* I am kswapd */
index 526e495..8221af1 100644 (file)
@@ -239,6 +239,7 @@ typedef struct ax25_dev {
 #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
        ax25_dama_info          dama;
 #endif
+       refcount_t              refcount;
 } ax25_dev;
 
 typedef struct ax25_cb {
@@ -293,6 +294,17 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25)
        }
 }
 
+static inline void ax25_dev_hold(ax25_dev *ax25_dev)
+{
+       refcount_inc(&ax25_dev->refcount);
+}
+
+static inline void ax25_dev_put(ax25_dev *ax25_dev)
+{
+       if (refcount_dec_and_test(&ax25_dev->refcount)) {
+               kfree(ax25_dev);
+       }
+}
 static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        skb->dev      = dev;
index 937389e..87419f7 100644 (file)
@@ -350,7 +350,8 @@ static inline struct neighbour *neigh_create(struct neigh_table *tbl,
        return __neigh_create(tbl, pkey, dev, true);
 }
 void neigh_destroy(struct neighbour *neigh);
-int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
+                      const bool immediate_ok);
 int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags,
                 u32 nlmsg_pid);
 void __neigh_set_probe_once(struct neighbour *neigh);
@@ -460,17 +461,24 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)
 
 #define neigh_hold(n)  refcount_inc(&(n)->refcnt)
 
-static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+static __always_inline int neigh_event_send_probe(struct neighbour *neigh,
+                                                 struct sk_buff *skb,
+                                                 const bool immediate_ok)
 {
        unsigned long now = jiffies;
-       
+
        if (READ_ONCE(neigh->used) != now)
                WRITE_ONCE(neigh->used, now);
-       if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
-               return __neigh_event_send(neigh, skb);
+       if (!(neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE)))
+               return __neigh_event_send(neigh, skb, immediate_ok);
        return 0;
 }
 
+static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+{
+       return neigh_event_send_probe(neigh, skb, true);
+}
+
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
 {
index 9b187d8..36da42c 100644 (file)
@@ -617,6 +617,7 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
 void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
 void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
 unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream);
 
 /**
  * snd_pcm_stream_lock_irqsave - Lock the PCM stream
@@ -635,6 +636,20 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
 void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
                                      unsigned long flags);
 
+/**
+ * snd_pcm_stream_lock_irqsave_nested - Single-nested PCM stream locking
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock_irqsave() but with
+ * the single-depth lockdep subclass.
+ */
+#define snd_pcm_stream_lock_irqsave_nested(substream, flags)           \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
+       } while (0)
+
 /**
  * snd_pcm_group_for_each_entry - iterate over the linked substreams
  * @s: the iterator
index b46bcdb..5191b57 100644 (file)
@@ -1624,9 +1624,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET  _IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET   _IO(KVMIO,   0xc4)
 
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
-
 struct kvm_s390_pv_sec_parm {
        __u64 origin;
        __u64 length;
@@ -2048,4 +2045,7 @@ struct kvm_stats_desc {
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
 
+/* Available with KVM_CAP_XSAVE2 */
+#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
+
 #endif /* __LINUX_KVM_H */
index 1b65042..82858b6 100644 (file)
@@ -465,6 +465,8 @@ struct perf_event_attr {
        /*
         * User provided data if sigtrap=1, passed back to user via
         * siginfo_t::si_perf_data, e.g. to permit user to identify the event.
+        * Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
+        * truncated accordingly on 32 bit architectures.
         */
        __u64   sig_data;
 };
index c7008d8..8cb3a6f 100644 (file)
@@ -84,12 +84,11 @@ struct smc_diag_conninfo {
 /* SMC_DIAG_LINKINFO */
 
 struct smc_diag_linkinfo {
-       __u8            link_id;                    /* link identifier */
-       __u8            ibname[IB_DEVICE_NAME_MAX]; /* name of the RDMA device */
-       __u8            ibport;                     /* RDMA device port number */
-       __u8            gid[40];                    /* local GID */
-       __u8            peer_gid[40];               /* peer GID */
-       __aligned_u64   net_cookie;                 /* RDMA device net namespace */
+       __u8 link_id;                   /* link identifier */
+       __u8 ibname[IB_DEVICE_NAME_MAX]; /* name of the RDMA device */
+       __u8 ibport;                    /* RDMA device port number */
+       __u8 gid[40];                   /* local GID */
+       __u8 peer_gid[40];              /* peer GID */
 };
 
 struct smc_diag_lgrinfo {
index ef0cafe..2d3e5df 100644 (file)
  *                                                                          *
  ****************************************************************************/
 
+#define AES_IEC958_STATUS_SIZE         24
+
 struct snd_aes_iec958 {
-       unsigned char status[24];       /* AES/IEC958 channel status bits */
+       unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
        unsigned char subcode[147];     /* AES/IEC958 subcode bits */
        unsigned char pad;              /* nothing */
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
index 9ac5515..7a71453 100644 (file)
@@ -47,7 +47,13 @@ struct ioctl_gntdev_grant_ref {
 /*
  * Inserts the grant references into the mapping table of an instance
  * of gntdev. N.B. This does not perform the mapping, which is deferred
- * until mmap() is called with @index as the offset.
+ * until mmap() is called with @index as the offset. @index should be
+ * considered opaque to userspace, with one exception: if no grant
+ * references have ever been inserted into the mapping table of this
+ * instance, @index will be set to 0. This is necessary to use gntdev
+ * with userspace APIs that expect a file descriptor that can be
+ * mmap()'d at offset 0, such as Wayland. If @count is set to 0, this
+ * ioctl will fail.
  */
 #define IOCTL_GNTDEV_MAP_GRANT_REF \
 _IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
index bbee8c6..4dc45a5 100644 (file)
@@ -1,6 +1,4 @@
 /******************************************************************************
- * evtchn.h
- *
  * Interface to /dev/xen/xenbus_backend.
  *
  * Copyright (c) 2011 Bastian Blank <waldi@debian.org>
index 6693daf..0dbdb98 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1964,6 +1964,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
         */
        un = lookup_undo(ulp, semid);
        if (un) {
+               spin_unlock(&ulp->lock);
                kvfree(new);
                goto success;
        }
@@ -1976,9 +1977,8 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        ipc_assert_locked_object(&sma->sem_perm);
        list_add(&new->list_id, &sma->list_id);
        un = new;
-
-success:
        spin_unlock(&ulp->lock);
+success:
        sem_unlock(sma, -1);
 out:
        return un;
index b8d7a66..b2c4ba5 100644 (file)
@@ -205,9 +205,6 @@ async_cookie_t async_schedule_node_domain(async_func_t func, void *data,
        atomic_inc(&entry_count);
        spin_unlock_irqrestore(&async_lock, flags);
 
-       /* mark that this task has queued an async job, used by module init */
-       current->flags |= PF_USED_ASYNC;
-
        /* schedule for execution */
        queue_work_node(node, system_unbound_wq, &entry->work);
 
index e4bbe2c..7690c29 100644 (file)
@@ -541,20 +541,22 @@ static void kauditd_printk_skb(struct sk_buff *skb)
 /**
  * kauditd_rehold_skb - Handle a audit record send failure in the hold queue
  * @skb: audit record
+ * @error: error code (unused)
  *
  * Description:
  * This should only be used by the kauditd_thread when it fails to flush the
  * hold queue.
  */
-static void kauditd_rehold_skb(struct sk_buff *skb)
+static void kauditd_rehold_skb(struct sk_buff *skb, __always_unused int error)
 {
-       /* put the record back in the queue at the same place */
-       skb_queue_head(&audit_hold_queue, skb);
+       /* put the record back in the queue */
+       skb_queue_tail(&audit_hold_queue, skb);
 }
 
 /**
  * kauditd_hold_skb - Queue an audit record, waiting for auditd
  * @skb: audit record
+ * @error: error code
  *
  * Description:
  * Queue the audit record, waiting for an instance of auditd.  When this
@@ -564,19 +566,31 @@ static void kauditd_rehold_skb(struct sk_buff *skb)
  * and queue it, if we have room.  If we want to hold on to the record, but we
  * don't have room, record a record lost message.
  */
-static void kauditd_hold_skb(struct sk_buff *skb)
+static void kauditd_hold_skb(struct sk_buff *skb, int error)
 {
        /* at this point it is uncertain if we will ever send this to auditd so
         * try to send the message via printk before we go any further */
        kauditd_printk_skb(skb);
 
        /* can we just silently drop the message? */
-       if (!audit_default) {
-               kfree_skb(skb);
-               return;
+       if (!audit_default)
+               goto drop;
+
+       /* the hold queue is only for when the daemon goes away completely,
+        * not -EAGAIN failures; if we are in a -EAGAIN state requeue the
+        * record on the retry queue unless it's full, in which case drop it
+        */
+       if (error == -EAGAIN) {
+               if (!audit_backlog_limit ||
+                   skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
+                       skb_queue_tail(&audit_retry_queue, skb);
+                       return;
+               }
+               audit_log_lost("kauditd retry queue overflow");
+               goto drop;
        }
 
-       /* if we have room, queue the message */
+       /* if we have room in the hold queue, queue the message */
        if (!audit_backlog_limit ||
            skb_queue_len(&audit_hold_queue) < audit_backlog_limit) {
                skb_queue_tail(&audit_hold_queue, skb);
@@ -585,24 +599,32 @@ static void kauditd_hold_skb(struct sk_buff *skb)
 
        /* we have no other options - drop the message */
        audit_log_lost("kauditd hold queue overflow");
+drop:
        kfree_skb(skb);
 }
 
 /**
  * kauditd_retry_skb - Queue an audit record, attempt to send again to auditd
  * @skb: audit record
+ * @error: error code (unused)
  *
  * Description:
  * Not as serious as kauditd_hold_skb() as we still have a connected auditd,
  * but for some reason we are having problems sending it audit records so
  * queue the given record and attempt to resend.
  */
-static void kauditd_retry_skb(struct sk_buff *skb)
+static void kauditd_retry_skb(struct sk_buff *skb, __always_unused int error)
 {
-       /* NOTE: because records should only live in the retry queue for a
-        * short period of time, before either being sent or moved to the hold
-        * queue, we don't currently enforce a limit on this queue */
-       skb_queue_tail(&audit_retry_queue, skb);
+       if (!audit_backlog_limit ||
+           skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
+               skb_queue_tail(&audit_retry_queue, skb);
+               return;
+       }
+
+       /* we have to drop the record, send it via printk as a last effort */
+       kauditd_printk_skb(skb);
+       audit_log_lost("kauditd retry queue overflow");
+       kfree_skb(skb);
 }
 
 /**
@@ -640,7 +662,7 @@ static void auditd_reset(const struct auditd_connection *ac)
        /* flush the retry queue to the hold queue, but don't touch the main
         * queue since we need to process that normally for multicast */
        while ((skb = skb_dequeue(&audit_retry_queue)))
-               kauditd_hold_skb(skb);
+               kauditd_hold_skb(skb, -ECONNREFUSED);
 }
 
 /**
@@ -714,16 +736,18 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                              struct sk_buff_head *queue,
                              unsigned int retry_limit,
                              void (*skb_hook)(struct sk_buff *skb),
-                             void (*err_hook)(struct sk_buff *skb))
+                             void (*err_hook)(struct sk_buff *skb, int error))
 {
        int rc = 0;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
+       struct sk_buff *skb_tail;
        unsigned int failed = 0;
 
        /* NOTE: kauditd_thread takes care of all our locking, we just use
         *       the netlink info passed to us (e.g. sk and portid) */
 
-       while ((skb = skb_dequeue(queue))) {
+       skb_tail = skb_peek_tail(queue);
+       while ((skb != skb_tail) && (skb = skb_dequeue(queue))) {
                /* call the skb_hook for each skb we touch */
                if (skb_hook)
                        (*skb_hook)(skb);
@@ -731,7 +755,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                /* can we send to anyone via unicast? */
                if (!sk) {
                        if (err_hook)
-                               (*err_hook)(skb);
+                               (*err_hook)(skb, -ECONNREFUSED);
                        continue;
                }
 
@@ -745,7 +769,7 @@ retry:
                            rc == -ECONNREFUSED || rc == -EPERM) {
                                sk = NULL;
                                if (err_hook)
-                                       (*err_hook)(skb);
+                                       (*err_hook)(skb, rc);
                                if (rc == -EAGAIN)
                                        rc = 0;
                                /* continue to drain the queue */
index 0606237..9e4ecc9 100644 (file)
@@ -207,7 +207,7 @@ BTF_ID(func, bpf_lsm_socket_socketpair)
 
 BTF_ID(func, bpf_lsm_syslog)
 BTF_ID(func, bpf_lsm_task_alloc)
-BTF_ID(func, bpf_lsm_task_getsecid_subj)
+BTF_ID(func, bpf_lsm_current_getsecid_subj)
 BTF_ID(func, bpf_lsm_task_getsecid_obj)
 BTF_ID(func, bpf_lsm_task_prctl)
 BTF_ID(func, bpf_lsm_task_setscheduler)
index 638d7fd..710ba9d 100644 (file)
@@ -104,7 +104,7 @@ static struct bpf_ringbuf *bpf_ringbuf_area_alloc(size_t data_sz, int numa_node)
        }
 
        rb = vmap(pages, nr_meta_pages + 2 * nr_data_pages,
-                 VM_ALLOC | VM_USERMAP, PAGE_KERNEL);
+                 VM_MAP | VM_USERMAP, PAGE_KERNEL);
        if (rb) {
                kmemleak_not_leak(pages);
                rb->pages = pages;
index 4b6974a..5e7edf9 100644 (file)
@@ -550,11 +550,12 @@ static __always_inline u64 notrace bpf_prog_start_time(void)
 static void notrace inc_misses_counter(struct bpf_prog *prog)
 {
        struct bpf_prog_stats *stats;
+       unsigned int flags;
 
        stats = this_cpu_ptr(prog->stats);
-       u64_stats_update_begin(&stats->syncp);
+       flags = u64_stats_update_begin_irqsave(&stats->syncp);
        u64_stats_inc(&stats->misses);
-       u64_stats_update_end(&stats->syncp);
+       u64_stats_update_end_irqrestore(&stats->syncp, flags);
 }
 
 /* The logic is similar to bpf_prog_run(), but with an explicit
index 41e0837..0e877db 100644 (file)
@@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
 
        BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
 
+       /*
+        * Release agent gets called with all capabilities,
+        * require capabilities to set release agent.
+        */
+       if ((of->file->f_cred->user_ns != &init_user_ns) ||
+           !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        cgrp = cgroup_kn_lock_live(of->kn, false);
        if (!cgrp)
                return -ENODEV;
@@ -954,6 +962,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
                /* Specifying two release agents is forbidden */
                if (ctx->release_agent)
                        return invalfc(fc, "release_agent respecified");
+               /*
+                * Release agent gets called with all capabilities,
+                * require capabilities to set release agent.
+                */
+               if ((fc->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
+                       return invalfc(fc, "Setting release_agent not allowed");
                ctx->release_agent = param->string;
                param->string = NULL;
                break;
index dc653ab..4c7254e 100644 (file)
@@ -590,6 +590,35 @@ static inline void free_cpuset(struct cpuset *cs)
        kfree(cs);
 }
 
+/*
+ * validate_change_legacy() - Validate conditions specific to legacy (v1)
+ *                            behavior.
+ */
+static int validate_change_legacy(struct cpuset *cur, struct cpuset *trial)
+{
+       struct cgroup_subsys_state *css;
+       struct cpuset *c, *par;
+       int ret;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       /* Each of our child cpusets must be a subset of us */
+       ret = -EBUSY;
+       cpuset_for_each_child(c, css, cur)
+               if (!is_cpuset_subset(c, trial))
+                       goto out;
+
+       /* On legacy hierarchy, we must be a subset of our parent cpuset. */
+       ret = -EACCES;
+       par = parent_cs(cur);
+       if (par && !is_cpuset_subset(trial, par))
+               goto out;
+
+       ret = 0;
+out:
+       return ret;
+}
+
 /*
  * validate_change() - Used to validate that any proposed cpuset change
  *                    follows the structural rules for cpusets.
@@ -614,20 +643,21 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
 {
        struct cgroup_subsys_state *css;
        struct cpuset *c, *par;
-       int ret;
-
-       /* The checks don't apply to root cpuset */
-       if (cur == &top_cpuset)
-               return 0;
+       int ret = 0;
 
        rcu_read_lock();
-       par = parent_cs(cur);
 
-       /* On legacy hierarchy, we must be a subset of our parent cpuset. */
-       ret = -EACCES;
-       if (!is_in_v2_mode() && !is_cpuset_subset(trial, par))
+       if (!is_in_v2_mode())
+               ret = validate_change_legacy(cur, trial);
+       if (ret)
+               goto out;
+
+       /* Remaining checks don't apply to root cpuset */
+       if (cur == &top_cpuset)
                goto out;
 
+       par = parent_cs(cur);
+
        /*
         * If either I or some sibling (!= me) is exclusive, we can't
         * overlap
@@ -1175,9 +1205,7 @@ enum subparts_cmd {
  *
  * Because of the implicit cpu exclusive nature of a partition root,
  * cpumask changes that violates the cpu exclusivity rule will not be
- * permitted when checked by validate_change(). The validate_change()
- * function will also prevent any changes to the cpu list if it is not
- * a superset of children's cpu lists.
+ * permitted when checked by validate_change().
  */
 static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
                                          struct cpumask *newmask,
@@ -1522,10 +1550,15 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
        struct cpuset *sibling;
        struct cgroup_subsys_state *pos_css;
 
+       percpu_rwsem_assert_held(&cpuset_rwsem);
+
        /*
         * Check all its siblings and call update_cpumasks_hier()
         * if their use_parent_ecpus flag is set in order for them
         * to use the right effective_cpus value.
+        *
+        * The update_cpumasks_hier() function may sleep. So we have to
+        * release the RCU read lock before calling it.
         */
        rcu_read_lock();
        cpuset_for_each_child(sibling, pos_css, parent) {
@@ -1533,8 +1566,13 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
                        continue;
                if (!sibling->use_parent_ecpus)
                        continue;
+               if (!css_tryget_online(&sibling->css))
+                       continue;
 
+               rcu_read_unlock();
                update_cpumasks_hier(sibling, tmp);
+               rcu_read_lock();
+               css_put(&sibling->css);
        }
        rcu_read_unlock();
 }
@@ -1607,8 +1645,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
         * Make sure that subparts_cpus is a subset of cpus_allowed.
         */
        if (cs->nr_subparts_cpus) {
-               cpumask_andnot(cs->subparts_cpus, cs->subparts_cpus,
-                              cs->cpus_allowed);
+               cpumask_and(cs->subparts_cpus, cs->subparts_cpus, cs->cpus_allowed);
                cs->nr_subparts_cpus = cpumask_weight(cs->subparts_cpus);
        }
        spin_unlock_irq(&callback_lock);
index 76c754e..57c7197 100644 (file)
@@ -3238,6 +3238,15 @@ static int perf_event_modify_breakpoint(struct perf_event *bp,
        return err;
 }
 
+/*
+ * Copy event-type-independent attributes that may be modified.
+ */
+static void perf_event_modify_copy_attr(struct perf_event_attr *to,
+                                       const struct perf_event_attr *from)
+{
+       to->sig_data = from->sig_data;
+}
+
 static int perf_event_modify_attr(struct perf_event *event,
                                  struct perf_event_attr *attr)
 {
@@ -3260,10 +3269,17 @@ static int perf_event_modify_attr(struct perf_event *event,
        WARN_ON_ONCE(event->ctx->parent_ctx);
 
        mutex_lock(&event->child_mutex);
+       /*
+        * Event-type-independent attributes must be copied before event-type
+        * modification, which will validate that final attributes match the
+        * source attributes after all relevant attributes have been copied.
+        */
+       perf_event_modify_copy_attr(&event->attr, attr);
        err = func(event, attr);
        if (err)
                goto out;
        list_for_each_entry(child, &event->child_list, child_list) {
+               perf_event_modify_copy_attr(&child->attr, attr);
                err = func(child, attr);
                if (err)
                        goto out;
index 24dab04..46a5c2e 100644 (file)
@@ -3725,12 +3725,6 @@ static noinline int do_init_module(struct module *mod)
        }
        freeinit->module_init = mod->init_layout.base;
 
-       /*
-        * We want to find out whether @mod uses async during init.  Clear
-        * PF_USED_ASYNC.  async_schedule*() will set it.
-        */
-       current->flags &= ~PF_USED_ASYNC;
-
        do_mod_ctors(mod);
        /* Start the module */
        if (mod->init != NULL)
@@ -3756,22 +3750,13 @@ static noinline int do_init_module(struct module *mod)
 
        /*
         * We need to finish all async code before the module init sequence
-        * is done.  This has potential to deadlock.  For example, a newly
-        * detected block device can trigger request_module() of the
-        * default iosched from async probing task.  Once userland helper
-        * reaches here, async_synchronize_full() will wait on the async
-        * task waiting on request_module() and deadlock.
-        *
-        * This deadlock is avoided by perfomring async_synchronize_full()
-        * iff module init queued any async jobs.  This isn't a full
-        * solution as it will deadlock the same if module loading from
-        * async jobs nests more than once; however, due to the various
-        * constraints, this hack seems to be the best option for now.
-        * Please refer to the following thread for details.
+        * is done. This has potential to deadlock if synchronous module
+        * loading is requested from async (which is not allowed!).
         *
-        * http://thread.gmane.org/gmane.linux.kernel/1420814
+        * See commit 0fdff3ec6d87 ("async, kmod: warn on synchronous
+        * request_module() from async workers") for more details.
         */
-       if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
+       if (!mod->async_probe_requested)
                async_synchronize_full();
 
        ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base +
index 653ae04..c228343 100644 (file)
@@ -12,7 +12,7 @@
 static const int ten_thousand = 10000;
 
 static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
-                               void __user *buffer, size_t *lenp, loff_t *ppos)
+                               void *buffer, size_t *lenp, loff_t *ppos)
 {
        if (write && !capable(CAP_SYS_ADMIN))
                return -EPERM;
index 66b8af3..ddb5a7f 100644 (file)
@@ -70,7 +70,7 @@ late_initcall(stackleak_sysctls_init);
 #define skip_erasing() false
 #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */
 
-asmlinkage void notrace stackleak_erase(void)
+asmlinkage void noinstr stackleak_erase(void)
 {
        /* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */
        unsigned long kstack_ptr = current->lowest_stack;
@@ -124,9 +124,8 @@ asmlinkage void notrace stackleak_erase(void)
        /* Reset the 'lowest_stack' value for the next syscall */
        current->lowest_stack = current_top_of_stack() - THREAD_SIZE/64;
 }
-NOKPROBE_SYMBOL(stackleak_erase);
 
-void __used __no_caller_saved_registers notrace stackleak_track_stack(void)
+void __used __no_caller_saved_registers noinstr stackleak_track_stack(void)
 {
        unsigned long sp = current_stack_pointer;
 
index 9364f79..c71c096 100644 (file)
 
 void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen)
 {
-       __blake2s_update(state, in, inlen, blake2s_compress);
+       __blake2s_update(state, in, inlen, false);
 }
 EXPORT_SYMBOL(blake2s_update);
 
 void blake2s_final(struct blake2s_state *state, u8 *out)
 {
        WARN_ON(IS_ENABLED(DEBUG) && !out);
-       __blake2s_final(state, out, blake2s_compress);
+       __blake2s_final(state, out, false);
        memzero_explicit(state, sizeof(*state));
 }
 EXPORT_SYMBOL(blake2s_final);
index a7ac97c..db2abd9 100644 (file)
@@ -171,6 +171,8 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
        ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep);
        pte = ptep_get(args->ptep);
        WARN_ON(pte_young(pte));
+
+       ptep_get_and_clear_full(args->mm, args->vaddr, args->ptep, 1);
 }
 
 static void __init pte_savedwrite_tests(struct pgtable_debug_args *args)
index f0af462..a9d4d72 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -124,8 +124,8 @@ static inline struct page *try_get_compound_head(struct page *page, int refs)
  * considered failure, and furthermore, a likely bug in the caller, so a warning
  * is also emitted.
  */
-struct page *try_grab_compound_head(struct page *page,
-                                   int refs, unsigned int flags)
+__maybe_unused struct page *try_grab_compound_head(struct page *page,
+                                                  int refs, unsigned int flags)
 {
        if (flags & FOLL_GET)
                return try_get_compound_head(page, refs);
@@ -208,10 +208,35 @@ static void put_compound_head(struct page *page, int refs, unsigned int flags)
  */
 bool __must_check try_grab_page(struct page *page, unsigned int flags)
 {
-       if (!(flags & (FOLL_GET | FOLL_PIN)))
-               return true;
+       WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN));
 
-       return try_grab_compound_head(page, 1, flags);
+       if (flags & FOLL_GET)
+               return try_get_page(page);
+       else if (flags & FOLL_PIN) {
+               int refs = 1;
+
+               page = compound_head(page);
+
+               if (WARN_ON_ONCE(page_ref_count(page) <= 0))
+                       return false;
+
+               if (hpage_pincount_available(page))
+                       hpage_pincount_add(page, 1);
+               else
+                       refs = GUP_PIN_COUNTING_BIAS;
+
+               /*
+                * Similar to try_grab_compound_head(): even if using the
+                * hpage_pincount_add/_sub() routines, be sure to
+                * *also* increment the normal page refcount field at least
+                * once, so that the page really is pinned.
+                */
+               page_ref_add(page, refs);
+
+               mod_node_page_state(page_pgdat(page), NR_FOLL_PIN_ACQUIRED, 1);
+       }
+
+       return true;
 }
 
 /**
index 35f14d0..131492f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/hashtable.h>
 #include <linux/userfaultfd_k.h>
 #include <linux/page_idle.h>
+#include <linux/page_table_check.h>
 #include <linux/swapops.h>
 #include <linux/shmem_fs.h>
 
@@ -1416,6 +1417,21 @@ static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm,
        return 0;
 }
 
+static void collapse_and_free_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
+                                 unsigned long addr, pmd_t *pmdp)
+{
+       spinlock_t *ptl;
+       pmd_t pmd;
+
+       mmap_assert_write_locked(mm);
+       ptl = pmd_lock(vma->vm_mm, pmdp);
+       pmd = pmdp_collapse_flush(vma, addr, pmdp);
+       spin_unlock(ptl);
+       mm_dec_nr_ptes(mm);
+       page_table_check_pte_clear_range(mm, addr, pmd);
+       pte_free(mm, pmd_pgtable(pmd));
+}
+
 /**
  * collapse_pte_mapped_thp - Try to collapse a pte-mapped THP for mm at
  * address haddr.
@@ -1433,7 +1449,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
        struct vm_area_struct *vma = find_vma(mm, haddr);
        struct page *hpage;
        pte_t *start_pte, *pte;
-       pmd_t *pmd, _pmd;
+       pmd_t *pmd;
        spinlock_t *ptl;
        int count = 0;
        int i;
@@ -1509,12 +1525,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
        }
 
        /* step 4: collapse pmd */
-       ptl = pmd_lock(vma->vm_mm, pmd);
-       _pmd = pmdp_collapse_flush(vma, haddr, pmd);
-       spin_unlock(ptl);
-       mm_dec_nr_ptes(mm);
-       pte_free(mm, pmd_pgtable(_pmd));
-
+       collapse_and_free_pmd(mm, vma, haddr, pmd);
 drop_hpage:
        unlock_page(hpage);
        put_page(hpage);
@@ -1552,7 +1563,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
        struct vm_area_struct *vma;
        struct mm_struct *mm;
        unsigned long addr;
-       pmd_t *pmd, _pmd;
+       pmd_t *pmd;
 
        i_mmap_lock_write(mapping);
        vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
@@ -1591,14 +1602,8 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
                 * reverse order. Trylock is a way to avoid deadlock.
                 */
                if (mmap_write_trylock(mm)) {
-                       if (!khugepaged_test_exit(mm)) {
-                               spinlock_t *ptl = pmd_lock(mm, pmd);
-                               /* assume page table is clear */
-                               _pmd = pmdp_collapse_flush(vma, addr, pmd);
-                               spin_unlock(ptl);
-                               mm_dec_nr_ptes(mm);
-                               pte_free(mm, pmd_pgtable(_pmd));
-                       }
+                       if (!khugepaged_test_exit(mm))
+                               collapse_and_free_pmd(mm, vma, addr, pmd);
                        mmap_write_unlock(mm);
                } else {
                        /* Try again later */
index dc3758f..7580baa 100644 (file)
@@ -1410,7 +1410,8 @@ static void kmemleak_scan(void)
 {
        unsigned long flags;
        struct kmemleak_object *object;
-       int i;
+       struct zone *zone;
+       int __maybe_unused i;
        int new_leaks = 0;
 
        jiffies_last_scan = jiffies;
@@ -1450,9 +1451,9 @@ static void kmemleak_scan(void)
         * Struct page scanning for each node.
         */
        get_online_mems();
-       for_each_online_node(i) {
-               unsigned long start_pfn = node_start_pfn(i);
-               unsigned long end_pfn = node_end_pfn(i);
+       for_each_populated_zone(zone) {
+               unsigned long start_pfn = zone->zone_start_pfn;
+               unsigned long end_pfn = zone_end_pfn(zone);
                unsigned long pfn;
 
                for (pfn = start_pfn; pfn < end_pfn; pfn++) {
@@ -1461,8 +1462,8 @@ static void kmemleak_scan(void)
                        if (!page)
                                continue;
 
-                       /* only scan pages belonging to this node */
-                       if (page_to_nid(page) != i)
+                       /* only scan pages belonging to this zone */
+                       if (page_zone(page) != zone)
                                continue;
                        /* only scan if page is in use */
                        if (page_count(page) == 0)
index 6a0ddda..f67c4c7 100644 (file)
@@ -115,7 +115,7 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
         * onlining - just onlined memory won't immediately be considered for
         * allocation.
         */
-       if (!isolated_page && PageBuddy(page)) {
+       if (!isolated_page) {
                nr_pages = move_freepages_block(zone, page, migratetype, NULL);
                __mod_zone_freepage_state(zone, nr_pages, migratetype);
        }
index 7504e7c..3763bd0 100644 (file)
@@ -86,8 +86,8 @@ static void page_table_check_clear(struct mm_struct *mm, unsigned long addr,
 {
        struct page_ext *page_ext;
        struct page *page;
+       unsigned long i;
        bool anon;
-       int i;
 
        if (!pfn_valid(pfn))
                return;
@@ -121,8 +121,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 {
        struct page_ext *page_ext;
        struct page *page;
+       unsigned long i;
        bool anon;
-       int i;
 
        if (!pfn_valid(pfn))
                return;
@@ -152,10 +152,10 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 void __page_table_check_zero(struct page *page, unsigned int order)
 {
        struct page_ext *page_ext = lookup_page_ext(page);
-       int i;
+       unsigned long i;
 
        BUG_ON(!page_ext);
-       for (i = 0; i < (1 << order); i++) {
+       for (i = 0; i < (1ul << order); i++) {
                struct page_table_check *ptc = get_page_table_check(page_ext);
 
                BUG_ON(atomic_read(&ptc->anon_map_count));
@@ -206,17 +206,10 @@ EXPORT_SYMBOL(__page_table_check_pud_clear);
 void __page_table_check_pte_set(struct mm_struct *mm, unsigned long addr,
                                pte_t *ptep, pte_t pte)
 {
-       pte_t old_pte;
-
        if (&init_mm == mm)
                return;
 
-       old_pte = *ptep;
-       if (pte_user_accessible_page(old_pte)) {
-               page_table_check_clear(mm, addr, pte_pfn(old_pte),
-                                      PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pte_clear(mm, addr, *ptep);
        if (pte_user_accessible_page(pte)) {
                page_table_check_set(mm, addr, pte_pfn(pte),
                                     PAGE_SIZE >> PAGE_SHIFT,
@@ -228,17 +221,10 @@ EXPORT_SYMBOL(__page_table_check_pte_set);
 void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd)
 {
-       pmd_t old_pmd;
-
        if (&init_mm == mm)
                return;
 
-       old_pmd = *pmdp;
-       if (pmd_user_accessible_page(old_pmd)) {
-               page_table_check_clear(mm, addr, pmd_pfn(old_pmd),
-                                      PMD_PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pmd_clear(mm, addr, *pmdp);
        if (pmd_user_accessible_page(pmd)) {
                page_table_check_set(mm, addr, pmd_pfn(pmd),
                                     PMD_PAGE_SIZE >> PAGE_SHIFT,
@@ -250,17 +236,10 @@ EXPORT_SYMBOL(__page_table_check_pmd_set);
 void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud)
 {
-       pud_t old_pud;
-
        if (&init_mm == mm)
                return;
 
-       old_pud = *pudp;
-       if (pud_user_accessible_page(old_pud)) {
-               page_table_check_clear(mm, addr, pud_pfn(old_pud),
-                                      PUD_PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pud_clear(mm, addr, *pudp);
        if (pud_user_accessible_page(pud)) {
                page_table_check_set(mm, addr, pud_pfn(pud),
                                     PUD_PAGE_SIZE >> PAGE_SHIFT,
@@ -268,3 +247,23 @@ void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
        }
 }
 EXPORT_SYMBOL(__page_table_check_pud_set);
+
+void __page_table_check_pte_clear_range(struct mm_struct *mm,
+                                       unsigned long addr,
+                                       pmd_t pmd)
+{
+       if (&init_mm == mm)
+               return;
+
+       if (!pmd_bad(pmd) && !pmd_leaf(pmd)) {
+               pte_t *ptep = pte_offset_map(&pmd, addr);
+               unsigned long i;
+
+               pte_unmap(ptep);
+               for (i = 0; i < PTRS_PER_PTE; i++) {
+                       __page_table_check_pte_clear(mm, addr, *ptep);
+                       addr += PAGE_SIZE;
+                       ptep++;
+               }
+       }
+}
index 02f43f3..3e49d28 100644 (file)
@@ -77,6 +77,7 @@ static void ax25_kill_by_device(struct net_device *dev)
 {
        ax25_dev *ax25_dev;
        ax25_cb *s;
+       struct sock *sk;
 
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
                return;
@@ -85,13 +86,16 @@ static void ax25_kill_by_device(struct net_device *dev)
 again:
        ax25_for_each(s, &ax25_list) {
                if (s->ax25_dev == ax25_dev) {
+                       sk = s->sk;
+                       sock_hold(sk);
                        spin_unlock_bh(&ax25_list_lock);
-                       lock_sock(s->sk);
+                       lock_sock(sk);
                        s->ax25_dev = NULL;
-                       release_sock(s->sk);
+                       ax25_dev_put(ax25_dev);
+                       release_sock(sk);
                        ax25_disconnect(s, ENETUNREACH);
                        spin_lock_bh(&ax25_list_lock);
-
+                       sock_put(sk);
                        /* The entry could have been deleted from the
                         * list meanwhile and thus the next pointer is
                         * no longer valid.  Play it safe and restart
@@ -355,21 +359,25 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
        if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
                return -EFAULT;
 
-       if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
-               return -ENODEV;
-
        if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
        if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
                return -EINVAL;
 
+       ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
+       if (!ax25_dev)
+               return -ENODEV;
+
        digi.ndigi = ax25_ctl.digi_count;
        for (k = 0; k < digi.ndigi; k++)
                digi.calls[k] = ax25_ctl.digi_addr[k];
 
-       if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL)
+       ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
+       if (!ax25) {
+               ax25_dev_put(ax25_dev);
                return -ENOTCONN;
+       }
 
        switch (ax25_ctl.cmd) {
        case AX25_KILL:
@@ -436,6 +444,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
          }
 
 out_put:
+       ax25_dev_put(ax25_dev);
        ax25_cb_put(ax25);
        return ret;
 
index 256fadb..d2a244e 100644 (file)
@@ -37,6 +37,7 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
        for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
                if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) {
                        res = ax25_dev;
+                       ax25_dev_hold(ax25_dev);
                }
        spin_unlock_bh(&ax25_dev_lock);
 
@@ -56,6 +57,7 @@ void ax25_dev_device_up(struct net_device *dev)
                return;
        }
 
+       refcount_set(&ax25_dev->refcount, 1);
        dev->ax25_ptr     = ax25_dev;
        ax25_dev->dev     = dev;
        dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
@@ -84,6 +86,7 @@ void ax25_dev_device_up(struct net_device *dev)
        ax25_dev->next = ax25_dev_list;
        ax25_dev_list  = ax25_dev;
        spin_unlock_bh(&ax25_dev_lock);
+       ax25_dev_hold(ax25_dev);
 
        ax25_register_dev_sysctl(ax25_dev);
 }
@@ -113,9 +116,10 @@ void ax25_dev_device_down(struct net_device *dev)
        if ((s = ax25_dev_list) == ax25_dev) {
                ax25_dev_list = s->next;
                spin_unlock_bh(&ax25_dev_lock);
+               ax25_dev_put(ax25_dev);
                dev->ax25_ptr = NULL;
                dev_put_track(dev, &ax25_dev->dev_tracker);
-               kfree(ax25_dev);
+               ax25_dev_put(ax25_dev);
                return;
        }
 
@@ -123,9 +127,10 @@ void ax25_dev_device_down(struct net_device *dev)
                if (s->next == ax25_dev) {
                        s->next = ax25_dev->next;
                        spin_unlock_bh(&ax25_dev_lock);
+                       ax25_dev_put(ax25_dev);
                        dev->ax25_ptr = NULL;
                        dev_put_track(dev, &ax25_dev->dev_tracker);
-                       kfree(ax25_dev);
+                       ax25_dev_put(ax25_dev);
                        return;
                }
 
@@ -133,6 +138,7 @@ void ax25_dev_device_down(struct net_device *dev)
        }
        spin_unlock_bh(&ax25_dev_lock);
        dev->ax25_ptr = NULL;
+       ax25_dev_put(ax25_dev);
 }
 
 int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
@@ -144,20 +150,32 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
 
        switch (cmd) {
        case SIOCAX25ADDFWD:
-               if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
+               fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
+               if (!fwd_dev) {
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
-               if (ax25_dev->forward != NULL)
+               }
+               if (ax25_dev->forward) {
+                       ax25_dev_put(fwd_dev);
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
+               }
                ax25_dev->forward = fwd_dev->dev;
+               ax25_dev_put(fwd_dev);
+               ax25_dev_put(ax25_dev);
                break;
 
        case SIOCAX25DELFWD:
-               if (ax25_dev->forward == NULL)
+               if (!ax25_dev->forward) {
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
+               }
                ax25_dev->forward = NULL;
+               ax25_dev_put(ax25_dev);
                break;
 
        default:
+               ax25_dev_put(ax25_dev);
                return -EINVAL;
        }
 
index d0b2e09..9751207 100644 (file)
@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
        ax25_dev *ax25_dev;
        int i;
 
-       if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
-               return -EINVAL;
        if (route->digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
+       ax25_dev = ax25_addr_ax25dev(&route->port_addr);
+       if (!ax25_dev)
+               return -EINVAL;
+
        write_lock_bh(&ax25_route_lock);
 
        ax25_rt = ax25_route_list;
@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                        if (route->digi_count != 0) {
                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                                        write_unlock_bh(&ax25_route_lock);
+                                       ax25_dev_put(ax25_dev);
                                        return -ENOMEM;
                                }
                                ax25_rt->digipeat->lastrepeat = -1;
@@ -101,6 +104,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                                }
                        }
                        write_unlock_bh(&ax25_route_lock);
+                       ax25_dev_put(ax25_dev);
                        return 0;
                }
                ax25_rt = ax25_rt->next;
@@ -108,6 +112,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
 
        if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
                write_unlock_bh(&ax25_route_lock);
+               ax25_dev_put(ax25_dev);
                return -ENOMEM;
        }
 
@@ -120,6 +125,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                        write_unlock_bh(&ax25_route_lock);
                        kfree(ax25_rt);
+                       ax25_dev_put(ax25_dev);
                        return -ENOMEM;
                }
                ax25_rt->digipeat->lastrepeat = -1;
@@ -132,6 +138,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
        ax25_rt->next   = ax25_route_list;
        ax25_route_list = ax25_rt;
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
 
        return 0;
 }
@@ -173,6 +180,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
                }
        }
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
 
        return 0;
 }
@@ -215,6 +223,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
 
 out:
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
        return err;
 }
 
index eba0efe..fbf858d 100644 (file)
@@ -49,7 +49,7 @@ static void nft_reject_br_send_v4_tcp_reset(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, dev, hook);
+       nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, NULL, hook);
        if (!nskb)
                return;
 
@@ -65,7 +65,7 @@ static void nft_reject_br_send_v4_unreach(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v4_unreach(net, oldskb, dev, hook, code);
+       nskb = nf_reject_skb_v4_unreach(net, oldskb, NULL, hook, code);
        if (!nskb)
                return;
 
@@ -81,7 +81,7 @@ static void nft_reject_br_send_v6_tcp_reset(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, dev, hook);
+       nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, NULL, hook);
        if (!nskb)
                return;
 
@@ -98,7 +98,7 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v6_unreach(net, oldskb, dev, hook, code);
+       nskb = nf_reject_skb_v6_unreach(net, oldskb, NULL, hook, code);
        if (!nskb)
                return;
 
index ecc400a..4c64415 100644 (file)
@@ -246,6 +246,7 @@ enum {
        Opt_cephx_sign_messages,
        Opt_tcp_nodelay,
        Opt_abort_on_full,
+       Opt_rxbounce,
 };
 
 enum {
@@ -295,6 +296,7 @@ static const struct fs_parameter_spec ceph_parameters[] = {
        fsparam_u32     ("osdkeepalive",                Opt_osdkeepalivetimeout),
        fsparam_enum    ("read_from_replica",           Opt_read_from_replica,
                         ceph_param_read_from_replica),
+       fsparam_flag    ("rxbounce",                    Opt_rxbounce),
        fsparam_enum    ("ms_mode",                     Opt_ms_mode,
                         ceph_param_ms_mode),
        fsparam_string  ("secret",                      Opt_secret),
@@ -584,6 +586,9 @@ int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt,
        case Opt_abort_on_full:
                opt->flags |= CEPH_OPT_ABORT_ON_FULL;
                break;
+       case Opt_rxbounce:
+               opt->flags |= CEPH_OPT_RXBOUNCE;
+               break;
 
        default:
                BUG();
@@ -660,6 +665,8 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client,
                seq_puts(m, "notcp_nodelay,");
        if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL))
                seq_puts(m, "abort_on_full,");
+       if (opt->flags & CEPH_OPT_RXBOUNCE)
+               seq_puts(m, "rxbounce,");
 
        if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
                seq_printf(m, "mount_timeout=%d,",
index 45eba2d..d3bb656 100644 (file)
@@ -515,6 +515,10 @@ static void ceph_con_reset_protocol(struct ceph_connection *con)
                ceph_msg_put(con->out_msg);
                con->out_msg = NULL;
        }
+       if (con->bounce_page) {
+               __free_page(con->bounce_page);
+               con->bounce_page = NULL;
+       }
 
        if (ceph_msgr2(from_msgr(con->msgr)))
                ceph_con_v2_reset_protocol(con);
index 2cb5ffd..6b014ec 100644 (file)
@@ -992,8 +992,7 @@ static int read_partial_message_section(struct ceph_connection *con,
 
 static int read_partial_msg_data(struct ceph_connection *con)
 {
-       struct ceph_msg *msg = con->in_msg;
-       struct ceph_msg_data_cursor *cursor = &msg->cursor;
+       struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
        bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
        struct page *page;
        size_t page_offset;
@@ -1001,9 +1000,6 @@ static int read_partial_msg_data(struct ceph_connection *con)
        u32 crc = 0;
        int ret;
 
-       if (!msg->num_data_items)
-               return -EIO;
-
        if (do_datacrc)
                crc = con->in_data_crc;
        while (cursor->total_resid) {
@@ -1031,6 +1027,46 @@ static int read_partial_msg_data(struct ceph_connection *con)
        return 1;       /* must return > 0 to indicate success */
 }
 
+static int read_partial_msg_data_bounce(struct ceph_connection *con)
+{
+       struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
+       struct page *page;
+       size_t off, len;
+       u32 crc;
+       int ret;
+
+       if (unlikely(!con->bounce_page)) {
+               con->bounce_page = alloc_page(GFP_NOIO);
+               if (!con->bounce_page) {
+                       pr_err("failed to allocate bounce page\n");
+                       return -ENOMEM;
+               }
+       }
+
+       crc = con->in_data_crc;
+       while (cursor->total_resid) {
+               if (!cursor->resid) {
+                       ceph_msg_data_advance(cursor, 0);
+                       continue;
+               }
+
+               page = ceph_msg_data_next(cursor, &off, &len, NULL);
+               ret = ceph_tcp_recvpage(con->sock, con->bounce_page, 0, len);
+               if (ret <= 0) {
+                       con->in_data_crc = crc;
+                       return ret;
+               }
+
+               crc = crc32c(crc, page_address(con->bounce_page), ret);
+               memcpy_to_page(page, off, page_address(con->bounce_page), ret);
+
+               ceph_msg_data_advance(cursor, ret);
+       }
+       con->in_data_crc = crc;
+
+       return 1;       /* must return > 0 to indicate success */
+}
+
 /*
  * read (part of) a message.
  */
@@ -1141,7 +1177,13 @@ static int read_partial_message(struct ceph_connection *con)
 
        /* (page) data */
        if (data_len) {
-               ret = read_partial_msg_data(con);
+               if (!m->num_data_items)
+                       return -EIO;
+
+               if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE))
+                       ret = read_partial_msg_data_bounce(con);
+               else
+                       ret = read_partial_msg_data(con);
                if (ret <= 0)
                        return ret;
        }
index c4099b6..c81379f 100644 (file)
@@ -57,8 +57,9 @@
 #define IN_S_HANDLE_CONTROL_REMAINDER  3
 #define IN_S_PREPARE_READ_DATA         4
 #define IN_S_PREPARE_READ_DATA_CONT    5
-#define IN_S_HANDLE_EPILOGUE           6
-#define IN_S_FINISH_SKIP               7
+#define IN_S_PREPARE_READ_ENC_PAGE     6
+#define IN_S_HANDLE_EPILOGUE           7
+#define IN_S_FINISH_SKIP               8
 
 #define OUT_S_QUEUE_DATA               1
 #define OUT_S_QUEUE_DATA_CONT          2
@@ -1032,22 +1033,41 @@ static int decrypt_control_remainder(struct ceph_connection *con)
                         padded_len(rem_len) + CEPH_GCM_TAG_LEN);
 }
 
-static int decrypt_message(struct ceph_connection *con)
+static int decrypt_tail(struct ceph_connection *con)
 {
+       struct sg_table enc_sgt = {};
        struct sg_table sgt = {};
+       int tail_len;
        int ret;
 
+       tail_len = tail_onwire_len(con->in_msg, true);
+       ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages,
+                                       con->v2.in_enc_page_cnt, 0, tail_len,
+                                       GFP_NOIO);
+       if (ret)
+               goto out;
+
        ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf),
                        MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf),
                        con->v2.in_buf, true);
        if (ret)
                goto out;
 
-       ret = gcm_crypt(con, false, sgt.sgl, sgt.sgl,
-                       tail_onwire_len(con->in_msg, true));
+       dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con,
+            con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents);
+       ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len);
+       if (ret)
+               goto out;
+
+       WARN_ON(!con->v2.in_enc_page_cnt);
+       ceph_release_page_vector(con->v2.in_enc_pages,
+                                con->v2.in_enc_page_cnt);
+       con->v2.in_enc_pages = NULL;
+       con->v2.in_enc_page_cnt = 0;
 
 out:
        sg_free_table(&sgt);
+       sg_free_table(&enc_sgt);
        return ret;
 }
 
@@ -1733,54 +1753,157 @@ static int prepare_read_control_remainder(struct ceph_connection *con)
        return 0;
 }
 
-static void prepare_read_data(struct ceph_connection *con)
+static int prepare_read_data(struct ceph_connection *con)
 {
        struct bio_vec bv;
 
-       if (!con_secure(con))
-               con->in_data_crc = -1;
+       con->in_data_crc = -1;
        ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg,
                                  data_len(con->in_msg));
 
        get_bvec_at(&con->v2.in_cursor, &bv);
-       set_in_bvec(con, &bv);
+       if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+               if (unlikely(!con->bounce_page)) {
+                       con->bounce_page = alloc_page(GFP_NOIO);
+                       if (!con->bounce_page) {
+                               pr_err("failed to allocate bounce page\n");
+                               return -ENOMEM;
+                       }
+               }
+
+               bv.bv_page = con->bounce_page;
+               bv.bv_offset = 0;
+               set_in_bvec(con, &bv);
+       } else {
+               set_in_bvec(con, &bv);
+       }
        con->v2.in_state = IN_S_PREPARE_READ_DATA_CONT;
+       return 0;
 }
 
 static void prepare_read_data_cont(struct ceph_connection *con)
 {
        struct bio_vec bv;
 
-       if (!con_secure(con))
+       if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+               con->in_data_crc = crc32c(con->in_data_crc,
+                                         page_address(con->bounce_page),
+                                         con->v2.in_bvec.bv_len);
+
+               get_bvec_at(&con->v2.in_cursor, &bv);
+               memcpy_to_page(bv.bv_page, bv.bv_offset,
+                              page_address(con->bounce_page),
+                              con->v2.in_bvec.bv_len);
+       } else {
                con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
                                                    con->v2.in_bvec.bv_page,
                                                    con->v2.in_bvec.bv_offset,
                                                    con->v2.in_bvec.bv_len);
+       }
 
        ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len);
        if (con->v2.in_cursor.total_resid) {
                get_bvec_at(&con->v2.in_cursor, &bv);
-               set_in_bvec(con, &bv);
+               if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+                       bv.bv_page = con->bounce_page;
+                       bv.bv_offset = 0;
+                       set_in_bvec(con, &bv);
+               } else {
+                       set_in_bvec(con, &bv);
+               }
                WARN_ON(con->v2.in_state != IN_S_PREPARE_READ_DATA_CONT);
                return;
        }
 
        /*
-        * We've read all data.  Prepare to read data padding (if any)
-        * and epilogue.
+        * We've read all data.  Prepare to read epilogue.
         */
        reset_in_kvecs(con);
-       if (con_secure(con)) {
-               if (need_padding(data_len(con->in_msg)))
-                       add_in_kvec(con, DATA_PAD(con->v2.in_buf),
-                                   padding_len(data_len(con->in_msg)));
-               add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_SECURE_LEN);
+       add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
+       con->v2.in_state = IN_S_HANDLE_EPILOGUE;
+}
+
+static int prepare_read_tail_plain(struct ceph_connection *con)
+{
+       struct ceph_msg *msg = con->in_msg;
+
+       if (!front_len(msg) && !middle_len(msg)) {
+               WARN_ON(!data_len(msg));
+               return prepare_read_data(con);
+       }
+
+       reset_in_kvecs(con);
+       if (front_len(msg)) {
+               add_in_kvec(con, msg->front.iov_base, front_len(msg));
+               WARN_ON(msg->front.iov_len != front_len(msg));
+       }
+       if (middle_len(msg)) {
+               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
+               WARN_ON(msg->middle->vec.iov_len != middle_len(msg));
+       }
+
+       if (data_len(msg)) {
+               con->v2.in_state = IN_S_PREPARE_READ_DATA;
        } else {
                add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
+               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
        }
+       return 0;
+}
+
+static void prepare_read_enc_page(struct ceph_connection *con)
+{
+       struct bio_vec bv;
+
+       dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i,
+            con->v2.in_enc_resid);
+       WARN_ON(!con->v2.in_enc_resid);
+
+       bv.bv_page = con->v2.in_enc_pages[con->v2.in_enc_i];
+       bv.bv_offset = 0;
+       bv.bv_len = min(con->v2.in_enc_resid, (int)PAGE_SIZE);
+
+       set_in_bvec(con, &bv);
+       con->v2.in_enc_i++;
+       con->v2.in_enc_resid -= bv.bv_len;
+
+       if (con->v2.in_enc_resid) {
+               con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE;
+               return;
+       }
+
+       /*
+        * We are set to read the last piece of ciphertext (ending
+        * with epilogue) + auth tag.
+        */
+       WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt);
        con->v2.in_state = IN_S_HANDLE_EPILOGUE;
 }
 
+static int prepare_read_tail_secure(struct ceph_connection *con)
+{
+       struct page **enc_pages;
+       int enc_page_cnt;
+       int tail_len;
+
+       tail_len = tail_onwire_len(con->in_msg, true);
+       WARN_ON(!tail_len);
+
+       enc_page_cnt = calc_pages_for(0, tail_len);
+       enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
+       if (IS_ERR(enc_pages))
+               return PTR_ERR(enc_pages);
+
+       WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt);
+       con->v2.in_enc_pages = enc_pages;
+       con->v2.in_enc_page_cnt = enc_page_cnt;
+       con->v2.in_enc_resid = tail_len;
+       con->v2.in_enc_i = 0;
+
+       prepare_read_enc_page(con);
+       return 0;
+}
+
 static void __finish_skip(struct ceph_connection *con)
 {
        con->in_seq++;
@@ -2589,47 +2712,26 @@ static int __handle_control(struct ceph_connection *con, void *p)
        }
 
        msg = con->in_msg;  /* set in process_message_header() */
-       if (!front_len(msg) && !middle_len(msg)) {
-               if (!data_len(msg))
-                       return process_message(con);
-
-               prepare_read_data(con);
-               return 0;
-       }
-
-       reset_in_kvecs(con);
        if (front_len(msg)) {
                WARN_ON(front_len(msg) > msg->front_alloc_len);
-               add_in_kvec(con, msg->front.iov_base, front_len(msg));
                msg->front.iov_len = front_len(msg);
-
-               if (con_secure(con) && need_padding(front_len(msg)))
-                       add_in_kvec(con, FRONT_PAD(con->v2.in_buf),
-                                   padding_len(front_len(msg)));
        } else {
                msg->front.iov_len = 0;
        }
        if (middle_len(msg)) {
                WARN_ON(middle_len(msg) > msg->middle->alloc_len);
-               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
                msg->middle->vec.iov_len = middle_len(msg);
-
-               if (con_secure(con) && need_padding(middle_len(msg)))
-                       add_in_kvec(con, MIDDLE_PAD(con->v2.in_buf),
-                                   padding_len(middle_len(msg)));
        } else if (msg->middle) {
                msg->middle->vec.iov_len = 0;
        }
 
-       if (data_len(msg)) {
-               con->v2.in_state = IN_S_PREPARE_READ_DATA;
-       } else {
-               add_in_kvec(con, con->v2.in_buf,
-                           con_secure(con) ? CEPH_EPILOGUE_SECURE_LEN :
-                                             CEPH_EPILOGUE_PLAIN_LEN);
-               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
-       }
-       return 0;
+       if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
+               return process_message(con);
+
+       if (con_secure(con))
+               return prepare_read_tail_secure(con);
+
+       return prepare_read_tail_plain(con);
 }
 
 static int handle_preamble(struct ceph_connection *con)
@@ -2717,7 +2819,7 @@ static int handle_epilogue(struct ceph_connection *con)
        int ret;
 
        if (con_secure(con)) {
-               ret = decrypt_message(con);
+               ret = decrypt_tail(con);
                if (ret) {
                        if (ret == -EBADMSG)
                                con->error_msg = "integrity error, bad epilogue auth tag";
@@ -2785,13 +2887,16 @@ static int populate_in_iter(struct ceph_connection *con)
                        ret = handle_control_remainder(con);
                        break;
                case IN_S_PREPARE_READ_DATA:
-                       prepare_read_data(con);
-                       ret = 0;
+                       ret = prepare_read_data(con);
                        break;
                case IN_S_PREPARE_READ_DATA_CONT:
                        prepare_read_data_cont(con);
                        ret = 0;
                        break;
+               case IN_S_PREPARE_READ_ENC_PAGE:
+                       prepare_read_enc_page(con);
+                       ret = 0;
+                       break;
                case IN_S_HANDLE_EPILOGUE:
                        ret = handle_epilogue(con);
                        break;
@@ -3326,20 +3431,16 @@ void ceph_con_v2_revoke(struct ceph_connection *con)
 
 static void revoke_at_prepare_read_data(struct ceph_connection *con)
 {
-       int remaining;  /* data + [data padding] + epilogue */
+       int remaining;
        int resid;
 
+       WARN_ON(con_secure(con));
        WARN_ON(!data_len(con->in_msg));
        WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
        WARN_ON(!resid);
 
-       if (con_secure(con))
-               remaining = padded_len(data_len(con->in_msg)) +
-                           CEPH_EPILOGUE_SECURE_LEN;
-       else
-               remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
-
+       remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
        dout("%s con %p resid %d remaining %d\n", __func__, con, resid,
             remaining);
        con->v2.in_iter.count -= resid;
@@ -3350,8 +3451,9 @@ static void revoke_at_prepare_read_data(struct ceph_connection *con)
 static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
 {
        int recved, resid;  /* current piece of data */
-       int remaining;  /* [data padding] + epilogue */
+       int remaining;
 
+       WARN_ON(con_secure(con));
        WARN_ON(!data_len(con->in_msg));
        WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
@@ -3363,12 +3465,7 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
                ceph_msg_data_advance(&con->v2.in_cursor, recved);
        WARN_ON(resid > con->v2.in_cursor.total_resid);
 
-       if (con_secure(con))
-               remaining = padding_len(data_len(con->in_msg)) +
-                           CEPH_EPILOGUE_SECURE_LEN;
-       else
-               remaining = CEPH_EPILOGUE_PLAIN_LEN;
-
+       remaining = CEPH_EPILOGUE_PLAIN_LEN;
        dout("%s con %p total_resid %zu remaining %d\n", __func__, con,
             con->v2.in_cursor.total_resid, remaining);
        con->v2.in_iter.count -= resid;
@@ -3376,11 +3473,26 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
        con->v2.in_state = IN_S_FINISH_SKIP;
 }
 
+static void revoke_at_prepare_read_enc_page(struct ceph_connection *con)
+{
+       int resid;  /* current enc page (not necessarily data) */
+
+       WARN_ON(!con_secure(con));
+       WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
+       resid = iov_iter_count(&con->v2.in_iter);
+       WARN_ON(!resid || resid > con->v2.in_bvec.bv_len);
+
+       dout("%s con %p resid %d enc_resid %d\n", __func__, con, resid,
+            con->v2.in_enc_resid);
+       con->v2.in_iter.count -= resid;
+       set_in_skip(con, resid + con->v2.in_enc_resid);
+       con->v2.in_state = IN_S_FINISH_SKIP;
+}
+
 static void revoke_at_handle_epilogue(struct ceph_connection *con)
 {
        int resid;
 
-       WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
        WARN_ON(!resid);
 
@@ -3399,6 +3511,9 @@ void ceph_con_v2_revoke_incoming(struct ceph_connection *con)
        case IN_S_PREPARE_READ_DATA_CONT:
                revoke_at_prepare_read_data_cont(con);
                break;
+       case IN_S_PREPARE_READ_ENC_PAGE:
+               revoke_at_prepare_read_enc_page(con);
+               break;
        case IN_S_HANDLE_EPILOGUE:
                revoke_at_handle_epilogue(con);
                break;
@@ -3432,6 +3547,13 @@ void ceph_con_v2_reset_protocol(struct ceph_connection *con)
        clear_out_sign_kvecs(con);
        free_conn_bufs(con);
 
+       if (con->v2.in_enc_pages) {
+               WARN_ON(!con->v2.in_enc_page_cnt);
+               ceph_release_page_vector(con->v2.in_enc_pages,
+                                        con->v2.in_enc_page_cnt);
+               con->v2.in_enc_pages = NULL;
+               con->v2.in_enc_page_cnt = 0;
+       }
        if (con->v2.out_enc_pages) {
                WARN_ON(!con->v2.out_enc_page_cnt);
                ceph_release_page_vector(con->v2.out_enc_pages,
index 6c2016f..ec0bf73 100644 (file)
@@ -1133,7 +1133,8 @@ out:
        neigh_release(neigh);
 }
 
-int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
+                      const bool immediate_ok)
 {
        int rc;
        bool immediate_probe = false;
@@ -1154,12 +1155,17 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        atomic_set(&neigh->probes,
                                   NEIGH_VAR(neigh->parms, UCAST_PROBES));
                        neigh_del_timer(neigh);
-                       neigh->nud_state     = NUD_INCOMPLETE;
+                       neigh->nud_state = NUD_INCOMPLETE;
                        neigh->updated = now;
-                       next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
-                                        HZ/100);
+                       if (!immediate_ok) {
+                               next = now + 1;
+                       } else {
+                               immediate_probe = true;
+                               next = now + max(NEIGH_VAR(neigh->parms,
+                                                          RETRANS_TIME),
+                                                HZ / 100);
+                       }
                        neigh_add_timer(neigh, next);
-                       immediate_probe = true;
                } else {
                        neigh->nud_state = NUD_FAILED;
                        neigh->updated = jiffies;
@@ -1571,7 +1577,7 @@ static void neigh_managed_work(struct work_struct *work)
 
        write_lock_bh(&tbl->lock);
        list_for_each_entry(neigh, &tbl->managed_list, managed_list)
-               neigh_event_send(neigh, NULL);
+               neigh_event_send_probe(neigh, NULL, false);
        queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
                           NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME));
        write_unlock_bh(&tbl->lock);
index e476403..710da8a 100644 (file)
@@ -3275,8 +3275,8 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
        unsigned char name_assign_type = NET_NAME_USER;
        struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
-       const struct rtnl_link_ops *m_ops = NULL;
-       struct net_device *master_dev = NULL;
+       const struct rtnl_link_ops *m_ops;
+       struct net_device *master_dev;
        struct net *net = sock_net(skb->sk);
        const struct rtnl_link_ops *ops;
        struct nlattr *tb[IFLA_MAX + 1];
@@ -3314,6 +3314,8 @@ replay:
        else
                dev = NULL;
 
+       master_dev = NULL;
+       m_ops = NULL;
        if (dev) {
                master_dev = netdev_master_upper_dev_get(dev);
                if (master_dev)
index 277124f..e0b072a 100644 (file)
@@ -1441,7 +1441,7 @@ static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1634,7 +1634,7 @@ static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1812,7 +1812,7 @@ static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1988,7 +1988,7 @@ static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
index 67087f9..aab3841 100644 (file)
@@ -58,10 +58,6 @@ config NF_TABLES_ARP
 
 endif # NF_TABLES
 
-config NF_FLOW_TABLE_IPV4
-       tristate
-       select NF_FLOW_TABLE_INET
-
 config NF_DUP_IPV4
        tristate "Netfilter IPv4 packet duplication to alternate destination"
        depends on !NF_CONNTRACK || NF_CONNTRACK
index 78e8146..bdf108f 100644 (file)
@@ -1322,10 +1322,13 @@ new_segment:
 
                        /* skb changing from pure zc to mixed, must charge zc */
                        if (unlikely(skb_zcopy_pure(skb))) {
-                               if (!sk_wmem_schedule(sk, skb->data_len))
+                               u32 extra = skb->truesize -
+                                           SKB_TRUESIZE(skb_end_offset(skb));
+
+                               if (!sk_wmem_schedule(sk, extra))
                                        goto wait_for_space;
 
-                               sk_mem_charge(sk, skb->data_len);
+                               sk_mem_charge(sk, extra);
                                skb_shinfo(skb)->flags &= ~SKBFL_PURE_ZEROCOPY;
                        }
 
index dc49a3d..bfe4112 100644 (file)
@@ -1660,6 +1660,8 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
            (mss != tcp_skb_seglen(skb)))
                goto out;
 
+       if (!tcp_skb_can_collapse(prev, skb))
+               goto out;
        len = skb->len;
        pcount = tcp_skb_pcount(skb);
        if (tcp_skb_shift(prev, skb, pcount, len))
index 97d3d1b..0ba62f4 100644 (file)
@@ -47,10 +47,6 @@ config NFT_FIB_IPV6
 endif # NF_TABLES_IPV6
 endif # NF_TABLES
 
-config NF_FLOW_TABLE_IPV6
-       tristate
-       select NF_FLOW_TABLE_INET
-
 config NF_DUP_IPV6
        tristate "Netfilter IPv6 packet duplication to alternate destination"
        depends on !NF_CONNTRACK || NF_CONNTRACK
index b853836..b8d6dc9 100644 (file)
@@ -28,9 +28,6 @@ obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
 obj-$(CONFIG_NFT_DUP_IPV6) += nft_dup_ipv6.o
 obj-$(CONFIG_NFT_FIB_IPV6) += nft_fib_ipv6.o
 
-# flow table support
-obj-$(CONFIG_NF_FLOW_TABLE_IPV6) += nf_flow_table_ipv6.o
-
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
diff --git a/net/ipv6/netfilter/nf_flow_table_ipv6.c b/net/ipv6/netfilter/nf_flow_table_ipv6.c
deleted file mode 100644 (file)
index e69de29..0000000
index cf454f8..5fa1699 100644 (file)
@@ -2011,7 +2011,6 @@ static void nft_last_rule(struct nft_rule_blob *blob, const void *ptr)
 
        prule = (struct nft_rule_dp *)ptr;
        prule->is_last = 1;
-       ptr += offsetof(struct nft_rule_dp, data);
        /* blob size does not include the trailer rule */
 }
 
index 9d5947a..e646e9e 100644 (file)
@@ -167,12 +167,24 @@ nla_put_failure:
        return -1;
 }
 
+static bool nft_byteorder_reduce(struct nft_regs_track *track,
+                                const struct nft_expr *expr)
+{
+       struct nft_byteorder *priv = nft_expr_priv(expr);
+
+       track->regs[priv->dreg].selector = NULL;
+       track->regs[priv->dreg].bitwise = NULL;
+
+       return false;
+}
+
 static const struct nft_expr_ops nft_byteorder_ops = {
        .type           = &nft_byteorder_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
        .eval           = nft_byteorder_eval,
        .init           = nft_byteorder_init,
        .dump           = nft_byteorder_dump,
+       .reduce         = nft_byteorder_reduce,
 };
 
 struct nft_expr_type nft_byteorder_type __read_mostly = {
index 518d96c..5adf8bb 100644 (file)
@@ -260,9 +260,12 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr,
        ct = this_cpu_read(nft_ct_pcpu_template);
 
        if (likely(refcount_read(&ct->ct_general.use) == 1)) {
+               refcount_inc(&ct->ct_general.use);
                nf_ct_zone_add(ct, &zone);
        } else {
-               /* previous skb got queued to userspace */
+               /* previous skb got queued to userspace, allocate temporary
+                * one until percpu template can be reused.
+                */
                ct = nf_ct_tmpl_alloc(nft_net(pkt), &zone, GFP_ATOMIC);
                if (!ct) {
                        regs->verdict.code = NF_DROP;
index 85ea7dd..ab87f22 100644 (file)
@@ -1789,7 +1789,10 @@ static int fanout_add(struct sock *sk, struct fanout_args *args)
                err = -ENOSPC;
                if (refcount_read(&match->sk_ref) < match->max_num_members) {
                        __dev_remove_pack(&po->prot_hook);
-                       po->fanout = match;
+
+                       /* Paired with packet_setsockopt(PACKET_FANOUT_DATA) */
+                       WRITE_ONCE(po->fanout, match);
+
                        po->rollover = rollover;
                        rollover = NULL;
                        refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1);
@@ -3934,7 +3937,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
        }
        case PACKET_FANOUT_DATA:
        {
-               if (!po->fanout)
+               /* Paired with the WRITE_ONCE() in fanout_add() */
+               if (!READ_ONCE(po->fanout))
                        return -EINVAL;
 
                return fanout_set_data(po, optval, optlen);
index d4e27c6..5f0f346 100644 (file)
@@ -1945,9 +1945,9 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
        bool prio_allocate;
        u32 parent;
        u32 chain_index;
-       struct Qdisc *q = NULL;
+       struct Qdisc *q;
        struct tcf_chain_info chain_info;
-       struct tcf_chain *chain = NULL;
+       struct tcf_chain *chain;
        struct tcf_block *block;
        struct tcf_proto *tp;
        unsigned long cl;
@@ -1976,6 +1976,8 @@ replay:
        tp = NULL;
        cl = 0;
        block = NULL;
+       q = NULL;
+       chain = NULL;
        flags = 0;
 
        if (prio == 0) {
@@ -2798,8 +2800,8 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
        struct tcmsg *t;
        u32 parent;
        u32 chain_index;
-       struct Qdisc *q = NULL;
-       struct tcf_chain *chain = NULL;
+       struct Qdisc *q;
+       struct tcf_chain *chain;
        struct tcf_block *block;
        unsigned long cl;
        int err;
@@ -2809,6 +2811,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
                return -EPERM;
 
 replay:
+       q = NULL;
        err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
                                     rtm_tca_policy, extack);
        if (err < 0)
index d5ea62b..8c89d0b 100644 (file)
@@ -566,17 +566,115 @@ static void smc_stat_fallback(struct smc_sock *smc)
        mutex_unlock(&net->smc.mutex_fback_rsn);
 }
 
+/* must be called under rcu read lock */
+static void smc_fback_wakeup_waitqueue(struct smc_sock *smc, void *key)
+{
+       struct socket_wq *wq;
+       __poll_t flags;
+
+       wq = rcu_dereference(smc->sk.sk_wq);
+       if (!skwq_has_sleeper(wq))
+               return;
+
+       /* wake up smc sk->sk_wq */
+       if (!key) {
+               /* sk_state_change */
+               wake_up_interruptible_all(&wq->wait);
+       } else {
+               flags = key_to_poll(key);
+               if (flags & (EPOLLIN | EPOLLOUT))
+                       /* sk_data_ready or sk_write_space */
+                       wake_up_interruptible_sync_poll(&wq->wait, flags);
+               else if (flags & EPOLLERR)
+                       /* sk_error_report */
+                       wake_up_interruptible_poll(&wq->wait, flags);
+       }
+}
+
+static int smc_fback_mark_woken(wait_queue_entry_t *wait,
+                               unsigned int mode, int sync, void *key)
+{
+       struct smc_mark_woken *mark =
+               container_of(wait, struct smc_mark_woken, wait_entry);
+
+       mark->woken = true;
+       mark->key = key;
+       return 0;
+}
+
+static void smc_fback_forward_wakeup(struct smc_sock *smc, struct sock *clcsk,
+                                    void (*clcsock_callback)(struct sock *sk))
+{
+       struct smc_mark_woken mark = { .woken = false };
+       struct socket_wq *wq;
+
+       init_waitqueue_func_entry(&mark.wait_entry,
+                                 smc_fback_mark_woken);
+       rcu_read_lock();
+       wq = rcu_dereference(clcsk->sk_wq);
+       if (!wq)
+               goto out;
+       add_wait_queue(sk_sleep(clcsk), &mark.wait_entry);
+       clcsock_callback(clcsk);
+       remove_wait_queue(sk_sleep(clcsk), &mark.wait_entry);
+
+       if (mark.woken)
+               smc_fback_wakeup_waitqueue(smc, mark.key);
+out:
+       rcu_read_unlock();
+}
+
+static void smc_fback_state_change(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_state_change);
+}
+
+static void smc_fback_data_ready(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_data_ready);
+}
+
+static void smc_fback_write_space(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_write_space);
+}
+
+static void smc_fback_error_report(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_error_report);
+}
+
 static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
 {
-       wait_queue_head_t *smc_wait = sk_sleep(&smc->sk);
-       wait_queue_head_t *clc_wait;
-       unsigned long flags;
+       struct sock *clcsk;
 
        mutex_lock(&smc->clcsock_release_lock);
        if (!smc->clcsock) {
                mutex_unlock(&smc->clcsock_release_lock);
                return -EBADF;
        }
+       clcsk = smc->clcsock->sk;
+
        smc->use_fallback = true;
        smc->fallback_rsn = reason_code;
        smc_stat_fallback(smc);
@@ -587,16 +685,22 @@ static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
                smc->clcsock->wq.fasync_list =
                        smc->sk.sk_socket->wq.fasync_list;
 
-               /* There may be some entries remaining in
-                * smc socket->wq, which should be removed
-                * to clcsocket->wq during the fallback.
+               /* There might be some wait entries remaining
+                * in smc sk->sk_wq and they should be woken up
+                * as clcsock's wait queue is woken up.
                 */
-               clc_wait = sk_sleep(smc->clcsock->sk);
-               spin_lock_irqsave(&smc_wait->lock, flags);
-               spin_lock_nested(&clc_wait->lock, SINGLE_DEPTH_NESTING);
-               list_splice_init(&smc_wait->head, &clc_wait->head);
-               spin_unlock(&clc_wait->lock);
-               spin_unlock_irqrestore(&smc_wait->lock, flags);
+               smc->clcsk_state_change = clcsk->sk_state_change;
+               smc->clcsk_data_ready = clcsk->sk_data_ready;
+               smc->clcsk_write_space = clcsk->sk_write_space;
+               smc->clcsk_error_report = clcsk->sk_error_report;
+
+               clcsk->sk_state_change = smc_fback_state_change;
+               clcsk->sk_data_ready = smc_fback_data_ready;
+               clcsk->sk_write_space = smc_fback_write_space;
+               clcsk->sk_error_report = smc_fback_error_report;
+
+               smc->clcsock->sk->sk_user_data =
+                       (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
        }
        mutex_unlock(&smc->clcsock_release_lock);
        return 0;
@@ -2115,10 +2219,9 @@ out:
 
 static void smc_clcsock_data_ready(struct sock *listen_clcsock)
 {
-       struct smc_sock *lsmc;
+       struct smc_sock *lsmc =
+               smc_clcsock_user_data(listen_clcsock);
 
-       lsmc = (struct smc_sock *)
-              ((uintptr_t)listen_clcsock->sk_user_data & ~SK_USER_DATA_NOCOPY);
        if (!lsmc)
                return;
        lsmc->clcsk_data_ready(listen_clcsock);
index 3d0b8e3..37b2001 100644 (file)
@@ -139,6 +139,12 @@ enum smc_urg_state {
        SMC_URG_READ    = 3,                    /* data was already read */
 };
 
+struct smc_mark_woken {
+       bool woken;
+       void *key;
+       wait_queue_entry_t wait_entry;
+};
+
 struct smc_connection {
        struct rb_node          alert_node;
        struct smc_link_group   *lgr;           /* link group of connection */
@@ -228,8 +234,14 @@ struct smc_connection {
 struct smc_sock {                              /* smc sock container */
        struct sock             sk;
        struct socket           *clcsock;       /* internal tcp socket */
+       void                    (*clcsk_state_change)(struct sock *sk);
+                                               /* original stat_change fct. */
        void                    (*clcsk_data_ready)(struct sock *sk);
-                                               /* original data_ready fct. **/
+                                               /* original data_ready fct. */
+       void                    (*clcsk_write_space)(struct sock *sk);
+                                               /* original write_space fct. */
+       void                    (*clcsk_error_report)(struct sock *sk);
+                                               /* original error_report fct. */
        struct smc_connection   conn;           /* smc connection */
        struct smc_sock         *listen_smc;    /* listen parent */
        struct work_struct      connect_work;   /* handle non-blocking connect*/
@@ -264,6 +276,12 @@ static inline struct smc_sock *smc_sk(const struct sock *sk)
        return (struct smc_sock *)sk;
 }
 
+static inline struct smc_sock *smc_clcsock_user_data(struct sock *clcsk)
+{
+       return (struct smc_sock *)
+              ((uintptr_t)clcsk->sk_user_data & ~SK_USER_DATA_NOCOPY);
+}
+
 extern struct workqueue_struct *smc_hs_wq;     /* wq for handshake work */
 extern struct workqueue_struct *smc_close_wq;  /* wq for close work */
 
index b8898c7..1fca2f9 100644 (file)
@@ -146,13 +146,11 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
            (req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) &&
            !list_empty(&smc->conn.lgr->list)) {
                struct smc_link *link = smc->conn.lnk;
-               struct net *net = read_pnet(&link->smcibdev->ibdev->coredev.rdma_net);
 
                struct smc_diag_lgrinfo linfo = {
                        .role = smc->conn.lgr->role,
                        .lnk[0].ibport = link->ibport,
                        .lnk[0].link_id = link->link_id,
-                       .lnk[0].net_cookie = net->net_cookie,
                };
 
                memcpy(linfo.lnk[0].ibname,
index 23240d7..895f4b9 100644 (file)
@@ -109,22 +109,25 @@ int asymmetric_verify(struct key *keyring, const char *sig,
 
        pk = asymmetric_key_public_key(key);
        pks.pkey_algo = pk->pkey_algo;
-       if (!strcmp(pk->pkey_algo, "rsa"))
+       if (!strcmp(pk->pkey_algo, "rsa")) {
                pks.encoding = "pkcs1";
-       else if (!strncmp(pk->pkey_algo, "ecdsa-", 6))
+       } else if (!strncmp(pk->pkey_algo, "ecdsa-", 6)) {
                /* edcsa-nist-p192 etc. */
                pks.encoding = "x962";
-       else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
-                  !strcmp(pk->pkey_algo, "sm2"))
+       else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
+                  !strcmp(pk->pkey_algo, "sm2")) {
                pks.encoding = "raw";
-       else
-               return -ENOPKG;
+       } else {
+               ret = -ENOPKG;
+               goto out;
+       }
 
        pks.digest = (u8 *)data;
        pks.digest_size = datalen;
        pks.s = hdr->sig;
        pks.s_size = siglen;
        ret = verify_signature(key, &pks);
+out:
        key_put(key);
        pr_debug("%s() = %d\n", __func__, ret);
        return ret;
index 3d8e9d5..3ad8f77 100644 (file)
@@ -496,12 +496,12 @@ int __init ima_fs_init(void)
 
        return 0;
 out:
+       securityfs_remove(ima_policy);
        securityfs_remove(violations);
        securityfs_remove(runtime_measurements_count);
        securityfs_remove(ascii_runtime_measurements);
        securityfs_remove(binary_runtime_measurements);
        securityfs_remove(ima_symlink);
        securityfs_remove(ima_dir);
-       securityfs_remove(ima_policy);
        return -1;
 }
index 320ca80..2a1f641 100644 (file)
@@ -1967,6 +1967,14 @@ int ima_policy_show(struct seq_file *m, void *v)
 
        rcu_read_lock();
 
+       /* Do not print rules with inactive LSM labels */
+       for (i = 0; i < MAX_LSM_RULES; i++) {
+               if (entry->lsm[i].args_p && !entry->lsm[i].rule) {
+                       rcu_read_unlock();
+                       return 0;
+               }
+       }
+
        if (entry->action & MEASURE)
                seq_puts(m, pt(Opt_measure));
        if (entry->action & DONT_MEASURE)
index 6945603..db1ad6d 100644 (file)
@@ -29,6 +29,7 @@ static struct ima_template_desc builtin_templates[] = {
 
 static LIST_HEAD(defined_templates);
 static DEFINE_SPINLOCK(template_list);
+static int template_setup_done;
 
 static const struct ima_template_field supported_fields[] = {
        {.field_id = "d", .field_init = ima_eventdigest_init,
@@ -101,10 +102,11 @@ static int __init ima_template_setup(char *str)
        struct ima_template_desc *template_desc;
        int template_len = strlen(str);
 
-       if (ima_template)
+       if (template_setup_done)
                return 1;
 
-       ima_init_template_list();
+       if (!ima_template)
+               ima_init_template_list();
 
        /*
         * Verify that a template with the supplied name exists.
@@ -128,6 +130,7 @@ static int __init ima_template_setup(char *str)
        }
 
        ima_template = template_desc;
+       template_setup_done = 1;
        return 1;
 }
 __setup("ima_template=", ima_template_setup);
@@ -136,7 +139,7 @@ static int __init ima_template_fmt_setup(char *str)
 {
        int num_templates = ARRAY_SIZE(builtin_templates);
 
-       if (ima_template)
+       if (template_setup_done)
                return 1;
 
        if (template_desc_init_fields(str, NULL, NULL) < 0) {
@@ -147,6 +150,7 @@ static int __init ima_template_fmt_setup(char *str)
 
        builtin_templates[num_templates - 1].fmt = str;
        ima_template = builtin_templates + num_templates - 1;
+       template_setup_done = 1;
 
        return 1;
 }
index 2922005..0ec5e4c 100644 (file)
@@ -45,6 +45,8 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
                return;
 
        ab = audit_log_start(audit_context(), GFP_KERNEL, audit_msgno);
+       if (!ab)
+               return;
        audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
                         task_pid_nr(current),
                         from_kuid(&init_user_ns, current_uid()),
index 2ec6e5c..feb206f 100644 (file)
@@ -152,6 +152,8 @@ static void cond_list_destroy(struct policydb *p)
        for (i = 0; i < p->cond_list_len; i++)
                cond_node_destroy(&p->cond_list[i]);
        kfree(p->cond_list);
+       p->cond_list = NULL;
+       p->cond_list_len = 0;
 }
 
 void cond_policydb_destroy(struct policydb *p)
@@ -441,7 +443,6 @@ int cond_read_list(struct policydb *p, void *fp)
        return 0;
 err:
        cond_list_destroy(p);
-       p->cond_list = NULL;
        return rc;
 }
 
index 621883e..a056b3e 100644 (file)
@@ -172,6 +172,19 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
 
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream)
+{
+       unsigned long flags = 0;
+       if (substream->pcm->nonatomic)
+               mutex_lock_nested(&substream->self_group.mutex,
+                                 SINGLE_DEPTH_NESTING);
+       else
+               spin_lock_irqsave_nested(&substream->self_group.lock, flags,
+                                        SINGLE_DEPTH_NESTING);
+       return flags;
+}
+EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave_nested);
+
 /**
  * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
  * @substream: PCM substream
index b7758db..5cb92f7 100644 (file)
@@ -50,11 +50,11 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
 static int
 sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
        int ret, i;
        u8 count;
 
-       if (acpi_bus_get_device(info->handle, &adev))
+       if (!adev)
                return -EINVAL;
 
        /* Found controller, find links supported */
@@ -119,7 +119,6 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
                                     void *cdata, void **return_value)
 {
        struct sdw_intel_acpi_info *info = cdata;
-       struct acpi_device *adev;
        acpi_status status;
        u64 adr;
 
@@ -127,7 +126,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        if (ACPI_FAILURE(status))
                return AE_OK; /* keep going */
 
-       if (acpi_bus_get_device(handle, &adev)) {
+       if (!acpi_fetch_acpi_dev(handle)) {
                pr_err("%s: Couldn't find ACPI handle\n", __func__);
                return AE_NOT_FOUND;
        }
index 82c492b..cd1db94 100644 (file)
@@ -981,7 +981,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
        int id = HDA_FIXUP_ID_NOT_SET;
        const char *name = NULL;
        const char *type = NULL;
-       int vendor, device;
+       unsigned int vendor, device;
 
        if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
                return;
index 7016b48..f552785 100644 (file)
@@ -3000,6 +3000,10 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)
 {
        struct hda_pcm *cpcm;
 
+       /* Skip the shutdown if codec is not registered */
+       if (!codec->registered)
+               return;
+
        list_for_each_entry(cpcm, &codec->pcm_list_head, list)
                snd_pcm_suspend_all(cpcm->pcm);
 
index 3bf5e34..fc114e5 100644 (file)
@@ -91,6 +91,12 @@ static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
        free_kctls(spec);
        snd_array_free(&spec->paths);
        snd_array_free(&spec->loopback_list);
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
+       if (spec->led_cdevs[LED_AUDIO_MUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
+       if (spec->led_cdevs[LED_AUDIO_MICMUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
+#endif
 }
 
 /*
@@ -3922,7 +3928,10 @@ static int create_mute_led_cdev(struct hda_codec *codec,
                                                enum led_brightness),
                                bool micmute)
 {
+       struct hda_gen_spec *spec = codec->spec;
        struct led_classdev *cdev;
+       int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
+       int err;
 
        cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
        if (!cdev)
@@ -3932,10 +3941,14 @@ static int create_mute_led_cdev(struct hda_codec *codec,
        cdev->max_brightness = 1;
        cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
        cdev->brightness_set_blocking = callback;
-       cdev->brightness = ledtrig_audio_get(micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE);
+       cdev->brightness = ledtrig_audio_get(idx);
        cdev->flags = LED_CORE_SUSPENDRESUME;
 
-       return devm_led_classdev_register(&codec->core.dev, cdev);
+       err = led_classdev_register(&codec->core.dev, cdev);
+       if (err < 0)
+               return err;
+       spec->led_cdevs[idx] = cdev;
+       return 0;
 }
 
 /**
index 8e1bc8e..34eba40 100644 (file)
@@ -294,6 +294,9 @@ struct hda_gen_spec {
                                   struct hda_jack_callback *cb);
        void (*mic_autoswitch_hook)(struct hda_codec *codec,
                                    struct hda_jack_callback *cb);
+
+       /* leds */
+       struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
 };
 
 /* values for add_stereo_mix_input flag */
index 668274e..8315bf7 100644 (file)
@@ -98,6 +98,7 @@ struct alc_spec {
        unsigned int gpio_mic_led_mask;
        struct alc_coef_led mute_led_coef;
        struct alc_coef_led mic_led_coef;
+       struct mutex coef_mutex;
 
        hda_nid_t headset_mic_pin;
        hda_nid_t headphone_mic_pin;
@@ -137,8 +138,8 @@ struct alc_spec {
  * COEF access helper functions
  */
 
-static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int coef_idx)
+static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx)
 {
        unsigned int val;
 
@@ -147,28 +148,61 @@ static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int coef_idx)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int val;
+
+       mutex_lock(&spec->coef_mutex);
+       val = __alc_read_coefex_idx(codec, nid, coef_idx);
+       mutex_unlock(&spec->coef_mutex);
+       return val;
+}
+
 #define alc_read_coef_idx(codec, coef_idx) \
        alc_read_coefex_idx(codec, 0x20, coef_idx)
 
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                unsigned int coef_idx, unsigned int coef_val)
+static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                  unsigned int coef_idx, unsigned int coef_val)
 {
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
 }
 
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx, unsigned int coef_val)
+{
+       struct alc_spec *spec = codec->spec;
+
+       mutex_lock(&spec->coef_mutex);
+       __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
+       mutex_unlock(&spec->coef_mutex);
+}
+
 #define alc_write_coef_idx(codec, coef_idx, coef_val) \
        alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
 
+static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                   unsigned int coef_idx, unsigned int mask,
+                                   unsigned int bits_set)
+{
+       unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
+
+       if (val != -1)
+               __alc_write_coefex_idx(codec, nid, coef_idx,
+                                      (val & ~mask) | bits_set);
+}
+
 static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
                                  unsigned int coef_idx, unsigned int mask,
                                  unsigned int bits_set)
 {
-       unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx);
+       struct alc_spec *spec = codec->spec;
 
-       if (val != -1)
-               alc_write_coefex_idx(codec, nid, coef_idx,
-                                    (val & ~mask) | bits_set);
+       mutex_lock(&spec->coef_mutex);
+       __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
+       mutex_unlock(&spec->coef_mutex);
 }
 
 #define alc_update_coef_idx(codec, coef_idx, mask, bits_set)   \
@@ -201,13 +235,17 @@ struct coef_fw {
 static void alc_process_coef_fw(struct hda_codec *codec,
                                const struct coef_fw *fw)
 {
+       struct alc_spec *spec = codec->spec;
+
+       mutex_lock(&spec->coef_mutex);
        for (; fw->nid; fw++) {
                if (fw->mask == (unsigned short)-1)
-                       alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+                       __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
                else
-                       alc_update_coefex_idx(codec, fw->nid, fw->idx,
-                                             fw->mask, fw->val);
+                       __alc_update_coefex_idx(codec, fw->nid, fw->idx,
+                                               fw->mask, fw->val);
        }
+       mutex_unlock(&spec->coef_mutex);
 }
 
 /*
@@ -1153,6 +1191,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
        codec->spdif_status_reset = 1;
        codec->forced_resume = 1;
        codec->patch_ops = alc_patch_ops;
+       mutex_init(&spec->coef_mutex);
 
        err = alc_codec_rename_from_preset(codec);
        if (err < 0) {
@@ -2125,6 +2164,7 @@ static void alc1220_fixup_gb_x570(struct hda_codec *codec,
 {
        static const hda_nid_t conn1[] = { 0x0c };
        static const struct coef_fw gb_x570_coefs[] = {
+               WRITE_COEF(0x07, 0x03c0),
                WRITE_COEF(0x1a, 0x01c1),
                WRITE_COEF(0x1b, 0x0202),
                WRITE_COEF(0x43, 0x3005),
@@ -2551,7 +2591,8 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
        SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
-       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
+       SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
        SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
@@ -2626,6 +2667,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = {
        {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
        {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
        {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+       {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
        {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
        {}
 };
@@ -8969,6 +9011,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
index c9caade..cd05ee2 100644 (file)
@@ -303,11 +303,11 @@ static const struct snd_soc_dapm_route rt1019_map_lr[] = {
 
 static struct snd_soc_codec_conf rt1019_conf[] = {
        {
-                .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
+                .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
                 .name_prefix = "Left",
        },
        {
-                .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
+                .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
                 .name_prefix = "Right",
        },
 };
index 598e090..ffdf8b6 100644 (file)
@@ -1667,6 +1667,8 @@ static int cpcap_codec_probe(struct platform_device *pdev)
 {
        struct device_node *codec_node =
                of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+       if (!codec_node)
+               return -ENODEV;
 
        pdev->dev.of_node = codec_node;
 
index b61f980..b07607a 100644 (file)
@@ -277,7 +277,7 @@ struct hdmi_codec_priv {
        bool busy;
        struct snd_soc_jack *jack;
        unsigned int jack_status;
-       u8 iec_status[5];
+       u8 iec_status[AES_IEC958_STATUS_SIZE];
 };
 
 static const struct snd_soc_dapm_widget hdmi_widgets[] = {
index aec5127..6ffe883 100644 (file)
@@ -2688,8 +2688,8 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
        int reg, b2_reg;
 
        /* Address does not automatically update if reading */
-       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
-       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
+       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg,
                                ((band_idx * BAND_MAX + coeff_idx) *
@@ -2718,7 +2718,7 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
 static void set_iir_band_coeff(struct snd_soc_component *component,
                               int iir_idx, int band_idx, uint32_t value)
 {
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg, (value & 0xFF));
        snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
@@ -2739,7 +2739,7 @@ static int rx_macro_put_iir_band_audio_mixer(
        int iir_idx = ctl->iir_idx;
        int band_idx = ctl->band_idx;
        u32 coeff[BAND_MAX];
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
 
        memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
 
index d75fd61..bc57d76 100644 (file)
@@ -64,7 +64,8 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
        struct max9759 *priv = snd_soc_component_get_drvdata(c);
 
-       if (ucontrol->value.integer.value[0] > 3)
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > 3)
                return -EINVAL;
 
        priv->gain = ucontrol->value.integer.value[0];
index 20e0f90..20fc0f3 100644 (file)
@@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work)
        struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
                jd_check_work.work);
 
-       if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
-               & RT5682_JDH_RS_MASK) {
+       if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK)
                /* jack out */
-               rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
-
-               snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
-                       SND_JACK_HEADSET |
-                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3);
-       } else {
+               mod_delayed_work(system_power_efficient_wq,
+                                &rt5682->jack_detect_work, 0);
+       else
                schedule_delayed_work(&rt5682->jd_check_work, 500);
-       }
 }
 
 static irqreturn_t rt5682_irq(int irq, void *data)
@@ -198,7 +192,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
        }
 
        mutex_init(&rt5682->calibrate_mutex);
-       mutex_init(&rt5682->jdet_mutex);
        rt5682_calibrate(rt5682);
 
        rt5682_apply_patch_list(rt5682, &i2c->dev);
index 415ec56..0a0ec4a 100644 (file)
@@ -922,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
  *
  * Returns detect status.
  */
-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
        struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
        struct snd_soc_dapm_context *dapm = &component->dapm;
        unsigned int val, count;
 
        if (jack_insert) {
-               snd_soc_dapm_mutex_lock(dapm);
-
                snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB);
@@ -981,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
                        RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
                        RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
-
-               snd_soc_dapm_mutex_unlock(dapm);
        } else {
                rt5682_enable_push_button_irq(component, false);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
@@ -1011,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
        dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
        return rt5682->jack_type;
 }
-EXPORT_SYMBOL_GPL(rt5682_headset_detect);
 
 static int rt5682_set_jack_detect(struct snd_soc_component *component,
                struct snd_soc_jack *hs_jack, void *data)
@@ -1094,6 +1089,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
 {
        struct rt5682_priv *rt5682 =
                container_of(work, struct rt5682_priv, jack_detect_work.work);
+       struct snd_soc_dapm_context *dapm;
        int val, btn_type;
 
        while (!rt5682->component)
@@ -1102,7 +1098,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
        while (!rt5682->component->card->instantiated)
                usleep_range(10000, 15000);
 
-       mutex_lock(&rt5682->jdet_mutex);
+       dapm = snd_soc_component_get_dapm(rt5682->component);
+
+       snd_soc_dapm_mutex_lock(dapm);
        mutex_lock(&rt5682->calibrate_mutex);
 
        val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
@@ -1162,6 +1160,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
                rt5682->irq_work_delay_time = 50;
        }
 
+       mutex_unlock(&rt5682->calibrate_mutex);
+       snd_soc_dapm_mutex_unlock(dapm);
+
        snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
                SND_JACK_HEADSET |
                SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@@ -1174,9 +1175,6 @@ void rt5682_jack_detect_handler(struct work_struct *work)
                else
                        cancel_delayed_work_sync(&rt5682->jd_check_work);
        }
-
-       mutex_unlock(&rt5682->calibrate_mutex);
-       mutex_unlock(&rt5682->jdet_mutex);
 }
 EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
 
@@ -1526,7 +1524,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *component =
                snd_soc_dapm_to_component(w->dapm);
-       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -1538,17 +1535,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
                        RT5682_DEPOP_1, 0x60, 0x60);
                snd_soc_component_update_bits(component,
                        RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
-
-               mutex_lock(&rt5682->jdet_mutex);
-
                snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
                usleep_range(5000, 10000);
                snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
                        RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
-
-               mutex_unlock(&rt5682->jdet_mutex);
                break;
 
        case SND_SOC_DAPM_POST_PMD:
index c917c76..52ff0d9 100644 (file)
@@ -1463,7 +1463,6 @@ struct rt5682_priv {
 
        int jack_type;
        int irq_work_delay_time;
-       struct mutex jdet_mutex;
 };
 
 extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
@@ -1473,7 +1472,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
 
 void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
 
-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
 void rt5682_jack_detect_handler(struct work_struct *work);
 
 bool rt5682_volatile_register(struct device *dev, unsigned int reg);
index eff200a..36cbc66 100644 (file)
@@ -1432,14 +1432,10 @@ static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
        return 0;
 }
 
-static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable)
+static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable)
 {
-       u8 port_num;
-
-       port_num = wcd->ch_info[ch_id].port_num;
-
        return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id],
-                                       &wcd->port_config[port_num],
+                                       &wcd->port_config[port_num - 1],
                                        enable);
 }
 
@@ -2563,7 +2559,7 @@ static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
                                      WCD938X_EAR_GAIN_MASK,
                                      ucontrol->value.integer.value[0]);
 
-       return 0;
+       return 1;
 }
 
 static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
@@ -2593,6 +2589,7 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
        struct wcd938x_sdw_priv *wcd;
        int value = ucontrol->value.integer.value[0];
+       int portidx;
        struct soc_mixer_control *mc;
        bool hphr;
 
@@ -2606,12 +2603,14 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
        else
                wcd938x->comp1_enable = value;
 
+       portidx = wcd->ch_info[mc->reg].port_num;
+
        if (value)
-               wcd938x_connect_port(wcd, mc->reg, true);
+               wcd938x_connect_port(wcd, portidx, mc->reg, true);
        else
-               wcd938x_connect_port(wcd, mc->reg, false);
+               wcd938x_connect_port(wcd, portidx, mc->reg, false);
 
-       return 0;
+       return 1;
 }
 
 static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol,
@@ -2882,9 +2881,11 @@ static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol,
        struct wcd938x_sdw_priv *wcd;
        struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
        int dai_id = mixer->shift;
-       int portidx = mixer->reg;
+       int portidx, ch_idx = mixer->reg;
+
 
        wcd = wcd938x->sdw_priv[dai_id];
+       portidx = wcd->ch_info[ch_idx].port_num;
 
        ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
 
@@ -2899,12 +2900,14 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
        struct wcd938x_sdw_priv *wcd;
        struct soc_mixer_control *mixer =
                (struct soc_mixer_control *)kcontrol->private_value;
-       int portidx = mixer->reg;
+       int ch_idx = mixer->reg;
+       int portidx;
        int dai_id = mixer->shift;
        bool enable;
 
        wcd = wcd938x->sdw_priv[dai_id];
 
+       portidx = wcd->ch_info[ch_idx].port_num;
        if (ucontrol->value.integer.value[0])
                enable = true;
        else
@@ -2912,9 +2915,9 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
 
        wcd->port_enable[portidx] = enable;
 
-       wcd938x_connect_port(wcd, portidx, enable);
+       wcd938x_connect_port(wcd, portidx, ch_idx, enable);
 
-       return 0;
+       return 1;
 
 }
 
index af3c3b9..83b4a22 100644 (file)
@@ -93,16 +93,21 @@ static int pcm030_fabric_probe(struct platform_device *op)
                dev_err(&op->dev, "platform_device_alloc() failed\n");
 
        ret = platform_device_add(pdata->codec_device);
-       if (ret)
+       if (ret) {
                dev_err(&op->dev, "platform_device_add() failed: %d\n", ret);
+               platform_device_put(pdata->codec_device);
+       }
 
        ret = snd_soc_register_card(card);
-       if (ret)
+       if (ret) {
                dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
+               platform_device_del(pdata->codec_device);
+               platform_device_put(pdata->codec_device);
+       }
 
        platform_set_drvdata(op, pdata);
-
        return ret;
+
 }
 
 static int pcm030_fabric_remove(struct platform_device *op)
index a89d1cf..78419e1 100644 (file)
@@ -28,6 +28,30 @@ static const struct snd_soc_ops simple_ops = {
        .hw_params      = asoc_simple_hw_params,
 };
 
+static int asoc_simple_parse_platform(struct device_node *node,
+                                     struct snd_soc_dai_link_component *dlc)
+{
+       struct of_phandle_args args;
+       int ret;
+
+       if (!node)
+               return 0;
+
+       /*
+        * Get node via "sound-dai = <&phandle port>"
+        * it will be used as xxx_of_node on soc_bind_dai_link()
+        */
+       ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
+       if (ret)
+               return ret;
+
+       /* dai_name is not required and may not exist for plat component */
+
+       dlc->of_node = args.np;
+
+       return 0;
+}
+
 static int asoc_simple_parse_dai(struct device_node *node,
                                 struct snd_soc_dai_link_component *dlc,
                                 int *is_single_link)
@@ -289,7 +313,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = asoc_simple_parse_dai(plat, platforms, NULL);
+       ret = asoc_simple_parse_platform(plat, platforms);
        if (ret < 0)
                goto dai_link_of_err;
 
index 9306b7c..0d15435 100644 (file)
@@ -216,7 +216,7 @@ config SND_SOC_MT8195_MT6359_RT1019_RT5682
 
 config SND_SOC_MT8195_MT6359_RT1011_RT5682
        tristate "ASoC Audio driver for MT8195 with MT6359 RT1011 RT5682 codec"
-       depends on I2C
+       depends on I2C && GPIOLIB
        depends on SND_SOC_MT8195 && MTK_PMIC_WRAP
        select SND_SOC_MT6359
        select SND_SOC_RT1011
index eb1c3ae..19c4a90 100644 (file)
@@ -308,8 +308,11 @@ static int q6apm_dai_close(struct snd_soc_component *component,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct q6apm_dai_rtd *prtd = runtime->private_data;
 
-       q6apm_graph_stop(prtd->graph);
-       q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       if (prtd->state) { /* only stop graph that is started */
+               q6apm_graph_stop(prtd->graph);
+               q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       }
+
        q6apm_graph_close(prtd->graph);
        prtd->graph = NULL;
        kfree(prtd);
index cbd7ea4..142476f 100644 (file)
@@ -55,16 +55,13 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine);
 static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level,
                                             void *context, void **ret)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
        acpi_status status;
        struct snd_soc_acpi_package_context *pkg_ctx = context;
 
        pkg_ctx->data_valid = false;
 
-       if (acpi_bus_get_device(handle, &adev))
-               return AE_OK;
-
-       if (adev->status.present && adev->status.functional) {
+       if (adev && adev->status.present && adev->status.functional) {
                struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
                union acpi_object  *myobj = NULL;
 
index 08eaa9d..9833611 100644 (file)
@@ -316,13 +316,27 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        if (sign_bit)
                mask = BIT(sign_bit + 1) - 1;
 
-       val = ((ucontrol->value.integer.value[0] + min) & mask);
+       if (ucontrol->value.integer.value[0] < 0)
+               return -EINVAL;
+       val = ucontrol->value.integer.value[0];
+       if (mc->platform_max && val > mc->platform_max)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
+       val = (val + min) & mask;
        if (invert)
                val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (snd_soc_volsw_is_stereo(mc)) {
-               val2 = ((ucontrol->value.integer.value[1] + min) & mask);
+               if (ucontrol->value.integer.value[1] < 0)
+                       return -EINVAL;
+               val2 = ucontrol->value.integer.value[1];
+               if (mc->platform_max && val2 > mc->platform_max)
+                       return -EINVAL;
+               if (val2 > max - min)
+                       return -EINVAL;
+               val2 = (val2 + min) & mask;
                if (invert)
                        val2 = max - val2;
                if (reg == reg2) {
@@ -409,8 +423,15 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
        int err = 0;
        unsigned int val, val_mask;
 
+       if (ucontrol->value.integer.value[0] < 0)
+               return -EINVAL;
+       val = ucontrol->value.integer.value[0];
+       if (mc->platform_max && val > mc->platform_max)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
        val_mask = mask << shift;
-       val = (ucontrol->value.integer.value[0] + min) & mask;
+       val = (val + min) & mask;
        val = val << shift;
 
        err = snd_soc_component_update_bits(component, reg, val_mask, val);
@@ -858,6 +879,8 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        long val = ucontrol->value.integer.value[0];
        unsigned int i;
 
+       if (val < mc->min || val > mc->max)
+               return -EINVAL;
        if (invert)
                val = max - val;
        val &= mask;
index 7abfc48..9a95468 100644 (file)
@@ -46,8 +46,8 @@ static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd,
        snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream));
 }
 
-#define snd_soc_dpcm_stream_lock_irqsave(rtd, stream, flags) \
-       snd_pcm_stream_lock_irqsave(snd_soc_dpcm_get_substream(rtd, stream), flags)
+#define snd_soc_dpcm_stream_lock_irqsave_nested(rtd, stream, flags) \
+       snd_pcm_stream_lock_irqsave_nested(snd_soc_dpcm_get_substream(rtd, stream), flags)
 
 static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd,
                                                  int stream)
@@ -1268,6 +1268,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
 void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
 {
        struct snd_soc_dpcm *dpcm, *d;
+       LIST_HEAD(deleted_dpcms);
 
        snd_soc_dpcm_mutex_assert_held(fe);
 
@@ -1287,13 +1288,18 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
                /* BEs still alive need new FE */
                dpcm_be_reparent(fe, dpcm->be, stream);
 
-               dpcm_remove_debugfs_state(dpcm);
-
                list_del(&dpcm->list_be);
+               list_move(&dpcm->list_fe, &deleted_dpcms);
+       }
+       snd_soc_dpcm_stream_unlock_irq(fe, stream);
+
+       while (!list_empty(&deleted_dpcms)) {
+               dpcm = list_first_entry(&deleted_dpcms, struct snd_soc_dpcm,
+                                       list_fe);
                list_del(&dpcm->list_fe);
+               dpcm_remove_debugfs_state(dpcm);
                kfree(dpcm);
        }
-       snd_soc_dpcm_stream_unlock_irq(fe, stream);
 }
 
 /* get BE for DAI widget and stream */
@@ -2094,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                be = dpcm->be;
                be_substream = snd_soc_dpcm_get_substream(be, stream);
 
-               snd_soc_dpcm_stream_lock_irqsave(be, stream, flags);
+               snd_soc_dpcm_stream_lock_irqsave_nested(be, stream, flags);
 
                /* is this op for this BE ? */
                if (!snd_soc_dpcm_be_can_update(fe, be, stream))
index 91afea9..ce19a60 100644 (file)
@@ -37,6 +37,7 @@
 #define XLNX_AUD_XFER_COUNT    0x28
 #define XLNX_AUD_CH_STS_START  0x2C
 #define XLNX_BYTES_PER_CH      0x44
+#define XLNX_AUD_ALIGN_BYTES   64
 
 #define AUD_STS_IOC_IRQ_MASK   BIT(31)
 #define AUD_STS_CH_STS_MASK    BIT(29)
@@ -368,12 +369,32 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
        snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware);
        runtime->private_data = stream_data;
 
-       /* Resize the period size divisible by 64 */
+       /* Resize the period bytes as divisible by 64 */
        err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                        XLNX_AUD_ALIGN_BYTES);
        if (err) {
                dev_err(component->dev,
-                       "unable to set constraint on period bytes\n");
+                       "Unable to set constraint on period bytes\n");
+               return err;
+       }
+
+       /* Resize the buffer bytes as divisible by 64 */
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                        XLNX_AUD_ALIGN_BYTES);
+       if (err) {
+               dev_err(component->dev,
+                       "Unable to set constraint on buffer bytes\n");
+               return err;
+       }
+
+       /* Set periods as integer multiple */
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               dev_err(component->dev,
+                       "Unable to set constraint on periods to be integer\n");
                return err;
        }
 
index e8f3f8d..630766b 100644 (file)
@@ -1527,6 +1527,10 @@ error:
                usb_audio_err(chip,
                        "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
                        UAC_GET_CUR, validx, idx, cval->val_type);
+
+               if (val)
+                       *val = 0;
+
                return filter_error(cval, ret);
        }
 
index b1522e4..0ea3956 100644 (file)
@@ -84,7 +84,7 @@
  * combination.
  */
 {
-       USB_DEVICE(0x041e, 0x4095),
+       USB_AUDIO_DEVICE(0x041e, 0x4095),
        .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
index 18de5f7..6db4e29 100644 (file)
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
+#define X86_FEATURE_AMX_BF16           (18*32+22) /* AMX bf16 Support */
 #define X86_FEATURE_AMX_TILE           (18*32+24) /* AMX tile Support */
+#define X86_FEATURE_AMX_INT8           (18*32+25) /* AMX int8 Support */
 
 /* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
 #define X86_FEATURE_CLZERO             (13*32+ 0) /* CLZERO instruction */
index 9ddeca9..320a88a 100644 (file)
@@ -9,7 +9,11 @@ ifeq ($(V),1)
   msg =
 else
   Q = @
-  msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+  ifeq ($(silent),1)
+    msg =
+  else
+    msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+  endif
   MAKEFLAGS=--no-print-directory
 endif
 
index b46bcdb..5191b57 100644 (file)
@@ -1624,9 +1624,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET  _IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET   _IO(KVMIO,   0xc4)
 
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
-
 struct kvm_s390_pv_sec_parm {
        __u64 origin;
        __u64 length;
@@ -2048,4 +2045,7 @@ struct kvm_stats_desc {
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
 
+/* Available with KVM_CAP_XSAVE2 */
+#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
+
 #endif /* __LINUX_KVM_H */
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
deleted file mode 100644 (file)
index 45fcbf9..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * lirc.h - linux infrared remote control header file
- * last modified 2010/07/13 by Jarod Wilson
- */
-
-#ifndef _LINUX_LIRC_H
-#define _LINUX_LIRC_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-#define PULSE_BIT       0x01000000
-#define PULSE_MASK      0x00FFFFFF
-
-#define LIRC_MODE2_SPACE     0x00000000
-#define LIRC_MODE2_PULSE     0x01000000
-#define LIRC_MODE2_FREQUENCY 0x02000000
-#define LIRC_MODE2_TIMEOUT   0x03000000
-
-#define LIRC_VALUE_MASK      0x00FFFFFF
-#define LIRC_MODE2_MASK      0xFF000000
-
-#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
-#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
-#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
-#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
-
-#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
-#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
-
-#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
-#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
-#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
-#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
-
-/* used heavily by lirc userspace */
-#define lirc_t int
-
-/*** lirc compatible hardware features ***/
-
-#define LIRC_MODE2SEND(x) (x)
-#define LIRC_SEND2MODE(x) (x)
-#define LIRC_MODE2REC(x) ((x) << 16)
-#define LIRC_REC2MODE(x) ((x) >> 16)
-
-#define LIRC_MODE_RAW                  0x00000001
-#define LIRC_MODE_PULSE                0x00000002
-#define LIRC_MODE_MODE2                0x00000004
-#define LIRC_MODE_SCANCODE             0x00000008
-#define LIRC_MODE_LIRCCODE             0x00000010
-
-
-#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
-#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
-#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
-#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_SEND_MASK             0x0000003f
-
-#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
-#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
-#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
-
-#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
-#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
-#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
-#define LIRC_CAN_REC_SCANCODE          LIRC_MODE2REC(LIRC_MODE_SCANCODE)
-#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
-
-#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
-#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
-
-#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
-#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
-#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
-#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
-#define LIRC_CAN_SET_REC_FILTER           0x08000000
-
-#define LIRC_CAN_MEASURE_CARRIER          0x02000000
-#define LIRC_CAN_USE_WIDEBAND_RECEIVER    0x04000000
-
-#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
-#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
-
-#define LIRC_CAN_NOTIFY_DECODE            0x01000000
-
-/*** IOCTL commands for lirc driver ***/
-
-#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
-
-#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
-#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
-#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
-
-#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
-#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
-
-/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
-#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
-
-#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
-#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
-/* Note: these can reset the according pulse_width */
-#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
-#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
-#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
-#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
-
-/*
- * when a timeout != 0 is set the driver will send a
- * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
- * never sent, timeout is disabled by default
- */
-#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
-
-/* 1 enables, 0 disables timeout reports in MODE2 */
-#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
-
-/*
- * if enabled from the next key press on the driver will send
- * LIRC_MODE2_FREQUENCY packets
- */
-#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
-
-/*
- * to set a range use LIRC_SET_REC_CARRIER_RANGE with the
- * lower bound first and later LIRC_SET_REC_CARRIER with the upper bound
- */
-#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
-
-#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
-
-/*
- * Return the recording timeout, which is either set by
- * the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols.
- */
-#define LIRC_GET_REC_TIMEOUT          _IOR('i', 0x00000024, __u32)
-
-/*
- * struct lirc_scancode - decoded scancode with protocol for use with
- *     LIRC_MODE_SCANCODE
- *
- * @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR
- *     was decoded.
- * @flags: should be 0 for transmit. When receiving scancodes,
- *     LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set
- *     depending on the protocol
- * @rc_proto: see enum rc_proto
- * @keycode: the translated keycode. Set to 0 for transmit.
- * @scancode: the scancode received or to be sent
- */
-struct lirc_scancode {
-       __u64   timestamp;
-       __u16   flags;
-       __u16   rc_proto;
-       __u32   keycode;
-       __u64   scancode;
-};
-
-/* Set if the toggle bit of rc-5 or rc-6 is enabled */
-#define LIRC_SCANCODE_FLAG_TOGGLE      1
-/* Set if this is a nec or sanyo repeat */
-#define LIRC_SCANCODE_FLAG_REPEAT      2
-
-/**
- * enum rc_proto - the Remote Controller protocol
- *
- * @RC_PROTO_UNKNOWN: Protocol not known
- * @RC_PROTO_OTHER: Protocol known but proprietary
- * @RC_PROTO_RC5: Philips RC5 protocol
- * @RC_PROTO_RC5X_20: Philips RC5x 20 bit protocol
- * @RC_PROTO_RC5_SZ: StreamZap variant of RC5
- * @RC_PROTO_JVC: JVC protocol
- * @RC_PROTO_SONY12: Sony 12 bit protocol
- * @RC_PROTO_SONY15: Sony 15 bit protocol
- * @RC_PROTO_SONY20: Sony 20 bit protocol
- * @RC_PROTO_NEC: NEC protocol
- * @RC_PROTO_NECX: Extended NEC protocol
- * @RC_PROTO_NEC32: NEC 32 bit protocol
- * @RC_PROTO_SANYO: Sanyo protocol
- * @RC_PROTO_MCIR2_KBD: RC6-ish MCE keyboard
- * @RC_PROTO_MCIR2_MSE: RC6-ish MCE mouse
- * @RC_PROTO_RC6_0: Philips RC6-0-16 protocol
- * @RC_PROTO_RC6_6A_20: Philips RC6-6A-20 protocol
- * @RC_PROTO_RC6_6A_24: Philips RC6-6A-24 protocol
- * @RC_PROTO_RC6_6A_32: Philips RC6-6A-32 protocol
- * @RC_PROTO_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol
- * @RC_PROTO_SHARP: Sharp protocol
- * @RC_PROTO_XMP: XMP protocol
- * @RC_PROTO_CEC: CEC protocol
- * @RC_PROTO_IMON: iMon Pad protocol
- * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
- * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
- * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
- */
-enum rc_proto {
-       RC_PROTO_UNKNOWN        = 0,
-       RC_PROTO_OTHER          = 1,
-       RC_PROTO_RC5            = 2,
-       RC_PROTO_RC5X_20        = 3,
-       RC_PROTO_RC5_SZ         = 4,
-       RC_PROTO_JVC            = 5,
-       RC_PROTO_SONY12         = 6,
-       RC_PROTO_SONY15         = 7,
-       RC_PROTO_SONY20         = 8,
-       RC_PROTO_NEC            = 9,
-       RC_PROTO_NECX           = 10,
-       RC_PROTO_NEC32          = 11,
-       RC_PROTO_SANYO          = 12,
-       RC_PROTO_MCIR2_KBD      = 13,
-       RC_PROTO_MCIR2_MSE      = 14,
-       RC_PROTO_RC6_0          = 15,
-       RC_PROTO_RC6_6A_20      = 16,
-       RC_PROTO_RC6_6A_24      = 17,
-       RC_PROTO_RC6_6A_32      = 18,
-       RC_PROTO_RC6_MCE        = 19,
-       RC_PROTO_SHARP          = 20,
-       RC_PROTO_XMP            = 21,
-       RC_PROTO_CEC            = 22,
-       RC_PROTO_IMON           = 23,
-       RC_PROTO_RCMM12         = 24,
-       RC_PROTO_RCMM24         = 25,
-       RC_PROTO_RCMM32         = 26,
-};
-
-#endif
index 4cd39aa..1b65042 100644 (file)
@@ -1332,9 +1332,9 @@ union perf_mem_data_src {
 
 /* hop level */
 #define PERF_MEM_HOPS_0                0x01 /* remote core, same node */
-#define PERF_MEM_HOPS_1         0x02 /* remote node, same socket */
-#define PERF_MEM_HOPS_2         0x03 /* remote socket, same board */
-#define PERF_MEM_HOPS_3         0x04 /* remote board */
+#define PERF_MEM_HOPS_1                0x02 /* remote node, same socket */
+#define PERF_MEM_HOPS_2                0x03 /* remote socket, same board */
+#define PERF_MEM_HOPS_3                0x04 /* remote board */
 /* 5-7 available */
 #define PERF_MEM_HOPS_SHIFT    43
 
index bb73e9a..e998764 100644 (file)
@@ -272,4 +272,7 @@ struct prctl_mm_map {
 # define PR_SCHED_CORE_SCOPE_THREAD_GROUP      1
 # define PR_SCHED_CORE_SCOPE_PROCESS_GROUP     2
 
+#define PR_SET_VMA             0x53564d41
+# define PR_SET_VMA_ANON_NAME          0
+
 #endif /* _LINUX_PRCTL_H */
index 5fbb79e..2d3e5df 100644 (file)
  *                                                                          *
  ****************************************************************************/
 
+#define AES_IEC958_STATUS_SIZE         24
+
 struct snd_aes_iec958 {
-       unsigned char status[24];       /* AES/IEC958 channel status bits */
+       unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
        unsigned char subcode[147];     /* AES/IEC958 subcode bits */
        unsigned char pad;              /* nothing */
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
@@ -202,6 +204,11 @@ typedef int __bitwise snd_pcm_format_t;
 #define        SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */
 #define        SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */
 #define        SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */
+/*
+ * For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
+ * available bit count in most significant bit. It's for the case of so-called 'left-justified' or
+ * `right-padding` sample which has less width than 32 bit.
+ */
 #define        SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
 #define        SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
 #define        SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
@@ -300,7 +307,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
 #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
 #define SNDRV_PCM_INFO_EXPLICIT_SYNC   0x10000000      /* needs explicit sync of pointers and data */
-
+#define SNDRV_PCM_INFO_NO_REWINDS      0x20000000      /* hardware can only support monotonic changes of appl_ptr */
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER   0x40000000              /* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
index f7ee07c..0d1634c 100644 (file)
@@ -13,6 +13,7 @@
 #include <internal/lib.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
+#include <linux/stringify.h>
 #include "internal.h"
 
 void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
@@ -294,6 +295,103 @@ static u64 read_timestamp(void)
 
        return low | ((u64)high) << 32;
 }
+#elif defined(__aarch64__)
+#define read_sysreg(r) ({                                              \
+       u64 __val;                                                      \
+       asm volatile("mrs %0, " __stringify(r) : "=r" (__val));         \
+       __val;                                                          \
+})
+
+static u64 read_pmccntr(void)
+{
+       return read_sysreg(pmccntr_el0);
+}
+
+#define PMEVCNTR_READ(idx)                                     \
+       static u64 read_pmevcntr_##idx(void) {                  \
+               return read_sysreg(pmevcntr##idx##_el0);        \
+       }
+
+PMEVCNTR_READ(0);
+PMEVCNTR_READ(1);
+PMEVCNTR_READ(2);
+PMEVCNTR_READ(3);
+PMEVCNTR_READ(4);
+PMEVCNTR_READ(5);
+PMEVCNTR_READ(6);
+PMEVCNTR_READ(7);
+PMEVCNTR_READ(8);
+PMEVCNTR_READ(9);
+PMEVCNTR_READ(10);
+PMEVCNTR_READ(11);
+PMEVCNTR_READ(12);
+PMEVCNTR_READ(13);
+PMEVCNTR_READ(14);
+PMEVCNTR_READ(15);
+PMEVCNTR_READ(16);
+PMEVCNTR_READ(17);
+PMEVCNTR_READ(18);
+PMEVCNTR_READ(19);
+PMEVCNTR_READ(20);
+PMEVCNTR_READ(21);
+PMEVCNTR_READ(22);
+PMEVCNTR_READ(23);
+PMEVCNTR_READ(24);
+PMEVCNTR_READ(25);
+PMEVCNTR_READ(26);
+PMEVCNTR_READ(27);
+PMEVCNTR_READ(28);
+PMEVCNTR_READ(29);
+PMEVCNTR_READ(30);
+
+/*
+ * Read a value direct from PMEVCNTR<idx>
+ */
+static u64 read_perf_counter(unsigned int counter)
+{
+       static u64 (* const read_f[])(void) = {
+               read_pmevcntr_0,
+               read_pmevcntr_1,
+               read_pmevcntr_2,
+               read_pmevcntr_3,
+               read_pmevcntr_4,
+               read_pmevcntr_5,
+               read_pmevcntr_6,
+               read_pmevcntr_7,
+               read_pmevcntr_8,
+               read_pmevcntr_9,
+               read_pmevcntr_10,
+               read_pmevcntr_11,
+               read_pmevcntr_13,
+               read_pmevcntr_12,
+               read_pmevcntr_14,
+               read_pmevcntr_15,
+               read_pmevcntr_16,
+               read_pmevcntr_17,
+               read_pmevcntr_18,
+               read_pmevcntr_19,
+               read_pmevcntr_20,
+               read_pmevcntr_21,
+               read_pmevcntr_22,
+               read_pmevcntr_23,
+               read_pmevcntr_24,
+               read_pmevcntr_25,
+               read_pmevcntr_26,
+               read_pmevcntr_27,
+               read_pmevcntr_28,
+               read_pmevcntr_29,
+               read_pmevcntr_30,
+               read_pmccntr
+       };
+
+       if (counter < ARRAY_SIZE(read_f))
+               return (read_f[counter])();
+
+       return 0;
+}
+
+static u64 read_timestamp(void) { return read_sysreg(cntvct_el0); }
+
 #else
 static u64 read_perf_counter(unsigned int counter __maybe_unused) { return 0; }
 static u64 read_timestamp(void) { return 0; }
index 33ae933..89be89a 100644 (file)
@@ -130,6 +130,9 @@ static int test_stat_user_read(int event)
        struct perf_event_attr attr = {
                .type   = PERF_TYPE_HARDWARE,
                .config = event,
+#ifdef __aarch64__
+               .config1 = 0x2,         /* Request user access */
+#endif
        };
        int err, i;
 
@@ -150,7 +153,7 @@ static int test_stat_user_read(int event)
        pc = perf_evsel__mmap_base(evsel, 0, 0);
        __T("failed to get mmapped address", pc);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
        __T("userspace counter access not supported", pc->cap_user_rdpmc);
        __T("userspace counter access not enabled", pc->index);
        __T("userspace counter width not set", pc->pmc_width >= 32);
index c2d2ab9..7c33ec6 100644 (file)
@@ -2854,7 +2854,7 @@ static inline bool func_uaccess_safe(struct symbol *func)
 
 static inline const char *call_dest_name(struct instruction *insn)
 {
-       static char pvname[16];
+       static char pvname[19];
        struct reloc *rel;
        int idx;
 
index dec24dc..a8785de 100644 (file)
@@ -1115,6 +1115,7 @@ enum perf_ftrace_subcommand {
 int cmd_ftrace(int argc, const char **argv)
 {
        int ret;
+       int (*cmd_func)(struct perf_ftrace *) = NULL;
        struct perf_ftrace ftrace = {
                .tracer = DEFAULT_TRACER,
                .target = { .uid = UINT_MAX, },
@@ -1221,6 +1222,28 @@ int cmd_ftrace(int argc, const char **argv)
                goto out_delete_filters;
        }
 
+       switch (subcmd) {
+       case PERF_FTRACE_TRACE:
+               if (!argc && target__none(&ftrace.target))
+                       ftrace.target.system_wide = true;
+               cmd_func = __cmd_ftrace;
+               break;
+       case PERF_FTRACE_LATENCY:
+               if (list_empty(&ftrace.filters)) {
+                       pr_err("Should provide a function to measure\n");
+                       parse_options_usage(ftrace_usage, options, "T", 1);
+                       ret = -EINVAL;
+                       goto out_delete_filters;
+               }
+               cmd_func = __cmd_latency;
+               break;
+       case PERF_FTRACE_NONE:
+       default:
+               pr_err("Invalid subcommand\n");
+               ret = -EINVAL;
+               goto out_delete_filters;
+       }
+
        ret = target__validate(&ftrace.target);
        if (ret) {
                char errbuf[512];
@@ -1248,27 +1271,7 @@ int cmd_ftrace(int argc, const char **argv)
                        goto out_delete_evlist;
        }
 
-       switch (subcmd) {
-       case PERF_FTRACE_TRACE:
-               if (!argc && target__none(&ftrace.target))
-                       ftrace.target.system_wide = true;
-               ret = __cmd_ftrace(&ftrace);
-               break;
-       case PERF_FTRACE_LATENCY:
-               if (list_empty(&ftrace.filters)) {
-                       pr_err("Should provide a function to measure\n");
-                       parse_options_usage(ftrace_usage, options, "T", 1);
-                       ret = -EINVAL;
-                       goto out_delete_evlist;
-               }
-               ret = __cmd_latency(&ftrace);
-               break;
-       case PERF_FTRACE_NONE:
-       default:
-               pr_err("Invalid subcommand\n");
-               ret = -EINVAL;
-               break;
-       }
+       ret = cmd_func(&ftrace);
 
 out_delete_evlist:
        evlist__delete(ftrace.evlist);
index 3109d7b..3d27878 100755 (executable)
@@ -4,7 +4,7 @@
 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
 
 printf "static const char *prctl_options[] = {\n"
-regex='^#define[[:space:]]+PR_(\w+)[[:space:]]*([[:xdigit:]]+).*'
+regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$'
 egrep $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \
        sed -r "s/$regex/\2 \1/g"       | \
        sort -n | xargs printf "\t[%s] = \"%s\",\n"
index 0190068..8190a12 100644 (file)
@@ -2036,6 +2036,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        memset(&objdump_process, 0, sizeof(objdump_process));
        objdump_process.argv = objdump_argv;
        objdump_process.out = -1;
+       objdump_process.err = -1;
        if (start_command(&objdump_process)) {
                pr_err("Failure starting to run %s\n", command);
                err = -1;
index 631e34a..ac60c08 100644 (file)
@@ -266,7 +266,7 @@ static int bperf_cgrp__read(struct evsel *evsel)
                idx = evsel->core.idx;
                err = bpf_map_lookup_elem(reading_map_fd, &idx, values);
                if (err) {
-                       pr_err("bpf map lookup falied: idx=%u, event=%s, cgrp=%s\n",
+                       pr_err("bpf map lookup failed: idx=%u, event=%s, cgrp=%s\n",
                               idx, evsel__name(evsel), evsel->cgrp->name);
                        goto out;
                }
index f70ba56..3945500 100644 (file)
@@ -2073,6 +2073,7 @@ static void ip__resolve_ams(struct thread *thread,
 
        ams->addr = ip;
        ams->al_addr = al.addr;
+       ams->al_level = al.level;
        ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
@@ -2092,6 +2093,7 @@ static void ip__resolve_data(struct thread *thread,
 
        ams->addr = addr;
        ams->al_addr = al.addr;
+       ams->al_level = al.level;
        ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
index 7d22ade..e08817b 100644 (file)
@@ -18,6 +18,7 @@ struct addr_map_symbol {
        struct map_symbol ms;
        u64           addr;
        u64           al_addr;
+       char          al_level;
        u64           phys_addr;
        u64           data_page_size;
 };
index 47b7531..98af3fa 100644 (file)
@@ -52,7 +52,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value)
                bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX),
                bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
                bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
-               bit_name(HW_INDEX),
+               bit_name(TYPE_SAVE), bit_name(HW_INDEX),
                { .name = NULL, }
        };
 #undef bit_name
index 2c0d30f..498b057 100644 (file)
@@ -1503,11 +1503,12 @@ static int machines__deliver_event(struct machines *machines,
                        ++evlist->stats.nr_unknown_id;
                        return 0;
                }
-               dump_sample(evsel, event, sample, perf_env__arch(machine->env));
                if (machine == NULL) {
                        ++evlist->stats.nr_unprocessable_samples;
+                       dump_sample(evsel, event, sample, perf_env__arch(NULL));
                        return 0;
                }
+               dump_sample(evsel, event, sample, perf_env__arch(machine->env));
                return evlist__deliver_sample(evlist, tool, event, sample, evsel, machine);
        case PERF_RECORD_MMAP:
                return tool->mmap(tool, event, sample, machine);
index cfba8c3..2da081e 100644 (file)
@@ -915,7 +915,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
                struct addr_map_symbol *from = &he->branch_info->from;
 
                return _hist_entry__sym_snprintf(&from->ms, from->al_addr,
-                                                he->level, bf, size, width);
+                                                from->al_level, bf, size, width);
        }
 
        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
@@ -928,7 +928,7 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
                struct addr_map_symbol *to = &he->branch_info->to;
 
                return _hist_entry__sym_snprintf(&to->ms, to->al_addr,
-                                                he->level, bf, size, width);
+                                                to->al_level, bf, size, width);
        }
 
        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
index 5db83e5..9cbe351 100644 (file)
@@ -585,15 +585,16 @@ static void collect_all_aliases(struct perf_stat_config *config, struct evsel *c
 
        alias = list_prepare_entry(counter, &(evlist->core.entries), core.node);
        list_for_each_entry_continue (alias, &evlist->core.entries, core.node) {
-               if (strcmp(evsel__name(alias), evsel__name(counter)) ||
-                   alias->scale != counter->scale ||
-                   alias->cgrp != counter->cgrp ||
-                   strcmp(alias->unit, counter->unit) ||
-                   evsel__is_clock(alias) != evsel__is_clock(counter) ||
-                   !strcmp(alias->pmu_name, counter->pmu_name))
-                       break;
-               alias->merged_stat = true;
-               cb(config, alias, data, false);
+               /* Merge events with the same name, etc. but on different PMUs. */
+               if (!strcmp(evsel__name(alias), evsel__name(counter)) &&
+                       alias->scale == counter->scale &&
+                       alias->cgrp == counter->cgrp &&
+                       !strcmp(alias->unit, counter->unit) &&
+                       evsel__is_clock(alias) == evsel__is_clock(counter) &&
+                       strcmp(alias->pmu_name, counter->pmu_name)) {
+                       alias->merged_stat = true;
+                       cb(config, alias, data, false);
+               }
        }
 }
 
index 70f0956..b654de0 100644 (file)
@@ -1784,6 +1784,25 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
                                  perf_event__handler_t process, bool needs_mmap,
                                  bool data_mmap, unsigned int nr_threads_synthesize)
 {
+       /*
+        * When perf runs in non-root PID namespace, and the namespace's proc FS
+        * is not mounted, nsinfo__is_in_root_namespace() returns false.
+        * In this case, the proc FS is coming for the parent namespace, thus
+        * perf tool will wrongly gather process info from its parent PID
+        * namespace.
+        *
+        * To avoid the confusion that the perf tool runs in a child PID
+        * namespace but it synthesizes thread info from its parent PID
+        * namespace, returns failure with warning.
+        */
+       if (!nsinfo__is_in_root_namespace()) {
+               pr_err("Perf runs in non-root PID namespace but it tries to ");
+               pr_err("gather process info from its parent PID namespace.\n");
+               pr_err("Please mount the proc file system properly, e.g. ");
+               pr_err("add the option '--mount-proc' for unshare command.\n");
+               return -EPERM;
+       }
+
        if (target__has_task(target))
                return perf_event__synthesize_thread_map(tool, threads, process, machine,
                                                         needs_mmap, data_mmap);
index b0be5f4..79d1023 100644 (file)
@@ -90,7 +90,7 @@ EXTRA_WARNINGS += -Wstrict-aliasing=3
 
 else ifneq ($(CROSS_COMPILE),)
 CLANG_CROSS_FLAGS := --target=$(notdir $(CROSS_COMPILE:%-=%))
-GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)gcc))
+GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)gcc 2>/dev/null))
 ifneq ($(GCC_TOOLCHAIN_DIR),)
 CLANG_CROSS_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))
 CLANG_CROSS_FLAGS += --sysroot=$(shell $(CROSS_COMPILE)gcc -print-sysroot)
index 44bbe54..3c4196c 100644 (file)
@@ -6,6 +6,7 @@
 # Author: Felix Guo <felixguoxiuping@gmail.com>
 # Author: Brendan Higgins <brendanhiggins@google.com>
 
+import importlib.abc
 import importlib.util
 import logging
 import subprocess
index ebf68dc..2893e9f 100644 (file)
@@ -28,7 +28,6 @@
 // 5. We can read keycode from same /dev/lirc device
 
 #include <linux/bpf.h>
-#include <linux/lirc.h>
 #include <linux/input.h>
 #include <errno.h>
 #include <stdio.h>
index 31f8c9a..60ce18e 100755 (executable)
@@ -194,5 +194,5 @@ prerequisite
 
 # Run requested functions
 clear_dumps $OUTFILE
-do_test >> $OUTFILE.txt
+do_test | tee -a $OUTFILE.txt
 dmesg_dumps $OUTFILE
index dd61118..12c5e27 100644 (file)
@@ -5,7 +5,7 @@ CFLAGS += -D_GNU_SOURCE
 
 TEST_PROGS := binfmt_script non-regular
 TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216
-TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir pipe
+TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir
 # Makefile is a run-time dependency, since it's accessed by the execveat test
 TEST_FILES := Makefile
 
index 12631f0..11e157d 100644 (file)
@@ -11,7 +11,7 @@ all:
        @for DIR in $(SUBDIRS); do              \
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
-               make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
                if [ -e $$DIR/$(TEST_PROGS) ]; then \
                        rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \
                fi \
@@ -32,6 +32,6 @@ override define CLEAN
        @for DIR in $(SUBDIRS); do              \
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
-               make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
        done
 endef
index 471eaa7..1177940 100644 (file)
@@ -877,7 +877,8 @@ static void __timeout_handler(int sig, siginfo_t *info, void *ucontext)
        }
 
        t->timed_out = true;
-       kill(t->pid, SIGKILL);
+       // signal process group
+       kill(-(t->pid), SIGKILL);
 }
 
 void __wait_for_test(struct __test_metadata *t)
@@ -987,6 +988,7 @@ void __run_test(struct __fixture_metadata *f,
                ksft_print_msg("ERROR SPAWNING TEST CHILD\n");
                t->passed = 0;
        } else if (t->pid == 0) {
+               setpgrp();
                t->fn(t, variant);
                if (t->skip)
                        _exit(255);
index e541066..4c88238 100644 (file)
@@ -207,15 +207,21 @@ TEST(check_file_mmap)
 
        errno = 0;
        fd = open(".", O_TMPFILE | O_RDWR, 0600);
-       ASSERT_NE(-1, fd) {
-               TH_LOG("Can't create temporary file: %s",
-                       strerror(errno));
+       if (fd < 0) {
+               ASSERT_EQ(errno, EOPNOTSUPP) {
+                       TH_LOG("Can't create temporary file: %s",
+                              strerror(errno));
+               }
+               SKIP(goto out_free, "O_TMPFILE not supported by filesystem.");
        }
        errno = 0;
        retval = fallocate(fd, 0, 0, FILE_SIZE);
-       ASSERT_EQ(0, retval) {
-               TH_LOG("Error allocating space for the temporary file: %s",
-                       strerror(errno));
+       if (retval) {
+               ASSERT_EQ(errno, EOPNOTSUPP) {
+                       TH_LOG("Error allocating space for the temporary file: %s",
+                              strerror(errno));
+               }
+               SKIP(goto out_close, "fallocate not supported by filesystem.");
        }
 
        /*
@@ -271,7 +277,9 @@ TEST(check_file_mmap)
        }
 
        munmap(addr, FILE_SIZE);
+out_close:
        close(fd);
+out_free:
        free(vec);
 }
 
index ed61f6c..df322e4 100755 (executable)
@@ -27,7 +27,7 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
        net6_port_net6_port net_port_mac_proto_net"
 
 # Reported bugs, also described by TYPE_ variables below
-BUGS="flush_remove_add"
+BUGS="flush_remove_add reload"
 
 # List of possible paths to pktgen script from kernel tree for performance tests
 PKTGEN_SCRIPT_PATHS="
@@ -354,6 +354,23 @@ TYPE_flush_remove_add="
 display                Add two elements, flush, re-add
 "
 
+TYPE_reload="
+display                net,mac with reload
+type_spec      ipv4_addr . ether_addr
+chain_spec     ip daddr . ether saddr
+dst            addr4
+src            mac
+start          1
+count          1
+src_delta      2000
+tools          sendip nc bash
+proto          udp
+
+race_repeat    0
+
+perf_duration  0
+"
+
 # Set template for all tests, types and rules are filled in depending on test
 set_template='
 flush ruleset
@@ -1473,6 +1490,59 @@ test_bug_flush_remove_add() {
        nft flush ruleset
 }
 
+# - add ranged element, check that packets match it
+# - reload the set, check packets still match
+test_bug_reload() {
+       setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
+       rstart=${start}
+
+       range_size=1
+       for i in $(seq "${start}" $((start + count))); do
+               end=$((start + range_size))
+
+               # Avoid negative or zero-sized port ranges
+               if [ $((end / 65534)) -gt $((start / 65534)) ]; then
+                       start=${end}
+                       end=$((end + 1))
+               fi
+               srcstart=$((start + src_delta))
+               srcend=$((end + src_delta))
+
+               add "$(format)" || return 1
+               range_size=$((range_size + 1))
+               start=$((end + range_size))
+       done
+
+       # check kernel does allocate pcpu sctrach map
+       # for reload with no elemet add/delete
+       ( echo flush set inet filter test ;
+         nft list set inet filter test ) | nft -f -
+
+       start=${rstart}
+       range_size=1
+
+       for i in $(seq "${start}" $((start + count))); do
+               end=$((start + range_size))
+
+               # Avoid negative or zero-sized port ranges
+               if [ $((end / 65534)) -gt $((start / 65534)) ]; then
+                       start=${end}
+                       end=$((end + 1))
+               fi
+               srcstart=$((start + src_delta))
+               srcend=$((end + src_delta))
+
+               for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
+                       send_match "${j}" $((j + src_delta)) || return 1
+               done
+
+               range_size=$((range_size + 1))
+               start=$((end + range_size))
+       done
+
+       nft flush ruleset
+}
+
 test_reported_issues() {
        eval test_bug_"${subtest}"
 }
index 349a319..79fe627 100755 (executable)
@@ -899,6 +899,144 @@ EOF
        ip netns exec "$ns0" nft delete table $family nat
 }
 
+test_stateless_nat_ip()
+{
+       local lret=0
+
+       ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
+       ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+
+       ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: cannot ping $ns1 from $ns2 before loading stateless rules"
+               return 1
+       fi
+
+ip netns exec "$ns0" nft -f /dev/stdin <<EOF
+table ip stateless {
+       map xlate_in {
+               typeof meta iifname . ip saddr . ip daddr : ip daddr
+               elements = {
+                       "veth1" . 10.0.2.99 . 10.0.1.99 : 10.0.2.2,
+               }
+       }
+       map xlate_out {
+               typeof meta iifname . ip saddr . ip daddr : ip daddr
+               elements = {
+                       "veth0" . 10.0.1.99 . 10.0.2.2 : 10.0.2.99
+               }
+       }
+
+       chain prerouting {
+               type filter hook prerouting priority -400; policy accept;
+               ip saddr set meta iifname . ip saddr . ip daddr map @xlate_in
+               ip daddr set meta iifname . ip saddr . ip daddr map @xlate_out
+       }
+}
+EOF
+       if [ $? -ne 0 ]; then
+               echo "SKIP: Could not add ip statless rules"
+               return $ksft_skip
+       fi
+
+       reset_counters
+
+       ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: cannot ping $ns1 from $ns2 with stateless rules"
+               lret=1
+       fi
+
+       # ns1 should have seen packets from .2.2, due to stateless rewrite.
+       expect="packets 1 bytes 84"
+       cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
+       if [ $? -ne 0 ]; then
+               bad_counter "$ns1" ns0insl "$expect" "test_stateless 1"
+               lret=1
+       fi
+
+       for dir in "in" "out" ; do
+               cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns2" ns1$dir "$expect" "test_stateless 2"
+                       lret=1
+               fi
+       done
+
+       # ns1 should not have seen packets from ns2, due to masquerade
+       expect="packets 0 bytes 0"
+       for dir in "in" "out" ; do
+               cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns1" ns0$dir "$expect" "test_stateless 3"
+                       lret=1
+               fi
+
+               cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns0" ns1$dir "$expect" "test_stateless 4"
+                       lret=1
+               fi
+       done
+
+       reset_counters
+
+       socat -h > /dev/null 2>&1
+       if [ $? -ne 0 ];then
+               echo "SKIP: Could not run stateless nat frag test without socat tool"
+               if [ $lret -eq 0 ]; then
+                       return $ksft_skip
+               fi
+
+               ip netns exec "$ns0" nft delete table ip stateless
+               return $lret
+       fi
+
+       local tmpfile=$(mktemp)
+       dd if=/dev/urandom of=$tmpfile bs=4096 count=1 2>/dev/null
+
+       local outfile=$(mktemp)
+       ip netns exec "$ns1" timeout 3 socat -u UDP4-RECV:4233 OPEN:$outfile < /dev/null &
+       sc_r=$!
+
+       sleep 1
+       # re-do with large ping -> ip fragmentation
+       ip netns exec "$ns2" timeout 3 socat - UDP4-SENDTO:"10.0.1.99:4233" < "$tmpfile" > /dev/null
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: failed to test udp $ns1 to $ns2 with stateless ip nat" 1>&2
+               lret=1
+       fi
+
+       wait
+
+       cmp "$tmpfile" "$outfile"
+       if [ $? -ne 0 ]; then
+               ls -l "$tmpfile" "$outfile"
+               echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2
+               lret=1
+       fi
+
+       rm -f "$tmpfile" "$outfile"
+
+       # ns1 should have seen packets from 2.2, due to stateless rewrite.
+       expect="packets 3 bytes 4164"
+       cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
+       if [ $? -ne 0 ]; then
+               bad_counter "$ns1" ns0insl "$expect" "test_stateless 5"
+               lret=1
+       fi
+
+       ip netns exec "$ns0" nft delete table ip stateless
+       if [ $? -ne 0 ]; then
+               echo "ERROR: Could not delete table ip stateless" 1>&2
+               lret=1
+       fi
+
+       test $lret -eq 0 && echo "PASS: IP statless for $ns2"
+
+       return $lret
+}
+
 # ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99
 for i in 0 1 2; do
 ip netns exec ns$i-$sfx nft -f /dev/stdin <<EOF
@@ -965,6 +1103,19 @@ table inet filter {
 EOF
 done
 
+# special case for stateless nat check, counter needs to
+# be done before (input) ip defragmentation
+ip netns exec ns1-$sfx nft -f /dev/stdin <<EOF
+table inet filter {
+       counter ns0insl {}
+
+       chain pre {
+               type filter hook prerouting priority -400; policy accept;
+               ip saddr 10.0.2.2 counter name "ns0insl"
+       }
+}
+EOF
+
 sleep 3
 # test basic connectivity
 for i in 1 2; do
@@ -1019,6 +1170,7 @@ $test_inet_nat && test_redirect inet
 $test_inet_nat && test_redirect6 inet
 
 test_port_shadowing
+test_stateless_nat_ip
 
 if [ $ret -ne 0 ];then
        echo -n "FAIL: "
index 0463311..5a8db0b 100755 (executable)
@@ -9,7 +9,7 @@ ns="ns-$sfx"
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
 
-zones=20000
+zones=2000
 have_ct_tool=0
 ret=0
 
@@ -75,10 +75,10 @@ EOF
 
        while [ $i -lt $max_zones ]; do
                local start=$(date +%s%3N)
-               i=$((i + 10000))
+               i=$((i + 1000))
                j=$((j + 1))
                # nft rule in output places each packet in a different zone.
-               dd if=/dev/zero of=/dev/stdout bs=8k count=10000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
+               dd if=/dev/zero of=/dev/stdout bs=8k count=1000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
                if [ $? -ne 0 ] ;then
                        ret=1
                        break
@@ -86,7 +86,7 @@ EOF
 
                stop=$(date +%s%3N)
                local duration=$((stop-start))
-               echo "PASS: added 10000 entries in $duration ms (now $i total, loop $j)"
+               echo "PASS: added 1000 entries in $duration ms (now $i total, loop $j)"
        done
 
        if [ $have_ct_tool -eq 1 ]; then
@@ -128,11 +128,11 @@ test_conntrack_tool() {
                        break
                fi
 
-               if [ $((i%10000)) -eq 0 ];then
+               if [ $((i%1000)) -eq 0 ];then
                        stop=$(date +%s%3N)
 
                        local duration=$((stop-start))
-                       echo "PASS: added 10000 entries in $duration ms (now $i total)"
+                       echo "PASS: added 1000 entries in $duration ms (now $i total)"
                        start=$stop
                fi
        done
index 4b93b14..843ba56 100644 (file)
@@ -5,4 +5,4 @@ TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test
 
 include ../lib.mk
 
-$(TEST_GEN_PROGS): helpers.c
+$(TEST_GEN_PROGS): helpers.c helpers.h
index a6ea273..7056340 100644 (file)
@@ -9,6 +9,7 @@
 
 #define _GNU_SOURCE
 #include <stdint.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <linux/types.h>
 #include "../kselftest.h"
@@ -62,11 +63,12 @@ bool needs_openat2(const struct open_how *how);
                                        (similar to chroot(2)). */
 #endif /* RESOLVE_IN_ROOT */
 
-#define E_func(func, ...)                                              \
-       do {                                                            \
-               if (func(__VA_ARGS__) < 0)                              \
-                       ksft_exit_fail_msg("%s:%d %s failed\n", \
-                                          __FILE__, __LINE__, #func);\
+#define E_func(func, ...)                                                    \
+       do {                                                                  \
+               errno = 0;                                                    \
+               if (func(__VA_ARGS__) < 0)                                    \
+                       ksft_exit_fail_msg("%s:%d %s failed - errno:%d\n",    \
+                                          __FILE__, __LINE__, #func, errno); \
        } while (0)
 
 #define E_asprintf(...)                E_func(asprintf,        __VA_ARGS__)
index 1bddbe9..7fb9020 100644 (file)
@@ -259,6 +259,16 @@ void test_openat2_flags(void)
                unlink(path);
 
                fd = sys_openat2(AT_FDCWD, path, &test->how);
+               if (fd < 0 && fd == -EOPNOTSUPP) {
+                       /*
+                        * Skip the testcase if it failed because not supported
+                        * by FS. (e.g. a valid O_TMPFILE combination on NFS)
+                        */
+                       ksft_test_result_skip("openat2 with %s fails with %d (%s)\n",
+                                             test->name, fd, strerror(-fd));
+                       goto next;
+               }
+
                if (test->err >= 0)
                        failed = (fd < 0);
                else
@@ -303,7 +313,7 @@ skip:
                else
                        resultfn("openat2 with %s fails with %d (%s)\n",
                                 test->name, test->err, strerror(-test->err));
-
+next:
                free(fdpath);
                fflush(stdout);
        }
index 8e83cf9..6d849dc 100644 (file)
@@ -44,9 +44,10 @@ static struct {
 } ctx;
 
 /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */
-#define TEST_SIG_DATA(addr) (~(unsigned long)(addr))
+#define TEST_SIG_DATA(addr, id) (~(unsigned long)(addr) + id)
 
-static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
+static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
+                                             unsigned long id)
 {
        struct perf_event_attr attr = {
                .type           = PERF_TYPE_BREAKPOINT,
@@ -60,7 +61,7 @@ static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
                .inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
                .remove_on_exec = 1, /* Required by sigtrap. */
                .sigtrap        = 1, /* Request synchronous SIGTRAP on event. */
-               .sig_data       = TEST_SIG_DATA(addr),
+               .sig_data       = TEST_SIG_DATA(addr, id),
        };
        return attr;
 }
@@ -110,7 +111,7 @@ FIXTURE(sigtrap_threads)
 
 FIXTURE_SETUP(sigtrap_threads)
 {
-       struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on);
+       struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
        struct sigaction action = {};
        int i;
 
@@ -165,7 +166,7 @@ TEST_F(sigtrap_threads, enable_event)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
 
        /* Check enabled for parent. */
        ctx.iterate_on = 0;
@@ -175,7 +176,7 @@ TEST_F(sigtrap_threads, enable_event)
 /* Test that modification propagates to all inherited events. */
 TEST_F(sigtrap_threads, modify_and_enable_event)
 {
-       struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on);
+       struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
 
        EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
        run_test_threads(_metadata, self);
@@ -184,7 +185,7 @@ TEST_F(sigtrap_threads, modify_and_enable_event)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
 
        /* Check enabled for parent. */
        ctx.iterate_on = 0;
@@ -204,7 +205,7 @@ TEST_F(sigtrap_threads, signal_stress)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
 }
 
 TEST_HARNESS_MAIN
index 3d603f1..883ca85 100644 (file)
@@ -33,110 +33,114 @@ typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
 typedef time_t (*vdso_time_t)(time_t *t);
 
-static int vdso_test_gettimeofday(void)
+#define VDSO_TEST_PASS_MSG()   "\n%s(): PASS\n", __func__
+#define VDSO_TEST_FAIL_MSG(x)  "\n%s(): %s FAIL\n", __func__, x
+#define VDSO_TEST_SKIP_MSG(x)  "\n%s(): SKIP: Could not find %s\n", __func__, x
+
+static void vdso_test_gettimeofday(void)
 {
        /* Find gettimeofday. */
        vdso_gettimeofday_t vdso_gettimeofday =
                (vdso_gettimeofday_t)vdso_sym(version, name[0]);
 
        if (!vdso_gettimeofday) {
-               printf("Could not find %s\n", name[0]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[0]));
+               return;
        }
 
        struct timeval tv;
        long ret = vdso_gettimeofday(&tv, 0);
 
        if (ret == 0) {
-               printf("The time is %lld.%06lld\n",
-                      (long long)tv.tv_sec, (long long)tv.tv_usec);
+               ksft_print_msg("The time is %lld.%06lld\n",
+                              (long long)tv.tv_sec, (long long)tv.tv_usec);
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[0]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[0]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_clock_gettime(clockid_t clk_id)
+static void vdso_test_clock_gettime(clockid_t clk_id)
 {
        /* Find clock_gettime. */
        vdso_clock_gettime_t vdso_clock_gettime =
                (vdso_clock_gettime_t)vdso_sym(version, name[1]);
 
        if (!vdso_clock_gettime) {
-               printf("Could not find %s\n", name[1]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[1]));
+               return;
        }
 
        struct timespec ts;
        long ret = vdso_clock_gettime(clk_id, &ts);
 
        if (ret == 0) {
-               printf("The time is %lld.%06lld\n",
-                      (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_print_msg("The time is %lld.%06lld\n",
+                              (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[1]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[1]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_time(void)
+static void vdso_test_time(void)
 {
        /* Find time. */
        vdso_time_t vdso_time =
                (vdso_time_t)vdso_sym(version, name[2]);
 
        if (!vdso_time) {
-               printf("Could not find %s\n", name[2]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[2]));
+               return;
        }
 
        long ret = vdso_time(NULL);
 
        if (ret > 0) {
-               printf("The time in hours since January 1, 1970 is %lld\n",
+               ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
                                (long long)(ret / 3600));
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[2]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[2]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_clock_getres(clockid_t clk_id)
+static void vdso_test_clock_getres(clockid_t clk_id)
 {
+       int clock_getres_fail = 0;
+
        /* Find clock_getres. */
        vdso_clock_getres_t vdso_clock_getres =
                (vdso_clock_getres_t)vdso_sym(version, name[3]);
 
        if (!vdso_clock_getres) {
-               printf("Could not find %s\n", name[3]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[3]));
+               return;
        }
 
        struct timespec ts, sys_ts;
        long ret = vdso_clock_getres(clk_id, &ts);
 
        if (ret == 0) {
-               printf("The resolution is %lld %lld\n",
-                      (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_print_msg("The vdso resolution is %lld %lld\n",
+                              (long long)ts.tv_sec, (long long)ts.tv_nsec);
        } else {
-               printf("%s failed\n", name[3]);
-               return KSFT_FAIL;
+               clock_getres_fail++;
        }
 
        ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
 
-       if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
-               printf("%s failed\n", name[3]);
-               return KSFT_FAIL;
-       }
+       ksft_print_msg("The syscall resolution is %lld %lld\n",
+                       (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
 
-       return KSFT_PASS;
+       if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
+               clock_getres_fail++;
+
+       if (clock_getres_fail > 0) {
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[3]));
+       } else {
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
+       }
 }
 
 const char *vdso_clock_name[12] = {
@@ -158,36 +162,23 @@ const char *vdso_clock_name[12] = {
  * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
  * with different values for clock_id.
  */
-static inline int vdso_test_clock(clockid_t clock_id)
+static inline void vdso_test_clock(clockid_t clock_id)
 {
-       int ret0, ret1;
-
-       ret0 = vdso_test_clock_gettime(clock_id);
-       /* A skipped test is considered passed */
-       if (ret0 == KSFT_SKIP)
-               ret0 = KSFT_PASS;
-
-       ret1 = vdso_test_clock_getres(clock_id);
-       /* A skipped test is considered passed */
-       if (ret1 == KSFT_SKIP)
-               ret1 = KSFT_PASS;
+       ksft_print_msg("\nclock_id: %s\n", vdso_clock_name[clock_id]);
 
-       ret0 += ret1;
+       vdso_test_clock_gettime(clock_id);
 
-       printf("clock_id: %s", vdso_clock_name[clock_id]);
-
-       if (ret0 > 0)
-               printf(" [FAIL]\n");
-       else
-               printf(" [PASS]\n");
-
-       return ret0;
+       vdso_test_clock_getres(clock_id);
 }
 
+#define VDSO_TEST_PLAN 16
+
 int main(int argc, char **argv)
 {
        unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
-       int ret;
+
+       ksft_print_header();
+       ksft_set_plan(VDSO_TEST_PLAN);
 
        if (!sysinfo_ehdr) {
                printf("AT_SYSINFO_EHDR is not present!\n");
@@ -201,44 +192,42 @@ int main(int argc, char **argv)
 
        vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
 
-       ret = vdso_test_gettimeofday();
+       vdso_test_gettimeofday();
 
 #if _POSIX_TIMERS > 0
 
 #ifdef CLOCK_REALTIME
-       ret += vdso_test_clock(CLOCK_REALTIME);
+       vdso_test_clock(CLOCK_REALTIME);
 #endif
 
 #ifdef CLOCK_BOOTTIME
-       ret += vdso_test_clock(CLOCK_BOOTTIME);
+       vdso_test_clock(CLOCK_BOOTTIME);
 #endif
 
 #ifdef CLOCK_TAI
-       ret += vdso_test_clock(CLOCK_TAI);
+       vdso_test_clock(CLOCK_TAI);
 #endif
 
 #ifdef CLOCK_REALTIME_COARSE
-       ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
+       vdso_test_clock(CLOCK_REALTIME_COARSE);
 #endif
 
 #ifdef CLOCK_MONOTONIC
-       ret += vdso_test_clock(CLOCK_MONOTONIC);
+       vdso_test_clock(CLOCK_MONOTONIC);
 #endif
 
 #ifdef CLOCK_MONOTONIC_RAW
-       ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
+       vdso_test_clock(CLOCK_MONOTONIC_RAW);
 #endif
 
 #ifdef CLOCK_MONOTONIC_COARSE
-       ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
+       vdso_test_clock(CLOCK_MONOTONIC_COARSE);
 #endif
 
 #endif
 
-       ret += vdso_test_time();
-
-       if (ret > 0)
-               return KSFT_FAIL;
+       vdso_test_time();
 
-       return KSFT_PASS;
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
 }
index d3fd24f..2f49c9a 100644 (file)
@@ -1417,6 +1417,7 @@ static void userfaultfd_pagemap_test(unsigned int test_pgsize)
 static int userfaultfd_stress(void)
 {
        void *area;
+       char *tmp_area;
        unsigned long nr;
        struct uffdio_register uffdio_register;
        struct uffd_stats uffd_stats[nr_cpus];
@@ -1527,9 +1528,13 @@ static int userfaultfd_stress(void)
                                            count_verify[nr], nr);
 
                /* prepare next bounce */
-               swap(area_src, area_dst);
+               tmp_area = area_src;
+               area_src = area_dst;
+               area_dst = tmp_area;
 
-               swap(area_src_alias, area_dst_alias);
+               tmp_area = area_src_alias;
+               area_src_alias = area_dst_alias;
+               area_dst_alias = tmp_area;
 
                uffd_stats_report(uffd_stats, nr_cpus);
        }
index 232e958..b0b91d9 100755 (executable)
@@ -2,9 +2,6 @@
 # SPDX-License-Identifier: GPL-2.0
 TCID="zram.sh"
 
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
 . ./zram_lib.sh
 
 run_zram () {
@@ -18,14 +15,4 @@ echo ""
 
 check_prereqs
 
-# check zram module exists
-MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
-if [ -f $MODULE_PATH ]; then
-       run_zram
-elif [ -b /dev/zram0 ]; then
-       run_zram
-else
-       echo "$TCID : No zram.ko module or /dev/zram0 device file not found"
-       echo "$TCID : CONFIG_ZRAM is not set"
-       exit $ksft_skip
-fi
+run_zram
index 114863d..8f4affe 100755 (executable)
@@ -33,9 +33,7 @@ zram_algs="lzo"
 
 zram_fill_fs()
 {
-       local mem_free0=$(free -m | awk 'NR==2 {print $4}')
-
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo "fill zram$i..."
                local b=0
                while [ true ]; do
@@ -45,29 +43,17 @@ zram_fill_fs()
                        b=$(($b + 1))
                done
                echo "zram$i can be filled with '$b' KB"
-       done
 
-       local mem_free1=$(free -m | awk 'NR==2 {print $4}')
-       local used_mem=$(($mem_free0 - $mem_free1))
+               local mem_used_total=`awk '{print $3}' "/sys/block/zram$i/mm_stat"`
+               local v=$((100 * 1024 * $b / $mem_used_total))
+               if [ "$v" -lt 100 ]; then
+                        echo "FAIL compression ratio: 0.$v:1"
+                        ERR_CODE=-1
+                        return
+               fi
 
-       local total_size=0
-       for sm in $zram_sizes; do
-               local s=$(echo $sm | sed 's/M//')
-               total_size=$(($total_size + $s))
+               echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK"
        done
-
-       echo "zram used ${used_mem}M, zram disk sizes ${total_size}M"
-
-       local v=$((100 * $total_size / $used_mem))
-
-       if [ "$v" -lt 100 ]; then
-               echo "FAIL compression ratio: 0.$v:1"
-               ERR_CODE=-1
-               zram_cleanup
-               return
-       fi
-
-       echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK"
 }
 
 check_prereqs
@@ -81,7 +67,6 @@ zram_mount
 
 zram_fill_fs
 zram_cleanup
-zram_unload
 
 if [ $ERR_CODE -ne 0 ]; then
        echo "$TCID : [FAIL]"
index e83b404..2418b0c 100755 (executable)
@@ -36,7 +36,6 @@ zram_set_memlimit
 zram_makeswap
 zram_swapoff
 zram_cleanup
-zram_unload
 
 if [ $ERR_CODE -ne 0 ]; then
        echo "$TCID : [FAIL]"
index 6f872f2..21ec196 100755 (executable)
@@ -5,12 +5,17 @@
 # Author: Alexey Kodanev <alexey.kodanev@oracle.com>
 # Modified: Naresh Kamboju <naresh.kamboju@linaro.org>
 
-MODULE=0
 dev_makeswap=-1
 dev_mounted=-1
-
+dev_start=0
+dev_end=-1
+module_load=-1
+sys_control=-1
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
+kernel_version=`uname -r | cut -d'.' -f1,2`
+kernel_major=${kernel_version%.*}
+kernel_minor=${kernel_version#*.}
 
 trap INT
 
@@ -25,68 +30,104 @@ check_prereqs()
        fi
 }
 
+kernel_gte()
+{
+       major=${1%.*}
+       minor=${1#*.}
+
+       if [ $kernel_major -gt $major ]; then
+               return 0
+       elif [[ $kernel_major -eq $major && $kernel_minor -ge $minor ]]; then
+               return 0
+       fi
+
+       return 1
+}
+
 zram_cleanup()
 {
        echo "zram cleanup"
        local i=
-       for i in $(seq 0 $dev_makeswap); do
+       for i in $(seq $dev_start $dev_makeswap); do
                swapoff /dev/zram$i
        done
 
-       for i in $(seq 0 $dev_mounted); do
+       for i in $(seq $dev_start $dev_mounted); do
                umount /dev/zram$i
        done
 
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo 1 > /sys/block/zram${i}/reset
                rm -rf zram$i
        done
 
-}
+       if [ $sys_control -eq 1 ]; then
+               for i in $(seq $dev_start $dev_end); do
+                       echo $i > /sys/class/zram-control/hot_remove
+               done
+       fi
 
-zram_unload()
-{
-       if [ $MODULE -ne 0 ] ; then
-               echo "zram rmmod zram"
+       if [ $module_load -eq 1 ]; then
                rmmod zram > /dev/null 2>&1
        fi
 }
 
 zram_load()
 {
-       # check zram module exists
-       MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
-       if [ -f $MODULE_PATH ]; then
-               MODULE=1
-               echo "create '$dev_num' zram device(s)"
-               modprobe zram num_devices=$dev_num
-               if [ $? -ne 0 ]; then
-                       echo "failed to insert zram module"
-                       exit 1
-               fi
-
-               dev_num_created=$(ls /dev/zram* | wc -w)
+       echo "create '$dev_num' zram device(s)"
+
+       # zram module loaded, new kernel
+       if [ -d "/sys/class/zram-control" ]; then
+               echo "zram modules already loaded, kernel supports" \
+                       "zram-control interface"
+               dev_start=$(ls /dev/zram* | wc -w)
+               dev_end=$(($dev_start + $dev_num - 1))
+               sys_control=1
+
+               for i in $(seq $dev_start $dev_end); do
+                       cat /sys/class/zram-control/hot_add > /dev/null
+               done
+
+               echo "all zram devices (/dev/zram$dev_start~$dev_end" \
+                       "successfully created"
+               return 0
+       fi
 
-               if [ "$dev_num_created" -ne "$dev_num" ]; then
-                       echo "unexpected num of devices: $dev_num_created"
-                       ERR_CODE=-1
+       # detect old kernel or built-in
+       modprobe zram num_devices=$dev_num
+       if [ ! -d "/sys/class/zram-control" ]; then
+               if grep -q '^zram' /proc/modules; then
+                       rmmod zram > /dev/null 2>&1
+                       if [ $? -ne 0 ]; then
+                               echo "zram module is being used on old kernel" \
+                                       "without zram-control interface"
+                               exit $ksft_skip
+                       fi
                else
-                       echo "zram load module successful"
+                       echo "test needs CONFIG_ZRAM=m on old kernel without" \
+                               "zram-control interface"
+                       exit $ksft_skip
                fi
-       elif [ -b /dev/zram0 ]; then
-               echo "/dev/zram0 device file found: OK"
-       else
-               echo "ERROR: No zram.ko module or no /dev/zram0 device found"
-               echo "$TCID : CONFIG_ZRAM is not set"
-               exit 1
+               modprobe zram num_devices=$dev_num
        fi
+
+       module_load=1
+       dev_end=$(($dev_num - 1))
+       echo "all zram devices (/dev/zram0~$dev_end) successfully created"
 }
 
 zram_max_streams()
 {
        echo "set max_comp_streams to zram device(s)"
 
-       local i=0
+       kernel_gte 4.7
+       if [ $? -eq 0 ]; then
+               echo "The device attribute max_comp_streams was"\
+                              "deprecated in 4.7"
+               return 0
+       fi
+
+       local i=$dev_start
        for max_s in $zram_max_streams; do
                local sys_path="/sys/block/zram${i}/max_comp_streams"
                echo $max_s > $sys_path || \
@@ -98,7 +139,7 @@ zram_max_streams()
                        echo "FAIL can't set max_streams '$max_s', get $max_stream"
 
                i=$(($i + 1))
-               echo "$sys_path = '$max_streams' ($i/$dev_num)"
+               echo "$sys_path = '$max_streams'"
        done
 
        echo "zram max streams: OK"
@@ -108,15 +149,16 @@ zram_compress_alg()
 {
        echo "test that we can set compression algorithm"
 
-       local algs=$(cat /sys/block/zram0/comp_algorithm)
+       local i=$dev_start
+       local algs=$(cat /sys/block/zram${i}/comp_algorithm)
        echo "supported algs: $algs"
-       local i=0
+
        for alg in $zram_algs; do
                local sys_path="/sys/block/zram${i}/comp_algorithm"
                echo "$alg" >   $sys_path || \
                        echo "FAIL can't set '$alg' to $sys_path"
                i=$(($i + 1))
-               echo "$sys_path = '$alg' ($i/$dev_num)"
+               echo "$sys_path = '$alg'"
        done
 
        echo "zram set compression algorithm: OK"
@@ -125,14 +167,14 @@ zram_compress_alg()
 zram_set_disksizes()
 {
        echo "set disk size to zram device(s)"
-       local i=0
+       local i=$dev_start
        for ds in $zram_sizes; do
                local sys_path="/sys/block/zram${i}/disksize"
                echo "$ds" >    $sys_path || \
                        echo "FAIL can't set '$ds' to $sys_path"
 
                i=$(($i + 1))
-               echo "$sys_path = '$ds' ($i/$dev_num)"
+               echo "$sys_path = '$ds'"
        done
 
        echo "zram set disksizes: OK"
@@ -142,14 +184,14 @@ zram_set_memlimit()
 {
        echo "set memory limit to zram device(s)"
 
-       local i=0
+       local i=$dev_start
        for ds in $zram_mem_limits; do
                local sys_path="/sys/block/zram${i}/mem_limit"
                echo "$ds" >    $sys_path || \
                        echo "FAIL can't set '$ds' to $sys_path"
 
                i=$(($i + 1))
-               echo "$sys_path = '$ds' ($i/$dev_num)"
+               echo "$sys_path = '$ds'"
        done
 
        echo "zram set memory limit: OK"
@@ -158,8 +200,8 @@ zram_set_memlimit()
 zram_makeswap()
 {
        echo "make swap with zram device(s)"
-       local i=0
-       for i in $(seq 0 $(($dev_num - 1))); do
+       local i=$dev_start
+       for i in $(seq $dev_start $dev_end); do
                mkswap /dev/zram$i > err.log 2>&1
                if [ $? -ne 0 ]; then
                        cat err.log
@@ -182,7 +224,7 @@ zram_makeswap()
 zram_swapoff()
 {
        local i=
-       for i in $(seq 0 $dev_makeswap); do
+       for i in $(seq $dev_start $dev_end); do
                swapoff /dev/zram$i > err.log 2>&1
                if [ $? -ne 0 ]; then
                        cat err.log
@@ -196,7 +238,7 @@ zram_swapoff()
 
 zram_makefs()
 {
-       local i=0
+       local i=$dev_start
        for fs in $zram_filesystems; do
                # if requested fs not supported default it to ext2
                which mkfs.$fs > /dev/null 2>&1 || fs=ext2
@@ -215,7 +257,7 @@ zram_makefs()
 zram_mount()
 {
        local i=0
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo "mount /dev/zram$i"
                mkdir zram$i
                mount /dev/zram$i zram$i > /dev/null || \