Skip to content

Commit

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

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (21 commits)
  mm: revert mremap pud_free anti-fix
  mm: fix BUG in __split_huge_page_pmd
  swap: fix set_blocksize race during swapon/swapoff
  procfs: call default get_unmapped_area on MMU-present architectures
  procfs: fix unintended truncation of returned mapped address
  writeback: fix negative bdi max pause
  percpu_refcount: export symbols
  fs: buffer: move allocation failure loop into the allocator
  mm: memcg: handle non-error OOM situations more gracefully
  tools/testing/selftests: fix uninitialized variable
  block/partitions/efi.c: treat size mismatch as a warning, not an error
  mm: hugetlb: initialize PG_reserved for tail pages of gigantic compound pages
  mm/zswap: bugfix: memory leak when re-swapon
  mm: /proc/pid/pagemap: inspect _PAGE_SOFT_DIRTY only on present pages
  mm: migration: do not lose soft dirty bit if page is in migration state
  gcov: MAINTAINERS: Add an entry for gcov
  mm/hugetlb.c: correct missing private flag clearing
  mm/vmscan.c: don't forget to free shrinker->nr_deferred
  ipc/sem.c: synchronize semop and semctl with IPC_RMID
  ipc: update locking scheme comments
  ...
  • Loading branch information
Linus Torvalds committed Oct 17, 2013
2 parents 0056019 + 57a8f0c commit 056cdce
Show file tree
Hide file tree
Showing 24 changed files with 219 additions and 189 deletions.
6 changes: 6 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -3624,6 +3624,12 @@ L: linux-scsi@vger.kernel.org
S: Odd Fixes (e.g., new signatures)
F: drivers/scsi/fdomain.*

GCOV BASED KERNEL PROFILING
M: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
S: Maintained
F: kernel/gcov/
F: Documentation/gcov.txt

