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:
 "15 fixes"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  MAINTAINERS: add IIO include files
  kernel/panic.c: update comments for print_tainted
  mem-hotplug: reset node present pages when hot-adding a new pgdat
  mem-hotplug: reset node managed pages when hot-adding a new pgdat
  mm/debug-pagealloc: correct freepage accounting and order resetting
  fanotify: fix notification of groups with inode & mount marks
  mm, compaction: prevent infinite loop in compact_zone
  mm: alloc_contig_range: demote pages busy message from warn to info
  mm/slab: fix unalignment problem on Malta with EVA due to slab merge
  mm/page_alloc: restrict max order of merging on isolated pageblock
  mm/page_alloc: move freepage counting logic to __free_one_page()
  mm/page_alloc: add freepage on isolate pageblock to correct buddy list
  mm/page_alloc: fix incorrect isolation behavior by rechecking migratetype
  mm/compaction: skip the range until proper target pageblock is met
  zram: avoid kunmap_atomic() of a NULL pointer
  • Loading branch information
torvalds committed Nov 14, 2014
2 parents b0ab3f1 + 8fe671f commit 971ad4e
Show file tree
Hide file tree
Showing 19 changed files with 240 additions and 76 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4716,6 +4716,7 @@ L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/
F: drivers/staging/iio/
F: include/linux/iio/

IKANOS/ADI EAGLE ADSL USB DRIVER
M: Matthieu Castet <castet.matthieu@free.fr>
Expand Down
3 changes: 2 additions & 1 deletion drivers/block/zram/zram_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
}

if (page_zero_filled(uncmem)) {
kunmap_atomic(user_mem);
if (user_mem)
kunmap_atomic(user_mem);
/* Free memory associated with this sector now. */
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
zram_free_page(zram, index);
Expand Down
36 changes: 21 additions & 15 deletions fs/notify/fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
&fsnotify_mark_srcu);
}

/*
* We need to merge inode & vfsmount mark lists so that inode mark
* ignore masks are properly reflected for mount mark notifications.
* That's why this traversal is so complicated...
*/
while (inode_node || vfsmount_node) {
inode_group = vfsmount_group = NULL;
inode_group = NULL;
inode_mark = NULL;
vfsmount_group = NULL;
vfsmount_mark = NULL;

if (inode_node) {
inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
Expand All @@ -244,21 +252,19 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
vfsmount_group = vfsmount_mark->group;
}

if (inode_group > vfsmount_group) {
/* handle inode */
ret = send_to_group(to_tell, inode_mark, NULL, mask,
data, data_is, cookie, file_name);
/* we didn't use the vfsmount_mark */
vfsmount_group = NULL;
} else if (vfsmount_group > inode_group) {
ret = send_to_group(to_tell, NULL, vfsmount_mark, mask,
data, data_is, cookie, file_name);
inode_group = NULL;
} else {
ret = send_to_group(to_tell, inode_mark, vfsmount_mark,
mask, data, data_is, cookie,
file_name);
if (inode_group && vfsmount_group) {
int cmp = fsnotify_compare_groups(inode_group,
vfsmount_group);
if (cmp > 0) {
inode_group = NULL;
inode_mark = NULL;
} else if (cmp < 0) {
vfsmount_group = NULL;
vfsmount_mark = NULL;
}
}
ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask,
data, data_is, cookie, file_name);

if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
goto out;
Expand Down
4 changes: 4 additions & 0 deletions fs/notify/fsnotify.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group);
/* protects reads of inode and vfsmount marks list */
extern struct srcu_struct fsnotify_mark_srcu;

/* compare two groups for sorting of marks lists */
extern int fsnotify_compare_groups(struct fsnotify_group *a,
struct fsnotify_group *b);

extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark,
__u32 mask);
/* add a mark to an inode */
Expand Down
8 changes: 3 additions & 5 deletions fs/notify/inode_mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
{
struct fsnotify_mark *lmark, *last = NULL;
int ret = 0;
int cmp;

mark->flags |= FSNOTIFY_MARK_FLAG_INODE;

Expand All @@ -219,11 +220,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
goto out;
}

if (mark->group->priority < lmark->group->priority)
continue;

if ((mark->group->priority == lmark->group->priority) &&
(mark->group < lmark->group))
cmp = fsnotify_compare_groups(lmark->group, mark->group);
if (cmp < 0)
continue;

hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list);
Expand Down
36 changes: 36 additions & 0 deletions fs/notify/mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,42 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas
mark->ignored_mask = mask;
}

