diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/btrfs/extent-tree.c | 27 | ||||
| -rw-r--r-- | fs/btrfs/scrub.c | 2 | ||||
| -rw-r--r-- | fs/ext3/namei.c | 2 | ||||
| -rw-r--r-- | fs/ext4/balloc.c | 4 | ||||
| -rw-r--r-- | fs/ext4/extents.c | 23 | ||||
| -rw-r--r-- | fs/ext4/extents_status.c | 73 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 19 | ||||
| -rw-r--r-- | fs/ext4/mballoc.c | 11 | ||||
| -rw-r--r-- | fs/ext4/namei.c | 2 | ||||
| -rw-r--r-- | fs/ext4/page-io.c | 35 | ||||
| -rw-r--r-- | fs/ext4/super.c | 14 | ||||
| -rw-r--r-- | fs/lockd/svclock.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 21 | ||||
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/nfsd.h | 1 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 13 | ||||
| -rw-r--r-- | fs/open.c | 2 | ||||
| -rw-r--r-- | fs/proc/vmcore.c | 2 | ||||
| -rw-r--r-- | fs/super.c | 25 | ||||
| -rw-r--r-- | fs/sysfs/group.c | 70 |
20 files changed, 222 insertions, 130 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0236de711989..1204c8ef6f32 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -7466,6 +7466,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7466 | int err = 0; | 7466 | int err = 0; |
| 7467 | int ret; | 7467 | int ret; |
| 7468 | int level; | 7468 | int level; |
| 7469 | bool root_dropped = false; | ||
| 7469 | 7470 | ||
| 7470 | path = btrfs_alloc_path(); | 7471 | path = btrfs_alloc_path(); |
| 7471 | if (!path) { | 7472 | if (!path) { |
| @@ -7523,6 +7524,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7523 | while (1) { | 7524 | while (1) { |
| 7524 | btrfs_tree_lock(path->nodes[level]); | 7525 | btrfs_tree_lock(path->nodes[level]); |
| 7525 | btrfs_set_lock_blocking(path->nodes[level]); | 7526 | btrfs_set_lock_blocking(path->nodes[level]); |
| 7527 | path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; | ||
| 7526 | 7528 | ||
| 7527 | ret = btrfs_lookup_extent_info(trans, root, | 7529 | ret = btrfs_lookup_extent_info(trans, root, |
| 7528 | path->nodes[level]->start, | 7530 | path->nodes[level]->start, |
| @@ -7538,6 +7540,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7538 | break; | 7540 | break; |
| 7539 | 7541 | ||
| 7540 | btrfs_tree_unlock(path->nodes[level]); | 7542 | btrfs_tree_unlock(path->nodes[level]); |
| 7543 | path->locks[level] = 0; | ||
| 7541 | WARN_ON(wc->refs[level] != 1); | 7544 | WARN_ON(wc->refs[level] != 1); |
| 7542 | level--; | 7545 | level--; |
| 7543 | } | 7546 | } |
| @@ -7552,11 +7555,6 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7552 | wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); | 7555 | wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); |
| 7553 | 7556 | ||
| 7554 | while (1) { | 7557 | while (1) { |
| 7555 | if (!for_reloc && btrfs_need_cleaner_sleep(root)) { | ||
| 7556 | pr_debug("btrfs: drop snapshot early exit\n"); | ||
| 7557 | err = -EAGAIN; | ||
| 7558 | goto out_end_trans; | ||
| 7559 | } | ||
| 7560 | 7558 | ||
| 7561 | ret = walk_down_tree(trans, root, path, wc); | 7559 | ret = walk_down_tree(trans, root, path, wc); |
| 7562 | if (ret < 0) { | 7560 | if (ret < 0) { |
| @@ -7584,7 +7582,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7584 | } | 7582 | } |
| 7585 | 7583 | ||
| 7586 | BUG_ON(wc->level == 0); | 7584 | BUG_ON(wc->level == 0); |
| 7587 | if (btrfs_should_end_transaction(trans, tree_root)) { | 7585 | if (btrfs_should_end_transaction(trans, tree_root) || |
| 7586 | (!for_reloc && btrfs_need_cleaner_sleep(root))) { | ||
| 7588 | ret = btrfs_update_root(trans, tree_root, | 7587 | ret = btrfs_update_root(trans, tree_root, |
| 7589 | &root->root_key, | 7588 | &root->root_key, |
| 7590 | root_item); | 7589 | root_item); |
| @@ -7595,6 +7594,12 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7595 | } | 7594 | } |
| 7596 | 7595 | ||
| 7597 | btrfs_end_transaction_throttle(trans, tree_root); | 7596 | btrfs_end_transaction_throttle(trans, tree_root); |
| 7597 | if (!for_reloc && btrfs_need_cleaner_sleep(root)) { | ||
| 7598 | pr_debug("btrfs: drop snapshot early exit\n"); | ||
| 7599 | err = -EAGAIN; | ||
| 7600 | goto out_free; | ||
| 7601 | } | ||
| 7602 | |||
| 7598 | trans = btrfs_start_transaction(tree_root, 0); | 7603 | trans = btrfs_start_transaction(tree_root, 0); |
| 7599 | if (IS_ERR(trans)) { | 7604 | if (IS_ERR(trans)) { |
| 7600 | err = PTR_ERR(trans); | 7605 | err = PTR_ERR(trans); |
| @@ -7639,12 +7644,22 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7639 | free_extent_buffer(root->commit_root); | 7644 | free_extent_buffer(root->commit_root); |
| 7640 | btrfs_put_fs_root(root); | 7645 | btrfs_put_fs_root(root); |
| 7641 | } | 7646 | } |
| 7647 | root_dropped = true; | ||
| 7642 | out_end_trans: | 7648 | out_end_trans: |
| 7643 | btrfs_end_transaction_throttle(trans, tree_root); | 7649 | btrfs_end_transaction_throttle(trans, tree_root); |
| 7644 | out_free: | 7650 | out_free: |
| 7645 | kfree(wc); | 7651 | kfree(wc); |
| 7646 | btrfs_free_path(path); | 7652 | btrfs_free_path(path); |
| 7647 | out: | 7653 | out: |
| 7654 | /* | ||
| 7655 | * So if we need to stop dropping the snapshot for whatever reason we | ||
| 7656 | * need to make sure to add it back to the dead root list so that we | ||
| 7657 | * keep trying to do the work later. This also cleans up roots if we | ||
| 7658 | * don't have it in the radix (like when we recover after a power fail | ||
| 7659 | * or unmount) so we don't leak memory. | ||
| 7660 | */ | ||
| 7661 | if (root_dropped == false) | ||
| 7662 | btrfs_add_dead_root(root); | ||
| 7648 | if (err) | 7663 | if (err) |
| 7649 | btrfs_std_error(root->fs_info, err); | 7664 | btrfs_std_error(root->fs_info, err); |
| 7650 | return err; | 7665 | return err; |
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 4ba2a69a60ad..64a157becbe5 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
| @@ -2495,7 +2495,7 @@ again: | |||
| 2495 | ret = scrub_extent(sctx, extent_logical, extent_len, | 2495 | ret = scrub_extent(sctx, extent_logical, extent_len, |
| 2496 | extent_physical, extent_dev, flags, | 2496 | extent_physical, extent_dev, flags, |
| 2497 | generation, extent_mirror_num, | 2497 | generation, extent_mirror_num, |
| 2498 | extent_physical); | 2498 | extent_logical - logical + physical); |
| 2499 | if (ret) | 2499 | if (ret) |
| 2500 | goto out; | 2500 | goto out; |
| 2501 | 2501 | ||
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 998ea111e537..1194b1f0f839 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
| @@ -1780,11 +1780,11 @@ retry: | |||
| 1780 | inode->i_op = &ext3_file_inode_operations; | 1780 | inode->i_op = &ext3_file_inode_operations; |
| 1781 | inode->i_fop = &ext3_file_operations; | 1781 | inode->i_fop = &ext3_file_operations; |
| 1782 | ext3_set_aops(inode); | 1782 | ext3_set_aops(inode); |
| 1783 | d_tmpfile(dentry, inode); | ||
| 1783 | err = ext3_orphan_add(handle, inode); | 1784 | err = ext3_orphan_add(handle, inode); |
| 1784 | if (err) | 1785 | if (err) |
| 1785 | goto err_drop_inode; | 1786 | goto err_drop_inode; |
| 1786 | mark_inode_dirty(inode); | 1787 | mark_inode_dirty(inode); |
| 1787 | d_tmpfile(dentry, inode); | ||
| 1788 | unlock_new_inode(inode); | 1788 | unlock_new_inode(inode); |
| 1789 | } | 1789 | } |
| 1790 | ext3_journal_stop(handle); | 1790 | ext3_journal_stop(handle); |
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 58339393fa6e..ddd715e42a5c 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
| @@ -38,8 +38,8 @@ ext4_group_t ext4_get_group_number(struct super_block *sb, | |||
| 38 | ext4_group_t group; | 38 | ext4_group_t group; |
| 39 | 39 | ||
| 40 | if (test_opt2(sb, STD_GROUP_SIZE)) | 40 | if (test_opt2(sb, STD_GROUP_SIZE)) |
| 41 | group = (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + | 41 | group = (block - |
| 42 | block) >> | 42 | le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) >> |
| 43 | (EXT4_BLOCK_SIZE_BITS(sb) + EXT4_CLUSTER_BITS(sb) + 3); | 43 | (EXT4_BLOCK_SIZE_BITS(sb) + EXT4_CLUSTER_BITS(sb) + 3); |
| 44 | else | 44 | else |
| 45 | ext4_get_group_no_and_offset(sb, block, &group, NULL); | 45 | ext4_get_group_no_and_offset(sb, block, &group, NULL); |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 7097b0f680e6..a61873808f76 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -2835,6 +2835,9 @@ again: | |||
| 2835 | err = -EIO; | 2835 | err = -EIO; |
| 2836 | break; | 2836 | break; |
| 2837 | } | 2837 | } |
| 2838 | /* Yield here to deal with large extent trees. | ||
| 2839 | * Should be a no-op if we did IO above. */ | ||
| 2840 | cond_resched(); | ||
| 2838 | if (WARN_ON(i + 1 > depth)) { | 2841 | if (WARN_ON(i + 1 > depth)) { |
| 2839 | err = -EIO; | 2842 | err = -EIO; |
| 2840 | break; | 2843 | break; |
| @@ -4261,8 +4264,8 @@ got_allocated_blocks: | |||
| 4261 | /* not a good idea to call discard here directly, | 4264 | /* not a good idea to call discard here directly, |
| 4262 | * but otherwise we'd need to call it every free() */ | 4265 | * but otherwise we'd need to call it every free() */ |
| 4263 | ext4_discard_preallocations(inode); | 4266 | ext4_discard_preallocations(inode); |
| 4264 | ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex), | 4267 | ext4_free_blocks(handle, inode, NULL, newblock, |
| 4265 | ext4_ext_get_actual_len(&newex), fb_flags); | 4268 | EXT4_C2B(sbi, allocated_clusters), fb_flags); |
| 4266 | goto out2; | 4269 | goto out2; |
| 4267 | } | 4270 | } |
| 4268 | 4271 | ||
| @@ -4382,8 +4385,9 @@ out2: | |||
| 4382 | } | 4385 | } |
| 4383 | 4386 | ||
| 4384 | out3: | 4387 | out3: |
| 4385 | trace_ext4_ext_map_blocks_exit(inode, flags, map, err ? err : allocated); | 4388 | trace_ext4_ext_map_blocks_exit(inode, flags, map, |
| 4386 | 4389 | err ? err : allocated); | |
| 4390 | ext4_es_lru_add(inode); | ||
| 4387 | return err ? err : allocated; | 4391 | return err ? err : allocated; |
| 4388 | } | 4392 | } |
| 4389 | 4393 | ||
| @@ -4405,9 +4409,20 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode) | |||
| 4405 | 4409 | ||
| 4406 | last_block = (inode->i_size + sb->s_blocksize - 1) | 4410 | last_block = (inode->i_size + sb->s_blocksize - 1) |
| 4407 | >> EXT4_BLOCK_SIZE_BITS(sb); | 4411 | >> EXT4_BLOCK_SIZE_BITS(sb); |
| 4412 | retry: | ||
| 4408 | err = ext4_es_remove_extent(inode, last_block, | 4413 | err = ext4_es_remove_extent(inode, last_block, |
| 4409 | EXT_MAX_BLOCKS - last_block); | 4414 | EXT_MAX_BLOCKS - last_block); |
| 4415 | if (err == ENOMEM) { | ||
| 4416 | cond_resched(); | ||
| 4417 | congestion_wait(BLK_RW_ASYNC, HZ/50); | ||
| 4418 | goto retry; | ||
| 4419 | } | ||
| 4420 | if (err) { | ||
| 4421 | ext4_std_error(inode->i_sb, err); | ||
| 4422 | return; | ||
| 4423 | } | ||
| 4410 | err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); | 4424 | err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); |
| 4425 | ext4_std_error(inode->i_sb, err); | ||
| 4411 | } | 4426 | } |
| 4412 | 4427 | ||
| 4413 | static void ext4_falloc_update_inode(struct inode *inode, | 4428 | static void ext4_falloc_update_inode(struct inode *inode, |
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index ee018d5f397e..91cb110da1b4 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
| @@ -148,6 +148,8 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
| 148 | ext4_lblk_t end); | 148 | ext4_lblk_t end); |
| 149 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, | 149 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, |
| 150 | int nr_to_scan); | 150 | int nr_to_scan); |
| 151 | static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, | ||
| 152 | struct ext4_inode_info *locked_ei); | ||
| 151 | 153 | ||
| 152 | int __init ext4_init_es(void) | 154 | int __init ext4_init_es(void) |
| 153 | { | 155 | { |
| @@ -439,7 +441,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, | |||
| 439 | */ | 441 | */ |
| 440 | if (!ext4_es_is_written(es) && !ext4_es_is_unwritten(es)) { | 442 | if (!ext4_es_is_written(es) && !ext4_es_is_unwritten(es)) { |
| 441 | if (in_range(es->es_lblk, ee_block, ee_len)) { | 443 | if (in_range(es->es_lblk, ee_block, ee_len)) { |
| 442 | pr_warn("ES insert assertation failed for " | 444 | pr_warn("ES insert assertion failed for " |
| 443 | "inode: %lu we can find an extent " | 445 | "inode: %lu we can find an extent " |
| 444 | "at block [%d/%d/%llu/%c], but we " | 446 | "at block [%d/%d/%llu/%c], but we " |
| 445 | "want to add an delayed/hole extent " | 447 | "want to add an delayed/hole extent " |
| @@ -458,7 +460,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, | |||
| 458 | */ | 460 | */ |
| 459 | if (es->es_lblk < ee_block || | 461 | if (es->es_lblk < ee_block || |
| 460 | ext4_es_pblock(es) != ee_start + es->es_lblk - ee_block) { | 462 | ext4_es_pblock(es) != ee_start + es->es_lblk - ee_block) { |
| 461 | pr_warn("ES insert assertation failed for inode: %lu " | 463 | pr_warn("ES insert assertion failed for inode: %lu " |
| 462 | "ex_status [%d/%d/%llu/%c] != " | 464 | "ex_status [%d/%d/%llu/%c] != " |
| 463 | "es_status [%d/%d/%llu/%c]\n", inode->i_ino, | 465 | "es_status [%d/%d/%llu/%c]\n", inode->i_ino, |
| 464 | ee_block, ee_len, ee_start, | 466 | ee_block, ee_len, ee_start, |
| @@ -468,7 +470,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, | |||
| 468 | } | 470 | } |
| 469 | 471 | ||
| 470 | if (ee_status ^ es_status) { | 472 | if (ee_status ^ es_status) { |
| 471 | pr_warn("ES insert assertation failed for inode: %lu " | 473 | pr_warn("ES insert assertion failed for inode: %lu " |
| 472 | "ex_status [%d/%d/%llu/%c] != " | 474 | "ex_status [%d/%d/%llu/%c] != " |
| 473 | "es_status [%d/%d/%llu/%c]\n", inode->i_ino, | 475 | "es_status [%d/%d/%llu/%c]\n", inode->i_ino, |
| 474 | ee_block, ee_len, ee_start, | 476 | ee_block, ee_len, ee_start, |
| @@ -481,7 +483,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, | |||
| 481 | * that we don't want to add an written/unwritten extent. | 483 | * that we don't want to add an written/unwritten extent. |
| 482 | */ | 484 | */ |
| 483 | if (!ext4_es_is_delayed(es) && !ext4_es_is_hole(es)) { | 485 | if (!ext4_es_is_delayed(es) && !ext4_es_is_hole(es)) { |
| 484 | pr_warn("ES insert assertation failed for inode: %lu " | 486 | pr_warn("ES insert assertion failed for inode: %lu " |
| 485 | "can't find an extent at block %d but we want " | 487 | "can't find an extent at block %d but we want " |
| 486 | "to add an written/unwritten extent " | 488 | "to add an written/unwritten extent " |
| 487 | "[%d/%d/%llu/%llx]\n", inode->i_ino, | 489 | "[%d/%d/%llu/%llx]\n", inode->i_ino, |
| @@ -519,7 +521,7 @@ static void ext4_es_insert_extent_ind_check(struct inode *inode, | |||
| 519 | * We want to add a delayed/hole extent but this | 521 | * We want to add a delayed/hole extent but this |
| 520 | * block has been allocated. | 522 | * block has been allocated. |
| 521 | */ | 523 | */ |
| 522 | pr_warn("ES insert assertation failed for inode: %lu " | 524 | pr_warn("ES insert assertion failed for inode: %lu " |
| 523 | "We can find blocks but we want to add a " | 525 | "We can find blocks but we want to add a " |
| 524 | "delayed/hole extent [%d/%d/%llu/%llx]\n", | 526 | "delayed/hole extent [%d/%d/%llu/%llx]\n", |
| 525 | inode->i_ino, es->es_lblk, es->es_len, | 527 | inode->i_ino, es->es_lblk, es->es_len, |
| @@ -527,13 +529,13 @@ static void ext4_es_insert_extent_ind_check(struct inode *inode, | |||
| 527 | return; | 529 | return; |
| 528 | } else if (ext4_es_is_written(es)) { | 530 | } else if (ext4_es_is_written(es)) { |
| 529 | if (retval != es->es_len) { | 531 | if (retval != es->es_len) { |
| 530 | pr_warn("ES insert assertation failed for " | 532 | pr_warn("ES insert assertion failed for " |
| 531 | "inode: %lu retval %d != es_len %d\n", | 533 | "inode: %lu retval %d != es_len %d\n", |
| 532 | inode->i_ino, retval, es->es_len); | 534 | inode->i_ino, retval, es->es_len); |
| 533 | return; | 535 | return; |
| 534 | } | 536 | } |
| 535 | if (map.m_pblk != ext4_es_pblock(es)) { | 537 | if (map.m_pblk != ext4_es_pblock(es)) { |
| 536 | pr_warn("ES insert assertation failed for " | 538 | pr_warn("ES insert assertion failed for " |
| 537 | "inode: %lu m_pblk %llu != " | 539 | "inode: %lu m_pblk %llu != " |
| 538 | "es_pblk %llu\n", | 540 | "es_pblk %llu\n", |
| 539 | inode->i_ino, map.m_pblk, | 541 | inode->i_ino, map.m_pblk, |
| @@ -549,7 +551,7 @@ static void ext4_es_insert_extent_ind_check(struct inode *inode, | |||
| 549 | } | 551 | } |
| 550 | } else if (retval == 0) { | 552 | } else if (retval == 0) { |
| 551 | if (ext4_es_is_written(es)) { | 553 | if (ext4_es_is_written(es)) { |
| 552 | pr_warn("ES insert assertation failed for inode: %lu " | 554 | pr_warn("ES insert assertion failed for inode: %lu " |
| 553 | "We can't find the block but we want to add " | 555 | "We can't find the block but we want to add " |
| 554 | "an written extent [%d/%d/%llu/%llx]\n", | 556 | "an written extent [%d/%d/%llu/%llx]\n", |
| 555 | inode->i_ino, es->es_lblk, es->es_len, | 557 | inode->i_ino, es->es_lblk, es->es_len, |
| @@ -632,10 +634,8 @@ out: | |||
| 632 | } | 634 | } |
| 633 | 635 | ||
| 634 | /* | 636 | /* |
| 635 | * ext4_es_insert_extent() adds a space to a extent status tree. | 637 | * ext4_es_insert_extent() adds information to an inode's extent |
| 636 | * | 638 | * status tree. |
| 637 | * ext4_es_insert_extent is called by ext4_da_write_begin and | ||
| 638 | * ext4_es_remove_extent. | ||
| 639 | * | 639 | * |
| 640 | * Return 0 on success, error code on failure. | 640 | * Return 0 on success, error code on failure. |
| 641 | */ | 641 | */ |
| @@ -667,7 +667,13 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, | |||
| 667 | err = __es_remove_extent(inode, lblk, end); | 667 | err = __es_remove_extent(inode, lblk, end); |
| 668 | if (err != 0) | 668 | if (err != 0) |
| 669 | goto error; | 669 | goto error; |
| 670 | retry: | ||
| 670 | err = __es_insert_extent(inode, &newes); | 671 | err = __es_insert_extent(inode, &newes); |
| 672 | if (err == -ENOMEM && __ext4_es_shrink(EXT4_SB(inode->i_sb), 1, | ||
| 673 | EXT4_I(inode))) | ||
| 674 | goto retry; | ||
| 675 | if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) | ||
| 676 | err = 0; | ||
| 671 | 677 | ||
| 672 | error: | 678 | error: |
| 673 | write_unlock(&EXT4_I(inode)->i_es_lock); | 679 | write_unlock(&EXT4_I(inode)->i_es_lock); |
| @@ -746,8 +752,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
| 746 | struct extent_status orig_es; | 752 | struct extent_status orig_es; |
| 747 | ext4_lblk_t len1, len2; | 753 | ext4_lblk_t len1, len2; |
| 748 | ext4_fsblk_t block; | 754 | ext4_fsblk_t block; |
| 749 | int err = 0; | 755 | int err; |
| 750 | 756 | ||
| 757 | retry: | ||
| 758 | err = 0; | ||
| 751 | es = __es_tree_search(&tree->root, lblk); | 759 | es = __es_tree_search(&tree->root, lblk); |
| 752 | if (!es) | 760 | if (!es) |
| 753 | goto out; | 761 | goto out; |
| @@ -782,6 +790,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
| 782 | if (err) { | 790 | if (err) { |
| 783 | es->es_lblk = orig_es.es_lblk; | 791 | es->es_lblk = orig_es.es_lblk; |
| 784 | es->es_len = orig_es.es_len; | 792 | es->es_len = orig_es.es_len; |
| 793 | if ((err == -ENOMEM) && | ||
| 794 | __ext4_es_shrink(EXT4_SB(inode->i_sb), 1, | ||
| 795 | EXT4_I(inode))) | ||
| 796 | goto retry; | ||
| 785 | goto out; | 797 | goto out; |
| 786 | } | 798 | } |
| 787 | } else { | 799 | } else { |
| @@ -891,22 +903,14 @@ static int ext4_inode_touch_time_cmp(void *priv, struct list_head *a, | |||
| 891 | return -1; | 903 | return -1; |
| 892 | } | 904 | } |
| 893 | 905 | ||
| 894 | static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | 906 | static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, |
| 907 | struct ext4_inode_info *locked_ei) | ||
| 895 | { | 908 | { |
| 896 | struct ext4_sb_info *sbi = container_of(shrink, | ||
| 897 | struct ext4_sb_info, s_es_shrinker); | ||
| 898 | struct ext4_inode_info *ei; | 909 | struct ext4_inode_info *ei; |
| 899 | struct list_head *cur, *tmp; | 910 | struct list_head *cur, *tmp; |
| 900 | LIST_HEAD(skiped); | 911 | LIST_HEAD(skiped); |
| 901 | int nr_to_scan = sc->nr_to_scan; | ||
| 902 | int ret, nr_shrunk = 0; | 912 | int ret, nr_shrunk = 0; |
| 903 | 913 | ||
| 904 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | ||
| 905 | trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | ||
| 906 | |||
| 907 | if (!nr_to_scan) | ||
| 908 | return ret; | ||
| 909 | |||
| 910 | spin_lock(&sbi->s_es_lru_lock); | 914 | spin_lock(&sbi->s_es_lru_lock); |
| 911 | 915 | ||
| 912 | /* | 916 | /* |
| @@ -935,7 +939,7 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | |||
| 935 | continue; | 939 | continue; |
| 936 | } | 940 | } |
| 937 | 941 | ||
| 938 | if (ei->i_es_lru_nr == 0) | 942 | if (ei->i_es_lru_nr == 0 || ei == locked_ei) |
| 939 | continue; | 943 | continue; |
| 940 | 944 | ||
| 941 | write_lock(&ei->i_es_lock); | 945 | write_lock(&ei->i_es_lock); |
| @@ -954,6 +958,27 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | |||
| 954 | list_splice_tail(&skiped, &sbi->s_es_lru); | 958 | list_splice_tail(&skiped, &sbi->s_es_lru); |
| 955 | spin_unlock(&sbi->s_es_lru_lock); | 959 | spin_unlock(&sbi->s_es_lru_lock); |
| 956 | 960 | ||
| 961 | if (locked_ei && nr_shrunk == 0) | ||
| 962 | nr_shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan); | ||
| 963 | |||
| 964 | return nr_shrunk; | ||
| 965 | } | ||
| 966 | |||
| 967 | static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | ||
| 968 | { | ||
| 969 | struct ext4_sb_info *sbi = container_of(shrink, | ||
| 970 | struct ext4_sb_info, s_es_shrinker); | ||
| 971 | int nr_to_scan = sc->nr_to_scan; | ||
| 972 | int ret, nr_shrunk; | ||
| 973 | |||
| 974 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | ||
| 975 | trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | ||
| 976 | |||
| 977 | if (!nr_to_scan) | ||
| 978 | return ret; | ||
| 979 | |||
| 980 | nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL); | ||
| 981 | |||
| 957 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | 982 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); |
| 958 | trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret); | 983 | trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret); |
| 959 | return ret; | 984 | return ret; |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0188e65e1f58..ba33c67d6e48 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -465,7 +465,7 @@ static void ext4_map_blocks_es_recheck(handle_t *handle, | |||
| 465 | if (es_map->m_lblk != map->m_lblk || | 465 | if (es_map->m_lblk != map->m_lblk || |
| 466 | es_map->m_flags != map->m_flags || | 466 | es_map->m_flags != map->m_flags || |
| 467 | es_map->m_pblk != map->m_pblk) { | 467 | es_map->m_pblk != map->m_pblk) { |
| 468 | printk("ES cache assertation failed for inode: %lu " | 468 | printk("ES cache assertion failed for inode: %lu " |
| 469 | "es_cached ex [%d/%d/%llu/%x] != " | 469 | "es_cached ex [%d/%d/%llu/%x] != " |
| 470 | "found ex [%d/%d/%llu/%x] retval %d flags %x\n", | 470 | "found ex [%d/%d/%llu/%x] retval %d flags %x\n", |
| 471 | inode->i_ino, es_map->m_lblk, es_map->m_len, | 471 | inode->i_ino, es_map->m_lblk, es_map->m_len, |
| @@ -514,10 +514,9 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
| 514 | "logical block %lu\n", inode->i_ino, flags, map->m_len, | 514 | "logical block %lu\n", inode->i_ino, flags, map->m_len, |
| 515 | (unsigned long) map->m_lblk); | 515 | (unsigned long) map->m_lblk); |
| 516 | 516 | ||
| 517 | ext4_es_lru_add(inode); | ||
| 518 | |||
| 519 | /* Lookup extent status tree firstly */ | 517 | /* Lookup extent status tree firstly */ |
| 520 | if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { | 518 | if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { |
| 519 | ext4_es_lru_add(inode); | ||
| 521 | if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { | 520 | if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { |
| 522 | map->m_pblk = ext4_es_pblock(&es) + | 521 | map->m_pblk = ext4_es_pblock(&es) + |
| 523 | map->m_lblk - es.es_lblk; | 522 | map->m_lblk - es.es_lblk; |
| @@ -558,7 +557,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
| 558 | 557 | ||
| 559 | #ifdef ES_AGGRESSIVE_TEST | 558 | #ifdef ES_AGGRESSIVE_TEST |
| 560 | if (retval != map->m_len) { | 559 | if (retval != map->m_len) { |
| 561 | printk("ES len assertation failed for inode: %lu " | 560 | printk("ES len assertion failed for inode: %lu " |
| 562 | "retval %d != map->m_len %d " | 561 | "retval %d != map->m_len %d " |
| 563 | "in %s (lookup)\n", inode->i_ino, retval, | 562 | "in %s (lookup)\n", inode->i_ino, retval, |
| 564 | map->m_len, __func__); | 563 | map->m_len, __func__); |
| @@ -659,7 +658,7 @@ found: | |||
| 659 | 658 | ||
| 660 | #ifdef ES_AGGRESSIVE_TEST | 659 | #ifdef ES_AGGRESSIVE_TEST |
| 661 | if (retval != map->m_len) { | 660 | if (retval != map->m_len) { |
| 662 | printk("ES len assertation failed for inode: %lu " | 661 | printk("ES len assertion failed for inode: %lu " |
| 663 | "retval %d != map->m_len %d " | 662 | "retval %d != map->m_len %d " |
| 664 | "in %s (allocation)\n", inode->i_ino, retval, | 663 | "in %s (allocation)\n", inode->i_ino, retval, |
| 665 | map->m_len, __func__); | 664 | map->m_len, __func__); |
| @@ -1529,11 +1528,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
| 1529 | "logical block %lu\n", inode->i_ino, map->m_len, | 1528 | "logical block %lu\n", inode->i_ino, map->m_len, |
| 1530 | (unsigned long) map->m_lblk); | 1529 | (unsigned long) map->m_lblk); |
| 1531 | 1530 | ||
| 1532 | ext4_es_lru_add(inode); | ||
| 1533 | |||
| 1534 | /* Lookup extent status tree firstly */ | 1531 | /* Lookup extent status tree firstly */ |
| 1535 | if (ext4_es_lookup_extent(inode, iblock, &es)) { | 1532 | if (ext4_es_lookup_extent(inode, iblock, &es)) { |
| 1536 | 1533 | ext4_es_lru_add(inode); | |
| 1537 | if (ext4_es_is_hole(&es)) { | 1534 | if (ext4_es_is_hole(&es)) { |
| 1538 | retval = 0; | 1535 | retval = 0; |
| 1539 | down_read((&EXT4_I(inode)->i_data_sem)); | 1536 | down_read((&EXT4_I(inode)->i_data_sem)); |
| @@ -1642,7 +1639,7 @@ add_delayed: | |||
| 1642 | 1639 | ||
| 1643 | #ifdef ES_AGGRESSIVE_TEST | 1640 | #ifdef ES_AGGRESSIVE_TEST |
| 1644 | if (retval != map->m_len) { | 1641 | if (retval != map->m_len) { |
| 1645 | printk("ES len assertation failed for inode: %lu " | 1642 | printk("ES len assertion failed for inode: %lu " |
| 1646 | "retval %d != map->m_len %d " | 1643 | "retval %d != map->m_len %d " |
| 1647 | "in %s (lookup)\n", inode->i_ino, retval, | 1644 | "in %s (lookup)\n", inode->i_ino, retval, |
| 1648 | map->m_len, __func__); | 1645 | map->m_len, __func__); |
| @@ -2163,7 +2160,7 @@ static int mpage_map_and_submit_extent(handle_t *handle, | |||
| 2163 | 2160 | ||
| 2164 | mpd->io_submit.io_end->offset = | 2161 | mpd->io_submit.io_end->offset = |
| 2165 | ((loff_t)map->m_lblk) << inode->i_blkbits; | 2162 | ((loff_t)map->m_lblk) << inode->i_blkbits; |
| 2166 | while (map->m_len) { | 2163 | do { |
| 2167 | err = mpage_map_one_extent(handle, mpd); | 2164 | err = mpage_map_one_extent(handle, mpd); |
| 2168 | if (err < 0) { | 2165 | if (err < 0) { |
| 2169 | struct super_block *sb = inode->i_sb; | 2166 | struct super_block *sb = inode->i_sb; |
| @@ -2201,7 +2198,7 @@ static int mpage_map_and_submit_extent(handle_t *handle, | |||
| 2201 | err = mpage_map_and_submit_buffers(mpd); | 2198 | err = mpage_map_and_submit_buffers(mpd); |
| 2202 | if (err < 0) | 2199 | if (err < 0) |
| 2203 | return err; | 2200 | return err; |
| 2204 | } | 2201 | } while (map->m_len); |
| 2205 | 2202 | ||
| 2206 | /* Update on-disk size after IO is submitted */ | 2203 | /* Update on-disk size after IO is submitted */ |
| 2207 | disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT; | 2204 | disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT; |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index a9ff5e5137ca..4bbbf13bd743 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
| @@ -4740,11 +4740,16 @@ do_more: | |||
| 4740 | * blocks being freed are metadata. these blocks shouldn't | 4740 | * blocks being freed are metadata. these blocks shouldn't |
| 4741 | * be used until this transaction is committed | 4741 | * be used until this transaction is committed |
| 4742 | */ | 4742 | */ |
| 4743 | retry: | ||
| 4743 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); | 4744 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); |
| 4744 | if (!new_entry) { | 4745 | if (!new_entry) { |
| 4745 | ext4_mb_unload_buddy(&e4b); | 4746 | /* |
| 4746 | err = -ENOMEM; | 4747 | * We use a retry loop because |
| 4747 | goto error_return; | 4748 | * ext4_free_blocks() is not allowed to fail. |
| 4749 | */ | ||
| 4750 | cond_resched(); | ||
| 4751 | congestion_wait(BLK_RW_ASYNC, HZ/50); | ||
| 4752 | goto retry; | ||
| 4748 | } | 4753 | } |
| 4749 | new_entry->efd_start_cluster = bit; | 4754 | new_entry->efd_start_cluster = bit; |
| 4750 | new_entry->efd_group = block_group; | 4755 | new_entry->efd_group = block_group; |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 234b834d5a97..35f55a0dbc4b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -2316,11 +2316,11 @@ retry: | |||
| 2316 | inode->i_op = &ext4_file_inode_operations; | 2316 | inode->i_op = &ext4_file_inode_operations; |
| 2317 | inode->i_fop = &ext4_file_operations; | 2317 | inode->i_fop = &ext4_file_operations; |
| 2318 | ext4_set_aops(inode); | 2318 | ext4_set_aops(inode); |
| 2319 | d_tmpfile(dentry, inode); | ||
| 2319 | err = ext4_orphan_add(handle, inode); | 2320 | err = ext4_orphan_add(handle, inode); |
| 2320 | if (err) | 2321 | if (err) |
| 2321 | goto err_drop_inode; | 2322 | goto err_drop_inode; |
| 2322 | mark_inode_dirty(inode); | 2323 | mark_inode_dirty(inode); |
| 2323 | d_tmpfile(dentry, inode); | ||
| 2324 | unlock_new_inode(inode); | 2324 | unlock_new_inode(inode); |
| 2325 | } | 2325 | } |
| 2326 | if (handle) | 2326 | if (handle) |
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 48786cdb5e6c..6625d210fb45 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
| 28 | #include <linux/ratelimit.h> | ||
| 28 | 29 | ||
| 29 | #include "ext4_jbd2.h" | 30 | #include "ext4_jbd2.h" |
| 30 | #include "xattr.h" | 31 | #include "xattr.h" |
| @@ -55,7 +56,7 @@ void ext4_exit_pageio(void) | |||
| 55 | static void buffer_io_error(struct buffer_head *bh) | 56 | static void buffer_io_error(struct buffer_head *bh) |
| 56 | { | 57 | { |
| 57 | char b[BDEVNAME_SIZE]; | 58 | char b[BDEVNAME_SIZE]; |
| 58 | printk(KERN_ERR "Buffer I/O error on device %s, logical block %llu\n", | 59 | printk_ratelimited(KERN_ERR "Buffer I/O error on device %s, logical block %llu\n", |
| 59 | bdevname(bh->b_bdev, b), | 60 | bdevname(bh->b_bdev, b), |
| 60 | (unsigned long long)bh->b_blocknr); | 61 | (unsigned long long)bh->b_blocknr); |
| 61 | } | 62 | } |
| @@ -308,6 +309,7 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) | |||
| 308 | return io_end; | 309 | return io_end; |
| 309 | } | 310 | } |
| 310 | 311 | ||
| 312 | /* BIO completion function for page writeback */ | ||
| 311 | static void ext4_end_bio(struct bio *bio, int error) | 313 | static void ext4_end_bio(struct bio *bio, int error) |
| 312 | { | 314 | { |
| 313 | ext4_io_end_t *io_end = bio->bi_private; | 315 | ext4_io_end_t *io_end = bio->bi_private; |
| @@ -318,18 +320,6 @@ static void ext4_end_bio(struct bio *bio, int error) | |||
| 318 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) | 320 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) |
| 319 | error = 0; | 321 | error = 0; |
| 320 | 322 | ||
| 321 | if (io_end->flag & EXT4_IO_END_UNWRITTEN) { | ||
| 322 | /* | ||
| 323 | * Link bio into list hanging from io_end. We have to do it | ||
| 324 | * atomically as bio completions can be racing against each | ||
| 325 | * other. | ||
| 326 | */ | ||
| 327 | bio->bi_private = xchg(&io_end->bio, bio); | ||
| 328 | } else { | ||
| 329 | ext4_finish_bio(bio); | ||
| 330 | bio_put(bio); | ||
| 331 | } | ||
| 332 | |||
| 333 | if (error) { | 323 | if (error) { |
| 334 | struct inode *inode = io_end->inode; | 324 | struct inode *inode = io_end->inode; |
| 335 | 325 | ||
| @@ -341,7 +331,24 @@ static void ext4_end_bio(struct bio *bio, int error) | |||
| 341 | (unsigned long long) | 331 | (unsigned long long) |
| 342 | bi_sector >> (inode->i_blkbits - 9)); | 332 | bi_sector >> (inode->i_blkbits - 9)); |
| 343 | } | 333 | } |
| 344 | ext4_put_io_end_defer(io_end); | 334 | |
| 335 | if (io_end->flag & EXT4_IO_END_UNWRITTEN) { | ||
| 336 | /* | ||
| 337 | * Link bio into list hanging from io_end. We have to do it | ||
| 338 | * atomically as bio completions can be racing against each | ||
| 339 | * other. | ||
| 340 | */ | ||
| 341 | bio->bi_private = xchg(&io_end->bio, bio); | ||
| 342 | ext4_put_io_end_defer(io_end); | ||
| 343 | } else { | ||
| 344 | /* | ||
| 345 | * Drop io_end reference early. Inode can get freed once | ||
| 346 | * we finish the bio. | ||
| 347 | */ | ||
| 348 | ext4_put_io_end_defer(io_end); | ||
| 349 | ext4_finish_bio(bio); | ||
| 350 | bio_put(bio); | ||
| 351 | } | ||
| 345 | } | 352 | } |
| 346 | 353 | ||
| 347 | void ext4_io_submit(struct ext4_io_submit *io) | 354 | void ext4_io_submit(struct ext4_io_submit *io) |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 85b3dd60169b..bca26f34edf4 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -1702,12 +1702,6 @@ static inline void ext4_show_quota_options(struct seq_file *seq, | |||
| 1702 | 1702 | ||
| 1703 | if (sbi->s_qf_names[GRPQUOTA]) | 1703 | if (sbi->s_qf_names[GRPQUOTA]) |
| 1704 | seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); | 1704 | seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); |
| 1705 | |||
| 1706 | if (test_opt(sb, USRQUOTA)) | ||
| 1707 | seq_puts(seq, ",usrquota"); | ||
| 1708 | |||
| 1709 | if (test_opt(sb, GRPQUOTA)) | ||
| 1710 | seq_puts(seq, ",grpquota"); | ||
| 1711 | #endif | 1705 | #endif |
| 1712 | } | 1706 | } |
| 1713 | 1707 | ||
| @@ -3624,10 +3618,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 3624 | sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); | 3618 | sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); |
| 3625 | sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); | 3619 | sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); |
| 3626 | 3620 | ||
| 3627 | /* Do we have standard group size of blocksize * 8 blocks ? */ | ||
| 3628 | if (sbi->s_blocks_per_group == blocksize << 3) | ||
| 3629 | set_opt2(sb, STD_GROUP_SIZE); | ||
| 3630 | |||
| 3631 | for (i = 0; i < 4; i++) | 3621 | for (i = 0; i < 4; i++) |
| 3632 | sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); | 3622 | sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); |
| 3633 | sbi->s_def_hash_version = es->s_def_hash_version; | 3623 | sbi->s_def_hash_version = es->s_def_hash_version; |
| @@ -3697,6 +3687,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 3697 | goto failed_mount; | 3687 | goto failed_mount; |
| 3698 | } | 3688 | } |
| 3699 | 3689 | ||
| 3690 | /* Do we have standard group size of clustersize * 8 blocks ? */ | ||
| 3691 | if (sbi->s_blocks_per_group == clustersize << 3) | ||
| 3692 | set_opt2(sb, STD_GROUP_SIZE); | ||
| 3693 | |||
| 3700 | /* | 3694 | /* |
| 3701 | * Test whether we have more sectors than will fit in sector_t, | 3695 | * Test whether we have more sectors than will fit in sector_t, |
| 3702 | * and whether the max offset is addressable by the page cache. | 3696 | * and whether the max offset is addressable by the page cache. |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 067778b0ccc9..e066a3902973 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
| @@ -951,6 +951,7 @@ nlmsvc_retry_blocked(void) | |||
| 951 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; | 951 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; |
| 952 | struct nlm_block *block; | 952 | struct nlm_block *block; |
| 953 | 953 | ||
| 954 | spin_lock(&nlm_blocked_lock); | ||
| 954 | while (!list_empty(&nlm_blocked) && !kthread_should_stop()) { | 955 | while (!list_empty(&nlm_blocked) && !kthread_should_stop()) { |
| 955 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); | 956 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); |
| 956 | 957 | ||
| @@ -960,6 +961,7 @@ nlmsvc_retry_blocked(void) | |||
| 960 | timeout = block->b_when - jiffies; | 961 | timeout = block->b_when - jiffies; |
| 961 | break; | 962 | break; |
| 962 | } | 963 | } |
| 964 | spin_unlock(&nlm_blocked_lock); | ||
| 963 | 965 | ||
| 964 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", | 966 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", |
| 965 | block, block->b_when); | 967 | block, block->b_when); |
| @@ -969,7 +971,9 @@ nlmsvc_retry_blocked(void) | |||
| 969 | retry_deferred_block(block); | 971 | retry_deferred_block(block); |
| 970 | } else | 972 | } else |
| 971 | nlmsvc_grant_blocked(block); | 973 | nlmsvc_grant_blocked(block); |
| 974 | spin_lock(&nlm_blocked_lock); | ||
| 972 | } | 975 | } |
| 976 | spin_unlock(&nlm_blocked_lock); | ||
| 973 | 977 | ||
| 974 | return timeout; | 978 | return timeout; |
| 975 | } | 979 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0abfb8466e79..c74d6168db99 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -999,6 +999,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
| 999 | __be32 *p; | 999 | __be32 *p; |
| 1000 | __be32 *q; | 1000 | __be32 *q; |
| 1001 | int len; | 1001 | int len; |
| 1002 | uint32_t bmval_len = 2; | ||
| 1002 | uint32_t bmval0 = 0; | 1003 | uint32_t bmval0 = 0; |
| 1003 | uint32_t bmval1 = 0; | 1004 | uint32_t bmval1 = 0; |
| 1004 | uint32_t bmval2 = 0; | 1005 | uint32_t bmval2 = 0; |
| @@ -1010,7 +1011,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
| 1010 | * = 40 bytes, plus any contribution from variable-length fields | 1011 | * = 40 bytes, plus any contribution from variable-length fields |
| 1011 | * such as owner/group. | 1012 | * such as owner/group. |
| 1012 | */ | 1013 | */ |
| 1013 | len = 20; | 1014 | len = 8; |
| 1014 | 1015 | ||
| 1015 | /* Sigh */ | 1016 | /* Sigh */ |
| 1016 | if (iap->ia_valid & ATTR_SIZE) | 1017 | if (iap->ia_valid & ATTR_SIZE) |
| @@ -1040,8 +1041,6 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
| 1040 | } | 1041 | } |
| 1041 | len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); | 1042 | len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); |
| 1042 | } | 1043 | } |
| 1043 | if (label) | ||
| 1044 | len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); | ||
| 1045 | if (iap->ia_valid & ATTR_ATIME_SET) | 1044 | if (iap->ia_valid & ATTR_ATIME_SET) |
| 1046 | len += 16; | 1045 | len += 16; |
| 1047 | else if (iap->ia_valid & ATTR_ATIME) | 1046 | else if (iap->ia_valid & ATTR_ATIME) |
| @@ -1050,15 +1049,22 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
| 1050 | len += 16; | 1049 | len += 16; |
| 1051 | else if (iap->ia_valid & ATTR_MTIME) | 1050 | else if (iap->ia_valid & ATTR_MTIME) |
| 1052 | len += 4; | 1051 | len += 4; |
| 1052 | if (label) { | ||
| 1053 | len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); | ||
| 1054 | bmval_len = 3; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | len += bmval_len << 2; | ||
| 1053 | p = reserve_space(xdr, len); | 1058 | p = reserve_space(xdr, len); |
| 1054 | 1059 | ||
| 1055 | /* | 1060 | /* |
| 1056 | * We write the bitmap length now, but leave the bitmap and the attribute | 1061 | * We write the bitmap length now, but leave the bitmap and the attribute |
| 1057 | * buffer length to be backfilled at the end of this routine. | 1062 | * buffer length to be backfilled at the end of this routine. |
| 1058 | */ | 1063 | */ |
| 1059 | *p++ = cpu_to_be32(3); | 1064 | *p++ = cpu_to_be32(bmval_len); |
| 1060 | q = p; | 1065 | q = p; |
| 1061 | p += 4; | 1066 | /* Skip bitmap entries + attrlen */ |
| 1067 | p += bmval_len + 1; | ||
| 1062 | 1068 | ||
| 1063 | if (iap->ia_valid & ATTR_SIZE) { | 1069 | if (iap->ia_valid & ATTR_SIZE) { |
| 1064 | bmval0 |= FATTR4_WORD0_SIZE; | 1070 | bmval0 |= FATTR4_WORD0_SIZE; |
| @@ -1112,10 +1118,11 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
| 1112 | len, ((char *)p - (char *)q) + 4); | 1118 | len, ((char *)p - (char *)q) + 4); |
| 1113 | BUG(); | 1119 | BUG(); |
| 1114 | } | 1120 | } |
| 1115 | len = (char *)p - (char *)q - 16; | 1121 | len = (char *)p - (char *)q - (bmval_len << 2); |
| 1116 | *q++ = htonl(bmval0); | 1122 | *q++ = htonl(bmval0); |
| 1117 | *q++ = htonl(bmval1); | 1123 | *q++ = htonl(bmval1); |
| 1118 | *q++ = htonl(bmval2); | 1124 | if (bmval_len == 3) |
| 1125 | *q++ = htonl(bmval2); | ||
| 1119 | *q = htonl(len); | 1126 | *q = htonl(len); |
| 1120 | 1127 | ||
| 1121 | /* out: */ | 1128 | /* out: */ |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index a7cee864e7b2..0d4c410e4589 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -1293,7 +1293,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
| 1293 | * According to RFC3010, this takes precedence over all other errors. | 1293 | * According to RFC3010, this takes precedence over all other errors. |
| 1294 | */ | 1294 | */ |
| 1295 | status = nfserr_minor_vers_mismatch; | 1295 | status = nfserr_minor_vers_mismatch; |
| 1296 | if (args->minorversion > nfsd_supported_minorversion) | 1296 | if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0) |
| 1297 | goto out; | 1297 | goto out; |
| 1298 | 1298 | ||
| 1299 | status = nfs41_check_op_ordering(args); | 1299 | status = nfs41_check_op_ordering(args); |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 2bbd94e51efc..30f34ab02137 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
| @@ -53,7 +53,6 @@ struct readdir_cd { | |||
| 53 | extern struct svc_program nfsd_program; | 53 | extern struct svc_program nfsd_program; |
| 54 | extern struct svc_version nfsd_version2, nfsd_version3, | 54 | extern struct svc_version nfsd_version2, nfsd_version3, |
| 55 | nfsd_version4; | 55 | nfsd_version4; |
| 56 | extern u32 nfsd_supported_minorversion; | ||
| 57 | extern struct mutex nfsd_mutex; | 56 | extern struct mutex nfsd_mutex; |
| 58 | extern spinlock_t nfsd_drc_lock; | 57 | extern spinlock_t nfsd_drc_lock; |
| 59 | extern unsigned long nfsd_drc_max_mem; | 58 | extern unsigned long nfsd_drc_max_mem; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 6b9f48ca4c25..760c85a6f534 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -116,7 +116,10 @@ struct svc_program nfsd_program = { | |||
| 116 | 116 | ||
| 117 | }; | 117 | }; |
| 118 | 118 | ||
| 119 | u32 nfsd_supported_minorversion = 1; | 119 | static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = { |
| 120 | [0] = 1, | ||
| 121 | [1] = 1, | ||
| 122 | }; | ||
| 120 | 123 | ||
| 121 | int nfsd_vers(int vers, enum vers_op change) | 124 | int nfsd_vers(int vers, enum vers_op change) |
| 122 | { | 125 | { |
| @@ -151,15 +154,13 @@ int nfsd_minorversion(u32 minorversion, enum vers_op change) | |||
| 151 | return -1; | 154 | return -1; |
| 152 | switch(change) { | 155 | switch(change) { |
| 153 | case NFSD_SET: | 156 | case NFSD_SET: |
| 154 | nfsd_supported_minorversion = minorversion; | 157 | nfsd_supported_minorversions[minorversion] = true; |
| 155 | break; | 158 | break; |
| 156 | case NFSD_CLEAR: | 159 | case NFSD_CLEAR: |
| 157 | if (minorversion == 0) | 160 | nfsd_supported_minorversions[minorversion] = false; |
| 158 | return -1; | ||
| 159 | nfsd_supported_minorversion = minorversion - 1; | ||
| 160 | break; | 161 | break; |
| 161 | case NFSD_TEST: | 162 | case NFSD_TEST: |
| 162 | return minorversion <= nfsd_supported_minorversion; | 163 | return nfsd_supported_minorversions[minorversion]; |
| 163 | case NFSD_AVAIL: | 164 | case NFSD_AVAIL: |
| 164 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; | 165 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; |
| 165 | } | 166 | } |
| @@ -844,6 +844,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o | |||
| 844 | if ((flags & O_TMPFILE_MASK) != O_TMPFILE) | 844 | if ((flags & O_TMPFILE_MASK) != O_TMPFILE) |
| 845 | return -EINVAL; | 845 | return -EINVAL; |
| 846 | acc_mode = MAY_OPEN | ACC_MODE(flags); | 846 | acc_mode = MAY_OPEN | ACC_MODE(flags); |
| 847 | if (!(acc_mode & MAY_WRITE)) | ||
| 848 | return -EINVAL; | ||
| 847 | } else if (flags & O_PATH) { | 849 | } else if (flags & O_PATH) { |
| 848 | /* | 850 | /* |
| 849 | * If we have O_PATH in the open flag. Then we | 851 | * If we have O_PATH in the open flag. Then we |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 28503172f2e4..a1a16eb97c7b 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
| @@ -223,7 +223,7 @@ static inline char *alloc_elfnotes_buf(size_t notes_sz) | |||
| 223 | * regions in the 1st kernel pointed to by PT_LOAD entries) into | 223 | * regions in the 1st kernel pointed to by PT_LOAD entries) into |
| 224 | * virtually contiguous user-space in ELF layout. | 224 | * virtually contiguous user-space in ELF layout. |
| 225 | */ | 225 | */ |
| 226 | #ifdef CONFIG_MMU | 226 | #if defined(CONFIG_MMU) && !defined(CONFIG_S390) |
| 227 | static int mmap_vmcore(struct file *file, struct vm_area_struct *vma) | 227 | static int mmap_vmcore(struct file *file, struct vm_area_struct *vma) |
| 228 | { | 228 | { |
| 229 | size_t size = vma->vm_end - vma->vm_start; | 229 | size_t size = vma->vm_end - vma->vm_start; |
diff --git a/fs/super.c b/fs/super.c index 7465d4364208..68307c029228 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -336,19 +336,19 @@ EXPORT_SYMBOL(deactivate_super); | |||
| 336 | * and want to turn it into a full-blown active reference. grab_super() | 336 | * and want to turn it into a full-blown active reference. grab_super() |
| 337 | * is called with sb_lock held and drops it. Returns 1 in case of | 337 | * is called with sb_lock held and drops it. Returns 1 in case of |
| 338 | * success, 0 if we had failed (superblock contents was already dead or | 338 | * success, 0 if we had failed (superblock contents was already dead or |
| 339 | * dying when grab_super() had been called). | 339 | * dying when grab_super() had been called). Note that this is only |
| 340 | * called for superblocks not in rundown mode (== ones still on ->fs_supers | ||
| 341 | * of their type), so increment of ->s_count is OK here. | ||
| 340 | */ | 342 | */ |
| 341 | static int grab_super(struct super_block *s) __releases(sb_lock) | 343 | static int grab_super(struct super_block *s) __releases(sb_lock) |
| 342 | { | 344 | { |
| 343 | if (atomic_inc_not_zero(&s->s_active)) { | ||
| 344 | spin_unlock(&sb_lock); | ||
| 345 | return 1; | ||
| 346 | } | ||
| 347 | /* it's going away */ | ||
| 348 | s->s_count++; | 345 | s->s_count++; |
| 349 | spin_unlock(&sb_lock); | 346 | spin_unlock(&sb_lock); |
| 350 | /* wait for it to die */ | ||
| 351 | down_write(&s->s_umount); | 347 | down_write(&s->s_umount); |
| 348 | if ((s->s_flags & MS_BORN) && atomic_inc_not_zero(&s->s_active)) { | ||
| 349 | put_super(s); | ||
| 350 | return 1; | ||
| 351 | } | ||
| 352 | up_write(&s->s_umount); | 352 | up_write(&s->s_umount); |
| 353 | put_super(s); | 353 | put_super(s); |
| 354 | return 0; | 354 | return 0; |
| @@ -463,11 +463,6 @@ retry: | |||
| 463 | destroy_super(s); | 463 | destroy_super(s); |
| 464 | s = NULL; | 464 | s = NULL; |
| 465 | } | 465 | } |
| 466 | down_write(&old->s_umount); | ||
| 467 | if (unlikely(!(old->s_flags & MS_BORN))) { | ||
| 468 | deactivate_locked_super(old); | ||
| 469 | goto retry; | ||
| 470 | } | ||
| 471 | return old; | 466 | return old; |
| 472 | } | 467 | } |
| 473 | } | 468 | } |
| @@ -660,10 +655,10 @@ restart: | |||
| 660 | if (hlist_unhashed(&sb->s_instances)) | 655 | if (hlist_unhashed(&sb->s_instances)) |
| 661 | continue; | 656 | continue; |
| 662 | if (sb->s_bdev == bdev) { | 657 | if (sb->s_bdev == bdev) { |
| 663 | if (grab_super(sb)) /* drops sb_lock */ | 658 | if (!grab_super(sb)) |
| 664 | return sb; | ||
| 665 | else | ||
| 666 | goto restart; | 659 | goto restart; |
| 660 | up_write(&sb->s_umount); | ||
| 661 | return sb; | ||
| 667 | } | 662 | } |
| 668 | } | 663 | } |
| 669 | spin_unlock(&sb_lock); | 664 | spin_unlock(&sb_lock); |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index aec3d5c98c94..09a1a25cd145 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
| @@ -20,38 +20,64 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
| 20 | const struct attribute_group *grp) | 20 | const struct attribute_group *grp) |
| 21 | { | 21 | { |
| 22 | struct attribute *const* attr; | 22 | struct attribute *const* attr; |
| 23 | int i; | 23 | struct bin_attribute *const* bin_attr; |
| 24 | 24 | ||
| 25 | for (i = 0, attr = grp->attrs; *attr; i++, attr++) | 25 | if (grp->attrs) |
| 26 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); | 26 | for (attr = grp->attrs; *attr; attr++) |
| 27 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); | ||
| 28 | if (grp->bin_attrs) | ||
| 29 | for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) | ||
| 30 | sysfs_remove_bin_file(kobj, *bin_attr); | ||
| 27 | } | 31 | } |
| 28 | 32 | ||
| 29 | static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | 33 | static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, |
| 30 | const struct attribute_group *grp, int update) | 34 | const struct attribute_group *grp, int update) |
| 31 | { | 35 | { |
| 32 | struct attribute *const* attr; | 36 | struct attribute *const* attr; |
| 37 | struct bin_attribute *const* bin_attr; | ||
| 33 | int error = 0, i; | 38 | int error = 0, i; |
| 34 | 39 | ||
| 35 | for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { | 40 | if (grp->attrs) { |
| 36 | umode_t mode = 0; | 41 | for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { |
| 42 | umode_t mode = 0; | ||
| 43 | |||
| 44 | /* | ||
| 45 | * In update mode, we're changing the permissions or | ||
| 46 | * visibility. Do this by first removing then | ||
| 47 | * re-adding (if required) the file. | ||
| 48 | */ | ||
| 49 | if (update) | ||
| 50 | sysfs_hash_and_remove(dir_sd, NULL, | ||
| 51 | (*attr)->name); | ||
| 52 | if (grp->is_visible) { | ||
| 53 | mode = grp->is_visible(kobj, *attr, i); | ||
| 54 | if (!mode) | ||
| 55 | continue; | ||
| 56 | } | ||
| 57 | error = sysfs_add_file_mode(dir_sd, *attr, | ||
| 58 | SYSFS_KOBJ_ATTR, | ||
| 59 | (*attr)->mode | mode); | ||
| 60 | if (unlikely(error)) | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | if (error) { | ||
| 64 | remove_files(dir_sd, kobj, grp); | ||
| 65 | goto exit; | ||
| 66 | } | ||
| 67 | } | ||
| 37 | 68 | ||
| 38 | /* in update mode, we're changing the permissions or | 69 | if (grp->bin_attrs) { |
| 39 | * visibility. Do this by first removing then | 70 | for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) { |
| 40 | * re-adding (if required) the file */ | 71 | if (update) |
| 41 | if (update) | 72 | sysfs_remove_bin_file(kobj, *bin_attr); |
| 42 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); | 73 | error = sysfs_create_bin_file(kobj, *bin_attr); |
| 43 | if (grp->is_visible) { | 74 | if (error) |
| 44 | mode = grp->is_visible(kobj, *attr, i); | 75 | break; |
| 45 | if (!mode) | ||
| 46 | continue; | ||
| 47 | } | 76 | } |
| 48 | error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR, | 77 | if (error) |
| 49 | (*attr)->mode | mode); | 78 | remove_files(dir_sd, kobj, grp); |
| 50 | if (unlikely(error)) | ||
| 51 | break; | ||
| 52 | } | 79 | } |
| 53 | if (error) | 80 | exit: |
| 54 | remove_files(dir_sd, kobj, grp); | ||
| 55 | return error; | 81 | return error; |
| 56 | } | 82 | } |
| 57 | 83 | ||
| @@ -67,8 +93,8 @@ static int internal_create_group(struct kobject *kobj, int update, | |||
| 67 | /* Updates may happen before the object has been instantiated */ | 93 | /* Updates may happen before the object has been instantiated */ |
| 68 | if (unlikely(update && !kobj->sd)) | 94 | if (unlikely(update && !kobj->sd)) |
| 69 | return -EINVAL; | 95 | return -EINVAL; |
| 70 | if (!grp->attrs) { | 96 | if (!grp->attrs && !grp->bin_attrs) { |
| 71 | WARN(1, "sysfs: attrs not set by subsystem for group: %s/%s\n", | 97 | WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n", |
| 72 | kobj->name, grp->name ? "" : grp->name); | 98 | kobj->name, grp->name ? "" : grp->name); |
| 73 | return -EINVAL; | 99 | return -EINVAL; |
| 74 | } | 100 | } |
