You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'akpm' (patches from Andrew)
Merge misc fixes from Andrew Morton: "A lot of stuff, sorry about that. A week on a beach, then a bunch of time catching up then more time letting it bake in -next. Shan't do that again!" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (51 commits) include/linux/fs.h: fix comment about struct address_space checkpatch: fix ignoring cover-letter logic m32r: fix build failure lib/ratelimit.c: use deferred printk() version kernel/params.c: improve STANDARD_PARAM_DEF readability kernel/params.c: fix an overflow in param_attr_show kernel/params.c: fix the maximum length in param_get_string mm/memory_hotplug: define find_{smallest|biggest}_section_pfn as unsigned long mm/memory_hotplug: change pfn_to_section_nr/section_nr_to_pfn macro to inline function kernel/kcmp.c: drop branch leftover typo memremap: add scheduling point to devm_memremap_pages mm, page_alloc: add scheduling point to memmap_init_zone mm, memory_hotplug: add scheduling point to __add_pages lib/idr.c: fix comment for idr_replace() mm: memcontrol: use vmalloc fallback for large kmem memcg arrays kernel/sysctl.c: remove duplicate UINT_MAX check on do_proc_douintvec_conv() include/linux/bitfield.h: remove 32bit from FIELD_GET comment block lib/lz4: make arrays static const, reduces object code size exec: binfmt_misc: kill the onstack iname[BINPRM_BUF_SIZE] array exec: binfmt_misc: fix race between load_misc_binary() and kill_node() ...
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/compiler.h>
|
||||
|
||||
@@ -194,6 +194,10 @@ config TIMER_DIVIDE
|
||||
int "Timer divider (integer)"
|
||||
default "128"
|
||||
|
||||
config CPU_BIG_ENDIAN
|
||||
bool "Generate big endian code"
|
||||
default n
|
||||
|
||||
config CPU_LITTLE_ENDIAN
|
||||
bool "Generate little endian code"
|
||||
default n
|
||||
|
||||
@@ -114,6 +114,15 @@ static void set_eit_vector_entries(void)
|
||||
_flush_cache_copyback_all();
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
BUG();
|
||||
|
||||
/* if that doesn't kill us, halt */
|
||||
panic("Oops failed to kill thread");
|
||||
}
|
||||
EXPORT_SYMBOL(abort);
|
||||
|
||||
void __init trap_init(void)
|
||||
{
|
||||
set_eit_vector_entries();
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
#define RIWAR_WRTYP_ALLOC 0x00006000
|
||||
#define RIWAR_SIZE_MASK 0x0000003F
|
||||
|
||||
static DEFINE_SPINLOCK(fsl_rio_config_lock);
|
||||
|
||||
#define __fsl_read_rio_config(x, addr, err, op) \
|
||||
__asm__ __volatile__( \
|
||||
"1: "op" %1,0(%2)\n" \
|
||||
@@ -184,6 +186,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
|
||||
u8 hopcount, u32 offset, int len, u32 *val)
|
||||
{
|
||||
struct rio_priv *priv = mport->priv;
|
||||
unsigned long flags;
|
||||
u8 *data;
|
||||
u32 rval, err = 0;
|
||||
|
||||
@@ -197,6 +200,8 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
|
||||
if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&fsl_rio_config_lock, flags);
|
||||
|
||||
out_be32(&priv->maint_atmu_regs->rowtar,
|
||||
(destid << 22) | (hopcount << 12) | (offset >> 12));
|
||||
out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10));
|
||||
@@ -213,6 +218,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
|
||||
__fsl_read_rio_config(rval, data, err, "lwz");
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&fsl_rio_config_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -221,6 +227,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
|
||||
err, destid, hopcount, offset);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fsl_rio_config_lock, flags);
|
||||
*val = rval;
|
||||
|
||||
return err;
|
||||
@@ -244,7 +251,10 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
|
||||
u8 hopcount, u32 offset, int len, u32 val)
|
||||
{
|
||||
struct rio_priv *priv = mport->priv;
|
||||
unsigned long flags;
|
||||
u8 *data;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug
|
||||
("fsl_rio_config_write:"
|
||||
" index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
|
||||
@@ -255,6 +265,8 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
|
||||
if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&fsl_rio_config_lock, flags);
|
||||
|
||||
out_be32(&priv->maint_atmu_regs->rowtar,
|
||||
(destid << 22) | (hopcount << 12) | (offset >> 12));
|
||||
out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10));
|
||||
@@ -271,10 +283,11 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
|
||||
out_be32((u32 *) data, val);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&fsl_rio_config_lock, flags);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fsl_rio_inbound_mem_init(struct rio_priv *priv)
|
||||
|
||||
@@ -104,6 +104,8 @@
|
||||
|
||||
#define DOORBELL_MESSAGE_SIZE 0x08
|
||||
|
||||
static DEFINE_SPINLOCK(fsl_rio_doorbell_lock);
|
||||
|
||||
struct rio_msg_regs {
|
||||
u32 omr;
|
||||
u32 osr;
|
||||
@@ -626,9 +628,13 @@ err_out:
|
||||
int fsl_rio_doorbell_send(struct rio_mport *mport,
|
||||
int index, u16 destid, u16 data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
|
||||
index, destid, data);
|
||||
|
||||
spin_lock_irqsave(&fsl_rio_doorbell_lock, flags);
|
||||
|
||||
/* In the serial version silicons, such as MPC8548, MPC8641,
|
||||
* below operations is must be.
|
||||
*/
|
||||
@@ -638,6 +644,8 @@ int fsl_rio_doorbell_send(struct rio_mport *mport,
|
||||
out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data);
|
||||
out_be32(&dbell->dbell_regs->odmr, 0x00000001);
|
||||
|
||||
spin_unlock_irqrestore(&fsl_rio_doorbell_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,9 +43,7 @@ enum {
|
||||
GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
|
||||
GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
|
||||
|
||||
/* Port H */
|
||||
GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
|
||||
GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
|
||||
/* Port H - Port H does not have a Data Register */
|
||||
|
||||
/* Port I - not on device */
|
||||
|
||||
|
||||
@@ -45,9 +45,7 @@ enum {
|
||||
GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
|
||||
GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
|
||||
|
||||
/* Port H */
|
||||
GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
|
||||
GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
|
||||
/* Port H - Port H does not have a Data Register */
|
||||
|
||||
/* Port I - not on device */
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ enum {
|
||||
GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
|
||||
|
||||
/* PTQ */
|
||||
GPIO_PTQ7, GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
|
||||
GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
|
||||
GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
|
||||
|
||||
/* PTR */
|
||||
|
||||
@@ -40,7 +40,7 @@ enum {
|
||||
|
||||
/* PTJ */
|
||||
GPIO_PTJ0, GPIO_PTJ1, GPIO_PTJ2, GPIO_PTJ3,
|
||||
GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6, GPIO_PTJ7_RESV,
|
||||
GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6,
|
||||
|
||||
/* PTK */
|
||||
GPIO_PTK0, GPIO_PTK1, GPIO_PTK2, GPIO_PTK3,
|
||||
@@ -48,7 +48,7 @@ enum {
|
||||
|
||||
/* PTL */
|
||||
GPIO_PTL0, GPIO_PTL1, GPIO_PTL2, GPIO_PTL3,
|
||||
GPIO_PTL4, GPIO_PTL5, GPIO_PTL6, GPIO_PTL7_RESV,
|
||||
GPIO_PTL4, GPIO_PTL5, GPIO_PTL6,
|
||||
|
||||
/* PTM */
|
||||
GPIO_PTM0, GPIO_PTM1, GPIO_PTM2, GPIO_PTM3,
|
||||
@@ -56,7 +56,7 @@ enum {
|
||||
|
||||
/* PTN */
|
||||
GPIO_PTN0, GPIO_PTN1, GPIO_PTN2, GPIO_PTN3,
|
||||
GPIO_PTN4, GPIO_PTN5, GPIO_PTN6, GPIO_PTN7_RESV,
|
||||
GPIO_PTN4, GPIO_PTN5, GPIO_PTN6,
|
||||
|
||||
/* PTO */
|
||||
GPIO_PTO0, GPIO_PTO1, GPIO_PTO2, GPIO_PTO3,
|
||||
@@ -68,7 +68,7 @@ enum {
|
||||
|
||||
/* PTQ */
|
||||
GPIO_PTQ0, GPIO_PTQ1, GPIO_PTQ2, GPIO_PTQ3,
|
||||
GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6, GPIO_PTQ7_RESV,
|
||||
GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6,
|
||||
|
||||
/* PTR */
|
||||
GPIO_PTR0, GPIO_PTR1, GPIO_PTR2, GPIO_PTR3,
|
||||
|
||||
@@ -913,6 +913,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
|
||||
struct binder_alloc *alloc;
|
||||
uintptr_t page_addr;
|
||||
size_t index;
|
||||
struct vm_area_struct *vma;
|
||||
|
||||
alloc = page->alloc;
|
||||
if (!mutex_trylock(&alloc->mutex))
|
||||
@@ -923,16 +924,22 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
|
||||
|
||||
index = page - alloc->pages;
|
||||
page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
|
||||
if (alloc->vma) {
|
||||
vma = alloc->vma;
|
||||
if (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;
|
||||
}
|
||||
|
||||
list_lru_isolate(lru, item);
|
||||
spin_unlock(lock);
|
||||
|
||||
if (vma) {
|
||||
trace_binder_unmap_user_start(alloc, index);
|
||||
|
||||
zap_page_range(alloc->vma,
|
||||
zap_page_range(vma,
|
||||
page_addr + alloc->user_buffer_offset,
|
||||
PAGE_SIZE);
|
||||
|
||||
@@ -950,13 +957,12 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
|
||||
|
||||
trace_binder_unmap_kernel_end(alloc, index);
|
||||
|
||||
list_lru_isolate(lru, item);
|
||||
|
||||
spin_lock(lock);
|
||||
mutex_unlock(&alloc->mutex);
|
||||
return LRU_REMOVED;
|
||||
return LRU_REMOVED_RETRY;
|
||||
|
||||
err_down_write_mmap_sem_failed:
|
||||
mmput(mm);
|
||||
mmput_async(mm);
|
||||
err_get_task_mm_failed:
|
||||
err_page_already_freed:
|
||||
mutex_unlock(&alloc->mutex);
|
||||
|
||||
@@ -766,27 +766,6 @@ static void zram_slot_unlock(struct zram *zram, u32 index)
|
||||
bit_spin_unlock(ZRAM_ACCESS, &zram->table[index].value);
|
||||
}
|
||||
|
||||
static bool zram_same_page_read(struct zram *zram, u32 index,
|
||||
struct page *page,
|
||||
unsigned int offset, unsigned int len)
|
||||
{
|
||||
zram_slot_lock(zram, index);
|
||||
if (unlikely(!zram_get_handle(zram, index) ||
|
||||
zram_test_flag(zram, index, ZRAM_SAME))) {
|
||||
void *mem;
|
||||
|
||||
zram_slot_unlock(zram, index);
|
||||
mem = kmap_atomic(page);
|
||||
zram_fill_page(mem + offset, len,
|
||||
zram_get_element(zram, index));
|
||||
kunmap_atomic(mem);
|
||||
return true;
|
||||
}
|
||||
zram_slot_unlock(zram, index);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void zram_meta_free(struct zram *zram, u64 disksize)
|
||||
{
|
||||
size_t num_pages = disksize >> PAGE_SHIFT;
|
||||
@@ -884,11 +863,20 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
|
||||
zram_slot_unlock(zram, index);
|
||||
}
|
||||
|
||||
if (zram_same_page_read(zram, index, page, 0, PAGE_SIZE))
|
||||
return 0;
|
||||
|
||||
zram_slot_lock(zram, index);
|
||||
handle = zram_get_handle(zram, index);
|
||||
if (!handle || zram_test_flag(zram, index, ZRAM_SAME)) {
|
||||
unsigned long value;
|
||||
void *mem;
|
||||
|
||||
value = handle ? zram_get_element(zram, index) : 0;
|
||||
mem = kmap_atomic(page);
|
||||
zram_fill_page(mem, PAGE_SIZE, value);
|
||||
kunmap_atomic(mem);
|
||||
zram_slot_unlock(zram, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = zram_get_obj_size(zram, index);
|
||||
|
||||
src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
|
||||
|
||||
@@ -51,6 +51,8 @@ module_param(mbox_sel, byte, S_IRUGO);
|
||||
MODULE_PARM_DESC(mbox_sel,
|
||||
"RIO Messaging MBOX Selection Mask (default: 0x0f = all)");
|
||||
|
||||
static DEFINE_SPINLOCK(tsi721_maint_lock);
|
||||
|
||||
static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
|
||||
static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);
|
||||
|
||||
@@ -124,12 +126,15 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size,
|
||||
void __iomem *regs = priv->regs + TSI721_DMAC_BASE(priv->mdma.ch_id);
|
||||
struct tsi721_dma_desc *bd_ptr;
|
||||
u32 rd_count, swr_ptr, ch_stat;
|
||||
unsigned long flags;
|
||||
int i, err = 0;
|
||||
u32 op = do_wr ? MAINT_WR : MAINT_RD;
|
||||
|
||||
if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32)))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&tsi721_maint_lock, flags);
|
||||
|
||||
bd_ptr = priv->mdma.bd_base;
|
||||
|
||||
rd_count = ioread32(regs + TSI721_DMAC_DRDCNT);
|
||||
@@ -197,7 +202,9 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size,
|
||||
*/
|
||||
swr_ptr = ioread32(regs + TSI721_DMAC_DSWP);
|
||||
iowrite32(swr_ptr, regs + TSI721_DMAC_DSRP);
|
||||
|
||||
err_out:
|
||||
spin_unlock_irqrestore(&tsi721_maint_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -13,17 +13,9 @@
|
||||
#include <linux/rio.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* These interrupt-safe spinlocks protect all accesses to RIO
|
||||
* configuration space and doorbell access.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(rio_config_lock);
|
||||
static DEFINE_SPINLOCK(rio_doorbell_lock);
|
||||
|
||||
/*
|
||||
* Wrappers for all RIO configuration access functions. They just check
|
||||
* alignment, do locking and call the low-level functions pointed to
|
||||
* by rio_mport->ops.
|
||||
* alignment and call the low-level functions pointed to by rio_mport->ops.
|
||||
*/
|
||||
|
||||
#define RIO_8_BAD 0
|
||||
@@ -44,13 +36,10 @@ int __rio_local_read_config_##size \
|
||||
(struct rio_mport *mport, u32 offset, type *value) \
|
||||
{ \
|
||||
int res; \
|
||||
unsigned long flags; \
|
||||
u32 data = 0; \
|
||||
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
|
||||
spin_lock_irqsave(&rio_config_lock, flags); \
|
||||
res = mport->ops->lcread(mport, mport->id, offset, len, &data); \
|
||||
*value = (type)data; \
|
||||
spin_unlock_irqrestore(&rio_config_lock, flags); \
|
||||
return res; \
|
||||
}
|
||||
|
||||
@@ -67,13 +56,8 @@ int __rio_local_read_config_##size \
|
||||
int __rio_local_write_config_##size \
|
||||
(struct rio_mport *mport, u32 offset, type value) \
|
||||
{ \
|
||||
int res; \
|
||||
unsigned long flags; \
|
||||
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
|
||||
spin_lock_irqsave(&rio_config_lock, flags); \
|
||||
res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\
|
||||
spin_unlock_irqrestore(&rio_config_lock, flags); \
|
||||
return res; \
|
||||
return mport->ops->lcwrite(mport, mport->id, offset, len, value);\
|
||||
}
|
||||
|
||||
RIO_LOP_READ(8, u8, 1)
|
||||
@@ -104,13 +88,10 @@ int rio_mport_read_config_##size \
|
||||
(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type *value) \
|
||||
{ \
|
||||
int res; \
|
||||
unsigned long flags; \
|
||||
u32 data = 0; \
|
||||
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
|
||||
spin_lock_irqsave(&rio_config_lock, flags); \
|
||||
res = mport->ops->cread(mport, mport->id, destid, hopcount, offset, len, &data); \
|
||||
*value = (type)data; \
|
||||
spin_unlock_irqrestore(&rio_config_lock, flags); \
|
||||
return res; \
|
||||
}
|
||||
|
||||
@@ -127,13 +108,9 @@ int rio_mport_read_config_##size \
|
||||
int rio_mport_write_config_##size \
|
||||
(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type value) \
|
||||
{ \
|
||||
int res; \
|
||||
unsigned long flags; \
|
||||
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
|
||||
spin_lock_irqsave(&rio_config_lock, flags); \
|
||||
res = mport->ops->cwrite(mport, mport->id, destid, hopcount, offset, len, value); \
|
||||
spin_unlock_irqrestore(&rio_config_lock, flags); \
|
||||
return res; \
|
||||
return mport->ops->cwrite(mport, mport->id, destid, hopcount, \
|
||||
offset, len, value); \
|
||||
}
|
||||
|
||||
RIO_OP_READ(8, u8, 1)
|
||||
@@ -162,14 +139,7 @@ EXPORT_SYMBOL_GPL(rio_mport_write_config_32);
|
||||
*/
|
||||
int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
|
||||
{
|
||||
int res;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rio_doorbell_lock, flags);
|
||||
res = mport->ops->dsend(mport, mport->id, destid, data);
|
||||
spin_unlock_irqrestore(&rio_doorbell_lock, flags);
|
||||
|
||||
return res;
|
||||
return mport->ops->dsend(mport, mport->id, destid, data);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(rio_mport_send_doorbell);
|
||||
|
||||
+26
-30
@@ -54,7 +54,7 @@ typedef struct {
|
||||
int size; /* size of magic/mask */
|
||||
char *magic; /* magic or filename extension */
|
||||
char *mask; /* mask, NULL for exact match */
|
||||
char *interpreter; /* filename of interpreter */
|
||||
const char *interpreter; /* filename of interpreter */
|
||||
char *name;
|
||||
struct dentry *dentry;
|
||||
struct file *interp_file;
|
||||
@@ -131,27 +131,26 @@ static int load_misc_binary(struct linux_binprm *bprm)
|
||||
{
|
||||
Node *fmt;
|
||||
struct file *interp_file = NULL;
|
||||
char iname[BINPRM_BUF_SIZE];
|
||||
const char *iname_addr = iname;
|
||||
int retval;
|
||||
int fd_binary = -1;
|
||||
|
||||
retval = -ENOEXEC;
|
||||
if (!enabled)
|
||||
goto ret;
|
||||
return retval;
|
||||
|
||||
/* to keep locking time low, we copy the interpreter string */
|
||||
read_lock(&entries_lock);
|
||||
fmt = check_file(bprm);
|
||||
if (fmt)
|
||||
strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE);
|
||||
dget(fmt->dentry);
|
||||
read_unlock(&entries_lock);
|
||||
if (!fmt)
|
||||
goto ret;
|
||||
return retval;
|
||||
|
||||
/* Need to be able to load the file after exec */
|
||||
retval = -ENOENT;
|
||||
if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
|
||||
return -ENOENT;
|
||||
goto ret;
|
||||
|
||||
if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
|
||||
retval = remove_arg_zero(bprm);
|
||||
@@ -195,22 +194,22 @@ static int load_misc_binary(struct linux_binprm *bprm)
|
||||
bprm->argc++;
|
||||
|
||||
/* add the interp as argv[0] */
|
||||
retval = copy_strings_kernel(1, &iname_addr, bprm);
|
||||
retval = copy_strings_kernel(1, &fmt->interpreter, bprm);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
bprm->argc++;
|
||||
|
||||
/* Update interp in case binfmt_script needs it. */
|
||||
retval = bprm_change_interp(iname, bprm);
|
||||
retval = bprm_change_interp(fmt->interpreter, bprm);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
if (fmt->flags & MISC_FMT_OPEN_FILE && fmt->interp_file) {
|
||||
if (fmt->flags & MISC_FMT_OPEN_FILE) {
|
||||
interp_file = filp_clone_open(fmt->interp_file);
|
||||
if (!IS_ERR(interp_file))
|
||||
deny_write_access(interp_file);
|
||||
} else {
|
||||
interp_file = open_exec(iname);
|
||||
interp_file = open_exec(fmt->interpreter);
|
||||
}
|
||||
retval = PTR_ERR(interp_file);
|
||||
if (IS_ERR(interp_file))
|
||||
@@ -238,6 +237,7 @@ static int load_misc_binary(struct linux_binprm *bprm)
|
||||
goto error;
|
||||
|
||||
ret:
|
||||
dput(fmt->dentry);
|
||||
return retval;
|
||||
error:
|
||||
if (fd_binary > 0)
|
||||
@@ -594,8 +594,13 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
|
||||
|
||||
static void bm_evict_inode(struct inode *inode)
|
||||
{
|
||||
Node *e = inode->i_private;
|
||||
|
||||
if (e->flags & MISC_FMT_OPEN_FILE)
|
||||
filp_close(e->interp_file, NULL);
|
||||
|
||||
clear_inode(inode);
|
||||
kfree(inode->i_private);
|
||||
kfree(e);
|
||||
}
|
||||
|
||||
static void kill_node(Node *e)
|
||||
@@ -603,24 +608,14 @@ static void kill_node(Node *e)
|
||||
struct dentry *dentry;
|
||||
|
||||
write_lock(&entries_lock);
|
||||
dentry = e->dentry;
|
||||
if (dentry) {
|
||||
list_del_init(&e->list);
|
||||
e->dentry = NULL;
|
||||
}
|
||||
list_del_init(&e->list);
|
||||
write_unlock(&entries_lock);
|
||||
|
||||
if ((e->flags & MISC_FMT_OPEN_FILE) && e->interp_file) {
|
||||
filp_close(e->interp_file, NULL);
|
||||
e->interp_file = NULL;
|
||||
}
|
||||
|
||||
if (dentry) {
|
||||
drop_nlink(d_inode(dentry));
|
||||
d_drop(dentry);
|
||||
dput(dentry);
|
||||
simple_release_fs(&bm_mnt, &entry_count);
|
||||
}
|
||||
dentry = e->dentry;
|
||||
drop_nlink(d_inode(dentry));
|
||||
d_drop(dentry);
|
||||
dput(dentry);
|
||||
simple_release_fs(&bm_mnt, &entry_count);
|
||||
}
|
||||
|
||||
/* /<entry> */
|
||||
@@ -665,7 +660,8 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
|
||||
root = file_inode(file)->i_sb->s_root;
|
||||
inode_lock(d_inode(root));
|
||||
|
||||
kill_node(e);
|
||||
if (!list_empty(&e->list))
|
||||
kill_node(e);
|
||||
|
||||
inode_unlock(d_inode(root));
|
||||
break;
|
||||
@@ -794,7 +790,7 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
|
||||
inode_lock(d_inode(root));
|
||||
|
||||
while (!list_empty(&entries))
|
||||
kill_node(list_entry(entries.next, Node, list));
|
||||
kill_node(list_first_entry(&entries, Node, list));
|
||||
|
||||
inode_unlock(d_inode(root));
|
||||
break;
|
||||
|
||||
+9
-8
@@ -19,7 +19,6 @@ static int load_script(struct linux_binprm *bprm)
|
||||
const char *i_arg, *i_name;
|
||||
char *cp;
|
||||
struct file *file;
|
||||
char interp[BINPRM_BUF_SIZE];
|
||||
int retval;
|
||||
|
||||
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
|
||||
@@ -55,7 +54,7 @@ static int load_script(struct linux_binprm *bprm)
|
||||
break;
|
||||
}
|
||||
for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
|
||||
if (*cp == '\0')
|
||||
if (*cp == '\0')
|
||||
return -ENOEXEC; /* No interpreter name found */
|
||||
i_name = cp;
|
||||
i_arg = NULL;
|
||||
@@ -65,7 +64,6 @@ static int load_script(struct linux_binprm *bprm)
|
||||
*cp++ = '\0';
|
||||
if (*cp)
|
||||
i_arg = cp;
|
||||
strcpy (interp, i_name);
|
||||
/*
|
||||
* OK, we've parsed out the interpreter name and
|
||||
* (optional) argument.
|
||||
@@ -80,24 +78,27 @@ static int load_script(struct linux_binprm *bprm)
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = copy_strings_kernel(1, &bprm->interp, bprm);
|
||||
if (retval < 0) return retval;
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm->argc++;
|
||||
if (i_arg) {
|
||||
retval = copy_strings_kernel(1, &i_arg, bprm);
|
||||
if (retval < 0) return retval;
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm->argc++;
|
||||
}
|
||||
retval = copy_strings_kernel(1, &i_name, bprm);
|
||||
if (retval) return retval;
|
||||
if (retval)
|
||||
return retval;
|
||||
bprm->argc++;
|
||||
retval = bprm_change_interp(interp, bprm);
|
||||
retval = bprm_change_interp(i_name, bprm);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* OK, now restart the process with the interpreter's dentry.
|
||||
*/
|
||||
file = open_exec(interp);
|
||||
file = open_exec(i_name);
|
||||
if (IS_ERR(file))
|
||||
return PTR_ERR(file);
|
||||
|
||||
|
||||
@@ -1410,7 +1410,7 @@ static void free_bprm(struct linux_binprm *bprm)
|
||||
kfree(bprm);
|
||||
}
|
||||
|
||||
int bprm_change_interp(char *interp, struct linux_binprm *bprm)
|
||||
int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
|
||||
{
|
||||
/* If a binfmt changed the interp, free it first. */
|
||||
if (bprm->interp != bprm->filename)
|
||||
|
||||
+56
-10
@@ -588,6 +588,12 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
|
||||
break;
|
||||
if (ACCESS_ONCE(ctx->released) ||
|
||||
fatal_signal_pending(current)) {
|
||||
/*
|
||||
* &ewq->wq may be queued in fork_event, but
|
||||
* __remove_wait_queue ignores the head
|
||||
* parameter. It would be a problem if it
|
||||
* didn't.
|
||||
*/
|
||||
__remove_wait_queue(&ctx->event_wqh, &ewq->wq);
|
||||
if (ewq->msg.event == UFFD_EVENT_FORK) {
|
||||
struct userfaultfd_ctx *new;
|
||||
@@ -1061,6 +1067,12 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
|
||||
(unsigned long)
|
||||
uwq->msg.arg.reserved.reserved1;
|
||||
list_move(&uwq->wq.entry, &fork_event);
|
||||
/*
|
||||
* fork_nctx can be freed as soon as
|
||||
* we drop the lock, unless we take a
|
||||
* reference on it.
|
||||
*/
|
||||
userfaultfd_ctx_get(fork_nctx);
|
||||
spin_unlock(&ctx->event_wqh.lock);
|
||||
ret = 0;
|
||||
break;
|
||||
@@ -1091,19 +1103,53 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
|
||||
|
||||
if (!ret && msg->event == UFFD_EVENT_FORK) {
|
||||
ret = resolve_userfault_fork(ctx, fork_nctx, msg);
|
||||
spin_lock(&ctx->event_wqh.lock);
|
||||
if (!list_empty(&fork_event)) {
|
||||
/*
|
||||
* The fork thread didn't abort, so we can
|
||||
* drop the temporary refcount.
|
||||
*/
|
||||
userfaultfd_ctx_put(fork_nctx);
|
||||
|
||||
if (!ret) {
|
||||
spin_lock(&ctx->event_wqh.lock);
|
||||
if (!list_empty(&fork_event)) {
|
||||
uwq = list_first_entry(&fork_event,
|
||||
typeof(*uwq),
|
||||
wq.entry);
|
||||
list_del(&uwq->wq.entry);
|
||||
__add_wait_queue(&ctx->event_wqh, &uwq->wq);
|
||||
uwq = list_first_entry(&fork_event,
|
||||
typeof(*uwq),
|
||||
wq.entry);
|
||||
/*
|
||||
* If fork_event list wasn't empty and in turn
|
||||
* the event wasn't already released by fork
|
||||
* (the event is allocated on fork kernel
|
||||
* stack), put the event back to its place in
|
||||
* the event_wq. fork_event head will be freed
|
||||
* as soon as we return so the event cannot
|
||||
* stay queued there no matter the current
|
||||
* "ret" value.
|
||||
*/
|
||||
list_del(&uwq->wq.entry);
|
||||
__add_wait_queue(&ctx->event_wqh, &uwq->wq);
|
||||
|
||||
/*
|
||||
* Leave the event in the waitqueue and report
|
||||
* error to userland if we failed to resolve
|
||||
* the userfault fork.
|
||||
*/
|
||||
if (likely(!ret))
|
||||
userfaultfd_event_complete(ctx, uwq);
|
||||
}
|
||||
spin_unlock(&ctx->event_wqh.lock);
|
||||
} else {
|
||||
/*
|
||||
* Here the fork thread aborted and the
|
||||
* refcount from the fork thread on fork_nctx
|
||||
* has already been released. We still hold
|
||||
* the reference we took before releasing the
|
||||
* lock above. If resolve_userfault_fork
|
||||
* failed we've to drop it because the
|
||||
* fork_nctx has to be freed in such case. If
|
||||
* it succeeded we'll hold it because the new
|
||||
* uffd references it.
|
||||
*/
|
||||
if (ret)
|
||||
userfaultfd_ctx_put(fork_nctx);
|
||||
}
|
||||
spin_unlock(&ctx->event_wqh.lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -131,7 +131,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
|
||||
int executable_stack);
|
||||
extern int transfer_args_to_stack(struct linux_binprm *bprm,
|
||||
unsigned long *sp_location);
|
||||
extern int bprm_change_interp(char *interp, struct linux_binprm *bprm);
|
||||
extern int bprm_change_interp(const char *interp, struct linux_binprm *bprm);
|
||||
extern int copy_strings_kernel(int argc, const char *const *argv,
|
||||
struct linux_binprm *bprm);
|
||||
extern int prepare_bprm_creds(struct linux_binprm *bprm);
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
/**
|
||||
* FIELD_GET() - extract a bitfield element
|
||||
* @_mask: shifted mask defining the field's length and position
|
||||
* @_reg: 32bit value of entire bitfield
|
||||
* @_reg: value of entire bitfield
|
||||
*
|
||||
* FIELD_GET() extracts the field specified by @_mask from the
|
||||
* bitfield passed in as @_reg by masking and shifting it down.
|
||||
|
||||
+1
-1
@@ -403,7 +403,7 @@ struct address_space {
|
||||
unsigned long flags; /* error bits */
|
||||
spinlock_t private_lock; /* for use by the address_space */
|
||||
gfp_t gfp_mask; /* implicit gfp mask for allocations */
|
||||
struct list_head private_list; /* ditto */
|
||||
struct list_head private_list; /* for use by the address_space */
|
||||
void *private_data; /* ditto */
|
||||
errseq_t wb_err;
|
||||
} __attribute__((aligned(sizeof(long)))) __randomize_layout;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user