Merge 7caee37c46 ("net: usb: usbnet: fix name regression") into android15-6.6-lts

Steps on the way to 6.6.59

Change-Id: I94b0e92b46abae9507c7f5eb877b48148cf48108
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2024-12-05 11:26:42 +00:00
commit c448d4e4c0
56 changed files with 1267 additions and 649 deletions

View File

@ -10,7 +10,7 @@
# #
# Copyright (C) 1995-2001 by Russell King # Copyright (C) 1995-2001 by Russell King
LDFLAGS_vmlinux :=--no-undefined -X LDFLAGS_vmlinux :=--no-undefined -X --pic-veneer
ifeq ($(CONFIG_RELOCATABLE), y) ifeq ($(CONFIG_RELOCATABLE), y)
# Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour

View File

@ -293,13 +293,15 @@ unsigned long stack_top(void)
{ {
unsigned long top = TASK_SIZE & PAGE_MASK; unsigned long top = TASK_SIZE & PAGE_MASK;
/* Space for the VDSO & data page */ if (current->thread.vdso) {
top -= PAGE_ALIGN(current->thread.vdso->size); /* Space for the VDSO & data page */
top -= VVAR_SIZE; top -= PAGE_ALIGN(current->thread.vdso->size);
top -= VVAR_SIZE;
/* Space to randomize the VDSO base */ /* Space to randomize the VDSO base */
if (current->flags & PF_RANDOMIZE) if (current->flags & PF_RANDOMIZE)
top -= VDSO_RANDOMIZE_SIZE; top -= VDSO_RANDOMIZE_SIZE;
}
return top; return top;
} }

View File

@ -139,7 +139,15 @@ int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
flags |= VBOX_MOUSE_POINTER_VISIBLE; flags |= VBOX_MOUSE_POINTER_VISIBLE;
} }
p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len, HGSMI_CH_VBVA, /*
* The 4 extra bytes come from switching struct vbva_mouse_pointer_shape
* from having a 4 bytes fixed array at the end to using a proper VLA
* at the end. These 4 extra bytes were not subtracted from sizeof(*p)
* before the switch to the VLA, so this way the behavior is unchanged.
* Chances are these 4 extra bytes are not necessary but they are kept
* to avoid regressions.
*/
p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len + 4, HGSMI_CH_VBVA,
VBVA_MOUSE_POINTER_SHAPE); VBVA_MOUSE_POINTER_SHAPE);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;

View File

@ -351,10 +351,8 @@ struct vbva_mouse_pointer_shape {
* Bytes in the gap between the AND and the XOR mask are undefined. * Bytes in the gap between the AND and the XOR mask are undefined.
* XOR mask scanlines have no gap between them and size of XOR mask is: * XOR mask scanlines have no gap between them and size of XOR mask is:
* xor_len = width * 4 * height. * xor_len = width * 4 * height.
*
* Preallocate 4 bytes for accessing actual data as p->data.
*/ */
u8 data[4]; u8 data[];
} __packed; } __packed;
/* pointer is visible */ /* pointer is visible */

View File

@ -1335,6 +1335,8 @@ config TI_LMP92064
tristate "Texas Instruments LMP92064 ADC driver" tristate "Texas Instruments LMP92064 ADC driver"
depends on SPI depends on SPI
select REGMAP_SPI select REGMAP_SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help help
Say yes here to build support for the LMP92064 Precision Current and Voltage Say yes here to build support for the LMP92064 Precision Current and Voltage
sensor. sensor.

View File

@ -1713,6 +1713,7 @@ int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,
ptr = shift / 8; ptr = shift / 8;
shift %= 8; shift %= 8;
mask >>= ptr * 8; mask >>= ptr * 8;
ptr <<= 8;
err = mv88e6393x_port_policy_read(chip, port, ptr, &reg); err = mv88e6393x_port_policy_read(chip, port, ptr, &reg);
if (err) if (err)

View File

@ -1381,10 +1381,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
be_get_wrb_params_from_skb(adapter, skb, &wrb_params); be_get_wrb_params_from_skb(adapter, skb, &wrb_params);
wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params); wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
if (unlikely(!wrb_cnt)) { if (unlikely(!wrb_cnt))
dev_kfree_skb_any(skb); goto drop_skb;
goto drop;
}
/* if os2bmc is enabled and if the pkt is destined to bmc, /* if os2bmc is enabled and if the pkt is destined to bmc,
* enqueue the pkt a 2nd time with mgmt bit set. * enqueue the pkt a 2nd time with mgmt bit set.
@ -1393,7 +1391,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
BE_WRB_F_SET(wrb_params.features, OS2BMC, 1); BE_WRB_F_SET(wrb_params.features, OS2BMC, 1);
wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params); wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
if (unlikely(!wrb_cnt)) if (unlikely(!wrb_cnt))
goto drop; goto drop_skb;
else else
skb_get(skb); skb_get(skb);
} }
@ -1407,6 +1405,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
be_xmit_flush(adapter, txo); be_xmit_flush(adapter, txo);
return NETDEV_TX_OK; return NETDEV_TX_OK;
drop_skb:
dev_kfree_skb_any(skb);
drop: drop:
tx_stats(txo)->tx_drv_drops++; tx_stats(txo)->tx_drv_drops++;
/* Flush the already enqueued tx requests */ /* Flush the already enqueued tx requests */

View File

@ -197,55 +197,67 @@ static int mac_probe(struct platform_device *_of_dev)
err = -EINVAL; err = -EINVAL;
goto _return_of_node_put; goto _return_of_node_put;
} }
mac_dev->fman_dev = &of_dev->dev;
/* Get the FMan cell-index */ /* Get the FMan cell-index */
err = of_property_read_u32(dev_node, "cell-index", &val); err = of_property_read_u32(dev_node, "cell-index", &val);
if (err) { if (err) {
dev_err(dev, "failed to read cell-index for %pOF\n", dev_node); dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
err = -EINVAL; err = -EINVAL;
goto _return_of_node_put; goto _return_dev_put;
} }
/* cell-index 0 => FMan id 1 */ /* cell-index 0 => FMan id 1 */
fman_id = (u8)(val + 1); fman_id = (u8)(val + 1);
priv->fman = fman_bind(&of_dev->dev); priv->fman = fman_bind(mac_dev->fman_dev);
if (!priv->fman) { if (!priv->fman) {
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node); dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
err = -ENODEV; err = -ENODEV;
goto _return_of_node_put; goto _return_dev_put;
} }
/* Two references have been taken in of_find_device_by_node()
* and fman_bind(). Release one of them here. The second one
* will be released in mac_remove().
*/
put_device(mac_dev->fman_dev);
of_node_put(dev_node); of_node_put(dev_node);
dev_node = NULL;
/* Get the address of the memory mapped registers */ /* Get the address of the memory mapped registers */
mac_dev->res = platform_get_mem_or_io(_of_dev, 0); mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
if (!mac_dev->res) { if (!mac_dev->res) {
dev_err(dev, "could not get registers\n"); dev_err(dev, "could not get registers\n");
return -EINVAL; err = -EINVAL;
goto _return_dev_put;
} }
err = devm_request_resource(dev, fman_get_mem_region(priv->fman), err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
mac_dev->res); mac_dev->res);
if (err) { if (err) {
dev_err_probe(dev, err, "could not request resource\n"); dev_err_probe(dev, err, "could not request resource\n");
return err; goto _return_dev_put;
} }
mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start, mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
resource_size(mac_dev->res)); resource_size(mac_dev->res));
if (!mac_dev->vaddr) { if (!mac_dev->vaddr) {
dev_err(dev, "devm_ioremap() failed\n"); dev_err(dev, "devm_ioremap() failed\n");
return -EIO; err = -EIO;
goto _return_dev_put;
} }
if (!of_device_is_available(mac_node)) if (!of_device_is_available(mac_node)) {
return -ENODEV; err = -ENODEV;
goto _return_dev_put;
}
/* Get the cell-index */ /* Get the cell-index */
err = of_property_read_u32(mac_node, "cell-index", &val); err = of_property_read_u32(mac_node, "cell-index", &val);
if (err) { if (err) {
dev_err(dev, "failed to read cell-index for %pOF\n", mac_node); dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
return -EINVAL; err = -EINVAL;
goto _return_dev_put;
} }
priv->cell_index = (u8)val; priv->cell_index = (u8)val;
@ -259,22 +271,26 @@ static int mac_probe(struct platform_device *_of_dev)
if (unlikely(nph < 0)) { if (unlikely(nph < 0)) {
dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n", dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
mac_node); mac_node);
return nph; err = nph;
goto _return_dev_put;
} }
if (nph != ARRAY_SIZE(mac_dev->port)) { if (nph != ARRAY_SIZE(mac_dev->port)) {
dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n", dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
mac_node); mac_node);
return -EINVAL; err = -EINVAL;
goto _return_dev_put;
} }
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) { /* PORT_NUM determines the size of the port array */
for (i = 0; i < PORT_NUM; i++) {
/* Find the port node */ /* Find the port node */
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i); dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
if (!dev_node) { if (!dev_node) {
dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n", dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
mac_node); mac_node);
return -EINVAL; err = -EINVAL;
goto _return_dev_arr_put;
} }
of_dev = of_find_device_by_node(dev_node); of_dev = of_find_device_by_node(dev_node);
@ -282,17 +298,24 @@ static int mac_probe(struct platform_device *_of_dev)
dev_err(dev, "of_find_device_by_node(%pOF) failed\n", dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
dev_node); dev_node);
err = -EINVAL; err = -EINVAL;
goto _return_of_node_put; goto _return_dev_arr_put;
} }
mac_dev->fman_port_devs[i] = &of_dev->dev;
mac_dev->port[i] = fman_port_bind(&of_dev->dev); mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
if (!mac_dev->port[i]) { if (!mac_dev->port[i]) {
dev_err(dev, "dev_get_drvdata(%pOF) failed\n", dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
dev_node); dev_node);
err = -EINVAL; err = -EINVAL;
goto _return_of_node_put; goto _return_dev_arr_put;
} }
/* Two references have been taken in of_find_device_by_node()
* and fman_port_bind(). Release one of them here. The second
* one will be released in mac_remove().
*/
put_device(mac_dev->fman_port_devs[i]);
of_node_put(dev_node); of_node_put(dev_node);
dev_node = NULL;
} }
/* Get the PHY connection type */ /* Get the PHY connection type */
@ -312,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
err = init(mac_dev, mac_node, &params); err = init(mac_dev, mac_node, &params);
if (err < 0) if (err < 0)
return err; goto _return_dev_arr_put;
if (!is_zero_ether_addr(mac_dev->addr)) if (!is_zero_ether_addr(mac_dev->addr))
dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr); dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
@ -327,6 +350,12 @@ static int mac_probe(struct platform_device *_of_dev)
return err; return err;
_return_dev_arr_put:
/* mac_dev is kzalloc'ed */
for (i = 0; i < PORT_NUM; i++)
put_device(mac_dev->fman_port_devs[i]);
_return_dev_put:
put_device(mac_dev->fman_dev);
_return_of_node_put: _return_of_node_put:
of_node_put(dev_node); of_node_put(dev_node);
return err; return err;
@ -335,6 +364,11 @@ _return_of_node_put:
static void mac_remove(struct platform_device *pdev) static void mac_remove(struct platform_device *pdev)
{ {
struct mac_device *mac_dev = platform_get_drvdata(pdev); struct mac_device *mac_dev = platform_get_drvdata(pdev);
int i;
for (i = 0; i < PORT_NUM; i++)
put_device(mac_dev->fman_port_devs[i]);
put_device(mac_dev->fman_dev);
platform_device_unregister(mac_dev->priv->eth_dev); platform_device_unregister(mac_dev->priv->eth_dev);
} }

View File

@ -19,12 +19,13 @@
struct fman_mac; struct fman_mac;
struct mac_priv_s; struct mac_priv_s;
#define PORT_NUM 2
struct mac_device { struct mac_device {
void __iomem *vaddr; void __iomem *vaddr;
struct device *dev; struct device *dev;
struct resource *res; struct resource *res;
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
struct fman_port *port[2]; struct fman_port *port[PORT_NUM];
struct phylink *phylink; struct phylink *phylink;
struct phylink_config phylink_config; struct phylink_config phylink_config;
phy_interface_t phy_if; phy_interface_t phy_if;
@ -52,6 +53,9 @@ struct mac_device {
struct fman_mac *fman_mac; struct fman_mac *fman_mac;
struct mac_priv_s *priv; struct mac_priv_s *priv;
struct device *fman_dev;
struct device *fman_port_devs[PORT_NUM];
}; };
static inline struct mac_device static inline struct mac_device

View File

@ -1012,6 +1012,7 @@ sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
if(skb->len > XMIT_BUFF_SIZE) if(skb->len > XMIT_BUFF_SIZE)
{ {
printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
dev_kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }

View File

@ -336,6 +336,51 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
return new_pkts; return new_pkts;
} }
/**
* octep_oq_next_pkt() - Move to the next packet in Rx queue.
*
* @oq: Octeon Rx queue data structure.
* @buff_info: Current packet buffer info.
* @read_idx: Current packet index in the ring.
* @desc_used: Current packet descriptor number.
*
* Free the resources associated with a packet.
* Increment packet index in the ring and packet descriptor number.
*/
static void octep_oq_next_pkt(struct octep_oq *oq,
struct octep_rx_buffer *buff_info,
u32 *read_idx, u32 *desc_used)
{
dma_unmap_page(oq->dev, oq->desc_ring[*read_idx].buffer_ptr,
PAGE_SIZE, DMA_FROM_DEVICE);
buff_info->page = NULL;
(*read_idx)++;
(*desc_used)++;
if (*read_idx == oq->max_count)
*read_idx = 0;
}
/**
* octep_oq_drop_rx() - Free the resources associated with a packet.
*
* @oq: Octeon Rx queue data structure.
* @buff_info: Current packet buffer info.
* @read_idx: Current packet index in the ring.
* @desc_used: Current packet descriptor number.
*
*/
static void octep_oq_drop_rx(struct octep_oq *oq,
struct octep_rx_buffer *buff_info,
u32 *read_idx, u32 *desc_used)
{
int data_len = buff_info->len - oq->max_single_buffer_size;
while (data_len > 0) {
octep_oq_next_pkt(oq, buff_info, read_idx, desc_used);
data_len -= oq->buffer_size;
};
}
/** /**
* __octep_oq_process_rx() - Process hardware Rx queue and push to stack. * __octep_oq_process_rx() - Process hardware Rx queue and push to stack.
* *
@ -365,10 +410,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
desc_used = 0; desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) { for (pkt = 0; pkt < pkts_to_process; pkt++) {
buff_info = (struct octep_rx_buffer *)&oq->buff_info[read_idx]; buff_info = (struct octep_rx_buffer *)&oq->buff_info[read_idx];
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
PAGE_SIZE, DMA_FROM_DEVICE);
resp_hw = page_address(buff_info->page); resp_hw = page_address(buff_info->page);
buff_info->page = NULL;
/* Swap the length field that is in Big-Endian to CPU */ /* Swap the length field that is in Big-Endian to CPU */
buff_info->len = be64_to_cpu(resp_hw->length); buff_info->len = be64_to_cpu(resp_hw->length);
@ -390,36 +432,33 @@ static int __octep_oq_process_rx(struct octep_device *oct,
*/ */
data_offset = OCTEP_OQ_RESP_HW_SIZE; data_offset = OCTEP_OQ_RESP_HW_SIZE;
} }
octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
skb = build_skb((void *)resp_hw, PAGE_SIZE);
if (!skb) {
octep_oq_drop_rx(oq, buff_info,
&read_idx, &desc_used);
oq->stats.alloc_failures++;
continue;
}
skb_reserve(skb, data_offset);
rx_bytes += buff_info->len; rx_bytes += buff_info->len;
if (buff_info->len <= oq->max_single_buffer_size) { if (buff_info->len <= oq->max_single_buffer_size) {
skb = build_skb((void *)resp_hw, PAGE_SIZE);
skb_reserve(skb, data_offset);
skb_put(skb, buff_info->len); skb_put(skb, buff_info->len);
read_idx++;
desc_used++;
if (read_idx == oq->max_count)
read_idx = 0;
} else { } else {
struct skb_shared_info *shinfo; struct skb_shared_info *shinfo;
u16 data_len; u16 data_len;
skb = build_skb((void *)resp_hw, PAGE_SIZE);
skb_reserve(skb, data_offset);
/* Head fragment includes response header(s); /* Head fragment includes response header(s);
* subsequent fragments contains only data. * subsequent fragments contains only data.
*/ */
skb_put(skb, oq->max_single_buffer_size); skb_put(skb, oq->max_single_buffer_size);
read_idx++;
desc_used++;
if (read_idx == oq->max_count)
read_idx = 0;
shinfo = skb_shinfo(skb); shinfo = skb_shinfo(skb);
data_len = buff_info->len - oq->max_single_buffer_size; data_len = buff_info->len - oq->max_single_buffer_size;
while (data_len) { while (data_len) {
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
PAGE_SIZE, DMA_FROM_DEVICE);
buff_info = (struct octep_rx_buffer *) buff_info = (struct octep_rx_buffer *)
&oq->buff_info[read_idx]; &oq->buff_info[read_idx];
if (data_len < oq->buffer_size) { if (data_len < oq->buffer_size) {
@ -434,11 +473,8 @@ static int __octep_oq_process_rx(struct octep_device *oct,
buff_info->page, 0, buff_info->page, 0,
buff_info->len, buff_info->len,
buff_info->len); buff_info->len);
buff_info->page = NULL;
read_idx++; octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
desc_used++;
if (read_idx == oq->max_count)
read_idx = 0;
} }
} }

View File

@ -815,7 +815,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
return HS_TIMEOUT; return HS_TIMEOUT;
} }
} }
break; fallthrough;
case PLIP_PK_LENGTH_LSB: case PLIP_PK_LENGTH_LSB:
if (plip_send(nibble_timeout, dev, if (plip_send(nibble_timeout, dev,

View File

@ -1771,7 +1771,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
// can rename the link if it knows better. // can rename the link if it knows better.
if ((dev->driver_info->flags & FLAG_ETHER) != 0 && if ((dev->driver_info->flags & FLAG_ETHER) != 0 &&
((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 ||
(net->dev_addr [0] & 0x02) == 0)) /* somebody touched it*/
!is_zero_ether_addr(net->dev_addr)))
strscpy(net->name, "eth%d", sizeof(net->name)); strscpy(net->name, "eth%d", sizeof(net->name));
/* WLAN devices should always be named "wlan%d" */ /* WLAN devices should always be named "wlan%d" */
if ((dev->driver_info->flags & FLAG_WLAN) != 0) if ((dev->driver_info->flags & FLAG_WLAN) != 0)

View File

@ -1031,7 +1031,7 @@ static const struct nla_policy wwan_rtnl_policy[IFLA_WWAN_MAX + 1] = {
static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = { static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = {
.kind = "wwan", .kind = "wwan",
.maxtype = __IFLA_WWAN_MAX, .maxtype = IFLA_WWAN_MAX,
.alloc = wwan_rtnl_alloc, .alloc = wwan_rtnl_alloc,
.validate = wwan_rtnl_validate, .validate = wwan_rtnl_validate,
.newlink = wwan_rtnl_newlink, .newlink = wwan_rtnl_newlink,

View File

@ -521,6 +521,7 @@ static int __init sysman_init(void)
int ret = 0; int ret = 0;
if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) && if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Alienware", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) { !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) {
pr_err("Unable to run on non-Dell system\n"); pr_err("Unable to run on non-Dell system\n");
return -ENODEV; return -ENODEV;

View File

@ -2133,6 +2133,11 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
{ {
u32 reg; u32 reg;
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
DWC3_GUSB2PHYCFG_SUSPHY) ||
(dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)) &
DWC3_GUSB3PIPECTL_SUSPHY);
switch (dwc->current_dr_role) { switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE: case DWC3_GCTL_PRTCAP_DEVICE:
if (pm_runtime_suspended(dwc->dev)) if (pm_runtime_suspended(dwc->dev))
@ -2180,6 +2185,15 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
break; break;
} }
if (!PMSG_IS_AUTO(msg)) {
/*
* TI AM62 platform requires SUSPHY to be
* enabled for system suspend to work.
*/
if (!dwc->susphy_state)
dwc3_enable_susphy(dwc, true);
}
return 0; return 0;
} }
@ -2242,6 +2256,11 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
break; break;
} }
if (!PMSG_IS_AUTO(msg)) {
/* restore SUSPHY state to that before system suspend. */
dwc3_enable_susphy(dwc, dwc->susphy_state);
}
return 0; return 0;
} }

