mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-05 17:05:21 +02:00
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:
commit
c448d4e4c0
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# Copyright (C) 1995-2001 by Russell King
|
||||
|
||||
LDFLAGS_vmlinux :=--no-undefined -X
|
||||
LDFLAGS_vmlinux :=--no-undefined -X --pic-veneer
|
||||
|
||||
ifeq ($(CONFIG_RELOCATABLE), y)
|
||||
# Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour
|
||||
|
|
|
@ -293,13 +293,15 @@ unsigned long stack_top(void)
|
|||
{
|
||||
unsigned long top = TASK_SIZE & PAGE_MASK;
|
||||
|
||||
/* Space for the VDSO & data page */
|
||||
top -= PAGE_ALIGN(current->thread.vdso->size);
|
||||
top -= VVAR_SIZE;
|
||||
if (current->thread.vdso) {
|
||||
/* Space for the VDSO & data page */
|
||||
top -= PAGE_ALIGN(current->thread.vdso->size);
|
||||
top -= VVAR_SIZE;
|
||||
|
||||
/* Space to randomize the VDSO base */
|
||||
if (current->flags & PF_RANDOMIZE)
|
||||
top -= VDSO_RANDOMIZE_SIZE;
|
||||
/* Space to randomize the VDSO base */
|
||||
if (current->flags & PF_RANDOMIZE)
|
||||
top -= VDSO_RANDOMIZE_SIZE;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
|
|
@ -139,7 +139,15 @@ int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
|
|||
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);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -351,10 +351,8 @@ struct vbva_mouse_pointer_shape {
|
|||
* 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_len = width * 4 * height.
|
||||
*
|
||||
* Preallocate 4 bytes for accessing actual data as p->data.
|
||||
*/
|
||||
u8 data[4];
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
/* pointer is visible */
|
||||
|
|
|
@ -1335,6 +1335,8 @@ config TI_LMP92064
|
|||
tristate "Texas Instruments LMP92064 ADC driver"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the LMP92064 Precision Current and Voltage
|
||||
sensor.
|
||||
|
|
|
@ -1713,6 +1713,7 @@ int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,
|
|||
ptr = shift / 8;
|
||||
shift %= 8;
|
||||
mask >>= ptr * 8;
|
||||
ptr <<= 8;
|
||||
|
||||
err = mv88e6393x_port_policy_read(chip, port, ptr, ®);
|
||||
if (err)
|
||||
|
|
|
@ -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);
|
||||
|
||||
wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
|
||||
if (unlikely(!wrb_cnt)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(!wrb_cnt))
|
||||
goto drop_skb;
|
||||
|
||||
/* if os2bmc is enabled and if the pkt is destined to bmc,
|
||||
* 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);
|
||||
wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
|
||||
if (unlikely(!wrb_cnt))
|
||||
goto drop;
|
||||
goto drop_skb;
|
||||
else
|
||||
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);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
drop_skb:
|
||||
dev_kfree_skb_any(skb);
|
||||
drop:
|
||||
tx_stats(txo)->tx_drv_drops++;
|
||||
/* Flush the already enqueued tx requests */
|
||||
|
|
|
@ -197,55 +197,67 @@ static int mac_probe(struct platform_device *_of_dev)
|
|||
err = -EINVAL;
|
||||
goto _return_of_node_put;
|
||||
}
|
||||
mac_dev->fman_dev = &of_dev->dev;
|
||||
|
||||
/* Get the FMan cell-index */
|
||||
err = of_property_read_u32(dev_node, "cell-index", &val);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
|
||||
err = -EINVAL;
|
||||
goto _return_of_node_put;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
/* cell-index 0 => FMan id 1 */
|
||||
fman_id = (u8)(val + 1);
|
||||
|
||||
priv->fman = fman_bind(&of_dev->dev);
|
||||
priv->fman = fman_bind(mac_dev->fman_dev);
|
||||
if (!priv->fman) {
|
||||
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
|
||||
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);
|
||||
dev_node = NULL;
|
||||
|
||||
/* Get the address of the memory mapped registers */
|
||||
mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
|
||||
if (!mac_dev->res) {
|
||||
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),
|
||||
mac_dev->res);
|
||||
if (err) {
|
||||
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,
|
||||
resource_size(mac_dev->res));
|
||||
if (!mac_dev->vaddr) {
|
||||
dev_err(dev, "devm_ioremap() failed\n");
|
||||
return -EIO;
|
||||
err = -EIO;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(mac_node))
|
||||
return -ENODEV;
|
||||
if (!of_device_is_available(mac_node)) {
|
||||
err = -ENODEV;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
/* Get the cell-index */
|
||||
err = of_property_read_u32(mac_node, "cell-index", &val);
|
||||
if (err) {
|
||||
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;
|
||||
|
||||
|
@ -259,22 +271,26 @@ static int mac_probe(struct platform_device *_of_dev)
|
|||
if (unlikely(nph < 0)) {
|
||||
dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
|
||||
mac_node);
|
||||
return nph;
|
||||
err = nph;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
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",
|
||||
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 */
|
||||
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
|
||||
if (!dev_node) {
|
||||
dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
|
||||
mac_node);
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto _return_dev_arr_put;
|
||||
}
|
||||
|
||||
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_node);
|
||||
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]) {
|
||||
dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
|
||||
dev_node);
|
||||
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);
|
||||
dev_node = NULL;
|
||||
}
|
||||
|
||||
/* Get the PHY connection type */
|
||||
|
@ -312,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
|
|||
|
||||
err = init(mac_dev, mac_node, ¶ms);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto _return_dev_arr_put;
|
||||
|
||||
if (!is_zero_ether_addr(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_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:
|
||||
of_node_put(dev_node);
|
||||
return err;
|
||||
|
@ -335,6 +364,11 @@ _return_of_node_put:
|
|||
static void mac_remove(struct platform_device *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);
|
||||
}
|
||||
|
|
|
@ -19,12 +19,13 @@
|
|||
struct fman_mac;
|
||||
struct mac_priv_s;
|
||||
|
||||
#define PORT_NUM 2
|
||||
struct mac_device {
|
||||
void __iomem *vaddr;
|
||||
struct device *dev;
|
||||
struct resource *res;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct fman_port *port[2];
|
||||
struct fman_port *port[PORT_NUM];
|
||||
struct phylink *phylink;
|
||||
struct phylink_config phylink_config;
|
||||
phy_interface_t phy_if;
|
||||
|
@ -52,6 +53,9 @@ struct mac_device {
|
|||
|
||||
struct fman_mac *fman_mac;
|
||||
struct mac_priv_s *priv;
|
||||
|
||||
struct device *fman_dev;
|
||||
struct device *fman_port_devs[PORT_NUM];
|
||||
};
|
||||
|
||||
static inline struct mac_device
|
||||
|
|
|
@ -1012,6 +1012,7 @@ sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
|
|||
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);
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -336,6 +336,51 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
|
|||
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.
|
||||
*
|
||||
|
@ -365,10 +410,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
|||
desc_used = 0;
|
||||
for (pkt = 0; pkt < pkts_to_process; pkt++) {
|
||||
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);
|
||||
buff_info->page = NULL;
|
||||
|
||||
/* Swap the length field that is in Big-Endian to CPU */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
} else {
|
||||
struct skb_shared_info *shinfo;
|
||||
u16 data_len;
|
||||
|
||||
skb = build_skb((void *)resp_hw, PAGE_SIZE);
|
||||
skb_reserve(skb, data_offset);
|
||||
/* Head fragment includes response header(s);
|
||||
* subsequent fragments contains only data.
|
||||
*/
|
||||
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);
|
||||
data_len = buff_info->len - oq->max_single_buffer_size;
|
||||
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 *)
|
||||
&oq->buff_info[read_idx];
|
||||
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->len,
|
||||
buff_info->len);
|
||||
buff_info->page = NULL;
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
|
||||
octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -815,7 +815,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
|
|||
return HS_TIMEOUT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
fallthrough;
|
||||
|
||||
case PLIP_PK_LENGTH_LSB:
|
||||
if (plip_send(nibble_timeout, dev,
|
||||
|
|
|
@ -1771,7 +1771,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
|
|||
// can rename the link if it knows better.
|
||||
if ((dev->driver_info->flags & FLAG_ETHER) != 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));
|
||||
/* WLAN devices should always be named "wlan%d" */
|
||||
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
|
||||
|
|
|
@ -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 = {
|
||||
.kind = "wwan",
|
||||
.maxtype = __IFLA_WWAN_MAX,
|
||||
.maxtype = IFLA_WWAN_MAX,
|
||||
.alloc = wwan_rtnl_alloc,
|
||||
.validate = wwan_rtnl_validate,
|
||||
.newlink = wwan_rtnl_newlink,
|
||||
|
|
|
@ -521,6 +521,7 @@ static int __init sysman_init(void)
|
|||
int ret = 0;
|
||||
|
||||
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)) {
|
||||
pr_err("Unable to run on non-Dell system\n");
|
||||
return -ENODEV;
|
||||
|
|
|
@ -2133,6 +2133,11 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
{
|
||||
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) {
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
if (pm_runtime_suspended(dwc->dev))
|
||||
|
@ -2180,6 +2185,15 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -2242,6 +2256,11 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!PMSG_IS_AUTO(msg)) {
|
||||
/* restore SUSPHY state to that before system suspend. */
|
||||
dwc3_enable_susphy(dwc, dwc->susphy_state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1147,6 +1147,8 @@ struct dwc3_scratchpad_array {
|
|||
* @sys_wakeup: set if the device may do system wakeup.
|
||||
* @wakeup_configured: set if the device is configured for remote wakeup.
|
||||
* @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
|
||||
* increments or 0 to disable.
|
||||
* @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 wakeup_configured:1;
|
||||
unsigned suspended:1;
|
||||
unsigned susphy_state:1;
|
||||
|
||||
u16 imod_interval;
|
||||
|
||||
|
|
|
@ -2042,7 +2042,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
|
|||
int result; \
|
||||
\
|
||||
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); \
|
||||
\
|
||||
return result; \
|
||||
|
@ -2052,7 +2052,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
|
|||
const char *page, size_t len) \
|
||||
{ \
|
||||
struct f_uac2_opts *opts = to_f_uac2_opts(item); \
|
||||
int ret = 0; \
|
||||
int ret = len; \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
if (opts->refcnt) { \
|
||||
|
@ -2060,8 +2060,11 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
|
|||
goto end; \
|
||||
} \
|
||||
\
|
||||
ret = snprintf(opts->name, min(sizeof(opts->name), len), \
|
||||
"%s", page); \
|
||||
if (len && page[len - 1] == '\n') \
|
||||
len--; \
|
||||
\
|
||||
scnprintf(opts->name, min(sizeof(opts->name), len + 1), \
|
||||
"%s", page); \
|
||||
\
|
||||
end: \
|
||||
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->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;
|
||||
}
|
||||
|
|
85
drivers/usb/host/xhci-caps.h
Normal file
85
drivers/usb/host/xhci-caps.h
Normal 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))
|
|
@ -108,7 +108,7 @@ struct dbc_port {
|
|||
struct tasklet_struct push;
|
||||
|
||||
struct list_head write_pool;
|
||||
struct kfifo write_fifo;
|
||||
unsigned int tx_boundary;
|
||||
|
||||
bool registered;
|
||||
};
|
||||
|
|
|
@ -25,16 +25,26 @@ static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc)
|
|||
}
|
||||
|
||||
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);
|
||||
if (len < size)
|
||||
size = len;
|
||||
if (size != 0)
|
||||
size = kfifo_out(&port->write_fifo, packet, size);
|
||||
return size;
|
||||
len = kfifo_len(&port->port.xmit_fifo);
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
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)
|
||||
|
@ -49,7 +59,7 @@ static int dbc_start_tx(struct dbc_port *port)
|
|||
|
||||
while (!list_empty(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)
|
||||
break;
|
||||
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;
|
||||
unsigned long flags;
|
||||
unsigned int written = 0;
|
||||
|
||||
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);
|
||||
|
||||
return count;
|
||||
return written;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
return status;
|
||||
|
@ -253,7 +281,11 @@ static unsigned int dbc_tty_write_room(struct tty_struct *tty)
|
|||
unsigned int room;
|
||||
|
||||
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);
|
||||
|
||||
return room;
|
||||
|
@ -266,7 +298,7 @@ static unsigned int dbc_tty_chars_in_buffer(struct tty_struct *tty)
|
|||
unsigned int chars;
|
||||
|
||||
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);
|
||||
|
||||
return chars;
|
||||
|
@ -424,7 +456,8 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
|
|||
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)
|
||||
goto err_exit_port;
|
||||
|
||||
|
@ -453,7 +486,7 @@ err_free_requests:
|
|||
xhci_dbc_free_requests(&port->read_pool);
|
||||
xhci_dbc_free_requests(&port->write_pool);
|
||||
err_free_fifo:
|
||||
kfifo_free(&port->write_fifo);
|
||||
kfifo_free(&port->port.xmit_fifo);
|
||||
err_exit_port:
|
||||
idr_remove(&dbc_tty_minors, port->minor);
|
||||
err_idr:
|
||||
|
@ -478,7 +511,7 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
|
|||
idr_remove(&dbc_tty_minors, port->minor);
|
||||
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_queue);
|
||||
xhci_dbc_free_requests(&port->write_pool);
|
||||
|
|
176
drivers/usb/host/xhci-port.h
Normal file
176
drivers/usb/host/xhci-port.h
Normal 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
|
|
@ -24,6 +24,9 @@
|
|||
#include "xhci-ext-caps.h"
|
||||
#include "pci-quirks.h"
|
||||
|
||||
#include "xhci-port.h"
|
||||
#include "xhci-caps.h"
|
||||
|
||||
/* max buffer size for trace and debug messages */
|
||||
#define XHCI_MSG_MAX 500
|
||||
|
||||
|
@ -64,90 +67,6 @@ struct xhci_cap_regs {
|
|||
/* 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 */
|
||||
#define NUM_PORT_REGS 4
|
||||
|
||||
|
@ -293,181 +212,6 @@ struct xhci_op_regs {
|
|||
#define CONFIG_CIE (1 << 9)
|
||||
/* 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
|
||||
* @irq_pending: IMAN - Interrupt Management Register. Used to enable
|
||||
|
|
21
fs/exec.c
21
fs/exec.c
|
@ -145,13 +145,11 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
|
|||
goto out;
|
||||
|
||||
/*
|
||||
* may_open() has already checked for this, so it should be
|
||||
* impossible to trip now. But we need to be extra cautious
|
||||
* and check again at the very end too.
|
||||
* Check do_open_execat() for an explanation.
|
||||
*/
|
||||
error = -EACCES;
|
||||
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) ||
|
||||
path_noexec(&file->f_path)))
|
||||
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) ||
|
||||
path_noexec(&file->f_path))
|
||||
goto exit;
|
||||
|
||||
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);
|
||||
if (IS_ERR(file))
|
||||
goto out;
|
||||
return file;
|
||||
|
||||
/*
|
||||
* may_open() has already checked for this, so it should be
|
||||
* impossible to trip now. But we need to be extra cautious
|
||||
* and check again at the very end too.
|
||||
* In the past the regular type check was here. It moved to may_open() in
|
||||
* 633fb6ac3980 ("exec: move S_ISREG() check earlier"). Since then it is
|
||||
* an invariant that all non-regular files error out before we get here.
|
||||
*/
|
||||
err = -EACCES;
|
||||
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) ||
|
||||
path_noexec(&file->f_path)))
|
||||
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) ||
|
||||
path_noexec(&file->f_path))
|
||||
goto exit;
|
||||
|
||||
err = deny_write_access(file);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
out:
|
||||
return file;
|
||||
|
||||
exit:
|
||||
|
|
|
@ -187,7 +187,7 @@ int dbMount(struct inode *ipbmap)
|
|||
}
|
||||
|
||||
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;
|
||||
goto err_release_metapage;
|
||||
}
|
||||
|
|
|
@ -330,6 +330,18 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
|
|||
|
||||
switch ((type = le64_to_cpu(buf->InodeType))) {
|
||||
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,
|
||||
len, true,
|
||||
cifs_sb->local_nls);
|
||||
|
@ -340,8 +352,19 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
|
|||
break;
|
||||
case NFS_SPECFILE_CHR:
|
||||
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_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;
|
||||
default:
|
||||
cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",
|
||||
|
|
|
@ -387,6 +387,7 @@ static void udf_table_free_blocks(struct super_block *sb,
|
|||
struct extent_position oepos, epos;
|
||||
int8_t etype;
|
||||
struct udf_inode_info *iinfo;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
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.bh = oepos.bh = NULL;
|
||||
|
||||
while (count &&
|
||||
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
|
||||
while (count) {
|
||||
ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1);
|
||||
if (ret < 0)
|
||||
goto error_return;
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (((eloc.logicalBlockNum +
|
||||
(elen >> sb->s_blocksize_bits)) == start)) {
|
||||
if ((0x3FFFFFFF - elen) <
|
||||
|
@ -476,11 +481,8 @@ static void udf_table_free_blocks(struct super_block *sb,
|
|||
adsize = sizeof(struct short_ad);
|
||||
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(struct long_ad);
|
||||
else {
|
||||
brelse(oepos.bh);
|
||||
brelse(epos.bh);
|
||||
else
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (epos.offset + (2 * adsize) > sb->s_blocksize) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
error_return:
|
||||
brelse(epos.bh);
|
||||
brelse(oepos.bh);
|
||||
|
||||
error_return:
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return;
|
||||
}
|
||||
|
@ -515,6 +517,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
|
|||
struct extent_position epos;
|
||||
int8_t etype = -1;
|
||||
struct udf_inode_info *iinfo;
|
||||
int ret = 0;
|
||||
|
||||
if (first_block >= sbi->s_partmaps[partition].s_partition_len)
|
||||
return 0;
|
||||
|
@ -533,11 +536,14 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
|
|||
epos.bh = NULL;
|
||||
eloc.logicalBlockNum = 0xFFFFFFFF;
|
||||
|
||||
while (first_block != eloc.logicalBlockNum &&
|
||||
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
|
||||
while (first_block != eloc.logicalBlockNum) {
|
||||
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",
|
||||
eloc.logicalBlockNum, elen, first_block);
|
||||
; /* empty loop body */
|
||||
}
|
||||
|
||||
if (first_block == eloc.logicalBlockNum) {
|
||||
|
@ -556,6 +562,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
|
|||
alloc_count = 0;
|
||||
}
|
||||
|
||||
err_out:
|
||||
brelse(epos.bh);
|
||||
|
||||
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;
|
||||
int8_t etype;
|
||||
struct udf_inode_info *iinfo = UDF_I(table);
|
||||
int ret = 0;
|
||||
|
||||
*err = -ENOSPC;
|
||||
|
||||
|
@ -600,8 +608,10 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
|
|||
epos.block = iinfo->i_location;
|
||||
epos.bh = goal_epos.bh = NULL;
|
||||
|
||||
while (spread &&
|
||||
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
|
||||
while (spread) {
|
||||
ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
if (goal >= eloc.logicalBlockNum) {
|
||||
if (goal < eloc.logicalBlockNum +
|
||||
(elen >> sb->s_blocksize_bits))
|
||||
|
@ -629,9 +639,11 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
|
|||
|
||||
brelse(epos.bh);
|
||||
|
||||
if (spread == 0xFFFFFFFF) {
|
||||
if (ret < 0 || spread == 0xFFFFFFFF) {
|
||||
brelse(goal_epos.bh);
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
if (ret < 0)
|
||||
*err = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
int8_t etype = -1;
|
||||
int err = 0;
|
||||
|
||||
iter->loffset++;
|
||||
if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits))
|
||||
return 0;
|
||||
|
||||
iter->loffset = 0;
|
||||
if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1)
|
||||
!= (EXT_RECORDED_ALLOCATED >> 30)) {
|
||||
err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc,
|
||||
&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) {
|
||||
iter->elen = 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);
|
||||
int err = 0;
|
||||
int8_t etype;
|
||||
|
||||
iter->dir = dir;
|
||||
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;
|
||||
}
|
||||
|
||||
if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
|
||||
&iter->eloc, &iter->elen, &iter->loffset) !=
|
||||
(EXT_RECORDED_ALLOCATED >> 30)) {
|
||||
err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
|
||||
&iter->eloc, &iter->elen, &iter->loffset, &etype);
|
||||
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
|
||||
if (pos == dir->i_size)
|
||||
return 0;
|
||||
udf_err(dir->i_sb,
|
||||
|
@ -457,6 +464,7 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
|
|||
sector_t block;
|
||||
uint32_t old_elen = iter->elen;
|
||||
int err;
|
||||
int8_t etype;
|
||||
|
||||
if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
|
||||
return -EINVAL;
|
||||
|
@ -471,8 +479,9 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
|
|||
udf_fiiter_update_elen(iter, old_elen);
|
||||
return err;
|
||||
}
|
||||
if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
|
||||
&iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) {
|
||||
err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
|
||||
&iter->loffset, &etype);
|
||||
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
|
||||
udf_err(iter->dir->i_sb,
|
||||
"block %llu not allocated in directory (ino %lu)\n",
|
||||
(unsigned long long)block, iter->dir->i_ino);
|
||||
|
|
202
fs/udf/inode.c
202
fs/udf/inode.c
|
@ -408,7 +408,7 @@ struct udf_map_rq {
|
|||
|
||||
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);
|
||||
|
||||
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;
|
||||
sector_t offset;
|
||||
struct extent_position epos = {};
|
||||
int8_t etype;
|
||||
|
||||
down_read(&iinfo->i_data_sem);
|
||||
if (inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset)
|
||||
== (EXT_RECORDED_ALLOCATED >> 30)) {
|
||||
ret = inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset,
|
||||
&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,
|
||||
offset);
|
||||
map->oflags |= UDF_BLK_MAPPED;
|
||||
ret = 0;
|
||||
}
|
||||
out_read:
|
||||
up_read(&iinfo->i_data_sem);
|
||||
brelse(epos.bh);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
udf_discard_prealloc(inode);
|
||||
udf_clear_extent_cache(inode);
|
||||
err = inode_getblk(inode, map);
|
||||
ret = inode_getblk(inode, map);
|
||||
up_write(&iinfo->i_data_sem);
|
||||
return err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 {
|
||||
struct kernel_lb_addr tmploc;
|
||||
uint32_t tmplen;
|
||||
int8_t tmptype;
|
||||
|
||||
udf_write_aext(inode, last_pos, &last_ext->extLocation,
|
||||
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
|
||||
* empty indirect extent.
|
||||
*/
|
||||
if (new_block_bytes)
|
||||
udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0);
|
||||
if (new_block_bytes) {
|
||||
err = udf_next_aext(inode, last_pos, &tmploc, &tmplen,
|
||||
&tmptype, 0);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
iinfo->i_lenExtents += add;
|
||||
|
||||
|
@ -661,8 +672,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
|
|||
*/
|
||||
udf_discard_prealloc(inode);
|
||||
|
||||
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
|
||||
within_last_ext = (etype != -1);
|
||||
err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
within_last_ext = (err == 1);
|
||||
/* We don't expect extents past EOF... */
|
||||
WARN_ON_ONCE(within_last_ext &&
|
||||
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;
|
||||
} else {
|
||||
epos.offset -= adsize;
|
||||
etype = udf_next_aext(inode, &epos, &extent.extLocation,
|
||||
&extent.extLength, 0);
|
||||
err = udf_next_aext(inode, &epos, &extent.extLocation,
|
||||
&extent.extLength, &etype, 0);
|
||||
if (err <= 0)
|
||||
goto out;
|
||||
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;
|
||||
udf_pblk_t newblocknum;
|
||||
sector_t offset = 0;
|
||||
int8_t etype;
|
||||
int8_t etype, tmpetype;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum;
|
||||
int lastblock = 0;
|
||||
bool isBeyondEOF;
|
||||
bool isBeyondEOF = false;
|
||||
int ret = 0;
|
||||
|
||||
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;
|
||||
cur_epos.offset = next_epos.offset;
|
||||
|
||||
etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1);
|
||||
if (etype == -1)
|
||||
ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 1);
|
||||
if (ret < 0) {
|
||||
goto out_free;
|
||||
} else if (ret == 0) {
|
||||
isBeyondEOF = true;
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
* the pointer to it
|
||||
*/
|
||||
udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0);
|
||||
udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0);
|
||||
ret = udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, &tmpetype, 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 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)) {
|
||||
elen = EXT_RECORDED_ALLOCATED |
|
||||
((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? */
|
||||
if (etype == -1) {
|
||||
if (isBeyondEOF) {
|
||||
loff_t hole_len;
|
||||
|
||||
isBeyondEOF = true;
|
||||
if (count) {
|
||||
if (c)
|
||||
laarr[0] = laarr[1];
|
||||
|
@ -834,7 +856,6 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
|
|||
endnum = c + 1;
|
||||
lastblock = 1;
|
||||
} else {
|
||||
isBeyondEOF = false;
|
||||
endnum = startnum = ((count > 2) ? 2 : count);
|
||||
|
||||
/* 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,
|
||||
read the next extent */
|
||||
etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0);
|
||||
if (etype != -1) {
|
||||
ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 0);
|
||||
if (ret > 0) {
|
||||
laarr[c + 1].extLength = (etype << 30) | elen;
|
||||
laarr[c + 1].extLocation = eloc;
|
||||
count++;
|
||||
startnum++;
|
||||
endnum++;
|
||||
} else
|
||||
} else if (ret == 0)
|
||||
lastblock = 1;
|
||||
else
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
struct kernel_lb_addr tmploc;
|
||||
uint32_t tmplen;
|
||||
int8_t tmpetype;
|
||||
int err;
|
||||
|
||||
if (startnum > endnum) {
|
||||
|
@ -1191,14 +1215,19 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr,
|
|||
*/
|
||||
if (err < 0)
|
||||
return err;
|
||||
udf_next_aext(inode, epos, &laarr[i].extLocation,
|
||||
&laarr[i].extLength, 1);
|
||||
err = udf_next_aext(inode, epos, &laarr[i].extLocation,
|
||||
&laarr[i].extLength, &tmpetype, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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 kernel_lb_addr neloc;
|
||||
int ver, adsize;
|
||||
int err = 0;
|
||||
|
||||
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
|
||||
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) {
|
||||
struct kernel_lb_addr cp_loc;
|
||||
uint32_t cp_len;
|
||||
int cp_type;
|
||||
int8_t cp_type;
|
||||
|
||||
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;
|
||||
|
||||
__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;
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
int ret = 0;
|
||||
udf_pblk_t block;
|
||||
|
||||
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
|
||||
(EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) {
|
||||
udf_pblk_t block;
|
||||
while (1) {
|
||||
ret = udf_current_aext(inode, epos, eloc, elen,
|
||||
etype, inc);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
if (*etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30))
|
||||
return ret;
|
||||
|
||||
if (++indirections > UDF_MAX_INDIR_EXTS) {
|
||||
udf_err(inode->i_sb,
|
||||
"too many indirect extents in inode %lu\n",
|
||||
inode->i_ino);
|
||||
return -1;
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!epos->bh) {
|
||||
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;
|
||||
int8_t etype;
|
||||
uint8_t *ptr;
|
||||
struct short_ad *sad;
|
||||
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) +
|
||||
iinfo->i_lenAlloc;
|
||||
} else {
|
||||
struct allocExtDesc *header =
|
||||
(struct allocExtDesc *)epos->bh->b_data;
|
||||
|
||||
if (!epos->offset)
|
||||
epos->offset = sizeof(struct allocExtDesc);
|
||||
ptr = epos->bh->b_data + epos->offset;
|
||||
alen = sizeof(struct allocExtDesc) +
|
||||
le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->
|
||||
lengthAllocDescs);
|
||||
if (check_add_overflow(sizeof(struct allocExtDesc),
|
||||
le32_to_cpu(header->lengthAllocDescs), &alen))
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (iinfo->i_alloc_type) {
|
||||
case ICBTAG_FLAG_AD_SHORT:
|
||||
sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc);
|
||||
if (!sad)
|
||||
return -1;
|
||||
etype = le32_to_cpu(sad->extLength) >> 30;
|
||||
return 0;
|
||||
*etype = le32_to_cpu(sad->extLength) >> 30;
|
||||
eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
|
||||
eloc->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:
|
||||
lad = udf_get_filelongad(ptr, alen, &epos->offset, inc);
|
||||
if (!lad)
|
||||
return -1;
|
||||
etype = le32_to_cpu(lad->extLength) >> 30;
|
||||
return 0;
|
||||
*etype = le32_to_cpu(lad->extLength) >> 30;
|
||||
*eloc = lelb_to_cpu(lad->extLocation);
|
||||
*elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
|
||||
break;
|
||||
default:
|
||||
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,
|
||||
|
@ -2251,20 +2299,24 @@ static int udf_insert_aext(struct inode *inode, struct extent_position epos,
|
|||
struct kernel_lb_addr oeloc;
|
||||
uint32_t oelen;
|
||||
int8_t etype;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
if (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);
|
||||
neloc = oeloc;
|
||||
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);
|
||||
|
||||
return err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 kernel_lb_addr eloc;
|
||||
uint32_t elen;
|
||||
int ret;
|
||||
|
||||
if (epos.bh) {
|
||||
get_bh(epos.bh);
|
||||
|
@ -2291,10 +2344,18 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
|
|||
adsize = 0;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
if (oepos.bh != epos.bh) {
|
||||
oepos.block = epos.block;
|
||||
|
@ -2351,14 +2412,17 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
|
|||
return (elen >> 30);
|
||||
}
|
||||
|
||||
int8_t inode_bmap(struct inode *inode, sector_t block,
|
||||
struct extent_position *pos, struct kernel_lb_addr *eloc,
|
||||
uint32_t *elen, sector_t *offset)
|
||||
/*
|
||||
* Returns 1 on success, -errno on error, 0 on hit EOF.
|
||||
*/
|
||||
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;
|
||||
loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits;
|
||||
int8_t etype;
|
||||
struct udf_inode_info *iinfo;
|
||||
int err = 0;
|
||||
|
||||
iinfo = UDF_I(inode);
|
||||
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;
|
||||
do {
|
||||
etype = udf_next_aext(inode, pos, eloc, elen, 1);
|
||||
if (etype == -1) {
|
||||
*offset = (bcount - lbcount) >> blocksize_bits;
|
||||
iinfo->i_lenExtents = lbcount;
|
||||
return -1;
|
||||
err = udf_next_aext(inode, pos, eloc, elen, etype, 1);
|
||||
if (err <= 0) {
|
||||
if (err == 0) {
|
||||
*offset = (bcount - lbcount) >> blocksize_bits;
|
||||
iinfo->i_lenExtents = lbcount;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
lbcount += *elen;
|
||||
} 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);
|
||||
*offset = (bcount + *elen - lbcount) >> blocksize_bits;
|
||||
|
||||
return etype;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -282,9 +282,11 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
|
|||
sector_t ext_offset;
|
||||
struct extent_position epos = {};
|
||||
uint32_t phyblock;
|
||||
int8_t etype;
|
||||
int err = 0;
|
||||
|
||||
if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
|
||||
(EXT_RECORDED_ALLOCATED >> 30))
|
||||
err = inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset, &etype);
|
||||
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30))
|
||||
phyblock = 0xFFFFFFFF;
|
||||
else {
|
||||
map = &UDF_SB(sb)->s_partmaps[partition];
|
||||
|
|
|
@ -2454,13 +2454,14 @@ static unsigned int udf_count_free_table(struct super_block *sb,
|
|||
uint32_t elen;
|
||||
struct kernel_lb_addr eloc;
|
||||
struct extent_position epos;
|
||||
int8_t etype;
|
||||
|
||||
mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
|
||||
epos.block = UDF_I(table)->i_location;
|
||||
epos.offset = sizeof(struct unallocSpaceEntry);
|
||||
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);
|
||||
|
||||
brelse(epos.bh);
|
||||
|
|
|
@ -69,6 +69,7 @@ void udf_truncate_tail_extent(struct inode *inode)
|
|||
int8_t etype = -1, netype;
|
||||
int adsize;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
int ret;
|
||||
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
|
||||
inode->i_size == iinfo->i_lenExtents)
|
||||
|
@ -85,7 +86,10 @@ void udf_truncate_tail_extent(struct inode *inode)
|
|||
BUG();
|
||||
|
||||
/* 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;
|
||||
lbcount += elen;
|
||||
if (lbcount > inode->i_size) {
|
||||
|
@ -101,7 +105,8 @@ void udf_truncate_tail_extent(struct inode *inode)
|
|||
epos.offset -= adsize;
|
||||
extent_trunc(inode, &epos, &eloc, etype, elen, nelen);
|
||||
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,
|
||||
"Extent after EOF in inode %u\n",
|
||||
(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
|
||||
* the inode dirty */
|
||||
iinfo->i_lenExtents = inode->i_size;
|
||||
if (ret == 0)
|
||||
iinfo->i_lenExtents = inode->i_size;
|
||||
brelse(epos.bh);
|
||||
}
|
||||
|
||||
|
@ -124,6 +130,8 @@ void udf_discard_prealloc(struct inode *inode)
|
|||
int8_t etype = -1;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
int bsize = i_blocksize(inode);
|
||||
int8_t tmpetype = -1;
|
||||
int ret;
|
||||
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
prev_epos = epos;
|
||||
if (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;
|
||||
}
|
||||
|
||||
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
|
||||
lbcount -= elen;
|
||||
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
|
||||
* the inode dirty */
|
||||
iinfo->i_lenExtents = lbcount;
|
||||
out:
|
||||
brelse(epos.bh);
|
||||
brelse(prev_epos.bh);
|
||||
}
|
||||
|
@ -188,6 +205,7 @@ int udf_truncate_extents(struct inode *inode)
|
|||
loff_t byte_offset;
|
||||
int adsize;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
int ret = 0;
|
||||
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
|
||||
adsize = sizeof(struct short_ad);
|
||||
|
@ -196,10 +214,12 @@ int udf_truncate_extents(struct inode *inode)
|
|||
else
|
||||
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) +
|
||||
(inode->i_size & (sb->s_blocksize - 1));
|
||||
if (etype == -1) {
|
||||
if (ret == 0) {
|
||||
/* We should extend the file? */
|
||||
WARN_ON(byte_offset);
|
||||
return 0;
|
||||
|
@ -217,8 +237,8 @@ int udf_truncate_extents(struct inode *inode)
|
|||
else
|
||||
lenalloc -= sizeof(struct allocExtDesc);
|
||||
|
||||
while ((etype = udf_current_aext(inode, &epos, &eloc,
|
||||
&elen, 0)) != -1) {
|
||||
while ((ret = udf_current_aext(inode, &epos, &eloc,
|
||||
&elen, &etype, 0)) > 0) {
|
||||
if (etype == (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) {
|
||||
udf_write_aext(inode, &epos, &neloc, nelen, 0);
|
||||
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) {
|
||||
BUG_ON(!epos.bh);
|
||||
udf_free_blocks(sb, NULL, &epos.block, 0, indirect_ext_len);
|
||||
|
|
|
@ -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 void udf_evict_inode(struct inode *);
|
||||
extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
|
||||
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
|
||||
struct kernel_lb_addr *, uint32_t *, sector_t *);
|
||||
extern 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);
|
||||
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,
|
||||
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 *,
|
||||
struct kernel_lb_addr *, uint32_t, int);
|
||||
extern int8_t udf_delete_aext(struct inode *, struct extent_position);
|
||||
extern int8_t udf_next_aext(struct inode *, struct extent_position *,
|
||||
struct kernel_lb_addr *, uint32_t *, int);
|
||||
extern int8_t udf_current_aext(struct inode *, struct extent_position *,
|
||||
struct kernel_lb_addr *, uint32_t *, int);
|
||||
extern int udf_next_aext(struct inode *inode, struct extent_position *epos,
|
||||
struct kernel_lb_addr *eloc, uint32_t *elen,
|
||||
int8_t *etype, int inc);
|
||||
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);
|
||||
|
||||
/* misc.c */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/* 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() */
|
||||
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))
|
||||
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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -339,20 +339,25 @@ struct xfrm_if_cb {
|
|||
void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb);
|
||||
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 xfrm_type;
|
||||
struct xfrm_dst;
|
||||
struct xfrm_policy_afinfo {
|
||||
struct dst_ops *dst_ops;
|
||||
struct dst_entry *(*dst_lookup)(struct net *net,
|
||||
int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
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);
|
||||
struct dst_entry *(*dst_lookup)(const struct xfrm_dst_lookup_params *params);
|
||||
int (*get_saddr)(xfrm_address_t *saddr,
|
||||
const struct xfrm_dst_lookup_params *params);
|
||||
int (*fill_dst)(struct xfrm_dst *xdst,
|
||||
struct net_device *dev,
|
||||
const struct flowi *fl);
|
||||
|
@ -1723,10 +1728,7 @@ static inline int xfrm_user_policy(struct sock *sk, int optname,
|
|||
}
|
||||
#endif
|
||||
|
||||
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr,
|
||||
int family, u32 mark);
|
||||
struct dst_entry *__xfrm_dst_lookup(int family, const struct xfrm_dst_lookup_params *params);
|
||||
|
||||
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);
|
||||
|
||||
|
|
|
@ -5773,6 +5773,7 @@ static const char readme_msg[] =
|
|||
"\t $stack<index>, $stack, $retval, $comm,\n"
|
||||
#endif
|
||||
"\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 b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
|
||||
"\t symstr, <type>\\[<array-size>\\]\n"
|
||||
|
|
|
@ -220,7 +220,7 @@ static struct trace_eprobe *alloc_event_probe(const char *group,
|
|||
if (!ep->event_system)
|
||||
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)
|
||||
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 */
|
||||
static int
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
|
||||
void *base)
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
|
||||
void *dest, void *base)
|
||||
{
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
@ -438,7 +438,7 @@ __eprobe_trace_func(struct eprobe_data *edata, void *rec)
|
|||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
event_call = find_and_get_event(sys_name, sys_event);
|
||||
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;
|
||||
/* 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);
|
||||
ret = trace_eprobe_tp_update_arg(ep, argv, i);
|
||||
if (ret)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2022 Google LLC.
|
||||
*/
|
||||
#define pr_fmt(fmt) "trace_fprobe: " fmt
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include <linux/fprobe.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -129,8 +130,8 @@ static bool trace_fprobe_is_registered(struct trace_fprobe *tf)
|
|||
* from user space.
|
||||
*/
|
||||
static int
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
|
||||
void *base)
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
|
||||
void *dest, void *base)
|
||||
{
|
||||
struct pt_regs *regs = rec;
|
||||
unsigned long val;
|
||||
|
@ -152,6 +153,9 @@ retry:
|
|||
case FETCH_OP_ARG:
|
||||
val = regs_get_kernel_argument(regs, code->param);
|
||||
break;
|
||||
case FETCH_OP_EDATA:
|
||||
val = *(unsigned long *)((unsigned long)edata + code->offset);
|
||||
break;
|
||||
#endif
|
||||
case FETCH_NOP_SYMBOL: /* Ignore a place holder */
|
||||
code++;
|
||||
|
@ -184,7 +188,7 @@ __fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
if (trace_trigger_soft_disabled(trace_file))
|
||||
return;
|
||||
|
||||
dsize = __get_data_size(&tf->tp, regs);
|
||||
dsize = __get_data_size(&tf->tp, regs, NULL);
|
||||
|
||||
entry = trace_event_buffer_reserve(&fbuffer, trace_file,
|
||||
sizeof(*entry) + tf->tp.size + dsize);
|
||||
|
@ -194,7 +198,7 @@ __fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
fbuffer.regs = regs;
|
||||
entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
|
||||
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);
|
||||
}
|
||||
|
@ -210,11 +214,24 @@ fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
}
|
||||
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
|
||||
__fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
||||
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 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))
|
||||
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,
|
||||
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->func = entry_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);
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -269,7 +286,7 @@ static int fentry_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
if (hlist_empty(head))
|
||||
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 = ALIGN(__size + sizeof(u32), sizeof(u64));
|
||||
size -= sizeof(u32);
|
||||
|
@ -280,7 +297,7 @@ static int fentry_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
|
||||
entry->ip = entry_ip;
|
||||
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,
|
||||
head, NULL);
|
||||
return 0;
|
||||
|
@ -289,7 +306,8 @@ NOKPROBE_SYMBOL(fentry_perf_func);
|
|||
|
||||
static void
|
||||
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 fexit_trace_entry_head *entry;
|
||||
|
@ -301,7 +319,7 @@ fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
if (hlist_empty(head))
|
||||
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 = ALIGN(__size + sizeof(u32), sizeof(u64));
|
||||
size -= sizeof(u32);
|
||||
|
@ -312,7 +330,7 @@ fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
|
|||
|
||||
entry->func = entry_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,
|
||||
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);
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
NOKPROBE_SYMBOL(fexit_dispatcher);
|
||||
|
@ -389,7 +407,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
|
|||
tf->tpoint = tpoint;
|
||||
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)
|
||||
goto error;
|
||||
|
||||
|
@ -1085,6 +1103,10 @@ static int __trace_fprobe_create(int argc, const char *argv[])
|
|||
argc = new_argc;
|
||||
argv = new_argv;
|
||||
}
|
||||
if (argc > MAX_TRACE_ARGS) {
|
||||
ret = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* setup a probe */
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
ctx.offset = 0;
|
||||
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 */
|
||||
}
|
||||
|
||||
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,
|
||||
is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -290,7 +290,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
|
|||
INIT_HLIST_NODE(&tk->rp.kp.hlist);
|
||||
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)
|
||||
goto error;
|
||||
|
||||
|
@ -740,6 +740,9 @@ static unsigned int number_of_same_symbols(char *func_name)
|
|||
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[])
|
||||
{
|
||||
/*
|
||||
|
@ -929,6 +932,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
|||
argc = new_argc;
|
||||
argv = new_argv;
|
||||
}
|
||||
if (argc > MAX_TRACE_ARGS) {
|
||||
ret = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* setup a probe */
|
||||
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 */
|
||||
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
trace_probe_log_set_index(i + 2);
|
||||
ctx.offset = 0;
|
||||
ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
|
||||
if (ret)
|
||||
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;
|
||||
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 */
|
||||
static int
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
|
||||
void *base)
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
|
||||
void *dest, void *base)
|
||||
{
|
||||
struct pt_regs *regs = rec;
|
||||
unsigned long val;
|
||||
|
@ -1324,6 +1336,9 @@ retry:
|
|||
case FETCH_OP_ARG:
|
||||
val = regs_get_kernel_argument(regs, code->param);
|
||||
break;
|
||||
case FETCH_OP_EDATA:
|
||||
val = *(unsigned long *)((unsigned long)edata + code->offset);
|
||||
break;
|
||||
#endif
|
||||
case FETCH_NOP_SYMBOL: /* Ignore a place holder */
|
||||
code++;
|
||||
|
@ -1354,7 +1369,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
|
|||
if (trace_trigger_soft_disabled(trace_file))
|
||||
return;
|
||||
|
||||
dsize = __get_data_size(&tk->tp, regs);
|
||||
dsize = __get_data_size(&tk->tp, regs, NULL);
|
||||
|
||||
entry = trace_event_buffer_reserve(&fbuffer, trace_file,
|
||||
sizeof(*entry) + tk->tp.size + dsize);
|
||||
|
@ -1363,7 +1378,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
|
|||
|
||||
fbuffer.regs = regs;
|
||||
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);
|
||||
}
|
||||
|
@ -1379,6 +1394,31 @@ kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs)
|
|||
NOKPROBE_SYMBOL(kprobe_trace_func);
|
||||
|
||||
/* 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
|
||||
__kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
|
||||
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))
|
||||
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,
|
||||
sizeof(*entry) + tk->tp.size + dsize);
|
||||
|
@ -1404,7 +1444,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
|
|||
fbuffer.regs = regs;
|
||||
entry->func = (unsigned long)tk->rp.kp.addr;
|
||||
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);
|
||||
}
|
||||
|
@ -1552,7 +1592,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
|
|||
if (hlist_empty(head))
|
||||
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 = ALIGN(__size + sizeof(u32), sizeof(u64));
|
||||
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;
|
||||
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,
|
||||
head, NULL);
|
||||
return 0;
|
||||
|
@ -1588,7 +1628,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
|
|||
if (hlist_empty(head))
|
||||
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 = ALIGN(__size + sizeof(u32), sizeof(u64));
|
||||
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->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,
|
||||
head, NULL);
|
||||
}
|
||||
|
|
|
@ -275,7 +275,7 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
|
|||
}
|
||||
trace_probe_log_err(offset, NO_EVENT_NAME);
|
||||
return -EINVAL;
|
||||
} else if (len > MAX_EVENT_NAME_LEN) {
|
||||
} else if (len >= MAX_EVENT_NAME_LEN) {
|
||||
trace_probe_log_err(offset, EVENT_TOO_LONG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -598,6 +598,8 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __store_entry_arg(struct trace_probe *tp, int argnum);
|
||||
|
||||
static int parse_btf_arg(char *varname,
|
||||
struct fetch_insn **pcode, struct fetch_insn *end,
|
||||
struct traceprobe_parse_context *ctx)
|
||||
|
@ -622,11 +624,7 @@ static int parse_btf_arg(char *varname,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (ctx->flags & TPARG_FL_RETURN) {
|
||||
if (strcmp(varname, "$retval") != 0) {
|
||||
trace_probe_log_err(ctx->offset, NO_BTFARG);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) {
|
||||
code->op = FETCH_OP_RETVAL;
|
||||
/* Check whether the function return type is not void */
|
||||
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);
|
||||
|
||||
if (name && !strcmp(name, varname)) {
|
||||
code->op = FETCH_OP_ARG;
|
||||
if (ctx->flags & TPARG_FL_TPOINT)
|
||||
code->param = i + 1;
|
||||
else
|
||||
code->param = i;
|
||||
if (tparg_is_function_entry(ctx->flags)) {
|
||||
code->op = FETCH_OP_ARG;
|
||||
if (ctx->flags & TPARG_FL_TPOINT)
|
||||
code->param = i + 1;
|
||||
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;
|
||||
goto found;
|
||||
}
|
||||
|
@ -759,6 +767,110 @@ static int check_prepare_btf_string_fetch(char *typename,
|
|||
|
||||
#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))
|
||||
|
||||
/* 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
|
||||
len = str_has_prefix(arg, "arg");
|
||||
if (len && tparg_is_function_entry(ctx->flags)) {
|
||||
if (len) {
|
||||
ret = kstrtoul(arg + len, 10, ¶m);
|
||||
if (ret)
|
||||
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;
|
||||
goto inval;
|
||||
}
|
||||
param--; /* argN starts from 1, but internal arg[N] starts from 0 */
|
||||
|
||||
code->op = FETCH_OP_ARG;
|
||||
code->param = (unsigned int)param - 1;
|
||||
/*
|
||||
* 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 (tparg_is_function_entry(ctx->flags)) {
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
@ -1041,7 +1167,8 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
|
|||
break;
|
||||
default:
|
||||
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);
|
||||
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];
|
||||
const char *body;
|
||||
|
||||
/* Increment count for freeing args in error case */
|
||||
tp->nr_args++;
|
||||
|
||||
ctx->tp = tp;
|
||||
body = strchr(arg, '=');
|
||||
if (body) {
|
||||
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")) {
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1765,12 +1891,18 @@ void trace_probe_cleanup(struct trace_probe *tp)
|
|||
for (i = 0; i < tp->nr_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)
|
||||
trace_probe_unlink(tp);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
tp->nr_args = nargs;
|
||||
/* Make sure pointers in args[] are NULL */
|
||||
if (nargs)
|
||||
memset(tp->args, 0, sizeof(tp->args[0]) * nargs);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
@ -92,6 +92,7 @@ enum fetch_op {
|
|||
FETCH_OP_ARG, /* Function argument : .param */
|
||||
FETCH_OP_FOFFS, /* File offset: .immediate */
|
||||
FETCH_OP_DATA, /* Allocated data: .data */
|
||||
FETCH_OP_EDATA, /* Entry data: .offset */
|
||||
// Stage 2 (dereference) op
|
||||
FETCH_OP_DEREF, /* 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_USTRING, /* User String: .offset, .size */
|
||||
FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */
|
||||
FETCH_OP_ST_EDATA, /* Store Entry Data: .offset */
|
||||
// Stage 4 (modify) op
|
||||
FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */
|
||||
// Stage 5 (loop) op
|
||||
|
@ -232,6 +234,11 @@ struct probe_arg {
|
|||
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 {
|
||||
rwlock_t rwlock;
|
||||
int nr_systemwide;
|
||||
|
@ -253,6 +260,7 @@ struct trace_probe {
|
|||
struct trace_probe_event *event;
|
||||
ssize_t size; /* trace entry size */
|
||||
unsigned int nr_args;
|
||||
struct probe_entry_arg *entry_arg; /* This is only for return probe */
|
||||
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,
|
||||
const char *group, bool alloc_filter);
|
||||
const char *group, bool alloc_filter, int nargs);
|
||||
void trace_probe_cleanup(struct trace_probe *tp);
|
||||
int trace_probe_append(struct trace_probe *tp, struct trace_probe *to);
|
||||
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,
|
||||
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) \
|
||||
list_for_each_entry(pos, &(tp)->event->files, list)
|
||||
#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);
|
||||
}
|
||||
|
||||
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 trace_event_call *event;
|
||||
/* BTF related parameters */
|
||||
|
@ -392,6 +417,7 @@ struct traceprobe_parse_context {
|
|||
const struct btf_type *last_type; /* Saved type */
|
||||
u32 last_bitoffs; /* Saved bitoffs */
|
||||
u32 last_bitsize; /* Saved bitsize */
|
||||
struct trace_probe *tp;
|
||||
unsigned int flags;
|
||||
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_BTF_ENTRY, "No BTF entry for this probe point"), \
|
||||
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(ARGS_2LONG, "$arg* failed because the argument list is too long"), \
|
||||
C(ARGIDX_2BIG, "$argN index is too big"), \
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
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);
|
||||
static nokprobe_inline int fetch_store_strlen(unsigned long addr);
|
||||
static nokprobe_inline int
|
||||
|
@ -232,7 +232,7 @@ array:
|
|||
|
||||
/* Sum up total data length for dynamic arrays (strings) */
|
||||
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;
|
||||
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++) {
|
||||
arg = tp->args + i;
|
||||
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)
|
||||
ret += len;
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
|
|||
|
||||
/* Store the value of each argument */
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
if (unlikely(arg->dynamic))
|
||||
*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)) {
|
||||
dyndata += ret;
|
||||
maxlen -= ret;
|
||||
|
|
|
@ -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 */
|
||||
static int
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
|
||||
void *base)
|
||||
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
|
||||
void *dest, void *base)
|
||||
{
|
||||
struct pt_regs *regs = rec;
|
||||
unsigned long val;
|
||||
|
@ -337,7 +337,7 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
|
|||
if (!tu)
|
||||
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)
|
||||
goto error;
|
||||
|
||||
|
@ -556,6 +556,8 @@ static int __trace_uprobe_create(int argc, const char **argv)
|
|||
|
||||
if (argc < 2)
|
||||
return -ECANCELED;
|
||||
if (argc - 2 > MAX_TRACE_ARGS)
|
||||
return -E2BIG;
|
||||
|
||||
if (argv[0][1] == ':')
|
||||
event = &argv[0][2];
|
||||
|
@ -681,7 +683,7 @@ static int __trace_uprobe_create(int argc, const char **argv)
|
|||
tu->filename = filename;
|
||||
|
||||
/* parse arguments */
|
||||
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
struct traceprobe_parse_context ctx = {
|
||||
.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 mutex mutex;
|
||||
void *buf;
|
||||
int dsize;
|
||||
};
|
||||
static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer;
|
||||
static int uprobe_buffer_refcnt;
|
||||
#define MAX_UCB_BUFFER_SIZE PAGE_SIZE
|
||||
|
||||
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)
|
||||
{
|
||||
if (!ucb)
|
||||
return;
|
||||
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,
|
||||
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 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);
|
||||
|
||||
if (WARN_ON_ONCE(tu->tp.size + dsize > PAGE_SIZE))
|
||||
return;
|
||||
|
||||
if (trace_trigger_soft_disabled(trace_file))
|
||||
return;
|
||||
|
||||
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);
|
||||
if (!entry)
|
||||
return;
|
||||
|
@ -977,23 +1007,26 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
|
|||
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);
|
||||
}
|
||||
|
||||
/* uprobe handler */
|
||||
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 uprobe_cpu_buffer *ucb;
|
||||
|
||||
if (is_ret_probe(tu))
|
||||
return 0;
|
||||
|
||||
ucb = prepare_uprobe_buffer(tu, regs, ucbp);
|
||||
|
||||
rcu_read_lock();
|
||||
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();
|
||||
|
||||
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,
|
||||
struct pt_regs *regs,
|
||||
struct uprobe_cpu_buffer *ucb, int dsize)
|
||||
struct uprobe_cpu_buffer **ucbp)
|
||||
{
|
||||
struct event_file_link *link;
|
||||
struct uprobe_cpu_buffer *ucb;
|
||||
|
||||
ucb = prepare_uprobe_buffer(tu, regs, ucbp);
|
||||
|
||||
rcu_read_lock();
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -1335,10 +1371,11 @@ static bool uprobe_perf_filter(struct uprobe_consumer *uc,
|
|||
|
||||
static void __uprobe_perf_func(struct trace_uprobe *tu,
|
||||
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 uprobe_trace_entry_head *entry;
|
||||
struct uprobe_cpu_buffer *ucb;
|
||||
struct hlist_head *head;
|
||||
void *data;
|
||||
int size, esize;
|
||||
|
@ -1356,7 +1393,8 @@ static void __uprobe_perf_func(struct trace_uprobe *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);
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
|
||||
return;
|
||||
|
@ -1379,13 +1417,10 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
|
|||
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) {
|
||||
int len = tu->tp.size + dsize;
|
||||
|
||||
memset(data + len, 0, size - esize - len);
|
||||
}
|
||||
if (size - esize > ucb->dsize)
|
||||
memset(data + ucb->dsize, 0, size - esize - ucb->dsize);
|
||||
|
||||
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
|
||||
head, NULL);
|
||||
|
@ -1395,21 +1430,21 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
|
|||
|
||||
/* uprobe profile handler */
|
||||
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))
|
||||
return UPROBE_HANDLER_REMOVE;
|
||||
|
||||
if (!is_ret_probe(tu))
|
||||
__uprobe_perf_func(tu, 0, regs, ucb, dsize);
|
||||
__uprobe_perf_func(tu, 0, regs, ucbp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func,
|
||||
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,
|
||||
|
@ -1474,11 +1509,9 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
|
|||
{
|
||||
struct trace_uprobe *tu;
|
||||
struct uprobe_dispatch_data udd;
|
||||
struct uprobe_cpu_buffer *ucb;
|
||||
int dsize, esize;
|
||||
struct uprobe_cpu_buffer *ucb = NULL;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
tu = container_of(con, struct trace_uprobe, consumer);
|
||||
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))
|
||||
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))
|
||||
ret |= uprobe_trace_func(tu, regs, ucb, dsize);
|
||||
ret |= uprobe_trace_func(tu, regs, &ucb);
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
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
|
||||
uprobe_buffer_put(ucb);
|
||||
return ret;
|
||||
|
@ -1512,8 +1539,7 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
|
|||
{
|
||||
struct trace_uprobe *tu;
|
||||
struct uprobe_dispatch_data udd;
|
||||
struct uprobe_cpu_buffer *ucb;
|
||||
int dsize, esize;
|
||||
struct uprobe_cpu_buffer *ucb = NULL;
|
||||
|
||||
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))
|
||||
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))
|
||||
uretprobe_trace_func(tu, func, regs, ucb, dsize);
|
||||
uretprobe_trace_func(tu, func, regs, &ucb);
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
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
|
||||
uprobe_buffer_put(ucb);
|
||||
return 0;
|
||||
|
|
|
@ -17,47 +17,43 @@
|
|||
#include <net/ip.h>
|
||||
#include <net/l3mdev.h>
|
||||
|
||||
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
|
||||
int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr,
|
||||
u32 mark)
|
||||
static struct dst_entry *__xfrm4_dst_lookup(struct flowi4 *fl4,
|
||||
const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
struct rtable *rt;
|
||||
|
||||
memset(fl4, 0, sizeof(*fl4));
|
||||
fl4->daddr = daddr->a4;
|
||||
fl4->flowi4_tos = tos;
|
||||
fl4->flowi4_l3mdev = l3mdev_master_ifindex_by_index(net, oif);
|
||||
fl4->flowi4_mark = mark;
|
||||
if (saddr)
|
||||
fl4->saddr = saddr->a4;
|
||||
fl4->daddr = params->daddr->a4;
|
||||
fl4->flowi4_tos = params->tos;
|
||||
fl4->flowi4_l3mdev = l3mdev_master_ifindex_by_index(params->net,
|
||||
params->oif);
|
||||
fl4->flowi4_mark = params->mark;
|
||||
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))
|
||||
return &rt->dst;
|
||||
|
||||
return ERR_CAST(rt);
|
||||
}
|
||||
|
||||
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr,
|
||||
u32 mark)
|
||||
static struct dst_entry *xfrm4_dst_lookup(const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
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,
|
||||
xfrm_address_t *saddr, xfrm_address_t *daddr,
|
||||
u32 mark)
|
||||
static int xfrm4_get_saddr(xfrm_address_t *saddr,
|
||||
const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
struct dst_entry *dst;
|
||||
struct flowi4 fl4;
|
||||
|
||||
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark);
|
||||
dst = __xfrm4_dst_lookup(&fl4, params);
|
||||
if (IS_ERR(dst))
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
|
|
|
@ -23,23 +23,24 @@
|
|||
#include <net/ip6_route.h>
|
||||
#include <net/l3mdev.h>
|
||||
|
||||
static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr,
|
||||
u32 mark)
|
||||
static struct dst_entry *xfrm6_dst_lookup(const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
struct flowi6 fl6;
|
||||
struct dst_entry *dst;
|
||||
int err;
|
||||
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
fl6.flowi6_l3mdev = l3mdev_master_ifindex_by_index(net, oif);
|
||||
fl6.flowi6_mark = mark;
|
||||
memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
|
||||
if (saddr)
|
||||
memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr));
|
||||
fl6.flowi6_l3mdev = l3mdev_master_ifindex_by_index(params->net,
|
||||
params->oif);
|
||||
fl6.flowi6_mark = params->mark;
|
||||
memcpy(&fl6.daddr, params->daddr, sizeof(fl6.daddr));
|
||||
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;
|
||||
if (dst->error) {
|
||||
|
@ -50,15 +51,14 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
|
|||
return dst;
|
||||
}
|
||||
|
||||
static int xfrm6_get_saddr(struct net *net, int oif,
|
||||
xfrm_address_t *saddr, xfrm_address_t *daddr,
|
||||
u32 mark)
|
||||
static int xfrm6_get_saddr(xfrm_address_t *saddr,
|
||||
const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
struct dst_entry *dst;
|
||||
struct net_device *dev;
|
||||
struct inet6_dev *idev;
|
||||
|
||||
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark);
|
||||
dst = xfrm6_dst_lookup(params);
|
||||
if (IS_ERR(dst))
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
|
@ -68,7 +68,8 @@ static int xfrm6_get_saddr(struct net *net, int oif,
|
|||
return -EHOSTUNREACH;
|
||||
}
|
||||
dev = idev->dev;
|
||||
ipv6_dev_get_saddr(dev_net(dev), dev, &daddr->in6, 0, &saddr->in6);
|
||||
ipv6_dev_get_saddr(dev_net(dev), dev, ¶ms->daddr->in6, 0,
|
||||
&saddr->in6);
|
||||
dst_release(dst);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ static unsigned int nf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb,
|
|||
struct bpf_nf_link {
|
||||
struct bpf_link link;
|
||||
struct nf_hook_ops hook_ops;
|
||||
netns_tracker ns_tracker;
|
||||
struct net *net;
|
||||
u32 dead;
|
||||
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)) {
|
||||
nf_unregister_net_hook(nf_link->net, &nf_link->hook_ops);
|
||||
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;
|
||||
}
|
||||
|
||||
get_net_track(net, &link->ns_tracker, GFP_KERNEL);
|
||||
|
||||
return bpf_link_settle(&link_primer);
|
||||
}
|
||||
|
||||
|
|
|
@ -505,19 +505,28 @@ static void dev_watchdog(struct timer_list *t)
|
|||
unsigned int timedout_ms = 0;
|
||||
unsigned int i;
|
||||
unsigned long trans_start;
|
||||
unsigned long oldest_start = jiffies;
|
||||
|
||||
for (i = 0; i < dev->num_tx_queues; i++) {
|
||||
struct netdev_queue *txq;
|
||||
|
||||
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);
|
||||
if (netif_xmit_stopped(txq) &&
|
||||
time_after(jiffies, (trans_start +
|
||||
dev->watchdog_timeo))) {
|
||||
|
||||
if (time_after(jiffies, trans_start + dev->watchdog_timeo)) {
|
||||
timedout_ms = jiffies_to_msecs(jiffies - trans_start);
|
||||
atomic_long_inc(&txq->trans_timeout);
|
||||
break;
|
||||
}
|
||||
if (time_after(oldest_start, trans_start))
|
||||
oldest_start = trans_start;
|
||||
}
|
||||
|
||||
if (unlikely(timedout_ms)) {
|
||||
|
@ -530,7 +539,7 @@ static void dev_watchdog(struct timer_list *t)
|
|||
netif_unfreeze_queues(dev);
|
||||
}
|
||||
if (!mod_timer(&dev->watchdog_timer,
|
||||
round_jiffies(jiffies +
|
||||
round_jiffies(oldest_start +
|
||||
dev->watchdog_timeo)))
|
||||
release = false;
|
||||
}
|
||||
|
|
|
@ -263,6 +263,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
|
|||
|
||||
dev = dev_get_by_index(net, xuo->ifindex);
|
||||
if (!dev) {
|
||||
struct xfrm_dst_lookup_params params;
|
||||
|
||||
if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
|
||||
saddr = &x->props.saddr;
|
||||
daddr = &x->id.daddr;
|
||||
|
@ -271,9 +273,12 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
|
|||
daddr = &x->props.saddr;
|
||||
}
|
||||
|
||||
dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr,
|
||||
x->props.family,
|
||||
xfrm_smark_get(0, x));
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.net = net;
|
||||
params.saddr = saddr;
|
||||
params.daddr = daddr;
|
||||
params.mark = xfrm_smark_get(0, x);
|
||||
dst = __xfrm_dst_lookup(x->props.family, ¶ms);
|
||||
if (IS_ERR(dst))
|
||||
return (is_packet_offload) ? -EINVAL : 0;
|
||||
|
||||
|
|
|
@ -251,10 +251,8 @@ static const struct xfrm_if_cb *xfrm_if_get_cb(void)
|
|||
return rcu_dereference(xfrm_if_cb);
|
||||
}
|
||||
|
||||
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr,
|
||||
int family, u32 mark)
|
||||
struct dst_entry *__xfrm_dst_lookup(int family,
|
||||
const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
const struct xfrm_policy_afinfo *afinfo;
|
||||
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))
|
||||
return ERR_PTR(-EAFNOSUPPORT);
|
||||
|
||||
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark);
|
||||
dst = afinfo->dst_lookup(params);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -277,6 +275,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
|
|||
xfrm_address_t *prev_daddr,
|
||||
int family, u32 mark)
|
||||
{
|
||||
struct xfrm_dst_lookup_params params;
|
||||
struct net *net = xs_net(x);
|
||||
xfrm_address_t *saddr = &x->props.saddr;
|
||||
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;
|
||||
}
|
||||
|
||||
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, ¶ms);
|
||||
|
||||
if (!IS_ERR(dst)) {
|
||||
if (prev_saddr != saddr)
|
||||
|
@ -2424,15 +2445,15 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
|
|||
}
|
||||
|
||||
static int
|
||||
xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local,
|
||||
xfrm_address_t *remote, unsigned short family, u32 mark)
|
||||
xfrm_get_saddr(unsigned short family, xfrm_address_t *saddr,
|
||||
const struct xfrm_dst_lookup_params *params)
|
||||
{
|
||||
int err;
|
||||
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
||||
|
||||
if (unlikely(afinfo == NULL))
|
||||
return -EINVAL;
|
||||
err = afinfo->get_saddr(net, oif, local, remote, mark);
|
||||
err = afinfo->get_saddr(saddr, params);
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
@ -2461,9 +2482,14 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
|
|||
remote = &tmpl->id.daddr;
|
||||
local = &tmpl->saddr;
|
||||
if (xfrm_addr_any(local, tmpl->encap_family)) {
|
||||
error = xfrm_get_saddr(net, fl->flowi_oif,
|
||||
&tmp, remote,
|
||||
tmpl->encap_family, 0);
|
||||
struct xfrm_dst_lookup_params params;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.net = net;
|
||||
params.oif = fl->flowi_oif;
|
||||
params.daddr = remote;
|
||||
error = xfrm_get_saddr(tmpl->encap_family, &tmp,
|
||||
¶ms);
|
||||
if (error)
|
||||
goto fail;
|
||||
local = &tmp;
|
||||
|
|
|
@ -444,6 +444,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
|||
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,
|
||||
.matches = {
|
||||
|
|
|
@ -909,7 +909,7 @@ static const struct reg_default rx_defaults[] = {
|
|||
{ CDC_RX_BCL_VBAT_PK_EST2, 0x01 },
|
||||
{ CDC_RX_BCL_VBAT_PK_EST3, 0x40 },
|
||||
{ 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_TAC2, 0x18 },
|
||||
{ CDC_RX_BCL_VBAT_TAC3, 0x18 },
|
||||
|
|
|
@ -604,6 +604,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
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 */
|
||||
if (tx)
|
||||
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),
|
||||
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);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
|
||||
/* 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_FCOMB_SHIFT BIT(26)
|
||||
#define FSL_SAI_CR4_FCOMB_SOFT BIT(27)
|
||||
|
|
|
@ -153,6 +153,7 @@ static int sm8250_platform_probe(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id snd_sm8250_dt_match[] = {
|
||||
{.compatible = "qcom,sm8250-sndcard"},
|
||||
{.compatible = "qcom,qrb4210-rb2-sndcard"},
|
||||
{.compatible = "qcom,qrb5165-rb5-sndcard"},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -34,7 +34,9 @@ check_error 'f vfs_read ^$stack10000' # BAD_STACK_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
|
||||
fi
|
||||
check_error 'f vfs_read ^$none_var' # 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 +0(^$arg*)' # BAD_VAR_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
|
||||
fi
|
||||
check_error 'f vfs_read ^hoge' # NO_BTFARG
|
||||
check_error 'f kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)
|
||||
check_error 'f kfree%return ^$retval' # NO_RETVAL
|
||||
|
|
|
@ -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 +0(^$arg*)' # BAD_VAR_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
|
||||
fi
|
||||
check_error 'p vfs_read+8 ^$arg*' # NOFENTRY_ARGS
|
||||
check_error 'p vfs_read ^hoge' # NO_BTFARG
|
||||
check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)
|
||||
|
|
Loading…
Reference in New Issue
Block a user