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

Steps on the way to 6.6.59

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

View File

@ -10,7 +10,7 @@
#
# Copyright (C) 1995-2001 by Russell King
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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &reg);
if (err)

View File

@ -1381,10 +1381,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
be_get_wrb_params_from_skb(adapter, skb, &wrb_params);
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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1771,7 +1771,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
// can rename the link if it knows better.
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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,6 +24,9 @@
#include "xhci-ext-caps.h"
#include "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

View File

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

View File

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

View File

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

View File

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

View File

@ -166,13 +166,19 @@ static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter)
*/
static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter)
{
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);

View File

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

View File

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

View File

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

View File

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

View File

@ -157,8 +157,9 @@ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
extern int udf_setsize(struct inode *, loff_t);
extern 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 */

View File

@ -3402,6 +3402,12 @@ static inline void netif_tx_wake_all_queues(struct net_device *dev)
static __always_inline void netif_tx_stop_queue(struct netdev_queue *dev_queue)
{
/* 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);
/*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -275,7 +275,7 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
}
trace_probe_log_err(offset, NO_EVENT_NAME);
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, &param);
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:

View File

@ -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"), \

View File

@ -54,7 +54,7 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
* If dest is NULL, don't store result and return required dynamic data size.
*/
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;

View File

@ -211,8 +211,8 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
/* Note that we don't verify it, since the code does not come from user space */
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;

View File

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

View File

@ -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, &params->daddr->in6, 0,
&saddr->in6);
dst_release(dst);
return 0;
}

View File

@ -23,6 +23,7 @@ static unsigned int nf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb,
struct bpf_nf_link {
struct bpf_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);
}

View File

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

View File

@ -263,6 +263,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
dev = dev_get_by_index(net, xuo->ifindex);
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(&params, 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, &params);
if (IS_ERR(dst))
return (is_packet_offload) ? -EINVAL : 0;

View File

@ -251,10 +251,8 @@ static const struct xfrm_if_cb *xfrm_if_get_cb(void)
return rcu_dereference(xfrm_if_cb);
}
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, &params);
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(&params, 0, sizeof(params));
params.net = net;
params.oif = fl->flowi_oif;
params.daddr = remote;
error = xfrm_get_saddr(tmpl->encap_family, &tmp,
&params);
if (error)
goto fail;
local = &tmp;

View File

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

View File

@ -909,7 +909,7 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_BCL_VBAT_PK_EST2, 0x01 },
{ CDC_RX_BCL_VBAT_PK_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 },

View File

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

View File

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

View File

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

View File

@ -34,7 +34,9 @@ check_error 'f vfs_read ^$stack10000' # BAD_STACK_NUM
check_error 'f vfs_read ^$arg10000' # BAD_ARG_NUM
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

View File

@ -108,7 +108,9 @@ if grep -q "<argname>" README; then
check_error 'p vfs_read args=^$arg*' # BAD_VAR_ARGS
check_error 'p vfs_read +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)