View File

@ -1147,6 +1147,8 @@ struct dwc3_scratchpad_array {
* @sys_wakeup: set if the device may do system wakeup. * @sys_wakeup: set if the device may do system wakeup.
* @wakeup_configured: set if the device is configured for remote wakeup. * @wakeup_configured: set if the device is configured for remote wakeup.
* @suspended: set to track suspend event due to U3/L2. * @suspended: set to track suspend event due to U3/L2.
* @susphy_state: state of DWC3_GUSB2PHYCFG_SUSPHY + DWC3_GUSB3PIPECTL_SUSPHY
* before PM suspend.
* @imod_interval: set the interrupt moderation interval in 250ns * @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable. * increments or 0 to disable.
* @max_cfg_eps: current max number of IN eps used across all USB configs. * @max_cfg_eps: current max number of IN eps used across all USB configs.
@ -1372,6 +1374,7 @@ struct dwc3 {
unsigned sys_wakeup:1; unsigned sys_wakeup:1;
unsigned wakeup_configured:1; unsigned wakeup_configured:1;
unsigned suspended:1; unsigned suspended:1;
unsigned susphy_state:1;
u16 imod_interval; u16 imod_interval;

View File

@ -2042,7 +2042,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
int result; \ int result; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
return result; \ return result; \
@ -2052,7 +2052,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \ const char *page, size_t len) \
{ \ { \
struct f_uac2_opts *opts = to_f_uac2_opts(item); \ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
int ret = 0; \ int ret = len; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
if (opts->refcnt) { \ if (opts->refcnt) { \
@ -2060,8 +2060,11 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
goto end; \ goto end; \
} \ } \
\ \
ret = snprintf(opts->name, min(sizeof(opts->name), len), \ if (len && page[len - 1] == '\n') \
"%s", page); \ len--; \
\
scnprintf(opts->name, min(sizeof(opts->name), len + 1), \
"%s", page); \
\ \
end: \ end: \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
@ -2178,7 +2181,7 @@ static struct usb_function_instance *afunc_alloc_inst(void)
opts->req_number = UAC2_DEF_REQ_NUM; opts->req_number = UAC2_DEF_REQ_NUM;
opts->fb_max = FBACK_FAST_MAX; opts->fb_max = FBACK_FAST_MAX;
snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); scnprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
return &opts->func_inst; return &opts->func_inst;
} }

View File

@ -0,0 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* hc_capbase bitmasks */
/* bits 7:0 - how long is the Capabilities register */
#define HC_LENGTH(p) XHCI_HC_LENGTH(p)
/* bits 31:16 */
#define HC_VERSION(p) (((p) >> 16) & 0xffff)
/* HCSPARAMS1 - hcs_params1 - bitmasks */
/* bits 0:7, Max Device Slots */
#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff)
#define HCS_SLOTS_MASK 0xff
/* bits 8:18, Max Interrupters */
#define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff)
/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f)
/* HCSPARAMS2 - hcs_params2 - bitmasks */
/* bits 0:3, frames or uframes that SW needs to queue transactions
* ahead of the HW to meet periodic deadlines */
#define HCS_IST(p) (((p) >> 0) & 0xf)
/* bits 4:7, max number of Event Ring segments */
#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf)
/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
#define HCS_MAX_SCRATCHPAD(p) ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
/* HCSPARAMS3 - hcs_params3 - bitmasks */
/* bits 0:7, Max U1 to U0 latency for the roothub ports */
#define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff)
/* bits 16:31, Max U2 to U0 latency for the roothub ports */
#define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff)
/* HCCPARAMS - hcc_params - bitmasks */
/* true: HC can use 64-bit address pointers */
#define HCC_64BIT_ADDR(p) ((p) & (1 << 0))
/* true: HC can do bandwidth negotiation */
#define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1))
/* true: HC uses 64-byte Device Context structures
* FIXME 64-byte context structures aren't supported yet.
*/
#define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2))
/* true: HC has port power switches */
#define HCC_PPC(p) ((p) & (1 << 3))
/* true: HC has port indicators */
#define HCS_INDICATOR(p) ((p) & (1 << 4))
/* true: HC has Light HC Reset Capability */
#define HCC_LIGHT_RESET(p) ((p) & (1 << 5))
/* true: HC supports latency tolerance messaging */
#define HCC_LTC(p) ((p) & (1 << 6))
/* true: no secondary Stream ID Support */
#define HCC_NSS(p) ((p) & (1 << 7))
/* true: HC supports Stopped - Short Packet */
#define HCC_SPC(p) ((p) & (1 << 9))
/* true: HC has Contiguous Frame ID Capability */
#define HCC_CFC(p) ((p) & (1 << 11))
/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
#define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1))
/* Extended Capabilities pointer from PCI base - section 5.3.6 */
#define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p)
#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
/* db_off bitmask - bits 0:1 reserved */
#define DBOFF_MASK (~0x3)
/* run_regs_off bitmask - bits 0:4 reserved */
#define RTSOFF_MASK (~0x1f)
/* HCCPARAMS2 - hcc_params2 - bitmasks */
/* true: HC supports U3 entry Capability */
#define HCC2_U3C(p) ((p) & (1 << 0))
/* true: HC supports Configure endpoint command Max exit latency too large */
#define HCC2_CMC(p) ((p) & (1 << 1))
/* true: HC supports Force Save context Capability */
#define HCC2_FSC(p) ((p) & (1 << 2))
/* true: HC supports Compliance Transition Capability */
#define HCC2_CTC(p) ((p) & (1 << 3))
/* true: HC support Large ESIT payload Capability > 48k */
#define HCC2_LEC(p) ((p) & (1 << 4))
/* true: HC support Configuration Information Capability */
#define HCC2_CIC(p) ((p) & (1 << 5))
/* true: HC support Extended TBC Capability, Isoc burst count > 65535 */
#define HCC2_ETC(p) ((p) & (1 << 6))

View File

@ -108,7 +108,7 @@ struct dbc_port {
struct tasklet_struct push; struct tasklet_struct push;
struct list_head write_pool; struct list_head write_pool;
struct kfifo write_fifo; unsigned int tx_boundary;
bool registered; bool registered;
}; };

View File

@ -25,16 +25,26 @@ static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc)
} }
static unsigned int static unsigned int
dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size) dbc_kfifo_to_req(struct dbc_port *port, char *packet)
{ {
unsigned int len; unsigned int len;
len = kfifo_len(&port->write_fifo); len = kfifo_len(&port->port.xmit_fifo);
if (len < size)
size = len; if (len == 0)
if (size != 0) return 0;
size = kfifo_out(&port->write_fifo, packet, size);
return size; len = min(len, DBC_MAX_PACKET);
if (port->tx_boundary)
len = min(port->tx_boundary, len);
len = kfifo_out(&port->port.xmit_fifo, packet, len);
if (port->tx_boundary)
port->tx_boundary -= len;
return len;
} }
static int dbc_start_tx(struct dbc_port *port) static int dbc_start_tx(struct dbc_port *port)
@ -49,7 +59,7 @@ static int dbc_start_tx(struct dbc_port *port)
while (!list_empty(pool)) { while (!list_empty(pool)) {
req = list_entry(pool->next, struct dbc_request, list_pool); req = list_entry(pool->next, struct dbc_request, list_pool);
len = dbc_send_packet(port, req->buf, DBC_MAX_PACKET); len = dbc_kfifo_to_req(port, req->buf);
if (len == 0) if (len == 0)
break; break;
do_tty_wake = true; do_tty_wake = true;
@ -213,14 +223,32 @@ static ssize_t dbc_tty_write(struct tty_struct *tty, const u8 *buf,
{ {
struct dbc_port *port = tty->driver_data; struct dbc_port *port = tty->driver_data;
unsigned long flags; unsigned long flags;
unsigned int written = 0;
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
if (count)
count = kfifo_in(&port->write_fifo, buf, count); /*
dbc_start_tx(port); * Treat tty write as one usb transfer. Make sure the writes are turned
* into TRB request having the same size boundaries as the tty writes.
* Don't add data to kfifo before previous write is turned into TRBs
*/
if (port->tx_boundary) {
spin_unlock_irqrestore(&port->port_lock, flags);
return 0;
}
if (count) {
written = kfifo_in(&port->port.xmit_fifo, buf, count);
if (written == count)
port->tx_boundary = kfifo_len(&port->port.xmit_fifo);
dbc_start_tx(port);
}
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
return count; return written;
} }
static int dbc_tty_put_char(struct tty_struct *tty, u8 ch) static int dbc_tty_put_char(struct tty_struct *tty, u8 ch)
@ -230,7 +258,7 @@ static int dbc_tty_put_char(struct tty_struct *tty, u8 ch)
int status; int status;
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
status = kfifo_put(&port->write_fifo, ch); status = kfifo_put(&port->port.xmit_fifo, ch);
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
return status; return status;
@ -253,7 +281,11 @@ static unsigned int dbc_tty_write_room(struct tty_struct *tty)
unsigned int room; unsigned int room;
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
room = kfifo_avail(&port->write_fifo); room = kfifo_avail(&port->port.xmit_fifo);
if (port->tx_boundary)
room = 0;
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
return room; return room;
@ -266,7 +298,7 @@ static unsigned int dbc_tty_chars_in_buffer(struct tty_struct *tty)
unsigned int chars; unsigned int chars;
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
chars = kfifo_len(&port->write_fifo); chars = kfifo_len(&port->port.xmit_fifo);
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
return chars; return chars;
@ -424,7 +456,8 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
goto err_idr; goto err_idr;
} }
ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL); ret = kfifo_alloc(&port->port.xmit_fifo, DBC_WRITE_BUF_SIZE,
GFP_KERNEL);
if (ret) if (ret)
goto err_exit_port; goto err_exit_port;
@ -453,7 +486,7 @@ err_free_requests:
xhci_dbc_free_requests(&port->read_pool); xhci_dbc_free_requests(&port->read_pool);
xhci_dbc_free_requests(&port->write_pool); xhci_dbc_free_requests(&port->write_pool);
err_free_fifo: err_free_fifo:
kfifo_free(&port->write_fifo); kfifo_free(&port->port.xmit_fifo);
err_exit_port: err_exit_port:
idr_remove(&dbc_tty_minors, port->minor); idr_remove(&dbc_tty_minors, port->minor);
err_idr: err_idr:
@ -478,7 +511,7 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
idr_remove(&dbc_tty_minors, port->minor); idr_remove(&dbc_tty_minors, port->minor);
mutex_unlock(&dbc_tty_minors_lock); mutex_unlock(&dbc_tty_minors_lock);
kfifo_free(&port->write_fifo); kfifo_free(&port->port.xmit_fifo);
xhci_dbc_free_requests(&port->read_pool); xhci_dbc_free_requests(&port->read_pool);
xhci_dbc_free_requests(&port->read_queue); xhci_dbc_free_requests(&port->read_queue);
xhci_dbc_free_requests(&port->write_pool); xhci_dbc_free_requests(&port->write_pool);

View File

@ -0,0 +1,176 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
/* true: device connected */
#define PORT_CONNECT (1 << 0)
/* true: port enabled */
#define PORT_PE (1 << 1)
/* bit 2 reserved and zeroed */
/* true: port has an over-current condition */
#define PORT_OC (1 << 3)
/* true: port reset signaling asserted */
#define PORT_RESET (1 << 4)
/* Port Link State - bits 5:8
* A read gives the current link PM state of the port,
* a write with Link State Write Strobe set sets the link state.
*/
#define PORT_PLS_MASK (0xf << 5)
#define XDEV_U0 (0x0 << 5)
#define XDEV_U1 (0x1 << 5)
#define XDEV_U2 (0x2 << 5)
#define XDEV_U3 (0x3 << 5)
#define XDEV_DISABLED (0x4 << 5)
#define XDEV_RXDETECT (0x5 << 5)
#define XDEV_INACTIVE (0x6 << 5)
#define XDEV_POLLING (0x7 << 5)
#define XDEV_RECOVERY (0x8 << 5)
#define XDEV_HOT_RESET (0x9 << 5)
#define XDEV_COMP_MODE (0xa << 5)
#define XDEV_TEST_MODE (0xb << 5)
#define XDEV_RESUME (0xf << 5)
/* true: port has power (see HCC_PPC) */
#define PORT_POWER (1 << 9)
/* bits 10:13 indicate device speed:
* 0 - undefined speed - port hasn't be initialized by a reset yet
* 1 - full speed
* 2 - low speed
* 3 - high speed
* 4 - super speed
* 5-15 reserved
*/
#define DEV_SPEED_MASK (0xf << 10)
#define XDEV_FS (0x1 << 10)
#define XDEV_LS (0x2 << 10)
#define XDEV_HS (0x3 << 10)
#define XDEV_SS (0x4 << 10)
#define XDEV_SSP (0x5 << 10)
#define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10))
#define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS)
#define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS)
#define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS)
#define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS)
#define DEV_SUPERSPEEDPLUS(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP)
#define DEV_SUPERSPEED_ANY(p) (((p) & DEV_SPEED_MASK) >= XDEV_SS)
#define DEV_PORT_SPEED(p) (((p) >> 10) & 0x0f)
/* Bits 20:23 in the Slot Context are the speed for the device */
#define SLOT_SPEED_FS (XDEV_FS << 10)
#define SLOT_SPEED_LS (XDEV_LS << 10)
#define SLOT_SPEED_HS (XDEV_HS << 10)
#define SLOT_SPEED_SS (XDEV_SS << 10)
#define SLOT_SPEED_SSP (XDEV_SSP << 10)
/* Port Indicator Control */
#define PORT_LED_OFF (0 << 14)
#define PORT_LED_AMBER (1 << 14)
#define PORT_LED_GREEN (2 << 14)
#define PORT_LED_MASK (3 << 14)
/* Port Link State Write Strobe - set this when changing link state */
#define PORT_LINK_STROBE (1 << 16)
/* true: connect status change */
#define PORT_CSC (1 << 17)
/* true: port enable change */
#define PORT_PEC (1 << 18)
/* true: warm reset for a USB 3.0 device is done. A "hot" reset puts the port
* into an enabled state, and the device into the default state. A "warm" reset
* also resets the link, forcing the device through the link training sequence.
* SW can also look at the Port Reset register to see when warm reset is done.
*/
#define PORT_WRC (1 << 19)
/* true: over-current change */
#define PORT_OCC (1 << 20)
/* true: reset change - 1 to 0 transition of PORT_RESET */
#define PORT_RC (1 << 21)
/* port link status change - set on some port link state transitions:
* Transition Reason
* ------------------------------------------------------------------------------
* - U3 to Resume Wakeup signaling from a device
* - Resume to Recovery to U0 USB 3.0 device resume
* - Resume to U0 USB 2.0 device resume
* - U3 to Recovery to U0 Software resume of USB 3.0 device complete
* - U3 to U0 Software resume of USB 2.0 device complete
* - U2 to U0 L1 resume of USB 2.1 device complete
* - U0 to U0 (???) L1 entry rejection by USB 2.1 device
* - U0 to disabled L1 entry error with USB 2.1 device
* - Any state to inactive Error on USB 3.0 port
*/
#define PORT_PLC (1 << 22)
/* port configure error change - port failed to configure its link partner */
#define PORT_CEC (1 << 23)
#define PORT_CHANGE_MASK (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
PORT_RC | PORT_PLC | PORT_CEC)
/* Cold Attach Status - xHC can set this bit to report device attached during
* Sx state. Warm port reset should be perfomed to clear this bit and move port
* to connected state.
*/
#define PORT_CAS (1 << 24)
/* wake on connect (enable) */
#define PORT_WKCONN_E (1 << 25)
/* wake on disconnect (enable) */
#define PORT_WKDISC_E (1 << 26)
/* wake on over-current (enable) */
#define PORT_WKOC_E (1 << 27)
/* bits 28:29 reserved */
/* true: device is non-removable - for USB 3.0 roothub emulation */
#define PORT_DEV_REMOVE (1 << 30)
/* Initiate a warm port reset - complete when PORT_WRC is '1' */
#define PORT_WR (1 << 31)
/* We mark duplicate entries with -1 */
#define DUPLICATE_ENTRY ((u8)(-1))
/* Port Power Management Status and Control - port_power_base bitmasks */
/* Inactivity timer value for transitions into U1, in microseconds.
* Timeout can be up to 127us. 0xFF means an infinite timeout.
*/
#define PORT_U1_TIMEOUT(p) ((p) & 0xff)
#define PORT_U1_TIMEOUT_MASK 0xff
/* Inactivity timer value for transitions into U2 */
#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8)
#define PORT_U2_TIMEOUT_MASK (0xff << 8)
/* Bits 24:31 for port testing */
/* USB2 Protocol PORTSPMSC */
#define PORT_L1S_MASK 7
#define PORT_L1S_SUCCESS 1
#define PORT_RWE (1 << 3)
#define PORT_HIRD(p) (((p) & 0xf) << 4)
#define PORT_HIRD_MASK (0xf << 4)
#define PORT_L1DS_MASK (0xff << 8)
#define PORT_L1DS(p) (((p) & 0xff) << 8)
#define PORT_HLE (1 << 16)
#define PORT_TEST_MODE_SHIFT 28
/* USB3 Protocol PORTLI Port Link Information */
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
#define PORT_TX_LANES(p) (((p) >> 20) & 0xf)
/* USB2 Protocol PORTHLPMC */
#define PORT_HIRDM(p)((p) & 3)
#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2)
#define PORT_BESLD(p)(((p) & 0xf) << 10)
/* use 512 microseconds as USB2 LPM L1 default timeout. */
#define XHCI_L1_TIMEOUT 512
/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency.
* Safe to use with mixed HIRD and BESL systems (host and device) and is used
* by other operating systems.
*
* XHCI 1.0 errata 8/14/12 Table 13 notes:
* "Software should choose xHC BESL/BESLD field values that do not violate a
* device's resume latency requirements,
* e.g. not program values > '4' if BLC = '1' and a HIRD device is attached,
* or not program values < '4' if BLC = '0' and a BESL device is attached.
*/
#define XHCI_DEFAULT_BESL 4
/*
* USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports
* to complete link training. usually link trainig completes much faster
* so check status 10 times with 36ms sleep in places we need to wait for
* polling to complete.
*/
#define XHCI_PORT_POLLING_LFPS_TIME 36

View File

