Skip to content

Commit 570203e

Browse files
committed
Merge branch 'akpm' (patches from Andrew)
Merge vm fixes from Andrew Morton: "5 fixes" * emailed patches from Andrew Morton <[email protected]>: mm/sparse: fix kernel crash with pfn_section_valid check mm: fork: fix kernel_stack memcg stats for various stack implementations hugetlb_cgroup: fix illegal access to memory drivers/base/memory.c: indicate all memory blocks as removable mm/swapfile.c: move inode_lock out of claim_swapfile
2 parents ab93e98 + b943f04 commit 570203e

File tree

7 files changed

+82
-45
lines changed

7 files changed

+82
-45
lines changed

drivers/base/memory.c

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -97,30 +97,13 @@ static ssize_t phys_index_show(struct device *dev,
9797
}
9898

9999
/*
100-
* Show whether the memory block is likely to be offlineable (or is already
101-
* offline). Once offline, the memory block could be removed. The return
102-
* value does, however, not indicate that there is a way to remove the
103-
* memory block.
100+
* Legacy interface that we cannot remove. Always indicate "removable"
101+
* with CONFIG_MEMORY_HOTREMOVE - bad heuristic.
104102
*/
105103
static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
106104
char *buf)
107105
{
108-
struct memory_block *mem = to_memory_block(dev);
109-
unsigned long pfn;
110-
int ret = 1, i;
111-
112-
if (mem->state != MEM_ONLINE)
113-
goto out;
114-
115-
for (i = 0; i < sections_per_block; i++) {
116-
if (!present_section_nr(mem->start_section_nr + i))
117-
continue;
118-
pfn = section_nr_to_pfn(mem->start_section_nr + i);
119-
ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
120-
}
121-
122-
out:
123-
return sprintf(buf, "%d\n", ret);
106+
return sprintf(buf, "%d\n", (int)IS_ENABLED(CONFIG_MEMORY_HOTREMOVE));
124107
}
125108

126109
/*

include/linux/memcontrol.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
695695
void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
696696
int val);
697697
void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val);
698+
void mod_memcg_obj_state(void *p, int idx, int val);
698699

699700
static inline void mod_lruvec_state(struct lruvec *lruvec,
700701
enum node_stat_item idx, int val)
@@ -1123,6 +1124,10 @@ static inline void __mod_lruvec_slab_state(void *p, enum node_stat_item idx,
11231124
__mod_node_page_state(page_pgdat(page), idx, val);
11241125
}
11251126

1127+
static inline void mod_memcg_obj_state(void *p, int idx, int val)
1128+
{
1129+
}
1130+
11261131
static inline
11271132
unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
11281133
gfp_t gfp_mask,
@@ -1427,6 +1432,8 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)
14271432
return memcg ? memcg->kmemcg_id : -1;
14281433
}
14291434

1435+
struct mem_cgroup *mem_cgroup_from_obj(void *p);
1436+
14301437
#else
14311438

14321439
static inline int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
@@ -1468,6 +1475,11 @@ static inline void memcg_put_cache_ids(void)
14681475
{
14691476
}
14701477

1478+
static inline struct mem_cgroup *mem_cgroup_from_obj(void *p)
1479+
{
1480+
return NULL;
1481+
}
1482+
14711483
#endif /* CONFIG_MEMCG_KMEM */
14721484

14731485
#endif /* _LINUX_MEMCONTROL_H */

kernel/fork.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ static void account_kernel_stack(struct task_struct *tsk, int account)
397397
mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB,
398398
THREAD_SIZE / 1024 * account);
399399

400-
mod_memcg_page_state(first_page, MEMCG_KERNEL_STACK_KB,
401-
account * (THREAD_SIZE / 1024));
400+
mod_memcg_obj_state(stack, MEMCG_KERNEL_STACK_KB,
401+
account * (THREAD_SIZE / 1024));
402402
}
403403
}
404404