/*
* Sorting function for lists of fsnotify marks.
*
* Fanotify supports different notification classes (reflected as priority of
* notification group). Events shall be passed to notification groups in
* decreasing priority order. To achieve this marks in notification lists for
* inodes and vfsmounts are sorted so that priorities of corresponding groups
* are descending.
*
* Furthermore correct handling of the ignore mask requires processing inode
* and vfsmount marks of each group together. Using the group address as
* further sort criterion provides a unique sorting order and thus we can
* merge inode and vfsmount lists of marks in linear time and find groups
* present in both lists.
*
* A return value of 1 signifies that b has priority over a.
* A return value of 0 signifies that the two marks have to be handled together.
* A return value of -1 signifies that a has priority over b.
*/
int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
{
if (a == b)
return 0;
if (!a)
return 1;
if (!b)
return -1;
if (a->priority < b->priority)
return 1;
if (a->priority > b->priority)
return -1;
if (a < b)
return 1;
return -1;
}

/*
* Attach an initialized mark to a given group and fs object.
* These marks may be used for the fsnotify backend to determine which
Expand Down
8 changes: 3 additions & 5 deletions fs/notify/vfsmount_mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
struct mount *m = real_mount(mnt);
struct fsnotify_mark *lmark, *last = NULL;
int ret = 0;
int cmp;

mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT;

Expand All @@ -178,11 +179,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
goto out;
}

if (mark->group->priority < lmark->group->priority)
continue;

if ((mark->group->priority == lmark->group->priority) &&
(mark->group < lmark->group))
cmp = fsnotify_compare_groups(lmark->group, mark->group);
if (cmp < 0)
continue;

hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list);
Expand Down
1 change: 1 addition & 0 deletions include/linux/bootmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern unsigned long init_bootmem_node(pg_data_t *pgdat,
extern unsigned long init_bootmem(unsigned long addr, unsigned long memend);

extern unsigned long free_all_bootmem(void);
extern void reset_node_managed_pages(pg_data_t *pgdat);
extern void reset_all_zones_managed_pages(void);

extern void free_bootmem_node(pg_data_t *pgdat,
Expand Down
9 changes: 9 additions & 0 deletions include/linux/mmzone.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,15 @@ struct zone {
*/
int nr_migrate_reserve_block;

#ifdef CONFIG_MEMORY_ISOLATION
/*
* Number of isolated pageblock. It is used to solve incorrect
* freepage counting problem due to racy retrieving migratetype
* of pageblock. Protected by zone->lock.
*/
unsigned long nr_isolate_pageblock;
#endif

#ifdef CONFIG_MEMORY_HOTPLUG
/* see spanned/present_pages for more description */
seqlock_t span_seqlock;
Expand Down
8 changes: 8 additions & 0 deletions include/linux/page-isolation.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#define __LINUX_PAGEISOLATION_H

#ifdef CONFIG_MEMORY_ISOLATION
static inline bool has_isolate_pageblock(struct zone *zone)
{
return zone->nr_isolate_pageblock;
}
static inline bool is_migrate_isolate_page(struct page *page)
{
return get_pageblock_migratetype(page) == MIGRATE_ISOLATE;
Expand All @@ -11,6 +15,10 @@ static inline bool is_migrate_isolate(int migratetype)
return migratetype == MIGRATE_ISOLATE;
}
#else
static inline bool has_isolate_pageblock(struct zone *zone)
{
return false;
}
static inline bool is_migrate_isolate_page(struct page *page)
{
return false;
Expand Down
1 change: 1 addition & 0 deletions kernel/panic.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ static const struct tnt tnts[] = {
* 'I' - Working around severe firmware bug.
* 'O' - Out-of-tree module has been loaded.
* 'E' - Unsigned module has been loaded.
* 'L' - A soft lockup has previously occurred.
*
* The string is overwritten by the next call to print_tainted().
*/
Expand Down
9 changes: 5 additions & 4 deletions mm/bootmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,10 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)

static int reset_managed_pages_done __initdata;

static inline void __init reset_node_managed_pages(pg_data_t *pgdat)
void reset_node_managed_pages(pg_data_t *pgdat)
{
struct zone *z;

if (reset_managed_pages_done)
return;

for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
z->managed_pages = 0;
}
Expand All @@ -258,8 +255,12 @@ void __init reset_all_zones_managed_pages(void)
{
struct pglist_data *pgdat;

if (reset_managed_pages_done)
return;

for_each_online_pgdat(pgdat)
reset_node_managed_pages(pgdat);

reset_managed_pages_done = 1;
}

Expand Down
18 changes: 16 additions & 2 deletions mm/compaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,16 @@ isolate_freepages_range(struct compact_control *cc,

block_end_pfn = min(block_end_pfn, end_pfn);

/*
* pfn could pass the block_end_pfn if isolated freepage
* is more than pageblock order. In this case, we adjust
* scanning range to right one.
*/
if (pfn >= block_end_pfn) {
block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
block_end_pfn = min(block_end_pfn, end_pfn);
}

if (!pageblock_pfn_to_page(pfn, block_end_pfn, cc->zone))
break;

Expand Down Expand Up @@ -1029,8 +1039,12 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
}

acct_isolated(zone, cc);
/* Record where migration scanner will be restarted */
cc->migrate_pfn = low_pfn;
/*
* Record where migration scanner will be restarted. If we end up in
* the same pageblock as the free scanner, make the scanners fully
* meet so that compact_finished() terminates compaction.
*/
cc->migrate_pfn = (end_pfn <= cc->free_pfn) ? low_pfn : cc->free_pfn;

return cc->nr_migratepages ? ISOLATE_SUCCESS : ISOLATE_NONE;
}
Expand Down
25 changes: 25 additions & 0 deletions mm/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,31 @@ extern pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address);
/*
* in mm/page_alloc.c
*/