@ -24,6 +24,9 @@
#include "xhci-ext-caps.h" #include "xhci-ext-caps.h"
#include "pci-quirks.h" #include "pci-quirks.h"
#include "xhci-port.h"
#include "xhci-caps.h"
/* max buffer size for trace and debug messages */ /* max buffer size for trace and debug messages */
#define XHCI_MSG_MAX 500 #define XHCI_MSG_MAX 500
@ -64,90 +67,6 @@ struct xhci_cap_regs {
/* Reserved up to (CAPLENGTH - 0x1C) */ /* Reserved up to (CAPLENGTH - 0x1C) */
}; };
/* hc_capbase bitmasks */
/* bits 7:0 - how long is the Capabilities register */
#define HC_LENGTH(p) XHCI_HC_LENGTH(p)
/* bits 31:16 */
#define HC_VERSION(p) (((p) >> 16) & 0xffff)
/* HCSPARAMS1 - hcs_params1 - bitmasks */
/* bits 0:7, Max Device Slots */
#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff)
#define HCS_SLOTS_MASK 0xff
/* bits 8:18, Max Interrupters */
#define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff)
/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f)
/* HCSPARAMS2 - hcs_params2 - bitmasks */
/* bits 0:3, frames or uframes that SW needs to queue transactions
* ahead of the HW to meet periodic deadlines */
#define HCS_IST(p) (((p) >> 0) & 0xf)
/* bits 4:7, max number of Event Ring segments */
#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf)
/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
#define HCS_MAX_SCRATCHPAD(p) ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
/* HCSPARAMS3 - hcs_params3 - bitmasks */
/* bits 0:7, Max U1 to U0 latency for the roothub ports */
#define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff)
/* bits 16:31, Max U2 to U0 latency for the roothub ports */
#define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff)
/* HCCPARAMS - hcc_params - bitmasks */
/* true: HC can use 64-bit address pointers */
#define HCC_64BIT_ADDR(p) ((p) & (1 << 0))
/* true: HC can do bandwidth negotiation */
#define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1))
/* true: HC uses 64-byte Device Context structures
* FIXME 64-byte context structures aren't supported yet.
*/
#define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2))
/* true: HC has port power switches */
#define HCC_PPC(p) ((p) & (1 << 3))
/* true: HC has port indicators */
#define HCS_INDICATOR(p) ((p) & (1 << 4))
/* true: HC has Light HC Reset Capability */
#define HCC_LIGHT_RESET(p) ((p) & (1 << 5))
/* true: HC supports latency tolerance messaging */
#define HCC_LTC(p) ((p) & (1 << 6))
/* true: no secondary Stream ID Support */
#define HCC_NSS(p) ((p) & (1 << 7))
/* true: HC supports Stopped - Short Packet */
#define HCC_SPC(p) ((p) & (1 << 9))
/* true: HC has Contiguous Frame ID Capability */
#define HCC_CFC(p) ((p) & (1 << 11))
/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
#define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1))
/* Extended Capabilities pointer from PCI base - section 5.3.6 */
#define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p)
#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
/* db_off bitmask - bits 0:1 reserved */
#define DBOFF_MASK (~0x3)
/* run_regs_off bitmask - bits 0:4 reserved */
#define RTSOFF_MASK (~0x1f)
/* HCCPARAMS2 - hcc_params2 - bitmasks */
/* true: HC supports U3 entry Capability */
#define HCC2_U3C(p) ((p) & (1 << 0))
/* true: HC supports Configure endpoint command Max exit latency too large */
#define HCC2_CMC(p) ((p) & (1 << 1))
/* true: HC supports Force Save context Capability */
#define HCC2_FSC(p) ((p) & (1 << 2))
/* true: HC supports Compliance Transition Capability */
#define HCC2_CTC(p) ((p) & (1 << 3))
/* true: HC support Large ESIT payload Capability > 48k */
#define HCC2_LEC(p) ((p) & (1 << 4))
/* true: HC support Configuration Information Capability */
#define HCC2_CIC(p) ((p) & (1 << 5))
/* true: HC support Extended TBC Capability, Isoc burst count > 65535 */
#define HCC2_ETC(p) ((p) & (1 << 6))
/* Number of registers per port */ /* Number of registers per port */
#define NUM_PORT_REGS 4 #define NUM_PORT_REGS 4
@ -293,181 +212,6 @@ struct xhci_op_regs {
#define CONFIG_CIE (1 << 9) #define CONFIG_CIE (1 << 9)
/* bits 10:31 - reserved and should be preserved */ /* bits 10:31 - reserved and should be preserved */
/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
/* true: device connected */
#define PORT_CONNECT (1 << 0)
/* true: port enabled */
#define PORT_PE (1 << 1)
/* bit 2 reserved and zeroed */
/* true: port has an over-current condition */
#define PORT_OC (1 << 3)
/* true: port reset signaling asserted */
#define PORT_RESET (1 << 4)
/* Port Link State - bits 5:8
* A read gives the current link PM state of the port,
* a write with Link State Write Strobe set sets the link state.
*/
#define PORT_PLS_MASK (0xf << 5)
#define XDEV_U0 (0x0 << 5)
#define XDEV_U1 (0x1 << 5)
#define XDEV_U2 (0x2 << 5)
#define XDEV_U3 (0x3 << 5)
#define XDEV_DISABLED (0x4 << 5)
#define XDEV_RXDETECT (0x5 << 5)
#define XDEV_INACTIVE (0x6 << 5)
#define XDEV_POLLING (0x7 << 5)
#define XDEV_RECOVERY (0x8 << 5)
#define XDEV_HOT_RESET (0x9 << 5)
#define XDEV_COMP_MODE (0xa << 5)
#define XDEV_TEST_MODE (0xb << 5)
#define XDEV_RESUME (0xf << 5)
/* true: port has power (see HCC_PPC) */
#define PORT_POWER (1 << 9)
/* bits 10:13 indicate device speed:
* 0 - undefined speed - port hasn't be initialized by a reset yet
* 1 - full speed
* 2 - low speed
* 3 - high speed
* 4 - super speed
* 5-15 reserved
*/
#define DEV_SPEED_MASK (0xf << 10)
#define XDEV_FS (0x1 << 10)
#define XDEV_LS (0x2 << 10)
#define XDEV_HS (0x3 << 10)
#define XDEV_SS (0x4 << 10)
#define XDEV_SSP (0x5 << 10)
#define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10))
#define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS)
#define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS)
#define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS)
#define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS)
#define DEV_SUPERSPEEDPLUS(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP)
#define DEV_SUPERSPEED_ANY(p) (((p) & DEV_SPEED_MASK) >= XDEV_SS)
#define DEV_PORT_SPEED(p) (((p) >> 10) & 0x0f)
/* Bits 20:23 in the Slot Context are the speed for the device */
#define SLOT_SPEED_FS (XDEV_FS << 10)
#define SLOT_SPEED_LS (XDEV_LS << 10)
#define SLOT_SPEED_HS (XDEV_HS << 10)
#define SLOT_SPEED_SS (XDEV_SS << 10)
#define SLOT_SPEED_SSP (XDEV_SSP << 10)
/* Port Indicator Control */
#define PORT_LED_OFF (0 << 14)
#define PORT_LED_AMBER (1 << 14)
#define PORT_LED_GREEN (2 << 14)
#define PORT_LED_MASK (3 << 14)
/* Port Link State Write Strobe - set this when changing link state */
#define PORT_LINK_STROBE (1 << 16)
/* true: connect status change */
#define PORT_CSC (1 << 17)
/* true: port enable change */
#define PORT_PEC (1 << 18)
/* true: warm reset for a USB 3.0 device is done. A "hot" reset puts the port
* into an enabled state, and the device into the default state. A "warm" reset
* also resets the link, forcing the device through the link training sequence.
* SW can also look at the Port Reset register to see when warm reset is done.
*/
#define PORT_WRC (1 << 19)
/* true: over-current change */
#define PORT_OCC (1 << 20)
/* true: reset change - 1 to 0 transition of PORT_RESET */
#define PORT_RC (1 << 21)
/* port link status change - set on some port link state transitions:
* Transition Reason
* ------------------------------------------------------------------------------
* - U3 to Resume Wakeup signaling from a device
* - Resume to Recovery to U0 USB 3.0 device resume
* - Resume to U0 USB 2.0 device resume
* - U3 to Recovery to U0 Software resume of USB 3.0 device complete
* - U3 to U0 Software resume of USB 2.0 device complete
* - U2 to U0 L1 resume of USB 2.1 device complete
* - U0 to U0 (???) L1 entry rejection by USB 2.1 device
* - U0 to disabled L1 entry error with USB 2.1 device
* - Any state to inactive Error on USB 3.0 port
*/
#define PORT_PLC (1 << 22)
/* port configure error change - port failed to configure its link partner */
#define PORT_CEC (1 << 23)
#define PORT_CHANGE_MASK (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
PORT_RC | PORT_PLC | PORT_CEC)
/* Cold Attach Status - xHC can set this bit to report device attached during
* Sx state. Warm port reset should be perfomed to clear this bit and move port
* to connected state.
*/
#define PORT_CAS (1 << 24)
/* wake on connect (enable) */
#define PORT_WKCONN_E (1 << 25)
/* wake on disconnect (enable) */
#define PORT_WKDISC_E (1 << 26)
/* wake on over-current (enable) */
#define PORT_WKOC_E (1 << 27)
/* bits 28:29 reserved */
/* true: device is non-removable - for USB 3.0 roothub emulation */
#define PORT_DEV_REMOVE (1 << 30)
/* Initiate a warm port reset - complete when PORT_WRC is '1' */
#define PORT_WR (1 << 31)
/* We mark duplicate entries with -1 */
#define DUPLICATE_ENTRY ((u8)(-1))
/* Port Power Management Status and Control - port_power_base bitmasks */
/* Inactivity timer value for transitions into U1, in microseconds.
* Timeout can be up to 127us. 0xFF means an infinite timeout.
*/
#define PORT_U1_TIMEOUT(p) ((p) & 0xff)
#define PORT_U1_TIMEOUT_MASK 0xff
/* Inactivity timer value for transitions into U2 */
#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8)
#define PORT_U2_TIMEOUT_MASK (0xff << 8)
/* Bits 24:31 for port testing */
/* USB2 Protocol PORTSPMSC */
#define PORT_L1S_MASK 7
#define PORT_L1S_SUCCESS 1
#define PORT_RWE (1 << 3)
#define PORT_HIRD(p) (((p) & 0xf) << 4)
#define PORT_HIRD_MASK (0xf << 4)
#define PORT_L1DS_MASK (0xff << 8)
#define PORT_L1DS(p) (((p) & 0xff) << 8)
#define PORT_HLE (1 << 16)
#define PORT_TEST_MODE_SHIFT 28
/* USB3 Protocol PORTLI Port Link Information */
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
#define PORT_TX_LANES(p) (((p) >> 20) & 0xf)
/* USB2 Protocol PORTHLPMC */
#define PORT_HIRDM(p)((p) & 3)
#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2)
#define PORT_BESLD(p)(((p) & 0xf) << 10)
/* use 512 microseconds as USB2 LPM L1 default timeout. */
#define XHCI_L1_TIMEOUT 512
/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency.
* Safe to use with mixed HIRD and BESL systems (host and device) and is used
* by other operating systems.
*
* XHCI 1.0 errata 8/14/12 Table 13 notes:
* "Software should choose xHC BESL/BESLD field values that do not violate a
* device's resume latency requirements,
* e.g. not program values > '4' if BLC = '1' and a HIRD device is attached,
* or not program values < '4' if BLC = '0' and a BESL device is attached.
*/
#define XHCI_DEFAULT_BESL 4
/*
* USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports
* to complete link training. usually link trainig completes much faster
* so check status 10 times with 36ms sleep in places we need to wait for
* polling to complete.
*/
#define XHCI_PORT_POLLING_LFPS_TIME 36
/** /**
* struct xhci_intr_reg - Interrupt Register Set * struct xhci_intr_reg - Interrupt Register Set
* @irq_pending: IMAN - Interrupt Management Register. Used to enable * @irq_pending: IMAN - Interrupt Management Register. Used to enable

View File

@ -145,13 +145,11 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
goto out; goto out;
/* /*
* may_open() has already checked for this, so it should be * Check do_open_execat() for an explanation.
* impossible to trip now. But we need to be extra cautious
* and check again at the very end too.
*/ */
error = -EACCES; error = -EACCES;
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) || if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) ||
path_noexec(&file->f_path))) path_noexec(&file->f_path))
goto exit; goto exit;
error = -ENOEXEC; error = -ENOEXEC;
@ -927,23 +925,22 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
file = do_filp_open(fd, name, &open_exec_flags); file = do_filp_open(fd, name, &open_exec_flags);
if (IS_ERR(file)) if (IS_ERR(file))
goto out; return file;
/* /*
* may_open() has already checked for this, so it should be * In the past the regular type check was here. It moved to may_open() in
* impossible to trip now. But we need to be extra cautious * 633fb6ac3980 ("exec: move S_ISREG() check earlier"). Since then it is
* and check again at the very end too. * an invariant that all non-regular files error out before we get here.
*/ */
err = -EACCES; err = -EACCES;
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) || if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) ||
path_noexec(&file->f_path))) path_noexec(&file->f_path))
goto exit; goto exit;
err = deny_write_access(file); err = deny_write_access(file);
if (err) if (err)
goto exit; goto exit;
out:
return file; return file;
exit: exit:

View File

@ -187,7 +187,7 @@ int dbMount(struct inode *ipbmap)
} }
bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag); bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
if (!bmp->db_numag || bmp->db_numag >= MAXAG) { if (!bmp->db_numag || bmp->db_numag > MAXAG) {
err = -EINVAL; err = -EINVAL;
goto err_release_metapage; goto err_release_metapage;
} }

View File

@ -330,6 +330,18 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
switch ((type = le64_to_cpu(buf->InodeType))) { switch ((type = le64_to_cpu(buf->InodeType))) {
case NFS_SPECFILE_LNK: case NFS_SPECFILE_LNK:
if (len == 0 || (len % 2)) {
cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");
return -EIO;
}
/*
* Check that buffer does not contain UTF-16 null codepoint
* because Linux cannot process symlink with null byte.
*/
if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {
cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");
return -EIO;
}
data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer, data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
len, true, len, true,
cifs_sb->local_nls); cifs_sb->local_nls);
@ -340,8 +352,19 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
break; break;
case NFS_SPECFILE_CHR: case NFS_SPECFILE_CHR:
case NFS_SPECFILE_BLK: case NFS_SPECFILE_BLK:
/* DataBuffer for block and char devices contains two 32-bit numbers */
if (len != 8) {
cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
return -EIO;
}
break;
case NFS_SPECFILE_FIFO: case NFS_SPECFILE_FIFO:
case NFS_SPECFILE_SOCK: case NFS_SPECFILE_SOCK:
/* DataBuffer for fifos and sockets is empty */
if (len != 0) {
cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
return -EIO;
}
break; break;
default: default:
cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n", cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",

View File

