mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +00:00
Merge branch 'akpm' (fixes from Andrew)
Merge patches from Andrew Morton: "13 fixes" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: mm: place page->pmd_huge_pte to right union MAINTAINERS: add keyboard driver to Hyper-V file list x86, mm: do not leak page->ptl for pmd page tables ipc,shm: correct error return value in shmctl (SHM_UNLOCK) mm, mempolicy: silence gcc warning block/partitions/efi.c: fix bound check ARM: drivers/rtc/rtc-at91rm9200.c: disable interrupts at shutdown mm: hugetlbfs: fix hugetlbfs optimization kernel: remove CONFIG_USE_GENERIC_SMP_HELPERS cleanly ipc,shm: fix shm_file deletion races mm: thp: give transparent hugepage code a separate copy_page checkpatch: fix "Use of uninitialized value" warnings configfs: fix race between dentry put and lookup
This commit is contained in:
commit
a5d6e63323
@ -63,9 +63,9 @@ levels.
|
||||
PMD split lock enabling requires pgtable_pmd_page_ctor() call on PMD table
|
||||
allocation and pgtable_pmd_page_dtor() on freeing.
|
||||
|
||||
Allocation usually happens in pmd_alloc_one(), freeing in pmd_free(), but
|
||||
make sure you cover all PMD table allocation / freeing paths: i.e X86_PAE
|
||||
preallocate few PMDs on pgd_alloc().
|
||||
Allocation usually happens in pmd_alloc_one(), freeing in pmd_free() and
|
||||
pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing
|
||||
paths: i.e X86_PAE preallocate few PMDs on pgd_alloc().
|
||||
|
||||
With everything in place you can set CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK.
|
||||
|
||||
|
@ -4065,6 +4065,7 @@ F: arch/x86/include/uapi/asm/hyperv.h
|
||||
F: arch/x86/kernel/cpu/mshyperv.c
|
||||
F: drivers/hid/hid-hyperv.c
|
||||
F: drivers/hv/
|
||||
F: drivers/input/serio/hyperv-keyboard.c
|
||||
F: drivers/net/hyperv/
|
||||
F: drivers/scsi/storvsc_drv.c
|
||||
F: drivers/video/hyperv_fb.c
|
||||
|
@ -61,6 +61,7 @@ void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
|
||||
#if PAGETABLE_LEVELS > 2
|
||||
void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
|
||||
{
|
||||
struct page *page = virt_to_page(pmd);
|
||||
paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT);
|
||||
/*
|
||||
* NOTE! For PAE, any changes to the top page-directory-pointer-table
|
||||
@ -69,7 +70,8 @@ void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
|
||||
#ifdef CONFIG_X86_PAE
|
||||
tlb->need_flush_all = 1;
|
||||
#endif
|
||||
tlb_remove_page(tlb, virt_to_page(pmd));
|
||||
pgtable_pmd_page_dtor(page);
|
||||
tlb_remove_page(tlb, page);
|
||||
}
|
||||
|
||||
#if PAGETABLE_LEVELS > 3
|
||||
|
@ -96,6 +96,7 @@
|
||||
* - Code works, detects all the partitions.
|
||||
*
|
||||
************************************************************/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/math64.h>
|
||||
@ -715,8 +716,8 @@ int efi_partition(struct parsed_partitions *state)
|
||||
efi_guid_unparse(&ptes[i].unique_partition_guid, info->uuid);
|
||||
|
||||
/* Naively convert UTF16-LE to 7 bits. */
|
||||
label_max = min(sizeof(info->volname) - 1,
|
||||
sizeof(ptes[i].partition_name));
|
||||
label_max = min(ARRAY_SIZE(info->volname) - 1,
|
||||
ARRAY_SIZE(ptes[i].partition_name));
|
||||
info->volname[label_max] = 0;
|
||||
while (label_count < label_max) {
|
||||
u8 c = ptes[i].partition_name[label_count] & 0xff;
|
||||
|
@ -223,7 +223,7 @@ static void null_softirq_done_fn(struct request *rq)
|
||||
blk_end_request_all(rq, 0);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS)
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
static void null_ipi_cmd_end_io(void *data)
|
||||
{
|
||||
@ -260,7 +260,7 @@ static void null_cmd_end_ipi(struct nullb_cmd *cmd)
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP && CONFIG_USE_GENERIC_SMP_HELPERS */
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
static inline void null_handle_cmd(struct nullb_cmd *cmd)
|
||||
{
|
||||
@ -270,7 +270,7 @@ static inline void null_handle_cmd(struct nullb_cmd *cmd)
|
||||
end_cmd(cmd);
|
||||
break;
|
||||
case NULL_IRQ_SOFTIRQ:
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS)
|
||||
#ifdef CONFIG_SMP
|
||||
null_cmd_end_ipi(cmd);
|
||||
#else
|
||||
end_cmd(cmd);
|
||||
@ -571,7 +571,7 @@ static int __init null_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
#if !defined(CONFIG_SMP) || !defined(CONFIG_USE_GENERIC_SMP_HELPERS)
|
||||
#if !defined(CONFIG_SMP)
|
||||
if (irqmode == NULL_IRQ_SOFTIRQ) {
|
||||
pr_warn("null_blk: softirq completions not available.\n");
|
||||
pr_warn("null_blk: using direct completions.\n");
|
||||
|
@ -428,6 +428,14 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at91_rtc_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
/* Disable all interrupts */
|
||||
at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
|
||||
AT91_RTC_SECEV | AT91_RTC_TIMEV |
|
||||
AT91_RTC_CALEV);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
/* AT91RM9200 RTC Power management control */
|
||||
@ -466,6 +474,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
|
||||
|
||||
static struct platform_driver at91_rtc_driver = {
|
||||
.remove = __exit_p(at91_rtc_remove),
|
||||
.shutdown = at91_rtc_shutdown,
|
||||
.driver = {
|
||||
.name = "at91_rtc",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -56,10 +56,19 @@ static void configfs_d_iput(struct dentry * dentry,
|
||||
struct configfs_dirent *sd = dentry->d_fsdata;
|
||||
|
||||
if (sd) {
|
||||
BUG_ON(sd->s_dentry != dentry);
|
||||
/* Coordinate with configfs_readdir */
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
sd->s_dentry = NULL;
|
||||
/* Coordinate with configfs_attach_attr where will increase
|
||||
* sd->s_count and update sd->s_dentry to new allocated one.
|
||||
* Only set sd->dentry to null when this dentry is the only
|
||||
* sd owner.
|
||||
* If not do so, configfs_d_iput may run just after
|
||||
* configfs_attach_attr and set sd->s_dentry to null
|
||||
* even it's still in use.
|
||||
*/
|
||||
if (atomic_read(&sd->s_count) <= 2)
|
||||
sd->s_dentry = NULL;
|
||||
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
configfs_put(sd);
|
||||
}
|
||||
@ -416,8 +425,11 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
|
||||
struct configfs_attribute * attr = sd->s_element;
|
||||
int error;
|
||||
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
dentry->d_fsdata = configfs_get(sd);
|
||||
sd->s_dentry = dentry;
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
|
||||
error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG,
|
||||
configfs_init_file);
|
||||
if (error) {
|
||||
|
@ -31,6 +31,7 @@ struct hugepage_subpool *hugepage_new_subpool(long nr_blocks);
|
||||
void hugepage_put_subpool(struct hugepage_subpool *spool);
|
||||
|
||||
int PageHuge(struct page *page);
|
||||
int PageHeadHuge(struct page *page_head);
|
||||
|
||||
void reset_vma_resv_huge_pages(struct vm_area_struct *vma);
|
||||
int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *);
|
||||
@ -69,7 +70,6 @@ int dequeue_hwpoisoned_huge_page(struct page *page);
|
||||
bool isolate_huge_page(struct page *page, struct list_head *list);
|
||||
void putback_active_hugepage(struct page *page);
|
||||
bool is_hugepage_active(struct page *page);
|
||||
void copy_huge_page(struct page *dst, struct page *src);
|
||||
|
||||
#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
|
||||
pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
|
||||
@ -104,6 +104,11 @@ static inline int PageHuge(struct page *page)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int PageHeadHuge(struct page *page_head)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma)
|
||||
{
|
||||
}
|
||||
@ -140,9 +145,6 @@ static inline int dequeue_hwpoisoned_huge_page(struct page *page)
|
||||
#define isolate_huge_page(p, l) false
|
||||
#define putback_active_hugepage(p) do {} while (0)
|
||||
#define is_hugepage_active(x) false
|
||||
static inline void copy_huge_page(struct page *dst, struct page *src)
|
||||
{
|
||||
}
|
||||
|
||||
static inline unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
|
||||
unsigned long address, unsigned long end, pgprot_t newprot)
|
||||
|
@ -65,9 +65,6 @@ struct page {
|
||||
* this page is only used to
|
||||
* free other pages.
|
||||
*/
|
||||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && USE_SPLIT_PMD_PTLOCKS
|
||||
pgtable_t pmd_huge_pte; /* protected by page->ptl */
|
||||
#endif
|
||||
};
|
||||
|
||||
union {
|
||||
@ -135,6 +132,9 @@ struct page {
|
||||
|
||||
struct list_head list; /* slobs list of pages */
|
||||
struct slab *slab_page; /* slab fields */
|
||||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && USE_SPLIT_PMD_PTLOCKS
|
||||
pgtable_t pmd_huge_pte; /* protected by page->ptl */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Remainder is not double word aligned */
|
||||
|
37
ipc/shm.c
37
ipc/shm.c
@ -208,15 +208,18 @@ static void shm_open(struct vm_area_struct *vma)
|
||||
*/
|
||||
static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
|
||||
{
|
||||
struct file *shm_file;
|
||||
|
||||
shm_file = shp->shm_file;
|
||||
shp->shm_file = NULL;
|
||||
ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
shm_rmid(ns, shp);
|
||||
shm_unlock(shp);
|
||||
if (!is_file_hugepages(shp->shm_file))
|
||||
shmem_lock(shp->shm_file, 0, shp->mlock_user);
|
||||
if (!is_file_hugepages(shm_file))
|
||||
shmem_lock(shm_file, 0, shp->mlock_user);
|
||||
else if (shp->mlock_user)
|
||||
user_shm_unlock(file_inode(shp->shm_file)->i_size,
|
||||
shp->mlock_user);
|
||||
fput (shp->shm_file);
|
||||
user_shm_unlock(file_inode(shm_file)->i_size, shp->mlock_user);
|
||||
fput(shm_file);
|
||||
ipc_rcu_putref(shp, shm_rcu_free);
|
||||
}
|
||||
|
||||
@ -974,15 +977,25 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
|
||||
ipc_lock_object(&shp->shm_perm);
|
||||
if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
|
||||
kuid_t euid = current_euid();
|
||||
err = -EPERM;
|
||||
if (!uid_eq(euid, shp->shm_perm.uid) &&
|
||||
!uid_eq(euid, shp->shm_perm.cuid))
|
||||
!uid_eq(euid, shp->shm_perm.cuid)) {
|
||||
err = -EPERM;
|
||||
goto out_unlock0;
|
||||
if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
|
||||
}
|
||||
if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) {
|
||||
err = -EPERM;
|
||||
goto out_unlock0;
|
||||
}
|
||||
}
|
||||
|
||||
shm_file = shp->shm_file;
|
||||
|
||||
/* check if shm_destroy() is tearing down shp */
|
||||
if (shm_file == NULL) {
|
||||
err = -EIDRM;
|
||||
goto out_unlock0;
|
||||
}
|
||||
|
||||
if (is_file_hugepages(shm_file))
|
||||
goto out_unlock0;
|
||||
|
||||
@ -1101,6 +1114,14 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
|
||||
goto out_unlock;
|
||||
|
||||
ipc_lock_object(&shp->shm_perm);
|
||||
|
||||
/* check if shm_destroy() is tearing down shp */
|
||||
if (shp->shm_file == NULL) {
|
||||
ipc_unlock_object(&shp->shm_perm);
|
||||
err = -EIDRM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
path = shp->shm_file->f_path;
|
||||
path_get(&path);
|
||||
shp->shm_nattch++;
|
||||
|
51
mm/hugetlb.c
51
mm/hugetlb.c
@ -476,40 +476,6 @@ static int vma_has_reserves(struct vm_area_struct *vma, long chg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void copy_gigantic_page(struct page *dst, struct page *src)
|
||||
{
|
||||
int i;
|
||||
struct hstate *h = page_hstate(src);
|
||||
struct page *dst_base = dst;
|
||||
struct page *src_base = src;
|
||||
|
||||
for (i = 0; i < pages_per_huge_page(h); ) {
|
||||
cond_resched();
|
||||
copy_highpage(dst, src);
|
||||
|
||||
i++;
|
||||
dst = mem_map_next(dst, dst_base, i);
|
||||
src = mem_map_next(src, src_base, i);
|
||||
}
|
||||
}
|
||||
|
||||
void copy_huge_page(struct page *dst, struct page *src)
|
||||
{
|
||||
int i;
|
||||
struct hstate *h = page_hstate(src);
|
||||
|
||||
if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) {
|
||||
copy_gigantic_page(dst, src);
|
||||
return;
|
||||
}
|
||||
|
||||
might_sleep();
|
||||
for (i = 0; i < pages_per_huge_page(h); i++) {
|
||||
cond_resched();
|
||||
copy_highpage(dst + i, src + i);
|
||||
}
|
||||
}
|
||||
|
||||
static void enqueue_huge_page(struct hstate *h, struct page *page)
|
||||
{
|
||||
int nid = page_to_nid(page);
|
||||
@ -736,6 +702,23 @@ int PageHuge(struct page *page)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(PageHuge);
|
||||
|
||||
/*
|
||||
* PageHeadHuge() only returns true for hugetlbfs head page, but not for
|
||||
* normal or transparent huge pages.
|
||||
*/
|
||||
int PageHeadHuge(struct page *page_head)
|
||||
{
|
||||
compound_page_dtor *dtor;
|
||||
|
||||
if (!PageHead(page_head))
|
||||
return 0;
|
||||
|
||||
dtor = get_compound_page_dtor(page_head);
|
||||
|
||||
return dtor == free_huge_page;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(PageHeadHuge);
|
||||
|
||||
pgoff_t __basepage_index(struct page *page)
|
||||
{
|
||||
struct page *page_head = compound_head(page);
|
||||
|
@ -2950,7 +2950,7 @@ void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
|
||||
return;
|
||||
}
|
||||
|
||||
p += snprintf(p, maxlen, policy_modes[mode]);
|
||||
p += snprintf(p, maxlen, "%s", policy_modes[mode]);
|
||||
|
||||
if (flags & MPOL_MODE_FLAGS) {
|
||||
p += snprintf(p, buffer + maxlen - p, "=");
|
||||
|
48
mm/migrate.c
48
mm/migrate.c
@ -441,6 +441,54 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
|
||||
return MIGRATEPAGE_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gigantic pages are so large that we do not guarantee that page++ pointer
|
||||
* arithmetic will work across the entire page. We need something more
|
||||
* specialized.
|
||||
*/
|
||||
static void __copy_gigantic_page(struct page *dst, struct page *src,
|
||||
int nr_pages)
|
||||
{
|
||||
int i;
|
||||
struct page *dst_base = dst;
|
||||
struct page *src_base = src;
|
||||
|
||||
for (i = 0; i < nr_pages; ) {
|
||||
cond_resched();
|
||||
copy_highpage(dst, src);
|
||||
|
||||
i++;
|
||||
dst = mem_map_next(dst, dst_base, i);
|
||||
src = mem_map_next(src, src_base, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_huge_page(struct page *dst, struct page *src)
|
||||
{
|
||||
int i;
|
||||
int nr_pages;
|
||||
|
||||
if (PageHuge(src)) {
|
||||
/* hugetlbfs page */
|
||||
struct hstate *h = page_hstate(src);
|
||||
nr_pages = pages_per_huge_page(h);
|
||||
|
||||
if (unlikely(nr_pages > MAX_ORDER_NR_PAGES)) {
|
||||
__copy_gigantic_page(dst, src, nr_pages);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* thp page */
|
||||
BUG_ON(!PageTransHuge(src));
|
||||
nr_pages = hpage_nr_pages(src);
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
cond_resched();
|
||||
copy_highpage(dst + i, src + i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the page to its new location
|
||||
*/
|
||||
|
143
mm/swap.c
143
mm/swap.c
@ -82,19 +82,6 @@ static void __put_compound_page(struct page *page)
|
||||
|
||||
static void put_compound_page(struct page *page)
|
||||
{
|
||||
/*
|
||||
* hugetlbfs pages cannot be split from under us. If this is a
|
||||
* hugetlbfs page, check refcount on head page and release the page if
|
||||
* the refcount becomes zero.
|
||||
*/
|
||||
if (PageHuge(page)) {
|
||||
page = compound_head(page);
|
||||
if (put_page_testzero(page))
|
||||
__put_compound_page(page);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(PageTail(page))) {
|
||||
/* __split_huge_page_refcount can run under us */
|
||||
struct page *page_head = compound_trans_head(page);
|
||||
@ -111,14 +98,31 @@ static void put_compound_page(struct page *page)
|
||||
* still hot on arches that do not support
|
||||
* this_cpu_cmpxchg_double().
|
||||
*/
|
||||
if (PageSlab(page_head)) {
|
||||
if (PageTail(page)) {
|
||||
if (PageSlab(page_head) || PageHeadHuge(page_head)) {
|
||||
if (likely(PageTail(page))) {
|
||||
/*
|
||||
* __split_huge_page_refcount
|
||||
* cannot race here.
|
||||
*/
|
||||
VM_BUG_ON(!PageHead(page_head));
|
||||
atomic_dec(&page->_mapcount);
|
||||
if (put_page_testzero(page_head))
|
||||
VM_BUG_ON(1);
|
||||
|
||||
atomic_dec(&page->_mapcount);
|
||||
goto skip_lock_tail;
|
||||
if (put_page_testzero(page_head))
|
||||
__put_compound_page(page_head);
|
||||
return;
|
||||
} else
|
||||
/*
|
||||
* __split_huge_page_refcount
|
||||
* run before us, "page" was a
|
||||
* THP tail. The split
|
||||
* page_head has been freed
|
||||
* and reallocated as slab or
|
||||
* hugetlbfs page of smaller
|
||||
* order (only possible if
|
||||
* reallocated as slab on
|
||||
* x86).
|
||||
*/
|
||||
goto skip_lock;
|
||||
}
|
||||
/*
|
||||
@ -132,8 +136,27 @@ static void put_compound_page(struct page *page)
|
||||
/* __split_huge_page_refcount run before us */
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
skip_lock:
|
||||
if (put_page_testzero(page_head))
|
||||
__put_single_page(page_head);
|
||||
if (put_page_testzero(page_head)) {
|
||||
/*
|
||||
* The head page may have been
|
||||
* freed and reallocated as a
|
||||
* compound page of smaller
|
||||
* order and then freed again.
|
||||
* All we know is that it
|
||||
* cannot have become: a THP
|
||||
* page, a compound page of
|
||||
* higher order, a tail page.
|
||||
* That is because we still
|
||||
* hold the refcount of the
|
||||
* split THP tail and
|
||||
* page_head was the THP head
|
||||
* before the split.
|
||||
*/
|
||||
if (PageHead(page_head))
|
||||
__put_compound_page(page_head);
|
||||
else
|
||||
__put_single_page(page_head);
|
||||
}
|
||||
out_put_single:
|
||||
if (put_page_testzero(page))
|
||||
__put_single_page(page);
|
||||
@ -155,7 +178,6 @@ static void put_compound_page(struct page *page)
|
||||
VM_BUG_ON(atomic_read(&page->_count) != 0);
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
|
||||
skip_lock_tail:
|
||||
if (put_page_testzero(page_head)) {
|
||||
if (PageHead(page_head))
|
||||
__put_compound_page(page_head);
|
||||
@ -198,51 +220,52 @@ bool __get_page_tail(struct page *page)
|
||||
* proper PT lock that already serializes against
|
||||
* split_huge_page().
|
||||
*/
|
||||
unsigned long flags;
|
||||
bool got = false;
|
||||
struct page *page_head;
|
||||
struct page *page_head = compound_trans_head(page);
|
||||
|
||||
/*
|
||||
* If this is a hugetlbfs page it cannot be split under us. Simply
|
||||
* increment refcount for the head page.
|
||||
*/
|
||||
if (PageHuge(page)) {
|
||||
page_head = compound_head(page);
|
||||
atomic_inc(&page_head->_count);
|
||||
got = true;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
|
||||
page_head = compound_trans_head(page);
|
||||
if (likely(page != page_head &&
|
||||
get_page_unless_zero(page_head))) {
|
||||
|
||||
/* Ref to put_compound_page() comment. */
|
||||
if (PageSlab(page_head)) {
|
||||
if (likely(PageTail(page))) {
|
||||
__get_page_tail_foll(page, false);
|
||||
return true;
|
||||
} else {
|
||||
put_page(page_head);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* page_head wasn't a dangling pointer but it
|
||||
* may not be a head page anymore by the time
|
||||
* we obtain the lock. That is ok as long as it
|
||||
* can't be freed from under us.
|
||||
*/
|
||||
flags = compound_lock_irqsave(page_head);
|
||||
/* here __split_huge_page_refcount won't run anymore */
|
||||
if (likely(page != page_head && get_page_unless_zero(page_head))) {
|
||||
/* Ref to put_compound_page() comment. */
|
||||
if (PageSlab(page_head) || PageHeadHuge(page_head)) {
|
||||
if (likely(PageTail(page))) {
|
||||
/*
|
||||
* This is a hugetlbfs page or a slab
|
||||
* page. __split_huge_page_refcount
|
||||
* cannot race here.
|
||||
*/
|
||||
VM_BUG_ON(!PageHead(page_head));
|
||||
__get_page_tail_foll(page, false);
|
||||
got = true;
|
||||
}
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
if (unlikely(!got))
|
||||
return true;
|
||||
} else {
|
||||
/*
|
||||
* __split_huge_page_refcount run
|
||||
* before us, "page" was a THP
|
||||
* tail. The split page_head has been
|
||||
* freed and reallocated as slab or
|
||||
* hugetlbfs page of smaller order
|
||||
* (only possible if reallocated as
|
||||
* slab on x86).
|
||||
*/
|
||||
put_page(page_head);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* page_head wasn't a dangling pointer but it
|
||||
* may not be a head page anymore by the time
|
||||
* we obtain the lock. That is ok as long as it
|
||||
* can't be freed from under us.
|
||||
*/
|
||||
flags = compound_lock_irqsave(page_head);
|
||||
/* here __split_huge_page_refcount won't run anymore */
|
||||
if (likely(PageTail(page))) {
|
||||
__get_page_tail_foll(page, false);
|
||||
got = true;
|
||||
}
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
if (unlikely(!got))
|
||||
put_page(page_head);
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ source "net/hsr/Kconfig"
|
||||
|
||||
config RPS
|
||||
boolean
|
||||
depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
|
||||
depends on SMP && SYSFS
|
||||
default y
|
||||
|
||||
config RFS_ACCEL
|
||||
@ -235,7 +235,7 @@ config RFS_ACCEL
|
||||
|
||||
config XPS
|
||||
boolean
|
||||
depends on SMP && USE_GENERIC_SMP_HELPERS
|
||||
depends on SMP
|
||||
default y
|
||||
|
||||
config NETPRIO_CGROUP
|
||||
|
@ -3289,6 +3289,7 @@ sub process {
|
||||
}
|
||||
}
|
||||
if (!defined $suppress_whiletrailers{$linenr} &&
|
||||
defined($stat) && defined($cond) &&
|
||||
$line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
|
||||
my ($s, $c) = ($stat, $cond);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user