]> Git Repo - linux.git/commitdiff
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Tue, 3 Dec 2019 17:29:50 +0000 (09:29 -0800)
committerLinus Torvalds <[email protected]>
Tue, 3 Dec 2019 17:29:50 +0000 (09:29 -0800)
Pull irq updates from Ingo Molnar:
 "Most of the IRQ subsystem changes in this cycle were irq-chip driver
  updates:

   - Qualcomm PDC wakeup interrupt support

   - Layerscape external IRQ support

   - Broadcom bcm7038 PM and wakeup support

   - Ingenic driver cleanup and modernization

   - GICv3 ITS preparation for GICv4.1 updates

   - GICv4 fixes

  There's also the series from Frederic Weisbecker that fixes memory
  ordering bugs for the irq-work logic, whose primary fix is to turn
  work->irq_work.flags into an atomic variable and then convert the
  complex (and buggy) atomic_cmpxchg() loop in irq_work_claim() into a
  much simpler atomic_fetch_or() call.

  There are also various smaller cleanups"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits)
  pinctrl/sdm845: Add PDC wakeup interrupt map for GPIOs
  pinctrl/msm: Setup GPIO chip in hierarchy
  irqchip/qcom-pdc: Add irqchip set/get state calls
  irqchip/qcom-pdc: Add irqdomain for wakeup capable GPIOs
  irqchip/qcom-pdc: Do not toggle IRQ_ENABLE during mask/unmask
  irqchip/qcom-pdc: Update max PDC interrupts
  of/irq: Document properties for wakeup interrupt parent
  genirq: Introduce irq_chip_get/set_parent_state calls
  irqdomain: Add bus token DOMAIN_BUS_WAKEUP
  genirq: Fix function documentation of __irq_alloc_descs()
  irq_work: Fix IRQ_WORK_BUSY bit clearing
  irqchip/ti-sci-inta: Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...))
  irq_work: Slightly simplify IRQ_WORK_PENDING clearing
  irq_work: Fix irq_work_claim() memory ordering
  irq_work: Convert flags to atomic_t
  irqchip: Ingenic: Add process for more than one irq at the same time.
  irqchip: ingenic: Alloc generic chips from IRQ domain
  irqchip: ingenic: Get virq number from IRQ domain
  irqchip: ingenic: Error out if IRQ domain creation failed
  irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions
  ...

1  2 
drivers/irqchip/irq-gic-v3.c
drivers/pinctrl/qcom/pinctrl-msm.c
include/linux/irqchip/arm-gic-v3.h
kernel/bpf/stackmap.c
kernel/printk/printk.c
kernel/trace/bpf_trace.c

index 6bb1f682f78bad8aea65df2d71c158b6e1d0825d,9e3515557b04fc97c9d1f8be94a0ff18bf72e0b6..d6218012097b42901e2d727c2b4ca207574cff1c
@@@ -87,15 -87,6 +87,15 @@@ static DEFINE_STATIC_KEY_TRUE(supports_
   */
  static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
  
 +/*
 + * Global static key controlling whether an update to PMR allowing more
 + * interrupts requires to be propagated to the redistributor (DSB SY).
 + * And this needs to be exported for modules to be able to enable
 + * interrupts...
 + */
 +DEFINE_STATIC_KEY_FALSE(gic_pmr_sync);
 +EXPORT_SYMBOL(gic_pmr_sync);
 +
  /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
  static refcount_t *ppi_nmi_refs;
  
@@@ -183,7 -174,7 +183,7 @@@ static void gic_do_wait_for_rwp(void __
                }
                cpu_relax();
                udelay(1);
-       };
+       }
  }
  
  /* Wait for completion of a distributor change */
@@@ -240,7 -231,7 +240,7 @@@ static void gic_enable_redist(bool enab
                        break;
                cpu_relax();
                udelay(1);
-       };
+       }
        if (!count)
                pr_err_ratelimited("redistributor failed to %s...\n",
                                   enable ? "wakeup" : "sleep");