@ -387,6 +387,7 @@ static void udf_table_free_blocks(struct super_block *sb,
struct extent_position oepos, epos; struct extent_position oepos, epos;
int8_t etype; int8_t etype;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
int ret = 0;
mutex_lock(&sbi->s_alloc_mutex); mutex_lock(&sbi->s_alloc_mutex);
iinfo = UDF_I(table); iinfo = UDF_I(table);
@ -400,8 +401,12 @@ static void udf_table_free_blocks(struct super_block *sb,
epos.block = oepos.block = iinfo->i_location; epos.block = oepos.block = iinfo->i_location;
epos.bh = oepos.bh = NULL; epos.bh = oepos.bh = NULL;
while (count && while (count) {
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1);
if (ret < 0)
goto error_return;
if (ret == 0)
break;
if (((eloc.logicalBlockNum + if (((eloc.logicalBlockNum +
(elen >> sb->s_blocksize_bits)) == start)) { (elen >> sb->s_blocksize_bits)) == start)) {
if ((0x3FFFFFFF - elen) < if ((0x3FFFFFFF - elen) <
@ -476,11 +481,8 @@ static void udf_table_free_blocks(struct super_block *sb,
adsize = sizeof(struct short_ad); adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad); adsize = sizeof(struct long_ad);
else { else
brelse(oepos.bh);
brelse(epos.bh);
goto error_return; goto error_return;
}
if (epos.offset + (2 * adsize) > sb->s_blocksize) { if (epos.offset + (2 * adsize) > sb->s_blocksize) {
/* Steal a block from the extent being free'd */ /* Steal a block from the extent being free'd */
@ -496,10 +498,10 @@ static void udf_table_free_blocks(struct super_block *sb,
__udf_add_aext(table, &epos, &eloc, elen, 1); __udf_add_aext(table, &epos, &eloc, elen, 1);
} }
error_return:
brelse(epos.bh); brelse(epos.bh);
brelse(oepos.bh); brelse(oepos.bh);
error_return:
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
return; return;
} }
@ -515,6 +517,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
struct extent_position epos; struct extent_position epos;
int8_t etype = -1; int8_t etype = -1;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
int ret = 0;
if (first_block >= sbi->s_partmaps[partition].s_partition_len) if (first_block >= sbi->s_partmaps[partition].s_partition_len)
return 0; return 0;
@ -533,11 +536,14 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
epos.bh = NULL; epos.bh = NULL;
eloc.logicalBlockNum = 0xFFFFFFFF; eloc.logicalBlockNum = 0xFFFFFFFF;
while (first_block != eloc.logicalBlockNum && while (first_block != eloc.logicalBlockNum) {
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1);
if (ret < 0)
goto err_out;
if (ret == 0)
break;
udf_debug("eloc=%u, elen=%u, first_block=%u\n", udf_debug("eloc=%u, elen=%u, first_block=%u\n",
eloc.logicalBlockNum, elen, first_block); eloc.logicalBlockNum, elen, first_block);
; /* empty loop body */
} }
if (first_block == eloc.logicalBlockNum) { if (first_block == eloc.logicalBlockNum) {
@ -556,6 +562,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
alloc_count = 0; alloc_count = 0;
} }
err_out:
brelse(epos.bh); brelse(epos.bh);
if (alloc_count) if (alloc_count)
@ -577,6 +584,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
struct extent_position epos, goal_epos; struct extent_position epos, goal_epos;
int8_t etype; int8_t etype;
struct udf_inode_info *iinfo = UDF_I(table); struct udf_inode_info *iinfo = UDF_I(table);
int ret = 0;
*err = -ENOSPC; *err = -ENOSPC;
@ -600,8 +608,10 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
epos.block = iinfo->i_location; epos.block = iinfo->i_location;
epos.bh = goal_epos.bh = NULL; epos.bh = goal_epos.bh = NULL;
while (spread && while (spread) {
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1);
if (ret <= 0)
break;
if (goal >= eloc.logicalBlockNum) { if (goal >= eloc.logicalBlockNum) {
if (goal < eloc.logicalBlockNum + if (goal < eloc.logicalBlockNum +
(elen >> sb->s_blocksize_bits)) (elen >> sb->s_blocksize_bits))
@ -629,9 +639,11 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
brelse(epos.bh); brelse(epos.bh);
if (spread == 0xFFFFFFFF) { if (ret < 0 || spread == 0xFFFFFFFF) {
brelse(goal_epos.bh); brelse(goal_epos.bh);
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
if (ret < 0)
*err = ret;
return 0; return 0;
} }

View File

@ -166,13 +166,19 @@ static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter)
*/ */
static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter)
{ {
int8_t etype = -1;
int err = 0;
iter->loffset++; iter->loffset++;
if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits))
return 0; return 0;
iter->loffset = 0; iter->loffset = 0;
if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc,
!= (EXT_RECORDED_ALLOCATED >> 30)) { &iter->elen, &etype, 1);
if (err < 0)
return err;
else if (err == 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
if (iter->pos == iter->dir->i_size) { if (iter->pos == iter->dir->i_size) {
iter->elen = 0; iter->elen = 0;
return 0; return 0;
@ -240,6 +246,7 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
{ {
struct udf_inode_info *iinfo = UDF_I(dir); struct udf_inode_info *iinfo = UDF_I(dir);
int err = 0; int err = 0;
int8_t etype;
iter->dir = dir; iter->dir = dir;
iter->bh[0] = iter->bh[1] = NULL; iter->bh[0] = iter->bh[1] = NULL;
@ -259,9 +266,9 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
goto out; goto out;
} }
if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
&iter->eloc, &iter->elen, &iter->loffset) != &iter->eloc, &iter->elen, &iter->loffset, &etype);
(EXT_RECORDED_ALLOCATED >> 30)) { if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
if (pos == dir->i_size) if (pos == dir->i_size)
return 0; return 0;
udf_err(dir->i_sb, udf_err(dir->i_sb,
@ -457,6 +464,7 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
sector_t block; sector_t block;
uint32_t old_elen = iter->elen; uint32_t old_elen = iter->elen;
int err; int err;
int8_t etype;
if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
return -EINVAL; return -EINVAL;
@ -471,8 +479,9 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
udf_fiiter_update_elen(iter, old_elen); udf_fiiter_update_elen(iter, old_elen);
return err; return err;
} }
if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
&iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { &iter->loffset, &etype);
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
udf_err(iter->dir->i_sb, udf_err(iter->dir->i_sb,
"block %llu not allocated in directory (ino %lu)\n", "block %llu not allocated in directory (ino %lu)\n",
(unsigned long long)block, iter->dir->i_ino); (unsigned long long)block, iter->dir->i_ino);

View File

@ -408,7 +408,7 @@ struct udf_map_rq {
static int udf_map_block(struct inode *inode, struct udf_map_rq *map) static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
{ {
int err; int ret;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
@ -420,18 +420,24 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
uint32_t elen; uint32_t elen;
sector_t offset; sector_t offset;
struct extent_position epos = {}; struct extent_position epos = {};
int8_t etype;
down_read(&iinfo->i_data_sem); down_read(&iinfo->i_data_sem);
if (inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset) ret = inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset,
== (EXT_RECORDED_ALLOCATED >> 30)) { &etype);
if (ret < 0)
goto out_read;
if (ret > 0 && etype == (EXT_RECORDED_ALLOCATED >> 30)) {
map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc, map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc,
offset); offset);
map->oflags |= UDF_BLK_MAPPED; map->oflags |= UDF_BLK_MAPPED;
ret = 0;
} }
out_read:
up_read(&iinfo->i_data_sem); up_read(&iinfo->i_data_sem);
brelse(epos.bh); brelse(epos.bh);
return 0; return ret;
} }
down_write(&iinfo->i_data_sem); down_write(&iinfo->i_data_sem);
@ -442,9 +448,9 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
if (((loff_t)map->lblk) << inode->i_blkbits >= iinfo->i_lenExtents) if (((loff_t)map->lblk) << inode->i_blkbits >= iinfo->i_lenExtents)
udf_discard_prealloc(inode); udf_discard_prealloc(inode);
udf_clear_extent_cache(inode); udf_clear_extent_cache(inode);
err = inode_getblk(inode, map); ret = inode_getblk(inode, map);
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
return err; return ret;
} }
static int __udf_get_block(struct inode *inode, sector_t block, static int __udf_get_block(struct inode *inode, sector_t block,
@ -547,6 +553,7 @@ static int udf_do_extend_file(struct inode *inode,
} else { } else {
struct kernel_lb_addr tmploc; struct kernel_lb_addr tmploc;
uint32_t tmplen; uint32_t tmplen;
int8_t tmptype;
udf_write_aext(inode, last_pos, &last_ext->extLocation, udf_write_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1); last_ext->extLength, 1);
@ -556,8 +563,12 @@ static int udf_do_extend_file(struct inode *inode,
* more extents, we may need to enter possible following * more extents, we may need to enter possible following
* empty indirect extent. * empty indirect extent.
*/ */
if (new_block_bytes) if (new_block_bytes) {
udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); err = udf_next_aext(inode, last_pos, &tmploc, &tmplen,
&tmptype, 0);
if (err < 0)
goto out_err;
}
} }
iinfo->i_lenExtents += add; iinfo->i_lenExtents += add;
@ -661,8 +672,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
*/ */
udf_discard_prealloc(inode); udf_discard_prealloc(inode);
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype);
within_last_ext = (etype != -1); if (err < 0)
goto out;
within_last_ext = (err == 1);
/* We don't expect extents past EOF... */ /* We don't expect extents past EOF... */
WARN_ON_ONCE(within_last_ext && WARN_ON_ONCE(within_last_ext &&
elen > ((loff_t)offset + 1) << inode->i_blkbits); elen > ((loff_t)offset + 1) << inode->i_blkbits);
@ -676,8 +689,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
} else { } else {
epos.offset -= adsize; epos.offset -= adsize;
etype = udf_next_aext(inode, &epos, &extent.extLocation, err = udf_next_aext(inode, &epos, &extent.extLocation,
&extent.extLength, 0); &extent.extLength, &etype, 0);
if (err <= 0)
goto out;
extent.extLength |= etype << 30; extent.extLength |= etype << 30;
} }
@ -714,11 +729,11 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
loff_t lbcount = 0, b_off = 0; loff_t lbcount = 0, b_off = 0;
udf_pblk_t newblocknum; udf_pblk_t newblocknum;
sector_t offset = 0; sector_t offset = 0;
int8_t etype; int8_t etype, tmpetype;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum; udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum;
int lastblock = 0; int lastblock = 0;
bool isBeyondEOF; bool isBeyondEOF = false;
int ret = 0; int ret = 0;
prev_epos.offset = udf_file_entry_alloc_offset(inode); prev_epos.offset = udf_file_entry_alloc_offset(inode);
@ -750,9 +765,13 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
prev_epos.offset = cur_epos.offset; prev_epos.offset = cur_epos.offset;
cur_epos.offset = next_epos.offset; cur_epos.offset = next_epos.offset;
etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1); ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 1);
if (etype == -1) if (ret < 0) {
goto out_free;
} else if (ret == 0) {
isBeyondEOF = true;
break; break;
}
c = !c; c = !c;
@ -773,13 +792,17 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
* Move prev_epos and cur_epos into indirect extent if we are at * Move prev_epos and cur_epos into indirect extent if we are at
* the pointer to it * the pointer to it
*/ */
udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0); ret = udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, &tmpetype, 0);
udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0); if (ret < 0)
goto out_free;
ret = udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, &tmpetype, 0);
if (ret < 0)
goto out_free;
/* if the extent is allocated and recorded, return the block /* if the extent is allocated and recorded, return the block
if the extent is not a multiple of the blocksize, round up */ if the extent is not a multiple of the blocksize, round up */
if (etype == (EXT_RECORDED_ALLOCATED >> 30)) { if (!isBeyondEOF && etype == (EXT_RECORDED_ALLOCATED >> 30)) {
if (elen & (inode->i_sb->s_blocksize - 1)) { if (elen & (inode->i_sb->s_blocksize - 1)) {
elen = EXT_RECORDED_ALLOCATED | elen = EXT_RECORDED_ALLOCATED |
((elen + inode->i_sb->s_blocksize - 1) & ((elen + inode->i_sb->s_blocksize - 1) &
@ -795,10 +818,9 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
} }
/* Are we beyond EOF and preallocated extent? */ /* Are we beyond EOF and preallocated extent? */
if (etype == -1) { if (isBeyondEOF) {
loff_t hole_len; loff_t hole_len;
isBeyondEOF = true;
if (count) { if (count) {
if (c) if (c)
laarr[0] = laarr[1]; laarr[0] = laarr[1];
@ -834,7 +856,6 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
endnum = c + 1; endnum = c + 1;
lastblock = 1; lastblock = 1;
} else { } else {
isBeyondEOF = false;
endnum = startnum = ((count > 2) ? 2 : count); endnum = startnum = ((count > 2) ? 2 : count);
/* if the current extent is in position 0, /* if the current extent is in position 0,
@ -848,15 +869,17 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
/* if the current block is located in an extent, /* if the current block is located in an extent,
read the next extent */ read the next extent */
etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0); ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 0);
if (etype != -1) { if (ret > 0) {
laarr[c + 1].extLength = (etype << 30) | elen; laarr[c + 1].extLength = (etype << 30) | elen;
laarr[c + 1].extLocation = eloc; laarr[c + 1].extLocation = eloc;
count++; count++;
startnum++; startnum++;
endnum++; endnum++;
} else } else if (ret == 0)
lastblock = 1; lastblock = 1;
else
goto out_free;
} }
/* if the current extent is not recorded but allocated, get the /* if the current extent is not recorded but allocated, get the
@ -1174,6 +1197,7 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr,
int start = 0, i; int start = 0, i;
struct kernel_lb_addr tmploc; struct kernel_lb_addr tmploc;
uint32_t tmplen; uint32_t tmplen;
int8_t tmpetype;
int err; int err;
if (startnum > endnum) { if (startnum > endnum) {
@ -1191,14 +1215,19 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr,
*/ */
if (err < 0) if (err < 0)
return err; return err;
udf_next_aext(inode, epos, &laarr[i].extLocation, err = udf_next_aext(inode, epos, &laarr[i].extLocation,
&laarr[i].extLength, 1); &laarr[i].extLength, &tmpetype, 1);
if (err < 0)
return err;
start++; start++;
} }
} }
for (i = start; i < endnum; i++) { for (i = start; i < endnum; i++) {
udf_next_aext(inode, epos, &tmploc, &tmplen, 0); err = udf_next_aext(inode, epos, &tmploc, &tmplen, &tmpetype, 0);
if (err < 0)
return err;
udf_write_aext(inode, epos, &laarr[i].extLocation, udf_write_aext(inode, epos, &laarr[i].extLocation,
laarr[i].extLength, 1); laarr[i].extLength, 1);
} }
@ -1953,6 +1982,7 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block,
struct extent_position nepos; struct extent_position nepos;
struct kernel_lb_addr neloc; struct kernel_lb_addr neloc;
int ver, adsize; int ver, adsize;
int err = 0;
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad); adsize = sizeof(struct short_ad);
@ -1997,10 +2027,12 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block,
if (epos->offset + adsize > sb->s_blocksize) { if (epos->offset + adsize > sb->s_blocksize) {
struct kernel_lb_addr cp_loc; struct kernel_lb_addr cp_loc;
uint32_t cp_len; uint32_t cp_len;
int cp_type; int8_t cp_type;
epos->offset -= adsize; epos->offset -= adsize;
cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); err = udf_current_aext(inode, epos, &cp_loc, &cp_len, &cp_type, 0);
if (err <= 0)
goto err_out;
cp_len |= ((uint32_t)cp_type) << 30; cp_len |= ((uint32_t)cp_type) << 30;
__udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1);
@ -2015,6 +2047,9 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block,
*epos = nepos; *epos = nepos;
return 0; return 0;
err_out:
brelse(bh);
return err;
} }
/* /*
@ -2160,21 +2195,30 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos,
*/ */
#define UDF_MAX_INDIR_EXTS 16 #define UDF_MAX_INDIR_EXTS 16
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, /*
struct kernel_lb_addr *eloc, uint32_t *elen, int inc) * Returns 1 on success, -errno on error, 0 on hit EOF.
*/
int udf_next_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype,
int inc)
{ {
int8_t etype;
unsigned int indirections = 0; unsigned int indirections = 0;
int ret = 0;
udf_pblk_t block;
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == while (1) {
(EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { ret = udf_current_aext(inode, epos, eloc, elen,
udf_pblk_t block; etype, inc);
if (ret <= 0)
return ret;
if (*etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30))
return ret;
if (++indirections > UDF_MAX_INDIR_EXTS) { if (++indirections > UDF_MAX_INDIR_EXTS) {
udf_err(inode->i_sb, udf_err(inode->i_sb,
"too many indirect extents in inode %lu\n", "too many indirect extents in inode %lu\n",
inode->i_ino); inode->i_ino);
return -1; return -EFSCORRUPTED;
} }
epos->block = *eloc; epos->block = *eloc;
@ -2184,18 +2228,19 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
epos->bh = sb_bread(inode->i_sb, block); epos->bh = sb_bread(inode->i_sb, block);
if (!epos->bh) { if (!epos->bh) {
udf_debug("reading block %u failed!\n", block); udf_debug("reading block %u failed!\n", block);
return -1; return -EIO;
} }
} }
return etype;
} }
int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, /*
struct kernel_lb_addr *eloc, uint32_t *elen, int inc) * Returns 1 on success, -errno on error, 0 on hit EOF.
*/
int udf_current_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype,
int inc)
{ {
int alen; int alen;
int8_t etype;
uint8_t *ptr; uint8_t *ptr;
struct short_ad *sad; struct short_ad *sad;
struct long_ad *lad; struct long_ad *lad;
@ -2210,20 +2255,23 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
alen = udf_file_entry_alloc_offset(inode) + alen = udf_file_entry_alloc_offset(inode) +
iinfo->i_lenAlloc; iinfo->i_lenAlloc;
} else { } else {
struct allocExtDesc *header =
(struct allocExtDesc *)epos->bh->b_data;
if (!epos->offset) if (!epos->offset)
epos->offset = sizeof(struct allocExtDesc); epos->offset = sizeof(struct allocExtDesc);
ptr = epos->bh->b_data + epos->offset; ptr = epos->bh->b_data + epos->offset;
alen = sizeof(struct allocExtDesc) + if (check_add_overflow(sizeof(struct allocExtDesc),
le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)-> le32_to_cpu(header->lengthAllocDescs), &alen))
lengthAllocDescs); return -1;
} }
switch (iinfo->i_alloc_type) { switch (iinfo->i_alloc_type) {
case ICBTAG_FLAG_AD_SHORT: case ICBTAG_FLAG_AD_SHORT:
sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc); sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc);
if (!sad) if (!sad)
return -1; return 0;
etype = le32_to_cpu(sad->extLength) >> 30; *etype = le32_to_cpu(sad->extLength) >> 30;
eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
eloc->partitionReferenceNum = eloc->partitionReferenceNum =
iinfo->i_location.partitionReferenceNum; iinfo->i_location.partitionReferenceNum;
@ -2232,17 +2280,17 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
case ICBTAG_FLAG_AD_LONG: case ICBTAG_FLAG_AD_LONG:
lad = udf_get_filelongad(ptr, alen, &epos->offset, inc); lad = udf_get_filelongad(ptr, alen, &epos->offset, inc);
if (!lad) if (!lad)
return -1; return 0;
etype = le32_to_cpu(lad->extLength) >> 30; *etype = le32_to_cpu(lad->extLength) >> 30;
*eloc = lelb_to_cpu(lad->extLocation); *eloc = lelb_to_cpu(lad->extLocation);
*elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
break; break;
default: default:
udf_debug("alloc_type = %u unsupported\n", iinfo->i_alloc_type); udf_debug("alloc_type = %u unsupported\n", iinfo->i_alloc_type);
return -1; return -EINVAL;
} }
return etype; return 1;
} }
static int udf_insert_aext(struct inode *inode, struct extent_position epos, static int udf_insert_aext(struct inode *inode, struct extent_position epos,
@ -2251,20 +2299,24 @@ static int udf_insert_aext(struct inode *inode, struct extent_position epos,
struct kernel_lb_addr oeloc; struct kernel_lb_addr oeloc;
uint32_t oelen; uint32_t oelen;
int8_t etype; int8_t etype;
int err; int ret;
if (epos.bh) if (epos.bh)
get_bh(epos.bh); get_bh(epos.bh);
while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { while (1) {
ret = udf_next_aext(inode, &epos, &oeloc, &oelen, &etype, 0);
if (ret <= 0)
break;
udf_write_aext(inode, &epos, &neloc, nelen, 1); udf_write_aext(inode, &epos, &neloc, nelen, 1);
neloc = oeloc; neloc = oeloc;
nelen = (etype << 30) | oelen; nelen = (etype << 30) | oelen;
} }
err = udf_add_aext(inode, &epos, &neloc, nelen, 1); if (ret == 0)
ret = udf_add_aext(inode, &epos, &neloc, nelen, 1);
brelse(epos.bh); brelse(epos.bh);
return err; return ret;
} }
int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
@ -2276,6 +2328,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
struct kernel_lb_addr eloc; struct kernel_lb_addr eloc;
uint32_t elen; uint32_t elen;
int ret;
if (epos.bh) { if (epos.bh) {
get_bh(epos.bh); get_bh(epos.bh);
@ -2291,10 +2344,18 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
adsize = 0; adsize = 0;
oepos = epos; oepos = epos;
if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) if (udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1) <= 0)
return -1; return -1;
while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { while (1) {
ret = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1);
if (ret < 0) {
brelse(epos.bh);
brelse(oepos.bh);
return -1;
}
if (ret == 0)
break;
udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1); udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1);
if (oepos.bh != epos.bh) { if (oepos.bh != epos.bh) {
oepos.block = epos.block; oepos.block = epos.block;
@ -2351,14 +2412,17 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
return (elen >> 30); return (elen >> 30);
} }
int8_t inode_bmap(struct inode *inode, sector_t block, /*
struct extent_position *pos, struct kernel_lb_addr *eloc, * Returns 1 on success, -errno on error, 0 on hit EOF.
uint32_t *elen, sector_t *offset) */
int inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos,
struct kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset,
int8_t *etype)
{ {
unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits;
int8_t etype;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
int err = 0;
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) {
@ -2368,11 +2432,13 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
} }
*elen = 0; *elen = 0;
do { do {
etype = udf_next_aext(inode, pos, eloc, elen, 1); err = udf_next_aext(inode, pos, eloc, elen, etype, 1);
if (etype == -1) { if (err <= 0) {
*offset = (bcount - lbcount) >> blocksize_bits; if (err == 0) {
iinfo->i_lenExtents = lbcount; *offset = (bcount - lbcount) >> blocksize_bits;
return -1; iinfo->i_lenExtents = lbcount;
}
return err;
} }
lbcount += *elen; lbcount += *elen;
} while (lbcount <= bcount); } while (lbcount <= bcount);
@ -2380,5 +2446,5 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
udf_update_extent_cache(inode, lbcount - *elen, pos); udf_update_extent_cache(inode, lbcount - *elen, pos);
*offset = (bcount + *elen - lbcount) >> blocksize_bits; *offset = (bcount + *elen - lbcount) >> blocksize_bits;
return etype; return 1;
} }

View File