/*
* Locate the struct page for both the matching buddy in our
* pair (buddy1) and the combined O(n+1) page they form (page).
*
* 1) Any buddy B1 will have an order O twin B2 which satisfies
* the following equation:
* B2 = B1 ^ (1 << O)
* For example, if the starting buddy (buddy2) is #8 its order
* 1 buddy is #10:
* B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
*
* 2) Any buddy B will have an order O+1 parent P which
* satisfies the following equation:
* P = B & ~(1 << O)
*
* Assumption: *_mem_map is contiguous at least up to MAX_ORDER
*/
static inline unsigned long
__find_buddy_index(unsigned long page_idx, unsigned int order)
{
return page_idx ^ (1 << order);
}

extern int __isolate_free_page(struct page *page, unsigned int order);
extern void __free_pages_bootmem(struct page *page, unsigned int order);
extern void prep_compound_page(struct page *page, unsigned long order);
#ifdef CONFIG_MEMORY_FAILURE
Expand Down
26 changes: 26 additions & 0 deletions mm/memory_hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/stop_machine.h>
#include <linux/hugetlb.h>
#include <linux/memblock.h>
#include <linux/bootmem.h>

#include <asm/tlbflush.h>

Expand Down Expand Up @@ -1066,6 +1067,16 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
}
#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */

static void reset_node_present_pages(pg_data_t *pgdat)
{
struct zone *z;

for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
z->present_pages = 0;

pgdat->node_present_pages = 0;
}

/* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
{
Expand Down Expand Up @@ -1096,6 +1107,21 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
build_all_zonelists(pgdat, NULL);
mutex_unlock(&zonelists_mutex);

/*
* zone->managed_pages is set to an approximate value in
* free_area_init_core(), which will cause
* /sys/device/system/node/nodeX/meminfo has wrong data.
* So reset it to 0 before any memory is onlined.
*/
reset_node_managed_pages(pgdat);

/*
* When memory is hot-added, all the memory is in offline state. So
* clear all zones' present_pages because they will be updated in
* online_pages() and offline_pages().
*/
reset_node_present_pages(pgdat);

return pgdat;
}

Expand Down
8 changes: 5 additions & 3 deletions mm/nobootmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,10 @@ static unsigned long __init free_low_memory_core_early(void)

static int reset_managed_pages_done __initdata;

static inline void __init reset_node_managed_pages(pg_data_t *pgdat)
void reset_node_managed_pages(pg_data_t *pgdat)
{
struct zone *z;

if (reset_managed_pages_done)
return;
for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
z->managed_pages = 0;
}
Expand All @@ -159,8 +157,12 @@ void __init reset_all_zones_managed_pages(void)
{
struct pglist_data *pgdat;

if (reset_managed_pages_done)
return;

for_each_online_pgdat(pgdat)
reset_node_managed_pages(pgdat);

reset_managed_pages_done = 1;
}

Expand Down
Loading

0 comments on commit 971ad4e

Please sign in to comment.