mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
Merge branch 'android-4.9' into amlogic-4.9-dev
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 9
|
||||
SUBLEVEL = 46
|
||||
SUBLEVEL = 50
|
||||
EXTRAVERSION =
|
||||
NAME = Roaring Lionus
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifndef _ALPHA_TYPES_H
|
||||
#define _ALPHA_TYPES_H
|
||||
|
||||
#include <asm-generic/int-ll64.h>
|
||||
#include <uapi/asm/types.h>
|
||||
|
||||
#endif /* _ALPHA_TYPES_H */
|
||||
|
||||
@@ -9,8 +9,18 @@
|
||||
* need to be careful to avoid a name clashes.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL__
|
||||
/*
|
||||
* This is here because we used to use l64 for alpha
|
||||
* and we don't want to impact user mode with our change to ll64
|
||||
* in the kernel.
|
||||
*
|
||||
* However, some user programs are fine with this. They can
|
||||
* flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here.
|
||||
*/
|
||||
#if !defined(__SANE_USERSPACE_TYPES__) && !defined(__KERNEL__)
|
||||
#include <asm-generic/int-l64.h>
|
||||
#else
|
||||
#include <asm-generic/int-ll64.h>
|
||||
#endif
|
||||
|
||||
#endif /* _UAPI_ALPHA_TYPES_H */
|
||||
|
||||
@@ -829,22 +829,22 @@ void stage2_unmap_vm(struct kvm *kvm)
|
||||
* Walks the level-1 page table pointed to by kvm->arch.pgd and frees all
|
||||
* underlying level-2 and level-3 tables before freeing the actual level-1 table
|
||||
* and setting the struct pointer to NULL.
|
||||
*
|
||||
* Note we don't need locking here as this is only called when the VM is
|
||||
* destroyed, which can only be done once.
|
||||
*/
|
||||
void kvm_free_stage2_pgd(struct kvm *kvm)
|
||||
{
|
||||
if (kvm->arch.pgd == NULL)
|
||||
return;
|
||||
void *pgd = NULL;
|
||||
|
||||
spin_lock(&kvm->mmu_lock);
|
||||
unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
|
||||
if (kvm->arch.pgd) {
|
||||
unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
|
||||
pgd = READ_ONCE(kvm->arch.pgd);
|
||||
kvm->arch.pgd = NULL;
|
||||
}
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
|
||||
/* Free the HW pgd, one page at a time */
|
||||
free_pages_exact(kvm->arch.pgd, S2_PGD_SIZE);
|
||||
kvm->arch.pgd = NULL;
|
||||
if (pgd)
|
||||
free_pages_exact(pgd, S2_PGD_SIZE);
|
||||
}
|
||||
|
||||
static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
|
||||
|
||||
@@ -314,8 +314,11 @@ retry:
|
||||
* signal first. We do not need to release the mmap_sem because
|
||||
* it would already be released in __lock_page_or_retry in
|
||||
* mm/filemap.c. */
|
||||
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
|
||||
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Major/minor page fault accounting is only done on the
|
||||
|
||||
@@ -170,6 +170,7 @@
|
||||
interrupt-controller;
|
||||
reg = <0x1d00000 0x10000>, /* GICD */
|
||||
<0x1d40000 0x40000>; /* GICR */
|
||||
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -157,9 +157,11 @@ void fpsimd_thread_switch(struct task_struct *next)
|
||||
|
||||
void fpsimd_flush_thread(void)
|
||||
{
|
||||
preempt_disable();
|
||||
memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
|
||||
fpsimd_flush_task_state(current);
|
||||
set_thread_flag(TIF_FOREIGN_FPSTATE);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -379,8 +379,11 @@ retry:
|
||||
* signal first. We do not need to release the mmap_sem because it
|
||||
* would already be released in __lock_page_or_retry in mm/filemap.c.
|
||||
*/
|
||||
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
|
||||
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Major/minor page fault accounting is only done on the initial
|
||||
|
||||
@@ -480,7 +480,7 @@ static inline int mm_alloc_pgste(struct mm_struct *mm)
|
||||
* In the case that a guest uses storage keys
|
||||
* faults should no longer be backed by zero pages
|
||||
*/
|
||||
#define mm_forbids_zeropage mm_use_skey
|
||||
#define mm_forbids_zeropage mm_has_pgste
|
||||
static inline int mm_use_skey(struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_PGSTE
|
||||
|
||||
@@ -2124,6 +2124,37 @@ static inline void thp_split_mm(struct mm_struct *mm)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove all empty zero pages from the mapping for lazy refaulting
|
||||
* - This must be called after mm->context.has_pgste is set, to avoid
|
||||
* future creation of zero pages
|
||||
* - This must be called after THP was enabled
|
||||
*/
|
||||
static int __zap_zero_pages(pmd_t *pmd, unsigned long start,
|
||||
unsigned long end, struct mm_walk *walk)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
for (addr = start; addr != end; addr += PAGE_SIZE) {
|
||||
pte_t *ptep;
|
||||
spinlock_t *ptl;
|
||||
|
||||
ptep = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
|
||||
if (is_zero_pfn(pte_pfn(*ptep)))
|
||||
ptep_xchg_direct(walk->mm, addr, ptep, __pte(_PAGE_INVALID));
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void zap_zero_pages(struct mm_struct *mm)
|
||||
{
|
||||
struct mm_walk walk = { .pmd_entry = __zap_zero_pages };
|
||||
|
||||
walk.mm = mm;
|
||||
walk_page_range(0, TASK_SIZE, &walk);
|
||||
}
|
||||
|
||||
/*
|
||||
* switch on pgstes for its userspace process (for kvm)
|
||||
*/
|
||||
@@ -2141,6 +2172,7 @@ int s390_enable_sie(void)
|
||||
mm->context.has_pgste = 1;
|
||||
/* split thp mappings and disable thp for future mappings */
|
||||
thp_split_mm(mm);
|
||||
zap_zero_pages(mm);
|
||||
up_write(&mm->mmap_sem);
|
||||
return 0;
|
||||
}
|
||||
@@ -2153,13 +2185,6 @@ EXPORT_SYMBOL_GPL(s390_enable_sie);
|
||||
static int __s390_enable_skey(pte_t *pte, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk)
|
||||
{
|
||||
/*
|
||||
* Remove all zero page mappings,
|
||||
* after establishing a policy to forbid zero page mappings
|
||||
* following faults for that page will get fresh anonymous pages
|
||||
*/
|
||||
if (is_zero_pfn(pte_pfn(*pte)))
|
||||
ptep_xchg_direct(walk->mm, addr, pte, __pte(_PAGE_INVALID));
|
||||
/* Clear storage key */
|
||||
ptep_zap_key(walk->mm, addr, pte);
|
||||
return 0;
|
||||
|
||||
@@ -304,13 +304,13 @@ static inline unsigned type in##bwl##_p(int port) \
|
||||
static inline void outs##bwl(int port, const void *addr, unsigned long count) \
|
||||
{ \
|
||||
asm volatile("rep; outs" #bwl \
|
||||
: "+S"(addr), "+c"(count) : "d"(port)); \
|
||||
: "+S"(addr), "+c"(count) : "d"(port) : "memory"); \
|
||||
} \
|
||||
\
|
||||
static inline void ins##bwl(int port, void *addr, unsigned long count) \
|
||||
{ \
|
||||
asm volatile("rep; ins" #bwl \
|
||||
: "+D"(addr), "+c"(count) : "d"(port)); \
|
||||
: "+D"(addr), "+c"(count) : "d"(port) : "memory"); \
|
||||
}
|
||||
|
||||
BUILDIO(b, b, char)
|
||||
|
||||
@@ -86,8 +86,13 @@ static void skcipher_free_async_sgls(struct skcipher_async_req *sreq)
|
||||
}
|
||||
sgl = sreq->tsg;
|
||||
n = sg_nents(sgl);
|
||||
for_each_sg(sgl, sg, n, i)
|
||||
put_page(sg_page(sg));
|
||||
for_each_sg(sgl, sg, n, i) {
|
||||
struct page *page = sg_page(sg);
|
||||
|
||||
/* some SGs may not have a page mapped */
|
||||
if (page && page_ref_count(page))
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
kfree(sreq->tsg);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,16 @@ config ANDROID_BINDER_IPC_32BIT
|
||||
|
||||
Note that enabling this will break newer Android user-space.
|
||||
|
||||
config ANDROID_BINDER_IPC_SELFTEST
|
||||
bool "Android Binder IPC Driver Selftest"
|
||||
depends on ANDROID_BINDER_IPC
|
||||
---help---
|
||||
This feature allows binder selftest to run.
|
||||
|
||||
Binder selftest checks the allocation and free of binder buffers
|
||||
exhaustively with combinations of various buffer sizes and
|
||||
alignments.
|
||||
|
||||
endif # if ANDROID
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ccflags-y += -I$(src) # needed for trace events
|
||||
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o
|
||||
|
||||
@@ -2480,7 +2480,6 @@ static int binder_translate_handle(struct flat_binder_object *fp,
|
||||
(u64)node->ptr);
|
||||
binder_node_unlock(node);
|
||||
} else {
|
||||
int ret;
|
||||
struct binder_ref_data dest_rdata;
|
||||
|
||||
binder_node_unlock(node);
|
||||
@@ -3252,6 +3251,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
err_dead_proc_or_thread:
|
||||
return_error = BR_DEAD_REPLY;
|
||||
return_error_line = __LINE__;
|
||||
binder_dequeue_work(proc, tcomplete);
|
||||
err_translate_failed:
|
||||
err_bad_object_type:
|
||||
err_bad_offset:
|
||||
@@ -4579,6 +4579,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
|
||||
proc->pid, current->pid, cmd, arg);*/
|
||||
|
||||
binder_selftest_alloc(&proc->alloc);
|
||||
|
||||
trace_binder_ioctl(cmd, arg);
|
||||
|
||||
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
|
||||
@@ -5424,6 +5426,8 @@ static void print_binder_proc_stats(struct seq_file *m,
|
||||
count = binder_alloc_get_allocated_count(&proc->alloc);
|
||||
seq_printf(m, " buffers: %d\n", count);
|
||||
|
||||
binder_alloc_print_pages(m, &proc->alloc);
|
||||
|
||||
count = 0;
|
||||
binder_inner_proc_lock(proc);
|
||||
list_for_each_entry(w, &proc->todo, entry) {
|
||||
@@ -5620,6 +5624,8 @@ static int __init binder_init(void)
|
||||
struct binder_device *device;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
binder_alloc_shrinker_init();
|
||||
|
||||
atomic_set(&binder_transaction_log.cur, ~0U);
|
||||
atomic_set(&binder_transaction_log_failed.cur, ~0U);
|
||||
|
||||
|
||||
@@ -27,9 +27,12 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/list_lru.h>
|
||||
#include "binder_alloc.h"
|
||||
#include "binder_trace.h"
|
||||
|
||||
struct list_lru binder_alloc_lru;
|
||||
|
||||
static DEFINE_MUTEX(binder_alloc_mmap_lock);
|
||||
|
||||
enum {
|
||||
@@ -48,14 +51,23 @@ module_param_named(debug_mask, binder_alloc_debug_mask,
|
||||
pr_info(x); \
|
||||
} while (0)
|
||||
|
||||
static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer)
|
||||
{
|
||||
return list_entry(buffer->entry.next, struct binder_buffer, entry);
|
||||
}
|
||||
|
||||
static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer)
|
||||
{
|
||||
return list_entry(buffer->entry.prev, struct binder_buffer, entry);
|
||||
}
|
||||
|
||||
static size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer)
|
||||
{
|
||||
if (list_is_last(&buffer->entry, &alloc->buffers))
|
||||
return alloc->buffer +
|
||||
alloc->buffer_size - (void *)buffer->data;
|
||||
return (size_t)list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry) - (size_t)buffer->data;
|
||||
return (u8 *)alloc->buffer +
|
||||
alloc->buffer_size - (u8 *)buffer->data;
|
||||
return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data;
|
||||
}
|
||||
|
||||
static void binder_insert_free_buffer(struct binder_alloc *alloc,
|
||||
@@ -105,9 +117,9 @@ static void binder_insert_allocated_buffer_locked(
|
||||
buffer = rb_entry(parent, struct binder_buffer, rb_node);
|
||||
BUG_ON(buffer->free);
|
||||
|
||||
if (new_buffer < buffer)
|
||||
if (new_buffer->data < buffer->data)
|
||||
p = &parent->rb_left;
|
||||
else if (new_buffer > buffer)
|
||||
else if (new_buffer->data > buffer->data)
|
||||
p = &parent->rb_right;
|
||||
else
|
||||
BUG();
|
||||
@@ -122,18 +134,17 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked(
|
||||
{
|
||||
struct rb_node *n = alloc->allocated_buffers.rb_node;
|
||||
struct binder_buffer *buffer;
|
||||
struct binder_buffer *kern_ptr;
|
||||
void *kern_ptr;
|
||||
|
||||
kern_ptr = (struct binder_buffer *)(user_ptr - alloc->user_buffer_offset
|
||||
- offsetof(struct binder_buffer, data));
|
||||
kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset);
|
||||
|
||||
while (n) {
|
||||
buffer = rb_entry(n, struct binder_buffer, rb_node);
|
||||
BUG_ON(buffer->free);
|
||||
|
||||
if (kern_ptr < buffer)
|
||||
if (kern_ptr < buffer->data)
|
||||
n = n->rb_left;
|
||||
else if (kern_ptr > buffer)
|
||||
else if (kern_ptr > buffer->data)
|
||||
n = n->rb_right;
|
||||
else {
|
||||
/*
|
||||
@@ -180,8 +191,9 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
|
||||
{
|
||||
void *page_addr;
|
||||
unsigned long user_page_addr;
|
||||
struct page **page;
|
||||
struct mm_struct *mm;
|
||||
struct binder_lru_page *page;
|
||||
struct mm_struct *mm = NULL;
|
||||
bool need_mm = false;
|
||||
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%d: %s pages %pK-%pK\n", alloc->pid,
|
||||
@@ -192,9 +204,18 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
|
||||
|
||||
trace_binder_update_page_range(alloc, allocate, start, end);
|
||||
|
||||
if (vma)
|
||||
mm = NULL;
|
||||
else
|
||||
if (allocate == 0)
|
||||
goto free_range;
|
||||
|
||||
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
|
||||
if (!page->page_ptr) {
|
||||
need_mm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vma && need_mm)
|
||||
mm = get_task_mm(alloc->tsk);
|
||||
|
||||
if (mm) {
|
||||
@@ -207,10 +228,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
|
||||
}
|
||||
}
|
||||
|
||||
if (allocate == 0)
|
||||
goto free_range;
|
||||
|
||||
if (vma == NULL) {
|
||||
if (!vma && need_mm) {
|
||||
pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
|
||||
alloc->pid);
|
||||
goto err_no_vma;
|
||||
@@ -218,18 +236,40 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
|
||||
|
||||
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
int ret;
|
||||
bool on_lru;
|
||||
size_t index;
|
||||
|
||||
page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
|
||||
index = (page_addr - alloc->buffer) / PAGE_SIZE;
|
||||
page = &alloc->pages[index];
|
||||
|
||||
BUG_ON(*page);
|
||||
*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
|
||||
if (*page == NULL) {
|
||||
if (page->page_ptr) {
|
||||
trace_binder_alloc_lru_start(alloc, index);
|
||||
|
||||
on_lru = list_lru_del(&binder_alloc_lru, &page->lru);
|
||||
WARN_ON(!on_lru);
|
||||
|
||||
trace_binder_alloc_lru_end(alloc, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WARN_ON(!vma))
|
||||
goto err_page_ptr_cleared;
|
||||
|
||||
trace_binder_alloc_page_start(alloc, index);
|
||||
page->page_ptr = alloc_page(GFP_KERNEL |
|
||||
__GFP_HIGHMEM |
|
||||
__GFP_ZERO);
|
||||
if (!page->page_ptr) {
|
||||
pr_err("%d: binder_alloc_buf failed for page at %pK\n",
|
||||
alloc->pid, page_addr);
|
||||
goto err_alloc_page_failed;
|
||||
}
|
||||
page->alloc = alloc;
|
||||
INIT_LIST_HEAD(&page->lru);
|
||||
|
||||
ret = map_kernel_range_noflush((unsigned long)page_addr,
|
||||
PAGE_SIZE, PAGE_KERNEL, page);
|
||||
PAGE_SIZE, PAGE_KERNEL,
|
||||
&page->page_ptr);
|
||||
flush_cache_vmap((unsigned long)page_addr,
|
||||
(unsigned long)page_addr + PAGE_SIZE);
|
||||
if (ret != 1) {
|
||||
@@ -239,12 +279,14 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
|
||||
}
|
||||
user_page_addr =
|
||||
(uintptr_t)page_addr + alloc->user_buffer_offset;
|
||||
ret = vm_insert_page(vma, user_page_addr, page[0]);
|
||||
ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
|
||||
if (ret) {
|
||||
pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n",
|
||||
alloc->pid, user_page_addr);
|
||||
goto err_vm_insert_page_failed;
|
||||
}
|
||||
|
||||
trace_binder_alloc_page_end(alloc, index);
|
||||
/* vm_insert_page does not seem to increment the refcount */
|
||||
}
|
||||
if (mm) {
|
||||
@@ -256,16 +298,27 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
|
||||
free_range:
|
||||
for (page_addr = end - PAGE_SIZE; page_addr >= start;
|
||||
page_addr -= PAGE_SIZE) {
|
||||
page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
|
||||
if (vma)
|
||||
zap_page_range(vma, (uintptr_t)page_addr +
|
||||
alloc->user_buffer_offset, PAGE_SIZE, NULL);
|
||||
bool ret;
|
||||
size_t index;
|
||||
|
||||
index = (page_addr - alloc->buffer) / PAGE_SIZE;
|
||||
page = &alloc->pages[index];
|
||||
|
||||
trace_binder_free_lru_start(alloc, index);
|
||||
|
||||
ret = list_lru_add(&binder_alloc_lru, &page->lru);
|
||||
WARN_ON(!ret);
|
||||
|
||||
trace_binder_free_lru_end(alloc, index);
|
||||
continue;
|
||||
|
||||
err_vm_insert_page_failed:
|
||||
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
|
||||
err_map_kernel_failed:
|
||||
__free_page(*page);
|
||||
*page = NULL;
|
||||
__free_page(page->page_ptr);
|
||||
page->page_ptr = NULL;
|
||||
err_alloc_page_failed:
|
||||
err_page_ptr_cleared:
|
||||
;
|
||||
}
|
||||
err_no_vma:
|
||||
@@ -321,6 +374,9 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc,
|
||||
return ERR_PTR(-ENOSPC);
|
||||
}
|
||||
|
||||
/* Pad 0-size buffers so they get assigned unique addresses */
|
||||
size = max(size, sizeof(void *));
|
||||
|
||||
while (n) {
|
||||
buffer = rb_entry(n, struct binder_buffer, rb_node);
|
||||
BUG_ON(!buffer->free);
|
||||
@@ -380,14 +436,9 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc,
|
||||
|
||||
has_page_addr =
|
||||
(void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK);
|
||||
if (n == NULL) {
|
||||
if (size + sizeof(struct binder_buffer) + 4 >= buffer_size)
|
||||
buffer_size = size; /* no room for other buffers */
|
||||
else
|
||||
buffer_size = size + sizeof(struct binder_buffer);
|
||||
}
|
||||
WARN_ON(n && buffer_size != size);
|
||||
end_page_addr =
|
||||
(void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size);
|
||||
(void *)PAGE_ALIGN((uintptr_t)buffer->data + size);
|
||||
if (end_page_addr > has_page_addr)
|
||||
end_page_addr = has_page_addr;
|
||||
ret = binder_update_page_range(alloc, 1,
|
||||
@@ -395,17 +446,25 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
rb_erase(best_fit, &alloc->free_buffers);
|
||||
buffer->free = 0;
|
||||
buffer->free_in_progress = 0;
|
||||
binder_insert_allocated_buffer_locked(alloc, buffer);
|
||||
if (buffer_size != size) {
|
||||
struct binder_buffer *new_buffer = (void *)buffer->data + size;
|
||||
struct binder_buffer *new_buffer;
|
||||
|
||||
new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||
if (!new_buffer) {
|
||||
pr_err("%s: %d failed to alloc new buffer struct\n",
|
||||
__func__, alloc->pid);
|
||||
goto err_alloc_buf_struct_failed;
|
||||
}
|
||||
new_buffer->data = (u8 *)buffer->data + size;
|
||||
list_add(&new_buffer->entry, &buffer->entry);
|
||||
new_buffer->free = 1;
|
||||
binder_insert_free_buffer(alloc, new_buffer);
|
||||
}
|
||||
|
||||
rb_erase(best_fit, &alloc->free_buffers);
|
||||
buffer->free = 0;
|
||||
buffer->free_in_progress = 0;
|
||||
binder_insert_allocated_buffer_locked(alloc, buffer);
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%d: binder_alloc_buf size %zd got %pK\n",
|
||||
alloc->pid, size, buffer);
|
||||
@@ -420,6 +479,12 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc,
|
||||
alloc->pid, size, alloc->free_async_space);
|
||||
}
|
||||
return buffer;
|
||||
|
||||
err_alloc_buf_struct_failed:
|
||||
binder_update_page_range(alloc, 0,
|
||||
(void *)PAGE_ALIGN((uintptr_t)buffer->data),
|
||||
end_page_addr, NULL);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,57 +519,59 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
|
||||
|
||||
static void *buffer_start_page(struct binder_buffer *buffer)
|
||||
{
|
||||
return (void *)((uintptr_t)buffer & PAGE_MASK);
|
||||
return (void *)((uintptr_t)buffer->data & PAGE_MASK);
|
||||
}
|
||||
|
||||
static void *buffer_end_page(struct binder_buffer *buffer)
|
||||
static void *prev_buffer_end_page(struct binder_buffer *buffer)
|
||||
{
|
||||
return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK);
|
||||
return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK);
|
||||
}
|
||||
|
||||
static void binder_delete_free_buffer(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer)
|
||||
{
|
||||
struct binder_buffer *prev, *next = NULL;
|
||||
int free_page_end = 1;
|
||||
int free_page_start = 1;
|
||||
|
||||
bool to_free = true;
|
||||
BUG_ON(alloc->buffers.next == &buffer->entry);
|
||||
prev = list_entry(buffer->entry.prev, struct binder_buffer, entry);
|
||||
prev = binder_buffer_prev(buffer);
|
||||
BUG_ON(!prev->free);
|
||||
if (buffer_end_page(prev) == buffer_start_page(buffer)) {
|
||||
free_page_start = 0;
|
||||
if (buffer_end_page(prev) == buffer_end_page(buffer))
|
||||
free_page_end = 0;
|
||||
if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) {
|
||||
to_free = false;
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%d: merge free, buffer %pK share page with %pK\n",
|
||||
alloc->pid, buffer, prev);
|
||||
"%d: merge free, buffer %pK share page with %pK\n",
|
||||
alloc->pid, buffer->data, prev->data);
|
||||
}
|
||||
|
||||
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
|
||||
next = list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry);
|
||||
if (buffer_start_page(next) == buffer_end_page(buffer)) {
|
||||
free_page_end = 0;
|
||||
if (buffer_start_page(next) ==
|
||||
buffer_start_page(buffer))
|
||||
free_page_start = 0;
|
||||
next = binder_buffer_next(buffer);
|
||||
if (buffer_start_page(next) == buffer_start_page(buffer)) {
|
||||
to_free = false;
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%d: merge free, buffer %pK share page with %pK\n",
|
||||
alloc->pid, buffer, prev);
|
||||
"%d: merge free, buffer %pK share page with %pK\n",
|
||||
alloc->pid,
|
||||
buffer->data,
|
||||
next->data);
|
||||
}
|
||||
}
|
||||
list_del(&buffer->entry);
|
||||
if (free_page_start || free_page_end) {
|
||||
|
||||
if (PAGE_ALIGNED(buffer->data)) {
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
|
||||
alloc->pid, buffer, free_page_start ? "" : " end",
|
||||
free_page_end ? "" : " start", prev, next);
|
||||
binder_update_page_range(alloc, 0, free_page_start ?
|
||||
buffer_start_page(buffer) : buffer_end_page(buffer),
|
||||
(free_page_end ? buffer_end_page(buffer) :
|
||||
buffer_start_page(buffer)) + PAGE_SIZE, NULL);
|
||||
"%d: merge free, buffer start %pK is page aligned\n",
|
||||
alloc->pid, buffer->data);
|
||||
to_free = false;
|
||||
}
|
||||
|
||||
if (to_free) {
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%d: merge free, buffer %pK do not share page with %pK or %pK\n",
|
||||
alloc->pid, buffer->data,
|
||||
prev->data, next->data);
|
||||
binder_update_page_range(alloc, 0, buffer_start_page(buffer),
|
||||
buffer_start_page(buffer) + PAGE_SIZE,
|
||||
NULL);
|
||||
}
|
||||
list_del(&buffer->entry);
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
static void binder_free_buf_locked(struct binder_alloc *alloc,
|
||||
@@ -525,8 +592,8 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
|
||||
BUG_ON(buffer->free);
|
||||
BUG_ON(size > buffer_size);
|
||||
BUG_ON(buffer->transaction != NULL);
|
||||
BUG_ON((void *)buffer < alloc->buffer);
|
||||
BUG_ON((void *)buffer > alloc->buffer + alloc->buffer_size);
|
||||
BUG_ON(buffer->data < alloc->buffer);
|
||||
BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size);
|
||||
|
||||
if (buffer->async_transaction) {
|
||||
alloc->free_async_space += size + sizeof(struct binder_buffer);
|
||||
@@ -544,8 +611,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
|
||||
rb_erase(&buffer->rb_node, &alloc->allocated_buffers);
|
||||
buffer->free = 1;
|
||||
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
|
||||
struct binder_buffer *next = list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry);
|
||||
struct binder_buffer *next = binder_buffer_next(buffer);
|
||||
|
||||
if (next->free) {
|
||||
rb_erase(&next->rb_node, &alloc->free_buffers);
|
||||
@@ -553,8 +619,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
|
||||
}
|
||||
}
|
||||
if (alloc->buffers.next != &buffer->entry) {
|
||||
struct binder_buffer *prev = list_entry(buffer->entry.prev,
|
||||
struct binder_buffer, entry);
|
||||
struct binder_buffer *prev = binder_buffer_prev(buffer);
|
||||
|
||||
if (prev->free) {
|
||||
binder_delete_free_buffer(alloc, buffer);
|
||||
@@ -640,14 +705,14 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
|
||||
}
|
||||
alloc->buffer_size = vma->vm_end - vma->vm_start;
|
||||
|
||||
if (binder_update_page_range(alloc, 1, alloc->buffer,
|
||||
alloc->buffer + PAGE_SIZE, vma)) {
|
||||
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
ret = -ENOMEM;
|
||||
failure_string = "alloc small buf";
|
||||
goto err_alloc_small_buf_failed;
|
||||
failure_string = "alloc buffer struct";
|
||||
goto err_alloc_buf_struct_failed;
|
||||
}
|
||||
buffer = alloc->buffer;
|
||||
INIT_LIST_HEAD(&alloc->buffers);
|
||||
|
||||
buffer->data = alloc->buffer;
|
||||
list_add(&buffer->entry, &alloc->buffers);
|
||||
buffer->free = 1;
|
||||
binder_insert_free_buffer(alloc, buffer);
|
||||
@@ -658,7 +723,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
|
||||
|
||||
return 0;
|
||||
|
||||
err_alloc_small_buf_failed:
|
||||
err_alloc_buf_struct_failed:
|
||||
kfree(alloc->pages);
|
||||
alloc->pages = NULL;
|
||||
err_alloc_pages_failed:
|
||||
@@ -678,14 +743,13 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
|
||||
{
|
||||
struct rb_node *n;
|
||||
int buffers, page_count;
|
||||
struct binder_buffer *buffer;
|
||||
|
||||
BUG_ON(alloc->vma);
|
||||
|
||||
buffers = 0;
|
||||
mutex_lock(&alloc->mutex);
|
||||
while ((n = rb_first(&alloc->allocated_buffers))) {
|
||||
struct binder_buffer *buffer;
|
||||
|
||||
buffer = rb_entry(n, struct binder_buffer, rb_node);
|
||||
|
||||
/* Transaction should already have been freed */
|
||||
@@ -695,22 +759,36 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
|
||||
buffers++;
|
||||
}
|
||||
|
||||
while (!list_empty(&alloc->buffers)) {
|
||||
buffer = list_first_entry(&alloc->buffers,
|
||||
struct binder_buffer, entry);
|
||||
WARN_ON(!buffer->free);
|
||||
|
||||
list_del(&buffer->entry);
|
||||
WARN_ON_ONCE(!list_empty(&alloc->buffers));
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
page_count = 0;
|
||||
if (alloc->pages) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
|
||||
void *page_addr;
|
||||
bool on_lru;
|
||||
|
||||
if (!alloc->pages[i])
|
||||
if (!alloc->pages[i].page_ptr)
|
||||
continue;
|
||||
|
||||
on_lru = list_lru_del(&binder_alloc_lru,
|
||||
&alloc->pages[i].lru);
|
||||
page_addr = alloc->buffer + i * PAGE_SIZE;
|
||||
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
||||
"%s: %d: page %d at %pK not freed\n",
|
||||
__func__, alloc->pid, i, page_addr);
|
||||
"%s: %d: page %d at %pK %s\n",
|
||||
__func__, alloc->pid, i, page_addr,
|
||||
on_lru ? "on lru" : "active");
|
||||
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
|
||||
__free_page(alloc->pages[i]);
|
||||
__free_page(alloc->pages[i].page_ptr);
|
||||
page_count++;
|
||||
}
|
||||
kfree(alloc->pages);
|
||||
@@ -753,6 +831,34 @@ void binder_alloc_print_allocated(struct seq_file *m,
|
||||
mutex_unlock(&alloc->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_alloc_print_pages() - print page usage
|
||||
* @m: seq_file for output via seq_printf()
|
||||
* @alloc: binder_alloc for this proc
|
||||
*/
|
||||
void binder_alloc_print_pages(struct seq_file *m,
|
||||
struct binder_alloc *alloc)
|
||||
{
|
||||
struct binder_lru_page *page;
|
||||
int i;
|
||||
int active = 0;
|
||||
int lru = 0;
|
||||
int free = 0;
|
||||
|
||||
mutex_lock(&alloc->mutex);
|
||||
for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
|
||||
page = &alloc->pages[i];
|
||||
if (!page->page_ptr)
|
||||
free++;
|
||||
else if (list_empty(&page->lru))
|
||||
active++;
|
||||
else
|
||||
lru++;
|
||||
}
|
||||
mutex_unlock(&alloc->mutex);
|
||||
seq_printf(m, " pages: %d:%d:%d\n", active, lru, free);
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_alloc_get_allocated_count() - return count of buffers
|
||||
* @alloc: binder_alloc for this proc
|
||||
@@ -786,6 +892,102 @@ void binder_alloc_vma_close(struct binder_alloc *alloc)
|
||||
WRITE_ONCE(alloc->vma_vm_mm, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_alloc_free_page() - shrinker callback to free pages
|
||||
* @item: item to free
|
||||
* @lock: lock protecting the item
|
||||
* @cb_arg: callback argument
|
||||
*
|
||||
* Called from list_lru_walk() in binder_shrink_scan() to free
|
||||
* up pages when the system is under memory pressure.
|
||||
*/
|
||||
enum lru_status binder_alloc_free_page(struct list_head *item,
|
||||
struct list_lru_one *lru,
|
||||
spinlock_t *lock,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct mm_struct *mm = NULL;
|
||||
struct binder_lru_page *page = container_of(item,
|
||||
struct binder_lru_page,
|
||||
lru);
|
||||
struct binder_alloc *alloc;
|
||||
uintptr_t page_addr;
|
||||
size_t index;
|
||||
|
||||
alloc = page->alloc;
|
||||
if (!mutex_trylock(&alloc->mutex))
|
||||
goto err_get_alloc_mutex_failed;
|
||||
|
||||
if (!page->page_ptr)
|
||||
goto err_page_already_freed;
|
||||
|
||||
index = page - alloc->pages;
|
||||
page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
|
||||
if (alloc->vma) {
|
||||
mm = get_task_mm(alloc->tsk);
|
||||
if (!mm)
|
||||
goto err_get_task_mm_failed;
|
||||
if (!down_write_trylock(&mm->mmap_sem))
|
||||
goto err_down_write_mmap_sem_failed;
|
||||
|
||||
trace_binder_unmap_user_start(alloc, index);
|
||||
|
||||
zap_page_range(alloc->vma,
|
||||
page_addr +
|
||||
alloc->user_buffer_offset,
|
||||
PAGE_SIZE, NULL);
|
||||
|
||||
trace_binder_unmap_user_end(alloc, index);
|
||||
|
||||
up_write(&mm->mmap_sem);
|
||||
mmput(mm);
|
||||
}
|
||||
|
||||
trace_binder_unmap_kernel_start(alloc, index);
|
||||
|
||||
unmap_kernel_range(page_addr, PAGE_SIZE);
|
||||
__free_page(page->page_ptr);
|
||||
page->page_ptr = NULL;
|
||||
|
||||
trace_binder_unmap_kernel_end(alloc, index);
|
||||
|
||||
list_lru_isolate(lru, item);
|
||||
|
||||
mutex_unlock(&alloc->mutex);
|
||||
return LRU_REMOVED;
|
||||
|
||||
err_down_write_mmap_sem_failed:
|
||||
mmput(mm);
|
||||
err_get_task_mm_failed:
|
||||
err_page_already_freed:
|
||||
mutex_unlock(&alloc->mutex);
|
||||
err_get_alloc_mutex_failed:
|
||||
return LRU_SKIP;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
unsigned long ret = list_lru_count(&binder_alloc_lru);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
ret = list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
|
||||
NULL, sc->nr_to_scan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct shrinker binder_shrinker = {
|
||||
.count_objects = binder_shrink_count,
|
||||
.scan_objects = binder_shrink_scan,
|
||||
.seeks = DEFAULT_SEEKS,
|
||||
};
|
||||
|
||||
/**
|
||||
* binder_alloc_init() - called by binder_open() for per-proc initialization
|
||||
* @alloc: binder_alloc for this proc
|
||||
@@ -798,5 +1000,11 @@ void binder_alloc_init(struct binder_alloc *alloc)
|
||||
alloc->tsk = current->group_leader;
|
||||
alloc->pid = current->group_leader->pid;
|
||||
mutex_init(&alloc->mutex);
|
||||
INIT_LIST_HEAD(&alloc->buffers);
|
||||
}
|
||||
|
||||
void binder_alloc_shrinker_init(void)
|
||||
{
|
||||
list_lru_init(&binder_alloc_lru);
|
||||
register_shrinker(&binder_shrinker);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#include <linux/rtmutex.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list_lru.h>
|
||||
|
||||
extern struct list_lru binder_alloc_lru;
|
||||
struct binder_transaction;
|
||||
|
||||
/**
|
||||
@@ -57,7 +59,19 @@ struct binder_buffer {
|
||||
size_t data_size;
|
||||
size_t offsets_size;
|
||||
size_t extra_buffers_size;
|
||||
uint8_t data[0];
|
||||
void *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct binder_lru_page - page object used for binder shrinker
|
||||
* @page_ptr: pointer to physical page in mmap'd space
|
||||
* @lru: entry in binder_alloc_lru
|
||||
* @alloc: binder_alloc for a proc
|
||||
*/
|
||||
struct binder_lru_page {
|
||||
struct list_head lru;
|
||||
struct page *page_ptr;
|
||||
struct binder_alloc *alloc;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -75,8 +89,7 @@ struct binder_buffer {
|
||||
* @allocated_buffers: rb tree of allocated buffers sorted by address
|
||||
* @free_async_space: VA space available for async buffers. This is
|
||||
* initialized at mmap time to 1/2 the full VA space
|
||||
* @pages: array of physical page addresses for each
|
||||
* page of mmap'd space
|
||||
* @pages: array of binder_lru_page
|
||||
* @buffer_size: size of address space specified via mmap
|
||||
* @pid: pid for associated binder_proc (invariant after init)
|
||||
*
|
||||
@@ -96,18 +109,27 @@ struct binder_alloc {
|
||||
struct rb_root free_buffers;
|
||||
struct rb_root allocated_buffers;
|
||||
size_t free_async_space;
|
||||
struct page **pages;
|
||||
struct binder_lru_page *pages;
|
||||
size_t buffer_size;
|
||||
uint32_t buffer_free;
|
||||
int pid;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST
|
||||
void binder_selftest_alloc(struct binder_alloc *alloc);
|
||||
#else
|
||||
static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
|
||||
#endif
|
||||
enum lru_status binder_alloc_free_page(struct list_head *item,
|
||||
struct list_lru_one *lru,
|
||||
spinlock_t *lock, void *cb_arg);
|
||||
extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
|
||||
size_t data_size,
|
||||
size_t offsets_size,
|
||||
size_t extra_buffers_size,
|
||||
int is_async);
|
||||
extern void binder_alloc_init(struct binder_alloc *alloc);
|
||||
void binder_alloc_shrinker_init(void);
|
||||
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
|
||||
extern struct binder_buffer *
|
||||
binder_alloc_prepare_to_free(struct binder_alloc *alloc,
|
||||
@@ -120,6 +142,8 @@ extern void binder_alloc_deferred_release(struct binder_alloc *alloc);
|
||||
extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
|
||||
extern void binder_alloc_print_allocated(struct seq_file *m,
|
||||
struct binder_alloc *alloc);
|
||||
void binder_alloc_print_pages(struct seq_file *m,
|
||||
struct binder_alloc *alloc);
|
||||
|
||||
/**
|
||||
* binder_alloc_get_free_async_space() - get free space available for async
|
||||
|
||||
310
drivers/android/binder_alloc_selftest.c
Normal file
310
drivers/android/binder_alloc_selftest.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/* binder_alloc_selftest.c
|
||||
*
|
||||
* Android IPC Subsystem
|
||||
*
|
||||
* Copyright (C) 2017 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/err.h>
|
||||
#include "binder_alloc.h"
|
||||
|
||||
#define BUFFER_NUM 5
|
||||
#define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
|
||||
|
||||
static bool binder_selftest_run = true;
|
||||
static int binder_selftest_failures;
|
||||
static DEFINE_MUTEX(binder_selftest_lock);
|
||||
|
||||
/**
|
||||
* enum buf_end_align_type - Page alignment of a buffer
|
||||
* end with regard to the end of the previous buffer.
|
||||
*
|
||||
* In the pictures below, buf2 refers to the buffer we
|
||||
* are aligning. buf1 refers to previous buffer by addr.
|
||||
* Symbol [ means the start of a buffer, ] means the end
|
||||
* of a buffer, and | means page boundaries.
|
||||
*/
|
||||
enum buf_end_align_type {
|
||||
/**
|
||||
* @SAME_PAGE_UNALIGNED: The end of this buffer is on
|
||||
* the same page as the end of the previous buffer and
|
||||
* is not page aligned. Examples:
|
||||
* buf1 ][ buf2 ][ ...
|
||||
* buf1 ]|[ buf2 ][ ...
|
||||
*/
|
||||
SAME_PAGE_UNALIGNED = 0,
|
||||
/**
|
||||
* @SAME_PAGE_ALIGNED: When the end of the previous buffer
|
||||
* is not page aligned, the end of this buffer is on the
|
||||
* same page as the end of the previous buffer and is page
|
||||
* aligned. When the previous buffer is page aligned, the
|
||||
* end of this buffer is aligned to the next page boundary.
|
||||
* Examples:
|
||||
* buf1 ][ buf2 ]| ...
|
||||
* buf1 ]|[ buf2 ]| ...
|
||||
*/
|
||||
SAME_PAGE_ALIGNED,
|
||||
/**
|
||||
* @NEXT_PAGE_UNALIGNED: The end of this buffer is on
|
||||
* the page next to the end of the previous buffer and
|
||||
* is not page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 ][ ...
|
||||
* buf1 ]|[ buf2 | buf2 ][ ...
|
||||
*/
|
||||
NEXT_PAGE_UNALIGNED,
|
||||
/**
|
||||
* @NEXT_PAGE_ALIGNED: The end of this buffer is on
|
||||
* the page next to the end of the previous buffer and
|
||||
* is page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 ]| ...
|
||||
* buf1 ]|[ buf2 | buf2 ]| ...
|
||||
*/
|
||||
NEXT_PAGE_ALIGNED,
|
||||
/**
|
||||
* @NEXT_NEXT_UNALIGNED: The end of this buffer is on
|
||||
* the page that follows the page after the end of the
|
||||
* previous buffer and is not page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 | buf2 ][ ...
|
||||
* buf1 ]|[ buf2 | buf2 | buf2 ][ ...
|
||||
*/
|
||||
NEXT_NEXT_UNALIGNED,
|
||||
LOOP_END,
|
||||
};
|
||||
|
||||
static void pr_err_size_seq(size_t *sizes, int *seq)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_err("alloc sizes: ");
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
pr_cont("[%zu]", sizes[i]);
|
||||
pr_cont("\n");
|
||||
pr_err("free seq: ");
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
pr_cont("[%d]", seq[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
static bool check_buffer_pages_allocated(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer,
|
||||
size_t size)
|
||||
{
|
||||
void *page_addr, *end;
|
||||
int page_index;
|
||||
|
||||
end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size);
|
||||
page_addr = buffer->data;
|
||||
for (; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
page_index = (page_addr - alloc->buffer) / PAGE_SIZE;
|
||||
if (!alloc->pages[page_index].page_ptr ||
|
||||
!list_empty(&alloc->pages[page_index].lru)) {
|
||||
pr_err("expect alloc but is %s at page index %d\n",
|
||||
alloc->pages[page_index].page_ptr ?
|
||||
"lru" : "free", page_index);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffers[],
|
||||
size_t *sizes, int *seq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
|
||||
if (IS_ERR(buffers[i]) ||
|
||||
!check_buffer_pages_allocated(alloc, buffers[i],
|
||||
sizes[i])) {
|
||||
pr_err_size_seq(sizes, seq);
|
||||
binder_selftest_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_free_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffers[],
|
||||
size_t *sizes, int *seq, size_t end)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
binder_alloc_free_buf(alloc, buffers[seq[i]]);
|
||||
|
||||
for (i = 0; i < end / PAGE_SIZE; i++) {
|
||||
/**
|
||||
* Error message on a free page can be false positive
|
||||
* if binder shrinker ran during binder_alloc_free_buf
|
||||
* calls above.
|
||||
*/
|
||||
if (list_empty(&alloc->pages[i].lru)) {
|
||||
pr_err_size_seq(sizes, seq);
|
||||
pr_err("expect lru but is %s at page index %d\n",
|
||||
alloc->pages[i].page_ptr ? "alloc" : "free", i);
|
||||
binder_selftest_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_free_page(struct binder_alloc *alloc)
|
||||
{
|
||||
int i;
|
||||
unsigned long count;
|
||||
|
||||
while ((count = list_lru_count(&binder_alloc_lru))) {
|
||||
list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
|
||||
NULL, count);
|
||||
}
|
||||
|
||||
for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
|
||||
if (alloc->pages[i].page_ptr) {
|
||||
pr_err("expect free but is %s at page index %d\n",
|
||||
list_empty(&alloc->pages[i].lru) ?
|
||||
"alloc" : "lru", i);
|
||||
binder_selftest_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_free(struct binder_alloc *alloc,
|
||||
size_t *sizes, int *seq, size_t end)
|
||||
{
|
||||
struct binder_buffer *buffers[BUFFER_NUM];
|
||||
|
||||
binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
|
||||
binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
|
||||
|
||||
/* Allocate from lru. */
|
||||
binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
|
||||
if (list_lru_count(&binder_alloc_lru))
|
||||
pr_err("lru list should be empty but is not\n");
|
||||
|
||||
binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
|
||||
binder_selftest_free_page(alloc);
|
||||
}
|
||||
|
||||
static bool is_dup(int *seq, int index, int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < index; i++) {
|
||||
if (seq[i] == val)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Generate BUFFER_NUM factorial free orders. */
|
||||
static void binder_selftest_free_seq(struct binder_alloc *alloc,
|
||||
size_t *sizes, int *seq,
|
||||
int index, size_t end)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (index == BUFFER_NUM) {
|
||||
binder_selftest_alloc_free(alloc, sizes, seq, end);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
if (is_dup(seq, index, i))
|
||||
continue;
|
||||
seq[index] = i;
|
||||
binder_selftest_free_seq(alloc, sizes, seq, index + 1, end);
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_size(struct binder_alloc *alloc,
|
||||
size_t *end_offset)
|
||||
{
|
||||
int i;
|
||||
int seq[BUFFER_NUM] = {0};
|
||||
size_t front_sizes[BUFFER_NUM];
|
||||
size_t back_sizes[BUFFER_NUM];
|
||||
size_t last_offset, offset = 0;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
last_offset = offset;
|
||||
offset = end_offset[i];
|
||||
front_sizes[i] = offset - last_offset;
|
||||
back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
|
||||
}
|
||||
/*
|
||||
* Buffers share the first or last few pages.
|
||||
* Only BUFFER_NUM - 1 buffer sizes are adjustable since
|
||||
* we need one giant buffer before getting to the last page.
|
||||
*/
|
||||
back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
|
||||
binder_selftest_free_seq(alloc, front_sizes, seq, 0,
|
||||
end_offset[BUFFER_NUM - 1]);
|
||||
binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size);
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_offset(struct binder_alloc *alloc,
|
||||
size_t *end_offset, int index)
|
||||
{
|
||||
int align;
|
||||
size_t end, prev;
|
||||
|
||||
if (index == BUFFER_NUM) {
|
||||
binder_selftest_alloc_size(alloc, end_offset);
|
||||
return;
|
||||
}
|
||||
prev = index == 0 ? 0 : end_offset[index - 1];
|
||||
end = prev;
|
||||
|
||||
BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
|
||||
|
||||
for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
|
||||
if (align % 2)
|
||||
end = ALIGN(end, PAGE_SIZE);
|
||||
else
|
||||
end += BUFFER_MIN_SIZE;
|
||||
end_offset[index] = end;
|
||||
binder_selftest_alloc_offset(alloc, end_offset, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_selftest_alloc() - Test alloc and free of buffer pages.
|
||||
* @alloc: Pointer to alloc struct.
|
||||
*
|
||||
* Allocate BUFFER_NUM buffers to cover all page alignment cases,
|
||||
* then free them in all orders possible. Check that pages are
|
||||
* correctly allocated, put onto lru when buffers are freed, and
|
||||
* are freed when binder_alloc_free_page is called.
|
||||
*/
|
||||
void binder_selftest_alloc(struct binder_alloc *alloc)
|
||||
{
|
||||
size_t end_offset[BUFFER_NUM];
|
||||
|
||||
if (!binder_selftest_run)
|
||||
return;
|
||||
mutex_lock(&binder_selftest_lock);
|
||||
if (!binder_selftest_run || !alloc->vma)
|
||||
goto done;
|
||||
pr_info("STARTED\n");
|
||||
binder_selftest_alloc_offset(alloc, end_offset, 0);
|
||||
binder_selftest_run = false;
|
||||
if (binder_selftest_failures > 0)
|
||||
pr_info("%d tests FAILED\n", binder_selftest_failures);
|
||||
else
|
||||
pr_info("PASSED\n");
|
||||
|
||||
done:
|
||||
mutex_unlock(&binder_selftest_lock);
|
||||
}
|
||||
@@ -291,6 +291,61 @@ TRACE_EVENT(binder_update_page_range,
|
||||
__entry->offset, __entry->size)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(binder_lru_page_class,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, proc)
|
||||
__field(size_t, page_index)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->proc = alloc->pid;
|
||||
__entry->page_index = page_index;
|
||||
),
|
||||
TP_printk("proc=%d page_index=%zu",
|
||||
__entry->proc, __entry->page_index)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end,
|
||||
TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
|
||||
TP_ARGS(alloc, page_index));
|
||||
|
||||
TRACE_EVENT(binder_command,
|
||||
TP_PROTO(uint32_t cmd),
|
||||
TP_ARGS(cmd),
|
||||
|
||||
@@ -616,6 +616,7 @@ static const struct pci_device_id amd[] = {
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 8 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), 9 },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -289,6 +289,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
|
||||
static const struct pci_device_id cs5536[] = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
@@ -736,7 +736,7 @@ int bus_add_driver(struct device_driver *drv)
|
||||
|
||||
out_unregister:
|
||||
kobject_put(&priv->kobj);
|
||||
kfree(drv->p);
|
||||
/* drv->p is freed in driver_release() */
|
||||
drv->p = NULL;
|
||||
out_put_bus:
|
||||
bus_put(bus);
|
||||
|
||||
@@ -342,6 +342,7 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK },
|
||||
|
||||
/* Additional Realtek 8821AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
|
||||
|
||||
@@ -315,6 +315,8 @@ struct adv7511 {
|
||||
bool edid_read;
|
||||
|
||||
wait_queue_head_t wq;
|
||||
struct work_struct hpd_work;
|
||||
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector connector;
|
||||
|
||||
|
||||
@@ -402,6 +402,27 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void adv7511_hpd_work(struct work_struct *work)
|
||||
{
|
||||
struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
|
||||
enum drm_connector_status status;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
|
||||
if (ret < 0)
|
||||
status = connector_status_disconnected;
|
||||
else if (val & ADV7511_STATUS_HPD)
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = connector_status_disconnected;
|
||||
|
||||
if (adv7511->connector.status != status) {
|
||||
adv7511->connector.status = status;
|
||||
drm_kms_helper_hotplug_event(adv7511->connector.dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
|
||||
{
|
||||
unsigned int irq0, irq1;
|
||||
@@ -419,7 +440,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
|
||||
|
||||
if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
|
||||
drm_helper_hpd_irq_event(adv7511->connector.dev);
|
||||
schedule_work(&adv7511->hpd_work);
|
||||
|
||||
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
|
||||
adv7511->edid_read = true;
|
||||
@@ -1006,6 +1027,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
goto err_i2c_unregister_edid;
|
||||
}
|
||||
|
||||
INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
|
||||
|
||||
if (i2c->irq) {
|
||||
init_waitqueue_head(&adv7511->wq);
|
||||
|
||||
|
||||
@@ -192,6 +192,10 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
pci->msi = false;
|
||||
#endif
|
||||
|
||||
pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi);
|
||||
if (pci->msi && func->msi_rearm) {
|
||||
pci->msi = pci_enable_msi(pci->pdev) == 0;
|
||||
|
||||
@@ -612,7 +612,7 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
|
||||
} else {
|
||||
pr_err("Failed to fill pool (%p)\n", pool);
|
||||
/* If we have any pages left put them to the pool. */
|
||||
list_for_each_entry(p, &pool->list, lru) {
|
||||
list_for_each_entry(p, &new_pages, lru) {
|
||||
++cpages;
|
||||
}
|
||||
list_splice(&new_pages, &pool->list);
|
||||
|
||||
@@ -85,6 +85,16 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
|
||||
.driver_data = (kernel_ulong_t)0,
|
||||
},
|
||||
{
|
||||
/* Cannon Lake H */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa326),
|
||||
.driver_data = (kernel_ulong_t)0,
|
||||
},
|
||||
{
|
||||
/* Cannon Lake LP */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da6),
|
||||
.driver_data = (kernel_ulong_t)0,
|
||||
},
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
|
||||
@@ -341,8 +341,10 @@ static int ismt_process_desc(const struct ismt_desc *desc,
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
memcpy(&data->block[1], dma_buffer, desc->rxbytes);
|
||||
data->block[0] = desc->rxbytes;
|
||||
if (desc->rxbytes != dma_buffer[0] + 1)
|
||||
return -EMSGSIZE;
|
||||
|
||||
memcpy(data->block, dma_buffer, desc->rxbytes);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -80,18 +80,12 @@ static const unsigned int ads1115_data_rate[] = {
|
||||
8, 16, 32, 64, 128, 250, 475, 860
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int scale;
|
||||
int uscale;
|
||||
} ads1015_scale[] = {
|
||||
{3, 0},
|
||||
{2, 0},
|
||||
{1, 0},
|
||||
{0, 500000},
|
||||
{0, 250000},
|
||||
{0, 125000},
|
||||
{0, 125000},
|
||||
{0, 125000},
|
||||
/*
|
||||
* Translation from PGA bits to full-scale positive and negative input voltage
|
||||
* range in mV
|
||||
*/
|
||||
static int ads1015_fullscale_range[] = {
|
||||
6144, 4096, 2048, 1024, 512, 256, 256, 256
|
||||
};
|
||||
|
||||
#define ADS1015_V_CHAN(_chan, _addr) { \
|
||||
@@ -182,6 +176,12 @@ struct ads1015_data {
|
||||
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
|
||||
|
||||
unsigned int *data_rate;
|
||||
/*
|
||||
* Set to true when the ADC is switched to the continuous-conversion
|
||||
* mode and exits from a power-down state. This flag is used to avoid
|
||||
* getting the stale result from the conversion register.
|
||||
*/
|
||||
bool conv_invalid;
|
||||
};
|
||||
|
||||
static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
@@ -234,33 +234,43 @@ static int ads1015_set_power_state(struct ads1015_data *data, bool on)
|
||||
ret = pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static
|
||||
int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
|
||||
{
|
||||
int ret, pga, dr, conv_time;
|
||||
bool change;
|
||||
unsigned int old, mask, cfg;
|
||||
|
||||
if (chan < 0 || chan >= ADS1015_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
pga = data->channel_data[chan].pga;
|
||||
dr = data->channel_data[chan].data_rate;
|
||||
|
||||
ret = regmap_update_bits_check(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MUX_MASK |
|
||||
ADS1015_CFG_PGA_MASK,
|
||||
chan << ADS1015_CFG_MUX_SHIFT |
|
||||
pga << ADS1015_CFG_PGA_SHIFT,
|
||||
&change);
|
||||
if (ret < 0)
|
||||
ret = regmap_read(data->regmap, ADS1015_CFG_REG, &old);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (change) {
|
||||
conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
|
||||
pga = data->channel_data[chan].pga;
|
||||
dr = data->channel_data[chan].data_rate;
|
||||
mask = ADS1015_CFG_MUX_MASK | ADS1015_CFG_PGA_MASK |
|
||||
ADS1015_CFG_DR_MASK;
|
||||
cfg = chan << ADS1015_CFG_MUX_SHIFT | pga << ADS1015_CFG_PGA_SHIFT |
|
||||
dr << ADS1015_CFG_DR_SHIFT;
|
||||
|
||||
cfg = (old & ~mask) | (cfg & mask);
|
||||
|
||||
ret = regmap_write(data->regmap, ADS1015_CFG_REG, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (old != cfg || data->conv_invalid) {
|
||||
int dr_old = (old & ADS1015_CFG_DR_MASK) >>
|
||||
ADS1015_CFG_DR_SHIFT;
|
||||
|
||||
conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr_old]);
|
||||
conv_time += DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
|
||||
usleep_range(conv_time, conv_time + 1);
|
||||
data->conv_invalid = false;
|
||||
}
|
||||
|
||||
return regmap_read(data->regmap, ADS1015_CONV_REG, val);
|
||||
@@ -297,17 +307,20 @@ err:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ads1015_set_scale(struct ads1015_data *data, int chan,
|
||||
static int ads1015_set_scale(struct ads1015_data *data,
|
||||
struct iio_chan_spec const *chan,
|
||||
int scale, int uscale)
|
||||
{
|
||||
int i, ret, rindex = -1;
|
||||
int fullscale = div_s64((scale * 1000000LL + uscale) <<
|
||||
(chan->scan_type.realbits - 1), 1000000);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_scale); i++)
|
||||
if (ads1015_scale[i].scale == scale &&
|
||||
ads1015_scale[i].uscale == uscale) {
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_fullscale_range); i++) {
|
||||
if (ads1015_fullscale_range[i] == fullscale) {
|
||||
rindex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rindex < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -317,32 +330,23 @@ static int ads1015_set_scale(struct ads1015_data *data, int chan,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->channel_data[chan].pga = rindex;
|
||||
data->channel_data[chan->address].pga = rindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
|
||||
{
|
||||
int i, ret, rindex = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++) {
|
||||
if (data->data_rate[i] == rate) {
|
||||
rindex = i;
|
||||
break;
|
||||
data->channel_data[chan].data_rate = i;
|
||||
return 0;
|
||||
}
|
||||
if (rindex < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_DR_MASK,
|
||||
rindex << ADS1015_CFG_DR_SHIFT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->channel_data[chan].data_rate = rindex;
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ads1015_read_raw(struct iio_dev *indio_dev,
|
||||
@@ -384,9 +388,9 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
idx = data->channel_data[chan->address].pga;
|
||||
*val = ads1015_scale[idx].scale;
|
||||
*val2 = ads1015_scale[idx].uscale;
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
*val = ads1015_fullscale_range[idx];
|
||||
*val2 = chan->scan_type.realbits - 1;
|
||||
ret = IIO_VAL_FRACTIONAL_LOG2;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
idx = data->channel_data[chan->address].data_rate;
|
||||
@@ -413,7 +417,7 @@ static int ads1015_write_raw(struct iio_dev *indio_dev,
|
||||
mutex_lock(&data->lock);
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = ads1015_set_scale(data, chan->address, val, val2);
|
||||
ret = ads1015_set_scale(data, chan, val, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = ads1015_set_data_rate(data, chan->address, val);
|
||||
@@ -445,7 +449,10 @@ static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
|
||||
.validate_scan_mask = &iio_validate_scan_mask_onehot,
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(scale_available, "3 2 1 0.5 0.25 0.125");
|
||||
static IIO_CONST_ATTR_NAMED(ads1015_scale_available, scale_available,
|
||||
"3 2 1 0.5 0.25 0.125");
|
||||
static IIO_CONST_ATTR_NAMED(ads1115_scale_available, scale_available,
|
||||
"0.1875 0.125 0.0625 0.03125 0.015625 0.007813");
|
||||
|
||||
static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available,
|
||||
sampling_frequency_available, "128 250 490 920 1600 2400 3300");
|
||||
@@ -453,7 +460,7 @@ static IIO_CONST_ATTR_NAMED(ads1115_sampling_frequency_available,
|
||||
sampling_frequency_available, "8 16 32 64 128 250 475 860");
|
||||
|
||||
static struct attribute *ads1015_attributes[] = {
|
||||
&iio_const_attr_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1015_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -463,7 +470,7 @@ static const struct attribute_group ads1015_attribute_group = {
|
||||
};
|
||||
|
||||
static struct attribute *ads1115_attributes[] = {
|
||||
&iio_const_attr_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1115_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -624,6 +631,15 @@ static int ads1015_probe(struct i2c_client *client,
|
||||
dev_err(&client->dev, "iio triggered buffer setup failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MOD_MASK,
|
||||
ADS1015_CONTINUOUS << ADS1015_CFG_MOD_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->conv_invalid = true;
|
||||
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
if (ret)
|
||||
goto err_buffer_cleanup;
|
||||
@@ -679,10 +695,15 @@ static int ads1015_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MOD_MASK,
|
||||
ADS1015_CONTINUOUS << ADS1015_CFG_MOD_SHIFT);
|
||||
if (!ret)
|
||||
data->conv_invalid = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -381,8 +381,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
||||
return 0;
|
||||
|
||||
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
|
||||
psmouse_warn(psmouse, "failed to get extended button data\n");
|
||||
button_info = 0;
|
||||
psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n");
|
||||
button_info = 0x33;
|
||||
}
|
||||
|
||||
psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
|
||||
|
||||
@@ -1115,8 +1115,11 @@ static int __init gic_of_init(struct device_node *node,
|
||||
gic_len = resource_size(&res);
|
||||
}
|
||||
|
||||
if (mips_cm_present())
|
||||
if (mips_cm_present()) {
|
||||
write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK);
|
||||
/* Ensure GIC region is enabled before trying to access it */
|
||||
__sync();
|
||||
}
|
||||
gic_present = true;
|
||||
|
||||
__gic_init(gic_base, gic_len, cpu_vec, 0, node);
|
||||
|
||||
@@ -114,6 +114,12 @@ static struct resource sc24_fpga_resource = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
static struct resource sc31_fpga_resource = {
|
||||
.start = 0xf000e000,
|
||||
.end = 0xf000e000 + CHAM_HEADER_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
static struct platform_driver mcb_lpc_driver = {
|
||||
.driver = {
|
||||
.name = "mcb-lpc",
|
||||
@@ -132,6 +138,15 @@ static const struct dmi_system_id mcb_lpc_dmi_table[] = {
|
||||
.driver_data = (void *)&sc24_fpga_resource,
|
||||
.callback = mcb_lpc_create_platform_device,
|
||||
},
|
||||
{
|
||||
.ident = "SC31",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MEN"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "14SC31"),
|
||||
},
|
||||
.driver_data = (void *)&sc31_fpga_resource,
|
||||
.callback = mcb_lpc_create_platform_device,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table);
|
||||
|
||||
@@ -877,6 +877,8 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
|
||||
}
|
||||
}
|
||||
|
||||
#define MXC_V1_ECCBYTES 5
|
||||
|
||||
static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobregion)
|
||||
{
|
||||
@@ -886,7 +888,7 @@ static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
return -ERANGE;
|
||||
|
||||
oobregion->offset = (section * 16) + 6;
|
||||
oobregion->length = nand_chip->ecc.bytes;
|
||||
oobregion->length = MXC_V1_ECCBYTES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -908,8 +910,7 @@ static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
oobregion->length = 4;
|
||||
}
|
||||
} else {
|
||||
oobregion->offset = ((section - 1) * 16) +
|
||||
nand_chip->ecc.bytes + 6;
|
||||
oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
|
||||
if (section < nand_chip->ecc.steps)
|
||||
oobregion->length = (section * 16) + 6 -
|
||||
oobregion->offset;
|
||||
|
||||
@@ -109,7 +109,11 @@
|
||||
#define READ_ADDR 0
|
||||
|
||||
/* NAND_DEV_CMD_VLD bits */
|
||||
#define READ_START_VLD 0
|
||||
#define READ_START_VLD BIT(0)
|
||||
#define READ_STOP_VLD BIT(1)
|
||||
#define WRITE_START_VLD BIT(2)
|
||||
#define ERASE_START_VLD BIT(3)
|
||||
#define SEQ_READ_START_VLD BIT(4)
|
||||
|
||||
/* NAND_EBI2_ECC_BUF_CFG bits */
|
||||
#define NUM_STEPS 0
|
||||
@@ -148,6 +152,10 @@
|
||||
#define FETCH_ID 0xb
|
||||
#define RESET_DEVICE 0xd
|
||||
|
||||
/* Default Value for NAND_DEV_CMD_VLD */
|
||||
#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
|
||||
ERASE_START_VLD | SEQ_READ_START_VLD)
|
||||
|
||||
/*
|
||||
* the NAND controller performs reads/writes with ECC in 516 byte chunks.
|
||||
* the driver calls the chunks 'step' or 'codeword' interchangeably
|
||||
@@ -672,8 +680,7 @@ static int nandc_param(struct qcom_nand_host *host)
|
||||
|
||||
/* configure CMD1 and VLD for ONFI param probing */
|
||||
nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
|
||||
(nandc->vld & ~(1 << READ_START_VLD))
|
||||
| 0 << READ_START_VLD);
|
||||
(nandc->vld & ~READ_START_VLD));
|
||||
nandc_set_reg(nandc, NAND_DEV_CMD1,
|
||||
(nandc->cmd1 & ~(0xFF << READ_ADDR))
|
||||
| NAND_CMD_PARAM << READ_ADDR);
|
||||
@@ -1893,7 +1900,7 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
|
||||
| wide_bus << WIDE_FLASH
|
||||
| 1 << DEV0_CFG1_ECC_DISABLE;
|
||||
|
||||
host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
|
||||
host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
|
||||
| 0 << ECC_SW_RESET
|
||||
| host->cw_data << ECC_NUM_DATA_BYTES
|
||||
| 1 << ECC_FORCE_CLK_OPEN
|
||||
@@ -1972,13 +1979,14 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
|
||||
{
|
||||
/* kill onenand */
|
||||
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
|
||||
nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL);
|
||||
|
||||
/* enable ADM DMA */
|
||||
nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
|
||||
|
||||
/* save the original values of these registers */
|
||||
nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1);
|
||||
nandc->vld = nandc_read(nandc, NAND_DEV_CMD_VLD);
|
||||
nandc->vld = NAND_DEV_CMD_VLD_VAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1852,6 +1852,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
||||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
/* If firmware indicates Full Rx Reorder support it must be used in a
|
||||
* slightly different manner. Let HTT code know.
|
||||
*/
|
||||
ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
|
||||
ar->wmi.svc_map));
|
||||
|
||||
status = ath10k_htt_rx_alloc(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
|
||||
@@ -1964,12 +1970,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
||||
}
|
||||
}
|
||||
|
||||
/* If firmware indicates Full Rx Reorder support it must be used in a
|
||||
* slightly different manner. Let HTT code know.
|
||||
*/
|
||||
ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
|
||||
ar->wmi.svc_map));
|
||||
|
||||
status = ath10k_htt_rx_ring_refill(ar);
|
||||
if (status) {
|
||||
ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
|
||||
|
||||
@@ -429,6 +429,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
||||
{IWL_PCI_DEVICE(0x095B, 0x520A, iwl7265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x095A, 0x9000, iwl7265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x095A, 0x9400, iwl7265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x095A, 0x9E10, iwl7265_2ac_cfg)},
|
||||
|
||||
/* 8000 Series */
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
|
||||
|
||||
@@ -488,7 +488,7 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
|
||||
|
||||
entry += sizeof(__le16);
|
||||
chan->pa_points_per_curve = 8;
|
||||
memset(chan->curve_data, 0, sizeof(*chan->curve_data));
|
||||
memset(chan->curve_data, 0, sizeof(chan->curve_data));
|
||||
memcpy(chan->curve_data, entry,
|
||||
sizeof(struct p54_pa_curve_data_sample) *
|
||||
min((u8)8, curve_data->points_per_channel));
|
||||
|
||||
@@ -4188,7 +4188,7 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter)
|
||||
if (adapter->config_bands & BAND_A)
|
||||
n_channels_a = mwifiex_band_5ghz.n_channels;
|
||||
|
||||
adapter->num_in_chan_stats = max_t(u32, n_channels_bg, n_channels_a);
|
||||
adapter->num_in_chan_stats = n_channels_bg + n_channels_a;
|
||||
adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) *
|
||||
adapter->num_in_chan_stats);
|
||||
|
||||
|
||||
@@ -2479,6 +2479,12 @@ mwifiex_update_chan_statistics(struct mwifiex_private *priv,
|
||||
sizeof(struct mwifiex_chan_stats);
|
||||
|
||||
for (i = 0 ; i < num_chan; i++) {
|
||||
if (adapter->survey_idx >= adapter->num_in_chan_stats) {
|
||||
mwifiex_dbg(adapter, WARN,
|
||||
"FW reported too many channel results (max %d)\n",
|
||||
adapter->num_in_chan_stats);
|
||||
return;
|
||||
}
|
||||
chan_stats.chan_num = fw_chan_stats->chan_num;
|
||||
chan_stats.bandcfg = fw_chan_stats->bandcfg;
|
||||
chan_stats.flags = fw_chan_stats->flags;
|
||||
|
||||
@@ -2269,7 +2269,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
|
||||
/* find adapter */
|
||||
if (!_rtl_pci_find_adapter(pdev, hw)) {
|
||||
err = -ENODEV;
|
||||
goto fail3;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* Init IO handler */
|
||||
@@ -2339,10 +2339,10 @@ fail3:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
rtl_deinit_core(hw);
|
||||
|
||||
fail2:
|
||||
if (rtlpriv->io.pci_mem_start != 0)
|
||||
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
|
||||
|
||||
fail2:
|
||||
pci_release_regions(pdev);
|
||||
complete(&rtlpriv->firmware_loading_complete);
|
||||
|
||||
|
||||
@@ -1571,6 +1571,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
|
||||
|
||||
wl->state = WL1251_STATE_OFF;
|
||||
mutex_init(&wl->mutex);
|
||||
spin_lock_init(&wl->wl_lock);
|
||||
|
||||
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
|
||||
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
|
||||
|
||||
@@ -77,7 +77,7 @@ static struct nvmf_host *nvmf_host_default(void)
|
||||
kref_init(&host->ref);
|
||||
uuid_be_gen(&host->id);
|
||||
snprintf(host->nqn, NVMF_NQN_SIZE,
|
||||
"nqn.2014-08.org.nvmexpress:NVMf:uuid:%pUb", &host->id);
|
||||
"nqn.2014-08.org.nvmexpress:uuid:%pUb", &host->id);
|
||||
|
||||
mutex_lock(&nvmf_hosts_mutex);
|
||||
list_add_tail(&host->list, &nvmf_hosts);
|
||||
|
||||
@@ -66,6 +66,9 @@ const char *rnc_state_name(enum scis_sds_remote_node_context_states state)
|
||||
{
|
||||
static const char * const strings[] = RNC_STATES;
|
||||
|
||||
if (state >= ARRAY_SIZE(strings))
|
||||
return "UNKNOWN";
|
||||
|
||||
return strings[state];
|
||||
}
|
||||
#undef C
|
||||
|
||||
@@ -142,6 +142,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
|
||||
struct sg_device *parentdp; /* owning device */
|
||||
wait_queue_head_t read_wait; /* queue read until command done */
|
||||
rwlock_t rq_list_lock; /* protect access to list in req_arr */
|
||||
struct mutex f_mutex; /* protect against changes in this fd */
|
||||
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
|
||||
int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
|
||||
Sg_scatter_hold reserve; /* buffer held for this file descriptor */
|
||||
@@ -155,6 +156,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
|
||||
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
|
||||
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
|
||||
char mmap_called; /* 0 -> mmap() never called on this fd */
|
||||
char res_in_use; /* 1 -> 'reserve' array in use */
|
||||
struct kref f_ref;
|
||||
struct execute_work ew;
|
||||
} Sg_fd;
|
||||
@@ -198,7 +200,6 @@ static void sg_remove_sfp(struct kref *);
|
||||
static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
|
||||
static Sg_request *sg_add_request(Sg_fd * sfp);
|
||||
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
|
||||
static int sg_res_in_use(Sg_fd * sfp);
|
||||
static Sg_device *sg_get_dev(int dev);
|
||||
static void sg_device_destroy(struct kref *kref);
|
||||
|
||||
@@ -614,6 +615,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
|
||||
}
|
||||
buf += SZ_SG_HEADER;
|
||||
__get_user(opcode, buf);
|
||||
mutex_lock(&sfp->f_mutex);
|
||||
if (sfp->next_cmd_len > 0) {
|
||||
cmd_size = sfp->next_cmd_len;
|
||||
sfp->next_cmd_len = 0; /* reset so only this write() effected */
|
||||
@@ -622,6 +624,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
|
||||
if ((opcode >= 0xc0) && old_hdr.twelve_byte)
|
||||
cmd_size = 12;
|
||||
}
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
|
||||
"sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
|
||||
/* Determine buffer size. */
|
||||
@@ -721,7 +724,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
|
||||
sg_remove_request(sfp, srp);
|
||||
return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */
|
||||
}
|
||||
if (sg_res_in_use(sfp)) {
|
||||
if (sfp->res_in_use) {
|
||||
sg_remove_request(sfp, srp);
|
||||
return -EBUSY; /* reserve buffer already being used */
|
||||
}
|
||||
@@ -892,7 +895,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
||||
return result;
|
||||
if (val) {
|
||||
sfp->low_dma = 1;
|
||||
if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
|
||||
if ((0 == sfp->low_dma) && !sfp->res_in_use) {
|
||||
val = (int) sfp->reserve.bufflen;
|
||||
sg_remove_scat(sfp, &sfp->reserve);
|
||||
sg_build_reserve(sfp, val);
|
||||
@@ -967,12 +970,18 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
||||
return -EINVAL;
|
||||
val = min_t(int, val,
|
||||
max_sectors_bytes(sdp->device->request_queue));
|
||||
mutex_lock(&sfp->f_mutex);
|
||||
if (val != sfp->reserve.bufflen) {
|
||||
if (sg_res_in_use(sfp) || sfp->mmap_called)
|
||||
if (sfp->mmap_called ||
|
||||
sfp->res_in_use) {
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
sg_remove_scat(sfp, &sfp->reserve);
|
||||
sg_build_reserve(sfp, val);
|
||||
}
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
return 0;
|
||||
case SG_GET_RESERVED_SIZE:
|
||||
val = min_t(int, sfp->reserve.bufflen,
|
||||
@@ -1235,6 +1244,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
unsigned long req_sz, len, sa;
|
||||
Sg_scatter_hold *rsv_schp;
|
||||
int k, length;
|
||||
int ret = 0;
|
||||
|
||||
if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
|
||||
return -ENXIO;
|
||||
@@ -1245,8 +1255,11 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
if (vma->vm_pgoff)
|
||||
return -EINVAL; /* want no offset */
|
||||
rsv_schp = &sfp->reserve;
|
||||
if (req_sz > rsv_schp->bufflen)
|
||||
return -ENOMEM; /* cannot map more than reserved buffer */
|
||||
mutex_lock(&sfp->f_mutex);
|
||||
if (req_sz > rsv_schp->bufflen) {
|
||||
ret = -ENOMEM; /* cannot map more than reserved buffer */
|
||||
goto out;
|
||||
}
|
||||
|
||||
sa = vma->vm_start;
|
||||
length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
|
||||
@@ -1260,7 +1273,9 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
|
||||
vma->vm_private_data = sfp;
|
||||
vma->vm_ops = &sg_mmap_vm_ops;
|
||||
return 0;
|
||||
out:
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1727,13 +1742,25 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
|
||||
md = &map_data;
|
||||
|
||||
if (md) {
|
||||
if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
|
||||
mutex_lock(&sfp->f_mutex);
|
||||
if (dxfer_len <= rsv_schp->bufflen &&
|
||||
!sfp->res_in_use) {
|
||||
sfp->res_in_use = 1;
|
||||
sg_link_reserve(sfp, srp, dxfer_len);
|
||||
else {
|
||||
} else if (hp->flags & SG_FLAG_MMAP_IO) {
|
||||
res = -EBUSY; /* sfp->res_in_use == 1 */
|
||||
if (dxfer_len > rsv_schp->bufflen)
|
||||
res = -ENOMEM;
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
return res;
|
||||
} else {
|
||||
res = sg_build_indirect(req_schp, sfp, dxfer_len);
|
||||
if (res)
|
||||
if (res) {
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sfp->f_mutex);
|
||||
|
||||
md->pages = req_schp->pages;
|
||||
md->page_order = req_schp->page_order;
|
||||
@@ -2024,6 +2051,8 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
|
||||
req_schp->sglist_len = 0;
|
||||
sfp->save_scat_len = 0;
|
||||
srp->res_used = 0;
|
||||
/* Called without mutex lock to avoid deadlock */
|
||||
sfp->res_in_use = 0;
|
||||
}
|
||||
|
||||
static Sg_request *
|
||||
@@ -2135,6 +2164,7 @@ sg_add_sfp(Sg_device * sdp)
|
||||
rwlock_init(&sfp->rq_list_lock);
|
||||
|
||||
kref_init(&sfp->f_ref);
|
||||
mutex_init(&sfp->f_mutex);
|
||||
sfp->timeout = SG_DEFAULT_TIMEOUT;
|
||||
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
|
||||
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
|
||||
@@ -2210,20 +2240,6 @@ sg_remove_sfp(struct kref *kref)
|
||||
schedule_work(&sfp->ew.work);
|
||||
}
|
||||
|
||||
static int
|
||||
sg_res_in_use(Sg_fd * sfp)
|
||||
{
|
||||
const Sg_request *srp;
|
||||
unsigned long iflags;
|
||||
|
||||
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
for (srp = sfp->headrp; srp; srp = srp->nextrp)
|
||||
if (srp->res_used)
|
||||
break;
|
||||
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
return srp ? 1 : 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_PROC_FS
|
||||
static int
|
||||
sg_idr_max_id(int id, void *p, void *data)
|
||||
|
||||
@@ -400,7 +400,7 @@ static void fiq_debugger_work(struct work_struct *work)
|
||||
cmd += 6;
|
||||
while (*cmd == ' ')
|
||||
cmd++;
|
||||
if (cmd != '\0')
|
||||
if (*cmd != '\0')
|
||||
kernel_restart(cmd);
|
||||
else
|
||||
kernel_restart(NULL);
|
||||
|
||||
@@ -414,7 +414,7 @@ void set_sense_data(struct rtsx_chip *chip, unsigned int lun, u8 err_code,
|
||||
sense->ascq = ascq;
|
||||
if (sns_key_info0 != 0) {
|
||||
sense->sns_key_info[0] = SKSV | sns_key_info0;
|
||||
sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 8;
|
||||
sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 4;
|
||||
sense->sns_key_info[2] = sns_key_info1 & 0x0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,23 +269,12 @@ static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
|
||||
|
||||
int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
|
||||
{
|
||||
int i = 0;
|
||||
int ret = -1;
|
||||
struct wilc_vif *vif;
|
||||
struct wilc *wilc;
|
||||
struct wilc_vif *vif = netdev_priv(wilc_netdev);
|
||||
|
||||
vif = netdev_priv(wilc_netdev);
|
||||
wilc = vif->wilc;
|
||||
memcpy(vif->bssid, bssid, 6);
|
||||
vif->mode = mode;
|
||||
|
||||
for (i = 0; i < wilc->vif_num; i++)
|
||||
if (wilc->vif[i]->ndev == wilc_netdev) {
|
||||
memcpy(wilc->vif[i]->bssid, bssid, 6);
|
||||
wilc->vif[i]->mode = mode;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
|
||||
@@ -1212,16 +1201,11 @@ void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
|
||||
|
||||
void wilc_netdev_cleanup(struct wilc *wilc)
|
||||
{
|
||||
int i = 0;
|
||||
struct wilc_vif *vif[NUM_CONCURRENT_IFC];
|
||||
int i;
|
||||
|
||||
if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
|
||||
if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev))
|
||||
unregister_inetaddr_notifier(&g_dev_notifier);
|
||||
|
||||
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
|
||||
vif[i] = netdev_priv(wilc->vif[i]->ndev);
|
||||
}
|
||||
|
||||
if (wilc && wilc->firmware) {
|
||||
release_firmware(wilc->firmware);
|
||||
wilc->firmware = NULL;
|
||||
@@ -1230,7 +1214,7 @@ void wilc_netdev_cleanup(struct wilc *wilc)
|
||||
if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
|
||||
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
|
||||
if (wilc->vif[i]->ndev)
|
||||
if (vif[i]->mac_opened)
|
||||
if (wilc->vif[i]->mac_opened)
|
||||
wilc_mac_close(wilc->vif[i]->ndev);
|
||||
|
||||
for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
|
||||
@@ -1278,9 +1262,9 @@ int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
|
||||
|
||||
vif->idx = wl->vif_num;
|
||||
vif->wilc = *wilc;
|
||||
vif->ndev = ndev;
|
||||
wl->vif[i] = vif;
|
||||
wl->vif[wl->vif_num]->ndev = ndev;
|
||||
wl->vif_num++;
|
||||
wl->vif_num = i;
|
||||
ndev->netdev_ops = &wilc_netdev_ops;
|
||||
|
||||
{
|
||||
|
||||
@@ -629,6 +629,8 @@ static void async_completed(struct urb *urb)
|
||||
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
|
||||
as->status != -ENOENT)
|
||||
cancel_bulk_urbs(ps, as->bulk_addr);
|
||||
|
||||
wake_up(&ps->wait);
|
||||
spin_unlock(&ps->lock);
|
||||
|
||||
if (signr) {
|
||||
@@ -636,8 +638,6 @@ static void async_completed(struct urb *urb)
|
||||
put_pid(pid);
|
||||
put_cred(cred);
|
||||
}
|
||||
|
||||
wake_up(&ps->wait);
|
||||
}
|
||||
|
||||
static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
|
||||
|
||||
@@ -57,8 +57,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||
/* Microsoft LifeCam-VX700 v2.0 */
|
||||
{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* Logitech HD Pro Webcams C920 and C930e */
|
||||
/* Logitech HD Pro Webcams C920, C920-C and C930e */
|
||||
{ USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
{ USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
{ USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
/* Logitech ConferenceCam CC3000e */
|
||||
@@ -217,6 +218,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
|
||||
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
|
||||
|
||||
/* Corsair Strafe RGB */
|
||||
{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
/* Acer C120 LED Projector */
|
||||
{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
|
||||
|
||||
|
||||
@@ -142,29 +142,30 @@ static int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_SB700;
|
||||
else if (rev >= 0x40 && rev <= 0x4f)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_SB800;
|
||||
}
|
||||
pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x145c, NULL);
|
||||
if (pinfo->smbus_dev) {
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
|
||||
} else {
|
||||
pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
|
||||
|
||||
if (!pinfo->smbus_dev) {
|
||||
pinfo->sb_type.gen = NOT_AMD_CHIPSET;
|
||||
return 0;
|
||||
if (pinfo->smbus_dev) {
|
||||
rev = pinfo->smbus_dev->revision;
|
||||
if (rev >= 0x11 && rev <= 0x14)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2;
|
||||
else if (rev >= 0x15 && rev <= 0x18)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_BOLTON;
|
||||
else if (rev >= 0x39 && rev <= 0x3a)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;
|
||||
} else {
|
||||
pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x145c, NULL);
|
||||
if (pinfo->smbus_dev) {
|
||||
rev = pinfo->smbus_dev->revision;
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
|
||||
} else {
|
||||
pinfo->sb_type.gen = NOT_AMD_CHIPSET;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rev = pinfo->smbus_dev->revision;
|
||||
if (rev >= 0x11 && rev <= 0x14)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2;
|
||||
else if (rev >= 0x15 && rev <= 0x18)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_BOLTON;
|
||||
else if (rev >= 0x39 && rev <= 0x3a)
|
||||
pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;
|
||||
}
|
||||
|
||||
pinfo->sb_type.rev = rev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2655,6 +2655,13 @@ static int musb_suspend(struct device *dev)
|
||||
{
|
||||
struct musb *musb = dev_to_musb(dev);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
musb_platform_disable(musb);
|
||||
musb_generic_disable(musb);
|
||||
@@ -2703,14 +2710,6 @@ static int musb_resume(struct device *dev)
|
||||
if ((devctl & mask) != (musb->context.devctl & mask))
|
||||
musb->port1_status = 0;
|
||||
|
||||
/*
|
||||
* The USB HUB code expects the device to be in RPM_ACTIVE once it came
|
||||
* out of suspend
|
||||
*/
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
musb_start(musb);
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
@@ -2720,6 +2719,9 @@ static int musb_resume(struct device *dev)
|
||||
error);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2023,6 +2023,7 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) }, /* D-Link DWM-157 C1 */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */
|
||||
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */
|
||||
|
||||
@@ -1834,6 +1834,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
goto restore;
|
||||
}
|
||||
|
||||
btrfs_qgroup_rescan_resume(fs_info);
|
||||
|
||||
if (!fs_info->uuid_root) {
|
||||
btrfs_info(fs_info, "creating UUID tree");
|
||||
ret = btrfs_create_uuid_tree(fs_info);
|
||||
|
||||
@@ -188,7 +188,7 @@ static int ceph_releasepage(struct page *page, gfp_t g)
|
||||
/*
|
||||
* read a single page, without unlocking it.
|
||||
*/
|
||||
static int readpage_nounlock(struct file *filp, struct page *page)
|
||||
static int ceph_do_readpage(struct file *filp, struct page *page)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
@@ -218,7 +218,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
|
||||
|
||||
err = ceph_readpage_from_fscache(inode, page);
|
||||
if (err == 0)
|
||||
goto out;
|
||||
return -EINPROGRESS;
|
||||
|
||||
dout("readpage inode %p file %p page %p index %lu\n",
|
||||
inode, filp, page, page->index);
|
||||
@@ -248,8 +248,11 @@ out:
|
||||
|
||||
static int ceph_readpage(struct file *filp, struct page *page)
|
||||
{
|
||||
int r = readpage_nounlock(filp, page);
|
||||
unlock_page(page);
|
||||
int r = ceph_do_readpage(filp, page);
|
||||
if (r != -EINPROGRESS)
|
||||
unlock_page(page);
|
||||
else
|
||||
r = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1235,7 +1238,7 @@ retry_locked:
|
||||
goto retry_locked;
|
||||
r = writepage_nounlock(page, NULL);
|
||||
if (r < 0)
|
||||
goto fail_nosnap;
|
||||
goto fail_unlock;
|
||||
goto retry_locked;
|
||||
}
|
||||
|
||||
@@ -1263,11 +1266,14 @@ retry_locked:
|
||||
}
|
||||
|
||||
/* we need to read it. */
|
||||
r = readpage_nounlock(file, page);
|
||||
if (r < 0)
|
||||
goto fail_nosnap;
|
||||
r = ceph_do_readpage(file, page);
|
||||
if (r < 0) {
|
||||
if (r == -EINPROGRESS)
|
||||
return -EAGAIN;
|
||||
goto fail_unlock;
|
||||
}
|
||||
goto retry_locked;
|
||||
fail_nosnap:
|
||||
fail_unlock:
|
||||
unlock_page(page);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -240,13 +240,7 @@ void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)
|
||||
}
|
||||
}
|
||||
|
||||
static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
|
||||
{
|
||||
if (!error)
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
|
||||
static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
|
||||
static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
|
||||
{
|
||||
if (!error)
|
||||
SetPageUptodate(page);
|
||||
@@ -274,7 +268,7 @@ int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
|
||||
return -ENOBUFS;
|
||||
|
||||
ret = fscache_read_or_alloc_page(ci->fscache, page,
|
||||
ceph_vfs_readpage_complete, NULL,
|
||||
ceph_readpage_from_fscache_complete, NULL,
|
||||
GFP_KERNEL);
|
||||
|
||||
switch (ret) {
|
||||
@@ -303,7 +297,7 @@ int ceph_readpages_from_fscache(struct inode *inode,
|
||||
return -ENOBUFS;
|
||||
|
||||
ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
|
||||
ceph_vfs_readpage_complete_unlock,
|
||||
ceph_readpage_from_fscache_complete,
|
||||
NULL, mapping_gfp_mask(mapping));
|
||||
|
||||
switch (ret) {
|
||||
|
||||
@@ -194,7 +194,7 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
|
||||
int i;
|
||||
|
||||
if (unlikely(direntry->d_name.len >
|
||||
tcon->fsAttrInfo.MaxPathNameComponentLength))
|
||||
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
|
||||
|
||||
@@ -84,8 +84,8 @@
|
||||
|
||||
#define NUMBER_OF_SMB2_COMMANDS 0x0013
|
||||
|
||||
/* BB FIXME - analyze following length BB */
|
||||
#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
|
||||
/* 4 len + 52 transform hdr + 64 hdr + 56 create rsp */
|
||||
#define MAX_SMB2_HDR_SIZE 0x00b0
|
||||
|
||||
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
|
||||
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
|
||||
|
||||
@@ -355,6 +355,10 @@ static int dlm_device_register(struct dlm_ls *ls, char *name)
|
||||
error = misc_register(&ls->ls_device);
|
||||
if (error) {
|
||||
kfree(ls->ls_device.name);
|
||||
/* this has to be set to NULL
|
||||
* to avoid a double-free in dlm_device_deregister
|
||||
*/
|
||||
ls->ls_device.name = NULL;
|
||||
}
|
||||
fail:
|
||||
return error;
|
||||
|
||||
@@ -524,8 +524,13 @@ static void ep_remove_wait_queue(struct eppoll_entry *pwq)
|
||||
wait_queue_head_t *whead;
|
||||
|
||||
rcu_read_lock();
|
||||
/* If it is cleared by POLLFREE, it should be rcu-safe */
|
||||
whead = rcu_dereference(pwq->whead);
|
||||
/*
|
||||
* If it is cleared by POLLFREE, it should be rcu-safe.
|
||||
* If we read NULL we need a barrier paired with
|
||||
* smp_store_release() in ep_poll_callback(), otherwise
|
||||
* we rely on whead->lock.
|
||||
*/
|
||||
whead = smp_load_acquire(&pwq->whead);
|
||||
if (whead)
|
||||
remove_wait_queue(whead, &pwq->wait);
|
||||
rcu_read_unlock();
|
||||
@@ -1010,17 +1015,6 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
|
||||
struct eventpoll *ep = epi->ep;
|
||||
int ewake = 0;
|
||||
|
||||
if ((unsigned long)key & POLLFREE) {
|
||||
ep_pwq_from_wait(wait)->whead = NULL;
|
||||
/*
|
||||
* whead = NULL above can race with ep_remove_wait_queue()
|
||||
* which can do another remove_wait_queue() after us, so we
|
||||
* can't use __remove_wait_queue(). whead->lock is held by
|
||||
* the caller.
|
||||
*/
|
||||
list_del_init(&wait->task_list);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
|
||||
/*
|
||||
@@ -1102,10 +1096,26 @@ out_unlock:
|
||||
if (pwake)
|
||||
ep_poll_safewake(&ep->poll_wait);
|
||||
|
||||
if (epi->event.events & EPOLLEXCLUSIVE)
|
||||
return ewake;
|
||||
if (!(epi->event.events & EPOLLEXCLUSIVE))
|
||||
ewake = 1;
|
||||
|
||||
return 1;
|
||||
if ((unsigned long)key & POLLFREE) {
|
||||
/*
|
||||
* If we race with ep_remove_wait_queue() it can miss
|
||||
* ->whead = NULL and do another remove_wait_queue() after
|
||||
* us, so we can't use __remove_wait_queue().
|
||||
*/
|
||||
list_del_init(&wait->task_list);
|
||||
/*
|
||||
* ->whead != NULL protects us from the race with ep_free()
|
||||
* or ep_remove(), ep_remove_wait_queue() takes whead->lock
|
||||
* held by the caller. Once we nullify it, nothing protects
|
||||
* ep/epi or even wait.
|
||||
*/
|
||||
smp_store_release(&ep_pwq_from_wait(wait)->whead, NULL);
|
||||
}
|
||||
|
||||
return ewake;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -227,6 +227,7 @@ static struct mount *alloc_vfsmnt(const char *name)
|
||||
mnt->mnt_count = 1;
|
||||
mnt->mnt_writers = 0;
|
||||
#endif
|
||||
mnt->mnt.data = NULL;
|
||||
|
||||
INIT_HLIST_NODE(&mnt->mnt_hash);
|
||||
INIT_LIST_HEAD(&mnt->mnt_child);
|
||||
@@ -976,7 +977,6 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
||||
if (!mnt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mnt->mnt.data = NULL;
|
||||
if (type->alloc_mnt_data) {
|
||||
mnt->mnt.data = type->alloc_mnt_data();
|
||||
if (!mnt->mnt.data) {
|
||||
@@ -990,7 +990,6 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
||||
|
||||
root = mount_fs(type, flags, name, &mnt->mnt, data);
|
||||
if (IS_ERR(root)) {
|
||||
kfree(mnt->mnt.data);
|
||||
mnt_free_id(mnt);
|
||||
free_vfsmnt(mnt);
|
||||
return ERR_CAST(root);
|
||||
@@ -1109,7 +1108,6 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
|
||||
return mnt;
|
||||
|
||||
out_free:
|
||||
kfree(mnt->mnt.data);
|
||||
mnt_free_id(mnt);
|
||||
free_vfsmnt(mnt);
|
||||
return ERR_PTR(err);
|
||||
|
||||
@@ -636,11 +636,11 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (result <= 0)
|
||||
goto out;
|
||||
|
||||
result = generic_write_sync(iocb, result);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
written = result;
|
||||
iocb->ki_pos += written;
|
||||
result = generic_write_sync(iocb, written);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
|
||||
/* Return error values */
|
||||
if (nfs_need_check_write(file, inode)) {
|
||||
|
||||
@@ -248,7 +248,6 @@ int nfs_iocounter_wait(struct nfs_lock_context *l_ctx);
|
||||
extern const struct nfs_pageio_ops nfs_pgio_rw_ops;
|
||||
struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
|
||||
void nfs_pgio_header_free(struct nfs_pgio_header *);
|
||||
void nfs_pgio_data_destroy(struct nfs_pgio_header *);
|
||||
int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
|
||||
int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
|
||||
struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
|
||||
|
||||
@@ -497,16 +497,6 @@ struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *ops)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc);
|
||||
|
||||
/*
|
||||
* nfs_pgio_header_free - Free a read or write header
|
||||
* @hdr: The header to free
|
||||
*/
|
||||
void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
hdr->rw_ops->rw_free_header(hdr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
|
||||
|
||||
/**
|
||||
* nfs_pgio_data_destroy - make @hdr suitable for reuse
|
||||
*
|
||||
@@ -515,14 +505,24 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
|
||||
*
|
||||
* @hdr: A header that has had nfs_generic_pgio called
|
||||
*/
|
||||
void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
|
||||
static void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
if (hdr->args.context)
|
||||
put_nfs_open_context(hdr->args.context);
|
||||
if (hdr->page_array.pagevec != hdr->page_array.page_array)
|
||||
kfree(hdr->page_array.pagevec);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy);
|
||||
|
||||
/*
|
||||
* nfs_pgio_header_free - Free a read or write header
|
||||
* @hdr: The header to free
|
||||
*/
|
||||
void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
nfs_pgio_data_destroy(hdr);
|
||||
hdr->rw_ops->rw_free_header(hdr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
|
||||
|
||||
/**
|
||||
* nfs_pgio_rpcsetup - Set up arguments for a pageio call
|
||||
@@ -636,7 +636,6 @@ EXPORT_SYMBOL_GPL(nfs_initiate_pgio);
|
||||
static void nfs_pgio_error(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
set_bit(NFS_IOHDR_REDO, &hdr->flags);
|
||||
nfs_pgio_data_destroy(hdr);
|
||||
hdr->completion_ops->completion(hdr);
|
||||
}
|
||||
|
||||
@@ -647,7 +646,6 @@ static void nfs_pgio_error(struct nfs_pgio_header *hdr)
|
||||
static void nfs_pgio_release(void *calldata)
|
||||
{
|
||||
struct nfs_pgio_header *hdr = calldata;
|
||||
nfs_pgio_data_destroy(hdr);
|
||||
hdr->completion_ops->completion(hdr);
|
||||
}
|
||||
|
||||
|
||||
@@ -2145,7 +2145,6 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
|
||||
nfs_pageio_reset_write_mds(desc);
|
||||
mirror->pg_recoalesce = 1;
|
||||
}
|
||||
nfs_pgio_data_destroy(hdr);
|
||||
hdr->release(hdr);
|
||||
}
|
||||
|
||||
@@ -2257,7 +2256,6 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
|
||||
nfs_pageio_reset_read_mds(desc);
|
||||
mirror->pg_recoalesce = 1;
|
||||
}
|
||||
nfs_pgio_data_destroy(hdr);
|
||||
hdr->release(hdr);
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,9 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name)
|
||||
gid_t gid = sbi->options.fs_low_gid;
|
||||
struct iattr newattrs;
|
||||
|
||||
if (!sbi->options.gid_derivation)
|
||||
return;
|
||||
|
||||
info = SDCARDFS_I(d_inode(dentry));
|
||||
info_d = info->data;
|
||||
perm = info_d->perm;
|
||||
|
||||
@@ -34,10 +34,14 @@ const struct cred *override_fsids(struct sdcardfs_sb_info *sbi,
|
||||
if (!cred)
|
||||
return NULL;
|
||||
|
||||
if (data->under_obb)
|
||||
uid = AID_MEDIA_OBB;
|
||||
else
|
||||
uid = multiuser_get_uid(data->userid, sbi->options.fs_low_uid);
|
||||
if (sbi->options.gid_derivation) {
|
||||
if (data->under_obb)
|
||||
uid = AID_MEDIA_OBB;
|
||||
else
|
||||
uid = multiuser_get_uid(data->userid, sbi->options.fs_low_uid);
|
||||
} else {
|
||||
uid = sbi->options.fs_low_uid;
|
||||
}
|
||||
cred->fsuid = make_kuid(&init_user_ns, uid);
|
||||
cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid);
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ enum {
|
||||
Opt_multiuser,
|
||||
Opt_userid,
|
||||
Opt_reserved_mb,
|
||||
Opt_gid_derivation,
|
||||
Opt_err,
|
||||
};
|
||||
|
||||
@@ -43,6 +44,7 @@ static const match_table_t sdcardfs_tokens = {
|
||||
{Opt_mask, "mask=%u"},
|
||||
{Opt_userid, "userid=%d"},
|
||||
{Opt_multiuser, "multiuser"},
|
||||
{Opt_gid_derivation, "derive_gid"},
|
||||
{Opt_reserved_mb, "reserved_mb=%u"},
|
||||
{Opt_err, NULL}
|
||||
};
|
||||
@@ -64,6 +66,8 @@ static int parse_options(struct super_block *sb, char *options, int silent,
|
||||
vfsopts->gid = 0;
|
||||
/* by default, 0MB is reserved */
|
||||
opts->reserved_mb = 0;
|
||||
/* by default, gid derivation is off */
|
||||
opts->gid_derivation = false;
|
||||
|
||||
*debug = 0;
|
||||
|
||||
@@ -115,6 +119,9 @@ static int parse_options(struct super_block *sb, char *options, int silent,
|
||||
return 0;
|
||||
opts->reserved_mb = option;
|
||||
break;
|
||||
case Opt_gid_derivation:
|
||||
opts->gid_derivation = true;
|
||||
break;
|
||||
/* unknown option */
|
||||
default:
|
||||
if (!silent)
|
||||
|
||||
@@ -219,6 +219,7 @@ struct sdcardfs_mount_options {
|
||||
gid_t fs_low_gid;
|
||||
userid_t fs_user_id;
|
||||
bool multiuser;
|
||||
bool gid_derivation;
|
||||
unsigned int reserved_mb;
|
||||
};
|
||||
|
||||
|
||||
@@ -302,6 +302,8 @@ static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m,
|
||||
seq_printf(m, ",mask=%u", vfsopts->mask);
|
||||
if (opts->fs_user_id)
|
||||
seq_printf(m, ",userid=%u", opts->fs_user_id);
|
||||
if (opts->gid_derivation)
|
||||
seq_puts(m, ",derive_gid");
|
||||
if (opts->reserved_mb != 0)
|
||||
seq_printf(m, ",reserved=%uMB", opts->reserved_mb);
|
||||
|
||||
|
||||
@@ -363,7 +363,14 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
|
||||
|
||||
/*
|
||||
* make sure we ignore the inode flag if the filesystem doesn't have a
|
||||
* configured realtime device.
|
||||
*/
|
||||
#define XFS_IS_REALTIME_INODE(ip) \
|
||||
(((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) && \
|
||||
(ip)->i_mount->m_rtdev_targp)
|
||||
#else
|
||||
#define XFS_IS_REALTIME_INODE(ip) (0)
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,11 @@
|
||||
#define parent_node(node) ((void)(node),0)
|
||||
#endif
|
||||
#ifndef cpumask_of_node
|
||||
#define cpumask_of_node(node) ((void)node, cpu_online_mask)
|
||||
#ifdef CONFIG_NEED_MULTIPLE_NODES
|
||||
#define cpumask_of_node(node) ((node) == 0 ? cpu_online_mask : cpu_none_mask)
|
||||
#else
|
||||
#define cpumask_of_node(node) ((void)node, cpu_online_mask)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef pcibus_to_node
|
||||
#define pcibus_to_node(bus) ((void)(bus), -1)
|
||||
|
||||
@@ -574,6 +574,7 @@
|
||||
#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095
|
||||
#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
|
||||
#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
|
||||
#define PCI_DEVICE_ID_AMD_CS5536_DEV_IDE 0x2092
|
||||
#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
|
||||
#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
|
||||
#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
|
||||
|
||||
@@ -311,8 +311,8 @@ enum {
|
||||
|
||||
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
|
||||
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
|
||||
__WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */
|
||||
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
|
||||
__WQ_ORDERED_EXPLICIT = 1 << 19, /* internal: alloc_ordered_workqueue() */
|
||||
|
||||
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
|
||||
WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
|
||||
|
||||
@@ -37,6 +37,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
CONFIG_IP6_NF_MATCH_RPFILTER=y
|
||||
CONFIG_IP6_NF_RAW=y
|
||||
CONFIG_IP6_NF_TARGET_REJECT=y
|
||||
CONFIG_IPV6=y
|
||||
@@ -149,7 +150,7 @@ CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_SYNC_FILE=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_UID_SYS_STATS=y
|
||||
CONFIG_UNIX=y
|
||||
|
||||
@@ -1908,6 +1908,7 @@ static struct cftype files[] = {
|
||||
{
|
||||
.name = "memory_pressure",
|
||||
.read_u64 = cpuset_read_u64,
|
||||
.private = FILE_MEMORY_PRESSURE,
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -1254,8 +1254,6 @@ void uprobe_end_dup_mmap(void)
|
||||
|
||||
void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
|
||||
{
|
||||
newmm->uprobes_state.xol_area = NULL;
|
||||
|
||||
if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) {
|
||||
set_bit(MMF_HAS_UPROBES, &newmm->flags);
|
||||
/* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */
|
||||
|
||||
@@ -745,6 +745,13 @@ static void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mm_init_uprobes_state(struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_UPROBES
|
||||
mm->uprobes_state.xol_area = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
|
||||
struct user_namespace *user_ns)
|
||||
{
|
||||
@@ -772,6 +779,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
|
||||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
|
||||
mm->pmd_huge_pte = NULL;
|
||||
#endif
|
||||
mm_init_uprobes_state(mm);
|
||||
|
||||
if (current->mm) {
|
||||
mm->flags = current->mm->flags & MMF_INIT_MASK;
|
||||
|
||||
@@ -98,6 +98,12 @@ void __gcov_merge_icall_topn(gcov_type *counters, unsigned int n_counters)
|
||||
}
|
||||
EXPORT_SYMBOL(__gcov_merge_icall_topn);
|
||||
|
||||
void __gcov_exit(void)
|
||||
{
|
||||
/* Unused. */
|
||||
}
|
||||
EXPORT_SYMBOL(__gcov_exit);
|
||||
|
||||
/**
|
||||
* gcov_enable_events - enable event reporting through gcov_event()
|
||||
*
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include "gcov.h"
|
||||
|
||||
#if (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
|
||||
#if (__GNUC__ >= 7)
|
||||
#define GCOV_COUNTERS 9
|
||||
#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
|
||||
#define GCOV_COUNTERS 10
|
||||
#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
|
||||
#define GCOV_COUNTERS 9
|
||||
|
||||
@@ -780,6 +780,10 @@ static void lock_torture_cleanup(void)
|
||||
else
|
||||
lock_torture_print_module_parms(cxt.cur_ops,
|
||||
"End of test: SUCCESS");
|
||||
|
||||
kfree(cxt.lwsa);
|
||||
kfree(cxt.lrsa);
|
||||
|
||||
end:
|
||||
torture_cleanup_end();
|
||||
}
|
||||
@@ -924,6 +928,8 @@ static int __init lock_torture_init(void)
|
||||
GFP_KERNEL);
|
||||
if (reader_tasks == NULL) {
|
||||
VERBOSE_TOROUT_ERRSTRING("reader_tasks: Out of memory");
|
||||
kfree(writer_tasks);
|
||||
writer_tasks = NULL;
|
||||
firsterr = -ENOMEM;
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
@@ -103,38 +103,14 @@ static inline void debug_spin_unlock(raw_spinlock_t *lock)
|
||||
lock->owner_cpu = -1;
|
||||
}
|
||||
|
||||
static void __spin_lock_debug(raw_spinlock_t *lock)
|
||||
{
|
||||
u64 i;
|
||||
u64 loops = loops_per_jiffy * HZ;
|
||||
|
||||
for (i = 0; i < loops; i++) {
|
||||
if (arch_spin_trylock(&lock->raw_lock))
|
||||
return;
|
||||
__delay(1);
|
||||
}
|
||||
/* lockup suspected: */
|
||||
spin_dump(lock, "lockup suspected");
|
||||
#ifdef CONFIG_SMP
|
||||
trigger_all_cpu_backtrace();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The trylock above was causing a livelock. Give the lower level arch
|
||||
* specific lock code a chance to acquire the lock. We have already
|
||||
* printed a warning/backtrace at this point. The non-debug arch
|
||||
* specific code might actually succeed in acquiring the lock. If it is
|
||||
* not successful, the end-result is the same - there is no forward
|
||||
* progress.
|
||||
*/
|
||||
arch_spin_lock(&lock->raw_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are now relying on the NMI watchdog to detect lockup instead of doing
|
||||
* the detection here with an unfair lock which can cause problem of its own.
|
||||
*/
|
||||
void do_raw_spin_lock(raw_spinlock_t *lock)
|
||||
{
|
||||
debug_spin_lock_before(lock);
|
||||
if (unlikely(!arch_spin_trylock(&lock->raw_lock)))
|
||||
__spin_lock_debug(lock);
|
||||
arch_spin_lock(&lock->raw_lock);
|
||||
debug_spin_lock_after(lock);
|
||||
}
|
||||
|
||||
@@ -172,32 +148,6 @@ static void rwlock_bug(rwlock_t *lock, const char *msg)
|
||||
|
||||
#define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg)
|
||||
|
||||
#if 0 /* __write_lock_debug() can lock up - maybe this can too? */
|
||||
static void __read_lock_debug(rwlock_t *lock)
|
||||
{
|
||||
u64 i;
|
||||
u64 loops = loops_per_jiffy * HZ;
|
||||
int print_once = 1;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < loops; i++) {
|
||||
if (arch_read_trylock(&lock->raw_lock))
|
||||
return;
|
||||
__delay(1);
|
||||
}
|
||||
/* lockup suspected: */
|
||||
if (print_once) {
|
||||
print_once = 0;
|
||||
printk(KERN_EMERG "BUG: read-lock lockup on CPU#%d, "
|
||||
"%s/%d, %p\n",
|
||||
raw_smp_processor_id(), current->comm,
|
||||
current->pid, lock);
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_raw_read_lock(rwlock_t *lock)
|
||||
{
|
||||
RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
|
||||
@@ -247,32 +197,6 @@ static inline void debug_write_unlock(rwlock_t *lock)
|
||||
lock->owner_cpu = -1;
|
||||
}
|
||||
|
||||
#if 0 /* This can cause lockups */
|
||||
static void __write_lock_debug(rwlock_t *lock)
|
||||
{
|
||||
u64 i;
|
||||
u64 loops = loops_per_jiffy * HZ;
|
||||
int print_once = 1;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < loops; i++) {
|
||||
if (arch_write_trylock(&lock->raw_lock))
|
||||
return;
|
||||
__delay(1);
|
||||
}
|
||||
/* lockup suspected: */
|
||||
if (print_once) {
|
||||
print_once = 0;
|
||||
printk(KERN_EMERG "BUG: write-lock lockup on CPU#%d, "
|
||||
"%s/%d, %p\n",
|
||||
raw_smp_processor_id(), current->comm,
|
||||
current->pid, lock);
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_raw_write_lock(rwlock_t *lock)
|
||||
{
|
||||
debug_write_lock_before(lock);
|
||||
|
||||
@@ -131,7 +131,7 @@ static inline int lz4hc_insertandfindbestmatch(struct lz4hc_data *hc4,
|
||||
#endif
|
||||
int nbattempts = MAX_NB_ATTEMPTS;
|
||||
size_t repl = 0, ml = 0;
|
||||
u16 delta;
|
||||
u16 delta = 0;
|
||||
|
||||
/* HC4 match finder */
|
||||
lz4hc_insert(hc4, ip);
|
||||
|
||||
@@ -364,11 +364,11 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes)
|
||||
}
|
||||
|
||||
miter.consumed = lzeros;
|
||||
sg_miter_stop(&miter);
|
||||
|
||||
nbytes -= lzeros;
|
||||
nbits = nbytes * 8;
|
||||
if (nbits > MAX_EXTERN_MPI_BITS) {
|
||||
sg_miter_stop(&miter);
|
||||
pr_info("MPI: mpi too large (%u bits)\n", nbits);
|
||||
return NULL;
|
||||
}
|
||||
@@ -376,6 +376,8 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes)
|
||||
if (nbytes > 0)
|
||||
nbits -= count_leading_zeros(*buff) - (BITS_PER_LONG - 8);
|
||||
|
||||
sg_miter_stop(&miter);
|
||||
|
||||
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
|
||||
val = mpi_alloc(nlimbs);
|
||||
if (!val)
|
||||
|
||||
@@ -533,6 +533,8 @@ static long madvise_remove(struct vm_area_struct *vma,
|
||||
static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
|
||||
{
|
||||
struct page *p;
|
||||
struct zone *zone;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
for (; start < end; start += PAGE_SIZE <<
|
||||
@@ -561,6 +563,11 @@ static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Ensure that all poisoned pages are removed from per-cpu lists */
|
||||
for_each_populated_zone(zone)
|
||||
drain_all_pages(zone);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
10
mm/memory.c
10
mm/memory.c
@@ -3596,6 +3596,11 @@ int handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
|
||||
/* do counter updates before entering really critical section. */
|
||||
check_sync_rss_stat(current);
|
||||
|
||||
if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
|
||||
flags & FAULT_FLAG_INSTRUCTION,
|
||||
flags & FAULT_FLAG_REMOTE))
|
||||
return VM_FAULT_SIGSEGV;
|
||||
|
||||
/*
|
||||
* Enable the memcg OOM handling for faults triggered in user
|
||||
* space. Kernel faults are handled more gracefully.
|
||||
@@ -3603,11 +3608,6 @@ int handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
|
||||
if (flags & FAULT_FLAG_USER)
|
||||
mem_cgroup_oom_enable();
|
||||
|
||||
if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
|
||||
flags & FAULT_FLAG_INSTRUCTION,
|
||||
flags & FAULT_FLAG_REMOTE))
|
||||
return VM_FAULT_SIGSEGV;
|
||||
|
||||
if (unlikely(is_vm_hugetlb_page(vma)))
|
||||
ret = hugetlb_fault(vma->vm_mm, vma, address, flags);
|
||||
else
|
||||
|
||||
@@ -58,7 +58,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
||||
u8 code, u8 ident, u16 dlen, void *data);
|
||||
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
|
||||
void *data);
|
||||
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
|
||||
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size);
|
||||
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
|
||||
|
||||
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
||||
@@ -1473,7 +1473,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, buf), buf);
|
||||
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -2977,12 +2977,15 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
|
||||
return len;
|
||||
}
|
||||
|
||||
static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
|
||||
static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val, size_t size)
|
||||
{
|
||||
struct l2cap_conf_opt *opt = *ptr;
|
||||
|
||||
BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val);
|
||||
|
||||
if (size < L2CAP_CONF_OPT_SIZE + len)
|
||||
return;
|
||||
|
||||
opt->type = type;
|
||||
opt->len = len;
|
||||
|
||||
@@ -3007,7 +3010,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
|
||||
*ptr += L2CAP_CONF_OPT_SIZE + len;
|
||||
}
|
||||
|
||||
static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
|
||||
static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan, size_t size)
|
||||
{
|
||||
struct l2cap_conf_efs efs;
|
||||
|
||||
@@ -3035,7 +3038,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
|
||||
}
|
||||
|
||||
l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
|
||||
(unsigned long) &efs);
|
||||
(unsigned long) &efs, size);
|
||||
}
|
||||
|
||||
static void l2cap_ack_timeout(struct work_struct *work)
|
||||
@@ -3181,11 +3184,12 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
|
||||
chan->ack_win = chan->tx_win;
|
||||
}
|
||||
|
||||
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
|
||||
{
|
||||
struct l2cap_conf_req *req = data;
|
||||
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
|
||||
void *ptr = req->data;
|
||||
void *endptr = data + data_size;
|
||||
u16 size;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
@@ -3210,7 +3214,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
|
||||
done:
|
||||
if (chan->imtu != L2CAP_DEFAULT_MTU)
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
|
||||
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
@@ -3229,7 +3233,7 @@ done:
|
||||
rfc.max_pdu_size = 0;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
(unsigned long) &rfc);
|
||||
(unsigned long) &rfc, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_MODE_ERTM:
|
||||
@@ -3249,21 +3253,21 @@ done:
|
||||
L2CAP_DEFAULT_TX_WINDOW);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
(unsigned long) &rfc);
|
||||
(unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
||||
l2cap_add_opt_efs(&ptr, chan);
|
||||
l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
||||
chan->tx_win);
|
||||
chan->tx_win, endptr - ptr);
|
||||
|
||||
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
||||
chan->fcs);
|
||||
chan->fcs, endptr - ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3281,17 +3285,17 @@ done:
|
||||
rfc.max_pdu_size = cpu_to_le16(size);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
(unsigned long) &rfc);
|
||||
(unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
||||
l2cap_add_opt_efs(&ptr, chan);
|
||||
l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
|
||||
|
||||
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
||||
chan->fcs);
|
||||
chan->fcs, endptr - ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3302,10 +3306,11 @@ done:
|
||||
return ptr - data;
|
||||
}
|
||||
|
||||
static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
|
||||
{
|
||||
struct l2cap_conf_rsp *rsp = data;
|
||||
void *ptr = rsp->data;
|
||||
void *endptr = data + data_size;
|
||||
void *req = chan->conf_req;
|
||||
int len = chan->conf_len;
|
||||
int type, hint, olen;
|
||||
@@ -3407,7 +3412,7 @@ done:
|
||||
return -ECONNREFUSED;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
(unsigned long) &rfc);
|
||||
(unsigned long) &rfc, endptr - ptr);
|
||||
}
|
||||
|
||||
if (result == L2CAP_CONF_SUCCESS) {
|
||||
@@ -3420,7 +3425,7 @@ done:
|
||||
chan->omtu = mtu;
|
||||
set_bit(CONF_MTU_DONE, &chan->conf_state);
|
||||
}
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu, endptr - ptr);
|
||||
|
||||
if (remote_efs) {
|
||||
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
|
||||
@@ -3434,7 +3439,7 @@ done:
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
|
||||
sizeof(efs),
|
||||
(unsigned long) &efs);
|
||||
(unsigned long) &efs, endptr - ptr);
|
||||
} else {
|
||||
/* Send PENDING Conf Rsp */
|
||||
result = L2CAP_CONF_PENDING;
|
||||
@@ -3467,7 +3472,7 @@ done:
|
||||
set_bit(CONF_MODE_DONE, &chan->conf_state);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
||||
sizeof(rfc), (unsigned long) &rfc);
|
||||
sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
|
||||
chan->remote_id = efs.id;
|
||||
@@ -3481,7 +3486,7 @@ done:
|
||||
le32_to_cpu(efs.sdu_itime);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
|
||||
sizeof(efs),
|
||||
(unsigned long) &efs);
|
||||
(unsigned long) &efs, endptr - ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3495,7 +3500,7 @@ done:
|
||||
set_bit(CONF_MODE_DONE, &chan->conf_state);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
(unsigned long) &rfc);
|
||||
(unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
break;
|
||||
|
||||
@@ -3517,10 +3522,11 @@ done:
|
||||
}
|
||||
|
||||
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
void *data, u16 *result)
|
||||
void *data, size_t size, u16 *result)
|
||||
{
|
||||
struct l2cap_conf_req *req = data;
|
||||
void *ptr = req->data;
|
||||
void *endptr = data + size;
|
||||
int type, olen;
|
||||
unsigned long val;
|
||||
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
|
||||
@@ -3538,13 +3544,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
|
||||
} else
|
||||
chan->imtu = val;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_FLUSH_TO:
|
||||
chan->flush_to = val;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
|
||||
2, chan->flush_to);
|
||||
2, chan->flush_to, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_RFC:
|
||||
@@ -3558,13 +3564,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
chan->fcs = 0;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
||||
sizeof(rfc), (unsigned long) &rfc);
|
||||
sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_EWS:
|
||||
chan->ack_win = min_t(u16, val, chan->ack_win);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
||||
chan->tx_win);
|
||||
chan->tx_win, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_EFS:
|
||||
@@ -3577,7 +3583,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
return -ECONNREFUSED;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
|
||||
(unsigned long) &efs);
|
||||
(unsigned long) &efs, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_FCS:
|
||||
@@ -3682,7 +3688,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
|
||||
return;
|
||||
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, buf), buf);
|
||||
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -3890,7 +3896,7 @@ sendresp:
|
||||
u8 buf[128];
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, buf), buf);
|
||||
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -3968,7 +3974,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
|
||||
break;
|
||||
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, req), req);
|
||||
l2cap_build_conf_req(chan, req, sizeof(req)), req);
|
||||
chan->num_conf_req++;
|
||||
break;
|
||||
|
||||
@@ -4080,7 +4086,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
||||
}
|
||||
|
||||
/* Complete config. */
|
||||
len = l2cap_parse_conf_req(chan, rsp);
|
||||
len = l2cap_parse_conf_req(chan, rsp, sizeof(rsp));
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto unlock;
|
||||
@@ -4114,7 +4120,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
||||
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
|
||||
u8 buf[64];
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, buf), buf);
|
||||
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -4174,7 +4180,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
||||
char buf[64];
|
||||
|
||||
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
||||
buf, &result);
|
||||
buf, sizeof(buf), &result);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
@@ -4204,7 +4210,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
||||
/* throw out any old stored conf requests */
|
||||
result = L2CAP_CONF_SUCCESS;
|
||||
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
||||
req, &result);
|
||||
req, sizeof(req), &result);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
@@ -4781,7 +4787,7 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
|
||||
L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, buf), buf);
|
||||
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
}
|
||||
@@ -7457,7 +7463,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn),
|
||||
L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(chan, buf),
|
||||
l2cap_build_conf_req(chan, buf, sizeof(buf)),
|
||||
buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -3308,9 +3308,15 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
||||
struct xfrm_state *x_new[XFRM_MAX_DEPTH];
|
||||
struct xfrm_migrate *mp;
|
||||
|
||||
/* Stage 0 - sanity checks */
|
||||
if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
|
||||
goto out;
|
||||
|
||||
if (dir >= XFRM_POLICY_MAX) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Stage 1 - find policy */
|
||||
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
|
||||
err = -ENOENT;
|
||||
|
||||
@@ -58,7 +58,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
|
||||
}
|
||||
|
||||
/**
|
||||
* cap_capable - Determine whether a task has a particular effective capability
|
||||
* __cap_capable - Determine whether a task has a particular effective capability
|
||||
* @cred: The credentials to use
|
||||
* @ns: The user namespace in which we need the capability
|
||||
* @cap: The capability to check for
|
||||
@@ -72,18 +72,11 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
|
||||
* cap_has_capability() returns 0 when a task has a capability, but the
|
||||
* kernel's capable() and has_capability() returns 1 for this case.
|
||||
*/
|
||||
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||
int __cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||
int cap, int audit)
|
||||
{
|
||||
struct user_namespace *ns = targ_ns;
|
||||
|
||||
#ifdef CONFIG_ANDROID_PARANOID_NETWORK
|
||||
if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW))
|
||||
return 0;
|
||||
if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* See if cred has the capability in the target user namespace
|
||||
* by examining the target user namespace and all of the target
|
||||
* user namespace's parents.
|
||||
@@ -114,6 +107,27 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||
/* We never get here */
|
||||
}
|
||||
|
||||
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||
int cap, int audit)
|
||||
{
|
||||
int ret = __cap_capable(cred, targ_ns, cap, audit);
|
||||
|
||||
#ifdef CONFIG_ANDROID_PARANOID_NETWORK
|
||||
if (ret != 0 && cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW)) {
|
||||
printk("Process %s granted CAP_NET_RAW from Android group net_raw.\n", current->comm);
|
||||
printk(" Please update the .rc file to explictly set 'capabilities NET_RAW'\n");
|
||||
printk(" Implicit grants are deprecated and will be removed in the future.\n");
|
||||
return 0;
|
||||
}
|
||||
if (ret != 0 && cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN)) {
|
||||
printk("Process %s granted CAP_NET_ADMIN from Android group net_admin.\n", current->comm);
|
||||
printk(" Please update the .rc file to explictly set 'capabilities NET_ADMIN'\n");
|
||||
printk(" Implicit grants are deprecated and will be removed in the future.\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* cap_settime - Determine whether the current process may set the system clock
|
||||
* @ts: The time to set
|
||||
|
||||
@@ -120,24 +120,24 @@ void snd_msndmidi_input_read(void *mpuv)
|
||||
unsigned long flags;
|
||||
struct snd_msndmidi *mpu = mpuv;
|
||||
void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
|
||||
u16 head, tail, size;
|
||||
|
||||
spin_lock_irqsave(&mpu->input_lock, flags);
|
||||
while (readw(mpu->dev->MIDQ + JQS_wTail) !=
|
||||
readw(mpu->dev->MIDQ + JQS_wHead)) {
|
||||
u16 wTmp, val;
|
||||
val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
|
||||
head = readw(mpu->dev->MIDQ + JQS_wHead);
|
||||
tail = readw(mpu->dev->MIDQ + JQS_wTail);
|
||||
size = readw(mpu->dev->MIDQ + JQS_wSize);
|
||||
if (head > size || tail > size)
|
||||
goto out;
|
||||
while (head != tail) {
|
||||
unsigned char val = readw(pwMIDQData + 2 * head);
|
||||
|
||||
if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
|
||||
&mpu->mode))
|
||||
snd_rawmidi_receive(mpu->substream_input,
|
||||
(unsigned char *)&val, 1);
|
||||
|
||||
wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
|
||||
if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
|
||||
writew(0, mpu->dev->MIDQ + JQS_wHead);
|
||||
else
|
||||
writew(wTmp, mpu->dev->MIDQ + JQS_wHead);
|
||||
if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
|
||||
snd_rawmidi_receive(mpu->substream_input, &val, 1);
|
||||
if (++head > size)
|
||||
head = 0;
|
||||
writew(head, mpu->dev->MIDQ + JQS_wHead);
|
||||
}
|
||||
out:
|
||||
spin_unlock_irqrestore(&mpu->input_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_msndmidi_input_read);
|
||||
|
||||
@@ -170,23 +170,24 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct snd_msnd *chip = dev_id;
|
||||
void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
|
||||
u16 head, tail, size;
|
||||
|
||||
/* Send ack to DSP */
|
||||
/* inb(chip->io + HP_RXL); */
|
||||
|
||||
/* Evaluate queued DSP messages */
|
||||
while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
|
||||
u16 wTmp;
|
||||
|
||||
snd_msnd_eval_dsp_msg(chip,
|
||||
readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
|
||||
|
||||
wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
|
||||
if (wTmp > readw(chip->DSPQ + JQS_wSize))
|
||||
writew(0, chip->DSPQ + JQS_wHead);
|
||||
else
|
||||
writew(wTmp, chip->DSPQ + JQS_wHead);
|
||||
head = readw(chip->DSPQ + JQS_wHead);
|
||||
tail = readw(chip->DSPQ + JQS_wTail);
|
||||
size = readw(chip->DSPQ + JQS_wSize);
|
||||
if (head > size || tail > size)
|
||||
goto out;
|
||||
while (head != tail) {
|
||||
snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head));
|
||||
if (++head > size)
|
||||
head = 0;
|
||||
writew(head, chip->DSPQ + JQS_wHead);
|
||||
}
|
||||
out:
|
||||
/* Send ack to DSP */
|
||||
inb(chip->io + HP_RXL);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
@@ -285,9 +285,12 @@ static void *threadproc(void *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
|
||||
static void set_gs_and_switch_to(unsigned long local,
|
||||
unsigned short force_sel,
|
||||
unsigned long remote)
|
||||
{
|
||||
unsigned long base;
|
||||
unsigned short sel_pre_sched, sel_post_sched;
|
||||
|
||||
bool hard_zero = false;
|
||||
if (local == HARD_ZERO) {
|
||||
@@ -297,6 +300,8 @@ static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
|
||||
|
||||
printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
|
||||
local, hard_zero ? " and clear gs" : "", remote);
|
||||
if (force_sel)
|
||||
printf("\tBefore schedule, set selector to 0x%hx\n", force_sel);
|
||||
if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
|
||||
err(1, "ARCH_SET_GS");
|
||||
if (hard_zero)
|
||||
@@ -307,18 +312,35 @@ static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
|
||||
printf("[FAIL]\tGSBASE wasn't set as expected\n");
|
||||
}
|
||||
|
||||
if (force_sel) {
|
||||
asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
|
||||
sel_pre_sched = force_sel;
|
||||
local = read_base(GS);
|
||||
|
||||
/*
|
||||
* Signal delivery seems to mess up weird selectors. Put it
|
||||
* back.
|
||||
*/
|
||||
asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
|
||||
} else {
|
||||
asm volatile ("mov %%gs, %0" : "=rm" (sel_pre_sched));
|
||||
}
|
||||
|
||||
remote_base = remote;
|
||||
ftx = 1;
|
||||
syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
|
||||
while (ftx != 0)
|
||||
syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
|
||||
|
||||
asm volatile ("mov %%gs, %0" : "=rm" (sel_post_sched));
|
||||
base = read_base(GS);
|
||||
if (base == local) {
|
||||
printf("[OK]\tGSBASE remained 0x%lx\n", local);
|
||||
if (base == local && sel_pre_sched == sel_post_sched) {
|
||||
printf("[OK]\tGS/BASE remained 0x%hx/0x%lx\n",
|
||||
sel_pre_sched, local);
|
||||
} else {
|
||||
nerrs++;
|
||||
printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
|
||||
printf("[FAIL]\tGS/BASE changed from 0x%hx/0x%lx to 0x%hx/0x%lx\n",
|
||||
sel_pre_sched, local, sel_post_sched, base);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,8 +403,15 @@ int main()
|
||||
|
||||
for (int local = 0; local < 4; local++) {
|
||||
for (int remote = 0; remote < 4; remote++) {
|
||||
set_gs_and_switch_to(bases_with_hard_zero[local],
|
||||
bases_with_hard_zero[remote]);
|
||||
for (unsigned short s = 0; s < 5; s++) {
|
||||
unsigned short sel = s;
|
||||
if (s == 4)
|
||||
asm ("mov %%ss, %0" : "=rm" (sel));
|
||||
set_gs_and_switch_to(
|
||||
bases_with_hard_zero[local],
|
||||
sel,
|
||||
bases_with_hard_zero[remote]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user