@@@ -1511,17 -1502,6 +1511,17 @@@ static void gic_enable_nmi_support(void
        for (i = 0; i < gic_data.ppi_nr; i++)
                refcount_set(&ppi_nmi_refs[i], 0);
  
 +      /*
 +       * Linux itself doesn't use 1:N distribution, so has no need to
 +       * set PMHE. The only reason to have it set is if EL3 requires it
 +       * (and we can't change it).
 +       */
 +      if (gic_read_ctlr() & ICC_CTLR_EL1_PMHE_MASK)
 +              static_branch_enable(&gic_pmr_sync);
 +
 +      pr_info("%s ICC_PMR_EL1 synchronisation\n",
 +              static_branch_unlikely(&gic_pmr_sync) ? "Forcing" : "Relaxing");
 +
        static_branch_enable(&supports_pseudo_nmis);
  
        if (static_branch_likely(&supports_deactivate_key))
index 62fcae9f05aed0a7e318b02eb0c316d740f02b5a,97883846409303f2484327d5a7ad4bda154002fd..5d6f9f61ce02cf8d34ee2ee87786571b190f6b7b
@@@ -23,6 -23,8 +23,8 @@@
  #include <linux/pm.h>
  #include <linux/log2.h>
  
+ #include <linux/soc/qcom/irq.h>
  #include "../core.h"
  #include "../pinconf.h"
  #include "pinctrl-msm.h"
@@@ -44,6 -46,7 +46,7 @@@
   * @enabled_irqs:   Bitmap of currently enabled irqs.
   * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
   *                  detection.
+  * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt controller
   * @soc;            Reference to soc_data of platform specific data.
   * @regs:           Base addresses for the TLMM tiles.
   */
@@@ -61,6 -64,7 +64,7 @@@ struct msm_pinctrl 
  
        DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
        DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+       DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO);
  
        const struct msm_pinctrl_soc_data *soc;
        void __iomem *regs[MAX_NR_TILES];