@ -282,9 +282,11 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
sector_t ext_offset; sector_t ext_offset;
struct extent_position epos = {}; struct extent_position epos = {};
uint32_t phyblock; uint32_t phyblock;
int8_t etype;
int err = 0;
if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != err = inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset, &etype);
(EXT_RECORDED_ALLOCATED >> 30)) if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30))
phyblock = 0xFFFFFFFF; phyblock = 0xFFFFFFFF;
else { else {
map = &UDF_SB(sb)->s_partmaps[partition]; map = &UDF_SB(sb)->s_partmaps[partition];

View File

@ -2454,13 +2454,14 @@ static unsigned int udf_count_free_table(struct super_block *sb,
uint32_t elen; uint32_t elen;
struct kernel_lb_addr eloc; struct kernel_lb_addr eloc;
struct extent_position epos; struct extent_position epos;
int8_t etype;
mutex_lock(&UDF_SB(sb)->s_alloc_mutex); mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
epos.block = UDF_I(table)->i_location; epos.block = UDF_I(table)->i_location;
epos.offset = sizeof(struct unallocSpaceEntry); epos.offset = sizeof(struct unallocSpaceEntry);
epos.bh = NULL; epos.bh = NULL;
while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1) while (udf_next_aext(table, &epos, &eloc, &elen, &etype, 1) > 0)
accum += (elen >> table->i_sb->s_blocksize_bits); accum += (elen >> table->i_sb->s_blocksize_bits);
brelse(epos.bh); brelse(epos.bh);

View File

@ -69,6 +69,7 @@ void udf_truncate_tail_extent(struct inode *inode)
int8_t etype = -1, netype; int8_t etype = -1, netype;
int adsize; int adsize;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int ret;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
inode->i_size == iinfo->i_lenExtents) inode->i_size == iinfo->i_lenExtents)
@ -85,7 +86,10 @@ void udf_truncate_tail_extent(struct inode *inode)
BUG(); BUG();
/* Find the last extent in the file */ /* Find the last extent in the file */
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { while (1) {
ret = udf_next_aext(inode, &epos, &eloc, &elen, &netype, 1);
if (ret <= 0)
break;
etype = netype; etype = netype;
lbcount += elen; lbcount += elen;
if (lbcount > inode->i_size) { if (lbcount > inode->i_size) {
@ -101,7 +105,8 @@ void udf_truncate_tail_extent(struct inode *inode)
epos.offset -= adsize; epos.offset -= adsize;
extent_trunc(inode, &epos, &eloc, etype, elen, nelen); extent_trunc(inode, &epos, &eloc, etype, elen, nelen);
epos.offset += adsize; epos.offset += adsize;
if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1) if (udf_next_aext(inode, &epos, &eloc, &elen,
&netype, 1) > 0)
udf_err(inode->i_sb, udf_err(inode->i_sb,
"Extent after EOF in inode %u\n", "Extent after EOF in inode %u\n",
(unsigned)inode->i_ino); (unsigned)inode->i_ino);
@ -110,7 +115,8 @@ void udf_truncate_tail_extent(struct inode *inode)
} }
/* This inode entry is in-memory only and thus we don't have to mark /* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */ * the inode dirty */
iinfo->i_lenExtents = inode->i_size; if (ret == 0)
iinfo->i_lenExtents = inode->i_size;
brelse(epos.bh); brelse(epos.bh);
} }
@ -124,6 +130,8 @@ void udf_discard_prealloc(struct inode *inode)
int8_t etype = -1; int8_t etype = -1;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int bsize = i_blocksize(inode); int bsize = i_blocksize(inode);
int8_t tmpetype = -1;
int ret;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize)) ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize))
@ -132,15 +140,23 @@ void udf_discard_prealloc(struct inode *inode)
epos.block = iinfo->i_location; epos.block = iinfo->i_location;
/* Find the last extent in the file */ /* Find the last extent in the file */
while (udf_next_aext(inode, &epos, &eloc, &elen, 0) != -1) { while (1) {
ret = udf_next_aext(inode, &epos, &eloc, &elen, &tmpetype, 0);
if (ret < 0)
goto out;
if (ret == 0)
break;
brelse(prev_epos.bh); brelse(prev_epos.bh);
prev_epos = epos; prev_epos = epos;
if (prev_epos.bh) if (prev_epos.bh)
get_bh(prev_epos.bh); get_bh(prev_epos.bh);
etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); ret = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1);
if (ret < 0)
goto out;
lbcount += elen; lbcount += elen;
} }
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
lbcount -= elen; lbcount -= elen;
udf_delete_aext(inode, prev_epos); udf_delete_aext(inode, prev_epos);
@ -150,6 +166,7 @@ void udf_discard_prealloc(struct inode *inode)
/* This inode entry is in-memory only and thus we don't have to mark /* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */ * the inode dirty */
iinfo->i_lenExtents = lbcount; iinfo->i_lenExtents = lbcount;
out:
brelse(epos.bh); brelse(epos.bh);
brelse(prev_epos.bh); brelse(prev_epos.bh);
} }
@ -188,6 +205,7 @@ int udf_truncate_extents(struct inode *inode)
loff_t byte_offset; loff_t byte_offset;
int adsize; int adsize;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int ret = 0;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad); adsize = sizeof(struct short_ad);
@ -196,10 +214,12 @@ int udf_truncate_extents(struct inode *inode)
else else
BUG(); BUG();
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); ret = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype);
if (ret < 0)
return ret;
byte_offset = (offset << sb->s_blocksize_bits) + byte_offset = (offset << sb->s_blocksize_bits) +
(inode->i_size & (sb->s_blocksize - 1)); (inode->i_size & (sb->s_blocksize - 1));
if (etype == -1) { if (ret == 0) {
/* We should extend the file? */ /* We should extend the file? */
WARN_ON(byte_offset); WARN_ON(byte_offset);
return 0; return 0;
@ -217,8 +237,8 @@ int udf_truncate_extents(struct inode *inode)
else else
lenalloc -= sizeof(struct allocExtDesc); lenalloc -= sizeof(struct allocExtDesc);
while ((etype = udf_current_aext(inode, &epos, &eloc, while ((ret = udf_current_aext(inode, &epos, &eloc,
&elen, 0)) != -1) { &elen, &etype, 0)) > 0) {
if (etype == (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { if (etype == (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) {
udf_write_aext(inode, &epos, &neloc, nelen, 0); udf_write_aext(inode, &epos, &neloc, nelen, 0);
if (indirect_ext_len) { if (indirect_ext_len) {
@ -253,6 +273,11 @@ int udf_truncate_extents(struct inode *inode)
} }
} }
if (ret < 0) {
brelse(epos.bh);
return ret;
}
if (indirect_ext_len) { if (indirect_ext_len) {
BUG_ON(!epos.bh); BUG_ON(!epos.bh);
udf_free_blocks(sb, NULL, &epos.block, 0, indirect_ext_len); udf_free_blocks(sb, NULL, &epos.block, 0, indirect_ext_len);

View File

@ -157,8 +157,9 @@ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
extern int udf_setsize(struct inode *, loff_t); extern int udf_setsize(struct inode *, loff_t);
extern void udf_evict_inode(struct inode *); extern void udf_evict_inode(struct inode *);
extern int udf_write_inode(struct inode *, struct writeback_control *wbc); extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, extern int inode_bmap(struct inode *inode, sector_t block,
struct kernel_lb_addr *, uint32_t *, sector_t *); struct extent_position *pos, struct kernel_lb_addr *eloc,
uint32_t *elen, sector_t *offset, int8_t *etype);
int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block,
struct extent_position *epos); struct extent_position *epos);
@ -169,10 +170,12 @@ extern int udf_add_aext(struct inode *, struct extent_position *,
extern void udf_write_aext(struct inode *, struct extent_position *, extern void udf_write_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int); struct kernel_lb_addr *, uint32_t, int);
extern int8_t udf_delete_aext(struct inode *, struct extent_position); extern int8_t udf_delete_aext(struct inode *, struct extent_position);
extern int8_t udf_next_aext(struct inode *, struct extent_position *, extern int udf_next_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *, uint32_t *, int); struct kernel_lb_addr *eloc, uint32_t *elen,
extern int8_t udf_current_aext(struct inode *, struct extent_position *, int8_t *etype, int inc);
struct kernel_lb_addr *, uint32_t *, int); extern int udf_current_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen,
int8_t *etype, int inc);
extern void udf_update_extra_perms(struct inode *inode, umode_t mode); extern void udf_update_extra_perms(struct inode *inode, umode_t mode);
/* misc.c */ /* misc.c */

View File

@ -3402,6 +3402,12 @@ static inline void netif_tx_wake_all_queues(struct net_device *dev)
static __always_inline void netif_tx_stop_queue(struct netdev_queue *dev_queue) static __always_inline void netif_tx_stop_queue(struct netdev_queue *dev_queue)
{ {
/* Paired with READ_ONCE() from dev_watchdog() */
WRITE_ONCE(dev_queue->trans_start, jiffies);
/* This barrier is paired with smp_mb() from dev_watchdog() */
smp_mb__before_atomic();
/* Must be an atomic op see netif_txq_try_stop() */ /* Must be an atomic op see netif_txq_try_stop() */
set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state);
} }
@ -3518,6 +3524,12 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
if (likely(dql_avail(&dev_queue->dql) >= 0)) if (likely(dql_avail(&dev_queue->dql) >= 0))
return; return;
/* Paired with READ_ONCE() from dev_watchdog() */
WRITE_ONCE(dev_queue->trans_start, jiffies);
/* This barrier is paired with smp_mb() from dev_watchdog() */
smp_mb__before_atomic();
set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state); set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);
/* /*

View File

@ -339,20 +339,25 @@ struct xfrm_if_cb {
void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb); void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb);
void xfrm_if_unregister_cb(void); void xfrm_if_unregister_cb(void);
struct xfrm_dst_lookup_params {
struct net *net;
int tos;
int oif;
xfrm_address_t *saddr;
xfrm_address_t *daddr;
u32 mark;
__u8 ipproto;
union flowi_uli uli;
};
struct net_device; struct net_device;
struct xfrm_type; struct xfrm_type;
struct xfrm_dst; struct xfrm_dst;
struct xfrm_policy_afinfo { struct xfrm_policy_afinfo {
struct dst_ops *dst_ops; struct dst_ops *dst_ops;
struct dst_entry *(*dst_lookup)(struct net *net, struct dst_entry *(*dst_lookup)(const struct xfrm_dst_lookup_params *params);
int tos, int oif, int (*get_saddr)(xfrm_address_t *saddr,
const xfrm_address_t *saddr, const struct xfrm_dst_lookup_params *params);
const xfrm_address_t *daddr,
u32 mark);
int (*get_saddr)(struct net *net, int oif,
xfrm_address_t *saddr,
xfrm_address_t *daddr,
u32 mark);
int (*fill_dst)(struct xfrm_dst *xdst, int (*fill_dst)(struct xfrm_dst *xdst,
struct net_device *dev, struct net_device *dev,
const struct flowi *fl); const struct flowi *fl);
@ -1723,10 +1728,7 @@ static inline int xfrm_user_policy(struct sock *sk, int optname,
} }
#endif #endif
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, struct dst_entry *__xfrm_dst_lookup(int family, const struct xfrm_dst_lookup_params *params);
const xfrm_address_t *saddr,
const xfrm_address_t *daddr,
int family, u32 mark);
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);

View File

@ -5773,6 +5773,7 @@ static const char readme_msg[] =
"\t $stack<index>, $stack, $retval, $comm,\n" "\t $stack<index>, $stack, $retval, $comm,\n"
#endif #endif
"\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n" "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
"\t kernel return probes support: $retval, $arg<N>, $comm\n"
"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n" "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n"
"\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n" "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
"\t symstr, <type>\\[<array-size>\\]\n" "\t symstr, <type>\\[<array-size>\\]\n"

View File

@ -220,7 +220,7 @@ static struct trace_eprobe *alloc_event_probe(const char *group,
if (!ep->event_system) if (!ep->event_system)
goto error; goto error;
ret = trace_probe_init(&ep->tp, this_event, group, false); ret = trace_probe_init(&ep->tp, this_event, group, false, nargs);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -390,8 +390,8 @@ static int get_eprobe_size(struct trace_probe *tp, void *rec)
/* Note that we don't verify it, since the code does not come from user space */ /* Note that we don't verify it, since the code does not come from user space */
static int static int
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest, process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
void *base) void *dest, void *base)
{ {
unsigned long val; unsigned long val;
int ret; int ret;
@ -438,7 +438,7 @@ __eprobe_trace_func(struct eprobe_data *edata, void *rec)
return; return;
entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event); entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
store_trace_args(&entry[1], &edata->ep->tp, rec, sizeof(*entry), dsize); store_trace_args(&entry[1], &edata->ep->tp, rec, NULL, sizeof(*entry), dsize);
trace_event_buffer_commit(&fbuffer); trace_event_buffer_commit(&fbuffer);
} }
@ -915,6 +915,11 @@ static int __trace_eprobe_create(int argc, const char *argv[])
} }
} }
if (argc - 2 > MAX_TRACE_ARGS) {
ret = -E2BIG;
goto error;
}
mutex_lock(&event_mutex); mutex_lock(&event_mutex);
event_call = find_and_get_event(sys_name, sys_event); event_call = find_and_get_event(sys_name, sys_event);
ep = alloc_event_probe(group, event, event_call, argc - 2); ep = alloc_event_probe(group, event, event_call, argc - 2);
@ -940,7 +945,7 @@ static int __trace_eprobe_create(int argc, const char *argv[])
argc -= 2; argv += 2; argc -= 2; argv += 2;
/* parse arguments */ /* parse arguments */
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc; i++) {
trace_probe_log_set_index(i + 2); trace_probe_log_set_index(i + 2);
ret = trace_eprobe_tp_update_arg(ep, argv, i); ret = trace_eprobe_tp_update_arg(ep, argv, i);
if (ret) if (ret)

View File

@ -4,6 +4,7 @@
* Copyright (C) 2022 Google LLC. * Copyright (C) 2022 Google LLC.
*/ */
#define pr_fmt(fmt) "trace_fprobe: " fmt #define pr_fmt(fmt) "trace_fprobe: " fmt
#include <asm/ptrace.h>
#include <linux/fprobe.h> #include <linux/fprobe.h>
#include <linux/module.h> #include <linux/module.h>
@ -129,8 +130,8 @@ static bool trace_fprobe_is_registered(struct trace_fprobe *tf)
* from user space. * from user space.
*/ */
static int static int
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest, process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
void *base) void *dest, void *base)
{ {
struct pt_regs *regs = rec; struct pt_regs *regs = rec;
unsigned long val; unsigned long val;
@ -152,6 +153,9 @@ retry:
case FETCH_OP_ARG: case FETCH_OP_ARG:
val = regs_get_kernel_argument(regs, code->param); val = regs_get_kernel_argument(regs, code->param);
break; break;
case FETCH_OP_EDATA:
val = *(unsigned long *)((unsigned long)edata + code->offset);
break;
#endif #endif
case FETCH_NOP_SYMBOL: /* Ignore a place holder */ case FETCH_NOP_SYMBOL: /* Ignore a place holder */
code++; code++;
@ -184,7 +188,7 @@ __fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
if (trace_trigger_soft_disabled(trace_file)) if (trace_trigger_soft_disabled(trace_file))
return; return;
dsize = __get_data_size(&tf->tp, regs); dsize = __get_data_size(&tf->tp, regs, NULL);
entry = trace_event_buffer_reserve(&fbuffer, trace_file, entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + tf->tp.size + dsize); sizeof(*entry) + tf->tp.size + dsize);
@ -194,7 +198,7 @@ __fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
fbuffer.regs = regs; fbuffer.regs = regs;
entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event); entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
entry->ip = entry_ip; entry->ip = entry_ip;
store_trace_args(&entry[1], &tf->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tf->tp, regs, NULL, sizeof(*entry), dsize);
trace_event_buffer_commit(&fbuffer); trace_event_buffer_commit(&fbuffer);
} }
@ -210,11 +214,24 @@ fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
} }
NOKPROBE_SYMBOL(fentry_trace_func); NOKPROBE_SYMBOL(fentry_trace_func);
/* Kretprobe handler */ /* function exit handler */
static int trace_fprobe_entry_handler(struct fprobe *fp, unsigned long entry_ip,
unsigned long ret_ip, struct pt_regs *regs,
void *entry_data)
{
struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
if (tf->tp.entry_arg)
store_trace_entry_data(entry_data, &tf->tp, regs);
return 0;
}
NOKPROBE_SYMBOL(trace_fprobe_entry_handler)
static nokprobe_inline void static nokprobe_inline void
__fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip, __fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
unsigned long ret_ip, struct pt_regs *regs, unsigned long ret_ip, struct pt_regs *regs,
struct trace_event_file *trace_file) void *entry_data, struct trace_event_file *trace_file)
{ {
struct fexit_trace_entry_head *entry; struct fexit_trace_entry_head *entry;
struct trace_event_buffer fbuffer; struct trace_event_buffer fbuffer;
@ -227,7 +244,7 @@ __fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
if (trace_trigger_soft_disabled(trace_file)) if (trace_trigger_soft_disabled(trace_file))
return; return;
dsize = __get_data_size(&tf->tp, regs); dsize = __get_data_size(&tf->tp, regs, entry_data);
entry = trace_event_buffer_reserve(&fbuffer, trace_file, entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + tf->tp.size + dsize); sizeof(*entry) + tf->tp.size + dsize);
@ -238,19 +255,19 @@ __fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event); entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
entry->func = entry_ip; entry->func = entry_ip;
entry->ret_ip = ret_ip; entry->ret_ip = ret_ip;
store_trace_args(&entry[1], &tf->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tf->tp, regs, entry_data, sizeof(*entry), dsize);
trace_event_buffer_commit(&fbuffer); trace_event_buffer_commit(&fbuffer);
} }
static void static void
fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip, fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
unsigned long ret_ip, struct pt_regs *regs) unsigned long ret_ip, struct pt_regs *regs, void *entry_data)
{ {
struct event_file_link *link; struct event_file_link *link;
trace_probe_for_each_link_rcu(link, &tf->tp) trace_probe_for_each_link_rcu(link, &tf->tp)
__fexit_trace_func(tf, entry_ip, ret_ip, regs, link->file); __fexit_trace_func(tf, entry_ip, ret_ip, regs, entry_data, link->file);
} }
NOKPROBE_SYMBOL(fexit_trace_func); NOKPROBE_SYMBOL(fexit_trace_func);
@ -269,7 +286,7 @@ static int fentry_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
if (hlist_empty(head)) if (hlist_empty(head))
return 0; return 0;
dsize = __get_data_size(&tf->tp, regs); dsize = __get_data_size(&tf->tp, regs, NULL);
__size = sizeof(*entry) + tf->tp.size + dsize; __size = sizeof(*entry) + tf->tp.size + dsize;
size = ALIGN(__size + sizeof(u32), sizeof(u64)); size = ALIGN(__size + sizeof(u32), sizeof(u64));
size -= sizeof(u32); size -= sizeof(u32);
@ -280,7 +297,7 @@ static int fentry_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
entry->ip = entry_ip; entry->ip = entry_ip;
memset(&entry[1], 0, dsize); memset(&entry[1], 0, dsize);
store_trace_args(&entry[1], &tf->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tf->tp, regs, NULL, sizeof(*entry), dsize);
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
head, NULL); head, NULL);
return 0; return 0;
@ -289,7 +306,8 @@ NOKPROBE_SYMBOL(fentry_perf_func);
static void static void
fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip, fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
unsigned long ret_ip, struct pt_regs *regs) unsigned long ret_ip, struct pt_regs *regs,
void *entry_data)
{ {
struct trace_event_call *call = trace_probe_event_call(&tf->tp); struct trace_event_call *call = trace_probe_event_call(&tf->tp);
struct fexit_trace_entry_head *entry; struct fexit_trace_entry_head *entry;
@ -301,7 +319,7 @@ fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
if (hlist_empty(head)) if (hlist_empty(head))
return; return;
dsize = __get_data_size(&tf->tp, regs); dsize = __get_data_size(&tf->tp, regs, entry_data);
__size = sizeof(*entry) + tf->tp.size + dsize; __size = sizeof(*entry) + tf->tp.size + dsize;
size = ALIGN(__size + sizeof(u32), sizeof(u64)); size = ALIGN(__size + sizeof(u32), sizeof(u64));
size -= sizeof(u32); size -= sizeof(u32);
@ -312,7 +330,7 @@ fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
entry->func = entry_ip; entry->func = entry_ip;
entry->ret_ip = ret_ip; entry->ret_ip = ret_ip;
store_trace_args(&entry[1], &tf->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tf->tp, regs, entry_data, sizeof(*entry), dsize);
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
head, NULL); head, NULL);
} }
@ -343,10 +361,10 @@ static void fexit_dispatcher(struct fprobe *fp, unsigned long entry_ip,
struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp); struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE)) if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE))
fexit_trace_func(tf, entry_ip, ret_ip, regs); fexit_trace_func(tf, entry_ip, ret_ip, regs, entry_data);
#ifdef CONFIG_PERF_EVENTS #ifdef CONFIG_PERF_EVENTS
if (trace_probe_test_flag(&tf->tp, TP_FLAG_PROFILE)) if (trace_probe_test_flag(&tf->tp, TP_FLAG_PROFILE))
fexit_perf_func(tf, entry_ip, ret_ip, regs); fexit_perf_func(tf, entry_ip, ret_ip, regs, entry_data);
#endif #endif
} }
NOKPROBE_SYMBOL(fexit_dispatcher); NOKPROBE_SYMBOL(fexit_dispatcher);
@ -389,7 +407,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
tf->tpoint = tpoint; tf->tpoint = tpoint;
tf->fp.nr_maxactive = maxactive; tf->fp.nr_maxactive = maxactive;
ret = trace_probe_init(&tf->tp, event, group, false); ret = trace_probe_init(&tf->tp, event, group, false, nargs);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -1085,6 +1103,10 @@ static int __trace_fprobe_create(int argc, const char *argv[])
argc = new_argc; argc = new_argc;
argv = new_argv; argv = new_argv;
} }
if (argc > MAX_TRACE_ARGS) {
ret = -E2BIG;
goto out;
}
/* setup a probe */ /* setup a probe */
tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive, tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive,
@ -1101,7 +1123,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
(unsigned long)tf->tpoint->probestub); (unsigned long)tf->tpoint->probestub);
/* parse arguments */ /* parse arguments */
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc; i++) {
trace_probe_log_set_index(i + 2); trace_probe_log_set_index(i + 2);
ctx.offset = 0; ctx.offset = 0;
ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], &ctx); ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], &ctx);
@ -1109,6 +1131,11 @@ static int __trace_fprobe_create(int argc, const char *argv[])
goto error; /* This can be -ENOMEM */ goto error; /* This can be -ENOMEM */
} }
if (is_return && tf->tp.entry_arg) {
tf->fp.entry_handler = trace_fprobe_entry_handler;
tf->fp.entry_data_size = traceprobe_get_entry_data_size(&tf->tp);
}
ret = traceprobe_set_print_fmt(&tf->tp, ret = traceprobe_set_print_fmt(&tf->tp,
is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL); is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL);
if (ret < 0) if (ret < 0)