GDT SCSI DISK ARRAY CONTROLLER DRIVER
M: Achim Leubner <achim_leubner@adaptec.com>
L: linux-scsi@vger.kernel.org
Expand Down
7 changes: 6 additions & 1 deletion block/partitions/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,16 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors)
* the disk size.
*
* Hybrid MBRs do not necessarily comply with this.
*
* Consider a bad value here to be a warning to support dd'ing
* an image from a smaller disk to a larger disk.
*/
if (ret == GPT_MBR_PROTECTIVE) {
sz = le32_to_cpu(mbr->partition_record[part].size_in_lba);
if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
ret = 0;
pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n",
sz, min_t(uint32_t,
total_sectors - 1, 0xFFFFFFFF));
}
done:
return ret;
Expand Down
14 changes: 12 additions & 2 deletions fs/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,9 +1005,19 @@ grow_dev_page(struct block_device *bdev, sector_t block,
struct buffer_head *bh;
sector_t end_block;
int ret = 0; /* Will call free_more_memory() */
gfp_t gfp_mask;

page = find_or_create_page(inode->i_mapping, index,
(mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
gfp_mask = mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS;
gfp_mask |= __GFP_MOVABLE;
/*
* XXX: __getblk_slow() can not really deal with failure and
* will endlessly loop on improvised global reclaim. Prefer
* looping in the allocator rather than here, at least that
* code knows what it's doing.
*/
gfp_mask |= __GFP_NOFAIL;

page = find_or_create_page(inode->i_mapping, index, gfp_mask);
if (!page)
return ret;

Expand Down
10 changes: 7 additions & 3 deletions fs/proc/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,14 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
int rv = -EIO;
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
unsigned long rv = -EIO;
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long) = NULL;
if (use_pde(pde)) {
get_unmapped_area = pde->proc_fops->get_unmapped_area;
#ifdef CONFIG_MMU
get_unmapped_area = current->mm->get_unmapped_area;
#endif
if (pde->proc_fops->get_unmapped_area)
get_unmapped_area = pde->proc_fops->get_unmapped_area;
if (get_unmapped_area)
rv = get_unmapped_area(file, orig_addr, len, pgoff, flags);
unuse_pde(pde);
Expand Down
4 changes: 3 additions & 1 deletion fs/proc/task_mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
frame = pte_pfn(pte);
flags = PM_PRESENT;
page = vm_normal_page(vma, addr, pte);
if (pte_soft_dirty(pte))
flags2 |= __PM_SOFT_DIRTY;
} else if (is_swap_pte(pte)) {
swp_entry_t entry;
if (pte_swp_soft_dirty(pte))
Expand All @@ -960,7 +962,7 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,

if (page && !PageAnon(page))
flags |= PM_FILE;
if ((vma->vm_flags & VM_SOFTDIRTY) || pte_soft_dirty(pte))
if ((vma->vm_flags & VM_SOFTDIRTY))
flags2 |= __PM_SOFT_DIRTY;

*pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags);
Expand Down
50 changes: 11 additions & 39 deletions include/linux/memcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,47 +137,24 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
extern void mem_cgroup_replace_page_cache(struct page *oldpage,
struct page *newpage);

/**
* mem_cgroup_toggle_oom - toggle the memcg OOM killer for the current task
* @new: true to enable, false to disable
*
* Toggle whether a failed memcg charge should invoke the OOM killer
* or just return -ENOMEM. Returns the previous toggle state.
*
* NOTE: Any path that enables the OOM killer before charging must
* call mem_cgroup_oom_synchronize() afterward to finalize the
* OOM handling and clean up.
*/
static inline bool mem_cgroup_toggle_oom(bool new)
static inline void mem_cgroup_oom_enable(void)
{
bool old;

old = current->memcg_oom.may_oom;
current->memcg_oom.may_oom = new;

return old;
WARN_ON(current->memcg_oom.may_oom);
current->memcg_oom.may_oom = 1;
}

static inline void mem_cgroup_enable_oom(void)
static inline void mem_cgroup_oom_disable(void)
{
bool old = mem_cgroup_toggle_oom(true);

WARN_ON(old == true);
}

static inline void mem_cgroup_disable_oom(void)
{
bool old = mem_cgroup_toggle_oom(false);

WARN_ON(old == false);
WARN_ON(!current->memcg_oom.may_oom);
current->memcg_oom.may_oom = 0;
}

static inline bool task_in_memcg_oom(struct task_struct *p)
{
return p->memcg_oom.in_memcg_oom;
return p->memcg_oom.memcg;
}

bool mem_cgroup_oom_synchronize(void);
bool mem_cgroup_oom_synchronize(bool wait);

#ifdef CONFIG_MEMCG_SWAP
extern int do_swap_account;
Expand Down Expand Up @@ -402,16 +379,11 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page,
{
}

static inline bool mem_cgroup_toggle_oom(bool new)
{
return false;
}

static inline void mem_cgroup_enable_oom(void)
static inline void mem_cgroup_oom_enable(void)
{
}

static inline void mem_cgroup_disable_oom(void)
static inline void mem_cgroup_oom_disable(void)
{
}

Expand All @@ -420,7 +392,7 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
return false;
}

static inline bool mem_cgroup_oom_synchronize(void)
static inline bool mem_cgroup_oom_synchronize(bool wait)
{
return false;
}
Expand Down
7 changes: 3 additions & 4 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1394,11 +1394,10 @@ struct task_struct {
} memcg_batch;
unsigned int memcg_kmem_skip_account;
struct memcg_oom_info {
struct mem_cgroup *memcg;
gfp_t gfp_mask;
int order;
unsigned int may_oom:1;
unsigned int in_memcg_oom:1;
unsigned int oom_locked:1;
int wakeups;
struct mem_cgroup *wait_on_memcg;
} memcg_oom;
#endif
#ifdef CONFIG_UPROBES
Expand Down
42 changes: 29 additions & 13 deletions ipc/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,12 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,

sem_lock(sma, NULL, -1);

if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
rcu_read_unlock();
return -EIDRM;
}

curr = &sma->sem_base[semnum];

ipc_assert_locked_object(&sma->sem_perm);
Expand Down Expand Up @@ -1336,12 +1342,14 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
int i;

sem_lock(sma, NULL, -1);
if (sma->sem_perm.deleted) {
err = -EIDRM;
goto out_unlock;
}
if(nsems > SEMMSL_FAST) {
if (!ipc_rcu_getref(sma)) {
sem_unlock(sma, -1);
rcu_read_unlock();
err = -EIDRM;
goto out_free;
goto out_unlock;
}
sem_unlock(sma, -1);
rcu_read_unlock();
Expand All @@ -1354,10 +1362,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
rcu_read_lock();
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
rcu_read_unlock();
err = -EIDRM;
goto out_free;
goto out_unlock;
}
}
for (i = 0; i < sma->sem_nsems; i++)
Expand All @@ -1375,8 +1381,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
struct sem_undo *un;

if (!ipc_rcu_getref(sma)) {
rcu_read_unlock();
return -EIDRM;
err = -EIDRM;
goto out_rcu_wakeup;
}
rcu_read_unlock();

Expand Down Expand Up @@ -1404,10 +1410,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
rcu_read_lock();
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
rcu_read_unlock();
err = -EIDRM;
goto out_free;
goto out_unlock;
}

for (i = 0; i < nsems; i++)
Expand All @@ -1431,6 +1435,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
goto out_rcu_wakeup;

sem_lock(sma, NULL, -1);
if (sma->sem_perm.deleted) {
err = -EIDRM;
goto out_unlock;
}
curr = &sma->sem_base[semnum];