mm/hugetlb_cgroup.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,7 @@ int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
240240
if (!page_counter_try_charge(&h_cg->hugepage[idx], nr_pages,
241241
&counter)) {
242242
ret = -ENOMEM;
243-
hugetlb_event(hugetlb_cgroup_from_counter(counter, idx), idx,
244-
HUGETLB_MAX);
243+
hugetlb_event(h_cg, idx, HUGETLB_MAX);
245244
}
246245
css_put(&h_cg->css);
247246
done:

mm/memcontrol.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,17 @@ void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val)
777777
rcu_read_unlock();
778778
}
779779

780+
void mod_memcg_obj_state(void *p, int idx, int val)
781+
{
782+
struct mem_cgroup *memcg;
783+
784+
rcu_read_lock();
785+
memcg = mem_cgroup_from_obj(p);
786+
if (memcg)
787+
mod_memcg_state(memcg, idx, val);
788+
rcu_read_unlock();
789+
}
790+
780791
/**
781792
* __count_memcg_events - account VM events in a cgroup
782793
* @memcg: the memory cgroup
@@ -2661,6 +2672,33 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg,
26612672
}
26622673

26632674
#ifdef CONFIG_MEMCG_KMEM
2675+
/*
2676+
* Returns a pointer to the memory cgroup to which the kernel object is charged.
2677+
*
2678+
* The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(),
2679+
* cgroup_mutex, etc.
2680+
*/
2681+
struct mem_cgroup *mem_cgroup_from_obj(void *p)
2682+
{
2683+
struct page *page;
2684+
2685+
if (mem_cgroup_disabled())
2686+
return NULL;
2687+
2688+
page = virt_to_head_page(p);
2689+
2690+
/*
2691+
* Slab pages don't have page->mem_cgroup set because corresponding
2692+
* kmem caches can be reparented during the lifetime. That's why
2693+
* memcg_from_slab_page() should be used instead.
2694+
*/
2695+
if (PageSlab(page))
2696+
return memcg_from_slab_page(page);
2697+
2698+
/* All other pages use page->mem_cgroup */
2699+
return page->mem_cgroup;
2700+
}
2701+
26642702
static int memcg_alloc_cache_id(void)
26652703
{
26662704
int id, size;

mm/sparse.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,12 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
781781
ms->usage = NULL;
782782
}
783783
memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
784+
/*
785+
* Mark the section invalid so that valid_section()
786+
* return false. This prevents code from dereferencing
787+
* ms->usage array.
788+
*/
789+
ms->section_mem_map &= ~SECTION_HAS_MEM_MAP;
784790
}
785791

786792
if (section_is_early && memmap)

mm/swapfile.c

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2899,10 +2899,6 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
28992899
p->bdev = inode->i_sb->s_bdev;
29002900
}
29012901

2902-
inode_lock(inode);
2903-
if (IS_SWAPFILE(inode))
2904-
return -EBUSY;
2905-
29062902
return 0;
29072903
}
29082904

@@ -3157,36 +3153,41 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
31573153
mapping = swap_file->f_mapping;
31583154
inode = mapping->host;
31593155

3160-
/* will take i_rwsem; */
31613156
error = claim_swapfile(p, inode);
31623157
if (unlikely(error))
31633158
goto bad_swap;
31643159

3160+
inode_lock(inode);
3161+
if (IS_SWAPFILE(inode)) {
3162+
error = -EBUSY;
3163+
goto bad_swap_unlock_inode;
3164+
}
3165+
31653166
/*
31663167
* Read the swap header.
31673168
*/
31683169
if (!mapping->a_ops->readpage) {
31693170
error = -EINVAL;
3170-
goto bad_swap;
3171+
goto bad_swap_unlock_inode;
31713172
}
31723173
page = read_mapping_page(mapping, 0, swap_file);
31733174
if (IS_ERR(page)) {
31743175
error = PTR_ERR(page);
3175-
goto bad_swap;
3176+
goto bad_swap_unlock_inode;
31763177
}
31773178
swap_header = kmap(page);
31783179