View File

@ -290,7 +290,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
INIT_HLIST_NODE(&tk->rp.kp.hlist); INIT_HLIST_NODE(&tk->rp.kp.hlist);
INIT_LIST_HEAD(&tk->rp.kp.list); INIT_LIST_HEAD(&tk->rp.kp.list);
ret = trace_probe_init(&tk->tp, event, group, false); ret = trace_probe_init(&tk->tp, event, group, false, nargs);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -740,6 +740,9 @@ static unsigned int number_of_same_symbols(char *func_name)
return ctx.count; return ctx.count;
} }
static int trace_kprobe_entry_handler(struct kretprobe_instance *ri,
struct pt_regs *regs);
static int __trace_kprobe_create(int argc, const char *argv[]) static int __trace_kprobe_create(int argc, const char *argv[])
{ {
/* /*
@ -929,6 +932,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
argc = new_argc; argc = new_argc;
argv = new_argv; argv = new_argv;
} }
if (argc > MAX_TRACE_ARGS) {
ret = -E2BIG;
goto out;
}
/* setup a probe */ /* setup a probe */
tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive, tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
@ -941,13 +948,18 @@ static int __trace_kprobe_create(int argc, const char *argv[])
} }
/* parse arguments */ /* parse arguments */
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc; i++) {
trace_probe_log_set_index(i + 2); trace_probe_log_set_index(i + 2);
ctx.offset = 0; ctx.offset = 0;
ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx); ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
if (ret) if (ret)
goto error; /* This can be -ENOMEM */ goto error; /* This can be -ENOMEM */
} }
/* entry handler for kretprobe */
if (is_return && tk->tp.entry_arg) {
tk->rp.entry_handler = trace_kprobe_entry_handler;
tk->rp.data_size = traceprobe_get_entry_data_size(&tk->tp);
}
ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL; ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
ret = traceprobe_set_print_fmt(&tk->tp, ptype); ret = traceprobe_set_print_fmt(&tk->tp, ptype);
@ -1298,8 +1310,8 @@ static const struct file_operations kprobe_profile_ops = {
/* Note that we don't verify it, since the code does not come from user space */ /* Note that we don't verify it, since the code does not come from user space */
static int static int
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest, process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
void *base) void *dest, void *base)
{ {
struct pt_regs *regs = rec; struct pt_regs *regs = rec;
unsigned long val; unsigned long val;
@ -1324,6 +1336,9 @@ retry:
case FETCH_OP_ARG: case FETCH_OP_ARG:
val = regs_get_kernel_argument(regs, code->param); val = regs_get_kernel_argument(regs, code->param);
break; break;
case FETCH_OP_EDATA:
val = *(unsigned long *)((unsigned long)edata + code->offset);
break;
#endif #endif
case FETCH_NOP_SYMBOL: /* Ignore a place holder */ case FETCH_NOP_SYMBOL: /* Ignore a place holder */
code++; code++;
@ -1354,7 +1369,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
if (trace_trigger_soft_disabled(trace_file)) if (trace_trigger_soft_disabled(trace_file))
return; return;
dsize = __get_data_size(&tk->tp, regs); dsize = __get_data_size(&tk->tp, regs, NULL);
entry = trace_event_buffer_reserve(&fbuffer, trace_file, entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + tk->tp.size + dsize); sizeof(*entry) + tk->tp.size + dsize);
@ -1363,7 +1378,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
fbuffer.regs = regs; fbuffer.regs = regs;
entry->ip = (unsigned long)tk->rp.kp.addr; entry->ip = (unsigned long)tk->rp.kp.addr;
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tk->tp, regs, NULL, sizeof(*entry), dsize);
trace_event_buffer_commit(&fbuffer); trace_event_buffer_commit(&fbuffer);
} }
@ -1379,6 +1394,31 @@ kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs)
NOKPROBE_SYMBOL(kprobe_trace_func); NOKPROBE_SYMBOL(kprobe_trace_func);
/* Kretprobe handler */ /* Kretprobe handler */
static int trace_kprobe_entry_handler(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
struct kretprobe *rp = get_kretprobe(ri);
struct trace_kprobe *tk;
/*
* There is a small chance that get_kretprobe(ri) returns NULL when
* the kretprobe is unregister on another CPU between kretprobe's
* trampoline_handler and this function.
*/
if (unlikely(!rp))
return -ENOENT;
tk = container_of(rp, struct trace_kprobe, rp);
/* store argument values into ri->data as entry data */
if (tk->tp.entry_arg)
store_trace_entry_data(ri->data, &tk->tp, regs);
return 0;
}
static nokprobe_inline void static nokprobe_inline void
__kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
struct pt_regs *regs, struct pt_regs *regs,
@ -1394,7 +1434,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
if (trace_trigger_soft_disabled(trace_file)) if (trace_trigger_soft_disabled(trace_file))
return; return;
dsize = __get_data_size(&tk->tp, regs); dsize = __get_data_size(&tk->tp, regs, ri->data);
entry = trace_event_buffer_reserve(&fbuffer, trace_file, entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + tk->tp.size + dsize); sizeof(*entry) + tk->tp.size + dsize);
@ -1404,7 +1444,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
fbuffer.regs = regs; fbuffer.regs = regs;
entry->func = (unsigned long)tk->rp.kp.addr; entry->func = (unsigned long)tk->rp.kp.addr;
entry->ret_ip = get_kretprobe_retaddr(ri); entry->ret_ip = get_kretprobe_retaddr(ri);
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tk->tp, regs, ri->data, sizeof(*entry), dsize);
trace_event_buffer_commit(&fbuffer); trace_event_buffer_commit(&fbuffer);
} }
@ -1552,7 +1592,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
if (hlist_empty(head)) if (hlist_empty(head))
return 0; return 0;
dsize = __get_data_size(&tk->tp, regs); dsize = __get_data_size(&tk->tp, regs, NULL);
__size = sizeof(*entry) + tk->tp.size + dsize; __size = sizeof(*entry) + tk->tp.size + dsize;
size = ALIGN(__size + sizeof(u32), sizeof(u64)); size = ALIGN(__size + sizeof(u32), sizeof(u64));
size -= sizeof(u32); size -= sizeof(u32);
@ -1563,7 +1603,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
entry->ip = (unsigned long)tk->rp.kp.addr; entry->ip = (unsigned long)tk->rp.kp.addr;
memset(&entry[1], 0, dsize); memset(&entry[1], 0, dsize);
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tk->tp, regs, NULL, sizeof(*entry), dsize);
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
head, NULL); head, NULL);
return 0; return 0;
@ -1588,7 +1628,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
if (hlist_empty(head)) if (hlist_empty(head))
return; return;
dsize = __get_data_size(&tk->tp, regs); dsize = __get_data_size(&tk->tp, regs, ri->data);
__size = sizeof(*entry) + tk->tp.size + dsize; __size = sizeof(*entry) + tk->tp.size + dsize;
size = ALIGN(__size + sizeof(u32), sizeof(u64)); size = ALIGN(__size + sizeof(u32), sizeof(u64));
size -= sizeof(u32); size -= sizeof(u32);
@ -1599,7 +1639,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
entry->func = (unsigned long)tk->rp.kp.addr; entry->func = (unsigned long)tk->rp.kp.addr;
entry->ret_ip = get_kretprobe_retaddr(ri); entry->ret_ip = get_kretprobe_retaddr(ri);
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); store_trace_args(&entry[1], &tk->tp, regs, ri->data, sizeof(*entry), dsize);
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
head, NULL); head, NULL);
} }

View File