switch (cmd) {
Expand Down Expand Up @@ -1836,15 +1844,17 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
if (error)
goto out_rcu_wakeup;

error = -EIDRM;
locknum = sem_lock(sma, sops, nsops);
if (sma->sem_perm.deleted)
goto out_unlock_free;
/*
* semid identifiers are not unique - find_alloc_undo may have
* allocated an undo structure, it was invalidated by an RMID
* and now a new array with received the same id. Check and fail.
* This case can be detected checking un->semid. The existence of
* "un" itself is guaranteed by rcu.
*/
error = -EIDRM;
locknum = sem_lock(sma, sops, nsops);
if (un && un->semid == -1)
goto out_unlock_free;

Expand Down Expand Up @@ -2057,6 +2067,12 @@ void exit_sem(struct task_struct *tsk)
}

sem_lock(sma, NULL, -1);
/* exit_sem raced with IPC_RMID, nothing to do */
if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
rcu_read_unlock();
continue;
}
un = __lookup_undo(ulp, semid);
if (un == NULL) {
/* exit_sem raced with IPC_RMID+semget() that created
Expand Down
27 changes: 21 additions & 6 deletions ipc/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,27 @@
* Pavel Emelianov <xemul@openvz.org>
*
* General sysv ipc locking scheme:
* when doing ipc id lookups, take the ids->rwsem
* rcu_read_lock()
* obtain the ipc object (kern_ipc_perm)
* perform security, capabilities, auditing and permission checks, etc.
* acquire the ipc lock (kern_ipc_perm.lock) throught ipc_lock_object()
* perform data updates (ie: SET, RMID, LOCK/UNLOCK commands)
* rcu_read_lock()
* obtain the ipc object (kern_ipc_perm) by looking up the id in an idr
* tree.
* - perform initial checks (capabilities, auditing and permission,
* etc).
* - perform read-only operations, such as STAT, INFO commands.
* acquire the ipc lock (kern_ipc_perm.lock) through
* ipc_lock_object()
* - perform data updates, such as SET, RMID commands and
* mechanism-specific operations (semop/semtimedop,
* msgsnd/msgrcv, shmat/shmdt).
* drop the ipc lock, through ipc_unlock_object().
* rcu_read_unlock()
*
* The ids->rwsem must be taken when:
* - creating, removing and iterating the existing entries in ipc
* identifier sets.
* - iterating through files under /proc/sysvipc/
*
* Note that sems have a special fast path that avoids kern_ipc_perm.lock -
* see sem_lock().
*/

#include <linux/mm.h>
Expand Down
3 changes: 3 additions & 0 deletions lib/percpu-refcount.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release)
ref->release = release;
return 0;
}
EXPORT_SYMBOL_GPL(percpu_ref_init);

/**
* percpu_ref_cancel_init - cancel percpu_ref_init()
Expand Down Expand Up @@ -84,6 +85,7 @@ void percpu_ref_cancel_init(struct percpu_ref *ref)
free_percpu(ref->pcpu_count);
}
}
EXPORT_SYMBOL_GPL(percpu_ref_cancel_init);

static void percpu_ref_kill_rcu(struct rcu_head *rcu)
{
Expand Down Expand Up @@ -156,3 +158,4 @@ void percpu_ref_kill_and_confirm(struct percpu_ref *ref,

call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu);
}
EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm);
11 changes: 1 addition & 10 deletions mm/filemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1616,7 +1616,6 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
struct inode *inode = mapping->host;
pgoff_t offset = vmf->pgoff;
struct page *page;
bool memcg_oom;
pgoff_t size;
int ret = 0;

Expand All @@ -1625,26 +1624,18 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return VM_FAULT_SIGBUS;

/*
* Do we have something in the page cache already? Either
* way, try readahead, but disable the memcg OOM killer for it
* as readahead is optional and no errors are propagated up
* the fault stack. The OOM killer is enabled while trying to
* instantiate the faulting page individually below.
* Do we have something in the page cache already?
*/
page = find_get_page(mapping, offset);
if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) {
/*
* We found the page, so try async readahead before
* waiting for the lock.
*/
memcg_oom = mem_cgroup_toggle_oom(false);
do_async_mmap_readahead(vma, ra, file, page, offset);
mem_cgroup_toggle_oom(memcg_oom);
} else if (!page) {
/* No page in the page cache at all */
memcg_oom = mem_cgroup_toggle_oom(false);
do_sync_mmap_readahead(vma, ra, file, offset);
mem_cgroup_toggle_oom(memcg_oom);
count_vm_event(PGMAJFAULT);
mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
ret = VM_FAULT_MAJOR;
Expand Down
Loading

0 comments on commit 056cdce

Please sign in to comment.