31793180
maxpages = read_swap_header(p, swap_header, inode);
31803181
if (unlikely(!maxpages)) {
31813182
error = -EINVAL;
3182-
goto bad_swap;
3183+
goto bad_swap_unlock_inode;
31833184
}
31843185

31853186
/* OK, set up the swap map and apply the bad block list */
31863187
swap_map = vzalloc(maxpages);
31873188
if (!swap_map) {
31883189
error = -ENOMEM;
3189-
goto bad_swap;
3190+
goto bad_swap_unlock_inode;
31903191
}
31913192

31923193
if (bdi_cap_stable_pages_required(inode_to_bdi(inode)))
@@ -3211,7 +3212,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
32113212
GFP_KERNEL);
32123213
if (!cluster_info) {
32133214
error = -ENOMEM;
3214-
goto bad_swap;
3215+
goto bad_swap_unlock_inode;
32153216
}
32163217

32173218
for (ci = 0; ci < nr_cluster; ci++)
@@ -3220,7 +3221,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
32203221
p->percpu_cluster = alloc_percpu(struct percpu_cluster);
32213222
if (!p->percpu_cluster) {
32223223
error = -ENOMEM;
3223-
goto bad_swap;
3224+
goto bad_swap_unlock_inode;
32243225
}
32253226
for_each_possible_cpu(cpu) {
32263227
struct percpu_cluster *cluster;
@@ -3234,13 +3235,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
32343235

32353236
error = swap_cgroup_swapon(p->type, maxpages);
32363237
if (error)
3237-
goto bad_swap;
3238+
goto bad_swap_unlock_inode;
32383239

32393240
nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map,
32403241
cluster_info, maxpages, &span);
32413242
if (unlikely(nr_extents < 0)) {
32423243
error = nr_extents;
3243-
goto bad_swap;
3244+
goto bad_swap_unlock_inode;
32443245
}
32453246
/* frontswap enabled? set up bit-per-page map for frontswap */
32463247
if (IS_ENABLED(CONFIG_FRONTSWAP))
@@ -3280,7 +3281,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
32803281

32813282
error = init_swap_address_space(p->type, maxpages);
32823283
if (error)
3283-
goto bad_swap;
3284+
goto bad_swap_unlock_inode;
32843285

32853286
/*
32863287
* Flush any pending IO and dirty mappings before we start using this
@@ -3290,7 +3291,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
32903291
error = inode_drain_writes(inode);
32913292
if (error) {
32923293
inode->i_flags &= ~S_SWAPFILE;
3293-
goto bad_swap;
3294+
goto bad_swap_unlock_inode;
32943295
}
32953296

32963297
mutex_lock(&swapon_mutex);
@@ -3315,13 +3316,16 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
33153316

33163317
error = 0;
33173318
goto out;
3319+
bad_swap_unlock_inode:
3320+
inode_unlock(inode);
33183321
bad_swap:
33193322
free_percpu(p->percpu_cluster);
33203323
p->percpu_cluster = NULL;
33213324
if (inode && S_ISBLK(inode->i_mode) && p->bdev) {
33223325
set_blocksize(p->bdev, p->old_block_size);
33233326
blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
33243327
}
3328+
inode = NULL;
33253329
destroy_swap_extents(p);
33263330
swap_cgroup_swapoff(p->type);
33273331
spin_lock(&swap_lock);
@@ -3333,13 +3337,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
33333337
kvfree(frontswap_map);
33343338
if (inced_nr_rotate_swap)
33353339
atomic_dec(&nr_rotate_swap);
3336-
if (swap_file) {
3337-
if (inode) {
3338-
inode_unlock(inode);
3339-
inode = NULL;
3340-
}
3340+
if (swap_file)
33413341
filp_close(swap_file, NULL);
3342-
}
33433342
out:
33443343
if (page && !IS_ERR(page)) {
33453344
kunmap(page);

0 commit comments

Comments
 (0)