@ -275,7 +275,7 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
} }
trace_probe_log_err(offset, NO_EVENT_NAME); trace_probe_log_err(offset, NO_EVENT_NAME);
return -EINVAL; return -EINVAL;
} else if (len > MAX_EVENT_NAME_LEN) { } else if (len >= MAX_EVENT_NAME_LEN) {
trace_probe_log_err(offset, EVENT_TOO_LONG); trace_probe_log_err(offset, EVENT_TOO_LONG);
return -EINVAL; return -EINVAL;
} }
@ -598,6 +598,8 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type,
return 0; return 0;
} }
static int __store_entry_arg(struct trace_probe *tp, int argnum);
static int parse_btf_arg(char *varname, static int parse_btf_arg(char *varname,
struct fetch_insn **pcode, struct fetch_insn *end, struct fetch_insn **pcode, struct fetch_insn *end,
struct traceprobe_parse_context *ctx) struct traceprobe_parse_context *ctx)
@ -622,11 +624,7 @@ static int parse_btf_arg(char *varname,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (ctx->flags & TPARG_FL_RETURN) { if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) {
if (strcmp(varname, "$retval") != 0) {
trace_probe_log_err(ctx->offset, NO_BTFARG);
return -ENOENT;
}
code->op = FETCH_OP_RETVAL; code->op = FETCH_OP_RETVAL;
/* Check whether the function return type is not void */ /* Check whether the function return type is not void */
if (query_btf_context(ctx) == 0) { if (query_btf_context(ctx) == 0) {
@ -658,11 +656,21 @@ static int parse_btf_arg(char *varname,
const char *name = btf_name_by_offset(ctx->btf, params[i].name_off); const char *name = btf_name_by_offset(ctx->btf, params[i].name_off);
if (name && !strcmp(name, varname)) { if (name && !strcmp(name, varname)) {
code->op = FETCH_OP_ARG; if (tparg_is_function_entry(ctx->flags)) {
if (ctx->flags & TPARG_FL_TPOINT) code->op = FETCH_OP_ARG;
code->param = i + 1; if (ctx->flags & TPARG_FL_TPOINT)
else code->param = i + 1;
code->param = i; else
code->param = i;
} else if (tparg_is_function_return(ctx->flags)) {
code->op = FETCH_OP_EDATA;
ret = __store_entry_arg(ctx->tp, i);
if (ret < 0) {
/* internal error */
return ret;
}
code->offset = ret;
}
tid = params[i].type; tid = params[i].type;
goto found; goto found;
} }
@ -759,6 +767,110 @@ static int check_prepare_btf_string_fetch(char *typename,
#endif #endif
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
static int __store_entry_arg(struct trace_probe *tp, int argnum)
{
struct probe_entry_arg *earg = tp->entry_arg;
bool match = false;
int i, offset;
if (!earg) {
earg = kzalloc(sizeof(*tp->entry_arg), GFP_KERNEL);
if (!earg)
return -ENOMEM;
earg->size = 2 * tp->nr_args + 1;
earg->code = kcalloc(earg->size, sizeof(struct fetch_insn),
GFP_KERNEL);
if (!earg->code) {
kfree(earg);
return -ENOMEM;
}
/* Fill the code buffer with 'end' to simplify it */
for (i = 0; i < earg->size; i++)
earg->code[i].op = FETCH_OP_END;
tp->entry_arg = earg;
}
offset = 0;
for (i = 0; i < earg->size - 1; i++) {
switch (earg->code[i].op) {
case FETCH_OP_END:
earg->code[i].op = FETCH_OP_ARG;
earg->code[i].param = argnum;
earg->code[i + 1].op = FETCH_OP_ST_EDATA;
earg->code[i + 1].offset = offset;
return offset;
case FETCH_OP_ARG:
match = (earg->code[i].param == argnum);
break;
case FETCH_OP_ST_EDATA:
offset = earg->code[i].offset;
if (match)
return offset;
offset += sizeof(unsigned long);
break;
default:
break;
}
}
return -ENOSPC;
}
int traceprobe_get_entry_data_size(struct trace_probe *tp)
{
struct probe_entry_arg *earg = tp->entry_arg;
int i, size = 0;
if (!earg)
return 0;
for (i = 0; i < earg->size; i++) {
switch (earg->code[i].op) {
case FETCH_OP_END:
goto out;
case FETCH_OP_ST_EDATA:
size = earg->code[i].offset + sizeof(unsigned long);
break;
default:
break;
}
}
out:
return size;
}
void store_trace_entry_data(void *edata, struct trace_probe *tp, struct pt_regs *regs)
{
struct probe_entry_arg *earg = tp->entry_arg;
unsigned long val;
int i;
if (!earg)
return;
for (i = 0; i < earg->size; i++) {
struct fetch_insn *code = &earg->code[i];
switch (code->op) {
case FETCH_OP_ARG:
val = regs_get_kernel_argument(regs, code->param);
break;
case FETCH_OP_ST_EDATA:
*(unsigned long *)((unsigned long)edata + code->offset) = val;
break;
case FETCH_OP_END:
goto end;
default:
break;
}
}
end:
return;
}
NOKPROBE_SYMBOL(store_trace_entry_data)
#endif
#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
/* Parse $vars. @orig_arg points '$', which syncs to @ctx->offset */ /* Parse $vars. @orig_arg points '$', which syncs to @ctx->offset */
@ -834,7 +946,7 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t,
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
len = str_has_prefix(arg, "arg"); len = str_has_prefix(arg, "arg");
if (len && tparg_is_function_entry(ctx->flags)) { if (len) {
ret = kstrtoul(arg + len, 10, &param); ret = kstrtoul(arg + len, 10, &param);
if (ret) if (ret)
goto inval; goto inval;
@ -843,15 +955,29 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t,
err = TP_ERR_BAD_ARG_NUM; err = TP_ERR_BAD_ARG_NUM;
goto inval; goto inval;
} }
param--; /* argN starts from 1, but internal arg[N] starts from 0 */
code->op = FETCH_OP_ARG; if (tparg_is_function_entry(ctx->flags)) {
code->param = (unsigned int)param - 1; code->op = FETCH_OP_ARG;
/* code->param = (unsigned int)param;
* The tracepoint probe will probe a stub function, and the /*
* first parameter of the stub is a dummy and should be ignored. * The tracepoint probe will probe a stub function, and the
*/ * first parameter of the stub is a dummy and should be ignored.
if (ctx->flags & TPARG_FL_TPOINT) */
code->param++; if (ctx->flags & TPARG_FL_TPOINT)
code->param++;
} else if (tparg_is_function_return(ctx->flags)) {
/* function entry argument access from return probe */
ret = __store_entry_arg(ctx->tp, param);
if (ret < 0) /* This error should be an internal error */
return ret;
code->op = FETCH_OP_EDATA;
code->offset = ret;
} else {
err = TP_ERR_NOFENTRY_ARGS;
goto inval;
}
return 0; return 0;
} }
#endif #endif
@ -1041,7 +1167,8 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
break; break;
default: default:
if (isalpha(arg[0]) || arg[0] == '_') { /* BTF variable */ if (isalpha(arg[0]) || arg[0] == '_') { /* BTF variable */
if (!tparg_is_function_entry(ctx->flags)) { if (!tparg_is_function_entry(ctx->flags) &&
!tparg_is_function_return(ctx->flags)) {
trace_probe_log_err(ctx->offset, NOSUP_BTFARG); trace_probe_log_err(ctx->offset, NOSUP_BTFARG);
return -EINVAL; return -EINVAL;
} }
@ -1383,9 +1510,7 @@ int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, const char *arg,
struct probe_arg *parg = &tp->args[i]; struct probe_arg *parg = &tp->args[i];
const char *body; const char *body;
/* Increment count for freeing args in error case */ ctx->tp = tp;
tp->nr_args++;
body = strchr(arg, '='); body = strchr(arg, '=');
if (body) { if (body) {
if (body - arg > MAX_ARG_NAME_LEN) { if (body - arg > MAX_ARG_NAME_LEN) {
@ -1442,7 +1567,8 @@ static int argv_has_var_arg(int argc, const char *argv[], int *args_idx,
if (str_has_prefix(argv[i], "$arg")) { if (str_has_prefix(argv[i], "$arg")) {
trace_probe_log_set_index(i + 2); trace_probe_log_set_index(i + 2);
if (!tparg_is_function_entry(ctx->flags)) { if (!tparg_is_function_entry(ctx->flags) &&
!tparg_is_function_return(ctx->flags)) {
trace_probe_log_err(0, NOFENTRY_ARGS); trace_probe_log_err(0, NOFENTRY_ARGS);
return -EINVAL; return -EINVAL;
} }
@ -1765,12 +1891,18 @@ void trace_probe_cleanup(struct trace_probe *tp)
for (i = 0; i < tp->nr_args; i++) for (i = 0; i < tp->nr_args; i++)
traceprobe_free_probe_arg(&tp->args[i]); traceprobe_free_probe_arg(&tp->args[i]);
if (tp->entry_arg) {
kfree(tp->entry_arg->code);
kfree(tp->entry_arg);
tp->entry_arg = NULL;
}
if (tp->event) if (tp->event)
trace_probe_unlink(tp); trace_probe_unlink(tp);
} }
int trace_probe_init(struct trace_probe *tp, const char *event, int trace_probe_init(struct trace_probe *tp, const char *event,
const char *group, bool alloc_filter) const char *group, bool alloc_filter, int nargs)
{ {
struct trace_event_call *call; struct trace_event_call *call;
size_t size = sizeof(struct trace_probe_event); size_t size = sizeof(struct trace_probe_event);
@ -1806,6 +1938,11 @@ int trace_probe_init(struct trace_probe *tp, const char *event,
goto error; goto error;
} }
tp->nr_args = nargs;
/* Make sure pointers in args[] are NULL */
if (nargs)
memset(tp->args, 0, sizeof(tp->args[0]) * nargs);
return 0; return 0;
error: error:

View File

@ -92,6 +92,7 @@ enum fetch_op {
FETCH_OP_ARG, /* Function argument : .param */ FETCH_OP_ARG, /* Function argument : .param */
FETCH_OP_FOFFS, /* File offset: .immediate */ FETCH_OP_FOFFS, /* File offset: .immediate */
FETCH_OP_DATA, /* Allocated data: .data */ FETCH_OP_DATA, /* Allocated data: .data */
FETCH_OP_EDATA, /* Entry data: .offset */
// Stage 2 (dereference) op // Stage 2 (dereference) op
FETCH_OP_DEREF, /* Dereference: .offset */ FETCH_OP_DEREF, /* Dereference: .offset */
FETCH_OP_UDEREF, /* User-space Dereference: .offset */ FETCH_OP_UDEREF, /* User-space Dereference: .offset */
@ -102,6 +103,7 @@ enum fetch_op {
FETCH_OP_ST_STRING, /* String: .offset, .size */ FETCH_OP_ST_STRING, /* String: .offset, .size */
FETCH_OP_ST_USTRING, /* User String: .offset, .size */ FETCH_OP_ST_USTRING, /* User String: .offset, .size */
FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */ FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */
FETCH_OP_ST_EDATA, /* Store Entry Data: .offset */
// Stage 4 (modify) op // Stage 4 (modify) op
FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */ FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */
// Stage 5 (loop) op // Stage 5 (loop) op
@ -232,6 +234,11 @@ struct probe_arg {
const struct fetch_type *type; /* Type of this argument */ const struct fetch_type *type; /* Type of this argument */
}; };
struct probe_entry_arg {
struct fetch_insn *code;
unsigned int size; /* The entry data size */
};
struct trace_uprobe_filter { struct trace_uprobe_filter {
rwlock_t rwlock; rwlock_t rwlock;
int nr_systemwide; int nr_systemwide;
@ -253,6 +260,7 @@ struct trace_probe {
struct trace_probe_event *event; struct trace_probe_event *event;
ssize_t size; /* trace entry size */ ssize_t size; /* trace entry size */
unsigned int nr_args; unsigned int nr_args;
struct probe_entry_arg *entry_arg; /* This is only for return probe */
struct probe_arg args[]; struct probe_arg args[];
}; };
@ -338,7 +346,7 @@ static inline bool trace_probe_has_single_file(struct trace_probe *tp)
} }
int trace_probe_init(struct trace_probe *tp, const char *event, int trace_probe_init(struct trace_probe *tp, const char *event,
const char *group, bool alloc_filter); const char *group, bool alloc_filter, int nargs);
void trace_probe_cleanup(struct trace_probe *tp); void trace_probe_cleanup(struct trace_probe *tp);
int trace_probe_append(struct trace_probe *tp, struct trace_probe *to); int trace_probe_append(struct trace_probe *tp, struct trace_probe *to);
void trace_probe_unlink(struct trace_probe *tp); void trace_probe_unlink(struct trace_probe *tp);
@ -355,6 +363,18 @@ int trace_probe_create(const char *raw_command, int (*createfn)(int, const char
int trace_probe_print_args(struct trace_seq *s, struct probe_arg *args, int nr_args, int trace_probe_print_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
u8 *data, void *field); u8 *data, void *field);
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
int traceprobe_get_entry_data_size(struct trace_probe *tp);
/* This is a runtime function to store entry data */
void store_trace_entry_data(void *edata, struct trace_probe *tp, struct pt_regs *regs);
#else /* !CONFIG_HAVE_FUNCTION_ARG_ACCESS_API */
static inline int traceprobe_get_entry_data_size(struct trace_probe *tp)
{
return 0;
}
#define store_trace_entry_data(edata, tp, regs) do { } while (0)
#endif
#define trace_probe_for_each_link(pos, tp) \ #define trace_probe_for_each_link(pos, tp) \
list_for_each_entry(pos, &(tp)->event->files, list) list_for_each_entry(pos, &(tp)->event->files, list)
#define trace_probe_for_each_link_rcu(pos, tp) \ #define trace_probe_for_each_link_rcu(pos, tp) \
@ -381,6 +401,11 @@ static inline bool tparg_is_function_entry(unsigned int flags)
return (flags & TPARG_FL_LOC_MASK) == (TPARG_FL_KERNEL | TPARG_FL_FENTRY); return (flags & TPARG_FL_LOC_MASK) == (TPARG_FL_KERNEL | TPARG_FL_FENTRY);
} }
static inline bool tparg_is_function_return(unsigned int flags)
{
return (flags & TPARG_FL_LOC_MASK) == (TPARG_FL_KERNEL | TPARG_FL_RETURN);
}
struct traceprobe_parse_context { struct traceprobe_parse_context {
struct trace_event_call *event; struct trace_event_call *event;
/* BTF related parameters */ /* BTF related parameters */
@ -392,6 +417,7 @@ struct traceprobe_parse_context {
const struct btf_type *last_type; /* Saved type */ const struct btf_type *last_type; /* Saved type */
u32 last_bitoffs; /* Saved bitoffs */ u32 last_bitoffs; /* Saved bitoffs */
u32 last_bitsize; /* Saved bitsize */ u32 last_bitsize; /* Saved bitsize */
struct trace_probe *tp;
unsigned int flags; unsigned int flags;
int offset; int offset;
}; };
@ -506,7 +532,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
C(NO_BTFARG, "This variable is not found at this probe point"),\ C(NO_BTFARG, "This variable is not found at this probe point"),\
C(NO_BTF_ENTRY, "No BTF entry for this probe point"), \ C(NO_BTF_ENTRY, "No BTF entry for this probe point"), \
C(BAD_VAR_ARGS, "$arg* must be an independent parameter without name etc."),\ C(BAD_VAR_ARGS, "$arg* must be an independent parameter without name etc."),\
C(NOFENTRY_ARGS, "$arg* can be used only on function entry"), \ C(NOFENTRY_ARGS, "$arg* can be used only on function entry or exit"), \
C(DOUBLE_ARGS, "$arg* can be used only once in the parameters"), \ C(DOUBLE_ARGS, "$arg* can be used only once in the parameters"), \
C(ARGS_2LONG, "$arg* failed because the argument list is too long"), \ C(ARGS_2LONG, "$arg* failed because the argument list is too long"), \
C(ARGIDX_2BIG, "$argN index is too big"), \ C(ARGIDX_2BIG, "$argN index is too big"), \

View File

@ -54,7 +54,7 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
* If dest is NULL, don't store result and return required dynamic data size. * If dest is NULL, don't store result and return required dynamic data size.
*/ */
static int static int
process_fetch_insn(struct fetch_insn *code, void *rec, process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
void *dest, void *base); void *dest, void *base);
static nokprobe_inline int fetch_store_strlen(unsigned long addr); static nokprobe_inline int fetch_store_strlen(unsigned long addr);
static nokprobe_inline int static nokprobe_inline int
@ -232,7 +232,7 @@ array:
/* Sum up total data length for dynamic arrays (strings) */ /* Sum up total data length for dynamic arrays (strings) */
static nokprobe_inline int static nokprobe_inline int
__get_data_size(struct trace_probe *tp, struct pt_regs *regs) __get_data_size(struct trace_probe *tp, struct pt_regs *regs, void *edata)
{ {
struct probe_arg *arg; struct probe_arg *arg;
int i, len, ret = 0; int i, len, ret = 0;
@ -240,7 +240,7 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
for (i = 0; i < tp->nr_args; i++) { for (i = 0; i < tp->nr_args; i++) {
arg = tp->args + i; arg = tp->args + i;
if (unlikely(arg->dynamic)) { if (unlikely(arg->dynamic)) {
len = process_fetch_insn(arg->code, regs, NULL, NULL); len = process_fetch_insn(arg->code, regs, edata, NULL, NULL);
if (len > 0) if (len > 0)
ret += len; ret += len;
} }
@ -251,7 +251,7 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
/* Store the value of each argument */ /* Store the value of each argument */
static nokprobe_inline void static nokprobe_inline void
store_trace_args(void *data, struct trace_probe *tp, void *rec, store_trace_args(void *data, struct trace_probe *tp, void *rec, void *edata,
int header_size, int maxlen) int header_size, int maxlen)
{ {
struct probe_arg *arg; struct probe_arg *arg;
@ -266,7 +266,7 @@ store_trace_args(void *data, struct trace_probe *tp, void *rec,
/* Point the dynamic data area if needed */ /* Point the dynamic data area if needed */
if (unlikely(arg->dynamic)) if (unlikely(arg->dynamic))
*dl = make_data_loc(maxlen, dyndata - base); *dl = make_data_loc(maxlen, dyndata - base);
ret = process_fetch_insn(arg->code, rec, dl, base); ret = process_fetch_insn(arg->code, rec, edata, dl, base);
if (arg->dynamic && likely(ret > 0)) { if (arg->dynamic && likely(ret > 0)) {
dyndata += ret; dyndata += ret;
maxlen -= ret; maxlen -= ret;

View File

@ -211,8 +211,8 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
/* Note that we don't verify it, since the code does not come from user space */ /* Note that we don't verify it, since the code does not come from user space */
static int static int
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest, process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
void *base) void *dest, void *base)
{ {
struct pt_regs *regs = rec; struct pt_regs *regs = rec;
unsigned long val; unsigned long val;
@ -337,7 +337,7 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
if (!tu) if (!tu)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ret = trace_probe_init(&tu->tp, event, group, true); ret = trace_probe_init(&tu->tp, event, group, true, nargs);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -556,6 +556,8 @@ static int __trace_uprobe_create(int argc, const char **argv)
if (argc < 2) if (argc < 2)
return -ECANCELED; return -ECANCELED;
if (argc - 2 > MAX_TRACE_ARGS)
return -E2BIG;
if (argv[0][1] == ':') if (argv[0][1] == ':')
event = &argv[0][2]; event = &argv[0][2];
@ -681,7 +683,7 @@ static int __trace_uprobe_create(int argc, const char **argv)
tu->filename = filename; tu->filename = filename;
/* parse arguments */ /* parse arguments */
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc; i++) {
struct traceprobe_parse_context ctx = { struct traceprobe_parse_context ctx = {
.flags = (is_return ? TPARG_FL_RETURN : 0) | TPARG_FL_USER, .flags = (is_return ? TPARG_FL_RETURN : 0) | TPARG_FL_USER,
}; };
@ -854,9 +856,11 @@ static const struct file_operations uprobe_profile_ops = {
struct uprobe_cpu_buffer { struct uprobe_cpu_buffer {
struct mutex mutex; struct mutex mutex;
void *buf; void *buf;
int dsize;
}; };
static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer; static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer;
static int uprobe_buffer_refcnt; static int uprobe_buffer_refcnt;
#define MAX_UCB_BUFFER_SIZE PAGE_SIZE
static int uprobe_buffer_init(void) static int uprobe_buffer_init(void)
{ {
@ -940,12 +944,41 @@ static struct uprobe_cpu_buffer *uprobe_buffer_get(void)
static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb) static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb)
{ {
if (!ucb)
return;
mutex_unlock(&ucb->mutex); mutex_unlock(&ucb->mutex);
} }
static struct uprobe_cpu_buffer *prepare_uprobe_buffer(struct trace_uprobe *tu,
struct pt_regs *regs,
struct uprobe_cpu_buffer **ucbp)
{
struct uprobe_cpu_buffer *ucb;
int dsize, esize;
if (*ucbp)
return *ucbp;
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
dsize = __get_data_size(&tu->tp, regs, NULL);
ucb = uprobe_buffer_get();
ucb->dsize = tu->tp.size + dsize;
if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) {
ucb->dsize = MAX_UCB_BUFFER_SIZE;
dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size;
}
store_trace_args(ucb->buf, &tu->tp, regs, NULL, esize, dsize);
*ucbp = ucb;
return ucb;
}
static void __uprobe_trace_func(struct trace_uprobe *tu, static void __uprobe_trace_func(struct trace_uprobe *tu,
unsigned long func, struct pt_regs *regs, unsigned long func, struct pt_regs *regs,
struct uprobe_cpu_buffer *ucb, int dsize, struct uprobe_cpu_buffer *ucb,
struct trace_event_file *trace_file) struct trace_event_file *trace_file)
{ {
struct uprobe_trace_entry_head *entry; struct uprobe_trace_entry_head *entry;
@ -956,14 +989,11 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
WARN_ON(call != trace_file->event_call); WARN_ON(call != trace_file->event_call);
if (WARN_ON_ONCE(tu->tp.size + dsize > PAGE_SIZE))
return;
if (trace_trigger_soft_disabled(trace_file)) if (trace_trigger_soft_disabled(trace_file))
return; return;
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
size = esize + tu->tp.size + dsize; size = esize + ucb->dsize;
entry = trace_event_buffer_reserve(&fbuffer, trace_file, size); entry = trace_event_buffer_reserve(&fbuffer, trace_file, size);
if (!entry) if (!entry)
return; return;
@ -977,23 +1007,26 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
data = DATAOF_TRACE_ENTRY(entry, false); data = DATAOF_TRACE_ENTRY(entry, false);
} }
memcpy(data, ucb->buf, tu->tp.size + dsize); memcpy(data, ucb->buf, ucb->dsize);
trace_event_buffer_commit(&fbuffer); trace_event_buffer_commit(&fbuffer);
} }
/* uprobe handler */ /* uprobe handler */
static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs, static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
struct uprobe_cpu_buffer *ucb, int dsize) struct uprobe_cpu_buffer **ucbp)
{ {
struct event_file_link *link; struct event_file_link *link;
struct uprobe_cpu_buffer *ucb;
if (is_ret_probe(tu)) if (is_ret_probe(tu))
return 0; return 0;
ucb = prepare_uprobe_buffer(tu, regs, ucbp);
rcu_read_lock(); rcu_read_lock();
trace_probe_for_each_link_rcu(link, &tu->tp) trace_probe_for_each_link_rcu(link, &tu->tp)
__uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file); __uprobe_trace_func(tu, 0, regs, ucb, link->file);
rcu_read_unlock(); rcu_read_unlock();
return 0; return 0;
@ -1001,13 +1034,16 @@ static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func, static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
struct pt_regs *regs, struct pt_regs *regs,
struct uprobe_cpu_buffer *ucb, int dsize) struct uprobe_cpu_buffer **ucbp)
{ {
struct event_file_link *link; struct event_file_link *link;
struct uprobe_cpu_buffer *ucb;
ucb = prepare_uprobe_buffer(tu, regs, ucbp);
rcu_read_lock(); rcu_read_lock();
trace_probe_for_each_link_rcu(link, &tu->tp) trace_probe_for_each_link_rcu(link, &tu->tp)
__uprobe_trace_func(tu, func, regs, ucb, dsize, link->file); __uprobe_trace_func(tu, func, regs, ucb, link->file);
rcu_read_unlock(); rcu_read_unlock();
} }
@ -1335,10 +1371,11 @@ static bool uprobe_perf_filter(struct uprobe_consumer *uc,
static void __uprobe_perf_func(struct trace_uprobe *tu, static void __uprobe_perf_func(struct trace_uprobe *tu,
unsigned long func, struct pt_regs *regs, unsigned long func, struct pt_regs *regs,
struct uprobe_cpu_buffer *ucb, int dsize) struct uprobe_cpu_buffer **ucbp)
{ {
struct trace_event_call *call = trace_probe_event_call(&tu->tp); struct trace_event_call *call = trace_probe_event_call(&tu->tp);
struct uprobe_trace_entry_head *entry; struct uprobe_trace_entry_head *entry;
struct uprobe_cpu_buffer *ucb;
struct hlist_head *head; struct hlist_head *head;
void *data; void *data;
int size, esize; int size, esize;
@ -1356,7 +1393,8 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
size = esize + tu->tp.size + dsize; ucb = prepare_uprobe_buffer(tu, regs, ucbp);
size = esize + ucb->dsize;
size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32); size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32);
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
return; return;
@ -1379,13 +1417,10 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
data = DATAOF_TRACE_ENTRY(entry, false); data = DATAOF_TRACE_ENTRY(entry, false);
} }
memcpy(data, ucb->buf, tu->tp.size + dsize); memcpy(data, ucb->buf, ucb->dsize);
if (size - esize > tu->tp.size + dsize) { if (size - esize > ucb->dsize)
int len = tu->tp.size + dsize; memset(data + ucb->dsize, 0, size - esize - ucb->dsize);
memset(data + len, 0, size - esize - len);
}
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
head, NULL); head, NULL);
@ -1395,21 +1430,21 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
/* uprobe profile handler */ /* uprobe profile handler */
static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs, static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs,
struct uprobe_cpu_buffer *ucb, int dsize) struct uprobe_cpu_buffer **ucbp)
{ {
if (!uprobe_perf_filter(&tu->consumer, 0, current->mm)) if (!uprobe_perf_filter(&tu->consumer, 0, current->mm))
return UPROBE_HANDLER_REMOVE; return UPROBE_HANDLER_REMOVE;
if (!is_ret_probe(tu)) if (!is_ret_probe(tu))
__uprobe_perf_func(tu, 0, regs, ucb, dsize); __uprobe_perf_func(tu, 0, regs, ucbp);
return 0; return 0;
} }
static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func, static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func,
struct pt_regs *regs, struct pt_regs *regs,
struct uprobe_cpu_buffer *ucb, int dsize) struct uprobe_cpu_buffer **ucbp)
{ {
__uprobe_perf_func(tu, func, regs, ucb, dsize); __uprobe_perf_func(tu, func, regs, ucbp);
} }
int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type, int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type,
@ -1474,11 +1509,9 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
{ {
struct trace_uprobe *tu; struct trace_uprobe *tu;
struct uprobe_dispatch_data udd; struct uprobe_dispatch_data udd;
struct uprobe_cpu_buffer *ucb; struct uprobe_cpu_buffer *ucb = NULL;
int dsize, esize;
int ret = 0; int ret = 0;
tu = container_of(con, struct trace_uprobe, consumer); tu = container_of(con, struct trace_uprobe, consumer);
tu->nhit++; tu->nhit++;
@ -1490,18 +1523,12 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
if (WARN_ON_ONCE(!uprobe_cpu_buffer)) if (WARN_ON_ONCE(!uprobe_cpu_buffer))
return 0; return 0;
dsize = __get_data_size(&tu->tp, regs);
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
ucb = uprobe_buffer_get();
store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE)) if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
ret |= uprobe_trace_func(tu, regs, ucb, dsize); ret |= uprobe_trace_func(tu, regs, &ucb);
#ifdef CONFIG_PERF_EVENTS #ifdef CONFIG_PERF_EVENTS
if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE)) if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
ret |= uprobe_perf_func(tu, regs, ucb, dsize); ret |= uprobe_perf_func(tu, regs, &ucb);
#endif #endif
uprobe_buffer_put(ucb); uprobe_buffer_put(ucb);
return ret; return ret;
@ -1512,8 +1539,7 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
{ {
struct trace_uprobe *tu; struct trace_uprobe *tu;
struct uprobe_dispatch_data udd; struct uprobe_dispatch_data udd;
struct uprobe_cpu_buffer *ucb; struct uprobe_cpu_buffer *ucb = NULL;
int dsize, esize;
tu = container_of(con, struct trace_uprobe, consumer); tu = container_of(con, struct trace_uprobe, consumer);
@ -1525,18 +1551,12 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
if (WARN_ON_ONCE(!uprobe_cpu_buffer)) if (WARN_ON_ONCE(!uprobe_cpu_buffer))
return 0; return 0;
dsize = __get_data_size(&tu->tp, regs);
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
ucb = uprobe_buffer_get();
store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE)) if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
uretprobe_trace_func(tu, func, regs, ucb, dsize); uretprobe_trace_func(tu, func, regs, &ucb);
#ifdef CONFIG_PERF_EVENTS #ifdef CONFIG_PERF_EVENTS
if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE)) if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
uretprobe_perf_func(tu, func, regs, ucb, dsize); uretprobe_perf_func(tu, func, regs, &ucb);
#endif #endif
uprobe_buffer_put(ucb); uprobe_buffer_put(ucb);
return 0; return 0;

View File

@ -17,47 +17,43 @@
#include <net/ip.h> #include <net/ip.h>
#include <net/l3mdev.h> #include <net/l3mdev.h>
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, static struct dst_entry *__xfrm4_dst_lookup(struct flowi4 *fl4,
int tos, int oif, const struct xfrm_dst_lookup_params *params)
const xfrm_address_t *saddr,
const xfrm_address_t *daddr,
u32 mark)
{ {
struct rtable *rt; struct rtable *rt;
memset(fl4, 0, sizeof(*fl4)); memset(fl4, 0, sizeof(*fl4));
fl4->daddr = daddr->a4; fl4->daddr = params->daddr->a4;
fl4->flowi4_tos = tos; fl4->flowi4_tos = params->tos;
fl4->flowi4_l3mdev = l3mdev_master_ifindex_by_index(net, oif); fl4->flowi4_l3mdev = l3mdev_master_ifindex_by_index(params->net,
fl4->flowi4_mark = mark; params->oif);
if (saddr) fl4->flowi4_mark = params->mark;
fl4->saddr = saddr->a4; if (params->saddr)
fl4->saddr = params->saddr->a4;
fl4->flowi4_proto = params->ipproto;
fl4->uli = params->uli;
rt = __ip_route_output_key(net, fl4); rt = __ip_route_output_key(params->net, fl4);
if (!IS_ERR(rt)) if (!IS_ERR(rt))
return &rt->dst; return &rt->dst;
return ERR_CAST(rt); return ERR_CAST(rt);
} }
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif, static struct dst_entry *xfrm4_dst_lookup(const struct xfrm_dst_lookup_params *params)
const xfrm_address_t *saddr,
const xfrm_address_t *daddr,
u32 mark)
{ {
struct flowi4 fl4; struct flowi4 fl4;
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark); return __xfrm4_dst_lookup(&fl4, params);
} }
static int xfrm4_get_saddr(struct net *net, int oif, static int xfrm4_get_saddr(xfrm_address_t *saddr,
xfrm_address_t *saddr, xfrm_address_t *daddr, const struct xfrm_dst_lookup_params *params)
u32 mark)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct flowi4 fl4; struct flowi4 fl4;
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark); dst = __xfrm4_dst_lookup(&fl4, params);
if (IS_ERR(dst)) if (IS_ERR(dst))
return -EHOSTUNREACH; return -EHOSTUNREACH;

