diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memory.c | 1 | ||||
-rw-r--r-- | mm/oom_kill.c | 17 | ||||
-rw-r--r-- | mm/page_alloc.c | 8 | ||||
-rw-r--r-- | mm/shmem.c | 36 |
4 files changed, 61 insertions, 1 deletions
diff --git a/mm/memory.c b/mm/memory.c index 1cc6bfbd872e..3e503831e042 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1147,6 +1147,7 @@ again: | |||
1147 | print_bad_pte(vma, addr, ptent, page); | 1147 | print_bad_pte(vma, addr, ptent, page); |
1148 | if (unlikely(!__tlb_remove_page(tlb, page))) { | 1148 | if (unlikely(!__tlb_remove_page(tlb, page))) { |
1149 | force_flush = 1; | 1149 | force_flush = 1; |
1150 | addr += PAGE_SIZE; | ||
1150 | break; | 1151 | break; |
1151 | } | 1152 | } |
1152 | continue; | 1153 | continue; |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index bbf405a3a18f..5340f6b91312 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -404,6 +404,23 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | |||
404 | dump_tasks(memcg, nodemask); | 404 | dump_tasks(memcg, nodemask); |
405 | } | 405 | } |
406 | 406 | ||
407 | /* | ||
408 | * Number of OOM killer invocations (including memcg OOM killer). | ||
409 | * Primarily used by PM freezer to check for potential races with | ||
410 | * OOM killed frozen task. | ||
411 | */ | ||
412 | static atomic_t oom_kills = ATOMIC_INIT(0); | ||
413 | |||
414 | int oom_kills_count(void) | ||
415 | { | ||
416 | return atomic_read(&oom_kills); | ||
417 | } | ||
418 | |||
419 | void note_oom_kill(void) | ||
420 | { | ||
421 | atomic_inc(&oom_kills); | ||
422 | } | ||
423 | |||
407 | #define K(x) ((x) << (PAGE_SHIFT-10)) | 424 | #define K(x) ((x) << (PAGE_SHIFT-10)) |
408 | /* | 425 | /* |
409 | * Must be called while holding a reference to p, which will be released upon | 426 | * Must be called while holding a reference to p, which will be released upon |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 736d8e1b6381..9cd36b822444 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2252,6 +2252,14 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | |||
2252 | } | 2252 | } |
2253 | 2253 | ||
2254 | /* | 2254 | /* |
2255 | * PM-freezer should be notified that there might be an OOM killer on | ||
2256 | * its way to kill and wake somebody up. This is too early and we might | ||
2257 | * end up not killing anything but false positives are acceptable. | ||
2258 | * See freeze_processes. | ||
2259 | */ | ||
2260 | note_oom_kill(); | ||
2261 | |||
2262 | /* | ||
2255 | * Go through the zonelist yet one more time, keep very high watermark | 2263 | * Go through the zonelist yet one more time, keep very high watermark |
2256 | * here, this is only to catch a parallel oom killing, we must fail if | 2264 | * here, this is only to catch a parallel oom killing, we must fail if |
2257 | * we're still under heavy pressure. | 2265 | * we're still under heavy pressure. |
diff --git a/mm/shmem.c b/mm/shmem.c index cd6fc7590e54..185836ba53ef 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -2345,6 +2345,32 @@ static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, stru | |||
2345 | return 0; | 2345 | return 0; |
2346 | } | 2346 | } |
2347 | 2347 | ||
2348 | static int shmem_whiteout(struct inode *old_dir, struct dentry *old_dentry) | ||
2349 | { | ||
2350 | struct dentry *whiteout; | ||
2351 | int error; | ||
2352 | |||
2353 | whiteout = d_alloc(old_dentry->d_parent, &old_dentry->d_name); | ||
2354 | if (!whiteout) | ||
2355 | return -ENOMEM; | ||
2356 | |||
2357 | error = shmem_mknod(old_dir, whiteout, | ||
2358 | S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); | ||
2359 | dput(whiteout); | ||
2360 | if (error) | ||
2361 | return error; | ||
2362 | |||
2363 | /* | ||
2364 | * Cheat and hash the whiteout while the old dentry is still in | ||
2365 | * place, instead of playing games with FS_RENAME_DOES_D_MOVE. | ||
2366 | * | ||
2367 | * d_lookup() will consistently find one of them at this point, | ||
2368 | * not sure which one, but that isn't even important. | ||
2369 | */ | ||
2370 | d_rehash(whiteout); | ||
2371 | return 0; | ||
2372 | } | ||
2373 | |||
2348 | /* | 2374 | /* |
2349 | * The VFS layer already does all the dentry stuff for rename, | 2375 | * The VFS layer already does all the dentry stuff for rename, |
2350 | * we just have to decrement the usage count for the target if | 2376 | * we just have to decrement the usage count for the target if |
@@ -2356,7 +2382,7 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc | |||
2356 | struct inode *inode = old_dentry->d_inode; | 2382 | struct inode *inode = old_dentry->d_inode; |
2357 | int they_are_dirs = S_ISDIR(inode->i_mode); | 2383 | int they_are_dirs = S_ISDIR(inode->i_mode); |
2358 | 2384 | ||
2359 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | 2385 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) |
2360 | return -EINVAL; | 2386 | return -EINVAL; |
2361 | 2387 | ||
2362 | if (flags & RENAME_EXCHANGE) | 2388 | if (flags & RENAME_EXCHANGE) |
@@ -2365,6 +2391,14 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc | |||
2365 | if (!simple_empty(new_dentry)) | 2391 | if (!simple_empty(new_dentry)) |
2366 | return -ENOTEMPTY; | 2392 | return -ENOTEMPTY; |
2367 | 2393 | ||
2394 | if (flags & RENAME_WHITEOUT) { | ||
2395 | int error; | ||
2396 | |||
2397 | error = shmem_whiteout(old_dir, old_dentry); | ||
2398 | if (error) | ||
2399 | return error; | ||
2400 | } | ||
2401 | |||
2368 | if (new_dentry->d_inode) { | 2402 | if (new_dentry->d_inode) { |
2369 | (void) shmem_unlink(new_dir, new_dentry); | 2403 | (void) shmem_unlink(new_dir, new_dentry); |
2370 | if (they_are_dirs) { | 2404 | if (they_are_dirs) { |