mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 04:42:04 -04:00
Merge "defconfig: lahaina: remove CONFIG_LEDS_CLASS_FLASH & CONFIG_LEDS_TRIGGER_TIMER"
This commit is contained in:
commit
da2e3647bf
23 changed files with 3923 additions and 6396 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1326,6 +1326,8 @@
|
|||
kvmalloc_node
|
||||
kzfree
|
||||
led_blink_set
|
||||
led_classdev_flash_register_ext
|
||||
led_classdev_flash_unregister
|
||||
led_classdev_register_ext
|
||||
led_classdev_unregister
|
||||
led_get_default_pattern
|
||||
|
|
|
|||
|
|
@ -2487,3 +2487,13 @@
|
|||
|
||||
# required by sprd_sip_svc.ko
|
||||
__arm_smccc_smc
|
||||
|
||||
# required by mali_gondul.ko
|
||||
bpf_trace_run5
|
||||
ktime_get_raw
|
||||
of_machine_is_compatible
|
||||
_totalram_pages
|
||||
trace_output_call
|
||||
trace_print_array_seq
|
||||
trace_print_flags_seq
|
||||
vmf_insert_pfn_prot
|
||||
|
|
|
|||
3
android/abi_gki_aarch64_workarounds
Normal file
3
android/abi_gki_aarch64_workarounds
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[abi_whitelist]
|
||||
# b/167230325
|
||||
ehci_handshake
|
||||
2
arch/arm64/configs/vendor/lahaina_GKI.config
vendored
2
arch/arm64/configs/vendor/lahaina_GKI.config
vendored
|
|
@ -136,10 +136,8 @@ CONFIG_QCOM_LAZY_MAPPING=m
|
|||
CONFIG_MFD_SPMI_PMIC=m
|
||||
CONFIG_PWM_QTI_LPG=m
|
||||
CONFIG_INTERCONNECT_QCOM_EPSS_L3=m
|
||||
CONFIG_LEDS_CLASS_FLASH=m
|
||||
CONFIG_LEDS_QTI_FLASH=m
|
||||
CONFIG_LEDS_QTI_TRI_LED=m
|
||||
CONFIG_LEDS_TRIGGER_TIMER=m
|
||||
CONFIG_MSM_SPCOM=m
|
||||
CONFIG_MSM_ADSPRPC=m
|
||||
CONFIG_MSM_RDBG=m
|
||||
|
|
|
|||
|
|
@ -268,6 +268,19 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
|||
/* Needed by apm.c */
|
||||
void notrace restore_processor_state(void)
|
||||
{
|
||||
#ifdef __clang__
|
||||
// The following code snippet is copied from __restore_processor_state.
|
||||
// Its purpose is to prepare GS segment before the function is called.
|
||||
// Since the function is compiled with SCS on, it will use GS at its
|
||||
// entry.
|
||||
// TODO: Hack to be removed later when compiler bug is fixed.
|
||||
#ifdef CONFIG_X86_64
|
||||
wrmsrl(MSR_GS_BASE, saved_context.kernelmode_gs_base);
|
||||
#else
|
||||
loadsegment(fs, __KERNEL_PERCPU);
|
||||
loadsegment(gs, __KERNEL_STACK_CANARY);
|
||||
#endif
|
||||
#endif
|
||||
__restore_processor_state(&saved_context);
|
||||
}
|
||||
#ifdef CONFIG_X86_32
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ android/abi_gki_aarch64_qcom
|
|||
android/abi_gki_aarch64_sunxi
|
||||
android/abi_gki_aarch64_unisoc
|
||||
android/abi_gki_aarch64_vivo
|
||||
android/abi_gki_aarch64_workarounds
|
||||
"
|
||||
TRIM_NONLISTED_KMI=1
|
||||
KMI_SYMBOL_LIST_ADD_ONLY=1
|
||||
|
|
|
|||
|
|
@ -3318,7 +3318,7 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
|
||||
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
|
||||
tr->offsets_size, extra_buffers_size,
|
||||
!reply && (t->flags & TF_ONE_WAY));
|
||||
!reply && (t->flags & TF_ONE_WAY), current->tgid);
|
||||
if (IS_ERR(t->buffer)) {
|
||||
/*
|
||||
* -ESRCH indicates VMA cleared. The target is dying.
|
||||
|
|
|
|||
|
|
@ -339,12 +339,50 @@ static inline struct vm_area_struct *binder_alloc_get_vma(
|
|||
return vma;
|
||||
}
|
||||
|
||||
static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid)
|
||||
{
|
||||
/*
|
||||
* Find the amount and size of buffers allocated by the current caller;
|
||||
* The idea is that once we cross the threshold, whoever is responsible
|
||||
* for the low async space is likely to try to send another async txn,
|
||||
* and at some point we'll catch them in the act. This is more efficient
|
||||
* than keeping a map per pid.
|
||||
*/
|
||||
struct rb_node *n = alloc->free_buffers.rb_node;
|
||||
struct binder_buffer *buffer;
|
||||
size_t total_alloc_size = 0;
|
||||
size_t num_buffers = 0;
|
||||
|
||||
for (n = rb_first(&alloc->allocated_buffers); n != NULL;
|
||||
n = rb_next(n)) {
|
||||
buffer = rb_entry(n, struct binder_buffer, rb_node);
|
||||
if (buffer->pid != pid)
|
||||
continue;
|
||||
if (!buffer->async_transaction)
|
||||
continue;
|
||||
total_alloc_size += binder_alloc_buffer_size(alloc, buffer)
|
||||
+ sizeof(struct binder_buffer);
|
||||
num_buffers++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn if this pid has more than 50 transactions, or more than 50% of
|
||||
* async space (which is 25% of total buffer size).
|
||||
*/
|
||||
if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) {
|
||||
binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
|
||||
"%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n",
|
||||
alloc->pid, pid, num_buffers, total_alloc_size);
|
||||
}
|
||||
}
|
||||
|
||||
static struct binder_buffer *binder_alloc_new_buf_locked(
|
||||
struct binder_alloc *alloc,
|
||||
size_t data_size,
|
||||
size_t offsets_size,
|
||||
size_t extra_buffers_size,
|
||||
int is_async)
|
||||
int is_async,
|
||||
int pid)
|
||||
{
|
||||
struct rb_node *n = alloc->free_buffers.rb_node;
|
||||
struct binder_buffer *buffer;
|
||||
|
|
@ -487,11 +525,20 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
|
|||
buffer->offsets_size = offsets_size;
|
||||
buffer->async_transaction = is_async;
|
||||
buffer->extra_buffers_size = extra_buffers_size;
|
||||
buffer->pid = pid;
|
||||
if (is_async) {
|
||||
alloc->free_async_space -= size + sizeof(struct binder_buffer);
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
|
||||
"%d: binder_alloc_buf size %zd async free %zd\n",
|
||||
alloc->pid, size, alloc->free_async_space);
|
||||
if (alloc->free_async_space < alloc->buffer_size / 10) {
|
||||
/*
|
||||
* Start detecting spammers once we have less than 20%
|
||||
* of async space left (which is less than 10% of total
|
||||
* buffer size).
|
||||
*/
|
||||
debug_low_async_space_locked(alloc, pid);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
|
||||
|
|
@ -509,6 +556,7 @@ err_alloc_buf_struct_failed:
|
|||
* @offsets_size: user specified buffer offset
|
||||
* @extra_buffers_size: size of extra space for meta-data (eg, security context)
|
||||
* @is_async: buffer for async transaction
|
||||
* @pid: pid to attribute allocation to (used for debugging)
|
||||
*
|
||||
* Allocate a new buffer given the requested sizes. Returns
|
||||
* the kernel version of the buffer pointer. The size allocated
|
||||
|
|
@ -521,13 +569,14 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
|
|||
size_t data_size,
|
||||
size_t offsets_size,
|
||||
size_t extra_buffers_size,
|
||||
int is_async)
|
||||
int is_async,
|
||||
int pid)
|
||||
{
|
||||
struct binder_buffer *buffer;
|
||||
|
||||
mutex_lock(&alloc->mutex);
|
||||
buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
|
||||
extra_buffers_size, is_async);
|
||||
extra_buffers_size, is_async, pid);
|
||||
mutex_unlock(&alloc->mutex);
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ struct binder_transaction;
|
|||
* @offsets_size: size of array of offsets
|
||||
* @extra_buffers_size: size of space for other objects (like sg lists)
|
||||
* @user_data: user pointer to base of buffer space
|
||||
* @pid: pid to attribute the buffer to (caller)
|
||||
*
|
||||
* Bookkeeping structure for binder transaction buffers
|
||||
*/
|
||||
|
|
@ -51,6 +52,7 @@ struct binder_buffer {
|
|||
size_t offsets_size;
|
||||
size_t extra_buffers_size;
|
||||
void __user *user_data;
|
||||
int pid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -117,7 +119,8 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
|
|||
size_t data_size,
|
||||
size_t offsets_size,
|
||||
size_t extra_buffers_size,
|
||||
int is_async);
|
||||
int is_async,
|
||||
int pid);
|
||||
extern void binder_alloc_init(struct binder_alloc *alloc);
|
||||
extern int binder_alloc_shrinker_init(void);
|
||||
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
|
|||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
|
||||
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0);
|
||||
if (IS_ERR(buffers[i]) ||
|
||||
!check_buffer_pages_allocated(alloc, buffers[i],
|
||||
sizes[i])) {
|
||||
|
|
|
|||
|
|
@ -55,3 +55,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alter_rwsem_list_add);
|
|||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alter_futex_plist_add);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_is_fpsimd_save);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_ipi_stop);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_printk_store);
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ enum {
|
|||
NETIF_F_GSO_ESP_BIT, /* ... ESP with TSO */
|
||||
NETIF_F_GSO_UDP_BIT, /* ... UFO, deprecated except tuntap */
|
||||
NETIF_F_GSO_UDP_L4_BIT, /* ... UDP payload GSO (not UFO) */
|
||||
NETIF_F_GSO_FRAGLIST_BIT, /* ... Fraglist GSO */
|
||||
/**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */
|
||||
NETIF_F_GSO_UDP_L4_BIT,
|
||||
NETIF_F_GSO_FRAGLIST_BIT,
|
||||
|
||||
NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */
|
||||
NETIF_F_SCTP_CRC_BIT, /* SCTP checksum offload */
|
||||
|
|
@ -80,6 +81,7 @@ enum {
|
|||
|
||||
NETIF_F_GRO_HW_BIT, /* Hardware Generic receive offload */
|
||||
NETIF_F_HW_TLS_RECORD_BIT, /* Offload TLS record */
|
||||
NETIF_F_GRO_FRAGLIST_BIT, /* Fraglist GRO */
|
||||
|
||||
/*
|
||||
* Add your fresh new feature above and remember to update
|
||||
|
|
@ -150,6 +152,8 @@ enum {
|
|||
#define NETIF_F_GSO_UDP_L4 __NETIF_F(GSO_UDP_L4)
|
||||
#define NETIF_F_HW_TLS_TX __NETIF_F(HW_TLS_TX)
|
||||
#define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX)
|
||||
#define NETIF_F_GRO_FRAGLIST __NETIF_F(GRO_FRAGLIST)
|
||||
#define NETIF_F_GSO_FRAGLIST __NETIF_F(GSO_FRAGLIST)
|
||||
|
||||
/* Finds the next feature with the highest number of the range of start till 0.
|
||||
*/
|
||||
|
|
@ -226,6 +230,9 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start)
|
|||
/* changeable features with no special hardware requirements */
|
||||
#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
|
||||
|
||||
/* Changeable features with no special hardware requirements that defaults to off. */
|
||||
#define NETIF_F_SOFT_FEATURES_OFF NETIF_F_GRO_FRAGLIST
|
||||
|
||||
#define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
|
||||
NETIF_F_HW_VLAN_CTAG_RX | \
|
||||
NETIF_F_HW_VLAN_CTAG_TX | \
|
||||
|
|
|
|||
|
|
@ -2350,7 +2350,8 @@ struct napi_gro_cb {
|
|||
/* Number of gro_receive callbacks this packet already went through */
|
||||
u8 recursion_counter:4;
|
||||
|
||||
/* 1 bit hole */
|
||||
/* GRO is done by frag_list pointer chaining. */
|
||||
u8 is_flist:1;
|
||||
|
||||
/* used to support CHECKSUM_COMPLETE for tunneling protocols */
|
||||
__wsum csum;
|
||||
|
|
@ -2705,6 +2706,7 @@ struct net_device *dev_get_by_napi_id(unsigned int napi_id);
|
|||
int netdev_get_name(struct net *net, char *name, int ifindex);
|
||||
int dev_restart(struct net_device *dev);
|
||||
int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb);
|
||||
int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb);
|
||||
|
||||
static inline unsigned int skb_gro_offset(const struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -4572,6 +4574,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
|
|||
BUILD_BUG_ON(SKB_GSO_ESP != (NETIF_F_GSO_ESP >> NETIF_F_GSO_SHIFT));
|
||||
BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_GSO_UDP >> NETIF_F_GSO_SHIFT));
|
||||
BUILD_BUG_ON(SKB_GSO_UDP_L4 != (NETIF_F_GSO_UDP_L4 >> NETIF_F_GSO_SHIFT));
|
||||
BUILD_BUG_ON(SKB_GSO_FRAGLIST != (NETIF_F_GSO_FRAGLIST >> NETIF_F_GSO_SHIFT));
|
||||
|
||||
return (features & feature) == feature;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -593,6 +593,8 @@ enum {
|
|||
SKB_GSO_UDP = 1 << 16,
|
||||
|
||||
SKB_GSO_UDP_L4 = 1 << 17,
|
||||
|
||||
SKB_GSO_FRAGLIST = 1 << 18,
|
||||
};
|
||||
|
||||
#if BITS_PER_LONG > 32
|
||||
|
|
@ -3529,6 +3531,8 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet);
|
|||
bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu);
|
||||
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
|
||||
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
|
||||
struct sk_buff *skb_segment_list(struct sk_buff *skb, netdev_features_t features,
|
||||
unsigned int offset);
|
||||
struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
|
||||
int skb_ensure_writable(struct sk_buff *skb, int write_len);
|
||||
int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci);
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ typedef struct sock *(*udp_lookup_t)(struct sk_buff *skb, __be16 sport,
|
|||
__be16 dport);
|
||||
|
||||
struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
|
||||
struct udphdr *uh, udp_lookup_t lookup);
|
||||
struct udphdr *uh, struct sock *sk);
|
||||
int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup);
|
||||
|
||||
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@
|
|||
#include <trace/hooks/vendor_hooks.h>
|
||||
|
||||
#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS)
|
||||
|
||||
struct pt_regs;
|
||||
DECLARE_HOOK(android_vh_ipi_stop,
|
||||
TP_PROTO(struct pt_regs *regs),
|
||||
TP_ARGS(regs))
|
||||
|
||||
DECLARE_HOOK(android_vh_printk_store,
|
||||
TP_PROTO(int facility, int level),
|
||||
TP_ARGS(facility, level))
|
||||
#else
|
||||
#define trace_android_vh_ipi_stop(regs)
|
||||
#define trace_android_vh_printk_store(facility, level)
|
||||
#endif
|
||||
|
||||
#endif /* _TRACE_HOOK_DEBUG_H */
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@
|
|||
#include <trace/events/initcall.h>
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/printk.h>
|
||||
#undef CREATE_TRACE_POINTS
|
||||
#include <trace/hooks/debug.h>
|
||||
|
||||
#include "console_cmdline.h"
|
||||
#include "braille.h"
|
||||
|
|
@ -2051,6 +2053,7 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|||
pending_output = (curr_log_seq != log_next_seq);
|
||||
logbuf_unlock_irqrestore(flags);
|
||||
|
||||
trace_android_vh_printk_store(facility, level);
|
||||
/* If called from the scheduler, we can not call up(). */
|
||||
if (!in_sched && pending_output) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -3032,7 +3032,7 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
|
|||
|
||||
segs = skb_mac_gso_segment(skb, features);
|
||||
|
||||
if (unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
|
||||
if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
|
||||
skb_warn_bad_offload(skb);
|
||||
|
||||
return segs;
|
||||
|
|
@ -9042,7 +9042,7 @@ int register_netdevice(struct net_device *dev)
|
|||
/* Transfer changeable features to wanted_features and enable
|
||||
* software offloads (GSO and GRO).
|
||||
*/
|
||||
dev->hw_features |= NETIF_F_SOFT_FEATURES;
|
||||
dev->hw_features |= (NETIF_F_SOFT_FEATURES | NETIF_F_SOFT_FEATURES_OFF);
|
||||
dev->features |= NETIF_F_SOFT_FEATURES;
|
||||
|
||||
if (dev->netdev_ops->ndo_udp_tunnel_add) {
|
||||
|
|
|
|||
|
|
@ -3640,6 +3640,97 @@ static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb)
|
|||
return head_frag;
|
||||
}
|
||||
|
||||
struct sk_buff *skb_segment_list(struct sk_buff *skb,
|
||||
netdev_features_t features,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct sk_buff *list_skb = skb_shinfo(skb)->frag_list;
|
||||
unsigned int tnl_hlen = skb_tnl_header_len(skb);
|
||||
unsigned int delta_truesize = 0;
|
||||
unsigned int delta_len = 0;
|
||||
struct sk_buff *tail = NULL;
|
||||
struct sk_buff *nskb;
|
||||
|
||||
skb_push(skb, -skb_network_offset(skb) + offset);
|
||||
|
||||
skb_shinfo(skb)->frag_list = NULL;
|
||||
|
||||
do {
|
||||
nskb = list_skb;
|
||||
list_skb = list_skb->next;
|
||||
|
||||
if (!tail)
|
||||
skb->next = nskb;
|
||||
else
|
||||
tail->next = nskb;
|
||||
|
||||
tail = nskb;
|
||||
|
||||
delta_len += nskb->len;
|
||||
delta_truesize += nskb->truesize;
|
||||
|
||||
skb_push(nskb, -skb_network_offset(nskb) + offset);
|
||||
|
||||
__copy_skb_header(nskb, skb);
|
||||
|
||||
skb_headers_offset_update(nskb, skb_headroom(nskb) - skb_headroom(skb));
|
||||
skb_copy_from_linear_data_offset(skb, -tnl_hlen,
|
||||
nskb->data - tnl_hlen,
|
||||
offset + tnl_hlen);
|
||||
|
||||
if (skb_needs_linearize(nskb, features) &&
|
||||
__skb_linearize(nskb))
|
||||
goto err_linearize;
|
||||
|
||||
} while (list_skb);
|
||||
|
||||
skb->truesize = skb->truesize - delta_truesize;
|
||||
skb->data_len = skb->data_len - delta_len;
|
||||
skb->len = skb->len - delta_len;
|
||||
|
||||
skb_gso_reset(skb);
|
||||
|
||||
skb->prev = tail;
|
||||
|
||||
if (skb_needs_linearize(skb, features) &&
|
||||
__skb_linearize(skb))
|
||||
goto err_linearize;
|
||||
|
||||
skb_get(skb);
|
||||
|
||||
return skb;
|
||||
|
||||
err_linearize:
|
||||
kfree_skb_list(skb->next);
|
||||
skb->next = NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skb_segment_list);
|
||||
|
||||
int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
|
||||
{
|
||||
if (unlikely(p->len + skb->len >= 65536))
|
||||
return -E2BIG;
|
||||
|
||||
if (NAPI_GRO_CB(p)->last == p)
|
||||
skb_shinfo(p)->frag_list = skb;
|
||||
else
|
||||
NAPI_GRO_CB(p)->last->next = skb;
|
||||
|
||||
skb_pull(skb, skb_gro_offset(skb));
|
||||
|
||||
NAPI_GRO_CB(p)->last = skb;
|
||||
NAPI_GRO_CB(p)->count++;
|
||||
p->data_len += skb->len;
|
||||
p->truesize += skb->truesize;
|
||||
p->len += skb->len;
|
||||
|
||||
NAPI_GRO_CB(skb)->same_flow = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skb_gro_receive_list);
|
||||
|
||||
/**
|
||||
* skb_segment - Perform protocol segmentation on skb.
|
||||
* @head_skb: buffer to segment
|
||||
|
|
|
|||
|
|
@ -184,6 +184,20 @@ out_unlock:
|
|||
}
|
||||
EXPORT_SYMBOL(skb_udp_tunnel_segment);
|
||||
|
||||
static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
unsigned int mss = skb_shinfo(skb)->gso_size;
|
||||
|
||||
skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
|
||||
if (IS_ERR(skb))
|
||||
return skb;
|
||||
|
||||
udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
|
|
@ -196,6 +210,9 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
|
|||
__sum16 check;
|
||||
__be16 newlen;
|
||||
|
||||
if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
|
||||
return __udp_gso_segment_list(gso_skb, features);
|
||||
|
||||
mss = skb_shinfo(gso_skb)->gso_size;
|
||||
if (gso_skb->len <= sizeof(*uh) + mss)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
@ -354,6 +371,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
|
|||
struct udphdr *uh2;
|
||||
struct sk_buff *p;
|
||||
unsigned int ulen;
|
||||
int ret = 0;
|
||||
|
||||
/* requires non zero csum, for symmetry with GSO */
|
||||
if (!uh->check) {
|
||||
|
|
@ -369,7 +387,6 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
|
|||
}
|
||||
/* pull encapsulating udp header */
|
||||
skb_gro_pull(skb, sizeof(struct udphdr));
|
||||
skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
|
||||
|
||||
list_for_each_entry(p, head, list) {
|
||||
if (!NAPI_GRO_CB(p)->same_flow)
|
||||
|
|
@ -383,14 +400,40 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (NAPI_GRO_CB(skb)->is_flist != NAPI_GRO_CB(p)->is_flist) {
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Terminate the flow on len mismatch or if it grow "too much".
|
||||
* Under small packet flood GRO count could elsewhere grow a lot
|
||||
* leading to excessive truesize values.
|
||||
* On len mismatch merge the first packet shorter than gso_size,
|
||||
* otherwise complete the GRO packet.
|
||||
*/
|
||||
if (ulen > ntohs(uh2->len) || skb_gro_receive(p, skb) ||
|
||||
ulen != ntohs(uh2->len) ||
|
||||
if (ulen > ntohs(uh2->len)) {
|
||||
pp = p;
|
||||
} else {
|
||||
if (NAPI_GRO_CB(skb)->is_flist) {
|
||||
if (!pskb_may_pull(skb, skb_gro_offset(skb))) {
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
return NULL;
|
||||
}
|
||||
if ((skb->ip_summed != p->ip_summed) ||
|
||||
(skb->csum_level != p->csum_level)) {
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
return NULL;
|
||||
}
|
||||
ret = skb_gro_receive_list(p, skb);
|
||||
} else {
|
||||
skb_gro_postpull_rcsum(skb, uh,
|
||||
sizeof(struct udphdr));
|
||||
|
||||
ret = skb_gro_receive(p, skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret || ulen != ntohs(uh2->len) ||
|
||||
NAPI_GRO_CB(p)->count >= UDP_GRO_CNT_MAX)
|
||||
pp = p;
|
||||
|
||||
|
|
@ -401,36 +444,30 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
INDIRECT_CALLABLE_DECLARE(struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
|
||||
__be16 sport, __be16 dport));
|
||||
struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
|
||||
struct udphdr *uh, udp_lookup_t lookup)
|
||||
struct udphdr *uh, struct sock *sk)
|
||||
{
|
||||
struct sk_buff *pp = NULL;
|
||||
struct sk_buff *p;
|
||||
struct udphdr *uh2;
|
||||
unsigned int off = skb_gro_offset(skb);
|
||||
int flush = 1;
|
||||
struct sock *sk;
|
||||
|
||||
rcu_read_lock();
|
||||
sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb,
|
||||
udp4_lib_lookup_skb, skb, uh->source, uh->dest);
|
||||
if (!sk)
|
||||
goto out_unlock;
|
||||
NAPI_GRO_CB(skb)->is_flist = 0;
|
||||
if (skb->dev->features & NETIF_F_GRO_FRAGLIST)
|
||||
NAPI_GRO_CB(skb)->is_flist = sk ? !udp_sk(sk)->gro_enabled: 1;
|
||||
|
||||
if (udp_sk(sk)->gro_enabled) {
|
||||
if ((sk && udp_sk(sk)->gro_enabled) || NAPI_GRO_CB(skb)->is_flist) {
|
||||
pp = call_gro_receive(udp_gro_receive_segment, head, skb);
|
||||
rcu_read_unlock();
|
||||
return pp;
|
||||
}
|
||||
|
||||
if (NAPI_GRO_CB(skb)->encap_mark ||
|
||||
if (!sk || NAPI_GRO_CB(skb)->encap_mark ||
|
||||
(skb->ip_summed != CHECKSUM_PARTIAL &&
|
||||
NAPI_GRO_CB(skb)->csum_cnt == 0 &&
|
||||
!NAPI_GRO_CB(skb)->csum_valid) ||
|
||||
!udp_sk(sk)->gro_receive)
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
/* mark that this skb passed once through the tunnel gro layer */
|
||||
NAPI_GRO_CB(skb)->encap_mark = 1;
|
||||
|
|
@ -457,8 +494,7 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
|
|||
skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
|
||||
pp = call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
|
||||
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
skb_gro_flush_final(skb, pp, flush);
|
||||
return pp;
|
||||
}
|
||||
|
|
@ -468,8 +504,10 @@ INDIRECT_CALLABLE_SCOPE
|
|||
struct sk_buff *udp4_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||
{
|
||||
struct udphdr *uh = udp_gro_udphdr(skb);
|
||||
struct sk_buff *pp;
|
||||
struct sock *sk;
|
||||
|
||||
if (unlikely(!uh) || !static_branch_unlikely(&udp_encap_needed_key))
|
||||
if (unlikely(!uh))
|
||||
goto flush;
|
||||
|
||||
/* Don't bother verifying checksum if we're going to flush anyway. */
|
||||
|
|
@ -484,7 +522,11 @@ struct sk_buff *udp4_gro_receive(struct list_head *head, struct sk_buff *skb)
|
|||
inet_gro_compute_pseudo);
|
||||
skip:
|
||||
NAPI_GRO_CB(skb)->is_ipv6 = 0;
|
||||
return udp_gro_receive(head, skb, uh, udp4_lib_lookup_skb);
|
||||
rcu_read_lock();
|
||||
sk = static_branch_unlikely(&udp_encap_needed_key) ? udp4_lib_lookup_skb(skb, uh->source, uh->dest) : NULL;
|
||||
pp = udp_gro_receive(head, skb, uh, sk);
|
||||
rcu_read_unlock();
|
||||
return pp;
|
||||
|
||||
flush:
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
|
|
@ -517,9 +559,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
|
|||
rcu_read_lock();
|
||||
sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb,
|
||||
udp4_lib_lookup_skb, skb, uh->source, uh->dest);
|
||||
if (sk && udp_sk(sk)->gro_enabled) {
|
||||
err = udp_gro_complete_segment(skb);
|
||||
} else if (sk && udp_sk(sk)->gro_complete) {
|
||||
if (sk && udp_sk(sk)->gro_complete) {
|
||||
skb_shinfo(skb)->gso_type = uh->check ? SKB_GSO_UDP_TUNNEL_CSUM
|
||||
: SKB_GSO_UDP_TUNNEL;
|
||||
|
||||
|
|
@ -529,6 +569,8 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
|
|||
skb->encapsulation = 1;
|
||||
err = udp_sk(sk)->gro_complete(sk, skb,
|
||||
nhoff + sizeof(struct udphdr));
|
||||
} else {
|
||||
err = udp_gro_complete_segment(skb);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
@ -544,6 +586,23 @@ INDIRECT_CALLABLE_SCOPE int udp4_gro_complete(struct sk_buff *skb, int nhoff)
|
|||
const struct iphdr *iph = ip_hdr(skb);
|
||||
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
|
||||
|
||||
if (NAPI_GRO_CB(skb)->is_flist) {
|
||||
uh->len = htons(skb->len - nhoff);
|
||||
|
||||
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
|
||||
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
|
||||
if (skb->csum_level < SKB_MAX_CSUM_LEVEL)
|
||||
skb->csum_level++;
|
||||
} else {
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->csum_level = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uh->check)
|
||||
uh->check = ~udp_v4_check(skb->len - nhoff, iph->saddr,
|
||||
iph->daddr, 0);
|
||||
|
|
|
|||
|
|
@ -115,8 +115,10 @@ INDIRECT_CALLABLE_SCOPE
|
|||
struct sk_buff *udp6_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||
{
|
||||
struct udphdr *uh = udp_gro_udphdr(skb);
|
||||
struct sk_buff *pp;
|
||||
struct sock *sk;
|
||||
|
||||
if (unlikely(!uh) || !static_branch_unlikely(&udpv6_encap_needed_key))
|
||||
if (unlikely(!uh))
|
||||
goto flush;
|
||||
|
||||
/* Don't bother verifying checksum if we're going to flush anyway. */
|
||||
|
|
@ -132,7 +134,11 @@ struct sk_buff *udp6_gro_receive(struct list_head *head, struct sk_buff *skb)
|
|||
|
||||
skip:
|
||||
NAPI_GRO_CB(skb)->is_ipv6 = 1;
|
||||
return udp_gro_receive(head, skb, uh, udp6_lib_lookup_skb);
|
||||
rcu_read_lock();
|
||||
sk = static_branch_unlikely(&udpv6_encap_needed_key) ? udp6_lib_lookup_skb(skb, uh->source, uh->dest) : NULL;
|
||||
pp = udp_gro_receive(head, skb, uh, sk);
|
||||
rcu_read_unlock();
|
||||
return pp;
|
||||
|
||||
flush:
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
|
|
@ -144,6 +150,23 @@ INDIRECT_CALLABLE_SCOPE int udp6_gro_complete(struct sk_buff *skb, int nhoff)
|
|||
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
||||
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
|
||||
|
||||
if (NAPI_GRO_CB(skb)->is_flist) {
|
||||
uh->len = htons(skb->len - nhoff);
|
||||
|
||||
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
|
||||
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
|
||||
if (skb->csum_level < SKB_MAX_CSUM_LEVEL)
|
||||
skb->csum_level++;
|
||||
} else {
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->csum_level = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uh->check)
|
||||
uh->check = ~udp_v6_check(skb->len - nhoff, &ipv6h->saddr,
|
||||
&ipv6h->daddr, 0);
|
||||
|
|
|
|||
Loading…
Reference in a new issue