View File

@ -23,23 +23,24 @@
#include <net/ip6_route.h> #include <net/ip6_route.h>
#include <net/l3mdev.h> #include <net/l3mdev.h>
static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, static struct dst_entry *xfrm6_dst_lookup(const struct xfrm_dst_lookup_params *params)
const xfrm_address_t *saddr,
const xfrm_address_t *daddr,
u32 mark)
{ {
struct flowi6 fl6; struct flowi6 fl6;
struct dst_entry *dst; struct dst_entry *dst;
int err; int err;
memset(&fl6, 0, sizeof(fl6)); memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_l3mdev = l3mdev_master_ifindex_by_index(net, oif); fl6.flowi6_l3mdev = l3mdev_master_ifindex_by_index(params->net,
fl6.flowi6_mark = mark; params->oif);
memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr)); fl6.flowi6_mark = params->mark;
if (saddr) memcpy(&fl6.daddr, params->daddr, sizeof(fl6.daddr));
memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr)); if (params->saddr)
memcpy(&fl6.saddr, params->saddr, sizeof(fl6.saddr));
dst = ip6_route_output(net, NULL, &fl6); fl6.flowi4_proto = params->ipproto;
fl6.uli = params->uli;
dst = ip6_route_output(params->net, NULL, &fl6);
err = dst->error; err = dst->error;
if (dst->error) { if (dst->error) {
@ -50,15 +51,14 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
return dst; return dst;
} }
static int xfrm6_get_saddr(struct net *net, int oif, static int xfrm6_get_saddr(xfrm_address_t *saddr,
xfrm_address_t *saddr, xfrm_address_t *daddr, const struct xfrm_dst_lookup_params *params)
u32 mark)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct net_device *dev; struct net_device *dev;
struct inet6_dev *idev; struct inet6_dev *idev;
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark); dst = xfrm6_dst_lookup(params);
if (IS_ERR(dst)) if (IS_ERR(dst))
return -EHOSTUNREACH; return -EHOSTUNREACH;
@ -68,7 +68,8 @@ static int xfrm6_get_saddr(struct net *net, int oif,
return -EHOSTUNREACH; return -EHOSTUNREACH;
} }
dev = idev->dev; dev = idev->dev;
ipv6_dev_get_saddr(dev_net(dev), dev, &daddr->in6, 0, &saddr->in6); ipv6_dev_get_saddr(dev_net(dev), dev, &params->daddr->in6, 0,
&saddr->in6);
dst_release(dst); dst_release(dst);
return 0; return 0;
} }

View File

@ -23,6 +23,7 @@ static unsigned int nf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb,
struct bpf_nf_link { struct bpf_nf_link {
struct bpf_link link; struct bpf_link link;
struct nf_hook_ops hook_ops; struct nf_hook_ops hook_ops;
netns_tracker ns_tracker;
struct net *net; struct net *net;
u32 dead; u32 dead;
const struct nf_defrag_hook *defrag_hook; const struct nf_defrag_hook *defrag_hook;
@ -120,6 +121,7 @@ static void bpf_nf_link_release(struct bpf_link *link)
if (!cmpxchg(&nf_link->dead, 0, 1)) { if (!cmpxchg(&nf_link->dead, 0, 1)) {
nf_unregister_net_hook(nf_link->net, &nf_link->hook_ops); nf_unregister_net_hook(nf_link->net, &nf_link->hook_ops);
bpf_nf_disable_defrag(nf_link); bpf_nf_disable_defrag(nf_link);
put_net_track(nf_link->net, &nf_link->ns_tracker);
} }
} }
@ -258,6 +260,8 @@ int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
return err; return err;
} }
get_net_track(net, &link->ns_tracker, GFP_KERNEL);
return bpf_link_settle(&link_primer); return bpf_link_settle(&link_primer);
} }

View File

@ -505,19 +505,28 @@ static void dev_watchdog(struct timer_list *t)
unsigned int timedout_ms = 0; unsigned int timedout_ms = 0;
unsigned int i; unsigned int i;
unsigned long trans_start; unsigned long trans_start;
unsigned long oldest_start = jiffies;
for (i = 0; i < dev->num_tx_queues; i++) { for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq; struct netdev_queue *txq;
txq = netdev_get_tx_queue(dev, i); txq = netdev_get_tx_queue(dev, i);
if (!netif_xmit_stopped(txq))
continue;
/* Paired with WRITE_ONCE() + smp_mb...() in
* netdev_tx_sent_queue() and netif_tx_stop_queue().
*/
smp_mb();
trans_start = READ_ONCE(txq->trans_start); trans_start = READ_ONCE(txq->trans_start);
if (netif_xmit_stopped(txq) &&
time_after(jiffies, (trans_start + if (time_after(jiffies, trans_start + dev->watchdog_timeo)) {
dev->watchdog_timeo))) {
timedout_ms = jiffies_to_msecs(jiffies - trans_start); timedout_ms = jiffies_to_msecs(jiffies - trans_start);
atomic_long_inc(&txq->trans_timeout); atomic_long_inc(&txq->trans_timeout);
break; break;
} }
if (time_after(oldest_start, trans_start))
oldest_start = trans_start;
} }
if (unlikely(timedout_ms)) { if (unlikely(timedout_ms)) {
@ -530,7 +539,7 @@ static void dev_watchdog(struct timer_list *t)
netif_unfreeze_queues(dev); netif_unfreeze_queues(dev);
} }
if (!mod_timer(&dev->watchdog_timer, if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies + round_jiffies(oldest_start +
dev->watchdog_timeo))) dev->watchdog_timeo)))
release = false; release = false;
} }

View File

@ -263,6 +263,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
dev = dev_get_by_index(net, xuo->ifindex); dev = dev_get_by_index(net, xuo->ifindex);
if (!dev) { if (!dev) {
struct xfrm_dst_lookup_params params;
if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) { if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
saddr = &x->props.saddr; saddr = &x->props.saddr;
daddr = &x->id.daddr; daddr = &x->id.daddr;
@ -271,9 +273,12 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
daddr = &x->props.saddr; daddr = &x->props.saddr;
} }
dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, memset(&params, 0, sizeof(params));
x->props.family, params.net = net;
xfrm_smark_get(0, x)); params.saddr = saddr;
params.daddr = daddr;
params.mark = xfrm_smark_get(0, x);
dst = __xfrm_dst_lookup(x->props.family, &params);
if (IS_ERR(dst)) if (IS_ERR(dst))
return (is_packet_offload) ? -EINVAL : 0; return (is_packet_offload) ? -EINVAL : 0;

View File

@ -251,10 +251,8 @@ static const struct xfrm_if_cb *xfrm_if_get_cb(void)
return rcu_dereference(xfrm_if_cb); return rcu_dereference(xfrm_if_cb);
} }
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, struct dst_entry *__xfrm_dst_lookup(int family,
const xfrm_address_t *saddr, const struct xfrm_dst_lookup_params *params)
const xfrm_address_t *daddr,
int family, u32 mark)
{ {
const struct xfrm_policy_afinfo *afinfo; const struct xfrm_policy_afinfo *afinfo;
struct dst_entry *dst; struct dst_entry *dst;
@ -263,7 +261,7 @@ struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return ERR_PTR(-EAFNOSUPPORT); return ERR_PTR(-EAFNOSUPPORT);
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark); dst = afinfo->dst_lookup(params);
rcu_read_unlock(); rcu_read_unlock();
@ -277,6 +275,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
xfrm_address_t *prev_daddr, xfrm_address_t *prev_daddr,
int family, u32 mark) int family, u32 mark)
{ {
struct xfrm_dst_lookup_params params;
struct net *net = xs_net(x); struct net *net = xs_net(x);
xfrm_address_t *saddr = &x->props.saddr; xfrm_address_t *saddr = &x->props.saddr;
xfrm_address_t *daddr = &x->id.daddr; xfrm_address_t *daddr = &x->id.daddr;
@ -291,7 +290,29 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
daddr = x->coaddr; daddr = x->coaddr;
} }
dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark); params.net = net;
params.saddr = saddr;
params.daddr = daddr;
params.tos = tos;
params.oif = oif;
params.mark = mark;
params.ipproto = x->id.proto;
if (x->encap) {
switch (x->encap->encap_type) {
case UDP_ENCAP_ESPINUDP:
params.ipproto = IPPROTO_UDP;
params.uli.ports.sport = x->encap->encap_sport;
params.uli.ports.dport = x->encap->encap_dport;
break;
case TCP_ENCAP_ESPINTCP:
params.ipproto = IPPROTO_TCP;
params.uli.ports.sport = x->encap->encap_sport;
params.uli.ports.dport = x->encap->encap_dport;
break;
}
}
dst = __xfrm_dst_lookup(family, &params);
if (!IS_ERR(dst)) { if (!IS_ERR(dst)) {
if (prev_saddr != saddr) if (prev_saddr != saddr)
@ -2424,15 +2445,15 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
} }
static int static int
xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local, xfrm_get_saddr(unsigned short family, xfrm_address_t *saddr,
xfrm_address_t *remote, unsigned short family, u32 mark) const struct xfrm_dst_lookup_params *params)
{ {
int err; int err;
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return -EINVAL; return -EINVAL;
err = afinfo->get_saddr(net, oif, local, remote, mark); err = afinfo->get_saddr(saddr, params);
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
@ -2461,9 +2482,14 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
remote = &tmpl->id.daddr; remote = &tmpl->id.daddr;
local = &tmpl->saddr; local = &tmpl->saddr;
if (xfrm_addr_any(local, tmpl->encap_family)) { if (xfrm_addr_any(local, tmpl->encap_family)) {
error = xfrm_get_saddr(net, fl->flowi_oif, struct xfrm_dst_lookup_params params;
&tmp, remote,
tmpl->encap_family, 0); memset(&params, 0, sizeof(params));
params.net = net;
params.oif = fl->flowi_oif;
params.daddr = remote;
error = xfrm_get_saddr(tmpl->encap_family, &tmp,
&params);
if (error) if (error)
goto fail; goto fail;
local = &tmp; local = &tmp;

View File

@ -444,6 +444,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "8A3E"), DMI_MATCH(DMI_BOARD_NAME, "8A3E"),
} }
}, },
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8A7F"),
}
},
{ {
.driver_data = &acp6x_card, .driver_data = &acp6x_card,
.matches = { .matches = {

View File

@ -909,7 +909,7 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_BCL_VBAT_PK_EST2, 0x01 }, { CDC_RX_BCL_VBAT_PK_EST2, 0x01 },
{ CDC_RX_BCL_VBAT_PK_EST3, 0x40 }, { CDC_RX_BCL_VBAT_PK_EST3, 0x40 },
{ CDC_RX_BCL_VBAT_RF_PROC1, 0x2A }, { CDC_RX_BCL_VBAT_RF_PROC1, 0x2A },
{ CDC_RX_BCL_VBAT_RF_PROC1, 0x00 }, { CDC_RX_BCL_VBAT_RF_PROC2, 0x00 },
{ CDC_RX_BCL_VBAT_TAC1, 0x00 }, { CDC_RX_BCL_VBAT_TAC1, 0x00 },
{ CDC_RX_BCL_VBAT_TAC2, 0x18 }, { CDC_RX_BCL_VBAT_TAC2, 0x18 },
{ CDC_RX_BCL_VBAT_TAC3, 0x18 }, { CDC_RX_BCL_VBAT_TAC3, 0x18 },

View File

@ -604,6 +604,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr4 |= FSL_SAI_CR4_FRSZ(slots); val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
/* Set to avoid channel swap */
val_cr4 |= FSL_SAI_CR4_FCONT;
/* Set to output mode to avoid tri-stated data pins */ /* Set to output mode to avoid tri-stated data pins */
if (tx) if (tx)
val_cr4 |= FSL_SAI_CR4_CHMOD; val_cr4 |= FSL_SAI_CR4_CHMOD;
@ -690,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
FSL_SAI_CR4_CHMOD_MASK, FSL_SAI_CR4_CHMOD_MASK | FSL_SAI_CR4_FCONT_MASK,
val_cr4); val_cr4);
regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |

View File

@ -137,6 +137,7 @@
/* SAI Transmit and Receive Configuration 4 Register */ /* SAI Transmit and Receive Configuration 4 Register */
#define FSL_SAI_CR4_FCONT_MASK BIT(28)
#define FSL_SAI_CR4_FCONT BIT(28) #define FSL_SAI_CR4_FCONT BIT(28)
#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26) #define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
#define FSL_SAI_CR4_FCOMB_SOFT BIT(27) #define FSL_SAI_CR4_FCOMB_SOFT BIT(27)

View File

@ -153,6 +153,7 @@ static int sm8250_platform_probe(struct platform_device *pdev)
static const struct of_device_id snd_sm8250_dt_match[] = { static const struct of_device_id snd_sm8250_dt_match[] = {
{.compatible = "qcom,sm8250-sndcard"}, {.compatible = "qcom,sm8250-sndcard"},
{.compatible = "qcom,qrb4210-rb2-sndcard"},
{.compatible = "qcom,qrb5165-rb5-sndcard"}, {.compatible = "qcom,qrb5165-rb5-sndcard"},
{} {}
}; };

View File

@ -34,7 +34,9 @@ check_error 'f vfs_read ^$stack10000' # BAD_STACK_NUM
check_error 'f vfs_read ^$arg10000' # BAD_ARG_NUM check_error 'f vfs_read ^$arg10000' # BAD_ARG_NUM
if !grep -q 'kernel return probes support:' README; then
check_error 'f vfs_read $retval ^$arg1' # BAD_VAR check_error 'f vfs_read $retval ^$arg1' # BAD_VAR
fi
check_error 'f vfs_read ^$none_var' # BAD_VAR check_error 'f vfs_read ^$none_var' # BAD_VAR
check_error 'f vfs_read ^'$REG # BAD_VAR check_error 'f vfs_read ^'$REG # BAD_VAR
@ -99,7 +101,9 @@ if grep -q "<argname>" README; then
check_error 'f vfs_read args=^$arg*' # BAD_VAR_ARGS check_error 'f vfs_read args=^$arg*' # BAD_VAR_ARGS
check_error 'f vfs_read +0(^$arg*)' # BAD_VAR_ARGS check_error 'f vfs_read +0(^$arg*)' # BAD_VAR_ARGS
check_error 'f vfs_read $arg* ^$arg*' # DOUBLE_ARGS check_error 'f vfs_read $arg* ^$arg*' # DOUBLE_ARGS
if !grep -q 'kernel return probes support:' README; then
check_error 'f vfs_read%return ^$arg*' # NOFENTRY_ARGS check_error 'f vfs_read%return ^$arg*' # NOFENTRY_ARGS
fi
check_error 'f vfs_read ^hoge' # NO_BTFARG check_error 'f vfs_read ^hoge' # NO_BTFARG
check_error 'f kfree ^$arg10' # NO_BTFARG (exceed the number of parameters) check_error 'f kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)
check_error 'f kfree%return ^$retval' # NO_RETVAL check_error 'f kfree%return ^$retval' # NO_RETVAL

View File

@ -108,7 +108,9 @@ if grep -q "<argname>" README; then
check_error 'p vfs_read args=^$arg*' # BAD_VAR_ARGS check_error 'p vfs_read args=^$arg*' # BAD_VAR_ARGS
check_error 'p vfs_read +0(^$arg*)' # BAD_VAR_ARGS check_error 'p vfs_read +0(^$arg*)' # BAD_VAR_ARGS
check_error 'p vfs_read $arg* ^$arg*' # DOUBLE_ARGS check_error 'p vfs_read $arg* ^$arg*' # DOUBLE_ARGS
if !grep -q 'kernel return probes support:' README; then
check_error 'r vfs_read ^$arg*' # NOFENTRY_ARGS check_error 'r vfs_read ^$arg*' # NOFENTRY_ARGS
fi
check_error 'p vfs_read+8 ^$arg*' # NOFENTRY_ARGS check_error 'p vfs_read+8 ^$arg*' # NOFENTRY_ARGS
check_error 'p vfs_read ^hoge' # NO_BTFARG check_error 'p vfs_read ^hoge' # NO_BTFARG
check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the number of parameters) check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)