@@@ -707,6 -711,12 +711,12 @@@ static void msm_gpio_irq_mask(struct ir
        unsigned long flags;
        u32 val;
  
+       if (d->parent_data)
+               irq_chip_mask_parent(d);
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return;
        g = &pctrl->soc->groups[d->hwirq];
  
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@@ -751,6 -761,12 +761,12 @@@ static void msm_gpio_irq_clear_unmask(s
        unsigned long flags;
        u32 val;
  
+       if (d->parent_data)
+               irq_chip_unmask_parent(d);
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return;
        g = &pctrl->soc->groups[d->hwirq];
  
        raw_spin_lock_irqsave(&pctrl->lock, flags);
  
  static void msm_gpio_irq_enable(struct irq_data *d)
  {
+       /*
+        * Clear the interrupt that may be pending before we enable
+        * the line.
+        * This is especially a problem with the GPIOs routed to the
+        * PDC. These GPIOs are direct-connect interrupts to the GIC.
+        * Disabling the interrupt line at the PDC does not prevent
+        * the interrupt from being latched at the GIC. The state at
+        * GIC needs to be cleared before enabling.
+        */
+       if (d->parent_data) {
+               irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0);
+               irq_chip_enable_parent(d);
+       }
  
        msm_gpio_irq_clear_unmask(d, true);
  }
  
+ static void msm_gpio_irq_disable(struct irq_data *d)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+       if (d->parent_data)
+               irq_chip_disable_parent(d);
+       if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               msm_gpio_irq_mask(d);
+ }
  static void msm_gpio_irq_unmask(struct irq_data *d)
  {
        msm_gpio_irq_clear_unmask(d, false);
@@@ -795,6 -836,9 +836,9 @@@ static void msm_gpio_irq_ack(struct irq
        unsigned long flags;
        u32 val;
  
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return;
        g = &pctrl->soc->groups[d->hwirq];
  
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@@ -820,6 -864,12 +864,12 @@@ static int msm_gpio_irq_set_type(struc
        unsigned long flags;
        u32 val;
  
+       if (d->parent_data)
+               irq_chip_set_type_parent(d, type);
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return 0;
        g = &pctrl->soc->groups[d->hwirq];
  
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@@ -912,6 -962,15 +962,15 @@@ static int msm_gpio_irq_set_wake(struc
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        unsigned long flags;
  
+       /*
+        * While they may not wake up when the TLMM is powered off,
+        * some GPIOs would like to wakeup the system from suspend
+        * when TLMM is powered on. To allow that, enable the GPIO
+        * summary line to be wakeup capable at GIC.
+        */
+       if (d->parent_data)
+               irq_chip_set_wake_parent(d, on);
        raw_spin_lock_irqsave(&pctrl->lock, flags);
  
        irq_set_irq_wake(pctrl->irq, on);
@@@ -990,6 -1049,30 +1049,30 @@@ static void msm_gpio_irq_handler(struc
        chained_irq_exit(chip, desc);
  }
  
+ static int msm_gpio_wakeirq(struct gpio_chip *gc,
+                           unsigned int child,
+                           unsigned int child_type,
+                           unsigned int *parent,
+                           unsigned int *parent_type)
+ {
+       struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+       const struct msm_gpio_wakeirq_map *map;
+       int i;
+       *parent = GPIO_NO_WAKE_IRQ;
+       *parent_type = IRQ_TYPE_EDGE_RISING;
+       for (i = 0; i < pctrl->soc->nwakeirq_map; i++) {
+               map = &pctrl->soc->wakeirq_map[i];
+               if (map->gpio == child) {
+                       *parent = map->wakeirq;
+                       break;
+               }
+       }
+       return 0;
+ }
  static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
  {
        if (pctrl->soc->reserved_gpios)
@@@ -1002,8 -1085,10 +1085,10 @@@ static int msm_gpio_init(struct msm_pin
  {
        struct gpio_chip *chip;
        struct gpio_irq_chip *girq;
-       int ret;
-       unsigned ngpio = pctrl->soc->ngpios;
+       int i, ret;
+       unsigned gpio, ngpio = pctrl->soc->ngpios;
+       struct device_node *np;
+       bool skip;
  
        if (WARN_ON(ngpio > MAX_NR_GPIO))
                return -EINVAL;
  
        pctrl->irq_chip.name = "msmgpio";
        pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
+       pctrl->irq_chip.irq_disable = msm_gpio_irq_disable;
        pctrl->irq_chip.irq_mask = msm_gpio_irq_mask;
        pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask;
        pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
+       pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent;
        pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type;
        pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
        pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
        pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
  
+       np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
+       if (np) {
+               chip->irq.parent_domain = irq_find_matching_host(np,
+                                                DOMAIN_BUS_WAKEUP);
+               of_node_put(np);
+               if (!chip->irq.parent_domain)
+                       return -EPROBE_DEFER;
+               chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq;
+               /*
+                * Let's skip handling the GPIOs, if the parent irqchip
+                * is handling the direct connect IRQ of the GPIO.
+                */
+               skip = irq_domain_qcom_handle_wakeup(chip->irq.parent_domain);
+               for (i = 0; skip && i < pctrl->soc->nwakeirq_map; i++) {
+                       gpio = pctrl->soc->wakeirq_map[i].gpio;
+                       set_bit(gpio, pctrl->skip_wake_irqs);
+               }
+       }
        girq = &chip->irq;
        girq->chip = &pctrl->irq_chip;
        girq->parent_handler = msm_gpio_irq_handler;
+       girq->fwnode = pctrl->dev->fwnode;
        girq->num_parents = 1;
        girq->parents = devm_kcalloc(pctrl->dev, 1, sizeof(*girq->parents),
                                     GFP_KERNEL);
@@@ -1150,7 -1258,8 +1258,7 @@@ int msm_pinctrl_probe(struct platform_d
                                return PTR_ERR(pctrl->regs[i]);
                }
        } else {
 -              res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 -              pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res);
 +              pctrl->regs[0] = devm_platform_ioremap_resource(pdev, 0);
                if (IS_ERR(pctrl->regs[0]))
                        return PTR_ERR(pctrl->regs[0]);
        }
index a0bde9e12efa3b2fd7cacba32ae4a3961fb14139,b6514e8893bf68f2ba8d77a7cc4c55b8a4c2fec3..de991d6633a5f99e929ca191506c87855a165e13
  #define GITS_TYPER_PLPIS              (1UL << 0)
  #define GITS_TYPER_VLPIS              (1UL << 1)
  #define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT       4
- #define GITS_TYPER_ITT_ENTRY_SIZE(r)  ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0xf) + 1)
+ #define GITS_TYPER_ITT_ENTRY_SIZE     GENMASK_ULL(7, 4)
  #define GITS_TYPER_IDBITS_SHIFT               8
  #define GITS_TYPER_DEVBITS_SHIFT      13
- #define GITS_TYPER_DEVBITS(r)         ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
+ #define GITS_TYPER_DEVBITS            GENMASK_ULL(17, 13)
  #define GITS_TYPER_PTA                        (1UL << 19)
  #define GITS_TYPER_HCC_SHIFT          24
  #define GITS_TYPER_HCC(r)             (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff)
  #define ICC_CTLR_EL1_EOImode_MASK     (1 << ICC_CTLR_EL1_EOImode_SHIFT)
  #define ICC_CTLR_EL1_CBPR_SHIFT               0
  #define ICC_CTLR_EL1_CBPR_MASK                (1 << ICC_CTLR_EL1_CBPR_SHIFT)
 +#define ICC_CTLR_EL1_PMHE_SHIFT               6
 +#define ICC_CTLR_EL1_PMHE_MASK                (1 << ICC_CTLR_EL1_PMHE_SHIFT)
  #define ICC_CTLR_EL1_PRI_BITS_SHIFT   8
  #define ICC_CTLR_EL1_PRI_BITS_MASK    (0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
  #define ICC_CTLR_EL1_ID_BITS_SHIFT    11
diff --combined kernel/bpf/stackmap.c
index caca752ee5e645f6a07022cac95da119582b65bf,4d31284095e29f0ddba9a667078fcb43c3da627d..3f958b90d914ffd6e25d3772938564435a79b4b6
@@@ -287,17 -287,16 +287,17 @@@ static void stack_map_get_build_id_offs
        bool irq_work_busy = false;
        struct stack_map_irq_work *work = NULL;
  
 -      if (in_nmi()) {
 +      if (irqs_disabled()) {
                work = this_cpu_ptr(&up_read_work);
-               if (work->irq_work.flags & IRQ_WORK_BUSY)
+               if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY)
                        /* cannot queue more up_read, fallback */
                        irq_work_busy = true;
        }
  
        /*
 -       * We cannot do up_read() in nmi context. To do build_id lookup
 -       * in nmi context, we need to run up_read() in irq_work. We use
 +       * We cannot do up_read() when the irq is disabled, because of
 +       * risk to deadlock with rq_lock. To do build_id lookup when the
 +       * irqs are disabled, we need to run up_read() in irq_work. We use
         * a percpu variable to do the irq_work. If the irq_work is
         * already used by another lookup, we fall back to report ips.
         *
                 * up_read_non_owner(). The rwsem_release() is called
                 * here to release the lock from lockdep's perspective.
                 */
 -              rwsem_release(&current->mm->mmap_sem.dep_map, 1, _RET_IP_);
 +              rwsem_release(&current->mm->mmap_sem.dep_map, _RET_IP_);
        }
  }
  
diff --combined kernel/printk/printk.c
index c8be5a0f525958ee9f8fbf8d3df371eccc4354fb,865727373a3bf2818908931da8ef1409365482a6..1ef6f75d92f1f6c186fd1187786023a996a7fea0
@@@ -248,7 -248,7 +248,7 @@@ static void __up_console_sem(unsigned l
  {
        unsigned long flags;
  
 -      mutex_release(&console_lock_dep_map, 1, ip);
 +      mutex_release(&console_lock_dep_map, ip);
  
        printk_safe_enter_irqsave(flags);
        up(&console_sem);
@@@ -1679,20 -1679,20 +1679,20 @@@ static int console_lock_spinning_disabl
        raw_spin_unlock(&console_owner_lock);
  
        if (!waiter) {
 -              spin_release(&console_owner_dep_map, 1, _THIS_IP_);
 +              spin_release(&console_owner_dep_map, _THIS_IP_);
                return 0;
        }
  
        /* The waiter is now free to continue */
        WRITE_ONCE(console_waiter, false);
  
 -      spin_release(&console_owner_dep_map, 1, _THIS_IP_);
 +      spin_release(&console_owner_dep_map, _THIS_IP_);
  
        /*
         * Hand off console_lock to waiter. The waiter will perform
         * the up(). After this, the waiter is the console_lock owner.
         */
 -      mutex_release(&console_lock_dep_map, 1, _THIS_IP_);
 +      mutex_release(&console_lock_dep_map, _THIS_IP_);
        return 1;
  }
  
@@@ -1746,7 -1746,7 +1746,7 @@@ static int console_trylock_spinning(voi
        /* Owner will clear console_waiter on hand off */
        while (READ_ONCE(console_waiter))
                cpu_relax();
 -      spin_release(&console_owner_dep_map, 1, _THIS_IP_);
 +      spin_release(&console_owner_dep_map, _THIS_IP_);
  
        printk_safe_exit_irqrestore(flags);
        /*
@@@ -2961,7 -2961,7 +2961,7 @@@ static void wake_up_klogd_work_func(str
  
  static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
        .func = wake_up_klogd_work_func,
-       .flags = IRQ_WORK_LAZY,
+       .flags = ATOMIC_INIT(IRQ_WORK_LAZY),
  };
  
  void wake_up_klogd(void)
diff --combined kernel/trace/bpf_trace.c
index ffc91d4935ac91dc63b472f71be6c254f0c29dee,ff467a4e263925e775961dc2847f88239b5a3eff..e5ef4ae9edb5060c78470826e28c452e687ce2fa
@@@ -138,140 -138,24 +138,140 @@@ static const struct bpf_func_proto bpf_
  };
  #endif
  
 -BPF_CALL_3(bpf_probe_read, void *, dst, u32, size, const void *, unsafe_ptr)
 +BPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size,
 +         const void __user *, unsafe_ptr)
  {
 -      int ret;
 +      int ret = probe_user_read(dst, unsafe_ptr, size);
  
 -      ret = security_locked_down(LOCKDOWN_BPF_READ);
 -      if (ret < 0)
 -              goto out;
 +      if (unlikely(ret < 0))
 +              memset(dst, 0, size);
 +
 +      return ret;
 +}
 +
 +static const struct bpf_func_proto bpf_probe_read_user_proto = {
 +      .func           = bpf_probe_read_user,
 +      .gpl_only       = true,
 +      .ret_type       = RET_INTEGER,
 +      .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
 +      .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
 +      .arg3_type      = ARG_ANYTHING,
 +};
 +
 +BPF_CALL_3(bpf_probe_read_user_str, void *, dst, u32, size,
 +         const void __user *, unsafe_ptr)
 +{
 +      int ret = strncpy_from_unsafe_user(dst, unsafe_ptr, size);
  
 -      ret = probe_kernel_read(dst, unsafe_ptr, size);
 +      if (unlikely(ret < 0))
 +              memset(dst, 0, size);
 +
 +      return ret;
 +}
 +
 +static const struct bpf_func_proto bpf_probe_read_user_str_proto = {
 +      .func           = bpf_probe_read_user_str,
 +      .gpl_only       = true,
 +      .ret_type       = RET_INTEGER,
 +      .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
 +      .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
 +      .arg3_type      = ARG_ANYTHING,
 +};
 +
 +static __always_inline int
 +bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr,
 +                           const bool compat)
 +{
 +      int ret = security_locked_down(LOCKDOWN_BPF_READ);
 +
 +      if (unlikely(ret < 0))
 +              goto out;
 +      ret = compat ? probe_kernel_read(dst, unsafe_ptr, size) :
 +            probe_kernel_read_strict(dst, unsafe_ptr, size);
        if (unlikely(ret < 0))
  out:
                memset(dst, 0, size);
 +      return ret;
 +}
 +
 +BPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size,
 +         const void *, unsafe_ptr)
 +{
 +      return bpf_probe_read_kernel_common(dst, size, unsafe_ptr, false);
 +}
 +
 +static const struct bpf_func_proto bpf_probe_read_kernel_proto = {
 +      .func           = bpf_probe_read_kernel,
 +      .gpl_only       = true,
 +      .ret_type       = RET_INTEGER,
 +      .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
 +      .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
 +      .arg3_type      = ARG_ANYTHING,
 +};
  
 +BPF_CALL_3(bpf_probe_read_compat, void *, dst, u32, size,
 +         const void *, unsafe_ptr)
 +{
 +      return bpf_probe_read_kernel_common(dst, size, unsafe_ptr, true);
 +}
 +
 +static const struct bpf_func_proto bpf_probe_read_compat_proto = {
 +      .func           = bpf_probe_read_compat,
 +      .gpl_only       = true,
 +      .ret_type       = RET_INTEGER,
 +      .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
 +      .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
 +      .arg3_type      = ARG_ANYTHING,
 +};
 +
 +static __always_inline int
 +bpf_probe_read_kernel_str_common(void *dst, u32 size, const void *unsafe_ptr,
 +                               const bool compat)
 +{
 +      int ret = security_locked_down(LOCKDOWN_BPF_READ);
 +
 +      if (unlikely(ret < 0))
 +              goto out;
 +      /*
 +       * The strncpy_from_unsafe_*() call will likely not fill the entire
 +       * buffer, but that's okay in this circumstance as we're probing
 +       * arbitrary memory anyway similar to bpf_probe_read_*() and might
 +       * as well probe the stack. Thus, memory is explicitly cleared
 +       * only in error case, so that improper users ignoring return
 +       * code altogether don't copy garbage; otherwise length of string
 +       * is returned that can be used for bpf_perf_event_output() et al.
 +       */
 +      ret = compat ? strncpy_from_unsafe(dst, unsafe_ptr, size) :
 +            strncpy_from_unsafe_strict(dst, unsafe_ptr, size);
 +      if (unlikely(ret < 0))
 +out:
 +              memset(dst, 0, size);
        return ret;
  }
  
 -static const struct bpf_func_proto bpf_probe_read_proto = {
 -      .func           = bpf_probe_read,
 +BPF_CALL_3(bpf_probe_read_kernel_str, void *, dst, u32, size,
 +         const void *, unsafe_ptr)
 +{
 +      return bpf_probe_read_kernel_str_common(dst, size, unsafe_ptr, false);
 +}
 +
 +static const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {
 +      .func           = bpf_probe_read_kernel_str,
 +      .gpl_only       = true,
 +      .ret_type       = RET_INTEGER,
 +      .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
 +      .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
 +      .arg3_type      = ARG_ANYTHING,
 +};
 +
 +BPF_CALL_3(bpf_probe_read_compat_str, void *, dst, u32, size,
 +         const void *, unsafe_ptr)
 +{
 +      return bpf_probe_read_kernel_str_common(dst, size, unsafe_ptr, true);
 +}
 +
 +static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {
 +      .func           = bpf_probe_read_compat_str,
        .gpl_only       = true,
        .ret_type       = RET_INTEGER,
        .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
        .arg3_type      = ARG_ANYTHING,
  };
  
 -BPF_CALL_3(bpf_probe_write_user, void *, unsafe_ptr, const void *, src,
 +BPF_CALL_3(bpf_probe_write_user, void __user *, unsafe_ptr, const void *, src,
           u32, size)
  {
        /*
                return -EPERM;
        if (unlikely(!nmi_uaccess_okay()))
                return -EPERM;
 -      if (!access_ok(unsafe_ptr, size))
 -              return -EPERM;
  
 -      return probe_kernel_write(unsafe_ptr, src, size);
 +      return probe_user_write(unsafe_ptr, src, size);
  }
  
  static const struct bpf_func_proto bpf_probe_write_user_proto = {
@@@ -699,6 -585,41 +699,6 @@@ static const struct bpf_func_proto bpf_
        .arg2_type      = ARG_ANYTHING,
  };
  
 -BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size,
 -         const void *, unsafe_ptr)
 -{
 -      int ret;
 -
 -      ret = security_locked_down(LOCKDOWN_BPF_READ);
 -      if (ret < 0)
 -              goto out;
 -
 -      /*
 -       * The strncpy_from_unsafe() call will likely not fill the entire
 -       * buffer, but that's okay in this circumstance as we're probing
 -       * arbitrary memory anyway similar to bpf_probe_read() and might
 -       * as well probe the stack. Thus, memory is explicitly cleared
 -       * only in error case, so that improper users ignoring return
 -       * code altogether don't copy garbage; otherwise length of string
 -       * is returned that can be used for bpf_perf_event_output() et al.
 -       */
 -      ret = strncpy_from_unsafe(dst, unsafe_ptr, size);
 -      if (unlikely(ret < 0))
 -out:
 -              memset(dst, 0, size);
 -
 -      return ret;
 -}
 -
 -static const struct bpf_func_proto bpf_probe_read_str_proto = {
 -      .func           = bpf_probe_read_str,
 -      .gpl_only       = true,
 -      .ret_type       = RET_INTEGER,
 -      .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
 -      .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
 -      .arg3_type      = ARG_ANYTHING,
 -};
 -
  struct send_signal_irq_work {
        struct irq_work irq_work;
        struct task_struct *task;
@@@ -739,7 -660,7 +739,7 @@@ BPF_CALL_1(bpf_send_signal, u32, sig
                        return -EINVAL;
  
                work = this_cpu_ptr(&send_signal_work);
-               if (work->irq_work.flags & IRQ_WORK_BUSY)
+               if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY)
                        return -EBUSY;
  
                /* Add the current task, which is the target of sending signal,
@@@ -778,6 -699,8 +778,6 @@@ tracing_func_proto(enum bpf_func_id fun
                return &bpf_map_pop_elem_proto;
        case BPF_FUNC_map_peek_elem:
                return &bpf_map_peek_elem_proto;
 -      case BPF_FUNC_probe_read:
 -              return &bpf_probe_read_proto;
        case BPF_FUNC_ktime_get_ns:
                return &bpf_ktime_get_ns_proto;
        case BPF_FUNC_tail_call:
                return &bpf_current_task_under_cgroup_proto;
        case BPF_FUNC_get_prandom_u32:
                return &bpf_get_prandom_u32_proto;
 +      case BPF_FUNC_probe_read_user:
 +              return &bpf_probe_read_user_proto;
 +      case BPF_FUNC_probe_read_kernel:
 +              return &bpf_probe_read_kernel_proto;
 +      case BPF_FUNC_probe_read:
 +              return &bpf_probe_read_compat_proto;
 +      case BPF_FUNC_probe_read_user_str:
 +              return &bpf_probe_read_user_str_proto;
 +      case BPF_FUNC_probe_read_kernel_str:
 +              return &bpf_probe_read_kernel_str_proto;
        case BPF_FUNC_probe_read_str:
 -              return &bpf_probe_read_str_proto;
 +              return &bpf_probe_read_compat_str_proto;
  #ifdef CONFIG_CGROUPS
        case BPF_FUNC_get_current_cgroup_id:
                return &bpf_get_current_cgroup_id_proto;
@@@ -1082,8 -995,6 +1082,8 @@@ static const struct bpf_func_proto bpf_
        .arg5_type      = ARG_CONST_SIZE_OR_ZERO,
  };
  
 +extern const struct bpf_func_proto bpf_skb_output_proto;
 +
  BPF_CALL_3(bpf_get_stackid_raw_tp, struct bpf_raw_tracepoint_args *, args,
           struct bpf_map *, map, u64, flags)
  {
@@@ -1151,25 -1062,13 +1151,25 @@@ raw_tp_prog_func_proto(enum bpf_func_i
        }
  }
  
 +static const struct bpf_func_proto *
 +tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 +{
 +      switch (func_id) {
 +#ifdef CONFIG_NET
 +      case BPF_FUNC_skb_output:
 +              return &bpf_skb_output_proto;
 +#endif
 +      default:
 +              return raw_tp_prog_func_proto(func_id, prog);
 +      }
 +}
 +
  static bool raw_tp_prog_is_valid_access(int off, int size,
                                        enum bpf_access_type type,
                                        const struct bpf_prog *prog,
                                        struct bpf_insn_access_aux *info)
  {
 -      /* largest tracepoint in the kernel has 12 args */
 -      if (off < 0 || off >= sizeof(__u64) * 12)
 +      if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS)
                return false;
        if (type != BPF_READ)
                return false;
        return true;
  }
  
 +static bool tracing_prog_is_valid_access(int off, int size,
 +                                       enum bpf_access_type type,
 +                                       const struct bpf_prog *prog,
 +                                       struct bpf_insn_access_aux *info)
 +{
 +      if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS)
 +              return false;
 +      if (type != BPF_READ)
 +              return false;
 +      if (off % size != 0)
 +              return false;
 +      return btf_ctx_access(off, size, type, prog, info);
 +}
 +
  const struct bpf_verifier_ops raw_tracepoint_verifier_ops = {
        .get_func_proto  = raw_tp_prog_func_proto,
        .is_valid_access = raw_tp_prog_is_valid_access,
  const struct bpf_prog_ops raw_tracepoint_prog_ops = {
  };
  
 +const struct bpf_verifier_ops tracing_verifier_ops = {
 +      .get_func_proto  = tracing_prog_func_proto,
 +      .is_valid_access = tracing_prog_is_valid_access,
 +};
 +
 +const struct bpf_prog_ops tracing_prog_ops = {
 +};
 +
  static bool raw_tp_writable_prog_is_valid_access(int off, int size,
                                                 enum bpf_access_type type,
                                                 const struct bpf_prog *prog,
This page took 0.172875 seconds and 4 git commands to generate.