diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 197ca5eccbae..39de1d6a077a 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -335,19 +335,19 @@ static unsigned shmem_find_get_pages_and_swap(struct address_space *mapping, | |||
335 | pgoff_t start, unsigned int nr_pages, | 335 | pgoff_t start, unsigned int nr_pages, |
336 | struct page **pages, pgoff_t *indices) | 336 | struct page **pages, pgoff_t *indices) |
337 | { | 337 | { |
338 | unsigned int i; | 338 | void **slot; |
339 | unsigned int ret; | 339 | unsigned int ret = 0; |
340 | unsigned int nr_found; | 340 | struct radix_tree_iter iter; |
341 | |||
342 | if (!nr_pages) | ||
343 | return 0; | ||
341 | 344 | ||
342 | rcu_read_lock(); | 345 | rcu_read_lock(); |
343 | restart: | 346 | restart: |
344 | nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, | 347 | radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) { |
345 | (void ***)pages, indices, start, nr_pages); | ||
346 | ret = 0; | ||
347 | for (i = 0; i < nr_found; i++) { | ||
348 | struct page *page; | 348 | struct page *page; |
349 | repeat: | 349 | repeat: |
350 | page = radix_tree_deref_slot((void **)pages[i]); | 350 | page = radix_tree_deref_slot(slot); |
351 | if (unlikely(!page)) | 351 | if (unlikely(!page)) |
352 | continue; | 352 | continue; |
353 | if (radix_tree_exception(page)) { | 353 | if (radix_tree_exception(page)) { |
@@ -364,17 +364,16 @@ repeat: | |||
364 | goto repeat; | 364 | goto repeat; |
365 | 365 | ||
366 | /* Has the page moved? */ | 366 | /* Has the page moved? */ |
367 | if (unlikely(page != *((void **)pages[i]))) { | 367 | if (unlikely(page != *slot)) { |
368 | page_cache_release(page); | 368 | page_cache_release(page); |
369 | goto repeat; | 369 | goto repeat; |
370 | } | 370 | } |
371 | export: | 371 | export: |
372 | indices[ret] = indices[i]; | 372 | indices[ret] = iter.index; |
373 | pages[ret] = page; | 373 | pages[ret] = page; |
374 | ret++; | 374 | if (++ret == nr_pages) |
375 | break; | ||
375 | } | 376 | } |
376 | if (unlikely(!ret && nr_found)) | ||
377 | goto restart; | ||
378 | rcu_read_unlock(); | 377 | rcu_read_unlock(); |
379 | return ret; | 378 | return ret; |
380 | } | 379 | } |
@@ -889,7 +888,7 @@ static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol) | |||
889 | if (!mpol || mpol->mode == MPOL_DEFAULT) | 888 | if (!mpol || mpol->mode == MPOL_DEFAULT) |
890 | return; /* show nothing */ | 889 | return; /* show nothing */ |
891 | 890 | ||
892 | mpol_to_str(buffer, sizeof(buffer), mpol, 1); | 891 | mpol_to_str(buffer, sizeof(buffer), mpol); |
893 | 892 | ||
894 | seq_printf(seq, ",mpol=%s", buffer); | 893 | seq_printf(seq, ",mpol=%s", buffer); |
895 | } | 894 | } |
@@ -2386,6 +2385,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2386 | bool remount) | 2385 | bool remount) |
2387 | { | 2386 | { |
2388 | char *this_char, *value, *rest; | 2387 | char *this_char, *value, *rest; |
2388 | struct mempolicy *mpol = NULL; | ||
2389 | uid_t uid; | 2389 | uid_t uid; |
2390 | gid_t gid; | 2390 | gid_t gid; |
2391 | 2391 | ||
@@ -2414,7 +2414,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2414 | printk(KERN_ERR | 2414 | printk(KERN_ERR |
2415 | "tmpfs: No value for mount option '%s'\n", | 2415 | "tmpfs: No value for mount option '%s'\n", |
2416 | this_char); | 2416 | this_char); |
2417 | return 1; | 2417 | goto error; |
2418 | } | 2418 | } |
2419 | 2419 | ||
2420 | if (!strcmp(this_char,"size")) { | 2420 | if (!strcmp(this_char,"size")) { |
@@ -2463,19 +2463,24 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2463 | if (!gid_valid(sbinfo->gid)) | 2463 | if (!gid_valid(sbinfo->gid)) |
2464 | goto bad_val; | 2464 | goto bad_val; |
2465 | } else if (!strcmp(this_char,"mpol")) { | 2465 | } else if (!strcmp(this_char,"mpol")) { |
2466 | if (mpol_parse_str(value, &sbinfo->mpol, 1)) | 2466 | mpol_put(mpol); |
2467 | mpol = NULL; | ||
2468 | if (mpol_parse_str(value, &mpol)) | ||
2467 | goto bad_val; | 2469 | goto bad_val; |
2468 | } else { | 2470 | } else { |
2469 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", | 2471 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", |
2470 | this_char); | 2472 | this_char); |
2471 | return 1; | 2473 | goto error; |
2472 | } | 2474 | } |
2473 | } | 2475 | } |
2476 | sbinfo->mpol = mpol; | ||
2474 | return 0; | 2477 | return 0; |
2475 | 2478 | ||
2476 | bad_val: | 2479 | bad_val: |
2477 | printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", | 2480 | printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", |
2478 | value, this_char); | 2481 | value, this_char); |
2482 | error: | ||
2483 | mpol_put(mpol); | ||
2479 | return 1; | 2484 | return 1; |
2480 | 2485 | ||
2481 | } | 2486 | } |
@@ -2487,6 +2492,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) | |||
2487 | unsigned long inodes; | 2492 | unsigned long inodes; |
2488 | int error = -EINVAL; | 2493 | int error = -EINVAL; |
2489 | 2494 | ||
2495 | config.mpol = NULL; | ||
2490 | if (shmem_parse_options(data, &config, true)) | 2496 | if (shmem_parse_options(data, &config, true)) |
2491 | return error; | 2497 | return error; |
2492 | 2498 | ||
@@ -2511,8 +2517,13 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) | |||
2511 | sbinfo->max_inodes = config.max_inodes; | 2517 | sbinfo->max_inodes = config.max_inodes; |
2512 | sbinfo->free_inodes = config.max_inodes - inodes; | 2518 | sbinfo->free_inodes = config.max_inodes - inodes; |
2513 | 2519 | ||
2514 | mpol_put(sbinfo->mpol); | 2520 | /* |
2515 | sbinfo->mpol = config.mpol; /* transfers initial ref */ | 2521 | * Preserve previous mempolicy unless mpol remount option was specified. |
2522 | */ | ||
2523 | if (config.mpol) { | ||
2524 | mpol_put(sbinfo->mpol); | ||
2525 | sbinfo->mpol = config.mpol; /* transfers initial ref */ | ||
2526 | } | ||
2516 | out: | 2527 | out: |
2517 | spin_unlock(&sbinfo->stat_lock); | 2528 | spin_unlock(&sbinfo->stat_lock); |
2518 | return error; | 2529 | return error; |
@@ -2545,6 +2556,7 @@ static void shmem_put_super(struct super_block *sb) | |||
2545 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); | 2556 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); |
2546 | 2557 | ||
2547 | percpu_counter_destroy(&sbinfo->used_blocks); | 2558 | percpu_counter_destroy(&sbinfo->used_blocks); |
2559 | mpol_put(sbinfo->mpol); | ||
2548 | kfree(sbinfo); | 2560 | kfree(sbinfo); |
2549 | sb->s_fs_info = NULL; | 2561 | sb->s_fs_info = NULL; |
2550 | } | 2562 | } |