6329 lines
215 KiB
Diff
6329 lines
215 KiB
Diff
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
|
|
index b48da698d6f25..bb96ca0f774b9 100644
|
|
--- a/Documentation/process/changes.rst
|
|
+++ b/Documentation/process/changes.rst
|
|
@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
|
|
====================== =============== ========================================
|
|
GNU C 5.1 gcc --version
|
|
Clang/LLVM (optional) 11.0.0 clang --version
|
|
-Rust (optional) 1.71.1 rustc --version
|
|
+Rust (optional) 1.73.0 rustc --version
|
|
bindgen (optional) 0.65.1 bindgen --version
|
|
GNU make 3.82 make --version
|
|
bash 4.2 bash --version
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index dd5de540ec0b5..40312bb550f06 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -23630,6 +23630,7 @@ F: include/xen/arm/swiotlb-xen.h
|
|
F: include/xen/swiotlb-xen.h
|
|
|
|
XFS FILESYSTEM
|
|
+M: Catherine Hoang <catherine.hoang@oracle.com>
|
|
M: Chandan Babu R <chandan.babu@oracle.com>
|
|
R: Darrick J. Wong <djwong@kernel.org>
|
|
L: linux-xfs@vger.kernel.org
|
|
diff --git a/Makefile b/Makefile
|
|
index ef1c4163c43e2..3330c00c0a471 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 6
|
|
PATCHLEVEL = 6
|
|
-SUBLEVEL = 16
|
|
+SUBLEVEL = 17
|
|
EXTRAVERSION =
|
|
NAME = Hurr durr I'ma ninja sloth
|
|
|
|
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h
|
|
index bd5b1a9a05440..6fc74500a9f52 100644
|
|
--- a/arch/arc/include/asm/cacheflush.h
|
|
+++ b/arch/arc/include/asm/cacheflush.h
|
|
@@ -40,6 +40,7 @@ void dma_cache_wback(phys_addr_t start, unsigned long sz);
|
|
|
|
/* TBD: optimize this */
|
|
#define flush_cache_vmap(start, end) flush_cache_all()
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) flush_cache_all()
|
|
|
|
#define flush_cache_dup_mm(mm) /* called on fork (VIVT only) */
|
|
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
|
|
index f6181f69577fe..1075534b0a2ee 100644
|
|
--- a/arch/arm/include/asm/cacheflush.h
|
|
+++ b/arch/arm/include/asm/cacheflush.h
|
|
@@ -340,6 +340,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end)
|
|
dsb(ishst);
|
|
}
|
|
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
+
|
|
static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
|
|
{
|
|
if (!cache_is_vipt_nonaliasing())
|
|
diff --git a/arch/csky/abiv1/inc/abi/cacheflush.h b/arch/csky/abiv1/inc/abi/cacheflush.h
|
|
index 908d8b0bc4fdc..d011a81575d21 100644
|
|
--- a/arch/csky/abiv1/inc/abi/cacheflush.h
|
|
+++ b/arch/csky/abiv1/inc/abi/cacheflush.h
|
|
@@ -43,6 +43,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
|
|
*/
|
|
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
|
|
#define flush_cache_vmap(start, end) cache_wbinv_all()
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) cache_wbinv_all()
|
|
|
|
#define flush_icache_range(start, end) cache_wbinv_range(start, end)
|
|
diff --git a/arch/csky/abiv2/inc/abi/cacheflush.h b/arch/csky/abiv2/inc/abi/cacheflush.h
|
|
index 40be16907267d..6513ac5d25788 100644
|
|
--- a/arch/csky/abiv2/inc/abi/cacheflush.h
|
|
+++ b/arch/csky/abiv2/inc/abi/cacheflush.h
|
|
@@ -41,6 +41,7 @@ void flush_icache_mm_range(struct mm_struct *mm,
|
|
void flush_icache_deferred(struct mm_struct *mm);
|
|
|
|
#define flush_cache_vmap(start, end) do { } while (0)
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) do { } while (0)
|
|
|
|
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
|
|
diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h
|
|
index ed12358c4783b..9a71b0148461a 100644
|
|
--- a/arch/m68k/include/asm/cacheflush_mm.h
|
|
+++ b/arch/m68k/include/asm/cacheflush_mm.h
|
|
@@ -191,6 +191,7 @@ extern void cache_push_v(unsigned long vaddr, int len);
|
|
#define flush_cache_all() __flush_cache_all()
|
|
|
|
#define flush_cache_vmap(start, end) flush_cache_all()
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) flush_cache_all()
|
|
|
|
static inline void flush_cache_mm(struct mm_struct *mm)
|
|
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
|
|
index f36c2519ed976..1f14132b3fc98 100644
|
|
--- a/arch/mips/include/asm/cacheflush.h
|
|
+++ b/arch/mips/include/asm/cacheflush.h
|
|
@@ -97,6 +97,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end)
|
|
__flush_cache_vmap();
|
|
}
|
|
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
+
|
|
extern void (*__flush_cache_vunmap)(void);
|
|
|
|
static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
|
|
diff --git a/arch/nios2/include/asm/cacheflush.h b/arch/nios2/include/asm/cacheflush.h
|
|
index 348cea0977927..81484a776b333 100644
|
|
--- a/arch/nios2/include/asm/cacheflush.h
|
|
+++ b/arch/nios2/include/asm/cacheflush.h
|
|
@@ -38,6 +38,7 @@ void flush_icache_pages(struct vm_area_struct *vma, struct page *page,
|
|
#define flush_icache_pages flush_icache_pages
|
|
|
|
#define flush_cache_vmap(start, end) flush_dcache_range(start, end)
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) flush_dcache_range(start, end)
|
|
|
|
extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
|
|
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
|
|
index b4006f2a97052..ba4c05bc24d69 100644
|
|
--- a/arch/parisc/include/asm/cacheflush.h
|
|
+++ b/arch/parisc/include/asm/cacheflush.h
|
|
@@ -41,6 +41,7 @@ void flush_kernel_vmap_range(void *vaddr, int size);
|
|
void invalidate_kernel_vmap_range(void *vaddr, int size);
|
|
|
|
#define flush_cache_vmap(start, end) flush_cache_all()
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) flush_cache_all()
|
|
|
|
void flush_dcache_folio(struct folio *folio);
|
|
diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h
|
|
index 3cb53c4df27cf..a129dac4521d3 100644
|
|
--- a/arch/riscv/include/asm/cacheflush.h
|
|
+++ b/arch/riscv/include/asm/cacheflush.h
|
|
@@ -37,7 +37,8 @@ static inline void flush_dcache_page(struct page *page)
|
|
flush_icache_mm(vma->vm_mm, 0)
|
|
|
|
#ifdef CONFIG_64BIT
|
|
-#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end)
|
|
+#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end)
|
|
+#define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end)
|
|
#endif
|
|
|
|
#ifndef CONFIG_SMP
|
|
diff --git a/arch/riscv/include/asm/hugetlb.h b/arch/riscv/include/asm/hugetlb.h
|
|
index 4c5b0e929890f..20f9c3ba23414 100644
|
|
--- a/arch/riscv/include/asm/hugetlb.h
|
|
+++ b/arch/riscv/include/asm/hugetlb.h
|
|
@@ -11,6 +11,9 @@ static inline void arch_clear_hugepage_flags(struct page *page)
|
|
}
|
|
#define arch_clear_hugepage_flags arch_clear_hugepage_flags
|
|
|
|
+bool arch_hugetlb_migration_supported(struct hstate *h);
|
|
+#define arch_hugetlb_migration_supported arch_hugetlb_migration_supported
|
|
+
|
|
#ifdef CONFIG_RISCV_ISA_SVNAPOT
|
|
#define __HAVE_ARCH_HUGE_PTE_CLEAR
|
|
void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
|
|
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
|
|
index 5b4a1bf5f4395..b79d0228144f4 100644
|
|
--- a/arch/riscv/include/asm/sbi.h
|
|
+++ b/arch/riscv/include/asm/sbi.h
|
|
@@ -273,9 +273,6 @@ void sbi_set_timer(uint64_t stime_value);
|
|
void sbi_shutdown(void);
|
|
void sbi_send_ipi(unsigned int cpu);
|
|
int sbi_remote_fence_i(const struct cpumask *cpu_mask);
|
|
-int sbi_remote_sfence_vma(const struct cpumask *cpu_mask,
|
|
- unsigned long start,
|
|
- unsigned long size);
|
|
|
|
int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask,
|
|
unsigned long start,
|
|
diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h
|
|
index f7e8ef2418b99..b1495a7e06ce6 100644
|
|
--- a/arch/riscv/include/asm/stacktrace.h
|
|
+++ b/arch/riscv/include/asm/stacktrace.h
|
|
@@ -21,4 +21,9 @@ static inline bool on_thread_stack(void)
|
|
return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1));
|
|
}
|
|
|
|
+
|
|
+#ifdef CONFIG_VMAP_STACK
|
|
+DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
|
|
+#endif /* CONFIG_VMAP_STACK */
|
|
+
|
|
#endif /* _ASM_RISCV_STACKTRACE_H */
|
|
diff --git a/arch/riscv/include/asm/tlb.h b/arch/riscv/include/asm/tlb.h
|
|
index 120bcf2ed8a87..50b63b5c15bd8 100644
|
|
--- a/arch/riscv/include/asm/tlb.h
|
|
+++ b/arch/riscv/include/asm/tlb.h
|
|
@@ -15,7 +15,13 @@ static void tlb_flush(struct mmu_gather *tlb);
|
|
|
|
static inline void tlb_flush(struct mmu_gather *tlb)
|
|
{
|
|
- flush_tlb_mm(tlb->mm);
|
|
+#ifdef CONFIG_MMU
|
|
+ if (tlb->fullmm || tlb->need_flush_all || tlb->freed_tables)
|
|
+ flush_tlb_mm(tlb->mm);
|
|
+ else
|
|
+ flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end,
|
|
+ tlb_get_unmap_size(tlb));
|
|
+#endif
|
|
}
|
|
|
|
#endif /* _ASM_RISCV_TLB_H */
|
|
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
|
|
index a09196f8de688..51664ae4852e7 100644
|
|
--- a/arch/riscv/include/asm/tlbflush.h
|
|
+++ b/arch/riscv/include/asm/tlbflush.h
|
|
@@ -11,6 +11,9 @@
|
|
#include <asm/smp.h>
|
|
#include <asm/errata_list.h>
|
|
|
|
+#define FLUSH_TLB_MAX_SIZE ((unsigned long)-1)
|
|
+#define FLUSH_TLB_NO_ASID ((unsigned long)-1)
|
|
+
|
|
#ifdef CONFIG_MMU
|
|
extern unsigned long asid_mask;
|
|
|
|
@@ -32,9 +35,13 @@ static inline void local_flush_tlb_page(unsigned long addr)
|
|
#if defined(CONFIG_SMP) && defined(CONFIG_MMU)
|
|
void flush_tlb_all(void);
|
|
void flush_tlb_mm(struct mm_struct *mm);
|
|
+void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
|
|
+ unsigned long end, unsigned int page_size);
|
|
void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
|
|
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
|
unsigned long end);
|
|
+void flush_tlb_kernel_range(unsigned long start, unsigned long end);
|
|
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
|
#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
|
|
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
|
@@ -51,14 +58,16 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
|
|
local_flush_tlb_all();
|
|
}
|
|
|
|
-#define flush_tlb_mm(mm) flush_tlb_all()
|
|
-#endif /* !CONFIG_SMP || !CONFIG_MMU */
|
|
-
|
|
/* Flush a range of kernel pages */
|
|
static inline void flush_tlb_kernel_range(unsigned long start,
|
|
unsigned long end)
|
|
{
|
|
- flush_tlb_all();
|
|
+ local_flush_tlb_all();
|
|
}
|
|
|
|
+#define flush_tlb_mm(mm) flush_tlb_all()
|
|
+#define flush_tlb_mm_range(mm, start, end, page_size) flush_tlb_all()
|
|
+#define local_flush_tlb_kernel_range(start, end) flush_tlb_all()
|
|
+#endif /* !CONFIG_SMP || !CONFIG_MMU */
|
|
+
|
|
#endif /* _ASM_RISCV_TLBFLUSH_H */
|
|
diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
|
|
index c672c8ba9a2a6..5a62ed1da4533 100644
|
|
--- a/arch/riscv/kernel/sbi.c
|
|
+++ b/arch/riscv/kernel/sbi.c
|
|
@@ -11,6 +11,7 @@
|
|
#include <linux/reboot.h>
|
|
#include <asm/sbi.h>
|
|
#include <asm/smp.h>
|
|
+#include <asm/tlbflush.h>
|
|
|
|
/* default SBI version is 0.1 */
|
|
unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT;
|
|
@@ -376,32 +377,15 @@ int sbi_remote_fence_i(const struct cpumask *cpu_mask)
|
|
}
|
|
EXPORT_SYMBOL(sbi_remote_fence_i);
|
|
|
|
-/**
|
|
- * sbi_remote_sfence_vma() - Execute SFENCE.VMA instructions on given remote
|
|
- * harts for the specified virtual address range.
|
|
- * @cpu_mask: A cpu mask containing all the target harts.
|
|
- * @start: Start of the virtual address
|
|
- * @size: Total size of the virtual address range.
|
|
- *
|
|
- * Return: 0 on success, appropriate linux error code otherwise.
|
|
- */
|
|
-int sbi_remote_sfence_vma(const struct cpumask *cpu_mask,
|
|
- unsigned long start,
|
|
- unsigned long size)
|
|
-{
|
|
- return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
|
|
- cpu_mask, start, size, 0, 0);
|
|
-}
|
|
-EXPORT_SYMBOL(sbi_remote_sfence_vma);
|
|
-
|
|
/**
|
|
* sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given
|
|
- * remote harts for a virtual address range belonging to a specific ASID.
|
|
+ * remote harts for a virtual address range belonging to a specific ASID or not.
|
|
*
|
|
* @cpu_mask: A cpu mask containing all the target harts.
|
|
* @start: Start of the virtual address
|
|
* @size: Total size of the virtual address range.
|
|
- * @asid: The value of address space identifier (ASID).
|
|
+ * @asid: The value of address space identifier (ASID), or FLUSH_TLB_NO_ASID
|
|
+ * for flushing all address spaces.
|
|
*
|
|
* Return: 0 on success, appropriate linux error code otherwise.
|
|
*/
|
|
@@ -410,8 +394,12 @@ int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask,
|
|
unsigned long size,
|
|
unsigned long asid)
|
|
{
|
|
- return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
|
|
- cpu_mask, start, size, asid, 0);
|
|
+ if (asid == FLUSH_TLB_NO_ASID)
|
|
+ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
|
|
+ cpu_mask, start, size, 0, 0);
|
|
+ else
|
|
+ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
|
|
+ cpu_mask, start, size, asid, 0);
|
|
}
|
|
EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
|
|
|
|
diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c
|
|
index b52f0210481fa..e7b69281875b2 100644
|
|
--- a/arch/riscv/mm/hugetlbpage.c
|
|
+++ b/arch/riscv/mm/hugetlbpage.c
|
|
@@ -125,6 +125,26 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
|
|
return pte;
|
|
}
|
|
|
|
+unsigned long hugetlb_mask_last_page(struct hstate *h)
|
|
+{
|
|
+ unsigned long hp_size = huge_page_size(h);
|
|
+
|
|
+ switch (hp_size) {
|
|
+#ifndef __PAGETABLE_PMD_FOLDED
|
|
+ case PUD_SIZE:
|
|
+ return P4D_SIZE - PUD_SIZE;
|
|
+#endif
|
|
+ case PMD_SIZE:
|
|
+ return PUD_SIZE - PMD_SIZE;
|
|
+ case napot_cont_size(NAPOT_CONT64KB_ORDER):
|
|
+ return PMD_SIZE - napot_cont_size(NAPOT_CONT64KB_ORDER);
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0UL;
|
|
+}
|
|
+
|
|
static pte_t get_clear_contig(struct mm_struct *mm,
|
|
unsigned long addr,
|
|
pte_t *ptep,
|
|
@@ -177,13 +197,36 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
|
|
return entry;
|
|
}
|
|
|
|
+static void clear_flush(struct mm_struct *mm,
|
|
+ unsigned long addr,
|
|
+ pte_t *ptep,
|
|
+ unsigned long pgsize,
|
|
+ unsigned long ncontig)
|
|
+{
|
|
+ struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
|
|
+ unsigned long i, saddr = addr;
|
|
+
|
|
+ for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
|
|
+ ptep_get_and_clear(mm, addr, ptep);
|
|
+
|
|
+ flush_tlb_range(&vma, saddr, addr);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * When dealing with NAPOT mappings, the privileged specification indicates that
|
|
+ * "if an update needs to be made, the OS generally should first mark all of the
|
|
+ * PTEs invalid, then issue SFENCE.VMA instruction(s) covering all 4 KiB regions
|
|
+ * within the range, [...] then update the PTE(s), as described in Section
|
|
+ * 4.2.1.". That's the equivalent of the Break-Before-Make approach used by
|
|
+ * arm64.
|
|
+ */
|
|
void set_huge_pte_at(struct mm_struct *mm,
|
|
unsigned long addr,
|
|
pte_t *ptep,
|
|
pte_t pte,
|
|
unsigned long sz)
|
|
{
|
|
- unsigned long hugepage_shift;
|
|
+ unsigned long hugepage_shift, pgsize;
|
|
int i, pte_num;
|
|
|
|
if (sz >= PGDIR_SIZE)
|
|
@@ -198,7 +241,22 @@ void set_huge_pte_at(struct mm_struct *mm,
|
|
hugepage_shift = PAGE_SHIFT;
|
|
|
|
pte_num = sz >> hugepage_shift;
|
|
- for (i = 0; i < pte_num; i++, ptep++, addr += (1 << hugepage_shift))
|
|
+ pgsize = 1 << hugepage_shift;
|
|
+
|
|
+ if (!pte_present(pte)) {
|
|
+ for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
|
|
+ set_ptes(mm, addr, ptep, pte, 1);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!pte_napot(pte)) {
|
|
+ set_ptes(mm, addr, ptep, pte, 1);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ clear_flush(mm, addr, ptep, pgsize, pte_num);
|
|
+
|
|
+ for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
|
|
set_pte_at(mm, addr, ptep, pte);
|
|
}
|
|
|
|
@@ -306,7 +364,7 @@ void huge_pte_clear(struct mm_struct *mm,
|
|
pte_clear(mm, addr, ptep);
|
|
}
|
|
|
|
-static __init bool is_napot_size(unsigned long size)
|
|
+static bool is_napot_size(unsigned long size)
|
|
{
|
|
unsigned long order;
|
|
|
|
@@ -334,7 +392,7 @@ arch_initcall(napot_hugetlbpages_init);
|
|
|
|
#else
|
|
|
|
-static __init bool is_napot_size(unsigned long size)
|
|
+static bool is_napot_size(unsigned long size)
|
|
{
|
|
return false;
|
|
}
|
|
@@ -351,7 +409,7 @@ int pmd_huge(pmd_t pmd)
|
|
return pmd_leaf(pmd);
|
|
}
|
|
|
|
-bool __init arch_hugetlb_valid_size(unsigned long size)
|
|
+static bool __hugetlb_valid_size(unsigned long size)
|
|
{
|
|
if (size == HPAGE_SIZE)
|
|
return true;
|
|
@@ -363,6 +421,16 @@ bool __init arch_hugetlb_valid_size(unsigned long size)
|
|
return false;
|
|
}
|
|
|
|
+bool __init arch_hugetlb_valid_size(unsigned long size)
|
|
+{
|
|
+ return __hugetlb_valid_size(size);
|
|
+}
|
|
+
|
|
+bool arch_hugetlb_migration_supported(struct hstate *h)
|
|
+{
|
|
+ return __hugetlb_valid_size(huge_page_size(h));
|
|
+}
|
|
+
|
|
#ifdef CONFIG_CONTIG_ALLOC
|
|
static __init int gigantic_pages_init(void)
|
|
{
|
|
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
|
|
index e71dd19ac8018..b50faa232b5e9 100644
|
|
--- a/arch/riscv/mm/init.c
|
|
+++ b/arch/riscv/mm/init.c
|
|
@@ -1502,6 +1502,10 @@ void __init misc_mem_init(void)
|
|
early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT);
|
|
arch_numa_init();
|
|
sparse_init();
|
|
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
|
+ /* The entire VMEMMAP region has been populated. Flush TLB for this region */
|
|
+ local_flush_tlb_kernel_range(VMEMMAP_START, VMEMMAP_END);
|
|
+#endif
|
|
zone_sizes_init();
|
|
reserve_crashkernel();
|
|
memblock_dump_all();
|
|
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
|
|
index 77be59aadc735..bdee5de918e06 100644
|
|
--- a/arch/riscv/mm/tlbflush.c
|
|
+++ b/arch/riscv/mm/tlbflush.c
|
|
@@ -8,28 +8,50 @@
|
|
|
|
static inline void local_flush_tlb_all_asid(unsigned long asid)
|
|
{
|
|
- __asm__ __volatile__ ("sfence.vma x0, %0"
|
|
- :
|
|
- : "r" (asid)
|
|
- : "memory");
|
|
+ if (asid != FLUSH_TLB_NO_ASID)
|
|
+ __asm__ __volatile__ ("sfence.vma x0, %0"
|
|
+ :
|
|
+ : "r" (asid)
|
|
+ : "memory");
|
|
+ else
|
|
+ local_flush_tlb_all();
|
|
}
|
|
|
|
static inline void local_flush_tlb_page_asid(unsigned long addr,
|
|
unsigned long asid)
|
|
{
|
|
- __asm__ __volatile__ ("sfence.vma %0, %1"
|
|
- :
|
|
- : "r" (addr), "r" (asid)
|
|
- : "memory");
|
|
+ if (asid != FLUSH_TLB_NO_ASID)
|
|
+ __asm__ __volatile__ ("sfence.vma %0, %1"
|
|
+ :
|
|
+ : "r" (addr), "r" (asid)
|
|
+ : "memory");
|
|
+ else
|
|
+ local_flush_tlb_page(addr);
|
|
}
|
|
|
|
-static inline void local_flush_tlb_range(unsigned long start,
|
|
- unsigned long size, unsigned long stride)
|
|
+/*
|
|
+ * Flush entire TLB if number of entries to be flushed is greater
|
|
+ * than the threshold below.
|
|
+ */
|
|
+static unsigned long tlb_flush_all_threshold __read_mostly = 64;
|
|
+
|
|
+static void local_flush_tlb_range_threshold_asid(unsigned long start,
|
|
+ unsigned long size,
|
|
+ unsigned long stride,
|
|
+ unsigned long asid)
|
|
{
|
|
- if (size <= stride)
|
|
- local_flush_tlb_page(start);
|
|
- else
|
|
- local_flush_tlb_all();
|
|
+ unsigned long nr_ptes_in_range = DIV_ROUND_UP(size, stride);
|
|
+ int i;
|
|
+
|
|
+ if (nr_ptes_in_range > tlb_flush_all_threshold) {
|
|
+ local_flush_tlb_all_asid(asid);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < nr_ptes_in_range; ++i) {
|
|
+ local_flush_tlb_page_asid(start, asid);
|
|
+ start += stride;
|
|
+ }
|
|
}
|
|
|
|
static inline void local_flush_tlb_range_asid(unsigned long start,
|
|
@@ -37,8 +59,16 @@ static inline void local_flush_tlb_range_asid(unsigned long start,
|
|
{
|
|
if (size <= stride)
|
|
local_flush_tlb_page_asid(start, asid);
|
|
- else
|
|
+ else if (size == FLUSH_TLB_MAX_SIZE)
|
|
local_flush_tlb_all_asid(asid);
|
|
+ else
|
|
+ local_flush_tlb_range_threshold_asid(start, size, stride, asid);
|
|
+}
|
|
+
|
|
+/* Flush a range of kernel pages without broadcasting */
|
|
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|
+{
|
|
+ local_flush_tlb_range_asid(start, end - start, PAGE_SIZE, FLUSH_TLB_NO_ASID);
|
|
}
|
|
|
|
static void __ipi_flush_tlb_all(void *info)
|
|
@@ -51,7 +81,7 @@ void flush_tlb_all(void)
|
|
if (riscv_use_ipi_for_rfence())
|
|
on_each_cpu(__ipi_flush_tlb_all, NULL, 1);
|
|
else
|
|
- sbi_remote_sfence_vma(NULL, 0, -1);
|
|
+ sbi_remote_sfence_vma_asid(NULL, 0, FLUSH_TLB_MAX_SIZE, FLUSH_TLB_NO_ASID);
|
|
}
|
|
|
|
struct flush_tlb_range_data {
|
|
@@ -68,68 +98,62 @@ static void __ipi_flush_tlb_range_asid(void *info)
|
|
local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid);
|
|
}
|
|
|
|
-static void __ipi_flush_tlb_range(void *info)
|
|
-{
|
|
- struct flush_tlb_range_data *d = info;
|
|
-
|
|
- local_flush_tlb_range(d->start, d->size, d->stride);
|
|
-}
|
|
-
|
|
static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
|
|
unsigned long size, unsigned long stride)
|
|
{
|
|
struct flush_tlb_range_data ftd;
|
|
- struct cpumask *cmask = mm_cpumask(mm);
|
|
- unsigned int cpuid;
|
|
+ const struct cpumask *cmask;
|
|
+ unsigned long asid = FLUSH_TLB_NO_ASID;
|
|
bool broadcast;
|
|
|
|
- if (cpumask_empty(cmask))
|
|
- return;
|
|
+ if (mm) {
|
|
+ unsigned int cpuid;
|
|
+
|
|
+ cmask = mm_cpumask(mm);
|
|
+ if (cpumask_empty(cmask))
|
|
+ return;
|
|
+
|
|
+ cpuid = get_cpu();
|
|
+ /* check if the tlbflush needs to be sent to other CPUs */
|
|
+ broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids;
|
|
+
|
|
+ if (static_branch_unlikely(&use_asid_allocator))
|
|
+ asid = atomic_long_read(&mm->context.id) & asid_mask;
|
|
+ } else {
|
|
+ cmask = cpu_online_mask;
|
|
+ broadcast = true;
|
|
+ }
|
|
|
|
- cpuid = get_cpu();
|
|
- /* check if the tlbflush needs to be sent to other CPUs */
|
|
- broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids;
|
|
- if (static_branch_unlikely(&use_asid_allocator)) {
|
|
- unsigned long asid = atomic_long_read(&mm->context.id) & asid_mask;
|
|
-
|
|
- if (broadcast) {
|
|
- if (riscv_use_ipi_for_rfence()) {
|
|
- ftd.asid = asid;
|
|
- ftd.start = start;
|
|
- ftd.size = size;
|
|
- ftd.stride = stride;
|
|
- on_each_cpu_mask(cmask,
|
|
- __ipi_flush_tlb_range_asid,
|
|
- &ftd, 1);
|
|
- } else
|
|
- sbi_remote_sfence_vma_asid(cmask,
|
|
- start, size, asid);
|
|
- } else {
|
|
- local_flush_tlb_range_asid(start, size, stride, asid);
|
|
- }
|
|
+ if (broadcast) {
|
|
+ if (riscv_use_ipi_for_rfence()) {
|
|
+ ftd.asid = asid;
|
|
+ ftd.start = start;
|
|
+ ftd.size = size;
|
|
+ ftd.stride = stride;
|
|
+ on_each_cpu_mask(cmask,
|
|
+ __ipi_flush_tlb_range_asid,
|
|
+ &ftd, 1);
|
|
+ } else
|
|
+ sbi_remote_sfence_vma_asid(cmask,
|
|
+ start, size, asid);
|
|
} else {
|
|
- if (broadcast) {
|
|
- if (riscv_use_ipi_for_rfence()) {
|
|
- ftd.asid = 0;
|
|
- ftd.start = start;
|
|
- ftd.size = size;
|
|
- ftd.stride = stride;
|
|
- on_each_cpu_mask(cmask,
|
|
- __ipi_flush_tlb_range,
|
|
- &ftd, 1);
|
|
- } else
|
|
- sbi_remote_sfence_vma(cmask, start, size);
|
|
- } else {
|
|
- local_flush_tlb_range(start, size, stride);
|
|
- }
|
|
+ local_flush_tlb_range_asid(start, size, stride, asid);
|
|
}
|
|
|
|
- put_cpu();
|
|
+ if (mm)
|
|
+ put_cpu();
|
|
}
|
|
|
|
void flush_tlb_mm(struct mm_struct *mm)
|
|
{
|
|
- __flush_tlb_range(mm, 0, -1, PAGE_SIZE);
|
|
+ __flush_tlb_range(mm, 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
|
|
+}
|
|
+
|
|
+void flush_tlb_mm_range(struct mm_struct *mm,
|
|
+ unsigned long start, unsigned long end,
|
|
+ unsigned int page_size)
|
|
+{
|
|
+ __flush_tlb_range(mm, start, end - start, page_size);
|
|
}
|
|
|
|
void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
|
|
@@ -142,6 +166,12 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
|
{
|
|
__flush_tlb_range(vma->vm_mm, start, end - start, PAGE_SIZE);
|
|
}
|
|
+
|
|
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|
+{
|
|
+ __flush_tlb_range(NULL, start, end - start, PAGE_SIZE);
|
|
+}
|
|
+
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
|
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
|
unsigned long end)
|
|
diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h
|
|
index 878b6b551bd2d..51112f54552b3 100644
|
|
--- a/arch/sh/include/asm/cacheflush.h
|
|
+++ b/arch/sh/include/asm/cacheflush.h
|
|
@@ -90,6 +90,7 @@ extern void copy_from_user_page(struct vm_area_struct *vma,
|
|
unsigned long len);
|
|
|
|
#define flush_cache_vmap(start, end) local_flush_cache_all(NULL)
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) local_flush_cache_all(NULL)
|
|
|
|
#define flush_dcache_mmap_lock(mapping) do { } while (0)
|
|
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h
|
|
index f3b7270bf71b2..9fee0ccfccb8e 100644
|
|
--- a/arch/sparc/include/asm/cacheflush_32.h
|
|
+++ b/arch/sparc/include/asm/cacheflush_32.h
|
|
@@ -48,6 +48,7 @@ static inline void flush_dcache_page(struct page *page)
|
|
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
|
|
|
|
#define flush_cache_vmap(start, end) flush_cache_all()
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) flush_cache_all()
|
|
|
|
/* When a context switch happens we must flush all user windows so that
|
|
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
|
|
index 0e879004efff1..2b1261b77ecd1 100644
|
|
--- a/arch/sparc/include/asm/cacheflush_64.h
|
|
+++ b/arch/sparc/include/asm/cacheflush_64.h
|
|
@@ -75,6 +75,7 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *,
|
|
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
|
|
|
|
#define flush_cache_vmap(start, end) do { } while (0)
|
|
+#define flush_cache_vmap_early(start, end) do { } while (0)
|
|
#define flush_cache_vunmap(start, end) do { } while (0)
|
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
|
|
index 9c63713477bbb..f6aad480febd3 100644
|
|
--- a/arch/x86/lib/getuser.S
|
|
+++ b/arch/x86/lib/getuser.S
|
|
@@ -163,23 +163,23 @@ SYM_CODE_END(__get_user_8_handle_exception)
|
|
#endif
|
|
|
|
/* get_user */
|
|
- _ASM_EXTABLE(1b, __get_user_handle_exception)
|
|
- _ASM_EXTABLE(2b, __get_user_handle_exception)
|
|
- _ASM_EXTABLE(3b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(1b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(2b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(3b, __get_user_handle_exception)
|
|
#ifdef CONFIG_X86_64
|
|
- _ASM_EXTABLE(4b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(4b, __get_user_handle_exception)
|
|
#else
|
|
- _ASM_EXTABLE(4b, __get_user_8_handle_exception)
|
|
- _ASM_EXTABLE(5b, __get_user_8_handle_exception)
|
|
+ _ASM_EXTABLE_UA(4b, __get_user_8_handle_exception)
|
|
+ _ASM_EXTABLE_UA(5b, __get_user_8_handle_exception)
|
|
#endif
|
|
|
|
/* __get_user */
|
|
- _ASM_EXTABLE(6b, __get_user_handle_exception)
|
|
- _ASM_EXTABLE(7b, __get_user_handle_exception)
|
|
- _ASM_EXTABLE(8b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(6b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(7b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(8b, __get_user_handle_exception)
|
|
#ifdef CONFIG_X86_64
|
|
- _ASM_EXTABLE(9b, __get_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(9b, __get_user_handle_exception)
|
|
#else
|
|
- _ASM_EXTABLE(9b, __get_user_8_handle_exception)
|
|
- _ASM_EXTABLE(10b, __get_user_8_handle_exception)
|
|
+ _ASM_EXTABLE_UA(9b, __get_user_8_handle_exception)
|
|
+ _ASM_EXTABLE_UA(10b, __get_user_8_handle_exception)
|
|
#endif
|
|
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
|
|
index 235bbda6fc823..512dc58c938b8 100644
|
|
--- a/arch/x86/lib/putuser.S
|
|
+++ b/arch/x86/lib/putuser.S
|
|
@@ -134,15 +134,15 @@ SYM_CODE_START_LOCAL(__put_user_handle_exception)
|
|
RET
|
|
SYM_CODE_END(__put_user_handle_exception)
|
|
|
|
- _ASM_EXTABLE(1b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(2b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(3b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(4b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(5b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(6b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(7b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(9b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(1b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(2b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(3b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(4b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(5b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(6b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(7b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(9b, __put_user_handle_exception)
|
|
#ifdef CONFIG_X86_32
|
|
- _ASM_EXTABLE(8b, __put_user_handle_exception)
|
|
- _ASM_EXTABLE(10b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(8b, __put_user_handle_exception)
|
|
+ _ASM_EXTABLE_UA(10b, __put_user_handle_exception)
|
|
#endif
|
|
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
|
|
index 785a00ce83c11..38bcecb0e457d 100644
|
|
--- a/arch/xtensa/include/asm/cacheflush.h
|
|
+++ b/arch/xtensa/include/asm/cacheflush.h
|
|
@@ -116,8 +116,9 @@ void flush_cache_page(struct vm_area_struct*,
|
|
#define flush_cache_mm(mm) flush_cache_all()
|
|
#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
|
|
|
|
-#define flush_cache_vmap(start,end) flush_cache_all()
|
|
-#define flush_cache_vunmap(start,end) flush_cache_all()
|
|
+#define flush_cache_vmap(start,end) flush_cache_all()
|
|
+#define flush_cache_vmap_early(start,end) do { } while (0)
|
|
+#define flush_cache_vunmap(start,end) flush_cache_all()
|
|
|
|
void flush_dcache_folio(struct folio *folio);
|
|
#define flush_dcache_folio flush_dcache_folio
|
|
@@ -140,6 +141,7 @@ void local_flush_cache_page(struct vm_area_struct *vma,
|
|
#define flush_cache_dup_mm(mm) do { } while (0)
|
|
|
|
#define flush_cache_vmap(start,end) do { } while (0)
|
|
+#define flush_cache_vmap_early(start,end) do { } while (0)
|
|
#define flush_cache_vunmap(start,end) do { } while (0)
|
|
|
|
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
|
|
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
|
|
index 089fcb9cfce37..7ee8d85c2c68d 100644
|
|
--- a/block/blk-iocost.c
|
|
+++ b/block/blk-iocost.c
|
|
@@ -1353,6 +1353,13 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
|
|
|
|
lockdep_assert_held(&iocg->waitq.lock);
|
|
|
|
+ /*
|
|
+ * If the delay is set by another CPU, we may be in the past. No need to
|
|
+ * change anything if so. This avoids decay calculation underflow.
|
|
+ */
|
|
+ if (time_before64(now->now, iocg->delay_at))
|
|
+ return false;
|
|
+
|
|
/* calculate the current delay in effect - 1/2 every second */
|
|
tdelta = now->now - iocg->delay_at;
|
|
if (iocg->delay)
|
|
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
|
|
index e327a0229dc17..e7f713cd70d3f 100644
|
|
--- a/drivers/atm/idt77252.c
|
|
+++ b/drivers/atm/idt77252.c
|
|
@@ -2930,6 +2930,8 @@ open_card_ubr0(struct idt77252_dev *card)
|
|
vc->scq = alloc_scq(card, vc->class);
|
|
if (!vc->scq) {
|
|
printk("%s: can't get SCQ.\n", card->name);
|
|
+ kfree(card->vcs[0]);
|
|
+ card->vcs[0] = NULL;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
|
|
index a42a37634881b..da91bc9a8e6f0 100644
|
|
--- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
|
|
+++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
|
|
@@ -38,15 +38,17 @@ static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan)
|
|
if (!dpaa2_chan->fd_pool)
|
|
goto err;
|
|
|
|
- dpaa2_chan->fl_pool = dma_pool_create("fl_pool", dev,
|
|
- sizeof(struct dpaa2_fl_entry),
|
|
- sizeof(struct dpaa2_fl_entry), 0);
|
|
+ dpaa2_chan->fl_pool =
|
|
+ dma_pool_create("fl_pool", dev,
|
|
+ sizeof(struct dpaa2_fl_entry) * 3,
|
|
+ sizeof(struct dpaa2_fl_entry), 0);
|
|
+
|
|
if (!dpaa2_chan->fl_pool)
|
|
goto err_fd;
|
|
|
|
dpaa2_chan->sdd_pool =
|
|
dma_pool_create("sdd_pool", dev,
|
|
- sizeof(struct dpaa2_qdma_sd_d),
|
|
+ sizeof(struct dpaa2_qdma_sd_d) * 2,
|
|
sizeof(struct dpaa2_qdma_sd_d), 0);
|
|
if (!dpaa2_chan->sdd_pool)
|
|
goto err_fl;
|
|
diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c
|
|
index a8cc8a4bc6102..e4c293b76e050 100644
|
|
--- a/drivers/dma/fsl-qdma.c
|
|
+++ b/drivers/dma/fsl-qdma.c
|
|
@@ -514,11 +514,11 @@ static struct fsl_qdma_queue
|
|
queue_temp = queue_head + i + (j * queue_num);
|
|
|
|
queue_temp->cq =
|
|
- dma_alloc_coherent(&pdev->dev,
|
|
- sizeof(struct fsl_qdma_format) *
|
|
- queue_size[i],
|
|
- &queue_temp->bus_addr,
|
|
- GFP_KERNEL);
|
|
+ dmam_alloc_coherent(&pdev->dev,
|
|
+ sizeof(struct fsl_qdma_format) *
|
|
+ queue_size[i],
|
|
+ &queue_temp->bus_addr,
|
|
+ GFP_KERNEL);
|
|
if (!queue_temp->cq)
|
|
return NULL;
|
|
queue_temp->block_base = fsl_qdma->block_base +
|
|
@@ -563,11 +563,11 @@ static struct fsl_qdma_queue
|
|
/*
|
|
* Buffer for queue command
|
|
*/
|
|
- status_head->cq = dma_alloc_coherent(&pdev->dev,
|
|
- sizeof(struct fsl_qdma_format) *
|
|
- status_size,
|
|
- &status_head->bus_addr,
|
|
- GFP_KERNEL);
|
|
+ status_head->cq = dmam_alloc_coherent(&pdev->dev,
|
|
+ sizeof(struct fsl_qdma_format) *
|
|
+ status_size,
|
|
+ &status_head->bus_addr,
|
|
+ GFP_KERNEL);
|
|
if (!status_head->cq) {
|
|
devm_kfree(&pdev->dev, status_head);
|
|
return NULL;
|
|
@@ -1268,8 +1268,6 @@ static void fsl_qdma_cleanup_vchan(struct dma_device *dmadev)
|
|
|
|
static int fsl_qdma_remove(struct platform_device *pdev)
|
|
{
|
|
- int i;
|
|
- struct fsl_qdma_queue *status;
|
|
struct device_node *np = pdev->dev.of_node;
|
|
struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev);
|
|
|
|
@@ -1278,11 +1276,6 @@ static int fsl_qdma_remove(struct platform_device *pdev)
|
|
of_dma_controller_free(np);
|
|
dma_async_device_unregister(&fsl_qdma->dma_dev);
|
|
|
|
- for (i = 0; i < fsl_qdma->block_number; i++) {
|
|
- status = fsl_qdma->status[i];
|
|
- dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_format) *
|
|
- status->n_cq, status->cq, status->bus_addr);
|
|
- }
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
|
|
index 30fd2f386f36a..037f1408e7983 100644
|
|
--- a/drivers/dma/ti/k3-udma.c
|
|
+++ b/drivers/dma/ti/k3-udma.c
|
|
@@ -3968,6 +3968,7 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc,
|
|
{
|
|
struct udma_chan *uc = to_udma_chan(&vc->chan);
|
|
struct udma_desc *d;
|
|
+ u8 status;
|
|
|
|
if (!vd)
|
|
return;
|
|
@@ -3977,12 +3978,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc,
|
|
if (d->metadata_size)
|
|
udma_fetch_epib(uc, d);
|
|
|
|
- /* Provide residue information for the client */
|
|
if (result) {
|
|
void *desc_vaddr = udma_curr_cppi5_desc_vaddr(d, d->desc_idx);
|
|
|
|
if (cppi5_desc_get_type(desc_vaddr) ==
|
|
CPPI5_INFO0_DESC_TYPE_VAL_HOST) {
|
|
+ /* Provide residue information for the client */
|
|
result->residue = d->residue -
|
|
cppi5_hdesc_get_pktlen(desc_vaddr);
|
|
if (result->residue)
|
|
@@ -3991,7 +3992,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc,
|
|
result->result = DMA_TRANS_NOERROR;
|
|
} else {
|
|
result->residue = 0;
|
|
- result->result = DMA_TRANS_NOERROR;
|
|
+ /* Propagate TR Response errors to the client */
|
|
+ status = d->hwdesc[0].tr_resp_base->status;
|
|
+ if (status)
|
|
+ result->result = DMA_TRANS_ABORTED;
|
|
+ else
|
|
+ result->result = DMA_TRANS_NOERROR;
|
|
}
|
|
}
|
|
}
|
|
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
|
|
index 212687c30d79c..c04b82ea40f21 100644
|
|
--- a/drivers/firmware/efi/libstub/efistub.h
|
|
+++ b/drivers/firmware/efi/libstub/efistub.h
|
|
@@ -956,7 +956,8 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out);
|
|
|
|
efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
|
|
unsigned long *addr, unsigned long random_seed,
|
|
- int memory_type, unsigned long alloc_limit);
|
|
+ int memory_type, unsigned long alloc_min,
|
|
+ unsigned long alloc_max);
|
|
|
|
efi_status_t efi_random_get_seed(void);
|
|
|
|
diff --git a/drivers/firmware/efi/libstub/kaslr.c b/drivers/firmware/efi/libstub/kaslr.c
|
|
index 62d63f7a2645b..1a9808012abd3 100644
|
|
--- a/drivers/firmware/efi/libstub/kaslr.c
|
|
+++ b/drivers/firmware/efi/libstub/kaslr.c
|
|
@@ -119,7 +119,7 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
|
|
*/
|
|
status = efi_random_alloc(*reserve_size, min_kimg_align,
|
|
reserve_addr, phys_seed,
|
|
- EFI_LOADER_CODE, EFI_ALLOC_LIMIT);
|
|
+ EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT);
|
|
if (status != EFI_SUCCESS)
|
|
efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
|
|
} else {
|
|
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
|
|
index 674a064b8f7ad..4e96a855fdf47 100644
|
|
--- a/drivers/firmware/efi/libstub/randomalloc.c
|
|
+++ b/drivers/firmware/efi/libstub/randomalloc.c
|
|
@@ -17,7 +17,7 @@
|
|
static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
|
|
unsigned long size,
|
|
unsigned long align_shift,
|
|
- u64 alloc_limit)
|
|
+ u64 alloc_min, u64 alloc_max)
|
|
{
|
|
unsigned long align = 1UL << align_shift;
|
|
u64 first_slot, last_slot, region_end;
|
|
@@ -30,11 +30,11 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
|
|
return 0;
|
|
|
|
region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
|
|
- alloc_limit);
|
|
+ alloc_max);
|
|
if (region_end < size)
|
|
return 0;
|
|
|
|
- first_slot = round_up(md->phys_addr, align);
|
|
+ first_slot = round_up(max(md->phys_addr, alloc_min), align);
|
|
last_slot = round_down(region_end - size + 1, align);
|
|
|
|
if (first_slot > last_slot)
|
|
@@ -56,7 +56,8 @@ efi_status_t efi_random_alloc(unsigned long size,
|
|
unsigned long *addr,
|
|
unsigned long random_seed,
|
|
int memory_type,
|
|
- unsigned long alloc_limit)
|
|
+ unsigned long alloc_min,
|
|
+ unsigned long alloc_max)
|
|
{
|
|
unsigned long total_slots = 0, target_slot;
|
|
unsigned long total_mirrored_slots = 0;
|
|
@@ -78,7 +79,8 @@ efi_status_t efi_random_alloc(unsigned long size,
|
|
efi_memory_desc_t *md = (void *)map->map + map_offset;
|
|
unsigned long slots;
|
|
|
|
- slots = get_entry_num_slots(md, size, ilog2(align), alloc_limit);
|
|
+ slots = get_entry_num_slots(md, size, ilog2(align), alloc_min,
|
|
+ alloc_max);
|
|
MD_NUM_SLOTS(md) = slots;
|
|
total_slots += slots;
|
|
if (md->attribute & EFI_MEMORY_MORE_RELIABLE)
|
|
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
|
|
index 70b325a2f1f31..4a11470bed5ea 100644
|
|
--- a/drivers/firmware/efi/libstub/x86-stub.c
|
|
+++ b/drivers/firmware/efi/libstub/x86-stub.c
|
|
@@ -223,8 +223,8 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
|
|
}
|
|
}
|
|
|
|
-void efi_adjust_memory_range_protection(unsigned long start,
|
|
- unsigned long size)
|
|
+efi_status_t efi_adjust_memory_range_protection(unsigned long start,
|
|
+ unsigned long size)
|
|
{
|
|
efi_status_t status;
|
|
efi_gcd_memory_space_desc_t desc;
|
|
@@ -236,13 +236,17 @@ void efi_adjust_memory_range_protection(unsigned long start,
|
|
rounded_end = roundup(start + size, EFI_PAGE_SIZE);
|
|
|
|
if (memattr != NULL) {
|
|
- efi_call_proto(memattr, clear_memory_attributes, rounded_start,
|
|
- rounded_end - rounded_start, EFI_MEMORY_XP);
|
|
- return;
|
|
+ status = efi_call_proto(memattr, clear_memory_attributes,
|
|
+ rounded_start,
|
|
+ rounded_end - rounded_start,
|
|
+ EFI_MEMORY_XP);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ efi_warn("Failed to clear EFI_MEMORY_XP attribute\n");
|
|
+ return status;
|
|
}
|
|
|
|
if (efi_dxe_table == NULL)
|
|
- return;
|
|
+ return EFI_SUCCESS;
|
|
|
|
/*
|
|
* Don't modify memory region attributes, they are
|
|
@@ -255,7 +259,7 @@ void efi_adjust_memory_range_protection(unsigned long start,
|
|
status = efi_dxe_call(get_memory_space_descriptor, start, &desc);
|
|
|
|
if (status != EFI_SUCCESS)
|
|
- return;
|
|
+ break;
|
|
|
|
next = desc.base_address + desc.length;
|
|
|
|
@@ -280,8 +284,10 @@ void efi_adjust_memory_range_protection(unsigned long start,
|
|
unprotect_start,
|
|
unprotect_start + unprotect_size,
|
|
status);
|
|
+ break;
|
|
}
|
|
}
|
|
+ return EFI_SUCCESS;
|
|
}
|
|
|
|
static void setup_unaccepted_memory(void)
|
|
@@ -825,6 +831,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
|
|
|
|
status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr,
|
|
seed[0], EFI_LOADER_CODE,
|
|
+ LOAD_PHYSICAL_ADDR,
|
|
EFI_X86_KERNEL_ALLOC_LIMIT);
|
|
if (status != EFI_SUCCESS)
|
|
return status;
|
|
@@ -837,9 +844,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
|
|
|
|
*kernel_entry = addr + entry;
|
|
|
|
- efi_adjust_memory_range_protection(addr, kernel_total_size);
|
|
-
|
|
- return EFI_SUCCESS;
|
|
+ return efi_adjust_memory_range_protection(addr, kernel_total_size);
|
|
}
|
|
|
|
static void __noreturn enter_kernel(unsigned long kernel_addr,
|
|
diff --git a/drivers/firmware/efi/libstub/x86-stub.h b/drivers/firmware/efi/libstub/x86-stub.h
|
|
index 2748bca192dfb..4433d0f97441c 100644
|
|
--- a/drivers/firmware/efi/libstub/x86-stub.h
|
|
+++ b/drivers/firmware/efi/libstub/x86-stub.h
|
|
@@ -7,8 +7,8 @@ extern struct boot_params *boot_params_pointer asm("boot_params");
|
|
extern void trampoline_32bit_src(void *, bool);
|
|
extern const u16 trampoline_ljmp_imm_offset;
|
|
|
|
-void efi_adjust_memory_range_protection(unsigned long start,
|
|
- unsigned long size);
|
|
+efi_status_t efi_adjust_memory_range_protection(unsigned long start,
|
|
+ unsigned long size);
|
|
|
|
#ifdef CONFIG_X86_64
|
|
efi_status_t efi_setup_5level_paging(void);
|
|
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
|
|
index bdb17eac0cb40..1ceace9567586 100644
|
|
--- a/drivers/firmware/efi/libstub/zboot.c
|
|
+++ b/drivers/firmware/efi/libstub/zboot.c
|
|
@@ -119,7 +119,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
|
}
|
|
|
|
status = efi_random_alloc(alloc_size, min_kimg_align, &image_base,
|
|
- seed, EFI_LOADER_CODE, EFI_ALLOC_LIMIT);
|
|
+ seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT);
|
|
if (status != EFI_SUCCESS) {
|
|
efi_err("Failed to allocate memory\n");
|
|
goto free_cmdline;
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c
|
|
index f99b1bc49694f..1b08749b084b1 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c
|
|
@@ -206,28 +206,32 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx)
|
|
void dcn21_set_pipe(struct pipe_ctx *pipe_ctx)
|
|
{
|
|
struct abm *abm = pipe_ctx->stream_res.abm;
|
|
- uint32_t otg_inst = pipe_ctx->stream_res.tg->inst;
|
|
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
|
|
struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
|
|
struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu;
|
|
+ uint32_t otg_inst;
|
|
+
|
|
+ if (!abm && !tg && !panel_cntl)
|
|
+ return;
|
|
+
|
|
+ otg_inst = tg->inst;
|
|
|
|
if (dmcu) {
|
|
dce110_set_pipe(pipe_ctx);
|
|
return;
|
|
}
|
|
|
|
- if (abm && panel_cntl) {
|
|
- if (abm->funcs && abm->funcs->set_pipe_ex) {
|
|
- abm->funcs->set_pipe_ex(abm,
|
|
+ if (abm->funcs && abm->funcs->set_pipe_ex) {
|
|
+ abm->funcs->set_pipe_ex(abm,
|
|
otg_inst,
|
|
SET_ABM_PIPE_NORMAL,
|
|
panel_cntl->inst,
|
|
panel_cntl->pwrseq_inst);
|
|
- } else {
|
|
- dmub_abm_set_pipe(abm, otg_inst,
|
|
- SET_ABM_PIPE_NORMAL,
|
|
- panel_cntl->inst,
|
|
- panel_cntl->pwrseq_inst);
|
|
- }
|
|
+ } else {
|
|
+ dmub_abm_set_pipe(abm, otg_inst,
|
|
+ SET_ABM_PIPE_NORMAL,
|
|
+ panel_cntl->inst,
|
|
+ panel_cntl->pwrseq_inst);
|
|
}
|
|
}
|
|
|
|
@@ -237,34 +241,35 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx,
|
|
{
|
|
struct dc_context *dc = pipe_ctx->stream->ctx;
|
|
struct abm *abm = pipe_ctx->stream_res.abm;
|
|
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
|
|
struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
|
|
+ uint32_t otg_inst;
|
|
+
|
|
+ if (!abm && !tg && !panel_cntl)
|
|
+ return false;
|
|
+
|
|
+ otg_inst = tg->inst;
|
|
|
|
if (dc->dc->res_pool->dmcu) {
|
|
dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp);
|
|
return true;
|
|
}
|
|
|
|
- if (abm != NULL) {
|
|
- uint32_t otg_inst = pipe_ctx->stream_res.tg->inst;
|
|
-
|
|
- if (abm && panel_cntl) {
|
|
- if (abm->funcs && abm->funcs->set_pipe_ex) {
|
|
- abm->funcs->set_pipe_ex(abm,
|
|
- otg_inst,
|
|
- SET_ABM_PIPE_NORMAL,
|
|
- panel_cntl->inst,
|
|
- panel_cntl->pwrseq_inst);
|
|
- } else {
|
|
- dmub_abm_set_pipe(abm,
|
|
- otg_inst,
|
|
- SET_ABM_PIPE_NORMAL,
|
|
- panel_cntl->inst,
|
|
- panel_cntl->pwrseq_inst);
|
|
- }
|
|
- }
|
|
+ if (abm->funcs && abm->funcs->set_pipe_ex) {
|
|
+ abm->funcs->set_pipe_ex(abm,
|
|
+ otg_inst,
|
|
+ SET_ABM_PIPE_NORMAL,
|
|
+ panel_cntl->inst,
|
|
+ panel_cntl->pwrseq_inst);
|
|
+ } else {
|
|
+ dmub_abm_set_pipe(abm,
|
|
+ otg_inst,
|
|
+ SET_ABM_PIPE_NORMAL,
|
|
+ panel_cntl->inst,
|
|
+ panel_cntl->pwrseq_inst);
|
|
}
|
|
|
|
- if (abm && abm->funcs && abm->funcs->set_backlight_level_pwm)
|
|
+ if (abm->funcs && abm->funcs->set_backlight_level_pwm)
|
|
abm->funcs->set_backlight_level_pwm(abm, backlight_pwm_u16_16,
|
|
frame_ramp, 0, panel_cntl->inst);
|
|
else
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
|
|
index 79d6697d13b67..9485fda890cd7 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
|
|
@@ -996,7 +996,7 @@ static struct stream_encoder *dcn301_stream_encoder_create(enum engine_id eng_id
|
|
vpg = dcn301_vpg_create(ctx, vpg_inst);
|
|
afmt = dcn301_afmt_create(ctx, afmt_inst);
|
|
|
|
- if (!enc1 || !vpg || !afmt) {
|
|
+ if (!enc1 || !vpg || !afmt || eng_id >= ARRAY_SIZE(stream_enc_regs)) {
|
|
kfree(enc1);
|
|
kfree(vpg);
|
|
kfree(afmt);
|
|
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
|
|
index a9f7fa9b90bda..d30f8814d9b10 100644
|
|
--- a/drivers/gpu/drm/i915/gvt/handlers.c
|
|
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
|
|
@@ -2850,8 +2850,7 @@ static int handle_mmio(struct intel_gvt_mmio_table_iter *iter, u32 offset,
|
|
for (i = start; i < end; i += 4) {
|
|
p = intel_gvt_find_mmio_info(gvt, i);
|
|
if (p) {
|
|
- WARN(1, "dup mmio definition offset %x\n",
|
|
- info->offset);
|
|
+ WARN(1, "dup mmio definition offset %x\n", i);
|
|
|
|
/* We return -EEXIST here to make GVT-g load fail.
|
|
* So duplicated MMIO can be found as soon as
|
|
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
|
|
index 7d4cf81fd31c9..ca4e5eae8e064 100644
|
|
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
|
|
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
|
|
@@ -2063,7 +2063,7 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
|
|
}
|
|
|
|
/* reset the merge 3D HW block */
|
|
- if (phys_enc->hw_pp->merge_3d) {
|
|
+ if (phys_enc->hw_pp && phys_enc->hw_pp->merge_3d) {
|
|
phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
|
|
BLEND_3D_NONE);
|
|
if (phys_enc->hw_ctl->ops.update_pending_flush_merge_3d)
|
|
@@ -2085,7 +2085,7 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
|
|
if (phys_enc->hw_wb)
|
|
intf_cfg.wb = phys_enc->hw_wb->idx;
|
|
|
|
- if (phys_enc->hw_pp->merge_3d)
|
|
+ if (phys_enc->hw_pp && phys_enc->hw_pp->merge_3d)
|
|
intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
|
|
|
|
if (ctl->ops.reset_intf_cfg)
|
|
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
|
|
index 77a8d9366ed7b..fb588fde298a2 100644
|
|
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
|
|
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
|
|
@@ -135,11 +135,6 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
|
|
tbd = dp_link_get_test_bits_depth(ctrl->link,
|
|
ctrl->panel->dp_mode.bpp);
|
|
|
|
- if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) {
|
|
- pr_debug("BIT_DEPTH not set. Configure default\n");
|
|
- tbd = DP_TEST_BIT_DEPTH_8;
|
|
- }
|
|
-
|
|
config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
|
|
|
|
/* Num of Lanes */
|
|
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
|
|
index 6375daaeb98e1..25950171caf3e 100644
|
|
--- a/drivers/gpu/drm/msm/dp/dp_link.c
|
|
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
|
|
@@ -7,6 +7,7 @@
|
|
|
|
#include <drm/drm_print.h>
|
|
|
|
+#include "dp_reg.h"
|
|
#include "dp_link.h"
|
|
#include "dp_panel.h"
|
|
|
|
@@ -1114,7 +1115,7 @@ int dp_link_process_request(struct dp_link *dp_link)
|
|
|
|
int dp_link_get_colorimetry_config(struct dp_link *dp_link)
|
|
{
|
|
- u32 cc;
|
|
+ u32 cc = DP_MISC0_COLORIMERY_CFG_LEGACY_RGB;
|
|
struct dp_link_private *link;
|
|
|
|
if (!dp_link) {
|
|
@@ -1128,10 +1129,11 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link)
|
|
* Unless a video pattern CTS test is ongoing, use RGB_VESA
|
|
* Only RGB_VESA and RGB_CEA supported for now
|
|
*/
|
|
- if (dp_link_is_video_pattern_requested(link))
|
|
- cc = link->dp_link.test_video.test_dyn_range;
|
|
- else
|
|
- cc = DP_TEST_DYNAMIC_RANGE_VESA;
|
|
+ if (dp_link_is_video_pattern_requested(link)) {
|
|
+ if (link->dp_link.test_video.test_dyn_range &
|
|
+ DP_TEST_DYNAMIC_RANGE_CEA)
|
|
+ cc = DP_MISC0_COLORIMERY_CFG_CEA_RGB;
|
|
+ }
|
|
|
|
return cc;
|
|
}
|
|
@@ -1211,6 +1213,9 @@ void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link)
|
|
u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
|
|
{
|
|
u32 tbd;
|
|
+ struct dp_link_private *link;
|
|
+
|
|
+ link = container_of(dp_link, struct dp_link_private, dp_link);
|
|
|
|
/*
|
|
* Few simplistic rules and assumptions made here:
|
|
@@ -1228,12 +1233,13 @@ u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
|
|
tbd = DP_TEST_BIT_DEPTH_10;
|
|
break;
|
|
default:
|
|
- tbd = DP_TEST_BIT_DEPTH_UNKNOWN;
|
|
+ drm_dbg_dp(link->drm_dev, "bpp=%d not supported, use bpc=8\n",
|
|
+ bpp);
|
|
+ tbd = DP_TEST_BIT_DEPTH_8;
|
|
break;
|
|
}
|
|
|
|
- if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN)
|
|
- tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);
|
|
+ tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);
|
|
|
|
return tbd;
|
|
}
|
|
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
|
|
index ea85a691e72b5..78785ed4b40c4 100644
|
|
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
|
|
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
|
|
@@ -143,6 +143,9 @@
|
|
#define DP_MISC0_COLORIMETRY_CFG_SHIFT (0x00000001)
|
|
#define DP_MISC0_TEST_BITS_DEPTH_SHIFT (0x00000005)
|
|
|
|
+#define DP_MISC0_COLORIMERY_CFG_LEGACY_RGB (0)
|
|
+#define DP_MISC0_COLORIMERY_CFG_CEA_RGB (0x04)
|
|
+
|
|
#define REG_DP_VALID_BOUNDARY (0x00000030)
|
|
#define REG_DP_VALID_BOUNDARY_2 (0x00000034)
|
|
|
|
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
|
|
index 997df4b405098..b2ae2176f11fe 100644
|
|
--- a/drivers/hwmon/aspeed-pwm-tacho.c
|
|
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
|
|
@@ -193,6 +193,8 @@ struct aspeed_pwm_tacho_data {
|
|
u8 fan_tach_ch_source[16];
|
|
struct aspeed_cooling_device *cdev[8];
|
|
const struct attribute_group *groups[3];
|
|
+ /* protects access to shared ASPEED_PTCR_RESULT */
|
|
+ struct mutex tach_lock;
|
|
};
|
|
|
|
enum type { TYPEM, TYPEN, TYPEO };
|
|
@@ -527,6 +529,8 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
|
|
u8 fan_tach_ch_source, type, mode, both;
|
|
int ret;
|
|
|
|
+ mutex_lock(&priv->tach_lock);
|
|
+
|
|
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
|
|
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
|
|
|
|
@@ -544,6 +548,8 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
|
|
ASPEED_RPM_STATUS_SLEEP_USEC,
|
|
usec);
|
|
|
|
+ mutex_unlock(&priv->tach_lock);
|
|
+
|
|
/* return -ETIMEDOUT if we didn't get an answer. */
|
|
if (ret)
|
|
return ret;
|
|
@@ -903,6 +909,7 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
+ mutex_init(&priv->tach_lock);
|
|
priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs,
|
|
&aspeed_pwm_tacho_regmap_config);
|
|
if (IS_ERR(priv->regmap))
|
|
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
|
|
index ba82d1e79c131..95f4c0b00b2d8 100644
|
|
--- a/drivers/hwmon/coretemp.c
|
|
+++ b/drivers/hwmon/coretemp.c
|
|
@@ -419,7 +419,7 @@ static ssize_t show_temp(struct device *dev,
|
|
}
|
|
|
|
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
|
|
- int attr_no)
|
|
+ int index)
|
|
{
|
|
int i;
|
|
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
|
|
@@ -431,13 +431,20 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
|
|
};
|
|
|
|
for (i = 0; i < tdata->attr_size; i++) {
|
|
+ /*
|
|
+ * We map the attr number to core id of the CPU
|
|
+ * The attr number is always core id + 2
|
|
+ * The Pkgtemp will always show up as temp1_*, if available
|
|
+ */
|
|
+ int attr_no = tdata->is_pkg_data ? 1 : tdata->cpu_core_id + 2;
|
|
+
|
|
snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH,
|
|
"temp%d_%s", attr_no, suffixes[i]);
|
|
sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
|
|
tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
|
|
tdata->sd_attrs[i].dev_attr.attr.mode = 0444;
|
|
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
|
|
- tdata->sd_attrs[i].index = attr_no;
|
|
+ tdata->sd_attrs[i].index = index;
|
|
tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
|
|
}
|
|
tdata->attr_group.attrs = tdata->attrs;
|
|
@@ -495,30 +502,25 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
|
|
struct platform_data *pdata = platform_get_drvdata(pdev);
|
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
|
u32 eax, edx;
|
|
- int err, index, attr_no;
|
|
+ int err, index;
|
|
|
|
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
|
|
return 0;
|
|
|
|
/*
|
|
- * Find attr number for sysfs:
|
|
- * We map the attr number to core id of the CPU
|
|
- * The attr number is always core id + 2
|
|
- * The Pkgtemp will always show up as temp1_*, if available
|
|
+ * Get the index of tdata in pdata->core_data[]
|
|
+ * tdata for package: pdata->core_data[1]
|
|
+ * tdata for core: pdata->core_data[2] .. pdata->core_data[NUM_REAL_CORES + 1]
|
|
*/
|
|
if (pkg_flag) {
|
|
- attr_no = PKG_SYSFS_ATTR_NO;
|
|
+ index = PKG_SYSFS_ATTR_NO;
|
|
} else {
|
|
- index = ida_alloc(&pdata->ida, GFP_KERNEL);
|
|
+ index = ida_alloc_max(&pdata->ida, NUM_REAL_CORES - 1, GFP_KERNEL);
|
|
if (index < 0)
|
|
return index;
|
|
- pdata->cpu_map[index] = topology_core_id(cpu);
|
|
- attr_no = index + BASE_SYSFS_ATTR_NO;
|
|
- }
|
|
|
|
- if (attr_no > MAX_CORE_DATA - 1) {
|
|
- err = -ERANGE;
|
|
- goto ida_free;
|
|
+ pdata->cpu_map[index] = topology_core_id(cpu);
|
|
+ index += BASE_SYSFS_ATTR_NO;
|
|
}
|
|
|
|
tdata = init_temp_data(cpu, pkg_flag);
|
|
@@ -544,20 +546,20 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
|
|
if (get_ttarget(tdata, &pdev->dev) >= 0)
|
|
tdata->attr_size++;
|
|
|
|
- pdata->core_data[attr_no] = tdata;
|
|
+ pdata->core_data[index] = tdata;
|
|
|
|
/* Create sysfs interfaces */
|
|
- err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
|
|
+ err = create_core_attrs(tdata, pdata->hwmon_dev, index);
|
|
if (err)
|
|
goto exit_free;
|
|
|
|
return 0;
|
|
exit_free:
|
|
- pdata->core_data[attr_no] = NULL;
|
|
+ pdata->core_data[index] = NULL;
|
|
kfree(tdata);
|
|
ida_free:
|
|
if (!pkg_flag)
|
|
- ida_free(&pdata->ida, index);
|
|
+ ida_free(&pdata->ida, index - BASE_SYSFS_ATTR_NO);
|
|
return err;
|
|
}
|
|
|
|
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
|
|
index 13ef6284223da..c229bd6b3f7f2 100644
|
|
--- a/drivers/input/keyboard/atkbd.c
|
|
+++ b/drivers/input/keyboard/atkbd.c
|
|
@@ -811,7 +811,6 @@ static int atkbd_probe(struct atkbd *atkbd)
|
|
{
|
|
struct ps2dev *ps2dev = &atkbd->ps2dev;
|
|
unsigned char param[2];
|
|
- bool skip_getid;
|
|
|
|
/*
|
|
* Some systems, where the bit-twiddling when testing the io-lines of the
|
|
@@ -825,6 +824,11 @@ static int atkbd_probe(struct atkbd *atkbd)
|
|
"keyboard reset failed on %s\n",
|
|
ps2dev->serio->phys);
|
|
|
|
+ if (atkbd_skip_getid(atkbd)) {
|
|
+ atkbd->id = 0xab83;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
/*
|
|
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
|
|
* Some keyboards report different values, but the first byte is always 0xab or
|
|
@@ -833,18 +837,17 @@ static int atkbd_probe(struct atkbd *atkbd)
|
|
*/
|
|
|
|
param[0] = param[1] = 0xa5; /* initialize with invalid values */
|
|
- skip_getid = atkbd_skip_getid(atkbd);
|
|
- if (skip_getid || ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
|
|
+ if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
|
|
|
|
/*
|
|
- * If the get ID command was skipped or failed, we check if we can at least set
|
|
+ * If the get ID command failed, we check if we can at least set
|
|
* the LEDs on the keyboard. This should work on every keyboard out there.
|
|
* It also turns the LEDs off, which we want anyway.
|
|
*/
|
|
param[0] = 0;
|
|
if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
|
|
return -1;
|
|
- atkbd->id = skip_getid ? 0xab83 : 0xabba;
|
|
+ atkbd->id = 0xabba;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
|
|
index b585b1dab870e..cd45a65e17f2c 100644
|
|
--- a/drivers/input/serio/i8042-acpipnpio.h
|
|
+++ b/drivers/input/serio/i8042-acpipnpio.h
|
|
@@ -1208,6 +1208,12 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
|
|
SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
|
|
SERIO_QUIRK_NOPNP)
|
|
},
|
|
+ {
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_BOARD_NAME, "NS5x_7xPU"),
|
|
+ },
|
|
+ .driver_data = (void *)(SERIO_QUIRK_NOAUX)
|
|
+ },
|
|
{
|
|
.matches = {
|
|
DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"),
|
|
diff --git a/drivers/media/pci/solo6x10/solo6x10-offsets.h b/drivers/media/pci/solo6x10/solo6x10-offsets.h
|
|
index f414ee1316f29..fdbb817e63601 100644
|
|
--- a/drivers/media/pci/solo6x10/solo6x10-offsets.h
|
|
+++ b/drivers/media/pci/solo6x10/solo6x10-offsets.h
|
|
@@ -57,16 +57,16 @@
|
|
#define SOLO_MP4E_EXT_ADDR(__solo) \
|
|
(SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo))
|
|
#define SOLO_MP4E_EXT_SIZE(__solo) \
|
|
- max((__solo->nr_chans * 0x00080000), \
|
|
- min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \
|
|
- __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000))
|
|
+ clamp(__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo) - \
|
|
+ __SOLO_JPEG_MIN_SIZE(__solo), \
|
|
+ __solo->nr_chans * 0x00080000, 0x00ff0000)
|
|
|
|
#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000)
|
|
#define SOLO_JPEG_EXT_ADDR(__solo) \
|
|
(SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
|
|
#define SOLO_JPEG_EXT_SIZE(__solo) \
|
|
- max(__SOLO_JPEG_MIN_SIZE(__solo), \
|
|
- min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000))
|
|
+ clamp(__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo), \
|
|
+ __SOLO_JPEG_MIN_SIZE(__solo), 0x00ff0000)
|
|
|
|
#define SOLO_SDRAM_END(__solo) \
|
|
(SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo))
|
|
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
|
|
index abd4832e4ed21..5acb3e16b5677 100644
|
|
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
|
|
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
|
|
@@ -993,7 +993,7 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
|
|
return 0;
|
|
|
|
err_exit_hwts_rx:
|
|
- aq_ring_free(&aq_ptp->hwts_rx);
|
|
+ aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
|
|
err_exit_ptp_rx:
|
|
aq_ring_free(&aq_ptp->ptp_rx);
|
|
err_exit_ptp_tx:
|
|
@@ -1011,7 +1011,7 @@ void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
|
|
|
|
aq_ring_free(&aq_ptp->ptp_tx);
|
|
aq_ring_free(&aq_ptp->ptp_rx);
|
|
- aq_ring_free(&aq_ptp->hwts_rx);
|
|
+ aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
|
|
|
|
aq_ptp_skb_ring_release(&aq_ptp->skb_ring);
|
|
}
|
|
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
|
|
index cda8597b4e146..f7433abd65915 100644
|
|
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
|
|
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
|
|
@@ -919,6 +919,19 @@ void aq_ring_free(struct aq_ring_s *self)
|
|
}
|
|
}
|
|
|
|
+void aq_ring_hwts_rx_free(struct aq_ring_s *self)
|
|
+{
|
|
+ if (!self)
|
|
+ return;
|
|
+
|
|
+ if (self->dx_ring) {
|
|
+ dma_free_coherent(aq_nic_get_dev(self->aq_nic),
|
|
+ self->size * self->dx_size + AQ_CFG_RXDS_DEF,
|
|
+ self->dx_ring, self->dx_ring_pa);
|
|
+ self->dx_ring = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data)
|
|
{
|
|
unsigned int count;
|
|
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
|
|
index 52847310740a2..d627ace850ff5 100644
|
|
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
|
|
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
|
|
@@ -210,6 +210,7 @@ int aq_ring_rx_fill(struct aq_ring_s *self);
|
|
int aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
|
|
struct aq_nic_s *aq_nic, unsigned int idx,
|
|
unsigned int size, unsigned int dx_size);
|
|
+void aq_ring_hwts_rx_free(struct aq_ring_s *self);
|
|
void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic);
|
|
|
|
unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data);
|
|
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
|
|
index 08e113e785a76..4f36b29d66c86 100644
|
|
--- a/drivers/net/ethernet/engleder/tsnep_main.c
|
|
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
|
|
@@ -668,17 +668,25 @@ static void tsnep_xdp_xmit_flush(struct tsnep_tx *tx)
|
|
|
|
static bool tsnep_xdp_xmit_back(struct tsnep_adapter *adapter,
|
|
struct xdp_buff *xdp,
|
|
- struct netdev_queue *tx_nq, struct tsnep_tx *tx)
|
|
+ struct netdev_queue *tx_nq, struct tsnep_tx *tx,
|
|
+ bool zc)
|
|
{
|
|
struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
|
|
bool xmit;
|
|
+ u32 type;
|
|
|
|
if (unlikely(!xdpf))
|
|
return false;
|
|
|
|
+ /* no page pool for zero copy */
|
|
+ if (zc)
|
|
+ type = TSNEP_TX_TYPE_XDP_NDO;
|
|
+ else
|
|
+ type = TSNEP_TX_TYPE_XDP_TX;
|
|
+
|
|
__netif_tx_lock(tx_nq, smp_processor_id());
|
|
|
|
- xmit = tsnep_xdp_xmit_frame_ring(xdpf, tx, TSNEP_TX_TYPE_XDP_TX);
|
|
+ xmit = tsnep_xdp_xmit_frame_ring(xdpf, tx, type);
|
|
|
|
/* Avoid transmit queue timeout since we share it with the slow path */
|
|
if (xmit)
|
|
@@ -1222,7 +1230,7 @@ static bool tsnep_xdp_run_prog(struct tsnep_rx *rx, struct bpf_prog *prog,
|
|
case XDP_PASS:
|
|
return false;
|
|
case XDP_TX:
|
|
- if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx))
|
|
+ if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx, false))
|
|
goto out_failure;
|
|
*status |= TSNEP_XDP_TX;
|
|
return true;
|
|
@@ -1272,7 +1280,7 @@ static bool tsnep_xdp_run_prog_zc(struct tsnep_rx *rx, struct bpf_prog *prog,
|
|
case XDP_PASS:
|
|
return false;
|
|
case XDP_TX:
|
|
- if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx))
|
|
+ if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx, true))
|
|
goto out_failure;
|
|
*status |= TSNEP_XDP_TX;
|
|
return true;
|
|
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
|
|
index 629cf1659e5f9..e6df4e6a78ab7 100644
|
|
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
|
|
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
|
|
@@ -951,8 +951,11 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
|
|
if (pfvf->ptp && qidx < pfvf->hw.tx_queues) {
|
|
err = qmem_alloc(pfvf->dev, &sq->timestamps, qset->sqe_cnt,
|
|
sizeof(*sq->timestamps));
|
|
- if (err)
|
|
+ if (err) {
|
|
+ kfree(sq->sg);
|
|
+ sq->sg = NULL;
|
|
return err;
|
|
+ }
|
|
}
|
|
|
|
sq->head = 0;
|
|
@@ -968,7 +971,14 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
|
|
sq->stats.bytes = 0;
|
|
sq->stats.pkts = 0;
|
|
|
|
- return pfvf->hw_ops->sq_aq_init(pfvf, qidx, sqb_aura);
|
|
+ err = pfvf->hw_ops->sq_aq_init(pfvf, qidx, sqb_aura);
|
|
+ if (err) {
|
|
+ kfree(sq->sg);
|
|
+ sq->sg = NULL;
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
|
|
index 1e996c29043dc..3d4f34e178a88 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
|
|
@@ -216,6 +216,7 @@ struct stmmac_safety_stats {
|
|
unsigned long mac_errors[32];
|
|
unsigned long mtl_errors[32];
|
|
unsigned long dma_errors[32];
|
|
+ unsigned long dma_dpp_errors[32];
|
|
};
|
|
|
|
/* Number of fields in Safety Stats */
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
|
|
index a4e8b498dea96..17394847476f3 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
|
|
@@ -319,6 +319,8 @@
|
|
#define XGMAC_RXCEIE BIT(4)
|
|
#define XGMAC_TXCEIE BIT(0)
|
|
#define XGMAC_MTL_ECC_INT_STATUS 0x000010cc
|
|
+#define XGMAC_MTL_DPP_CONTROL 0x000010e0
|
|
+#define XGMAC_DPP_DISABLE BIT(0)
|
|
#define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x)))
|
|
#define XGMAC_TQS GENMASK(25, 16)
|
|
#define XGMAC_TQS_SHIFT 16
|
|
@@ -401,6 +403,7 @@
|
|
#define XGMAC_DCEIE BIT(1)
|
|
#define XGMAC_TCEIE BIT(0)
|
|
#define XGMAC_DMA_ECC_INT_STATUS 0x0000306c
|
|
+#define XGMAC_DMA_DPP_INT_STATUS 0x00003074
|
|
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
|
|
#define XGMAC_SPH BIT(24)
|
|
#define XGMAC_PBLx8 BIT(16)
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
index a74e71db79f94..b5509f244ecd1 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
@@ -830,6 +830,44 @@ static const struct dwxgmac3_error_desc dwxgmac3_dma_errors[32]= {
|
|
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
|
};
|
|
|
|
+#define DPP_RX_ERR "Read Rx Descriptor Parity checker Error"
|
|
+#define DPP_TX_ERR "Read Tx Descriptor Parity checker Error"
|
|
+
|
|
+static const struct dwxgmac3_error_desc dwxgmac3_dma_dpp_errors[32] = {
|
|
+ { true, "TDPES0", DPP_TX_ERR },
|
|
+ { true, "TDPES1", DPP_TX_ERR },
|
|
+ { true, "TDPES2", DPP_TX_ERR },
|
|
+ { true, "TDPES3", DPP_TX_ERR },
|
|
+ { true, "TDPES4", DPP_TX_ERR },
|
|
+ { true, "TDPES5", DPP_TX_ERR },
|
|
+ { true, "TDPES6", DPP_TX_ERR },
|
|
+ { true, "TDPES7", DPP_TX_ERR },
|
|
+ { true, "TDPES8", DPP_TX_ERR },
|
|
+ { true, "TDPES9", DPP_TX_ERR },
|
|
+ { true, "TDPES10", DPP_TX_ERR },
|
|
+ { true, "TDPES11", DPP_TX_ERR },
|
|
+ { true, "TDPES12", DPP_TX_ERR },
|
|
+ { true, "TDPES13", DPP_TX_ERR },
|
|
+ { true, "TDPES14", DPP_TX_ERR },
|
|
+ { true, "TDPES15", DPP_TX_ERR },
|
|
+ { true, "RDPES0", DPP_RX_ERR },
|
|
+ { true, "RDPES1", DPP_RX_ERR },
|
|
+ { true, "RDPES2", DPP_RX_ERR },
|
|
+ { true, "RDPES3", DPP_RX_ERR },
|
|
+ { true, "RDPES4", DPP_RX_ERR },
|
|
+ { true, "RDPES5", DPP_RX_ERR },
|
|
+ { true, "RDPES6", DPP_RX_ERR },
|
|
+ { true, "RDPES7", DPP_RX_ERR },
|
|
+ { true, "RDPES8", DPP_RX_ERR },
|
|
+ { true, "RDPES9", DPP_RX_ERR },
|
|
+ { true, "RDPES10", DPP_RX_ERR },
|
|
+ { true, "RDPES11", DPP_RX_ERR },
|
|
+ { true, "RDPES12", DPP_RX_ERR },
|
|
+ { true, "RDPES13", DPP_RX_ERR },
|
|
+ { true, "RDPES14", DPP_RX_ERR },
|
|
+ { true, "RDPES15", DPP_RX_ERR },
|
|
+};
|
|
+
|
|
static void dwxgmac3_handle_dma_err(struct net_device *ndev,
|
|
void __iomem *ioaddr, bool correctable,
|
|
struct stmmac_safety_stats *stats)
|
|
@@ -841,6 +879,13 @@ static void dwxgmac3_handle_dma_err(struct net_device *ndev,
|
|
|
|
dwxgmac3_log_error(ndev, value, correctable, "DMA",
|
|
dwxgmac3_dma_errors, STAT_OFF(dma_errors), stats);
|
|
+
|
|
+ value = readl(ioaddr + XGMAC_DMA_DPP_INT_STATUS);
|
|
+ writel(value, ioaddr + XGMAC_DMA_DPP_INT_STATUS);
|
|
+
|
|
+ dwxgmac3_log_error(ndev, value, false, "DMA_DPP",
|
|
+ dwxgmac3_dma_dpp_errors,
|
|
+ STAT_OFF(dma_dpp_errors), stats);
|
|
}
|
|
|
|
static int
|
|
@@ -881,6 +926,12 @@ dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
|
|
value |= XGMAC_TMOUTEN; /* FSM Timeout Feature */
|
|
writel(value, ioaddr + XGMAC_MAC_FSM_CONTROL);
|
|
|
|
+ /* 5. Enable Data Path Parity Protection */
|
|
+ value = readl(ioaddr + XGMAC_MTL_DPP_CONTROL);
|
|
+ /* already enabled by default, explicit enable it again */
|
|
+ value &= ~XGMAC_DPP_DISABLE;
|
|
+ writel(value, ioaddr + XGMAC_MTL_DPP_CONTROL);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -914,7 +965,11 @@ static int dwxgmac3_safety_feat_irq_status(struct net_device *ndev,
|
|
ret |= !corr;
|
|
}
|
|
|
|
- err = dma & (XGMAC_DEUIS | XGMAC_DECIS);
|
|
+ /* DMA_DPP_Interrupt_Status is indicated by MCSIS bit in
|
|
+ * DMA_Safety_Interrupt_Status, so we handle DMA Data Path
|
|
+ * Parity Errors here
|
|
+ */
|
|
+ err = dma & (XGMAC_DEUIS | XGMAC_DECIS | XGMAC_MCSIS);
|
|
corr = dma & XGMAC_DECIS;
|
|
if (err) {
|
|
dwxgmac3_handle_dma_err(ndev, ioaddr, corr, stats);
|
|
@@ -930,6 +985,7 @@ static const struct dwxgmac3_error {
|
|
{ dwxgmac3_mac_errors },
|
|
{ dwxgmac3_mtl_errors },
|
|
{ dwxgmac3_dma_errors },
|
|
+ { dwxgmac3_dma_dpp_errors },
|
|
};
|
|
|
|
static int dwxgmac3_safety_feat_dump(struct stmmac_safety_stats *stats,
|
|
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
|
|
index b4d3b9cde8bd6..92a7a36b93ac0 100644
|
|
--- a/drivers/net/netdevsim/dev.c
|
|
+++ b/drivers/net/netdevsim/dev.c
|
|
@@ -835,14 +835,14 @@ static void nsim_dev_trap_report_work(struct work_struct *work)
|
|
trap_report_dw.work);
|
|
nsim_dev = nsim_trap_data->nsim_dev;
|
|
|
|
- /* For each running port and enabled packet trap, generate a UDP
|
|
- * packet with a random 5-tuple and report it.
|
|
- */
|
|
if (!devl_trylock(priv_to_devlink(nsim_dev))) {
|
|
- schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 0);
|
|
+ schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 1);
|
|
return;
|
|
}
|
|
|
|
+ /* For each running port and enabled packet trap, generate a UDP
|
|
+ * packet with a random 5-tuple and report it.
|
|
+ */
|
|
list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) {
|
|
if (!netif_running(nsim_dev_port->ns->netdev))
|
|
continue;
|
|
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
|
|
index fbaaa8c102a1b..e94a4b08fd63b 100644
|
|
--- a/drivers/net/ppp/ppp_async.c
|
|
+++ b/drivers/net/ppp/ppp_async.c
|
|
@@ -460,6 +460,10 @@ ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
|
|
case PPPIOCSMRU:
|
|
if (get_user(val, p))
|
|
break;
|
|
+ if (val > U16_MAX) {
|
|
+ err = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
if (val < PPP_MRU)
|
|
val = PPP_MRU;
|
|
ap->mru = val;
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
index 2a90bb24ba77f..6049f9a761d9d 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
@@ -3780,8 +3780,10 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
|
|
if (req->channels[i] == chan)
|
|
break;
|
|
}
|
|
- if (i == req->n_channels)
|
|
- req->channels[req->n_channels++] = chan;
|
|
+ if (i == req->n_channels) {
|
|
+ req->n_channels++;
|
|
+ req->channels[i] = chan;
|
|
+ }
|
|
|
|
for (i = 0; i < req->n_ssids; i++) {
|
|
if (req->ssids[i].ssid_len == ssid_len &&
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
|
|
index 1e58f02342934..2d1fd7ac8577f 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
|
|
@@ -435,6 +435,9 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|
mvmvif->ap_ibss_active = false;
|
|
}
|
|
|
|
+ iwl_mvm_link_changed(mvm, vif, link_conf,
|
|
+ LINK_CONTEXT_MODIFY_ACTIVE, false);
|
|
+
|
|
if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
|
|
int ret = iwl_mvm_esr_mode_inactive(mvm, vif);
|
|
|
|
@@ -446,9 +449,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|
if (vif->type == NL80211_IFTYPE_MONITOR)
|
|
iwl_mvm_mld_rm_snif_sta(mvm, vif);
|
|
|
|
- iwl_mvm_link_changed(mvm, vif, link_conf,
|
|
- LINK_CONTEXT_MODIFY_ACTIVE, false);
|
|
-
|
|
if (switching_chanctx)
|
|
return;
|
|
mvmvif->link[link_id]->phy_ctxt = NULL;
|
|
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
|
|
index e53eace7c91e3..6387c0d34c551 100644
|
|
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
|
|
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
|
|
@@ -673,8 +673,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|
channel->irq = platform_get_irq_optional(pdev, 0);
|
|
channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
|
|
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
|
|
- int ret;
|
|
-
|
|
channel->is_otg_channel = true;
|
|
channel->uses_otg_pins = !of_property_read_bool(dev->of_node,
|
|
"renesas,no-otg-pins");
|
|
@@ -738,8 +736,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|
ret = PTR_ERR(provider);
|
|
goto error;
|
|
} else if (channel->is_otg_channel) {
|
|
- int ret;
|
|
-
|
|
ret = device_create_file(dev, &dev_attr_role);
|
|
if (ret < 0)
|
|
goto error;
|
|
diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c
|
|
index 762d3de8b3c53..6bd3c74923306 100644
|
|
--- a/drivers/phy/ti/phy-omap-usb2.c
|
|
+++ b/drivers/phy/ti/phy-omap-usb2.c
|
|
@@ -116,7 +116,7 @@ static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
|
|
{
|
|
struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
|
|
|
|
- if (!phy->comparator)
|
|
+ if (!phy->comparator || !phy->comparator->set_vbus)
|
|
return -ENODEV;
|
|
|
|
return phy->comparator->set_vbus(phy->comparator, enabled);
|
|
@@ -126,7 +126,7 @@ static int omap_usb_start_srp(struct usb_otg *otg)
|
|
{
|
|
struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
|
|
|
|
- if (!phy->comparator)
|
|
+ if (!phy->comparator || !phy->comparator->start_srp)
|
|
return -ENODEV;
|
|
|
|
return phy->comparator->start_srp(phy->comparator);
|
|
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
|
|
index 3328b175a8326..43eff1107038a 100644
|
|
--- a/drivers/scsi/scsi_error.c
|
|
+++ b/drivers/scsi/scsi_error.c
|
|
@@ -282,11 +282,12 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head)
|
|
{
|
|
struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
|
|
struct Scsi_Host *shost = scmd->device->host;
|
|
+ unsigned int busy = scsi_host_busy(shost);
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(shost->host_lock, flags);
|
|
shost->host_failed++;
|
|
- scsi_eh_wakeup(shost, scsi_host_busy(shost));
|
|
+ scsi_eh_wakeup(shost, busy);
|
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
|
}
|
|
|
|
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
|
|
index dfdffe55c5a6a..552809bca3507 100644
|
|
--- a/drivers/scsi/scsi_lib.c
|
|
+++ b/drivers/scsi/scsi_lib.c
|
|
@@ -278,9 +278,11 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
|
|
rcu_read_lock();
|
|
__clear_bit(SCMD_STATE_INFLIGHT, &cmd->state);
|
|
if (unlikely(scsi_host_in_recovery(shost))) {
|
|
+ unsigned int busy = scsi_host_busy(shost);
|
|
+
|
|
spin_lock_irqsave(shost->host_lock, flags);
|
|
if (shost->host_failed || shost->host_eh_scheduled)
|
|
- scsi_eh_wakeup(shost, scsi_host_busy(shost));
|
|
+ scsi_eh_wakeup(shost, busy);
|
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
|
}
|
|
rcu_read_unlock();
|
|
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
|
|
index 6604845c397cd..39564e17f3b07 100644
|
|
--- a/drivers/usb/dwc3/dwc3-pci.c
|
|
+++ b/drivers/usb/dwc3/dwc3-pci.c
|
|
@@ -51,6 +51,8 @@
|
|
#define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1
|
|
#define PCI_DEVICE_ID_INTEL_MTLS 0x7f6f
|
|
#define PCI_DEVICE_ID_INTEL_MTL 0x7e7e
|
|
+#define PCI_DEVICE_ID_INTEL_ARLH 0x7ec1
|
|
+#define PCI_DEVICE_ID_INTEL_ARLH_PCH 0x777e
|
|
#define PCI_DEVICE_ID_INTEL_TGL 0x9a15
|
|
#define PCI_DEVICE_ID_AMD_MR 0x163a
|
|
|
|
@@ -421,6 +423,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
|
|
{ PCI_DEVICE_DATA(INTEL, MTLP, &dwc3_pci_intel_swnode) },
|
|
{ PCI_DEVICE_DATA(INTEL, MTL, &dwc3_pci_intel_swnode) },
|
|
{ PCI_DEVICE_DATA(INTEL, MTLS, &dwc3_pci_intel_swnode) },
|
|
+ { PCI_DEVICE_DATA(INTEL, ARLH, &dwc3_pci_intel_swnode) },
|
|
+ { PCI_DEVICE_DATA(INTEL, ARLH_PCH, &dwc3_pci_intel_swnode) },
|
|
{ PCI_DEVICE_DATA(INTEL, TGL, &dwc3_pci_intel_swnode) },
|
|
|
|
{ PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) },
|
|
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
|
|
index 61f57fe5bb783..43230915323c7 100644
|
|
--- a/drivers/usb/dwc3/host.c
|
|
+++ b/drivers/usb/dwc3/host.c
|
|
@@ -61,7 +61,7 @@ out:
|
|
|
|
int dwc3_host_init(struct dwc3 *dwc)
|
|
{
|
|
- struct property_entry props[4];
|
|
+ struct property_entry props[5];
|
|
struct platform_device *xhci;
|
|
int ret, irq;
|
|
int prop_idx = 0;
|
|
@@ -89,6 +89,8 @@ int dwc3_host_init(struct dwc3 *dwc)
|
|
|
|
memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
|
|
|
|
+ props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-sg-trb-cache-size-quirk");
|
|
+
|
|
if (dwc->usb3_lpm_capable)
|
|
props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable");
|
|
|
|
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
|
|
index f0853c4478f57..d68e9abcdc69a 100644
|
|
--- a/drivers/usb/host/xhci-plat.c
|
|
+++ b/drivers/usb/host/xhci-plat.c
|
|
@@ -250,6 +250,9 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
|
|
if (device_property_read_bool(tmpdev, "quirk-broken-port-ped"))
|
|
xhci->quirks |= XHCI_BROKEN_PORT_PED;
|
|
|
|
+ if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
|
|
+ xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
|
|
+
|
|
device_property_read_u32(tmpdev, "imod-interval-ns",
|
|
&xhci->imod_interval);
|
|
}
|
|
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
|
index 3e5dc0723a8fc..c410a98ed63cf 100644
|
|
--- a/drivers/usb/host/xhci-ring.c
|
|
+++ b/drivers/usb/host/xhci-ring.c
|
|
@@ -2377,6 +2377,9 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
|
/* handle completion code */
|
|
switch (trb_comp_code) {
|
|
case COMP_SUCCESS:
|
|
+ /* Don't overwrite status if TD had an error, see xHCI 4.9.1 */
|
|
+ if (td->error_mid_td)
|
|
+ break;
|
|
if (remaining) {
|
|
frame->status = short_framestatus;
|
|
if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
|
|
@@ -2392,9 +2395,13 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
|
case COMP_BANDWIDTH_OVERRUN_ERROR:
|
|
frame->status = -ECOMM;
|
|
break;
|
|
- case COMP_ISOCH_BUFFER_OVERRUN:
|
|
case COMP_BABBLE_DETECTED_ERROR:
|
|
+ sum_trbs_for_length = true;
|
|
+ fallthrough;
|
|
+ case COMP_ISOCH_BUFFER_OVERRUN:
|
|
frame->status = -EOVERFLOW;
|
|
+ if (ep_trb != td->last_trb)
|
|
+ td->error_mid_td = true;
|
|
break;
|
|
case COMP_INCOMPATIBLE_DEVICE_ERROR:
|
|
case COMP_STALL_ERROR:
|
|
@@ -2402,8 +2409,9 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
|
break;
|
|
case COMP_USB_TRANSACTION_ERROR:
|
|
frame->status = -EPROTO;
|
|
+ sum_trbs_for_length = true;
|
|
if (ep_trb != td->last_trb)
|
|
- return 0;
|
|
+ td->error_mid_td = true;
|
|
break;
|
|
case COMP_STOPPED:
|
|
sum_trbs_for_length = true;
|
|
@@ -2423,6 +2431,9 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
|
break;
|
|
}
|
|
|
|
+ if (td->urb_length_set)
|
|
+ goto finish_td;
|
|
+
|
|
if (sum_trbs_for_length)
|
|
frame->actual_length = sum_trb_lengths(xhci, ep->ring, ep_trb) +
|
|
ep_trb_len - remaining;
|
|
@@ -2431,6 +2442,14 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
|
|
|
td->urb->actual_length += frame->actual_length;
|
|
|
|
+finish_td:
|
|
+ /* Don't give back TD yet if we encountered an error mid TD */
|
|
+ if (td->error_mid_td && ep_trb != td->last_trb) {
|
|
+ xhci_dbg(xhci, "Error mid isoc TD, wait for final completion event\n");
|
|
+ td->urb_length_set = true;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
return finish_td(xhci, ep, ep_ring, td, trb_comp_code);
|
|
}
|
|
|
|
@@ -2809,17 +2828,51 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
}
|
|
|
|
if (!ep_seg) {
|
|
- if (!ep->skip ||
|
|
- !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
|
- /* Some host controllers give a spurious
|
|
- * successful event after a short transfer.
|
|
- * Ignore it.
|
|
- */
|
|
- if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
|
|
- ep_ring->last_td_was_short) {
|
|
- ep_ring->last_td_was_short = false;
|
|
- goto cleanup;
|
|
+
|
|
+ if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
|
+ skip_isoc_td(xhci, td, ep, status);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Some hosts give a spurious success event after a short
|
|
+ * transfer. Ignore it.
|
|
+ */
|
|
+ if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
|
|
+ ep_ring->last_td_was_short) {
|
|
+ ep_ring->last_td_was_short = false;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * xhci 4.10.2 states isoc endpoints should continue
|
|
+ * processing the next TD if there was an error mid TD.
|
|
+ * So host like NEC don't generate an event for the last
|
|
+ * isoc TRB even if the IOC flag is set.
|
|
+ * xhci 4.9.1 states that if there are errors in mult-TRB
|
|
+ * TDs xHC should generate an error for that TRB, and if xHC
|
|
+ * proceeds to the next TD it should genete an event for
|
|
+ * any TRB with IOC flag on the way. Other host follow this.
|
|
+ * So this event might be for the next TD.
|
|
+ */
|
|
+ if (td->error_mid_td &&
|
|
+ !list_is_last(&td->td_list, &ep_ring->td_list)) {
|
|
+ struct xhci_td *td_next = list_next_entry(td, td_list);
|
|
+
|
|
+ ep_seg = trb_in_td(xhci, td_next->start_seg, td_next->first_trb,
|
|
+ td_next->last_trb, ep_trb_dma, false);
|
|
+ if (ep_seg) {
|
|
+ /* give back previous TD, start handling new */
|
|
+ xhci_dbg(xhci, "Missing TD completion event after mid TD error\n");
|
|
+ ep_ring->dequeue = td->last_trb;
|
|
+ ep_ring->deq_seg = td->last_trb_seg;
|
|
+ inc_deq(xhci, ep_ring);
|
|
+ xhci_td_cleanup(xhci, td, ep_ring, td->status);
|
|
+ td = td_next;
|
|
}
|
|
+ }
|
|
+
|
|
+ if (!ep_seg) {
|
|
/* HC is busted, give up! */
|
|
xhci_err(xhci,
|
|
"ERROR Transfer event TRB DMA ptr not "
|
|
@@ -2831,9 +2884,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
ep_trb_dma, true);
|
|
return -ESHUTDOWN;
|
|
}
|
|
-
|
|
- skip_isoc_td(xhci, td, ep, status);
|
|
- goto cleanup;
|
|
}
|
|
if (trb_comp_code == COMP_SHORT_PACKET)
|
|
ep_ring->last_td_was_short = true;
|
|
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
|
index 5df370482521f..31088602c0708 100644
|
|
--- a/drivers/usb/host/xhci.h
|
|
+++ b/drivers/usb/host/xhci.h
|
|
@@ -1573,6 +1573,7 @@ struct xhci_td {
|
|
struct xhci_segment *bounce_seg;
|
|
/* actual_length of the URB has already been set */
|
|
bool urb_length_set;
|
|
+ bool error_mid_td;
|
|
unsigned int num_trbs;
|
|
};
|
|
|
|
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
|
|
index 1e61fe0431715..923e0ed85444b 100644
|
|
--- a/drivers/usb/serial/cp210x.c
|
|
+++ b/drivers/usb/serial/cp210x.c
|
|
@@ -146,6 +146,7 @@ static const struct usb_device_id id_table[] = {
|
|
{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
|
|
{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
|
|
{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
|
|
+ { USB_DEVICE(0x10C4, 0x87ED) }, /* IMST USB-Stick for Smart Meter */
|
|
{ USB_DEVICE(0x10C4, 0x8856) }, /* CEL EM357 ZigBee USB Stick - LR */
|
|
{ USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */
|
|
{ USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
|
|
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
|
|
index 72390dbf07692..2ae124c49d448 100644
|
|
--- a/drivers/usb/serial/option.c
|
|
+++ b/drivers/usb/serial/option.c
|
|
@@ -2269,6 +2269,7 @@ static const struct usb_device_id option_ids[] = {
|
|
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0111, 0xff) }, /* Fibocom FM160 (MBIM mode) */
|
|
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
|
|
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a2, 0xff) }, /* Fibocom FM101-GL (laptop MBIM) */
|
|
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a3, 0xff) }, /* Fibocom FM101-GL (laptop MBIM) */
|
|
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a4, 0xff), /* Fibocom FM101-GL (laptop MBIM) */
|
|
.driver_info = RSVD(4) },
|
|
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
|
|
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
|
|
index b1e844bf31f81..703a9c5635573 100644
|
|
--- a/drivers/usb/serial/qcserial.c
|
|
+++ b/drivers/usb/serial/qcserial.c
|
|
@@ -184,6 +184,8 @@ static const struct usb_device_id id_table[] = {
|
|
{DEVICE_SWI(0x413c, 0x81d0)}, /* Dell Wireless 5819 */
|
|
{DEVICE_SWI(0x413c, 0x81d1)}, /* Dell Wireless 5818 */
|
|
{DEVICE_SWI(0x413c, 0x81d2)}, /* Dell Wireless 5818 */
|
|
+ {DEVICE_SWI(0x413c, 0x8217)}, /* Dell Wireless DW5826e */
|
|
+ {DEVICE_SWI(0x413c, 0x8218)}, /* Dell Wireless DW5826e QDL */
|
|
|
|
/* Huawei devices */
|
|
{DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
|
|
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
|
|
index 6d455ca76125e..47ae2d520fda5 100644
|
|
--- a/drivers/usb/typec/tcpm/tcpm.c
|
|
+++ b/drivers/usb/typec/tcpm/tcpm.c
|
|
@@ -4862,8 +4862,7 @@ static void run_state_machine(struct tcpm_port *port)
|
|
break;
|
|
case PORT_RESET:
|
|
tcpm_reset_port(port);
|
|
- tcpm_set_cc(port, tcpm_default_state(port) == SNK_UNATTACHED ?
|
|
- TYPEC_CC_RD : tcpm_rp_cc(port));
|
|
+ tcpm_set_cc(port, TYPEC_CC_OPEN);
|
|
tcpm_set_state(port, PORT_RESET_WAIT_OFF,
|
|
PD_T_ERROR_RECOVERY);
|
|
break;
|
|
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
|
|
index 1fd4ed19060db..529ca47da0353 100644
|
|
--- a/fs/ext4/mballoc.c
|
|
+++ b/fs/ext4/mballoc.c
|
|
@@ -1232,6 +1232,24 @@ void ext4_mb_generate_buddy(struct super_block *sb,
|
|
atomic64_add(period, &sbi->s_mb_generation_time);
|
|
}
|
|
|
|
+static void mb_regenerate_buddy(struct ext4_buddy *e4b)
|
|
+{
|
|
+ int count;
|
|
+ int order = 1;
|
|
+ void *buddy;
|
|
+
|
|
+ while ((buddy = mb_find_buddy(e4b, order++, &count)))
|
|
+ mb_set_bits(buddy, 0, count);
|
|
+
|
|
+ e4b->bd_info->bb_fragments = 0;
|
|
+ memset(e4b->bd_info->bb_counters, 0,
|
|
+ sizeof(*e4b->bd_info->bb_counters) *
|
|
+ (e4b->bd_sb->s_blocksize_bits + 2));
|
|
+
|
|
+ ext4_mb_generate_buddy(e4b->bd_sb, e4b->bd_buddy,
|
|
+ e4b->bd_bitmap, e4b->bd_group, e4b->bd_info);
|
|
+}
|
|
+
|
|
/* The buddy information is attached the buddy cache inode
|
|
* for convenience. The information regarding each group
|
|
* is loaded via ext4_mb_load_buddy. The information involve
|
|
@@ -1920,6 +1938,8 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
|
|
ext4_mark_group_bitmap_corrupted(
|
|
sb, e4b->bd_group,
|
|
EXT4_GROUP_INFO_BBITMAP_CORRUPT);
|
|
+ } else {
|
|
+ mb_regenerate_buddy(e4b);
|
|
}
|
|
goto done;
|
|
}
|
|
diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
|
|
index 0e6a2777870c3..29a9b0b29e4f8 100644
|
|
--- a/fs/ntfs3/ntfs_fs.h
|
|
+++ b/fs/ntfs3/ntfs_fs.h
|
|
@@ -473,7 +473,7 @@ bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
|
|
int al_update(struct ntfs_inode *ni, int sync);
|
|
static inline size_t al_aligned(size_t size)
|
|
{
|
|
- return (size + 1023) & ~(size_t)1023;
|
|
+ return size_add(size, 1023) & ~(size_t)1023;
|
|
}
|
|
|
|
/* Globals from bitfunc.c */
|
|
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
|
|
index 62596299a3964..a20a5d0836dc9 100644
|
|
--- a/fs/smb/client/sess.c
|
|
+++ b/fs/smb/client/sess.c
|
|
@@ -263,6 +263,8 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
|
|
&iface->sockaddr,
|
|
rc);
|
|
kref_put(&iface->refcount, release_iface);
|
|
+ /* failure to add chan should increase weight */
|
|
+ iface->weight_fulfilled++;
|
|
continue;
|
|
}
|
|
|
|
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
|
|
index f5006aa97f5b3..5d9c87d2e1e01 100644
|
|
--- a/fs/smb/client/smb2pdu.c
|
|
+++ b/fs/smb/client/smb2pdu.c
|
|
@@ -410,7 +410,7 @@ skip_sess_setup:
|
|
rc = SMB3_request_interfaces(xid, tcon, false);
|
|
free_xid(xid);
|
|
|
|
- if (rc == -EOPNOTSUPP) {
|
|
+ if (rc == -EOPNOTSUPP && ses->chan_count > 1) {
|
|
/*
|
|
* some servers like Azure SMB server do not advertise
|
|
* that multichannel has been disabled with server
|
|
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
|
|
index ed0bc8cbc703d..567fb37274d35 100644
|
|
--- a/fs/xfs/Kconfig
|
|
+++ b/fs/xfs/Kconfig
|
|
@@ -147,7 +147,7 @@ config XFS_ONLINE_SCRUB_STATS
|
|
bool "XFS online metadata check usage data collection"
|
|
default y
|
|
depends on XFS_ONLINE_SCRUB
|
|
- select XFS_DEBUG
|
|
+ select DEBUG_FS
|
|
help
|
|
If you say Y here, the kernel will gather usage data about
|
|
the online metadata check subsystem. This includes the number
|
|
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
|
|
index 3069194527dd0..100ab5931b313 100644
|
|
--- a/fs/xfs/libxfs/xfs_alloc.c
|
|
+++ b/fs/xfs/libxfs/xfs_alloc.c
|
|
@@ -2275,16 +2275,37 @@ xfs_alloc_min_freelist(
|
|
|
|
ASSERT(mp->m_alloc_maxlevels > 0);
|
|
|
|
+ /*
|
|
+ * For a btree shorter than the maximum height, the worst case is that
|
|
+ * every level gets split and a new level is added, then while inserting
|
|
+ * another entry to refill the AGFL, every level under the old root gets
|
|
+ * split again. This is:
|
|
+ *
|
|
+ * (full height split reservation) + (AGFL refill split height)
|
|
+ * = (current height + 1) + (current height - 1)
|
|
+ * = (new height) + (new height - 2)
|
|
+ * = 2 * new height - 2
|
|
+ *
|
|
+ * For a btree of maximum height, the worst case is that every level
|
|
+ * under the root gets split, then while inserting another entry to
|
|
+ * refill the AGFL, every level under the root gets split again. This is
|
|
+ * also:
|
|
+ *
|
|
+ * 2 * (current height - 1)
|
|
+ * = 2 * (new height - 1)
|
|
+ * = 2 * new height - 2
|
|
+ */
|
|
+
|
|
/* space needed by-bno freespace btree */
|
|
min_free = min_t(unsigned int, levels[XFS_BTNUM_BNOi] + 1,
|
|
- mp->m_alloc_maxlevels);
|
|
+ mp->m_alloc_maxlevels) * 2 - 2;
|
|
/* space needed by-size freespace btree */
|
|
min_free += min_t(unsigned int, levels[XFS_BTNUM_CNTi] + 1,
|
|
- mp->m_alloc_maxlevels);
|
|
+ mp->m_alloc_maxlevels) * 2 - 2;
|
|
/* space needed reverse mapping used space btree */
|
|
if (xfs_has_rmapbt(mp))
|
|
min_free += min_t(unsigned int, levels[XFS_BTNUM_RMAPi] + 1,
|
|
- mp->m_rmap_maxlevels);
|
|
+ mp->m_rmap_maxlevels) * 2 - 2;
|
|
|
|
return min_free;
|
|
}
|
|
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
|
|
index 30c931b38853c..617cc7e78e384 100644
|
|
--- a/fs/xfs/libxfs/xfs_bmap.c
|
|
+++ b/fs/xfs/libxfs/xfs_bmap.c
|
|
@@ -4827,7 +4827,7 @@ xfs_bmap_del_extent_delay(
|
|
ASSERT(got_endoff >= del_endoff);
|
|
|
|
if (isrt) {
|
|
- uint64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount);
|
|
+ uint64_t rtexts = del->br_blockcount;
|
|
|
|
do_div(rtexts, mp->m_sb.sb_rextsize);
|
|
xfs_mod_frextents(mp, rtexts);
|
|
@@ -5057,33 +5057,20 @@ xfs_bmap_del_extent_real(
|
|
|
|
flags = XFS_ILOG_CORE;
|
|
if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) {
|
|
- xfs_filblks_t len;
|
|
- xfs_extlen_t mod;
|
|
-
|
|
- len = div_u64_rem(del->br_blockcount, mp->m_sb.sb_rextsize,
|
|
- &mod);
|
|
- ASSERT(mod == 0);
|
|
-
|
|
if (!(bflags & XFS_BMAPI_REMAP)) {
|
|
- xfs_fsblock_t bno;
|
|
-
|
|
- bno = div_u64_rem(del->br_startblock,
|
|
- mp->m_sb.sb_rextsize, &mod);
|
|
- ASSERT(mod == 0);
|
|
-
|
|
- error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len);
|
|
+ error = xfs_rtfree_blocks(tp, del->br_startblock,
|
|
+ del->br_blockcount);
|
|
if (error)
|
|
goto done;
|
|
}
|
|
|
|
do_fx = 0;
|
|
- nblks = len * mp->m_sb.sb_rextsize;
|
|
qfield = XFS_TRANS_DQ_RTBCOUNT;
|
|
} else {
|
|
do_fx = 1;
|
|
- nblks = del->br_blockcount;
|
|
qfield = XFS_TRANS_DQ_BCOUNT;
|
|
}
|
|
+ nblks = del->br_blockcount;
|
|
|
|
del_endblock = del->br_startblock + del->br_blockcount;
|
|
if (cur) {
|
|
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
|
|
index bcfb6a4203cdd..f71679ce23b95 100644
|
|
--- a/fs/xfs/libxfs/xfs_defer.c
|
|
+++ b/fs/xfs/libxfs/xfs_defer.c
|
|
@@ -245,21 +245,18 @@ xfs_defer_create_intents(
|
|
return ret;
|
|
}
|
|
|
|
-/* Abort all the intents that were committed. */
|
|
STATIC void
|
|
-xfs_defer_trans_abort(
|
|
- struct xfs_trans *tp,
|
|
- struct list_head *dop_pending)
|
|
+xfs_defer_pending_abort(
|
|
+ struct xfs_mount *mp,
|
|
+ struct list_head *dop_list)
|
|
{
|
|
struct xfs_defer_pending *dfp;
|
|
const struct xfs_defer_op_type *ops;
|
|
|
|
- trace_xfs_defer_trans_abort(tp, _RET_IP_);
|
|
-
|
|
/* Abort intent items that don't have a done item. */
|
|
- list_for_each_entry(dfp, dop_pending, dfp_list) {
|
|
+ list_for_each_entry(dfp, dop_list, dfp_list) {
|
|
ops = defer_op_types[dfp->dfp_type];
|
|
- trace_xfs_defer_pending_abort(tp->t_mountp, dfp);
|
|
+ trace_xfs_defer_pending_abort(mp, dfp);
|
|
if (dfp->dfp_intent && !dfp->dfp_done) {
|
|
ops->abort_intent(dfp->dfp_intent);
|
|
dfp->dfp_intent = NULL;
|
|
@@ -267,6 +264,16 @@ xfs_defer_trans_abort(
|
|
}
|
|
}
|
|
|
|
+/* Abort all the intents that were committed. */
|
|
+STATIC void
|
|
+xfs_defer_trans_abort(
|
|
+ struct xfs_trans *tp,
|
|
+ struct list_head *dop_pending)
|
|
+{
|
|
+ trace_xfs_defer_trans_abort(tp, _RET_IP_);
|
|
+ xfs_defer_pending_abort(tp->t_mountp, dop_pending);
|
|
+}
|
|
+
|
|
/*
|
|
* Capture resources that the caller said not to release ("held") when the
|
|
* transaction commits. Caller is responsible for zero-initializing @dres.
|
|
@@ -756,12 +763,13 @@ xfs_defer_ops_capture(
|
|
|
|
/* Release all resources that we used to capture deferred ops. */
|
|
void
|
|
-xfs_defer_ops_capture_free(
|
|
+xfs_defer_ops_capture_abort(
|
|
struct xfs_mount *mp,
|
|
struct xfs_defer_capture *dfc)
|
|
{
|
|
unsigned short i;
|
|
|
|
+ xfs_defer_pending_abort(mp, &dfc->dfc_dfops);
|
|
xfs_defer_cancel_list(mp, &dfc->dfc_dfops);
|
|
|
|
for (i = 0; i < dfc->dfc_held.dr_bufs; i++)
|
|
@@ -802,7 +810,7 @@ xfs_defer_ops_capture_and_commit(
|
|
/* Commit the transaction and add the capture structure to the list. */
|
|
error = xfs_trans_commit(tp);
|
|
if (error) {
|
|
- xfs_defer_ops_capture_free(mp, dfc);
|
|
+ xfs_defer_ops_capture_abort(mp, dfc);
|
|
return error;
|
|
}
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
|
|
index 114a3a4930a3c..8788ad5f6a731 100644
|
|
--- a/fs/xfs/libxfs/xfs_defer.h
|
|
+++ b/fs/xfs/libxfs/xfs_defer.h
|
|
@@ -121,7 +121,7 @@ int xfs_defer_ops_capture_and_commit(struct xfs_trans *tp,
|
|
struct list_head *capture_list);
|
|
void xfs_defer_ops_continue(struct xfs_defer_capture *d, struct xfs_trans *tp,
|
|
struct xfs_defer_resources *dres);
|
|
-void xfs_defer_ops_capture_free(struct xfs_mount *mp,
|
|
+void xfs_defer_ops_capture_abort(struct xfs_mount *mp,
|
|
struct xfs_defer_capture *d);
|
|
void xfs_defer_resources_rele(struct xfs_defer_resources *dres);
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
|
|
index a35781577cad9..0f970a0b33824 100644
|
|
--- a/fs/xfs/libxfs/xfs_inode_buf.c
|
|
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
|
|
@@ -508,6 +508,9 @@ xfs_dinode_verify(
|
|
if (mode && nextents + naextents > nblocks)
|
|
return __this_address;
|
|
|
|
+ if (nextents + naextents == 0 && nblocks != 0)
|
|
+ return __this_address;
|
|
+
|
|
if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents)
|
|
return __this_address;
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
|
|
index fa180ab66b73a..655108a4cd05d 100644
|
|
--- a/fs/xfs/libxfs/xfs_rtbitmap.c
|
|
+++ b/fs/xfs/libxfs/xfs_rtbitmap.c
|
|
@@ -1005,6 +1005,39 @@ xfs_rtfree_extent(
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * Free some blocks in the realtime subvolume. rtbno and rtlen are in units of
|
|
+ * rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen
|
|
+ * cannot exceed XFS_MAX_BMBT_EXTLEN.
|
|
+ */
|
|
+int
|
|
+xfs_rtfree_blocks(
|
|
+ struct xfs_trans *tp,
|
|
+ xfs_fsblock_t rtbno,
|
|
+ xfs_filblks_t rtlen)
|
|
+{
|
|
+ struct xfs_mount *mp = tp->t_mountp;
|
|
+ xfs_rtblock_t bno;
|
|
+ xfs_filblks_t len;
|
|
+ xfs_extlen_t mod;
|
|
+
|
|
+ ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN);
|
|
+
|
|
+ len = div_u64_rem(rtlen, mp->m_sb.sb_rextsize, &mod);
|
|
+ if (mod) {
|
|
+ ASSERT(mod == 0);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ bno = div_u64_rem(rtbno, mp->m_sb.sb_rextsize, &mod);
|
|
+ if (mod) {
|
|
+ ASSERT(mod == 0);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ return xfs_rtfree_extent(tp, bno, len);
|
|
+}
|
|
+
|
|
/* Find all the free records within a given range. */
|
|
int
|
|
xfs_rtalloc_query_range(
|
|
diff --git a/fs/xfs/libxfs/xfs_sb.h b/fs/xfs/libxfs/xfs_sb.h
|
|
index a5e14740ec9ac..19134b23c10be 100644
|
|
--- a/fs/xfs/libxfs/xfs_sb.h
|
|
+++ b/fs/xfs/libxfs/xfs_sb.h
|
|
@@ -25,7 +25,7 @@ extern uint64_t xfs_sb_version_to_features(struct xfs_sb *sbp);
|
|
|
|
extern int xfs_update_secondary_sbs(struct xfs_mount *mp);
|
|
|
|
-#define XFS_FS_GEOM_MAX_STRUCT_VER (4)
|
|
+#define XFS_FS_GEOM_MAX_STRUCT_VER (5)
|
|
extern void xfs_fs_geometry(struct xfs_mount *mp, struct xfs_fsop_geom *geo,
|
|
int struct_version);
|
|
extern int xfs_sb_read_secondary(struct xfs_mount *mp,
|
|
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
|
|
index fcefab6872859..ad4aba5002c12 100644
|
|
--- a/fs/xfs/xfs_bmap_util.c
|
|
+++ b/fs/xfs/xfs_bmap_util.c
|
|
@@ -780,12 +780,10 @@ xfs_alloc_file_space(
|
|
{
|
|
xfs_mount_t *mp = ip->i_mount;
|
|
xfs_off_t count;
|
|
- xfs_filblks_t allocated_fsb;
|
|
xfs_filblks_t allocatesize_fsb;
|
|
xfs_extlen_t extsz, temp;
|
|
xfs_fileoff_t startoffset_fsb;
|
|
xfs_fileoff_t endoffset_fsb;
|
|
- int nimaps;
|
|
int rt;
|
|
xfs_trans_t *tp;
|
|
xfs_bmbt_irec_t imaps[1], *imapp;
|
|
@@ -808,7 +806,6 @@ xfs_alloc_file_space(
|
|
|
|
count = len;
|
|
imapp = &imaps[0];
|
|
- nimaps = 1;
|
|
startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
|
|
endoffset_fsb = XFS_B_TO_FSB(mp, offset + count);
|
|
allocatesize_fsb = endoffset_fsb - startoffset_fsb;
|
|
@@ -819,6 +816,7 @@ xfs_alloc_file_space(
|
|
while (allocatesize_fsb && !error) {
|
|
xfs_fileoff_t s, e;
|
|
unsigned int dblocks, rblocks, resblks;
|
|
+ int nimaps = 1;
|
|
|
|
/*
|
|
* Determine space reservations for data/realtime.
|
|
@@ -884,15 +882,19 @@ xfs_alloc_file_space(
|
|
if (error)
|
|
break;
|
|
|
|
- allocated_fsb = imapp->br_blockcount;
|
|
-
|
|
- if (nimaps == 0) {
|
|
- error = -ENOSPC;
|
|
- break;
|
|
+ /*
|
|
+ * If the allocator cannot find a single free extent large
|
|
+ * enough to cover the start block of the requested range,
|
|
+ * xfs_bmapi_write will return 0 but leave *nimaps set to 0.
|
|
+ *
|
|
+ * In that case we simply need to keep looping with the same
|
|
+ * startoffset_fsb so that one of the following allocations
|
|
+ * will eventually reach the requested range.
|
|
+ */
|
|
+ if (nimaps) {
|
|
+ startoffset_fsb += imapp->br_blockcount;
|
|
+ allocatesize_fsb -= imapp->br_blockcount;
|
|
}
|
|
-
|
|
- startoffset_fsb += allocated_fsb;
|
|
- allocatesize_fsb -= allocated_fsb;
|
|
}
|
|
|
|
return error;
|
|
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
|
|
index ac6ba646624df..a013b87ab8d5e 100644
|
|
--- a/fs/xfs/xfs_dquot.c
|
|
+++ b/fs/xfs/xfs_dquot.c
|
|
@@ -562,7 +562,8 @@ xfs_dquot_from_disk(
|
|
struct xfs_dquot *dqp,
|
|
struct xfs_buf *bp)
|
|
{
|
|
- struct xfs_disk_dquot *ddqp = bp->b_addr + dqp->q_bufoffset;
|
|
+ struct xfs_dqblk *dqb = xfs_buf_offset(bp, dqp->q_bufoffset);
|
|
+ struct xfs_disk_dquot *ddqp = &dqb->dd_diskdq;
|
|
|
|
/*
|
|
* Ensure that we got the type and ID we were looking for.
|
|
@@ -1250,7 +1251,7 @@ xfs_qm_dqflush(
|
|
}
|
|
|
|
/* Flush the incore dquot to the ondisk buffer. */
|
|
- dqblk = bp->b_addr + dqp->q_bufoffset;
|
|
+ dqblk = xfs_buf_offset(bp, dqp->q_bufoffset);
|
|
xfs_dquot_to_disk(&dqblk->dd_diskdq, dqp);
|
|
|
|
/*
|
|
diff --git a/fs/xfs/xfs_dquot_item_recover.c b/fs/xfs/xfs_dquot_item_recover.c
|
|
index 8966ba842395b..2c2720ce69238 100644
|
|
--- a/fs/xfs/xfs_dquot_item_recover.c
|
|
+++ b/fs/xfs/xfs_dquot_item_recover.c
|
|
@@ -19,6 +19,7 @@
|
|
#include "xfs_log.h"
|
|
#include "xfs_log_priv.h"
|
|
#include "xfs_log_recover.h"
|
|
+#include "xfs_error.h"
|
|
|
|
STATIC void
|
|
xlog_recover_dquot_ra_pass2(
|
|
@@ -65,6 +66,7 @@ xlog_recover_dquot_commit_pass2(
|
|
{
|
|
struct xfs_mount *mp = log->l_mp;
|
|
struct xfs_buf *bp;
|
|
+ struct xfs_dqblk *dqb;
|
|
struct xfs_disk_dquot *ddq, *recddq;
|
|
struct xfs_dq_logformat *dq_f;
|
|
xfs_failaddr_t fa;
|
|
@@ -130,14 +132,14 @@ xlog_recover_dquot_commit_pass2(
|
|
return error;
|
|
|
|
ASSERT(bp);
|
|
- ddq = xfs_buf_offset(bp, dq_f->qlf_boffset);
|
|
+ dqb = xfs_buf_offset(bp, dq_f->qlf_boffset);
|
|
+ ddq = &dqb->dd_diskdq;
|
|
|
|
/*
|
|
* If the dquot has an LSN in it, recover the dquot only if it's less
|
|
* than the lsn of the transaction we are replaying.
|
|
*/
|
|
if (xfs_has_crc(mp)) {
|
|
- struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq;
|
|
xfs_lsn_t lsn = be64_to_cpu(dqb->dd_lsn);
|
|
|
|
if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
|
|
@@ -147,10 +149,23 @@ xlog_recover_dquot_commit_pass2(
|
|
|
|
memcpy(ddq, recddq, item->ri_buf[1].i_len);
|
|
if (xfs_has_crc(mp)) {
|
|
- xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk),
|
|
+ xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
|
|
XFS_DQUOT_CRC_OFF);
|
|
}
|
|
|
|
+ /* Validate the recovered dquot. */
|
|
+ fa = xfs_dqblk_verify(log->l_mp, dqb, dq_f->qlf_id);
|
|
+ if (fa) {
|
|
+ XFS_CORRUPTION_ERROR("Bad dquot after recovery",
|
|
+ XFS_ERRLEVEL_LOW, mp, dqb,
|
|
+ sizeof(struct xfs_dqblk));
|
|
+ xfs_alert(mp,
|
|
+ "Metadata corruption detected at %pS, dquot 0x%x",
|
|
+ fa, dq_f->qlf_id);
|
|
+ error = -EFSCORRUPTED;
|
|
+ goto out_release;
|
|
+ }
|
|
+
|
|
ASSERT(dq_f->qlf_size == 2);
|
|
ASSERT(bp->b_mount == mp);
|
|
bp->b_flags |= _XBF_LOGRECOVERY;
|
|
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
|
|
index 203700278ddbb..e33e5e13b95f4 100644
|
|
--- a/fs/xfs/xfs_file.c
|
|
+++ b/fs/xfs/xfs_file.c
|
|
@@ -214,6 +214,43 @@ xfs_ilock_iocb(
|
|
return 0;
|
|
}
|
|
|
|
+static int
|
|
+xfs_ilock_iocb_for_write(
|
|
+ struct kiocb *iocb,
|
|
+ unsigned int *lock_mode)
|
|
+{
|
|
+ ssize_t ret;
|
|
+ struct xfs_inode *ip = XFS_I(file_inode(iocb->ki_filp));
|
|
+
|
|
+ ret = xfs_ilock_iocb(iocb, *lock_mode);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (*lock_mode == XFS_IOLOCK_EXCL)
|
|
+ return 0;
|
|
+ if (!xfs_iflags_test(ip, XFS_IREMAPPING))
|
|
+ return 0;
|
|
+
|
|
+ xfs_iunlock(ip, *lock_mode);
|
|
+ *lock_mode = XFS_IOLOCK_EXCL;
|
|
+ return xfs_ilock_iocb(iocb, *lock_mode);
|
|
+}
|
|
+
|
|
+static unsigned int
|
|
+xfs_ilock_for_write_fault(
|
|
+ struct xfs_inode *ip)
|
|
+{
|
|
+ /* get a shared lock if no remapping in progress */
|
|
+ xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
|
|
+ if (!xfs_iflags_test(ip, XFS_IREMAPPING))
|
|
+ return XFS_MMAPLOCK_SHARED;
|
|
+
|
|
+ /* wait for remapping to complete */
|
|
+ xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
|
|
+ xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
|
|
+ return XFS_MMAPLOCK_EXCL;
|
|
+}
|
|
+
|
|
STATIC ssize_t
|
|
xfs_file_dio_read(
|
|
struct kiocb *iocb,
|
|
@@ -551,7 +588,7 @@ xfs_file_dio_write_aligned(
|
|
unsigned int iolock = XFS_IOLOCK_SHARED;
|
|
ssize_t ret;
|
|
|
|
- ret = xfs_ilock_iocb(iocb, iolock);
|
|
+ ret = xfs_ilock_iocb_for_write(iocb, &iolock);
|
|
if (ret)
|
|
return ret;
|
|
ret = xfs_file_write_checks(iocb, from, &iolock);
|
|
@@ -618,7 +655,7 @@ retry_exclusive:
|
|
flags = IOMAP_DIO_FORCE_WAIT;
|
|
}
|
|
|
|
- ret = xfs_ilock_iocb(iocb, iolock);
|
|
+ ret = xfs_ilock_iocb_for_write(iocb, &iolock);
|
|
if (ret)
|
|
return ret;
|
|
|
|
@@ -1180,7 +1217,7 @@ xfs_file_remap_range(
|
|
if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out))
|
|
xfs_log_force_inode(dest);
|
|
out_unlock:
|
|
- xfs_iunlock2_io_mmap(src, dest);
|
|
+ xfs_iunlock2_remapping(src, dest);
|
|
if (ret)
|
|
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
|
|
return remapped > 0 ? remapped : ret;
|
|
@@ -1328,6 +1365,7 @@ __xfs_filemap_fault(
|
|
struct inode *inode = file_inode(vmf->vma->vm_file);
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
vm_fault_t ret;
|
|
+ unsigned int lock_mode = 0;
|
|
|
|
trace_xfs_filemap_fault(ip, order, write_fault);
|
|
|
|
@@ -1336,25 +1374,24 @@ __xfs_filemap_fault(
|
|
file_update_time(vmf->vma->vm_file);
|
|
}
|
|
|
|
+ if (IS_DAX(inode) || write_fault)
|
|
+ lock_mode = xfs_ilock_for_write_fault(XFS_I(inode));
|
|
+
|
|
if (IS_DAX(inode)) {
|
|
pfn_t pfn;
|
|
|
|
- xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
|
|
ret = xfs_dax_fault(vmf, order, write_fault, &pfn);
|
|
if (ret & VM_FAULT_NEEDDSYNC)
|
|
ret = dax_finish_sync_fault(vmf, order, pfn);
|
|
- xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
|
|
+ } else if (write_fault) {
|
|
+ ret = iomap_page_mkwrite(vmf, &xfs_page_mkwrite_iomap_ops);
|
|
} else {
|
|
- if (write_fault) {
|
|
- xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
|
|
- ret = iomap_page_mkwrite(vmf,
|
|
- &xfs_page_mkwrite_iomap_ops);
|
|
- xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
|
|
- } else {
|
|
- ret = filemap_fault(vmf);
|
|
- }
|
|
+ ret = filemap_fault(vmf);
|
|
}
|
|
|
|
+ if (lock_mode)
|
|
+ xfs_iunlock(XFS_I(inode), lock_mode);
|
|
+
|
|
if (write_fault)
|
|
sb_end_pagefault(inode->i_sb);
|
|
return ret;
|
|
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
|
|
index 4d55f58d99b7a..f9d29acd72b9e 100644
|
|
--- a/fs/xfs/xfs_inode.c
|
|
+++ b/fs/xfs/xfs_inode.c
|
|
@@ -918,6 +918,13 @@ xfs_droplink(
|
|
xfs_trans_t *tp,
|
|
xfs_inode_t *ip)
|
|
{
|
|
+ if (VFS_I(ip)->i_nlink == 0) {
|
|
+ xfs_alert(ip->i_mount,
|
|
+ "%s: Attempt to drop inode (%llu) with nlink zero.",
|
|
+ __func__, ip->i_ino);
|
|
+ return -EFSCORRUPTED;
|
|
+ }
|
|
+
|
|
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
|
|
|
|
drop_nlink(VFS_I(ip));
|
|
@@ -3621,6 +3628,23 @@ xfs_iunlock2_io_mmap(
|
|
inode_unlock(VFS_I(ip1));
|
|
}
|
|
|
|
+/* Drop the MMAPLOCK and the IOLOCK after a remap completes. */
|
|
+void
|
|
+xfs_iunlock2_remapping(
|
|
+ struct xfs_inode *ip1,
|
|
+ struct xfs_inode *ip2)
|
|
+{
|
|
+ xfs_iflags_clear(ip1, XFS_IREMAPPING);
|
|
+
|
|
+ if (ip1 != ip2)
|
|
+ xfs_iunlock(ip1, XFS_MMAPLOCK_SHARED);
|
|
+ xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
|
|
+
|
|
+ if (ip1 != ip2)
|
|
+ inode_unlock_shared(VFS_I(ip1));
|
|
+ inode_unlock(VFS_I(ip2));
|
|
+}
|
|
+
|
|
/*
|
|
* Reload the incore inode list for this inode. Caller should ensure that
|
|
* the link count cannot change, either by taking ILOCK_SHARED or otherwise
|
|
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
|
|
index 0c5bdb91152e1..3beb470f18920 100644
|
|
--- a/fs/xfs/xfs_inode.h
|
|
+++ b/fs/xfs/xfs_inode.h
|
|
@@ -347,6 +347,14 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
|
|
/* Quotacheck is running but inode has not been added to quota counts. */
|
|
#define XFS_IQUOTAUNCHECKED (1 << 14)
|
|
|
|
+/*
|
|
+ * Remap in progress. Callers that wish to update file data while
|
|
+ * holding a shared IOLOCK or MMAPLOCK must drop the lock and retake
|
|
+ * the lock in exclusive mode. Relocking the file will block until
|
|
+ * IREMAPPING is cleared.
|
|
+ */
|
|
+#define XFS_IREMAPPING (1U << 15)
|
|
+
|
|
/* All inode state flags related to inode reclaim. */
|
|
#define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \
|
|
XFS_IRECLAIM | \
|
|
@@ -561,6 +569,14 @@ extern void xfs_setup_inode(struct xfs_inode *ip);
|
|
extern void xfs_setup_iops(struct xfs_inode *ip);
|
|
extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init);
|
|
|
|
+static inline void xfs_update_stable_writes(struct xfs_inode *ip)
|
|
+{
|
|
+ if (bdev_stable_writes(xfs_inode_buftarg(ip)->bt_bdev))
|
|
+ mapping_set_stable_writes(VFS_I(ip)->i_mapping);
|
|
+ else
|
|
+ mapping_clear_stable_writes(VFS_I(ip)->i_mapping);
|
|
+}
|
|
+
|
|
/*
|
|
* When setting up a newly allocated inode, we need to call
|
|
* xfs_finish_inode_setup() once the inode is fully instantiated at
|
|
@@ -595,6 +611,7 @@ void xfs_end_io(struct work_struct *work);
|
|
|
|
int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
|
|
void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
|
|
+void xfs_iunlock2_remapping(struct xfs_inode *ip1, struct xfs_inode *ip2);
|
|
|
|
static inline bool
|
|
xfs_inode_unlinked_incomplete(
|
|
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
|
|
index e6609067ef261..144198a6b2702 100644
|
|
--- a/fs/xfs/xfs_inode_item_recover.c
|
|
+++ b/fs/xfs/xfs_inode_item_recover.c
|
|
@@ -286,6 +286,7 @@ xlog_recover_inode_commit_pass2(
|
|
struct xfs_log_dinode *ldip;
|
|
uint isize;
|
|
int need_free = 0;
|
|
+ xfs_failaddr_t fa;
|
|
|
|
if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
|
|
in_f = item->ri_buf[0].i_addr;
|
|
@@ -530,8 +531,19 @@ out_owner_change:
|
|
(dip->di_mode != 0))
|
|
error = xfs_recover_inode_owner_change(mp, dip, in_f,
|
|
buffer_list);
|
|
- /* re-generate the checksum. */
|
|
+ /* re-generate the checksum and validate the recovered inode. */
|
|
xfs_dinode_calc_crc(log->l_mp, dip);
|
|
+ fa = xfs_dinode_verify(log->l_mp, in_f->ilf_ino, dip);
|
|
+ if (fa) {
|
|
+ XFS_CORRUPTION_ERROR(
|
|
+ "Bad dinode after recovery",
|
|
+ XFS_ERRLEVEL_LOW, mp, dip, sizeof(*dip));
|
|
+ xfs_alert(mp,
|
|
+ "Metadata corruption detected at %pS, inode 0x%llx",
|
|
+ fa, in_f->ilf_ino);
|
|
+ error = -EFSCORRUPTED;
|
|
+ goto out_release;
|
|
+ }
|
|
|
|
ASSERT(bp->b_mount == mp);
|
|
bp->b_flags |= _XBF_LOGRECOVERY;
|
|
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
|
|
index 55bb01173cde8..535f6d38cdb54 100644
|
|
--- a/fs/xfs/xfs_ioctl.c
|
|
+++ b/fs/xfs/xfs_ioctl.c
|
|
@@ -1120,23 +1120,25 @@ xfs_ioctl_setattr_xflags(
|
|
struct fileattr *fa)
|
|
{
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
+ bool rtflag = (fa->fsx_xflags & FS_XFLAG_REALTIME);
|
|
uint64_t i_flags2;
|
|
|
|
- /* Can't change realtime flag if any extents are allocated. */
|
|
- if ((ip->i_df.if_nextents || ip->i_delayed_blks) &&
|
|
- XFS_IS_REALTIME_INODE(ip) != (fa->fsx_xflags & FS_XFLAG_REALTIME))
|
|
- return -EINVAL;
|
|
+ if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
|
|
+ /* Can't change realtime flag if any extents are allocated. */
|
|
+ if (ip->i_df.if_nextents || ip->i_delayed_blks)
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
- /* If realtime flag is set then must have realtime device */
|
|
- if (fa->fsx_xflags & FS_XFLAG_REALTIME) {
|
|
+ if (rtflag) {
|
|
+ /* If realtime flag is set then must have realtime device */
|
|
if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
|
|
(ip->i_extsize % mp->m_sb.sb_rextsize))
|
|
return -EINVAL;
|
|
- }
|
|
|
|
- /* Clear reflink if we are actually able to set the rt flag. */
|
|
- if ((fa->fsx_xflags & FS_XFLAG_REALTIME) && xfs_is_reflink_inode(ip))
|
|
- ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
|
|
+ /* Clear reflink if we are actually able to set the rt flag. */
|
|
+ if (xfs_is_reflink_inode(ip))
|
|
+ ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
|
|
+ }
|
|
|
|
/* diflags2 only valid for v3 inodes. */
|
|
i_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
|
|
@@ -1147,6 +1149,14 @@ xfs_ioctl_setattr_xflags(
|
|
ip->i_diflags2 = i_flags2;
|
|
|
|
xfs_diflags_to_iflags(ip, false);
|
|
+
|
|
+ /*
|
|
+ * Make the stable writes flag match that of the device the inode
|
|
+ * resides on when flipping the RT flag.
|
|
+ */
|
|
+ if (rtflag != XFS_IS_REALTIME_INODE(ip) && S_ISREG(VFS_I(ip)->i_mode))
|
|
+ xfs_update_stable_writes(ip);
|
|
+
|
|
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
|
|
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
XFS_STATS_INC(mp, xs_ig_attrchg);
|
|
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
|
|
index 2b3b05c28e9e4..b8ec045708c31 100644
|
|
--- a/fs/xfs/xfs_iops.c
|
|
+++ b/fs/xfs/xfs_iops.c
|
|
@@ -1298,6 +1298,13 @@ xfs_setup_inode(
|
|
gfp_mask = mapping_gfp_mask(inode->i_mapping);
|
|
mapping_set_gfp_mask(inode->i_mapping, (gfp_mask & ~(__GFP_FS)));
|
|
|
|
+ /*
|
|
+ * For real-time inodes update the stable write flags to that of the RT
|
|
+ * device instead of the data device.
|
|
+ */
|
|
+ if (S_ISREG(inode->i_mode) && XFS_IS_REALTIME_INODE(ip))
|
|
+ xfs_update_stable_writes(ip);
|
|
+
|
|
/*
|
|
* If there is no attribute fork no ACL can exist on this inode,
|
|
* and it can't have any file capabilities attached to it either.
|
|
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
|
|
index 51c100c861770..ee206facf0dc0 100644
|
|
--- a/fs/xfs/xfs_log.c
|
|
+++ b/fs/xfs/xfs_log.c
|
|
@@ -1893,9 +1893,7 @@ xlog_write_iclog(
|
|
* the buffer manually, the code needs to be kept in sync
|
|
* with the I/O completion path.
|
|
*/
|
|
- xlog_state_done_syncing(iclog);
|
|
- up(&iclog->ic_sema);
|
|
- return;
|
|
+ goto sync;
|
|
}
|
|
|
|
/*
|
|
@@ -1925,20 +1923,17 @@ xlog_write_iclog(
|
|
* avoid shutdown re-entering this path and erroring out again.
|
|
*/
|
|
if (log->l_targ != log->l_mp->m_ddev_targp &&
|
|
- blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev)) {
|
|
- xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
|
|
- return;
|
|
- }
|
|
+ blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev))
|
|
+ goto shutdown;
|
|
}
|
|
if (iclog->ic_flags & XLOG_ICL_NEED_FUA)
|
|
iclog->ic_bio.bi_opf |= REQ_FUA;
|
|
|
|
iclog->ic_flags &= ~(XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA);
|
|
|
|
- if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count)) {
|
|
- xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
|
|
- return;
|
|
- }
|
|
+ if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count))
|
|
+ goto shutdown;
|
|
+
|
|
if (is_vmalloc_addr(iclog->ic_data))
|
|
flush_kernel_vmap_range(iclog->ic_data, count);
|
|
|
|
@@ -1959,6 +1954,12 @@ xlog_write_iclog(
|
|
}
|
|
|
|
submit_bio(&iclog->ic_bio);
|
|
+ return;
|
|
+shutdown:
|
|
+ xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
|
|
+sync:
|
|
+ xlog_state_done_syncing(iclog);
|
|
+ up(&iclog->ic_sema);
|
|
}
|
|
|
|
/*
|
|
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
|
|
index 13b94d2e605bd..a1e18b24971a2 100644
|
|
--- a/fs/xfs/xfs_log_recover.c
|
|
+++ b/fs/xfs/xfs_log_recover.c
|
|
@@ -2511,7 +2511,7 @@ xlog_abort_defer_ops(
|
|
|
|
list_for_each_entry_safe(dfc, next, capture_list, dfc_list) {
|
|
list_del_init(&dfc->dfc_list);
|
|
- xfs_defer_ops_capture_free(mp, dfc);
|
|
+ xfs_defer_ops_capture_abort(mp, dfc);
|
|
}
|
|
}
|
|
|
|
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
|
|
index eb9102453affb..e5b62dc284664 100644
|
|
--- a/fs/xfs/xfs_reflink.c
|
|
+++ b/fs/xfs/xfs_reflink.c
|
|
@@ -784,6 +784,7 @@ xfs_reflink_end_cow_extent(
|
|
}
|
|
}
|
|
del = got;
|
|
+ xfs_trim_extent(&del, *offset_fsb, end_fsb - *offset_fsb);
|
|
|
|
/* Grab the corresponding mapping in the data fork. */
|
|
nmaps = 1;
|
|
@@ -1540,6 +1541,10 @@ xfs_reflink_remap_prep(
|
|
if (ret)
|
|
goto out_unlock;
|
|
|
|
+ xfs_iflags_set(src, XFS_IREMAPPING);
|
|
+ if (inode_in != inode_out)
|
|
+ xfs_ilock_demote(src, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
|
|
+
|
|
return 0;
|
|
out_unlock:
|
|
xfs_iunlock2_io_mmap(src, dest);
|
|
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
|
|
index 16534e9873f69..0e4e2df08aed0 100644
|
|
--- a/fs/xfs/xfs_rtalloc.c
|
|
+++ b/fs/xfs/xfs_rtalloc.c
|
|
@@ -211,6 +211,23 @@ xfs_rtallocate_range(
|
|
return error;
|
|
}
|
|
|
|
+/*
|
|
+ * Make sure we don't run off the end of the rt volume. Be careful that
|
|
+ * adjusting maxlen downwards doesn't cause us to fail the alignment checks.
|
|
+ */
|
|
+static inline xfs_extlen_t
|
|
+xfs_rtallocate_clamp_len(
|
|
+ struct xfs_mount *mp,
|
|
+ xfs_rtblock_t startrtx,
|
|
+ xfs_extlen_t rtxlen,
|
|
+ xfs_extlen_t prod)
|
|
+{
|
|
+ xfs_extlen_t ret;
|
|
+
|
|
+ ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
|
|
+ return rounddown(ret, prod);
|
|
+}
|
|
+
|
|
/*
|
|
* Attempt to allocate an extent minlen<=len<=maxlen starting from
|
|
* bitmap block bbno. If we don't get maxlen then use prod to trim
|
|
@@ -248,7 +265,7 @@ xfs_rtallocate_extent_block(
|
|
i <= end;
|
|
i++) {
|
|
/* Make sure we don't scan off the end of the rt volume. */
|
|
- maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
|
|
+ maxlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
|
|
|
|
/*
|
|
* See if there's a free extent of maxlen starting at i.
|
|
@@ -355,7 +372,8 @@ xfs_rtallocate_extent_exact(
|
|
int isfree; /* extent is free */
|
|
xfs_rtblock_t next; /* next block to try (dummy) */
|
|
|
|
- ASSERT(minlen % prod == 0 && maxlen % prod == 0);
|
|
+ ASSERT(minlen % prod == 0);
|
|
+ ASSERT(maxlen % prod == 0);
|
|
/*
|
|
* Check if the range in question (for maxlen) is free.
|
|
*/
|
|
@@ -438,7 +456,9 @@ xfs_rtallocate_extent_near(
|
|
xfs_rtblock_t n; /* next block to try */
|
|
xfs_rtblock_t r; /* result block */
|
|
|
|
- ASSERT(minlen % prod == 0 && maxlen % prod == 0);
|
|
+ ASSERT(minlen % prod == 0);
|
|
+ ASSERT(maxlen % prod == 0);
|
|
+
|
|
/*
|
|
* If the block number given is off the end, silently set it to
|
|
* the last block.
|
|
@@ -447,7 +467,7 @@ xfs_rtallocate_extent_near(
|
|
bno = mp->m_sb.sb_rextents - 1;
|
|
|
|
/* Make sure we don't run off the end of the rt volume. */
|
|
- maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
|
|
+ maxlen = xfs_rtallocate_clamp_len(mp, bno, maxlen, prod);
|
|
if (maxlen < minlen) {
|
|
*rtblock = NULLRTBLOCK;
|
|
return 0;
|
|
@@ -638,7 +658,8 @@ xfs_rtallocate_extent_size(
|
|
xfs_rtblock_t r; /* result block number */
|
|
xfs_suminfo_t sum; /* summary information for extents */
|
|
|
|
- ASSERT(minlen % prod == 0 && maxlen % prod == 0);
|
|
+ ASSERT(minlen % prod == 0);
|
|
+ ASSERT(maxlen % prod == 0);
|
|
ASSERT(maxlen != 0);
|
|
|
|
/*
|
|
@@ -954,7 +975,7 @@ xfs_growfs_rt(
|
|
return -EINVAL;
|
|
|
|
/* Unsupported realtime features. */
|
|
- if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp))
|
|
+ if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
|
|
return -EOPNOTSUPP;
|
|
|
|
nrblocks = in->newblocks;
|
|
diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h
|
|
index 62c7ad79cbb61..65c284e9d33e9 100644
|
|
--- a/fs/xfs/xfs_rtalloc.h
|
|
+++ b/fs/xfs/xfs_rtalloc.h
|
|
@@ -58,6 +58,10 @@ xfs_rtfree_extent(
|
|
xfs_rtblock_t bno, /* starting block number to free */
|
|
xfs_extlen_t len); /* length of extent freed */
|
|
|
|
+/* Same as above, but in units of rt blocks. */
|
|
+int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
|
|
+ xfs_filblks_t rtlen);
|
|
+
|
|
/*
|
|
* Initialize realtime fields in the mount structure.
|
|
*/
|
|
@@ -137,16 +141,17 @@ int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp,
|
|
bool *is_free);
|
|
int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
|
|
#else
|
|
-# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (ENOSYS)
|
|
-# define xfs_rtfree_extent(t,b,l) (ENOSYS)
|
|
-# define xfs_rtpick_extent(m,t,l,rb) (ENOSYS)
|
|
-# define xfs_growfs_rt(mp,in) (ENOSYS)
|
|
-# define xfs_rtalloc_query_range(t,l,h,f,p) (ENOSYS)
|
|
-# define xfs_rtalloc_query_all(m,t,f,p) (ENOSYS)
|
|
-# define xfs_rtbuf_get(m,t,b,i,p) (ENOSYS)
|
|
-# define xfs_verify_rtbno(m, r) (false)
|
|
-# define xfs_rtalloc_extent_is_free(m,t,s,l,i) (ENOSYS)
|
|
-# define xfs_rtalloc_reinit_frextents(m) (0)
|
|
+# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (-ENOSYS)
|
|
+# define xfs_rtfree_extent(t,b,l) (-ENOSYS)
|
|
+# define xfs_rtfree_blocks(t,rb,rl) (-ENOSYS)
|
|
+# define xfs_rtpick_extent(m,t,l,rb) (-ENOSYS)
|
|
+# define xfs_growfs_rt(mp,in) (-ENOSYS)
|
|
+# define xfs_rtalloc_query_range(m,t,l,h,f,p) (-ENOSYS)
|
|
+# define xfs_rtalloc_query_all(m,t,f,p) (-ENOSYS)
|
|
+# define xfs_rtbuf_get(m,t,b,i,p) (-ENOSYS)
|
|
+# define xfs_verify_rtbno(m, r) (false)
|
|
+# define xfs_rtalloc_extent_is_free(m,t,s,l,i) (-ENOSYS)
|
|
+# define xfs_rtalloc_reinit_frextents(m) (0)
|
|
static inline int /* error */
|
|
xfs_rtmount_init(
|
|
xfs_mount_t *mp) /* file system mount structure */
|
|
@@ -157,7 +162,7 @@ xfs_rtmount_init(
|
|
xfs_warn(mp, "Not built with CONFIG_XFS_RT");
|
|
return -ENOSYS;
|
|
}
|
|
-# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
|
|
+# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (-ENOSYS))
|
|
# define xfs_rtunmount_inodes(m)
|
|
#endif /* CONFIG_XFS_RT */
|
|
|
|
diff --git a/include/asm-generic/cacheflush.h b/include/asm-generic/cacheflush.h
|
|
index 84ec53ccc4502..7ee8a179d1036 100644
|
|
--- a/include/asm-generic/cacheflush.h
|
|
+++ b/include/asm-generic/cacheflush.h
|
|
@@ -91,6 +91,12 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end)
|
|
}
|
|
#endif
|
|
|
|
+#ifndef flush_cache_vmap_early
|
|
+static inline void flush_cache_vmap_early(unsigned long start, unsigned long end)
|
|
+{
|
|
+}
|
|
+#endif
|
|
+
|
|
#ifndef flush_cache_vunmap
|
|
static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
|
|
{
|
|
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
|
|
index 2eaaabbe98cb6..1717cc57cdacd 100644
|
|
--- a/include/linux/ceph/messenger.h
|
|
+++ b/include/linux/ceph/messenger.h
|
|
@@ -283,7 +283,7 @@ struct ceph_msg {
|
|
struct kref kref;
|
|
bool more_to_follow;
|
|
bool needs_out_seq;
|
|
- bool sparse_read;
|
|
+ u64 sparse_read_total;
|
|
int front_alloc_len;
|
|
|
|
struct ceph_msgpool *pool;
|
|
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
|
|
index c3656e5902131..cff3dba658209 100644
|
|
--- a/include/linux/dmaengine.h
|
|
+++ b/include/linux/dmaengine.h
|
|
@@ -955,7 +955,8 @@ static inline int dmaengine_slave_config(struct dma_chan *chan,
|
|
|
|
static inline bool is_slave_direction(enum dma_transfer_direction direction)
|
|
{
|
|
- return (direction == DMA_MEM_TO_DEV) || (direction == DMA_DEV_TO_MEM);
|
|
+ return (direction == DMA_MEM_TO_DEV) || (direction == DMA_DEV_TO_MEM) ||
|
|
+ (direction == DMA_DEV_TO_DEV);
|
|
}
|
|
|
|
static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
|
|
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
|
|
index f2044d5a652b5..254d4a898179c 100644
|
|
--- a/include/linux/hrtimer.h
|
|
+++ b/include/linux/hrtimer.h
|
|
@@ -197,6 +197,7 @@ enum hrtimer_base_type {
|
|
* @max_hang_time: Maximum time spent in hrtimer_interrupt
|
|
* @softirq_expiry_lock: Lock which is taken while softirq based hrtimer are
|
|
* expired
|
|
+ * @online: CPU is online from an hrtimers point of view
|
|
* @timer_waiters: A hrtimer_cancel() invocation waits for the timer
|
|
* callback to finish.
|
|
* @expires_next: absolute time of the next event, is required for remote
|
|
@@ -219,7 +220,8 @@ struct hrtimer_cpu_base {
|
|
unsigned int hres_active : 1,
|
|
in_hrtirq : 1,
|
|
hang_detected : 1,
|
|
- softirq_activated : 1;
|
|
+ softirq_activated : 1,
|
|
+ online : 1;
|
|
#ifdef CONFIG_HIGH_RES_TIMERS
|
|
unsigned int nr_events;
|
|
unsigned short nr_retries;
|
|
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
|
|
index f7e537f64db45..0dd4a21d172da 100644
|
|
--- a/include/trace/events/rxrpc.h
|
|
+++ b/include/trace/events/rxrpc.h
|
|
@@ -128,6 +128,7 @@
|
|
EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \
|
|
EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \
|
|
EM(rxrpc_skb_get_conn_work, "GET conn-work") \
|
|
+ EM(rxrpc_skb_get_last_nack, "GET last-nack") \
|
|
EM(rxrpc_skb_get_local_work, "GET locl-work") \
|
|
EM(rxrpc_skb_get_reject_work, "GET rej-work ") \
|
|
EM(rxrpc_skb_get_to_recvmsg, "GET to-recv ") \
|
|
@@ -141,6 +142,7 @@
|
|
EM(rxrpc_skb_put_error_report, "PUT error-rep") \
|
|
EM(rxrpc_skb_put_input, "PUT input ") \
|
|
EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \
|
|
+ EM(rxrpc_skb_put_last_nack, "PUT last-nack") \
|
|
EM(rxrpc_skb_put_purge, "PUT purge ") \
|
|
EM(rxrpc_skb_put_rotate, "PUT rotate ") \
|
|
EM(rxrpc_skb_put_unknown, "PUT unknown ") \
|
|
@@ -1549,7 +1551,7 @@ TRACE_EVENT(rxrpc_congest,
|
|
memcpy(&__entry->sum, summary, sizeof(__entry->sum));
|
|
),
|
|
|
|
- TP_printk("c=%08x r=%08x %s q=%08x %s cw=%u ss=%u nA=%u,%u+%u r=%u b=%u u=%u d=%u l=%x%s%s%s",
|
|
+ TP_printk("c=%08x r=%08x %s q=%08x %s cw=%u ss=%u nA=%u,%u+%u,%u b=%u u=%u d=%u l=%x%s%s%s",
|
|
__entry->call,
|
|
__entry->ack_serial,
|
|
__print_symbolic(__entry->sum.ack_reason, rxrpc_ack_names),
|
|
@@ -1557,9 +1559,9 @@ TRACE_EVENT(rxrpc_congest,
|
|
__print_symbolic(__entry->sum.mode, rxrpc_congest_modes),
|
|
__entry->sum.cwnd,
|
|
__entry->sum.ssthresh,
|
|
- __entry->sum.nr_acks, __entry->sum.saw_nacks,
|
|
+ __entry->sum.nr_acks, __entry->sum.nr_retained_nacks,
|
|
__entry->sum.nr_new_acks,
|
|
- __entry->sum.nr_rot_new_acks,
|
|
+ __entry->sum.nr_new_nacks,
|
|
__entry->top - __entry->hard_ack,
|
|
__entry->sum.cumulative_acks,
|
|
__entry->sum.dup_acks,
|
|
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
|
|
index ca30232b7bc8a..117c6a9b845b1 100644
|
|
--- a/include/uapi/linux/netfilter/nf_tables.h
|
|
+++ b/include/uapi/linux/netfilter/nf_tables.h
|
|
@@ -285,9 +285,11 @@ enum nft_rule_attributes {
|
|
/**
|
|
* enum nft_rule_compat_flags - nf_tables rule compat flags
|
|
*
|
|
+ * @NFT_RULE_COMPAT_F_UNUSED: unused
|
|
* @NFT_RULE_COMPAT_F_INV: invert the check result
|
|
*/
|
|
enum nft_rule_compat_flags {
|
|
+ NFT_RULE_COMPAT_F_UNUSED = (1 << 0),
|
|
NFT_RULE_COMPAT_F_INV = (1 << 1),
|
|
NFT_RULE_COMPAT_F_MASK = NFT_RULE_COMPAT_F_INV,
|
|
};
|
|
diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h
|
|
index d2bad1df347da..c8cba78310831 100644
|
|
--- a/io_uring/io_uring.h
|
|
+++ b/io_uring/io_uring.h
|
|
@@ -30,6 +30,13 @@ enum {
|
|
IOU_OK = 0,
|
|
IOU_ISSUE_SKIP_COMPLETE = -EIOCBQUEUED,
|
|
|
|
+ /*
|
|
+ * Requeue the task_work to restart operations on this request. The
|
|
+ * actual value isn't important, should just be not an otherwise
|
|
+ * valid error code, yet less than -MAX_ERRNO and valid internally.
|
|
+ */
|
|
+ IOU_REQUEUE = -3072,
|
|
+
|
|
/*
|
|
* Intended only when both IO_URING_F_MULTISHOT is passed
|
|
* to indicate to the poll runner that multishot should be
|
|
diff --git a/io_uring/net.c b/io_uring/net.c
|
|
index 75d494dad7e2c..43bc9a5f96f9d 100644
|
|
--- a/io_uring/net.c
|
|
+++ b/io_uring/net.c
|
|
@@ -60,6 +60,7 @@ struct io_sr_msg {
|
|
unsigned len;
|
|
unsigned done_io;
|
|
unsigned msg_flags;
|
|
+ unsigned nr_multishot_loops;
|
|
u16 flags;
|
|
/* initialised and used only by !msg send variants */
|
|
u16 addr_len;
|
|
@@ -70,6 +71,13 @@ struct io_sr_msg {
|
|
struct io_kiocb *notif;
|
|
};
|
|
|
|
+/*
|
|
+ * Number of times we'll try and do receives if there's more data. If we
|
|
+ * exceed this limit, then add us to the back of the queue and retry from
|
|
+ * there. This helps fairness between flooding clients.
|
|
+ */
|
|
+#define MULTISHOT_MAX_RETRY 32
|
|
+
|
|
static inline bool io_check_multishot(struct io_kiocb *req,
|
|
unsigned int issue_flags)
|
|
{
|
|
@@ -611,6 +619,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|
sr->msg_flags |= MSG_CMSG_COMPAT;
|
|
#endif
|
|
sr->done_io = 0;
|
|
+ sr->nr_multishot_loops = 0;
|
|
return 0;
|
|
}
|
|
|
|
@@ -645,23 +654,35 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
|
|
return true;
|
|
}
|
|
|
|
- if (!mshot_finished) {
|
|
- if (io_fill_cqe_req_aux(req, issue_flags & IO_URING_F_COMPLETE_DEFER,
|
|
- *ret, cflags | IORING_CQE_F_MORE)) {
|
|
- io_recv_prep_retry(req);
|
|
- /* Known not-empty or unknown state, retry */
|
|
- if (cflags & IORING_CQE_F_SOCK_NONEMPTY ||
|
|
- msg->msg_inq == -1)
|
|
+ if (mshot_finished)
|
|
+ goto finish;
|
|
+
|
|
+ /*
|
|
+ * Fill CQE for this receive and see if we should keep trying to
|
|
+ * receive from this socket.
|
|
+ */
|
|
+ if (io_fill_cqe_req_aux(req, issue_flags & IO_URING_F_COMPLETE_DEFER,
|
|
+ *ret, cflags | IORING_CQE_F_MORE)) {
|
|
+ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
|
|
+ int mshot_retry_ret = IOU_ISSUE_SKIP_COMPLETE;
|
|
+
|
|
+ io_recv_prep_retry(req);
|
|
+ /* Known not-empty or unknown state, retry */
|
|
+ if (cflags & IORING_CQE_F_SOCK_NONEMPTY || msg->msg_inq == -1) {
|
|
+ if (sr->nr_multishot_loops++ < MULTISHOT_MAX_RETRY)
|
|
return false;
|
|
- if (issue_flags & IO_URING_F_MULTISHOT)
|
|
- *ret = IOU_ISSUE_SKIP_COMPLETE;
|
|
- else
|
|
- *ret = -EAGAIN;
|
|
- return true;
|
|
+ /* mshot retries exceeded, force a requeue */
|
|
+ sr->nr_multishot_loops = 0;
|
|
+ mshot_retry_ret = IOU_REQUEUE;
|
|
}
|
|
- /* Otherwise stop multishot but use the current result. */
|
|
+ if (issue_flags & IO_URING_F_MULTISHOT)
|
|
+ *ret = mshot_retry_ret;
|
|
+ else
|
|
+ *ret = -EAGAIN;
|
|
+ return true;
|
|
}
|
|
-
|
|
+ /* Otherwise stop multishot but use the current result. */
|
|
+finish:
|
|
io_req_set_res(req, *ret, cflags);
|
|
|
|
if (issue_flags & IO_URING_F_MULTISHOT)
|
|
@@ -902,6 +923,7 @@ retry_multishot:
|
|
if (!buf)
|
|
return -ENOBUFS;
|
|
sr->buf = buf;
|
|
+ sr->len = len;
|
|
}
|
|
|
|
ret = import_ubuf(ITER_DEST, sr->buf, len, &msg.msg_iter);
|
|
diff --git a/io_uring/poll.c b/io_uring/poll.c
|
|
index 4c360ba8793a5..48ca0810a54af 100644
|
|
--- a/io_uring/poll.c
|
|
+++ b/io_uring/poll.c
|
|
@@ -226,8 +226,24 @@ enum {
|
|
IOU_POLL_NO_ACTION = 1,
|
|
IOU_POLL_REMOVE_POLL_USE_RES = 2,
|
|
IOU_POLL_REISSUE = 3,
|
|
+ IOU_POLL_REQUEUE = 4,
|
|
};
|
|
|
|
+static void __io_poll_execute(struct io_kiocb *req, int mask)
|
|
+{
|
|
+ io_req_set_res(req, mask, 0);
|
|
+ req->io_task_work.func = io_poll_task_func;
|
|
+
|
|
+ trace_io_uring_task_add(req, mask);
|
|
+ io_req_task_work_add(req);
|
|
+}
|
|
+
|
|
+static inline void io_poll_execute(struct io_kiocb *req, int res)
|
|
+{
|
|
+ if (io_poll_get_ownership(req))
|
|
+ __io_poll_execute(req, res);
|
|
+}
|
|
+
|
|
/*
|
|
* All poll tw should go through this. Checks for poll events, manages
|
|
* references, does rewait, etc.
|
|
@@ -309,6 +325,8 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
|
|
int ret = io_poll_issue(req, ts);
|
|
if (ret == IOU_STOP_MULTISHOT)
|
|
return IOU_POLL_REMOVE_POLL_USE_RES;
|
|
+ else if (ret == IOU_REQUEUE)
|
|
+ return IOU_POLL_REQUEUE;
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
@@ -331,8 +349,12 @@ void io_poll_task_func(struct io_kiocb *req, struct io_tw_state *ts)
|
|
int ret;
|
|
|
|
ret = io_poll_check_events(req, ts);
|
|
- if (ret == IOU_POLL_NO_ACTION)
|
|
+ if (ret == IOU_POLL_NO_ACTION) {
|
|
+ return;
|
|
+ } else if (ret == IOU_POLL_REQUEUE) {
|
|
+ __io_poll_execute(req, 0);
|
|
return;
|
|
+ }
|
|
io_poll_remove_entries(req);
|
|
io_poll_tw_hash_eject(req, ts);
|
|
|
|
@@ -364,21 +386,6 @@ void io_poll_task_func(struct io_kiocb *req, struct io_tw_state *ts)
|
|
}
|
|
}
|
|
|
|
-static void __io_poll_execute(struct io_kiocb *req, int mask)
|
|
-{
|
|
- io_req_set_res(req, mask, 0);
|
|
- req->io_task_work.func = io_poll_task_func;
|
|
-
|
|
- trace_io_uring_task_add(req, mask);
|
|
- io_req_task_work_add(req);
|
|
-}
|
|
-
|
|
-static inline void io_poll_execute(struct io_kiocb *req, int res)
|
|
-{
|
|
- if (io_poll_get_ownership(req))
|
|
- __io_poll_execute(req, res);
|
|
-}
|
|
-
|
|
static void io_poll_cancel_req(struct io_kiocb *req)
|
|
{
|
|
io_poll_mark_cancelled(req);
|
|
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
|
|
index 760793998cdd7..edb0f821dceaa 100644
|
|
--- a/kernel/time/hrtimer.c
|
|
+++ b/kernel/time/hrtimer.c
|
|
@@ -1085,6 +1085,7 @@ static int enqueue_hrtimer(struct hrtimer *timer,
|
|
enum hrtimer_mode mode)
|
|
{
|
|
debug_activate(timer, mode);
|
|
+ WARN_ON_ONCE(!base->cpu_base->online);
|
|
|
|
base->cpu_base->active_bases |= 1 << base->index;
|
|
|
|
@@ -2183,6 +2184,7 @@ int hrtimers_prepare_cpu(unsigned int cpu)
|
|
cpu_base->softirq_next_timer = NULL;
|
|
cpu_base->expires_next = KTIME_MAX;
|
|
cpu_base->softirq_expires_next = KTIME_MAX;
|
|
+ cpu_base->online = 1;
|
|
hrtimer_cpu_base_init_expiry_lock(cpu_base);
|
|
return 0;
|
|
}
|
|
@@ -2250,6 +2252,7 @@ int hrtimers_cpu_dying(unsigned int dying_cpu)
|
|
smp_call_function_single(ncpu, retrigger_next_event, NULL, 0);
|
|
|
|
raw_spin_unlock(&new_base->lock);
|
|
+ old_base->online = 0;
|
|
raw_spin_unlock(&old_base->lock);
|
|
|
|
return 0;
|
|
diff --git a/mm/percpu.c b/mm/percpu.c
|
|
index a7665de8485fd..d287cebd58caa 100644
|
|
--- a/mm/percpu.c
|
|
+++ b/mm/percpu.c
|
|
@@ -3306,13 +3306,7 @@ int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_to_node_fn_t
|
|
if (rc < 0)
|
|
panic("failed to map percpu area, err=%d\n", rc);
|
|
|
|
- /*
|
|
- * FIXME: Archs with virtual cache should flush local
|
|
- * cache for the linear mapping here - something
|
|
- * equivalent to flush_cache_vmap() on the local cpu.
|
|
- * flush_cache_vmap() can't be used as most supporting
|
|
- * data structures are not set up yet.
|
|
- */
|
|
+ flush_cache_vmap_early(unit_addr, unit_addr + ai->unit_size);
|
|
|
|
/* copy static data */
|
|
memcpy((void *)unit_addr, __per_cpu_load, ai->static_size);
|
|
diff --git a/net/ceph/messenger_v1.c b/net/ceph/messenger_v1.c
|
|
index f9a50d7f0d204..0cb61c76b9b87 100644
|
|
--- a/net/ceph/messenger_v1.c
|
|
+++ b/net/ceph/messenger_v1.c
|
|
@@ -160,8 +160,9 @@ static size_t sizeof_footer(struct ceph_connection *con)
|
|
static void prepare_message_data(struct ceph_msg *msg, u32 data_len)
|
|
{
|
|
/* Initialize data cursor if it's not a sparse read */
|
|
- if (!msg->sparse_read)
|
|
- ceph_msg_data_cursor_init(&msg->cursor, msg, data_len);
|
|
+ u64 len = msg->sparse_read_total ? : data_len;
|
|
+
|
|
+ ceph_msg_data_cursor_init(&msg->cursor, msg, len);
|
|
}
|
|
|
|
/*
|
|
@@ -991,7 +992,7 @@ static inline int read_partial_message_section(struct ceph_connection *con,
|
|
return read_partial_message_chunk(con, section, sec_len, crc);
|
|
}
|
|
|
|
-static int read_sparse_msg_extent(struct ceph_connection *con, u32 *crc)
|
|
+static int read_partial_sparse_msg_extent(struct ceph_connection *con, u32 *crc)
|
|
{
|
|
struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
|
|
bool do_bounce = ceph_test_opt(from_msgr(con->msgr), RXBOUNCE);
|
|
@@ -1026,7 +1027,7 @@ static int read_sparse_msg_extent(struct ceph_connection *con, u32 *crc)
|
|
return 1;
|
|
}
|
|
|
|
-static int read_sparse_msg_data(struct ceph_connection *con)
|
|
+static int read_partial_sparse_msg_data(struct ceph_connection *con)
|
|
{
|
|
struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
|
|
bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
|
|
@@ -1036,31 +1037,31 @@ static int read_sparse_msg_data(struct ceph_connection *con)
|
|
if (do_datacrc)
|
|
crc = con->in_data_crc;
|
|
|
|
- do {
|
|
+ while (cursor->total_resid) {
|
|
if (con->v1.in_sr_kvec.iov_base)
|
|
ret = read_partial_message_chunk(con,
|
|
&con->v1.in_sr_kvec,
|
|
con->v1.in_sr_len,
|
|
&crc);
|
|
else if (cursor->sr_resid > 0)
|
|
- ret = read_sparse_msg_extent(con, &crc);
|
|
-
|
|
- if (ret <= 0) {
|
|
- if (do_datacrc)
|
|
- con->in_data_crc = crc;
|
|
- return ret;
|
|
- }
|
|
+ ret = read_partial_sparse_msg_extent(con, &crc);
|
|
+ if (ret <= 0)
|
|
+ break;
|
|
|
|
memset(&con->v1.in_sr_kvec, 0, sizeof(con->v1.in_sr_kvec));
|
|
ret = con->ops->sparse_read(con, cursor,
|
|
(char **)&con->v1.in_sr_kvec.iov_base);
|
|
+ if (ret <= 0) {
|
|
+ ret = ret ? ret : 1; /* must return > 0 to indicate success */
|
|
+ break;
|
|
+ }
|
|
con->v1.in_sr_len = ret;
|
|
- } while (ret > 0);
|
|
+ }
|
|
|
|
if (do_datacrc)
|
|
con->in_data_crc = crc;
|
|
|
|
- return ret < 0 ? ret : 1; /* must return > 0 to indicate success */
|
|
+ return ret;
|
|
}
|
|
|
|
static int read_partial_msg_data(struct ceph_connection *con)
|
|
@@ -1253,8 +1254,8 @@ static int read_partial_message(struct ceph_connection *con)
|
|
if (!m->num_data_items)
|
|
return -EIO;
|
|
|
|
- if (m->sparse_read)
|
|
- ret = read_sparse_msg_data(con);
|
|
+ if (m->sparse_read_total)
|
|
+ ret = read_partial_sparse_msg_data(con);
|
|
else if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE))
|
|
ret = read_partial_msg_data_bounce(con);
|
|
else
|
|
diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c
|
|
index d09a39ff2cf04..a901cae2f1060 100644
|
|
--- a/net/ceph/messenger_v2.c
|
|
+++ b/net/ceph/messenger_v2.c
|
|
@@ -1132,7 +1132,7 @@ static int decrypt_tail(struct ceph_connection *con)
|
|
struct sg_table enc_sgt = {};
|
|
struct sg_table sgt = {};
|
|
struct page **pages = NULL;
|
|
- bool sparse = con->in_msg->sparse_read;
|
|
+ bool sparse = !!con->in_msg->sparse_read_total;
|
|
int dpos = 0;
|
|
int tail_len;
|
|
int ret;
|
|
@@ -2064,7 +2064,7 @@ static int prepare_read_tail_plain(struct ceph_connection *con)
|
|
}
|
|
|
|
if (data_len(msg)) {
|
|
- if (msg->sparse_read)
|
|
+ if (msg->sparse_read_total)
|
|
con->v2.in_state = IN_S_PREPARE_SPARSE_DATA;
|
|
else
|
|
con->v2.in_state = IN_S_PREPARE_READ_DATA;
|
|
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
|
|
index d3a759e052c81..8d9760397b887 100644
|
|
--- a/net/ceph/osd_client.c
|
|
+++ b/net/ceph/osd_client.c
|
|
@@ -5510,7 +5510,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
|
|
}
|
|
|
|
m = ceph_msg_get(req->r_reply);
|
|
- m->sparse_read = (bool)srlen;
|
|
+ m->sparse_read_total = srlen;
|
|
|
|
dout("get_reply tid %lld %p\n", tid, m);
|
|
|
|
@@ -5777,11 +5777,8 @@ static int prep_next_sparse_read(struct ceph_connection *con,
|
|
}
|
|
|
|
if (o->o_sparse_op_idx < 0) {
|
|
- u64 srlen = sparse_data_requested(req);
|
|
-
|
|
- dout("%s: [%d] starting new sparse read req. srlen=0x%llx\n",
|
|
- __func__, o->o_osd, srlen);
|
|
- ceph_msg_data_cursor_init(cursor, con->in_msg, srlen);
|
|
+ dout("%s: [%d] starting new sparse read req\n",
|
|
+ __func__, o->o_osd);
|
|
} else {
|
|
u64 end;
|
|
|
|
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
|
|
index 1c58bd72e1245..e59962f34caa6 100644
|
|
--- a/net/ipv4/af_inet.c
|
|
+++ b/net/ipv4/af_inet.c
|
|
@@ -1628,10 +1628,12 @@ EXPORT_SYMBOL(inet_current_timestamp);
|
|
|
|
int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
|
|
{
|
|
- if (sk->sk_family == AF_INET)
|
|
+ unsigned int family = READ_ONCE(sk->sk_family);
|
|
+
|
|
+ if (family == AF_INET)
|
|
return ip_recv_error(sk, msg, len, addr_len);
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
- if (sk->sk_family == AF_INET6)
|
|
+ if (family == AF_INET6)
|
|
return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len);
|
|
#endif
|
|
return -EINVAL;
|
|
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
|
|
index 586b1b3e35b80..80ccd6661aa32 100644
|
|
--- a/net/ipv4/ip_tunnel_core.c
|
|
+++ b/net/ipv4/ip_tunnel_core.c
|
|
@@ -332,7 +332,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu)
|
|
};
|
|
skb_reset_network_header(skb);
|
|
|
|
- csum = csum_partial(icmp6h, len, 0);
|
|
+ csum = skb_checksum(skb, skb_transport_offset(skb), len, 0);
|
|
icmp6h->icmp6_cksum = csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr, len,
|
|
IPPROTO_ICMPV6, csum);
|
|
|
|
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
|
|
index 73f8df03d159c..d9e716f38b0e9 100644
|
|
--- a/net/mac80211/mlme.c
|
|
+++ b/net/mac80211/mlme.c
|
|
@@ -7727,8 +7727,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|
|
|
rcu_read_lock();
|
|
beacon_ies = rcu_dereference(req->bss->beacon_ies);
|
|
-
|
|
- if (beacon_ies) {
|
|
+ if (!beacon_ies) {
|
|
/*
|
|
* Wait up to one beacon interval ...
|
|
* should this be more if we miss one?
|
|
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
|
|
index d45d4be63dd87..5481acbfc1d43 100644
|
|
--- a/net/mac80211/tx.c
|
|
+++ b/net/mac80211/tx.c
|
|
@@ -3086,10 +3086,11 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
|
|
/* DA SA BSSID */
|
|
build.da_offs = offsetof(struct ieee80211_hdr, addr1);
|
|
build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
|
|
+ rcu_read_lock();
|
|
link = rcu_dereference(sdata->link[tdls_link_id]);
|
|
- if (WARN_ON_ONCE(!link))
|
|
- break;
|
|
- memcpy(hdr->addr3, link->u.mgd.bssid, ETH_ALEN);
|
|
+ if (!WARN_ON_ONCE(!link))
|
|
+ memcpy(hdr->addr3, link->u.mgd.bssid, ETH_ALEN);
|
|
+ rcu_read_unlock();
|
|
build.hdr_len = 24;
|
|
break;
|
|
}
|
|
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
|
|
index f0eeda97bfcd9..1f9474fefe849 100644
|
|
--- a/net/netfilter/nft_compat.c
|
|
+++ b/net/netfilter/nft_compat.c
|
|
@@ -135,7 +135,7 @@ static void nft_target_eval_bridge(const struct nft_expr *expr,
|
|
|
|
static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
|
|
[NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING },
|
|
- [NFTA_TARGET_REV] = { .type = NLA_U32 },
|
|
+ [NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255),
|
|
[NFTA_TARGET_INFO] = { .type = NLA_BINARY },
|
|
};
|
|
|
|
@@ -200,6 +200,7 @@ static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1]
|
|
static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
|
|
{
|
|
struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
|
|
+ u32 l4proto;
|
|
u32 flags;
|
|
int err;
|
|
|
|
@@ -212,12 +213,18 @@ static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
|
|
return -EINVAL;
|
|
|
|
flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
|
|
- if (flags & ~NFT_RULE_COMPAT_F_MASK)
|
|
+ if (flags & NFT_RULE_COMPAT_F_UNUSED ||
|
|
+ flags & ~NFT_RULE_COMPAT_F_MASK)
|
|
return -EINVAL;
|
|
if (flags & NFT_RULE_COMPAT_F_INV)
|
|
*inv = true;
|
|
|
|
- *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
|
|
+ l4proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
|
|
+ if (l4proto > U16_MAX)
|
|
+ return -EINVAL;
|
|
+
|
|
+ *proto = l4proto;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -419,7 +426,7 @@ static void nft_match_eval(const struct nft_expr *expr,
|
|
|
|
static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
|
|
[NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING },
|
|
- [NFTA_MATCH_REV] = { .type = NLA_U32 },
|
|
+ [NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255),
|
|
[NFTA_MATCH_INFO] = { .type = NLA_BINARY },
|
|
};
|
|
|
|
@@ -724,7 +731,7 @@ out_put:
|
|
static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
|
|
[NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING,
|
|
.len = NFT_COMPAT_NAME_MAX-1 },
|
|
- [NFTA_COMPAT_REV] = { .type = NLA_U32 },
|
|
+ [NFTA_COMPAT_REV] = NLA_POLICY_MAX(NLA_BE32, 255),
|
|
[NFTA_COMPAT_TYPE] = { .type = NLA_U32 },
|
|
};
|
|
|
|
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
|
|
index aac98a3c966e9..bfd3e5a14dab6 100644
|
|
--- a/net/netfilter/nft_ct.c
|
|
+++ b/net/netfilter/nft_ct.c
|
|
@@ -476,6 +476,9 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
|
|
break;
|
|
#endif
|
|
case NFT_CT_ID:
|
|
+ if (tb[NFTA_CT_DIRECTION])
|
|
+ return -EINVAL;
|
|
+
|
|
len = sizeof(u32);
|
|
break;
|
|
default:
|
|
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
|
|
index 3ff31043f7148..8e9b200779666 100644
|
|
--- a/net/netfilter/nft_set_pipapo.c
|
|
+++ b/net/netfilter/nft_set_pipapo.c
|
|
@@ -342,9 +342,6 @@
|
|
#include "nft_set_pipapo_avx2.h"
|
|
#include "nft_set_pipapo.h"
|
|
|
|
-/* Current working bitmap index, toggled between field matches */
|
|
-static DEFINE_PER_CPU(bool, nft_pipapo_scratch_index);
|
|
-
|
|
/**
|
|
* pipapo_refill() - For each set bit, set bits from selected mapping table item
|
|
* @map: Bitmap to be scanned for set bits
|
|
@@ -412,6 +409,7 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
|
|
const u32 *key, const struct nft_set_ext **ext)
|
|
{
|
|
struct nft_pipapo *priv = nft_set_priv(set);
|
|
+ struct nft_pipapo_scratch *scratch;
|
|
unsigned long *res_map, *fill_map;
|
|
u8 genmask = nft_genmask_cur(net);
|
|
const u8 *rp = (const u8 *)key;
|
|
@@ -422,15 +420,17 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
|
|
|
|
local_bh_disable();
|
|
|
|
- map_index = raw_cpu_read(nft_pipapo_scratch_index);
|
|
-
|
|
m = rcu_dereference(priv->match);
|
|
|
|
if (unlikely(!m || !*raw_cpu_ptr(m->scratch)))
|
|
goto out;
|
|
|
|
- res_map = *raw_cpu_ptr(m->scratch) + (map_index ? m->bsize_max : 0);
|
|
- fill_map = *raw_cpu_ptr(m->scratch) + (map_index ? 0 : m->bsize_max);
|
|
+ scratch = *raw_cpu_ptr(m->scratch);
|
|
+
|
|
+ map_index = scratch->map_index;
|
|
+
|
|
+ res_map = scratch->map + (map_index ? m->bsize_max : 0);
|
|
+ fill_map = scratch->map + (map_index ? 0 : m->bsize_max);
|
|
|
|
memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
|
|
|
|
@@ -460,7 +460,7 @@ next_match:
|
|
b = pipapo_refill(res_map, f->bsize, f->rules, fill_map, f->mt,
|
|
last);
|
|
if (b < 0) {
|
|
- raw_cpu_write(nft_pipapo_scratch_index, map_index);
|
|
+ scratch->map_index = map_index;
|
|
local_bh_enable();
|
|
|
|
return false;
|
|
@@ -477,7 +477,7 @@ next_match:
|
|
* current inactive bitmap is clean and can be reused as
|
|
* *next* bitmap (not initial) for the next packet.
|
|
*/
|
|
- raw_cpu_write(nft_pipapo_scratch_index, map_index);
|
|
+ scratch->map_index = map_index;
|
|
local_bh_enable();
|
|
|
|
return true;
|
|
@@ -1101,6 +1101,25 @@ static void pipapo_map(struct nft_pipapo_match *m,
|
|
f->mt[map[i].to + j].e = e;
|
|
}
|
|
|
|
+/**
|
|
+ * pipapo_free_scratch() - Free per-CPU map at original (not aligned) address
|
|
+ * @m: Matching data
|
|
+ * @cpu: CPU number
|
|
+ */
|
|
+static void pipapo_free_scratch(const struct nft_pipapo_match *m, unsigned int cpu)
|
|
+{
|
|
+ struct nft_pipapo_scratch *s;
|
|
+ void *mem;
|
|
+
|
|
+ s = *per_cpu_ptr(m->scratch, cpu);
|
|
+ if (!s)
|
|
+ return;
|
|
+
|
|
+ mem = s;
|
|
+ mem -= s->align_off;
|
|
+ kfree(mem);
|
|
+}
|
|
+
|
|
/**
|
|
* pipapo_realloc_scratch() - Reallocate scratch maps for partial match results
|
|
* @clone: Copy of matching data with pending insertions and deletions
|
|
@@ -1114,12 +1133,13 @@ static int pipapo_realloc_scratch(struct nft_pipapo_match *clone,
|
|
int i;
|
|
|
|
for_each_possible_cpu(i) {
|
|
- unsigned long *scratch;
|
|
+ struct nft_pipapo_scratch *scratch;
|
|
#ifdef NFT_PIPAPO_ALIGN
|
|
- unsigned long *scratch_aligned;
|
|
+ void *scratch_aligned;
|
|
+ u32 align_off;
|
|
#endif
|
|
-
|
|
- scratch = kzalloc_node(bsize_max * sizeof(*scratch) * 2 +
|
|
+ scratch = kzalloc_node(struct_size(scratch, map,
|
|
+ bsize_max * 2) +
|
|
NFT_PIPAPO_ALIGN_HEADROOM,
|
|
GFP_KERNEL, cpu_to_node(i));
|
|
if (!scratch) {
|
|
@@ -1133,14 +1153,25 @@ static int pipapo_realloc_scratch(struct nft_pipapo_match *clone,
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- kfree(*per_cpu_ptr(clone->scratch, i));
|
|
-
|
|
- *per_cpu_ptr(clone->scratch, i) = scratch;
|
|
+ pipapo_free_scratch(clone, i);
|
|
|
|
#ifdef NFT_PIPAPO_ALIGN
|
|
- scratch_aligned = NFT_PIPAPO_LT_ALIGN(scratch);
|
|
- *per_cpu_ptr(clone->scratch_aligned, i) = scratch_aligned;
|
|
+ /* Align &scratch->map (not the struct itself): the extra
|
|
+ * %NFT_PIPAPO_ALIGN_HEADROOM bytes passed to kzalloc_node()
|
|
+ * above guarantee we can waste up to those bytes in order
|
|
+ * to align the map field regardless of its offset within
|
|
+ * the struct.
|
|
+ */
|
|
+ BUILD_BUG_ON(offsetof(struct nft_pipapo_scratch, map) > NFT_PIPAPO_ALIGN_HEADROOM);
|
|
+
|
|
+ scratch_aligned = NFT_PIPAPO_LT_ALIGN(&scratch->map);
|
|
+ scratch_aligned -= offsetof(struct nft_pipapo_scratch, map);
|
|
+ align_off = scratch_aligned - (void *)scratch;
|
|
+
|
|
+ scratch = scratch_aligned;
|
|
+ scratch->align_off = align_off;
|
|
#endif
|
|
+ *per_cpu_ptr(clone->scratch, i) = scratch;
|
|
}
|
|
|
|
return 0;
|
|
@@ -1293,11 +1324,6 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
|
|
if (!new->scratch)
|
|
goto out_scratch;
|
|
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- new->scratch_aligned = alloc_percpu(*new->scratch_aligned);
|
|
- if (!new->scratch_aligned)
|
|
- goto out_scratch;
|
|
-#endif
|
|
for_each_possible_cpu(i)
|
|
*per_cpu_ptr(new->scratch, i) = NULL;
|
|
|
|
@@ -1349,10 +1375,7 @@ out_lt:
|
|
}
|
|
out_scratch_realloc:
|
|
for_each_possible_cpu(i)
|
|
- kfree(*per_cpu_ptr(new->scratch, i));
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- free_percpu(new->scratch_aligned);
|
|
-#endif
|
|
+ pipapo_free_scratch(new, i);
|
|
out_scratch:
|
|
free_percpu(new->scratch);
|
|
kfree(new);
|
|
@@ -1637,13 +1660,9 @@ static void pipapo_free_match(struct nft_pipapo_match *m)
|
|
int i;
|
|
|
|
for_each_possible_cpu(i)
|
|
- kfree(*per_cpu_ptr(m->scratch, i));
|
|
+ pipapo_free_scratch(m, i);
|
|
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- free_percpu(m->scratch_aligned);
|
|
-#endif
|
|
free_percpu(m->scratch);
|
|
-
|
|
pipapo_free_fields(m);
|
|
|
|
kfree(m);
|
|
@@ -2130,7 +2149,7 @@ static int nft_pipapo_init(const struct nft_set *set,
|
|
m->field_count = field_count;
|
|
m->bsize_max = 0;
|
|
|
|
- m->scratch = alloc_percpu(unsigned long *);
|
|
+ m->scratch = alloc_percpu(struct nft_pipapo_scratch *);
|
|
if (!m->scratch) {
|
|
err = -ENOMEM;
|
|
goto out_scratch;
|
|
@@ -2138,16 +2157,6 @@ static int nft_pipapo_init(const struct nft_set *set,
|
|
for_each_possible_cpu(i)
|
|
*per_cpu_ptr(m->scratch, i) = NULL;
|
|
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- m->scratch_aligned = alloc_percpu(unsigned long *);
|
|
- if (!m->scratch_aligned) {
|
|
- err = -ENOMEM;
|
|
- goto out_free;
|
|
- }
|
|
- for_each_possible_cpu(i)
|
|
- *per_cpu_ptr(m->scratch_aligned, i) = NULL;
|
|
-#endif
|
|
-
|
|
rcu_head_init(&m->rcu);
|
|
|
|
nft_pipapo_for_each_field(f, i, m) {
|
|
@@ -2178,9 +2187,6 @@ static int nft_pipapo_init(const struct nft_set *set,
|
|
return 0;
|
|
|
|
out_free:
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- free_percpu(m->scratch_aligned);
|
|
-#endif
|
|
free_percpu(m->scratch);
|
|
out_scratch:
|
|
kfree(m);
|
|
@@ -2234,11 +2240,8 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx,
|
|
|
|
nft_set_pipapo_match_destroy(ctx, set, m);
|
|
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- free_percpu(m->scratch_aligned);
|
|
-#endif
|
|
for_each_possible_cpu(cpu)
|
|
- kfree(*per_cpu_ptr(m->scratch, cpu));
|
|
+ pipapo_free_scratch(m, cpu);
|
|
free_percpu(m->scratch);
|
|
pipapo_free_fields(m);
|
|
kfree(m);
|
|
@@ -2251,11 +2254,8 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx,
|
|
if (priv->dirty)
|
|
nft_set_pipapo_match_destroy(ctx, set, m);
|
|
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- free_percpu(priv->clone->scratch_aligned);
|
|
-#endif
|
|
for_each_possible_cpu(cpu)
|
|
- kfree(*per_cpu_ptr(priv->clone->scratch, cpu));
|
|
+ pipapo_free_scratch(priv->clone, cpu);
|
|
free_percpu(priv->clone->scratch);
|
|
|
|
pipapo_free_fields(priv->clone);
|
|
diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h
|
|
index 2e164a319945f..a4a58812c1088 100644
|
|
--- a/net/netfilter/nft_set_pipapo.h
|
|
+++ b/net/netfilter/nft_set_pipapo.h
|
|
@@ -130,21 +130,29 @@ struct nft_pipapo_field {
|
|
union nft_pipapo_map_bucket *mt;
|
|
};
|
|
|
|
+/**
|
|
+ * struct nft_pipapo_scratch - percpu data used for lookup and matching
|
|
+ * @map_index: Current working bitmap index, toggled between field matches
|
|
+ * @align_off: Offset to get the originally allocated address
|
|
+ * @map: store partial matching results during lookup
|
|
+ */
|
|
+struct nft_pipapo_scratch {
|
|
+ u8 map_index;
|
|
+ u32 align_off;
|
|
+ unsigned long map[];
|
|
+};
|
|
+
|
|
/**
|
|
* struct nft_pipapo_match - Data used for lookup and matching
|
|
* @field_count Amount of fields in set
|
|
* @scratch: Preallocated per-CPU maps for partial matching results
|
|
- * @scratch_aligned: Version of @scratch aligned to NFT_PIPAPO_ALIGN bytes
|
|
* @bsize_max: Maximum lookup table bucket size of all fields, in longs
|
|
* @rcu Matching data is swapped on commits
|
|
* @f: Fields, with lookup and mapping tables
|
|
*/
|
|
struct nft_pipapo_match {
|
|
int field_count;
|
|
-#ifdef NFT_PIPAPO_ALIGN
|
|
- unsigned long * __percpu *scratch_aligned;
|
|
-#endif
|
|
- unsigned long * __percpu *scratch;
|
|
+ struct nft_pipapo_scratch * __percpu *scratch;
|
|
size_t bsize_max;
|
|
struct rcu_head rcu;
|
|
struct nft_pipapo_field f[] __counted_by(field_count);
|
|
diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c
|
|
index 52e0d026d30ad..90e275bb3e5d7 100644
|
|
--- a/net/netfilter/nft_set_pipapo_avx2.c
|
|
+++ b/net/netfilter/nft_set_pipapo_avx2.c
|
|
@@ -71,9 +71,6 @@
|
|
#define NFT_PIPAPO_AVX2_ZERO(reg) \
|
|
asm volatile("vpxor %ymm" #reg ", %ymm" #reg ", %ymm" #reg)
|
|
|
|
-/* Current working bitmap index, toggled between field matches */
|
|
-static DEFINE_PER_CPU(bool, nft_pipapo_avx2_scratch_index);
|
|
-
|
|
/**
|
|
* nft_pipapo_avx2_prepare() - Prepare before main algorithm body
|
|
*
|
|
@@ -1120,11 +1117,12 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
|
|
const u32 *key, const struct nft_set_ext **ext)
|
|
{
|
|
struct nft_pipapo *priv = nft_set_priv(set);
|
|
- unsigned long *res, *fill, *scratch;
|
|
+ struct nft_pipapo_scratch *scratch;
|
|
u8 genmask = nft_genmask_cur(net);
|
|
const u8 *rp = (const u8 *)key;
|
|
struct nft_pipapo_match *m;
|
|
struct nft_pipapo_field *f;
|
|
+ unsigned long *res, *fill;
|
|
bool map_index;
|
|
int i, ret = 0;
|
|
|
|
@@ -1141,15 +1139,16 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
|
|
*/
|
|
kernel_fpu_begin_mask(0);
|
|
|
|
- scratch = *raw_cpu_ptr(m->scratch_aligned);
|
|
+ scratch = *raw_cpu_ptr(m->scratch);
|
|
if (unlikely(!scratch)) {
|
|
kernel_fpu_end();
|
|
return false;
|
|
}
|
|
- map_index = raw_cpu_read(nft_pipapo_avx2_scratch_index);
|
|
|
|
- res = scratch + (map_index ? m->bsize_max : 0);
|
|
- fill = scratch + (map_index ? 0 : m->bsize_max);
|
|
+ map_index = scratch->map_index;
|
|
+
|
|
+ res = scratch->map + (map_index ? m->bsize_max : 0);
|
|
+ fill = scratch->map + (map_index ? 0 : m->bsize_max);
|
|
|
|
/* Starting map doesn't need to be set for this implementation */
|
|
|
|
@@ -1221,7 +1220,7 @@ next_match:
|
|
|
|
out:
|
|
if (i % 2)
|
|
- raw_cpu_write(nft_pipapo_avx2_scratch_index, !map_index);
|
|
+ scratch->map_index = !map_index;
|
|
kernel_fpu_end();
|
|
|
|
return ret >= 0;
|
|
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
|
|
index e34662f4a71e0..5bf5572e945cc 100644
|
|
--- a/net/netfilter/nft_set_rbtree.c
|
|
+++ b/net/netfilter/nft_set_rbtree.c
|
|
@@ -235,7 +235,7 @@ static void nft_rbtree_gc_remove(struct net *net, struct nft_set *set,
|
|
|
|
static const struct nft_rbtree_elem *
|
|
nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv,
|
|
- struct nft_rbtree_elem *rbe, u8 genmask)
|
|
+ struct nft_rbtree_elem *rbe)
|
|
{
|
|
struct nft_set *set = (struct nft_set *)__set;
|
|
struct rb_node *prev = rb_prev(&rbe->node);
|
|
@@ -254,7 +254,7 @@ nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv,
|
|
while (prev) {
|
|
rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node);
|
|
if (nft_rbtree_interval_end(rbe_prev) &&
|
|
- nft_set_elem_active(&rbe_prev->ext, genmask))
|
|
+ nft_set_elem_active(&rbe_prev->ext, NFT_GENMASK_ANY))
|
|
break;
|
|
|
|
prev = rb_prev(prev);
|
|
@@ -365,7 +365,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|
nft_set_elem_active(&rbe->ext, cur_genmask)) {
|
|
const struct nft_rbtree_elem *removed_end;
|
|
|
|
- removed_end = nft_rbtree_gc_elem(set, priv, rbe, genmask);
|
|
+ removed_end = nft_rbtree_gc_elem(set, priv, rbe);
|
|
if (IS_ERR(removed_end))
|
|
return PTR_ERR(removed_end);
|
|
|
|
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
|
|
index e8b43408136ab..bda3f6690b321 100644
|
|
--- a/net/rxrpc/ar-internal.h
|
|
+++ b/net/rxrpc/ar-internal.h
|
|
@@ -198,11 +198,19 @@ struct rxrpc_host_header {
|
|
*/
|
|
struct rxrpc_skb_priv {
|
|
struct rxrpc_connection *conn; /* Connection referred to (poke packet) */
|
|
- u16 offset; /* Offset of data */
|
|
- u16 len; /* Length of data */
|
|
- u8 flags;
|
|
+ union {
|
|
+ struct {
|
|
+ u16 offset; /* Offset of data */
|
|
+ u16 len; /* Length of data */
|
|
+ u8 flags;
|
|
#define RXRPC_RX_VERIFIED 0x01
|
|
-
|
|
+ };
|
|
+ struct {
|
|
+ rxrpc_seq_t first_ack; /* First packet in acks table */
|
|
+ u8 nr_acks; /* Number of acks+nacks */
|
|
+ u8 nr_nacks; /* Number of nacks */
|
|
+ };
|
|
+ };
|
|
struct rxrpc_host_header hdr; /* RxRPC packet header from this packet */
|
|
};
|
|
|
|
@@ -506,7 +514,7 @@ struct rxrpc_connection {
|
|
enum rxrpc_call_completion completion; /* Completion condition */
|
|
s32 abort_code; /* Abort code of connection abort */
|
|
int debug_id; /* debug ID for printks */
|
|
- atomic_t serial; /* packet serial number counter */
|
|
+ rxrpc_serial_t tx_serial; /* Outgoing packet serial number counter */
|
|
unsigned int hi_serial; /* highest serial number received */
|
|
u32 service_id; /* Service ID, possibly upgraded */
|
|
u32 security_level; /* Security level selected */
|
|
@@ -688,11 +696,11 @@ struct rxrpc_call {
|
|
u8 cong_dup_acks; /* Count of ACKs showing missing packets */
|
|
u8 cong_cumul_acks; /* Cumulative ACK count */
|
|
ktime_t cong_tstamp; /* Last time cwnd was changed */
|
|
+ struct sk_buff *cong_last_nack; /* Last ACK with nacks received */
|
|
|
|
/* Receive-phase ACK management (ACKs we send). */
|
|
u8 ackr_reason; /* reason to ACK */
|
|
u16 ackr_sack_base; /* Starting slot in SACK table ring */
|
|
- rxrpc_serial_t ackr_serial; /* serial of packet being ACK'd */
|
|
rxrpc_seq_t ackr_window; /* Base of SACK window */
|
|
rxrpc_seq_t ackr_wtop; /* Base of SACK window */
|
|
unsigned int ackr_nr_unacked; /* Number of unacked packets */
|
|
@@ -726,7 +734,8 @@ struct rxrpc_call {
|
|
struct rxrpc_ack_summary {
|
|
u16 nr_acks; /* Number of ACKs in packet */
|
|
u16 nr_new_acks; /* Number of new ACKs in packet */
|
|
- u16 nr_rot_new_acks; /* Number of rotated new ACKs */
|
|
+ u16 nr_new_nacks; /* Number of new nacks in packet */
|
|
+ u16 nr_retained_nacks; /* Number of nacks retained between ACKs */
|
|
u8 ack_reason;
|
|
bool saw_nacks; /* Saw NACKs in packet */
|
|
bool new_low_nack; /* T if new low NACK found */
|
|
@@ -818,6 +827,20 @@ static inline bool rxrpc_sending_to_client(const struct rxrpc_txbuf *txb)
|
|
|
|
#include <trace/events/rxrpc.h>
|
|
|
|
+/*
|
|
+ * Allocate the next serial number on a connection. 0 must be skipped.
|
|
+ */
|
|
+static inline rxrpc_serial_t rxrpc_get_next_serial(struct rxrpc_connection *conn)
|
|
+{
|
|
+ rxrpc_serial_t serial;
|
|
+
|
|
+ serial = conn->tx_serial;
|
|
+ if (serial == 0)
|
|
+ serial = 1;
|
|
+ conn->tx_serial = serial + 1;
|
|
+ return serial;
|
|
+}
|
|
+
|
|
/*
|
|
* af_rxrpc.c
|
|
*/
|
|
diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
|
|
index e363f21a20141..0f78544d043be 100644
|
|
--- a/net/rxrpc/call_event.c
|
|
+++ b/net/rxrpc/call_event.c
|
|
@@ -43,8 +43,6 @@ void rxrpc_propose_delay_ACK(struct rxrpc_call *call, rxrpc_serial_t serial,
|
|
unsigned long expiry = rxrpc_soft_ack_delay;
|
|
unsigned long now = jiffies, ack_at;
|
|
|
|
- call->ackr_serial = serial;
|
|
-
|
|
if (rxrpc_soft_ack_delay < expiry)
|
|
expiry = rxrpc_soft_ack_delay;
|
|
if (call->peer->srtt_us != 0)
|
|
@@ -114,6 +112,7 @@ static void rxrpc_congestion_timeout(struct rxrpc_call *call)
|
|
void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
|
|
{
|
|
struct rxrpc_ackpacket *ack = NULL;
|
|
+ struct rxrpc_skb_priv *sp;
|
|
struct rxrpc_txbuf *txb;
|
|
unsigned long resend_at;
|
|
rxrpc_seq_t transmitted = READ_ONCE(call->tx_transmitted);
|
|
@@ -141,14 +140,15 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
|
|
* explicitly NAK'd packets.
|
|
*/
|
|
if (ack_skb) {
|
|
+ sp = rxrpc_skb(ack_skb);
|
|
ack = (void *)ack_skb->data + sizeof(struct rxrpc_wire_header);
|
|
|
|
- for (i = 0; i < ack->nAcks; i++) {
|
|
+ for (i = 0; i < sp->nr_acks; i++) {
|
|
rxrpc_seq_t seq;
|
|
|
|
if (ack->acks[i] & 1)
|
|
continue;
|
|
- seq = ntohl(ack->firstPacket) + i;
|
|
+ seq = sp->first_ack + i;
|
|
if (after(txb->seq, transmitted))
|
|
break;
|
|
if (after(txb->seq, seq))
|
|
@@ -373,7 +373,6 @@ static void rxrpc_send_initial_ping(struct rxrpc_call *call)
|
|
bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
|
|
{
|
|
unsigned long now, next, t;
|
|
- rxrpc_serial_t ackr_serial;
|
|
bool resend = false, expired = false;
|
|
s32 abort_code;
|
|
|
|
@@ -423,8 +422,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
|
|
if (time_after_eq(now, t)) {
|
|
trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now);
|
|
cmpxchg(&call->delay_ack_at, t, now + MAX_JIFFY_OFFSET);
|
|
- ackr_serial = xchg(&call->ackr_serial, 0);
|
|
- rxrpc_send_ACK(call, RXRPC_ACK_DELAY, ackr_serial,
|
|
+ rxrpc_send_ACK(call, RXRPC_ACK_DELAY, 0,
|
|
rxrpc_propose_ack_ping_for_lost_ack);
|
|
}
|
|
|
|
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
|
|
index f10b37c147721..0a50341d920af 100644
|
|
--- a/net/rxrpc/call_object.c
|
|
+++ b/net/rxrpc/call_object.c
|
|
@@ -685,6 +685,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
|
|
|
|
del_timer_sync(&call->timer);
|
|
|
|
+ rxrpc_free_skb(call->cong_last_nack, rxrpc_skb_put_last_nack);
|
|
rxrpc_cleanup_ring(call);
|
|
while ((txb = list_first_entry_or_null(&call->tx_sendmsg,
|
|
struct rxrpc_txbuf, call_link))) {
|
|
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
|
|
index 95f4bc206b3dc..1f251d758cb9d 100644
|
|
--- a/net/rxrpc/conn_event.c
|
|
+++ b/net/rxrpc/conn_event.c
|
|
@@ -95,6 +95,14 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
|
|
|
|
_enter("%d", conn->debug_id);
|
|
|
|
+ if (sp && sp->hdr.type == RXRPC_PACKET_TYPE_ACK) {
|
|
+ if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
|
|
+ &pkt.ack, sizeof(pkt.ack)) < 0)
|
|
+ return;
|
|
+ if (pkt.ack.reason == RXRPC_ACK_PING_RESPONSE)
|
|
+ return;
|
|
+ }
|
|
+
|
|
chan = &conn->channels[channel];
|
|
|
|
/* If the last call got moved on whilst we were waiting to run, just
|
|
@@ -117,7 +125,7 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
|
|
iov[2].iov_base = &ack_info;
|
|
iov[2].iov_len = sizeof(ack_info);
|
|
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
|
|
pkt.whdr.epoch = htonl(conn->proto.epoch);
|
|
pkt.whdr.cid = htonl(conn->proto.cid | channel);
|
|
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
|
|
index 92495e73b8699..9691de00ade75 100644
|
|
--- a/net/rxrpc/input.c
|
|
+++ b/net/rxrpc/input.c
|
|
@@ -45,11 +45,9 @@ static void rxrpc_congestion_management(struct rxrpc_call *call,
|
|
}
|
|
|
|
cumulative_acks += summary->nr_new_acks;
|
|
- cumulative_acks += summary->nr_rot_new_acks;
|
|
if (cumulative_acks > 255)
|
|
cumulative_acks = 255;
|
|
|
|
- summary->mode = call->cong_mode;
|
|
summary->cwnd = call->cong_cwnd;
|
|
summary->ssthresh = call->cong_ssthresh;
|
|
summary->cumulative_acks = cumulative_acks;
|
|
@@ -151,6 +149,7 @@ out_no_clear_ca:
|
|
cwnd = RXRPC_TX_MAX_WINDOW;
|
|
call->cong_cwnd = cwnd;
|
|
call->cong_cumul_acks = cumulative_acks;
|
|
+ summary->mode = call->cong_mode;
|
|
trace_rxrpc_congest(call, summary, acked_serial, change);
|
|
if (resend)
|
|
rxrpc_resend(call, skb);
|
|
@@ -213,7 +212,6 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to,
|
|
list_for_each_entry_rcu(txb, &call->tx_buffer, call_link, false) {
|
|
if (before_eq(txb->seq, call->acks_hard_ack))
|
|
continue;
|
|
- summary->nr_rot_new_acks++;
|
|
if (test_bit(RXRPC_TXBUF_LAST, &txb->flags)) {
|
|
set_bit(RXRPC_CALL_TX_LAST, &call->flags);
|
|
rot_last = true;
|
|
@@ -254,6 +252,11 @@ static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
|
|
{
|
|
ASSERT(test_bit(RXRPC_CALL_TX_LAST, &call->flags));
|
|
|
|
+ if (unlikely(call->cong_last_nack)) {
|
|
+ rxrpc_free_skb(call->cong_last_nack, rxrpc_skb_put_last_nack);
|
|
+ call->cong_last_nack = NULL;
|
|
+ }
|
|
+
|
|
switch (__rxrpc_call_state(call)) {
|
|
case RXRPC_CALL_CLIENT_SEND_REQUEST:
|
|
case RXRPC_CALL_CLIENT_AWAIT_REPLY:
|
|
@@ -702,6 +705,43 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
|
|
wake_up(&call->waitq);
|
|
}
|
|
|
|
+/*
|
|
+ * Determine how many nacks from the previous ACK have now been satisfied.
|
|
+ */
|
|
+static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rxrpc_call *call,
|
|
+ struct rxrpc_ack_summary *summary,
|
|
+ rxrpc_seq_t seq)
|
|
+{
|
|
+ struct sk_buff *skb = call->cong_last_nack;
|
|
+ struct rxrpc_ackpacket ack;
|
|
+ struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
+ unsigned int i, new_acks = 0, retained_nacks = 0;
|
|
+ rxrpc_seq_t old_seq = sp->first_ack;
|
|
+ u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(ack);
|
|
+
|
|
+ if (after_eq(seq, old_seq + sp->nr_acks)) {
|
|
+ summary->nr_new_acks += sp->nr_nacks;
|
|
+ summary->nr_new_acks += seq - (old_seq + sp->nr_acks);
|
|
+ summary->nr_retained_nacks = 0;
|
|
+ } else if (seq == old_seq) {
|
|
+ summary->nr_retained_nacks = sp->nr_nacks;
|
|
+ } else {
|
|
+ for (i = 0; i < sp->nr_acks; i++) {
|
|
+ if (acks[i] == RXRPC_ACK_TYPE_NACK) {
|
|
+ if (before(old_seq + i, seq))
|
|
+ new_acks++;
|
|
+ else
|
|
+ retained_nacks++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ summary->nr_new_acks += new_acks;
|
|
+ summary->nr_retained_nacks = retained_nacks;
|
|
+ }
|
|
+
|
|
+ return old_seq + sp->nr_acks;
|
|
+}
|
|
+
|
|
/*
|
|
* Process individual soft ACKs.
|
|
*
|
|
@@ -711,25 +751,51 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
|
|
* the timer on the basis that the peer might just not have processed them at
|
|
* the time the ACK was sent.
|
|
*/
|
|
-static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
|
|
- rxrpc_seq_t seq, int nr_acks,
|
|
- struct rxrpc_ack_summary *summary)
|
|
+static void rxrpc_input_soft_acks(struct rxrpc_call *call,
|
|
+ struct rxrpc_ack_summary *summary,
|
|
+ struct sk_buff *skb,
|
|
+ rxrpc_seq_t seq,
|
|
+ rxrpc_seq_t since)
|
|
{
|
|
- unsigned int i;
|
|
+ struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
+ unsigned int i, old_nacks = 0;
|
|
+ rxrpc_seq_t lowest_nak = seq + sp->nr_acks;
|
|
+ u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket);
|
|
|
|
- for (i = 0; i < nr_acks; i++) {
|
|
+ for (i = 0; i < sp->nr_acks; i++) {
|
|
if (acks[i] == RXRPC_ACK_TYPE_ACK) {
|
|
summary->nr_acks++;
|
|
- summary->nr_new_acks++;
|
|
+ if (after_eq(seq, since))
|
|
+ summary->nr_new_acks++;
|
|
} else {
|
|
- if (!summary->saw_nacks &&
|
|
- call->acks_lowest_nak != seq + i) {
|
|
- call->acks_lowest_nak = seq + i;
|
|
- summary->new_low_nack = true;
|
|
- }
|
|
summary->saw_nacks = true;
|
|
+ if (before(seq, since)) {
|
|
+ /* Overlap with previous ACK */
|
|
+ old_nacks++;
|
|
+ } else {
|
|
+ summary->nr_new_nacks++;
|
|
+ sp->nr_nacks++;
|
|
+ }
|
|
+
|
|
+ if (before(seq, lowest_nak))
|
|
+ lowest_nak = seq;
|
|
}
|
|
+ seq++;
|
|
+ }
|
|
+
|
|
+ if (lowest_nak != call->acks_lowest_nak) {
|
|
+ call->acks_lowest_nak = lowest_nak;
|
|
+ summary->new_low_nack = true;
|
|
}
|
|
+
|
|
+ /* We *can* have more nacks than we did - the peer is permitted to drop
|
|
+ * packets it has soft-acked and re-request them. Further, it is
|
|
+ * possible for the nack distribution to change whilst the number of
|
|
+ * nacks stays the same or goes down.
|
|
+ */
|
|
+ if (old_nacks < summary->nr_retained_nacks)
|
|
+ summary->nr_new_acks += summary->nr_retained_nacks - old_nacks;
|
|
+ summary->nr_retained_nacks = old_nacks;
|
|
}
|
|
|
|
/*
|
|
@@ -773,7 +839,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
|
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
struct rxrpc_ackinfo info;
|
|
rxrpc_serial_t ack_serial, acked_serial;
|
|
- rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt;
|
|
+ rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt, since;
|
|
int nr_acks, offset, ioffset;
|
|
|
|
_enter("");
|
|
@@ -789,6 +855,8 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
|
|
prev_pkt = ntohl(ack.previousPacket);
|
|
hard_ack = first_soft_ack - 1;
|
|
nr_acks = ack.nAcks;
|
|
+ sp->first_ack = first_soft_ack;
|
|
+ sp->nr_acks = nr_acks;
|
|
summary.ack_reason = (ack.reason < RXRPC_ACK__INVALID ?
|
|
ack.reason : RXRPC_ACK__INVALID);
|
|
|
|
@@ -858,6 +926,16 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
|
|
if (nr_acks > 0)
|
|
skb_condense(skb);
|
|
|
|
+ if (call->cong_last_nack) {
|
|
+ since = rxrpc_input_check_prev_ack(call, &summary, first_soft_ack);
|
|
+ rxrpc_free_skb(call->cong_last_nack, rxrpc_skb_put_last_nack);
|
|
+ call->cong_last_nack = NULL;
|
|
+ } else {
|
|
+ summary.nr_new_acks = first_soft_ack - call->acks_first_seq;
|
|
+ call->acks_lowest_nak = first_soft_ack + nr_acks;
|
|
+ since = first_soft_ack;
|
|
+ }
|
|
+
|
|
call->acks_latest_ts = skb->tstamp;
|
|
call->acks_first_seq = first_soft_ack;
|
|
call->acks_prev_seq = prev_pkt;
|
|
@@ -866,7 +944,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
|
|
case RXRPC_ACK_PING:
|
|
break;
|
|
default:
|
|
- if (after(acked_serial, call->acks_highest_serial))
|
|
+ if (acked_serial && after(acked_serial, call->acks_highest_serial))
|
|
call->acks_highest_serial = acked_serial;
|
|
break;
|
|
}
|
|
@@ -905,8 +983,9 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
|
|
if (nr_acks > 0) {
|
|
if (offset > (int)skb->len - nr_acks)
|
|
return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_short_sack);
|
|
- rxrpc_input_soft_acks(call, skb->data + offset, first_soft_ack,
|
|
- nr_acks, &summary);
|
|
+ rxrpc_input_soft_acks(call, &summary, skb, first_soft_ack, since);
|
|
+ rxrpc_get_skb(skb, rxrpc_skb_get_last_nack);
|
|
+ call->cong_last_nack = skb;
|
|
}
|
|
|
|
if (test_bit(RXRPC_CALL_TX_LAST, &call->flags) &&
|
|
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
|
|
index a0906145e8293..4a292f860ae37 100644
|
|
--- a/net/rxrpc/output.c
|
|
+++ b/net/rxrpc/output.c
|
|
@@ -216,7 +216,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
|
iov[0].iov_len = sizeof(txb->wire) + sizeof(txb->ack) + n;
|
|
len = iov[0].iov_len;
|
|
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
txb->wire.serial = htonl(serial);
|
|
trace_rxrpc_tx_ack(call->debug_id, serial,
|
|
ntohl(txb->ack.firstPacket),
|
|
@@ -302,7 +302,7 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
|
|
iov[0].iov_base = &pkt;
|
|
iov[0].iov_len = sizeof(pkt);
|
|
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
pkt.whdr.serial = htonl(serial);
|
|
|
|
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, sizeof(pkt));
|
|
@@ -334,7 +334,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
|
_enter("%x,{%d}", txb->seq, txb->len);
|
|
|
|
/* Each transmission of a Tx packet needs a new serial number */
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
txb->wire.serial = htonl(serial);
|
|
|
|
if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) &&
|
|
@@ -558,7 +558,7 @@ void rxrpc_send_conn_abort(struct rxrpc_connection *conn)
|
|
|
|
len = iov[0].iov_len + iov[1].iov_len;
|
|
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
whdr.serial = htonl(serial);
|
|
|
|
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len);
|
|
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
|
|
index 682636d3b060b..208312c244f6b 100644
|
|
--- a/net/rxrpc/proc.c
|
|
+++ b/net/rxrpc/proc.c
|
|
@@ -181,7 +181,7 @@ print:
|
|
atomic_read(&conn->active),
|
|
state,
|
|
key_serial(conn->key),
|
|
- atomic_read(&conn->serial),
|
|
+ conn->tx_serial,
|
|
conn->hi_serial,
|
|
conn->channels[0].call_id,
|
|
conn->channels[1].call_id,
|
|
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
|
|
index b52dedcebce0a..6b32d61d4cdc4 100644
|
|
--- a/net/rxrpc/rxkad.c
|
|
+++ b/net/rxrpc/rxkad.c
|
|
@@ -664,7 +664,7 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
|
|
|
|
len = iov[0].iov_len + iov[1].iov_len;
|
|
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
whdr.serial = htonl(serial);
|
|
|
|
ret = kernel_sendmsg(conn->local->socket, &msg, iov, 2, len);
|
|
@@ -721,7 +721,7 @@ static int rxkad_send_response(struct rxrpc_connection *conn,
|
|
|
|
len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
|
|
|
|
- serial = atomic_inc_return(&conn->serial);
|
|
+ serial = rxrpc_get_next_serial(conn);
|
|
whdr.serial = htonl(serial);
|
|
|
|
rxrpc_local_dont_fragment(conn->local, false);
|
|
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
|
|
index 2cde375477e38..878415c435276 100644
|
|
--- a/net/tipc/bearer.c
|
|
+++ b/net/tipc/bearer.c
|
|
@@ -1086,6 +1086,12 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
#ifdef CONFIG_TIPC_MEDIA_UDP
|
|
if (attrs[TIPC_NLA_BEARER_UDP_OPTS]) {
|
|
+ if (b->media->type_id != TIPC_MEDIA_TYPE_UDP) {
|
|
+ rtnl_unlock();
|
|
+ NL_SET_ERR_MSG(info->extack, "UDP option is unsupported");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
err = tipc_udp_nl_bearer_add(b,
|
|
attrs[TIPC_NLA_BEARER_UDP_OPTS]);
|
|
if (err) {
|
|
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
|
|
index 2405f0f9af31c..8f63f0b4bf012 100644
|
|
--- a/net/unix/garbage.c
|
|
+++ b/net/unix/garbage.c
|
|
@@ -314,6 +314,17 @@ void unix_gc(void)
|
|
/* Here we are. Hitlist is filled. Die. */
|
|
__skb_queue_purge(&hitlist);
|
|
|
|
+#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
|
+ list_for_each_entry_safe(u, next, &gc_candidates, link) {
|
|
+ struct sk_buff *skb = u->oob_skb;
|
|
+
|
|
+ if (skb) {
|
|
+ u->oob_skb = NULL;
|
|
+ kfree_skb(skb);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
spin_lock(&unix_gc_lock);
|
|
|
|
/* There could be io_uring registered files, just push them back to
|
|
diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs
|
|
index 0b6bf5b6da434..8cb4a31cf6e54 100644
|
|
--- a/rust/alloc/alloc.rs
|
|
+++ b/rust/alloc/alloc.rs
|
|
@@ -6,9 +6,7 @@
|
|
|
|
#[cfg(not(test))]
|
|
use core::intrinsics;
|
|
-use core::intrinsics::{min_align_of_val, size_of_val};
|
|
|
|
-use core::ptr::Unique;
|
|
#[cfg(not(test))]
|
|
use core::ptr::{self, NonNull};
|
|
|
|
@@ -40,7 +38,6 @@ extern "Rust" {
|
|
#[rustc_nounwind]
|
|
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
|
|
|
- #[cfg(not(bootstrap))]
|
|
static __rust_no_alloc_shim_is_unstable: u8;
|
|
}
|
|
|
|
@@ -98,7 +95,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
|
|
unsafe {
|
|
// Make sure we don't accidentally allow omitting the allocator shim in
|
|
// stable code until it is actually stabilized.
|
|
- #[cfg(not(bootstrap))]
|
|
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
|
|
|
|
__rust_alloc(layout.size(), layout.align())
|
|
@@ -339,22 +335,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
|
}
|
|
}
|
|
|
|
-#[cfg_attr(not(test), lang = "box_free")]
|
|
-#[inline]
|
|
-// This signature has to be the same as `Box`, otherwise an ICE will happen.
|
|
-// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
|
|
-// well.
|
|
-// For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
|
|
-// this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
|
|
-pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
|
|
- unsafe {
|
|
- let size = size_of_val(ptr.as_ref());
|
|
- let align = min_align_of_val(ptr.as_ref());
|
|
- let layout = Layout::from_size_align_unchecked(size, align);
|
|
- alloc.deallocate(From::from(ptr.cast()), layout)
|
|
- }
|
|
-}
|
|
-
|
|
// # Allocation error handler
|
|
|
|
#[cfg(not(no_global_oom_handling))]
|
|
@@ -414,7 +394,6 @@ pub mod __alloc_error_handler {
|
|
static __rust_alloc_error_handler_should_panic: u8;
|
|
}
|
|
|
|
- #[allow(unused_unsafe)]
|
|
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
|
|
panic!("memory allocation of {size} bytes failed")
|
|
} else {
|
|
diff --git a/rust/alloc/boxed.rs b/rust/alloc/boxed.rs
|
|
index c8173cea83177..9620eba172687 100644
|
|
--- a/rust/alloc/boxed.rs
|
|
+++ b/rust/alloc/boxed.rs
|
|
@@ -159,12 +159,12 @@ use core::hash::{Hash, Hasher};
|
|
use core::iter::FusedIterator;
|
|
use core::marker::Tuple;
|
|
use core::marker::Unsize;
|
|
-use core::mem;
|
|
+use core::mem::{self, SizedTypeProperties};
|
|
use core::ops::{
|
|
CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver,
|
|
};
|
|
use core::pin::Pin;
|
|
-use core::ptr::{self, Unique};
|
|
+use core::ptr::{self, NonNull, Unique};
|
|
use core::task::{Context, Poll};
|
|
|
|
#[cfg(not(no_global_oom_handling))]
|
|
@@ -483,8 +483,12 @@ impl<T, A: Allocator> Box<T, A> {
|
|
where
|
|
A: Allocator,
|
|
{
|
|
- let layout = Layout::new::<mem::MaybeUninit<T>>();
|
|
- let ptr = alloc.allocate(layout)?.cast();
|
|
+ let ptr = if T::IS_ZST {
|
|
+ NonNull::dangling()
|
|
+ } else {
|
|
+ let layout = Layout::new::<mem::MaybeUninit<T>>();
|
|
+ alloc.allocate(layout)?.cast()
|
|
+ };
|
|
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
|
|
}
|
|
|
|
@@ -553,8 +557,12 @@ impl<T, A: Allocator> Box<T, A> {
|
|
where
|
|
A: Allocator,
|
|
{
|
|
- let layout = Layout::new::<mem::MaybeUninit<T>>();
|
|
- let ptr = alloc.allocate_zeroed(layout)?.cast();
|
|
+ let ptr = if T::IS_ZST {
|
|
+ NonNull::dangling()
|
|
+ } else {
|
|
+ let layout = Layout::new::<mem::MaybeUninit<T>>();
|
|
+ alloc.allocate_zeroed(layout)?.cast()
|
|
+ };
|
|
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
|
|
}
|
|
|
|
@@ -679,14 +687,16 @@ impl<T> Box<[T]> {
|
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
|
#[inline]
|
|
pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
|
|
- unsafe {
|
|
+ let ptr = if T::IS_ZST || len == 0 {
|
|
+ NonNull::dangling()
|
|
+ } else {
|
|
let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
|
|
Ok(l) => l,
|
|
Err(_) => return Err(AllocError),
|
|
};
|
|
- let ptr = Global.allocate(layout)?;
|
|
- Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len))
|
|
- }
|
|
+ Global.allocate(layout)?.cast()
|
|
+ };
|
|
+ unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
|
|
}
|
|
|
|
/// Constructs a new boxed slice with uninitialized contents, with the memory
|
|
@@ -711,14 +721,16 @@ impl<T> Box<[T]> {
|
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
|
#[inline]
|
|
pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
|
|
- unsafe {
|
|
+ let ptr = if T::IS_ZST || len == 0 {
|
|
+ NonNull::dangling()
|
|
+ } else {
|
|
let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
|
|
Ok(l) => l,
|
|
Err(_) => return Err(AllocError),
|
|
};
|
|
- let ptr = Global.allocate_zeroed(layout)?;
|
|
- Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len))
|
|
- }
|
|
+ Global.allocate_zeroed(layout)?.cast()
|
|
+ };
|
|
+ unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
|
|
}
|
|
}
|
|
|
|
@@ -1215,8 +1227,18 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
|
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
|
|
+ #[inline]
|
|
fn drop(&mut self) {
|
|
- // FIXME: Do nothing, drop is currently performed by compiler.
|
|
+ // the T in the Box is dropped by the compiler before the destructor is run
|
|
+
|
|
+ let ptr = self.0;
|
|
+
|
|
+ unsafe {
|
|
+ let layout = Layout::for_value_raw(ptr.as_ptr());
|
|
+ if layout.size() != 0 {
|
|
+ self.1.deallocate(From::from(ptr.cast()), layout);
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -2165,7 +2187,7 @@ impl dyn Error + Send {
|
|
let err: Box<dyn Error> = self;
|
|
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
|
// Reapply the `Send` marker.
|
|
- mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
|
|
+ Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
|
|
})
|
|
}
|
|
}
|
|
@@ -2179,7 +2201,7 @@ impl dyn Error + Send + Sync {
|
|
let err: Box<dyn Error> = self;
|
|
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
|
// Reapply the `Send + Sync` marker.
|
|
- mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
|
|
+ Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
|
|
})
|
|
}
|
|
}
|
|
diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs
|
|
index 85e91356ecb30..73b9ffd845d95 100644
|
|
--- a/rust/alloc/lib.rs
|
|
+++ b/rust/alloc/lib.rs
|
|
@@ -58,6 +58,11 @@
|
|
//! [`Rc`]: rc
|
|
//! [`RefCell`]: core::cell
|
|
|
|
+// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
|
+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
|
+// rustc itself never sets the feature, so this line has no effect there.
|
|
+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
|
+//
|
|
#![allow(unused_attributes)]
|
|
#![stable(feature = "alloc", since = "1.36.0")]
|
|
#![doc(
|
|
@@ -77,11 +82,6 @@
|
|
))]
|
|
#![no_std]
|
|
#![needs_allocator]
|
|
-// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
|
-// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
|
-// rustc itself never sets the feature, so this line has no affect there.
|
|
-#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
|
-//
|
|
// Lints:
|
|
#![deny(unsafe_op_in_unsafe_fn)]
|
|
#![deny(fuzzy_provenance_casts)]
|
|
@@ -90,6 +90,8 @@
|
|
#![warn(missing_docs)]
|
|
#![allow(explicit_outlives_requirements)]
|
|
#![warn(multiple_supertrait_upcastable)]
|
|
+#![cfg_attr(not(bootstrap), allow(internal_features))]
|
|
+#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
|
|
//
|
|
// Library features:
|
|
// tidy-alphabetical-start
|
|
@@ -139,7 +141,6 @@
|
|
#![feature(maybe_uninit_uninit_array_transpose)]
|
|
#![feature(pattern)]
|
|
#![feature(pointer_byte_offsets)]
|
|
-#![feature(provide_any)]
|
|
#![feature(ptr_internals)]
|
|
#![feature(ptr_metadata)]
|
|
#![feature(ptr_sub_ptr)]
|
|
diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
|
|
index 65d5ce15828e4..a7425582a323f 100644
|
|
--- a/rust/alloc/raw_vec.rs
|
|
+++ b/rust/alloc/raw_vec.rs
|
|
@@ -471,16 +471,26 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
|
|
// See current_memory() why this assert is here
|
|
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
|
|
- let ptr = unsafe {
|
|
- // `Layout::array` cannot overflow here because it would have
|
|
- // overflowed earlier when capacity was larger.
|
|
- let new_size = mem::size_of::<T>().unchecked_mul(cap);
|
|
- let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
|
- self.alloc
|
|
- .shrink(ptr, layout, new_layout)
|
|
- .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
|
|
- };
|
|
- self.set_ptr_and_cap(ptr, cap);
|
|
+
|
|
+ // If shrinking to 0, deallocate the buffer. We don't reach this point
|
|
+ // for the T::IS_ZST case since current_memory() will have returned
|
|
+ // None.
|
|
+ if cap == 0 {
|
|
+ unsafe { self.alloc.deallocate(ptr, layout) };
|
|
+ self.ptr = Unique::dangling();
|
|
+ self.cap = 0;
|
|
+ } else {
|
|
+ let ptr = unsafe {
|
|
+ // `Layout::array` cannot overflow here because it would have
|
|
+ // overflowed earlier when capacity was larger.
|
|
+ let new_size = mem::size_of::<T>().unchecked_mul(cap);
|
|
+ let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
|
+ self.alloc
|
|
+ .shrink(ptr, layout, new_layout)
|
|
+ .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
|
|
+ };
|
|
+ self.set_ptr_and_cap(ptr, cap);
|
|
+ }
|
|
Ok(())
|
|
}
|
|
}
|
|
diff --git a/rust/alloc/vec/drain_filter.rs b/rust/alloc/vec/drain_filter.rs
|
|
deleted file mode 100644
|
|
index 09efff090e428..0000000000000
|
|
--- a/rust/alloc/vec/drain_filter.rs
|
|
+++ /dev/null
|
|
@@ -1,199 +0,0 @@
|
|
-// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
-
|
|
-use crate::alloc::{Allocator, Global};
|
|
-use core::mem::{ManuallyDrop, SizedTypeProperties};
|
|
-use core::ptr;
|
|
-use core::slice;
|
|
-
|
|
-use super::Vec;
|
|
-
|
|
-/// An iterator which uses a closure to determine if an element should be removed.
|
|
-///
|
|
-/// This struct is created by [`Vec::drain_filter`].
|
|
-/// See its documentation for more.
|
|
-///
|
|
-/// # Example
|
|
-///
|
|
-/// ```
|
|
-/// #![feature(drain_filter)]
|
|
-///
|
|
-/// let mut v = vec![0, 1, 2];
|
|
-/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0);
|
|
-/// ```
|
|
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
-#[derive(Debug)]
|
|
-pub struct DrainFilter<
|
|
- 'a,
|
|
- T,
|
|
- F,
|
|
- #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
|
-> where
|
|
- F: FnMut(&mut T) -> bool,
|
|
-{
|
|
- pub(super) vec: &'a mut Vec<T, A>,
|
|
- /// The index of the item that will be inspected by the next call to `next`.
|
|
- pub(super) idx: usize,
|
|
- /// The number of items that have been drained (removed) thus far.
|
|
- pub(super) del: usize,
|
|
- /// The original length of `vec` prior to draining.
|
|
- pub(super) old_len: usize,
|
|
- /// The filter test predicate.
|
|
- pub(super) pred: F,
|
|
- /// A flag that indicates a panic has occurred in the filter test predicate.
|
|
- /// This is used as a hint in the drop implementation to prevent consumption
|
|
- /// of the remainder of the `DrainFilter`. Any unprocessed items will be
|
|
- /// backshifted in the `vec`, but no further items will be dropped or
|
|
- /// tested by the filter predicate.
|
|
- pub(super) panic_flag: bool,
|
|
-}
|
|
-
|
|
-impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
|
|
-where
|
|
- F: FnMut(&mut T) -> bool,
|
|
-{
|
|
- /// Returns a reference to the underlying allocator.
|
|
- #[unstable(feature = "allocator_api", issue = "32838")]
|
|
- #[inline]
|
|
- pub fn allocator(&self) -> &A {
|
|
- self.vec.allocator()
|
|
- }
|
|
-
|
|
- /// Keep unyielded elements in the source `Vec`.
|
|
- ///
|
|
- /// # Examples
|
|
- ///
|
|
- /// ```
|
|
- /// #![feature(drain_filter)]
|
|
- /// #![feature(drain_keep_rest)]
|
|
- ///
|
|
- /// let mut vec = vec!['a', 'b', 'c'];
|
|
- /// let mut drain = vec.drain_filter(|_| true);
|
|
- ///
|
|
- /// assert_eq!(drain.next().unwrap(), 'a');
|
|
- ///
|
|
- /// // This call keeps 'b' and 'c' in the vec.
|
|
- /// drain.keep_rest();
|
|
- ///
|
|
- /// // If we wouldn't call `keep_rest()`,
|
|
- /// // `vec` would be empty.
|
|
- /// assert_eq!(vec, ['b', 'c']);
|
|
- /// ```
|
|
- #[unstable(feature = "drain_keep_rest", issue = "101122")]
|
|
- pub fn keep_rest(self) {
|
|
- // At this moment layout looks like this:
|
|
- //
|
|
- // _____________________/-- old_len
|
|
- // / \
|
|
- // [kept] [yielded] [tail]
|
|
- // \_______/ ^-- idx
|
|
- // \-- del
|
|
- //
|
|
- // Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
|
|
- //
|
|
- // 1. Move [tail] after [kept]
|
|
- // 2. Update length of the original vec to `old_len - del`
|
|
- // a. In case of ZST, this is the only thing we want to do
|
|
- // 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
|
|
- let mut this = ManuallyDrop::new(self);
|
|
-
|
|
- unsafe {
|
|
- // ZSTs have no identity, so we don't need to move them around.
|
|
- if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
|
|
- let ptr = this.vec.as_mut_ptr();
|
|
- let src = ptr.add(this.idx);
|
|
- let dst = src.sub(this.del);
|
|
- let tail_len = this.old_len - this.idx;
|
|
- src.copy_to(dst, tail_len);
|
|
- }
|
|
-
|
|
- let new_len = this.old_len - this.del;
|
|
- this.vec.set_len(new_len);
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
-impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
|
|
-where
|
|
- F: FnMut(&mut T) -> bool,
|
|
-{
|
|
- type Item = T;
|
|
-
|
|
- fn next(&mut self) -> Option<T> {
|
|
- unsafe {
|
|
- while self.idx < self.old_len {
|
|
- let i = self.idx;
|
|
- let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
|
|
- self.panic_flag = true;
|
|
- let drained = (self.pred)(&mut v[i]);
|
|
- self.panic_flag = false;
|
|
- // Update the index *after* the predicate is called. If the index
|
|
- // is updated prior and the predicate panics, the element at this
|
|
- // index would be leaked.
|
|
- self.idx += 1;
|
|
- if drained {
|
|
- self.del += 1;
|
|
- return Some(ptr::read(&v[i]));
|
|
- } else if self.del > 0 {
|
|
- let del = self.del;
|
|
- let src: *const T = &v[i];
|
|
- let dst: *mut T = &mut v[i - del];
|
|
- ptr::copy_nonoverlapping(src, dst, 1);
|
|
- }
|
|
- }
|
|
- None
|
|
- }
|
|
- }
|
|
-
|
|
- fn size_hint(&self) -> (usize, Option<usize>) {
|
|
- (0, Some(self.old_len - self.idx))
|
|
- }
|
|
-}
|
|
-
|
|
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
-impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
|
|
-where
|
|
- F: FnMut(&mut T) -> bool,
|
|
-{
|
|
- fn drop(&mut self) {
|
|
- struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
|
|
- where
|
|
- F: FnMut(&mut T) -> bool,
|
|
- {
|
|
- drain: &'b mut DrainFilter<'a, T, F, A>,
|
|
- }
|
|
-
|
|
- impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
|
|
- where
|
|
- F: FnMut(&mut T) -> bool,
|
|
- {
|
|
- fn drop(&mut self) {
|
|
- unsafe {
|
|
- if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
|
|
- // This is a pretty messed up state, and there isn't really an
|
|
- // obviously right thing to do. We don't want to keep trying
|
|
- // to execute `pred`, so we just backshift all the unprocessed
|
|
- // elements and tell the vec that they still exist. The backshift
|
|
- // is required to prevent a double-drop of the last successfully
|
|
- // drained item prior to a panic in the predicate.
|
|
- let ptr = self.drain.vec.as_mut_ptr();
|
|
- let src = ptr.add(self.drain.idx);
|
|
- let dst = src.sub(self.drain.del);
|
|
- let tail_len = self.drain.old_len - self.drain.idx;
|
|
- src.copy_to(dst, tail_len);
|
|
- }
|
|
- self.drain.vec.set_len(self.drain.old_len - self.drain.del);
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- let backshift = BackshiftOnDrop { drain: self };
|
|
-
|
|
- // Attempt to consume any remaining elements if the filter predicate
|
|
- // has not yet panicked. We'll backshift any remaining elements
|
|
- // whether we've already panicked or if the consumption here panics.
|
|
- if !backshift.drain.panic_flag {
|
|
- backshift.drain.for_each(drop);
|
|
- }
|
|
- }
|
|
-}
|
|
diff --git a/rust/alloc/vec/extract_if.rs b/rust/alloc/vec/extract_if.rs
|
|
new file mode 100644
|
|
index 0000000000000..f314a51d4d3db
|
|
--- /dev/null
|
|
+++ b/rust/alloc/vec/extract_if.rs
|
|
@@ -0,0 +1,115 @@
|
|
+// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
+
|
|
+use crate::alloc::{Allocator, Global};
|
|
+use core::ptr;
|
|
+use core::slice;
|
|
+
|
|
+use super::Vec;
|
|
+
|
|
+/// An iterator which uses a closure to determine if an element should be removed.
|
|
+///
|
|
+/// This struct is created by [`Vec::extract_if`].
|
|
+/// See its documentation for more.
|
|
+///
|
|
+/// # Example
|
|
+///
|
|
+/// ```
|
|
+/// #![feature(extract_if)]
|
|
+///
|
|
+/// let mut v = vec![0, 1, 2];
|
|
+/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
|
|
+/// ```
|
|
+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
|
+#[derive(Debug)]
|
|
+#[must_use = "iterators are lazy and do nothing unless consumed"]
|
|
+pub struct ExtractIf<
|
|
+ 'a,
|
|
+ T,
|
|
+ F,
|
|
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
|
+> where
|
|
+ F: FnMut(&mut T) -> bool,
|
|
+{
|
|
+ pub(super) vec: &'a mut Vec<T, A>,
|
|
+ /// The index of the item that will be inspected by the next call to `next`.
|
|
+ pub(super) idx: usize,
|
|
+ /// The number of items that have been drained (removed) thus far.
|
|
+ pub(super) del: usize,
|
|
+ /// The original length of `vec` prior to draining.
|
|
+ pub(super) old_len: usize,
|
|
+ /// The filter test predicate.
|
|
+ pub(super) pred: F,
|
|
+}
|
|
+
|
|
+impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
|
|
+where
|
|
+ F: FnMut(&mut T) -> bool,
|
|
+{
|
|
+ /// Returns a reference to the underlying allocator.
|
|
+ #[unstable(feature = "allocator_api", issue = "32838")]
|
|
+ #[inline]
|
|
+ pub fn allocator(&self) -> &A {
|
|
+ self.vec.allocator()
|
|
+ }
|
|
+}
|
|
+
|
|
+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
|
+impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
|
|
+where
|
|
+ F: FnMut(&mut T) -> bool,
|
|
+{
|
|
+ type Item = T;
|
|
+
|
|
+ fn next(&mut self) -> Option<T> {
|
|
+ unsafe {
|
|
+ while self.idx < self.old_len {
|
|
+ let i = self.idx;
|
|
+ let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
|
|
+ let drained = (self.pred)(&mut v[i]);
|
|
+ // Update the index *after* the predicate is called. If the index
|
|
+ // is updated prior and the predicate panics, the element at this
|
|
+ // index would be leaked.
|
|
+ self.idx += 1;
|
|
+ if drained {
|
|
+ self.del += 1;
|
|
+ return Some(ptr::read(&v[i]));
|
|
+ } else if self.del > 0 {
|
|
+ let del = self.del;
|
|
+ let src: *const T = &v[i];
|
|
+ let dst: *mut T = &mut v[i - del];
|
|
+ ptr::copy_nonoverlapping(src, dst, 1);
|
|
+ }
|
|
+ }
|
|
+ None
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fn size_hint(&self) -> (usize, Option<usize>) {
|
|
+ (0, Some(self.old_len - self.idx))
|
|
+ }
|
|
+}
|
|
+
|
|
+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
|
+impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A>
|
|
+where
|
|
+ F: FnMut(&mut T) -> bool,
|
|
+{
|
|
+ fn drop(&mut self) {
|
|
+ unsafe {
|
|
+ if self.idx < self.old_len && self.del > 0 {
|
|
+ // This is a pretty messed up state, and there isn't really an
|
|
+ // obviously right thing to do. We don't want to keep trying
|
|
+ // to execute `pred`, so we just backshift all the unprocessed
|
|
+ // elements and tell the vec that they still exist. The backshift
|
|
+ // is required to prevent a double-drop of the last successfully
|
|
+ // drained item prior to a panic in the predicate.
|
|
+ let ptr = self.vec.as_mut_ptr();
|
|
+ let src = ptr.add(self.idx);
|
|
+ let dst = src.sub(self.del);
|
|
+ let tail_len = self.old_len - self.idx;
|
|
+ src.copy_to(dst, tail_len);
|
|
+ }
|
|
+ self.vec.set_len(self.old_len - self.del);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
|
|
index 05c70de0227ed..209a88cfe598f 100644
|
|
--- a/rust/alloc/vec/mod.rs
|
|
+++ b/rust/alloc/vec/mod.rs
|
|
@@ -74,10 +74,10 @@ use crate::boxed::Box;
|
|
use crate::collections::{TryReserveError, TryReserveErrorKind};
|
|
use crate::raw_vec::RawVec;
|
|
|
|
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
-pub use self::drain_filter::DrainFilter;
|
|
+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
|
+pub use self::extract_if::ExtractIf;
|
|
|
|
-mod drain_filter;
|
|
+mod extract_if;
|
|
|
|
#[cfg(not(no_global_oom_handling))]
|
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
|
@@ -216,7 +216,7 @@ mod spec_extend;
|
|
///
|
|
/// # Indexing
|
|
///
|
|
-/// The `Vec` type allows to access values by index, because it implements the
|
|
+/// The `Vec` type allows access to values by index, because it implements the
|
|
/// [`Index`] trait. An example will be more explicit:
|
|
///
|
|
/// ```
|
|
@@ -618,22 +618,20 @@ impl<T> Vec<T> {
|
|
/// Using memory that was allocated elsewhere:
|
|
///
|
|
/// ```rust
|
|
- /// #![feature(allocator_api)]
|
|
- ///
|
|
- /// use std::alloc::{AllocError, Allocator, Global, Layout};
|
|
+ /// use std::alloc::{alloc, Layout};
|
|
///
|
|
/// fn main() {
|
|
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
|
///
|
|
/// let vec = unsafe {
|
|
- /// let mem = match Global.allocate(layout) {
|
|
- /// Ok(mem) => mem.cast::<u32>().as_ptr(),
|
|
- /// Err(AllocError) => return,
|
|
- /// };
|
|
+ /// let mem = alloc(layout).cast::<u32>();
|
|
+ /// if mem.is_null() {
|
|
+ /// return;
|
|
+ /// }
|
|
///
|
|
/// mem.write(1_000_000);
|
|
///
|
|
- /// Vec::from_raw_parts_in(mem, 1, 16, Global)
|
|
+ /// Vec::from_raw_parts(mem, 1, 16)
|
|
/// };
|
|
///
|
|
/// assert_eq!(vec, &[1_000_000]);
|
|
@@ -876,19 +874,22 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
/// Using memory that was allocated elsewhere:
|
|
///
|
|
/// ```rust
|
|
- /// use std::alloc::{alloc, Layout};
|
|
+ /// #![feature(allocator_api)]
|
|
+ ///
|
|
+ /// use std::alloc::{AllocError, Allocator, Global, Layout};
|
|
///
|
|
/// fn main() {
|
|
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
|
+ ///
|
|
/// let vec = unsafe {
|
|
- /// let mem = alloc(layout).cast::<u32>();
|
|
- /// if mem.is_null() {
|
|
- /// return;
|
|
- /// }
|
|
+ /// let mem = match Global.allocate(layout) {
|
|
+ /// Ok(mem) => mem.cast::<u32>().as_ptr(),
|
|
+ /// Err(AllocError) => return,
|
|
+ /// };
|
|
///
|
|
/// mem.write(1_000_000);
|
|
///
|
|
- /// Vec::from_raw_parts(mem, 1, 16)
|
|
+ /// Vec::from_raw_parts_in(mem, 1, 16, Global)
|
|
/// };
|
|
///
|
|
/// assert_eq!(vec, &[1_000_000]);
|
|
@@ -2507,7 +2508,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
|
|
let len = self.len();
|
|
|
|
if new_len > len {
|
|
- self.extend_with(new_len - len, ExtendElement(value))
|
|
+ self.extend_with(new_len - len, value)
|
|
} else {
|
|
self.truncate(new_len);
|
|
}
|
|
@@ -2545,7 +2546,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
|
|
let len = self.len();
|
|
|
|
if new_len > len {
|
|
- self.try_extend_with(new_len - len, ExtendElement(value))
|
|
+ self.try_extend_with(new_len - len, value)
|
|
} else {
|
|
self.truncate(new_len);
|
|
Ok(())
|
|
@@ -2684,26 +2685,10 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
|
|
}
|
|
}
|
|
|
|
-// This code generalizes `extend_with_{element,default}`.
|
|
-trait ExtendWith<T> {
|
|
- fn next(&mut self) -> T;
|
|
- fn last(self) -> T;
|
|
-}
|
|
-
|
|
-struct ExtendElement<T>(T);
|
|
-impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
|
|
- fn next(&mut self) -> T {
|
|
- self.0.clone()
|
|
- }
|
|
- fn last(self) -> T {
|
|
- self.0
|
|
- }
|
|
-}
|
|
-
|
|
-impl<T, A: Allocator> Vec<T, A> {
|
|
+impl<T: Clone, A: Allocator> Vec<T, A> {
|
|
#[cfg(not(no_global_oom_handling))]
|
|
- /// Extend the vector by `n` values, using the given generator.
|
|
- fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
|
|
+ /// Extend the vector by `n` clones of value.
|
|
+ fn extend_with(&mut self, n: usize, value: T) {
|
|
self.reserve(n);
|
|
|
|
unsafe {
|
|
@@ -2715,15 +2700,15 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
|
|
// Write all elements except the last one
|
|
for _ in 1..n {
|
|
- ptr::write(ptr, value.next());
|
|
+ ptr::write(ptr, value.clone());
|
|
ptr = ptr.add(1);
|
|
- // Increment the length in every step in case next() panics
|
|
+ // Increment the length in every step in case clone() panics
|
|
local_len.increment_len(1);
|
|
}
|
|
|
|
if n > 0 {
|
|
// We can write the last element directly without cloning needlessly
|
|
- ptr::write(ptr, value.last());
|
|
+ ptr::write(ptr, value);
|
|
local_len.increment_len(1);
|
|
}
|
|
|
|
@@ -2731,8 +2716,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
}
|
|
}
|
|
|
|
- /// Try to extend the vector by `n` values, using the given generator.
|
|
- fn try_extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) -> Result<(), TryReserveError> {
|
|
+ /// Try to extend the vector by `n` clones of value.
|
|
+ fn try_extend_with(&mut self, n: usize, value: T) -> Result<(), TryReserveError> {
|
|
self.try_reserve(n)?;
|
|
|
|
unsafe {
|
|
@@ -2744,15 +2729,15 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
|
|
// Write all elements except the last one
|
|
for _ in 1..n {
|
|
- ptr::write(ptr, value.next());
|
|
+ ptr::write(ptr, value.clone());
|
|
ptr = ptr.add(1);
|
|
- // Increment the length in every step in case next() panics
|
|
+ // Increment the length in every step in case clone() panics
|
|
local_len.increment_len(1);
|
|
}
|
|
|
|
if n > 0 {
|
|
// We can write the last element directly without cloning needlessly
|
|
- ptr::write(ptr, value.last());
|
|
+ ptr::write(ptr, value);
|
|
local_len.increment_len(1);
|
|
}
|
|
|
|
@@ -3210,6 +3195,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
|
/// by the iterator.
|
|
///
|
|
+ /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
|
+ /// or the iteration short-circuits, then the remaining elements will be retained.
|
|
+ /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
|
+ ///
|
|
+ /// [`retain`]: Vec::retain
|
|
+ ///
|
|
/// Using this method is equivalent to the following code:
|
|
///
|
|
/// ```
|
|
@@ -3228,10 +3219,10 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
/// # assert_eq!(vec, vec![1, 4, 5]);
|
|
/// ```
|
|
///
|
|
- /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
|
|
+ /// But `extract_if` is easier to use. `extract_if` is also more efficient,
|
|
/// because it can backshift the elements of the array in bulk.
|
|
///
|
|
- /// Note that `drain_filter` also lets you mutate every element in the filter closure,
|
|
+ /// Note that `extract_if` also lets you mutate every element in the filter closure,
|
|
/// regardless of whether you choose to keep or remove it.
|
|
///
|
|
/// # Examples
|
|
@@ -3239,17 +3230,17 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
/// Splitting an array into evens and odds, reusing the original allocation:
|
|
///
|
|
/// ```
|
|
- /// #![feature(drain_filter)]
|
|
+ /// #![feature(extract_if)]
|
|
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
|
|
///
|
|
- /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
|
+ /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
|
/// let odds = numbers;
|
|
///
|
|
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
|
|
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
|
|
/// ```
|
|
- #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
- pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
|
|
+ #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
|
+ pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
|
|
where
|
|
F: FnMut(&mut T) -> bool,
|
|
{
|
|
@@ -3260,7 +3251,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
self.set_len(0);
|
|
}
|
|
|
|
- DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
|
|
+ ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter }
|
|
}
|
|
}
|
|
|
|
@@ -3272,7 +3263,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|
/// [`copy_from_slice`]: slice::copy_from_slice
|
|
#[cfg(not(no_global_oom_handling))]
|
|
#[stable(feature = "extend_ref", since = "1.2.0")]
|
|
-impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
|
|
+impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> {
|
|
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
|
self.spec_extend(iter.into_iter())
|
|
}
|
|
@@ -3290,9 +3281,14 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
|
|
|
|
/// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison).
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
|
-impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
|
|
+impl<T, A1, A2> PartialOrd<Vec<T, A2>> for Vec<T, A1>
|
|
+where
|
|
+ T: PartialOrd,
|
|
+ A1: Allocator,
|
|
+ A2: Allocator,
|
|
+{
|
|
#[inline]
|
|
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
+ fn partial_cmp(&self, other: &Vec<T, A2>) -> Option<Ordering> {
|
|
PartialOrd::partial_cmp(&**self, &**other)
|
|
}
|
|
}
|
|
diff --git a/rust/alloc/vec/spec_extend.rs b/rust/alloc/vec/spec_extend.rs
|
|
index a6a735201e59b..ada9195374460 100644
|
|
--- a/rust/alloc/vec/spec_extend.rs
|
|
+++ b/rust/alloc/vec/spec_extend.rs
|
|
@@ -77,7 +77,7 @@ impl<T, A: Allocator> TrySpecExtend<T, IntoIter<T>> for Vec<T, A> {
|
|
}
|
|
|
|
#[cfg(not(no_global_oom_handling))]
|
|
-impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
|
|
+impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec<T, A>
|
|
where
|
|
I: Iterator<Item = &'a T>,
|
|
T: Clone,
|
|
@@ -87,7 +87,7 @@ where
|
|
}
|
|
}
|
|
|
|
-impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A>
|
|
+impl<'a, T: 'a, I, A: Allocator> TrySpecExtend<&'a T, I> for Vec<T, A>
|
|
where
|
|
I: Iterator<Item = &'a T>,
|
|
T: Clone,
|
|
@@ -98,7 +98,7 @@ where
|
|
}
|
|
|
|
#[cfg(not(no_global_oom_handling))]
|
|
-impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
|
+impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
|
where
|
|
T: Copy,
|
|
{
|
|
@@ -108,7 +108,7 @@ where
|
|
}
|
|
}
|
|
|
|
-impl<'a, T: 'a, A: Allocator + 'a> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
|
+impl<'a, T: 'a, A: Allocator> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
|
where
|
|
T: Copy,
|
|
{
|
|
diff --git a/rust/compiler_builtins.rs b/rust/compiler_builtins.rs
|
|
index fb8ac3f211de5..bba2922c6ef77 100644
|
|
--- a/rust/compiler_builtins.rs
|
|
+++ b/rust/compiler_builtins.rs
|
|
@@ -19,6 +19,7 @@
|
|
//! [`compiler_builtins`]: https://github.com/rust-lang/compiler-builtins
|
|
//! [`compiler-rt`]: https://compiler-rt.llvm.org/
|
|
|
|
+#![allow(internal_features)]
|
|
#![feature(compiler_builtins)]
|
|
#![compiler_builtins]
|
|
#![no_builtins]
|
|
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
|
|
index 8009184bf6d76..f48926e3e9fe3 100644
|
|
--- a/rust/kernel/print.rs
|
|
+++ b/rust/kernel/print.rs
|
|
@@ -399,6 +399,7 @@ macro_rules! pr_debug (
|
|
/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
|
|
/// `alloc::format!` for information about the formatting syntax.
|
|
///
|
|
+/// [`pr_info!`]: crate::pr_info!
|
|
/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
|
|
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
|
|
///
|
|
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
|
|
index 3d496391a9bd8..7f04e4f00a2c7 100644
|
|
--- a/rust/kernel/sync/arc.rs
|
|
+++ b/rust/kernel/sync/arc.rs
|
|
@@ -302,7 +302,7 @@ impl<T: ?Sized> Drop for Arc<T> {
|
|
// The count reached zero, we must free the memory.
|
|
//
|
|
// SAFETY: The pointer was initialised from the result of `Box::leak`.
|
|
- unsafe { Box::from_raw(self.ptr.as_ptr()) };
|
|
+ unsafe { drop(Box::from_raw(self.ptr.as_ptr())) };
|
|
}
|
|
}
|
|
}
|
|
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
|
|
index 7eda15e5f1b37..b2299bc7ac1ff 100644
|
|
--- a/rust/kernel/task.rs
|
|
+++ b/rust/kernel/task.rs
|
|
@@ -82,7 +82,7 @@ impl Task {
|
|
/// Returns a task reference for the currently executing task/thread.
|
|
///
|
|
/// The recommended way to get the current task/thread is to use the
|
|
- /// [`current`](crate::current) macro because it is safe.
|
|
+ /// [`current`] macro because it is safe.
|
|
///
|
|
/// # Safety
|
|
///
|
|
diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
|
|
index d65ab8bfeaf4b..fd5ffdb81bab7 100755
|
|
--- a/scripts/min-tool-version.sh
|
|
+++ b/scripts/min-tool-version.sh
|
|
@@ -31,7 +31,7 @@ llvm)
|
|
fi
|
|
;;
|
|
rustc)
|
|
- echo 1.71.1
|
|
+ echo 1.73.0
|
|
;;
|
|
bindgen)
|
|
echo 0.65.1
|
|
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
|
|
index 955145448c23b..f27c275800091 100644
|
|
--- a/sound/soc/amd/acp-config.c
|
|
+++ b/sound/soc/amd/acp-config.c
|
|
@@ -3,7 +3,7 @@
|
|
// This file is provided under a dual BSD/GPLv2 license. When using or
|
|
// redistributing this file, you may do so under either license.
|
|
//
|
|
-// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
|
|
+// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
|
//
|
|
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
|
//
|
|
@@ -47,19 +47,6 @@ static const struct config_entry config_table[] = {
|
|
{}
|
|
},
|
|
},
|
|
- {
|
|
- .flags = FLAG_AMD_LEGACY,
|
|
- .device = ACP_PCI_DEV_ID,
|
|
- .dmi_table = (const struct dmi_system_id []) {
|
|
- {
|
|
- .matches = {
|
|
- DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
|
|
- DMI_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
|
|
- },
|
|
- },
|
|
- {}
|
|
- },
|
|
- },
|
|
{
|
|
.flags = FLAG_AMD_SOF,
|
|
.device = ACP_PCI_DEV_ID,
|
|
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
|
|
index 07cc6a201579a..09712e61c606e 100644
|
|
--- a/sound/usb/quirks.c
|
|
+++ b/sound/usb/quirks.c
|
|
@@ -2031,10 +2031,14 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
|
|
DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */
|
|
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
+ DEVICE_FLG(0x0499, 0x3108, /* Yamaha YIT-W12TX */
|
|
+ QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
DEVICE_FLG(0x04d8, 0xfeea, /* Benchmark DAC1 Pre */
|
|
QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
DEVICE_FLG(0x04e8, 0xa051, /* Samsung USBC Headset (AKG) */
|
|
QUIRK_FLAG_SKIP_CLOCK_SELECTOR | QUIRK_FLAG_CTL_MSG_DELAY_5M),
|
|
+ DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
|
|
+ QUIRK_FLAG_IFACE_SKIP_CLOSE),
|
|
DEVICE_FLG(0x054c, 0x0b8c, /* Sony WALKMAN NW-A45 DAC */
|
|
QUIRK_FLAG_SET_IFACE_FIRST),
|
|
DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */
|
|
@@ -2073,14 +2077,22 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
DEVICE_FLG(0x0763, 0x2031, /* M-Audio Fast Track C600 */
|
|
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
+ DEVICE_FLG(0x07fd, 0x000b, /* MOTU M Series 2nd hardware revision */
|
|
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
|
|
DEVICE_FLG(0x08bb, 0x2702, /* LineX FM Transmitter */
|
|
QUIRK_FLAG_IGNORE_CTL_ERROR),
|
|
DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
|
|
QUIRK_FLAG_CTL_MSG_DELAY_1M),
|
|
DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
|
|
QUIRK_FLAG_CTL_MSG_DELAY_1M),
|
|
+ DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
|
|
+ QUIRK_FLAG_FIXED_RATE),
|
|
+ DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
|
|
+ QUIRK_FLAG_FIXED_RATE),
|
|
DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */
|
|
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
|
|
+ DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
|
|
+ QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
|
|
QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */
|
|
@@ -2113,6 +2125,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
|
|
DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */
|
|
QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
+ DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */
|
|
+ QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
+ DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
|
|
+ QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
|
|
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
|
|
DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */
|
|
@@ -2155,6 +2171,12 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
QUIRK_FLAG_IGNORE_CTL_ERROR),
|
|
DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
|
|
QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
+ DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
|
|
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
+ DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
|
|
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
+ DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
|
|
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */
|
|
QUIRK_FLAG_IGNORE_CTL_ERROR),
|
|
DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
|
|
@@ -2163,22 +2185,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
QUIRK_FLAG_ALIGN_TRANSFER),
|
|
DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
|
|
QUIRK_FLAG_ALIGN_TRANSFER),
|
|
- DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
|
|
- QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
- DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
|
|
- QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
- DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
|
|
- QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
- DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
|
|
- QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
|
- DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
|
|
- QUIRK_FLAG_IFACE_SKIP_CLOSE),
|
|
- DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
|
|
- QUIRK_FLAG_FIXED_RATE),
|
|
- DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
|
|
- QUIRK_FLAG_FIXED_RATE),
|
|
- DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
|
|
- QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
|
|
/* Vendor matches */
|
|
VENDOR_FLG(0x045e, /* MS Lifecam */
|
|
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
|
|
index c779b9f2e6220..8a8fe1fa0d386 100644
|
|
--- a/tools/perf/util/evlist.c
|
|
+++ b/tools/perf/util/evlist.c
|
|
@@ -103,7 +103,14 @@ struct evlist *evlist__new_default(void)
|
|
err = parse_event(evlist, can_profile_kernel ? "cycles:P" : "cycles:Pu");
|
|
if (err) {
|
|
evlist__delete(evlist);
|
|
- evlist = NULL;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (evlist->core.nr_entries > 1) {
|
|
+ struct evsel *evsel;
|
|
+
|
|
+ evlist__for_each_entry(evlist, evsel)
|
|
+ evsel__set_sample_id(evsel, /*can_sample_identifier=*/false);
|
|
}
|
|
|
|
return evlist;
|
|
diff --git a/tools/testing/selftests/net/big_tcp.sh b/tools/testing/selftests/net/big_tcp.sh
|
|
index cde9a91c47971..2db9d15cd45fe 100755
|
|
--- a/tools/testing/selftests/net/big_tcp.sh
|
|
+++ b/tools/testing/selftests/net/big_tcp.sh
|
|
@@ -122,7 +122,9 @@ do_netperf() {
|
|
local netns=$1
|
|
|
|
[ "$NF" = "6" ] && serip=$SERVER_IP6
|
|
- ip net exec $netns netperf -$NF -t TCP_STREAM -H $serip 2>&1 >/dev/null
|
|
+
|
|
+ # use large write to be sure to generate big tcp packets
|
|
+ ip net exec $netns netperf -$NF -t TCP_STREAM -l 1 -H $serip -- -m 262144 2>&1 >/dev/null
|
|
}
|
|
|
|
do_test() {
|
|
diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh
|
|
index 330d0b1ceced3..c921750ca118d 100755
|
|
--- a/tools/testing/selftests/net/cmsg_ipv6.sh
|
|
+++ b/tools/testing/selftests/net/cmsg_ipv6.sh
|
|
@@ -91,7 +91,7 @@ for ovr in setsock cmsg both diff; do
|
|
check_result $? 0 "TCLASS $prot $ovr - pass"
|
|
|
|
while [ -d /proc/$BG ]; do
|
|
- $NSEXE ./cmsg_sender -6 -p u $TGT6 1234
|
|
+ $NSEXE ./cmsg_sender -6 -p $p $m $((TOS2)) $TGT6 1234
|
|
done
|
|
|
|
tcpdump -r $TMPF -v 2>&1 | grep "class $TOS2" >> /dev/null
|
|
@@ -128,7 +128,7 @@ for ovr in setsock cmsg both diff; do
|
|
check_result $? 0 "HOPLIMIT $prot $ovr - pass"
|
|
|
|
while [ -d /proc/$BG ]; do
|
|
- $NSEXE ./cmsg_sender -6 -p u $TGT6 1234
|
|
+ $NSEXE ./cmsg_sender -6 -p $p $m $LIM $TGT6 1234
|
|
done
|
|
|
|
tcpdump -r $TMPF -v 2>&1 | grep "hlim $LIM[^0-9]" >> /dev/null
|
|
diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh
|
|
index 4a5f031be2324..d65fdd407d73f 100755
|
|
--- a/tools/testing/selftests/net/pmtu.sh
|
|
+++ b/tools/testing/selftests/net/pmtu.sh
|
|
@@ -1,4 +1,4 @@
|
|
-#!/bin/sh
|
|
+#!/bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# Check that route PMTU values match expectations, and that initial device MTU
|
|
@@ -198,8 +198,8 @@
|
|
# - pmtu_ipv6_route_change
|
|
# Same as above but with IPv6
|
|
|
|
-# Kselftest framework requirement - SKIP code is 4.
|
|
-ksft_skip=4
|
|
+source lib.sh
|
|
+source net_helper.sh
|
|
|
|
PAUSE_ON_FAIL=no
|
|
VERBOSE=0
|
|
@@ -268,16 +268,6 @@ tests="
|
|
pmtu_ipv4_route_change ipv4: PMTU exception w/route replace 1
|
|
pmtu_ipv6_route_change ipv6: PMTU exception w/route replace 1"
|
|
|
|
-NS_A="ns-A"
|
|
-NS_B="ns-B"
|
|
-NS_C="ns-C"
|
|
-NS_R1="ns-R1"
|
|
-NS_R2="ns-R2"
|
|
-ns_a="ip netns exec ${NS_A}"
|
|
-ns_b="ip netns exec ${NS_B}"
|
|
-ns_c="ip netns exec ${NS_C}"
|
|
-ns_r1="ip netns exec ${NS_R1}"
|
|
-ns_r2="ip netns exec ${NS_R2}"
|
|
# Addressing and routing for tests with routers: four network segments, with
|
|
# index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an
|
|
# identifier ID, which is 1 for hosts (A and B), 2 for routers (R1 and R2).
|
|
@@ -543,13 +533,17 @@ setup_ip6ip6() {
|
|
}
|
|
|
|
setup_namespaces() {
|
|
+ setup_ns NS_A NS_B NS_C NS_R1 NS_R2
|
|
for n in ${NS_A} ${NS_B} ${NS_C} ${NS_R1} ${NS_R2}; do
|
|
- ip netns add ${n} || return 1
|
|
-
|
|
# Disable DAD, so that we don't have to wait to use the
|
|
# configured IPv6 addresses
|
|
ip netns exec ${n} sysctl -q net/ipv6/conf/default/accept_dad=0
|
|
done
|
|
+ ns_a="ip netns exec ${NS_A}"
|
|
+ ns_b="ip netns exec ${NS_B}"
|
|
+ ns_c="ip netns exec ${NS_C}"
|
|
+ ns_r1="ip netns exec ${NS_R1}"
|
|
+ ns_r2="ip netns exec ${NS_R2}"
|
|
}
|
|
|
|
setup_veth() {
|
|
@@ -839,7 +833,7 @@ setup_bridge() {
|
|
run_cmd ${ns_a} ip link set br0 up
|
|
|
|
run_cmd ${ns_c} ip link add veth_C-A type veth peer name veth_A-C
|
|
- run_cmd ${ns_c} ip link set veth_A-C netns ns-A
|
|
+ run_cmd ${ns_c} ip link set veth_A-C netns ${NS_A}
|
|
|
|
run_cmd ${ns_a} ip link set veth_A-C up
|
|
run_cmd ${ns_c} ip link set veth_C-A up
|
|
@@ -944,9 +938,7 @@ cleanup() {
|
|
done
|
|
socat_pids=
|
|
|
|
- for n in ${NS_A} ${NS_B} ${NS_C} ${NS_R1} ${NS_R2}; do
|
|
- ip netns del ${n} 2> /dev/null
|
|
- done
|
|
+ cleanup_all_ns
|
|
|
|
ip link del veth_A-C 2>/dev/null
|
|
ip link del veth_A-R1 2>/dev/null
|
|
@@ -1345,13 +1337,15 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_geneveY_exception() {
|
|
TCPDST="TCP:[${dst}]:50000"
|
|
fi
|
|
${ns_b} socat -T 3 -u -6 TCP-LISTEN:50000 STDOUT > $tmpoutfile &
|
|
+ local socat_pid=$!
|
|
|
|
- sleep 1
|
|
+ wait_local_port_listen ${NS_B} 50000 tcp
|
|
|
|
dd if=/dev/zero status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3
|
|
|
|
size=$(du -sb $tmpoutfile)
|
|
size=${size%%/tmp/*}
|
|
+ wait ${socat_pid}
|
|
|
|
[ $size -ne 1048576 ] && err "File size $size mismatches exepcted value in locally bridged vxlan test" && return 1
|
|
done
|
|
@@ -1963,6 +1957,13 @@ check_command() {
|
|
return 0
|
|
}
|
|
|
|
+check_running() {
|
|
+ pid=${1}
|
|
+ cmd=${2}
|
|
+
|
|
+ [ "$(cat /proc/${pid}/cmdline 2>/dev/null | tr -d '\0')" = "{cmd}" ]
|
|
+}
|
|
+
|
|
test_cleanup_vxlanX_exception() {
|
|
outer="${1}"
|
|
encap="vxlan"
|
|
@@ -1993,11 +1994,12 @@ test_cleanup_vxlanX_exception() {
|
|
|
|
${ns_a} ip link del dev veth_A-R1 &
|
|
iplink_pid=$!
|
|
- sleep 1
|
|
- if [ "$(cat /proc/${iplink_pid}/cmdline 2>/dev/null | tr -d '\0')" = "iplinkdeldevveth_A-R1" ]; then
|
|
- err " can't delete veth device in a timely manner, PMTU dst likely leaked"
|
|
- return 1
|
|
- fi
|
|
+ for i in $(seq 1 20); do
|
|
+ check_running ${iplink_pid} "iplinkdeldevveth_A-R1" || return 0
|
|
+ sleep 0.1
|
|
+ done
|
|
+ err " can't delete veth device in a timely manner, PMTU dst likely leaked"
|
|
+ return 1
|
|
}
|
|
|
|
test_cleanup_ipv6_exception() {
|
|
diff --git a/tools/testing/selftests/net/udpgro_fwd.sh b/tools/testing/selftests/net/udpgro_fwd.sh
|
|
index d6b9c759043ca..9cd5e885e91f7 100755
|
|
--- a/tools/testing/selftests/net/udpgro_fwd.sh
|
|
+++ b/tools/testing/selftests/net/udpgro_fwd.sh
|
|
@@ -39,6 +39,10 @@ create_ns() {
|
|
for ns in $NS_SRC $NS_DST; do
|
|
ip netns add $ns
|
|
ip -n $ns link set dev lo up
|
|
+
|
|
+ # disable route solicitations to decrease 'noise' traffic
|
|
+ ip netns exec $ns sysctl -qw net.ipv6.conf.default.router_solicitations=0
|
|
+ ip netns exec $ns sysctl -qw net.ipv6.conf.all.router_solicitations=0
|
|
done
|
|
|
|
ip link add name veth$SRC type veth peer name veth$DST
|
|
@@ -80,6 +84,12 @@ create_vxlan_pair() {
|
|
create_vxlan_endpoint $BASE$ns veth$ns $BM_NET_V6$((3 - $ns)) vxlan6$ns 6
|
|
ip -n $BASE$ns addr add dev vxlan6$ns $OL_NET_V6$ns/24 nodad
|
|
done
|
|
+
|
|
+ # preload neighbur cache, do avoid some noisy traffic
|
|
+ local addr_dst=$(ip -j -n $BASE$DST link show dev vxlan6$DST |jq -r '.[]["address"]')
|
|
+ local addr_src=$(ip -j -n $BASE$SRC link show dev vxlan6$SRC |jq -r '.[]["address"]')
|
|
+ ip -n $BASE$DST neigh add dev vxlan6$DST lladdr $addr_src $OL_NET_V6$SRC
|
|
+ ip -n $BASE$SRC neigh add dev vxlan6$SRC lladdr $addr_dst $OL_NET_V6$DST
|
|
}
|
|
|
|
is_ipv6() {
|
|
@@ -119,7 +129,7 @@ run_test() {
|
|
# not enable GRO
|
|
ip netns exec $NS_DST $ipt -A INPUT -p udp --dport 4789
|
|
ip netns exec $NS_DST $ipt -A INPUT -p udp --dport 8000
|
|
- ip netns exec $NS_DST ./udpgso_bench_rx -C 1000 -R 10 -n 10 -l 1300 $rx_args &
|
|
+ ip netns exec $NS_DST ./udpgso_bench_rx -C 2000 -R 100 -n 10 -l 1300 $rx_args &
|
|
local spid=$!
|
|
wait_local_port_listen "$NS_DST" 8000 udp
|
|
ip netns exec $NS_SRC ./udpgso_bench_tx $family -M 1 -s 13000 -S 1300 -D $dst
|
|
@@ -168,7 +178,7 @@ run_bench() {
|
|
# bind the sender and the receiver to different CPUs to try
|
|
# get reproducible results
|
|
ip netns exec $NS_DST bash -c "echo 2 > /sys/class/net/veth$DST/queues/rx-0/rps_cpus"
|
|
- ip netns exec $NS_DST taskset 0x2 ./udpgso_bench_rx -C 1000 -R 10 &
|
|
+ ip netns exec $NS_DST taskset 0x2 ./udpgso_bench_rx -C 2000 -R 100 &
|
|
local spid=$!
|
|
wait_local_port_listen "$NS_DST" 8000 udp
|
|
ip netns exec $NS_SRC taskset 0x1 ./udpgso_bench_tx $family -l 3 -S 1300 -D $dst
|
|
diff --git a/tools/testing/selftests/net/udpgso_bench_rx.c b/tools/testing/selftests/net/udpgso_bench_rx.c
|
|
index f35a924d4a303..1cbadd267c963 100644
|
|
--- a/tools/testing/selftests/net/udpgso_bench_rx.c
|
|
+++ b/tools/testing/selftests/net/udpgso_bench_rx.c
|
|
@@ -375,7 +375,7 @@ static void do_recv(void)
|
|
do_flush_udp(fd);
|
|
|
|
tnow = gettimeofday_ms();
|
|
- if (tnow > treport) {
|
|
+ if (!cfg_expected_pkt_nr && tnow > treport) {
|
|
if (packets)
|
|
fprintf(stderr,
|
|
"%s rx: %6lu MB/s %8lu calls/s\n",
|
|
diff --git a/tools/testing/selftests/net/unicast_extensions.sh b/tools/testing/selftests/net/unicast_extensions.sh
|
|
index 2d10ccac898a7..f52aa5f7da524 100755
|
|
--- a/tools/testing/selftests/net/unicast_extensions.sh
|
|
+++ b/tools/testing/selftests/net/unicast_extensions.sh
|
|
@@ -1,4 +1,4 @@
|
|
-#!/bin/sh
|
|
+#!/bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# By Seth Schoen (c) 2021, for the IPv4 Unicast Extensions Project
|
|
@@ -28,8 +28,7 @@
|
|
# These tests provide an easy way to flip the expected result of any
|
|
# of these behaviors for testing kernel patches that change them.
|
|
|
|
-# Kselftest framework requirement - SKIP code is 4.
|
|
-ksft_skip=4
|
|
+source lib.sh
|
|
|
|
# nettest can be run from PATH or from same directory as this selftest
|
|
if ! which nettest >/dev/null; then
|
|
@@ -61,20 +60,20 @@ _do_segmenttest(){
|
|
# foo --- bar
|
|
# Arguments: ip_a ip_b prefix_length test_description
|
|
#
|
|
- # Caller must set up foo-ns and bar-ns namespaces
|
|
+ # Caller must set up $foo_ns and $bar_ns namespaces
|
|
# containing linked veth devices foo and bar,
|
|
# respectively.
|
|
|
|
- ip -n foo-ns address add $1/$3 dev foo || return 1
|
|
- ip -n foo-ns link set foo up || return 1
|
|
- ip -n bar-ns address add $2/$3 dev bar || return 1
|
|
- ip -n bar-ns link set bar up || return 1
|
|
+ ip -n $foo_ns address add $1/$3 dev foo || return 1
|
|
+ ip -n $foo_ns link set foo up || return 1
|
|
+ ip -n $bar_ns address add $2/$3 dev bar || return 1
|
|
+ ip -n $bar_ns link set bar up || return 1
|
|
|
|
- ip netns exec foo-ns timeout 2 ping -c 1 $2 || return 1
|
|
- ip netns exec bar-ns timeout 2 ping -c 1 $1 || return 1
|
|
+ ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1
|
|
+ ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1
|
|
|
|
- nettest -B -N bar-ns -O foo-ns -r $1 || return 1
|
|
- nettest -B -N foo-ns -O bar-ns -r $2 || return 1
|
|
+ nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1
|
|
+ nettest -B -N $foo_ns -O $bar_ns -r $2 || return 1
|
|
|
|
return 0
|
|
}
|
|
@@ -88,31 +87,31 @@ _do_route_test(){
|
|
# Arguments: foo_ip foo1_ip bar1_ip bar_ip prefix_len test_description
|
|
# Displays test result and returns success or failure.
|
|
|
|
- # Caller must set up foo-ns, bar-ns, and router-ns
|
|
+ # Caller must set up $foo_ns, $bar_ns, and $router_ns
|
|
# containing linked veth devices foo-foo1, bar1-bar
|
|
- # (foo in foo-ns, foo1 and bar1 in router-ns, and
|
|
- # bar in bar-ns).
|
|
-
|
|
- ip -n foo-ns address add $1/$5 dev foo || return 1
|
|
- ip -n foo-ns link set foo up || return 1
|
|
- ip -n foo-ns route add default via $2 || return 1
|
|
- ip -n bar-ns address add $4/$5 dev bar || return 1
|
|
- ip -n bar-ns link set bar up || return 1
|
|
- ip -n bar-ns route add default via $3 || return 1
|
|
- ip -n router-ns address add $2/$5 dev foo1 || return 1
|
|
- ip -n router-ns link set foo1 up || return 1
|
|
- ip -n router-ns address add $3/$5 dev bar1 || return 1
|
|
- ip -n router-ns link set bar1 up || return 1
|
|
-
|
|
- echo 1 | ip netns exec router-ns tee /proc/sys/net/ipv4/ip_forward
|
|
-
|
|
- ip netns exec foo-ns timeout 2 ping -c 1 $2 || return 1
|
|
- ip netns exec foo-ns timeout 2 ping -c 1 $4 || return 1
|
|
- ip netns exec bar-ns timeout 2 ping -c 1 $3 || return 1
|
|
- ip netns exec bar-ns timeout 2 ping -c 1 $1 || return 1
|
|
-
|
|
- nettest -B -N bar-ns -O foo-ns -r $1 || return 1
|
|
- nettest -B -N foo-ns -O bar-ns -r $4 || return 1
|
|
+ # (foo in $foo_ns, foo1 and bar1 in $router_ns, and
|
|
+ # bar in $bar_ns).
|
|
+
|
|
+ ip -n $foo_ns address add $1/$5 dev foo || return 1
|
|
+ ip -n $foo_ns link set foo up || return 1
|
|
+ ip -n $foo_ns route add default via $2 || return 1
|
|
+ ip -n $bar_ns address add $4/$5 dev bar || return 1
|
|
+ ip -n $bar_ns link set bar up || return 1
|
|
+ ip -n $bar_ns route add default via $3 || return 1
|
|
+ ip -n $router_ns address add $2/$5 dev foo1 || return 1
|
|
+ ip -n $router_ns link set foo1 up || return 1
|
|
+ ip -n $router_ns address add $3/$5 dev bar1 || return 1
|
|
+ ip -n $router_ns link set bar1 up || return 1
|
|
+
|
|
+ echo 1 | ip netns exec $router_ns tee /proc/sys/net/ipv4/ip_forward
|
|
+
|
|
+ ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1
|
|
+ ip netns exec $foo_ns timeout 2 ping -c 1 $4 || return 1
|
|
+ ip netns exec $bar_ns timeout 2 ping -c 1 $3 || return 1
|
|
+ ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1
|
|
+
|
|
+ nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1
|
|
+ nettest -B -N $foo_ns -O $bar_ns -r $4 || return 1
|
|
|
|
return 0
|
|
}
|
|
@@ -121,17 +120,15 @@ segmenttest(){
|
|
# Sets up veth link and tries to connect over it.
|
|
# Arguments: ip_a ip_b prefix_len test_description
|
|
hide_output
|
|
- ip netns add foo-ns
|
|
- ip netns add bar-ns
|
|
- ip link add foo netns foo-ns type veth peer name bar netns bar-ns
|
|
+ setup_ns foo_ns bar_ns
|
|
+ ip link add foo netns $foo_ns type veth peer name bar netns $bar_ns
|
|
|
|
test_result=0
|
|
_do_segmenttest "$@" || test_result=1
|
|
|
|
- ip netns pids foo-ns | xargs -r kill -9
|
|
- ip netns pids bar-ns | xargs -r kill -9
|
|
- ip netns del foo-ns
|
|
- ip netns del bar-ns
|
|
+ ip netns pids $foo_ns | xargs -r kill -9
|
|
+ ip netns pids $bar_ns | xargs -r kill -9
|
|
+ cleanup_ns $foo_ns $bar_ns
|
|
show_output
|
|
|
|
# inverted tests will expect failure instead of success
|
|
@@ -147,21 +144,17 @@ route_test(){
|
|
# Returns success or failure.
|
|
|
|
hide_output
|
|
- ip netns add foo-ns
|
|
- ip netns add bar-ns
|
|
- ip netns add router-ns
|
|
- ip link add foo netns foo-ns type veth peer name foo1 netns router-ns
|
|
- ip link add bar netns bar-ns type veth peer name bar1 netns router-ns
|
|
+ setup_ns foo_ns bar_ns router_ns
|
|
+ ip link add foo netns $foo_ns type veth peer name foo1 netns $router_ns
|
|
+ ip link add bar netns $bar_ns type veth peer name bar1 netns $router_ns
|
|
|
|
test_result=0
|
|
_do_route_test "$@" || test_result=1
|
|
|
|
- ip netns pids foo-ns | xargs -r kill -9
|
|
- ip netns pids bar-ns | xargs -r kill -9
|
|
- ip netns pids router-ns | xargs -r kill -9
|
|
- ip netns del foo-ns
|
|
- ip netns del bar-ns
|
|
- ip netns del router-ns
|
|
+ ip netns pids $foo_ns | xargs -r kill -9
|
|
+ ip netns pids $bar_ns | xargs -r kill -9
|
|
+ ip netns pids $router_ns | xargs -r kill -9
|
|
+ cleanup_ns $foo_ns $bar_ns $router_ns
|
|
|
|
show_output
|
|
|