Skip to content

Commit

Permalink
Merge branch 'akpm' (patches from Andrew)
Browse files Browse the repository at this point in the history
Merge misc fixes from Andrew Morton:
 "8 fixes"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  fs/exec.c: account for argv/envp pointers
  ocfs2: fix deadlock caused by recursive locking in xattr
  slub: make sysfs file removal asynchronous
  lib/cmdline.c: fix get_options() overflow while parsing ranges
  fs/dax.c: fix inefficiency in dax_writeback_mapping_range()
  autofs: sanity check status reported with AUTOFS_DEV_IOCTL_FAIL
  mm/vmalloc.c: huge-vmap: fail gracefully on unexpected huge vmap mappings
  mm, thp: remove cond_resched from __collapse_huge_page_copy
  • Loading branch information
Linus Torvalds committed Jun 23, 2017
2 parents 2592d2e + 98da7d0 commit 337c6ba
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 35 deletions.
2 changes: 1 addition & 1 deletion fs/autofs4/dev-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ static int autofs_dev_ioctl_fail(struct file *fp,
int status;

token = (autofs_wqt_t) param->fail.token;
status = param->fail.status ? param->fail.status : -ENOENT;
status = param->fail.status < 0 ? param->fail.status : -ENOENT;
return autofs4_wait_release(sbi, token, status);
}

Expand Down
1 change: 1 addition & 0 deletions fs/dax.c
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,7 @@ int dax_writeback_mapping_range(struct address_space *mapping,
if (ret < 0)
goto out;
}
start_index = indices[pvec.nr - 1] + 1;
}
out:
put_dax(dax_dev);
Expand Down
28 changes: 24 additions & 4 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,26 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,

if (write) {
unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
unsigned long ptr_size;
struct rlimit *rlim;

/*
* Since the stack will hold pointers to the strings, we
* must account for them as well.
*
* The size calculation is the entire vma while each arg page is
* built, so each time we get here it's calculating how far it
* is currently (rather than each call being just the newly
* added size from the arg page). As a result, we need to
* always add the entire size of the pointers, so that on the
* last call to get_arg_page() we'll actually have the entire
* correct size.
*/
ptr_size = (bprm->argc + bprm->envc) * sizeof(void *);
if (ptr_size > ULONG_MAX - size)
goto fail;
size += ptr_size;

acct_arg_size(bprm, size / PAGE_SIZE);

/*
Expand All @@ -239,13 +257,15 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
* to work from.
*/
rlim = current->signal->rlim;
if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
put_page(page);
return NULL;
}
if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4)
goto fail;
}

return page;

fail:
put_page(page);
return NULL;
}

static void put_arg_page(struct page *page)
Expand Down
4 changes: 4 additions & 0 deletions fs/ocfs2/dlmglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -2591,6 +2591,10 @@ void ocfs2_inode_unlock_tracker(struct inode *inode,
struct ocfs2_lock_res *lockres;

lockres = &OCFS2_I(inode)->ip_inode_lockres;
/* had_lock means that the currect process already takes the cluster
* lock previously. If had_lock is 1, we have nothing to do here, and
* it will get unlocked where we got the lock.
*/
if (!had_lock) {
ocfs2_remove_holder(lockres, oh);
ocfs2_inode_unlock(inode, ex);
Expand Down
23 changes: 13 additions & 10 deletions fs/ocfs2/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1328,20 +1328,21 @@ static int ocfs2_xattr_get(struct inode *inode,
void *buffer,
size_t buffer_size)
{
int ret;
int ret, had_lock;
struct buffer_head *di_bh = NULL;
struct ocfs2_lock_holder oh;

ret = ocfs2_inode_lock(inode, &di_bh, 0);
if (ret < 0) {
mlog_errno(ret);
return ret;
had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
if (had_lock < 0) {
mlog_errno(had_lock);
return had_lock;
}
down_read(&OCFS2_I(inode)->ip_xattr_sem);
ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
name, buffer, buffer_size);
up_read(&OCFS2_I(inode)->ip_xattr_sem);

ocfs2_inode_unlock(inode, 0);
ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);

brelse(di_bh);

Expand Down Expand Up @@ -3537,11 +3538,12 @@ int ocfs2_xattr_set(struct inode *inode,
{
struct buffer_head *di_bh = NULL;
struct ocfs2_dinode *di;
int ret, credits, ref_meta = 0, ref_credits = 0;
int ret, credits, had_lock, ref_meta = 0, ref_credits = 0;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct inode *tl_inode = osb->osb_tl_inode;
struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, NULL, };
struct ocfs2_refcount_tree *ref_tree = NULL;
struct ocfs2_lock_holder oh;

struct ocfs2_xattr_info xi = {
.xi_name_index = name_index,
Expand Down Expand Up @@ -3572,8 +3574,9 @@ int ocfs2_xattr_set(struct inode *inode,
return -ENOMEM;
}

ret = ocfs2_inode_lock(inode, &di_bh, 1);
if (ret < 0) {
had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 1, &oh);
if (had_lock < 0) {
ret = had_lock;
mlog_errno(ret);
goto cleanup_nolock;
}
Expand Down Expand Up @@ -3670,7 +3673,7 @@ int ocfs2_xattr_set(struct inode *inode,
if (ret)
mlog_errno(ret);
}
ocfs2_inode_unlock(inode, 1);
ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
cleanup_nolock:
brelse(di_bh);
brelse(xbs.xattr_bh);
Expand Down
1 change: 1 addition & 0 deletions include/linux/slub_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct kmem_cache {
int red_left_pad; /* Left redzone padding size */
#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
struct work_struct kobj_remove_work;
#endif
#ifdef CONFIG_MEMCG
struct memcg_cache_params memcg_params;
Expand Down
6 changes: 3 additions & 3 deletions lib/cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
* the values[M, M+1, ..., N] into the ints array in get_options.
*/

static int get_range(char **str, int *pint)
static int get_range(char **str, int *pint, int n)
{
int x, inc_counter, upper_range;

(*str)++;
upper_range = simple_strtol((*str), NULL, 0);
inc_counter = upper_range - *pint;
for (x = *pint; x < upper_range; x++)
for (x = *pint; n && x < upper_range; x++, n--)
*pint++ = x;
return inc_counter;
}
Expand Down Expand Up @@ -97,7 +97,7 @@ char *get_options(const char *str, int nints, int *ints)
break;
if (res == 3) {
int range_nums;
range_nums = get_range((char **)&str, ints + i);
range_nums = get_range((char **)&str, ints + i, nints - i);
if (range_nums < 0)
break;
/*
Expand Down
1 change: 0 additions & 1 deletion mm/khugepaged.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,6 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page,
spin_unlock(ptl);
free_page_and_swap_cache(src_page);
}
cond_resched();
}
}

Expand Down
40 changes: 26 additions & 14 deletions mm/slub.c
Original file line number Diff line number Diff line change
Expand Up @@ -5625,13 +5625,37 @@ static char *create_unique_id(struct kmem_cache *s)
return name;
}

static void sysfs_slab_remove_workfn(struct work_struct *work)
{
struct kmem_cache *s =
container_of(work, struct kmem_cache, kobj_remove_work);

if (!s->kobj.state_in_sysfs)
/*
* For a memcg cache, this may be called during
* deactivation and again on shutdown. Remove only once.
* A cache is never shut down before deactivation is
* complete, so no need to worry about synchronization.
*/
return;

#ifdef CONFIG_MEMCG
kset_unregister(s->memcg_kset);
#endif
kobject_uevent(&s->kobj, KOBJ_REMOVE);
kobject_del(&s->kobj);
kobject_put(&s->kobj);
}

static int sysfs_slab_add(struct kmem_cache *s)
{
int err;
const char *name;
struct kset *kset = cache_kset(s);
int unmergeable = slab_unmergeable(s);

INIT_WORK(&s->kobj_remove_work, sysfs_slab_remove_workfn);

if (!kset) {
kobject_init(&s->kobj, &slab_ktype);
return 0;
Expand Down Expand Up @@ -5695,20 +5719,8 @@ static void sysfs_slab_remove(struct kmem_cache *s)
*/
return;

if (!s->kobj.state_in_sysfs)
/*
* For a memcg cache, this may be called during
* deactivation and again on shutdown. Remove only once.
* A cache is never shut down before deactivation is
* complete, so no need to worry about synchronization.
*/
return;

#ifdef CONFIG_MEMCG
kset_unregister(s->memcg_kset);
#endif
kobject_uevent(&s->kobj, KOBJ_REMOVE);
kobject_del(&s->kobj);
kobject_get(&s->kobj);
schedule_work(&s->kobj_remove_work);
}

void sysfs_slab_release(struct kmem_cache *s)
Expand Down
15 changes: 13 additions & 2 deletions mm/vmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,21 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
if (p4d_none(*p4d))
return NULL;
pud = pud_offset(p4d, addr);
if (pud_none(*pud))

/*
* Don't dereference bad PUD or PMD (below) entries. This will also
* identify huge mappings, which we may encounter on architectures
* that define CONFIG_HAVE_ARCH_HUGE_VMAP=y. Such regions will be
* identified as vmalloc addresses by is_vmalloc_addr(), but are
* not [unambiguously] associated with a struct page, so there is
* no correct value to return for them.
*/
WARN_ON_ONCE(pud_bad(*pud));
if (pud_none(*pud) || pud_bad(*pud))
return NULL;
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd))
WARN_ON_ONCE(pmd_bad(*pmd));
if (pmd_none(*pmd) || pmd_bad(*pmd))
return NULL;

ptep = pte_offset_map(pmd, addr);
Expand Down

0 comments on commit 337c6ba

Please sign in to comment.