diff options
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 131 |
1 files changed, 76 insertions, 55 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 1cb84f78909e..3520ab8a6639 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -67,6 +67,7 @@ static struct buffer_head *ext4_append(handle_t *handle, | |||
67 | return ERR_PTR(err); | 67 | return ERR_PTR(err); |
68 | inode->i_size += inode->i_sb->s_blocksize; | 68 | inode->i_size += inode->i_sb->s_blocksize; |
69 | EXT4_I(inode)->i_disksize = inode->i_size; | 69 | EXT4_I(inode)->i_disksize = inode->i_size; |
70 | BUFFER_TRACE(bh, "get_write_access"); | ||
70 | err = ext4_journal_get_write_access(handle, bh); | 71 | err = ext4_journal_get_write_access(handle, bh); |
71 | if (err) { | 72 | if (err) { |
72 | brelse(bh); | 73 | brelse(bh); |
@@ -1778,6 +1779,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1778 | 1779 | ||
1779 | blocksize = dir->i_sb->s_blocksize; | 1780 | blocksize = dir->i_sb->s_blocksize; |
1780 | dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); | 1781 | dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); |
1782 | BUFFER_TRACE(bh, "get_write_access"); | ||
1781 | retval = ext4_journal_get_write_access(handle, bh); | 1783 | retval = ext4_journal_get_write_access(handle, bh); |
1782 | if (retval) { | 1784 | if (retval) { |
1783 | ext4_std_error(dir->i_sb, retval); | 1785 | ext4_std_error(dir->i_sb, retval); |
@@ -2510,8 +2512,7 @@ static int empty_dir(struct inode *inode) | |||
2510 | ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize); | 2512 | ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize); |
2511 | de = ext4_next_entry(de1, sb->s_blocksize); | 2513 | de = ext4_next_entry(de1, sb->s_blocksize); |
2512 | while (offset < inode->i_size) { | 2514 | while (offset < inode->i_size) { |
2513 | if (!bh || | 2515 | if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { |
2514 | (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { | ||
2515 | unsigned int lblock; | 2516 | unsigned int lblock; |
2516 | err = 0; | 2517 | err = 0; |
2517 | brelse(bh); | 2518 | brelse(bh); |
@@ -2539,26 +2540,37 @@ static int empty_dir(struct inode *inode) | |||
2539 | return 1; | 2540 | return 1; |
2540 | } | 2541 | } |
2541 | 2542 | ||
2542 | /* ext4_orphan_add() links an unlinked or truncated inode into a list of | 2543 | /* |
2544 | * ext4_orphan_add() links an unlinked or truncated inode into a list of | ||
2543 | * such inodes, starting at the superblock, in case we crash before the | 2545 | * such inodes, starting at the superblock, in case we crash before the |
2544 | * file is closed/deleted, or in case the inode truncate spans multiple | 2546 | * file is closed/deleted, or in case the inode truncate spans multiple |
2545 | * transactions and the last transaction is not recovered after a crash. | 2547 | * transactions and the last transaction is not recovered after a crash. |
2546 | * | 2548 | * |
2547 | * At filesystem recovery time, we walk this list deleting unlinked | 2549 | * At filesystem recovery time, we walk this list deleting unlinked |
2548 | * inodes and truncating linked inodes in ext4_orphan_cleanup(). | 2550 | * inodes and truncating linked inodes in ext4_orphan_cleanup(). |
2551 | * | ||
2552 | * Orphan list manipulation functions must be called under i_mutex unless | ||
2553 | * we are just creating the inode or deleting it. | ||
2549 | */ | 2554 | */ |
2550 | int ext4_orphan_add(handle_t *handle, struct inode *inode) | 2555 | int ext4_orphan_add(handle_t *handle, struct inode *inode) |
2551 | { | 2556 | { |
2552 | struct super_block *sb = inode->i_sb; | 2557 | struct super_block *sb = inode->i_sb; |
2558 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
2553 | struct ext4_iloc iloc; | 2559 | struct ext4_iloc iloc; |
2554 | int err = 0, rc; | 2560 | int err = 0, rc; |
2561 | bool dirty = false; | ||
2555 | 2562 | ||
2556 | if (!EXT4_SB(sb)->s_journal) | 2563 | if (!sbi->s_journal) |
2557 | return 0; | 2564 | return 0; |
2558 | 2565 | ||
2559 | mutex_lock(&EXT4_SB(sb)->s_orphan_lock); | 2566 | WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) && |
2567 | !mutex_is_locked(&inode->i_mutex)); | ||
2568 | /* | ||
2569 | * Exit early if inode already is on orphan list. This is a big speedup | ||
2570 | * since we don't have to contend on the global s_orphan_lock. | ||
2571 | */ | ||
2560 | if (!list_empty(&EXT4_I(inode)->i_orphan)) | 2572 | if (!list_empty(&EXT4_I(inode)->i_orphan)) |
2561 | goto out_unlock; | 2573 | return 0; |
2562 | 2574 | ||
2563 | /* | 2575 | /* |
2564 | * Orphan handling is only valid for files with data blocks | 2576 | * Orphan handling is only valid for files with data blocks |
@@ -2569,48 +2581,51 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2569 | J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 2581 | J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
2570 | S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); | 2582 | S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); |
2571 | 2583 | ||
2572 | BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); | 2584 | BUFFER_TRACE(sbi->s_sbh, "get_write_access"); |
2573 | err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); | 2585 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); |
2574 | if (err) | 2586 | if (err) |
2575 | goto out_unlock; | 2587 | goto out; |
2576 | 2588 | ||
2577 | err = ext4_reserve_inode_write(handle, inode, &iloc); | 2589 | err = ext4_reserve_inode_write(handle, inode, &iloc); |
2578 | if (err) | 2590 | if (err) |
2579 | goto out_unlock; | 2591 | goto out; |
2592 | |||
2593 | mutex_lock(&sbi->s_orphan_lock); | ||
2580 | /* | 2594 | /* |
2581 | * Due to previous errors inode may be already a part of on-disk | 2595 | * Due to previous errors inode may be already a part of on-disk |
2582 | * orphan list. If so skip on-disk list modification. | 2596 | * orphan list. If so skip on-disk list modification. |
2583 | */ | 2597 | */ |
2584 | if (NEXT_ORPHAN(inode) && NEXT_ORPHAN(inode) <= | 2598 | if (!NEXT_ORPHAN(inode) || NEXT_ORPHAN(inode) > |
2585 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) | 2599 | (le32_to_cpu(sbi->s_es->s_inodes_count))) { |
2586 | goto mem_insert; | 2600 | /* Insert this inode at the head of the on-disk orphan list */ |
2587 | 2601 | NEXT_ORPHAN(inode) = le32_to_cpu(sbi->s_es->s_last_orphan); | |
2588 | /* Insert this inode at the head of the on-disk orphan list... */ | 2602 | sbi->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); |
2589 | NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); | 2603 | dirty = true; |
2590 | EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); | 2604 | } |
2591 | err = ext4_handle_dirty_super(handle, sb); | 2605 | list_add(&EXT4_I(inode)->i_orphan, &sbi->s_orphan); |
2592 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); | 2606 | mutex_unlock(&sbi->s_orphan_lock); |
2593 | if (!err) | 2607 | |
2594 | err = rc; | 2608 | if (dirty) { |
2595 | 2609 | err = ext4_handle_dirty_super(handle, sb); | |
2596 | /* Only add to the head of the in-memory list if all the | 2610 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); |
2597 | * previous operations succeeded. If the orphan_add is going to | 2611 | if (!err) |
2598 | * fail (possibly taking the journal offline), we can't risk | 2612 | err = rc; |
2599 | * leaving the inode on the orphan list: stray orphan-list | 2613 | if (err) { |
2600 | * entries can cause panics at unmount time. | 2614 | /* |
2601 | * | 2615 | * We have to remove inode from in-memory list if |
2602 | * This is safe: on error we're going to ignore the orphan list | 2616 | * addition to on disk orphan list failed. Stray orphan |
2603 | * anyway on the next recovery. */ | 2617 | * list entries can cause panics at unmount time. |
2604 | mem_insert: | 2618 | */ |
2605 | if (!err) | 2619 | mutex_lock(&sbi->s_orphan_lock); |
2606 | list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); | 2620 | list_del(&EXT4_I(inode)->i_orphan); |
2607 | 2621 | mutex_unlock(&sbi->s_orphan_lock); | |
2622 | } | ||
2623 | } | ||
2608 | jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); | 2624 | jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); |
2609 | jbd_debug(4, "orphan inode %lu will point to %d\n", | 2625 | jbd_debug(4, "orphan inode %lu will point to %d\n", |
2610 | inode->i_ino, NEXT_ORPHAN(inode)); | 2626 | inode->i_ino, NEXT_ORPHAN(inode)); |
2611 | out_unlock: | 2627 | out: |
2612 | mutex_unlock(&EXT4_SB(sb)->s_orphan_lock); | 2628 | ext4_std_error(sb, err); |
2613 | ext4_std_error(inode->i_sb, err); | ||
2614 | return err; | 2629 | return err; |
2615 | } | 2630 | } |
2616 | 2631 | ||
@@ -2622,45 +2637,51 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2622 | { | 2637 | { |
2623 | struct list_head *prev; | 2638 | struct list_head *prev; |
2624 | struct ext4_inode_info *ei = EXT4_I(inode); | 2639 | struct ext4_inode_info *ei = EXT4_I(inode); |
2625 | struct ext4_sb_info *sbi; | 2640 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
2626 | __u32 ino_next; | 2641 | __u32 ino_next; |
2627 | struct ext4_iloc iloc; | 2642 | struct ext4_iloc iloc; |
2628 | int err = 0; | 2643 | int err = 0; |
2629 | 2644 | ||
2630 | if ((!EXT4_SB(inode->i_sb)->s_journal) && | 2645 | if (!sbi->s_journal && !(sbi->s_mount_state & EXT4_ORPHAN_FS)) |
2631 | !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) | ||
2632 | return 0; | 2646 | return 0; |
2633 | 2647 | ||
2634 | mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); | 2648 | WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) && |
2649 | !mutex_is_locked(&inode->i_mutex)); | ||
2650 | /* Do this quick check before taking global s_orphan_lock. */ | ||
2635 | if (list_empty(&ei->i_orphan)) | 2651 | if (list_empty(&ei->i_orphan)) |
2636 | goto out; | 2652 | return 0; |
2637 | 2653 | ||
2638 | ino_next = NEXT_ORPHAN(inode); | 2654 | if (handle) { |
2639 | prev = ei->i_orphan.prev; | 2655 | /* Grab inode buffer early before taking global s_orphan_lock */ |
2640 | sbi = EXT4_SB(inode->i_sb); | 2656 | err = ext4_reserve_inode_write(handle, inode, &iloc); |
2657 | } | ||
2641 | 2658 | ||
2659 | mutex_lock(&sbi->s_orphan_lock); | ||
2642 | jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); | 2660 | jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); |
2643 | 2661 | ||
2662 | prev = ei->i_orphan.prev; | ||
2644 | list_del_init(&ei->i_orphan); | 2663 | list_del_init(&ei->i_orphan); |
2645 | 2664 | ||
2646 | /* If we're on an error path, we may not have a valid | 2665 | /* If we're on an error path, we may not have a valid |
2647 | * transaction handle with which to update the orphan list on | 2666 | * transaction handle with which to update the orphan list on |
2648 | * disk, but we still need to remove the inode from the linked | 2667 | * disk, but we still need to remove the inode from the linked |
2649 | * list in memory. */ | 2668 | * list in memory. */ |
2650 | if (!handle) | 2669 | if (!handle || err) { |
2651 | goto out; | 2670 | mutex_unlock(&sbi->s_orphan_lock); |
2652 | |||
2653 | err = ext4_reserve_inode_write(handle, inode, &iloc); | ||
2654 | if (err) | ||
2655 | goto out_err; | 2671 | goto out_err; |
2672 | } | ||
2656 | 2673 | ||
2674 | ino_next = NEXT_ORPHAN(inode); | ||
2657 | if (prev == &sbi->s_orphan) { | 2675 | if (prev == &sbi->s_orphan) { |
2658 | jbd_debug(4, "superblock will point to %u\n", ino_next); | 2676 | jbd_debug(4, "superblock will point to %u\n", ino_next); |
2659 | BUFFER_TRACE(sbi->s_sbh, "get_write_access"); | 2677 | BUFFER_TRACE(sbi->s_sbh, "get_write_access"); |
2660 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); | 2678 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); |
2661 | if (err) | 2679 | if (err) { |
2680 | mutex_unlock(&sbi->s_orphan_lock); | ||
2662 | goto out_brelse; | 2681 | goto out_brelse; |
2682 | } | ||
2663 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); | 2683 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); |
2684 | mutex_unlock(&sbi->s_orphan_lock); | ||
2664 | err = ext4_handle_dirty_super(handle, inode->i_sb); | 2685 | err = ext4_handle_dirty_super(handle, inode->i_sb); |
2665 | } else { | 2686 | } else { |
2666 | struct ext4_iloc iloc2; | 2687 | struct ext4_iloc iloc2; |
@@ -2670,20 +2691,20 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2670 | jbd_debug(4, "orphan inode %lu will point to %u\n", | 2691 | jbd_debug(4, "orphan inode %lu will point to %u\n", |
2671 | i_prev->i_ino, ino_next); | 2692 | i_prev->i_ino, ino_next); |
2672 | err = ext4_reserve_inode_write(handle, i_prev, &iloc2); | 2693 | err = ext4_reserve_inode_write(handle, i_prev, &iloc2); |
2673 | if (err) | 2694 | if (err) { |
2695 | mutex_unlock(&sbi->s_orphan_lock); | ||
2674 | goto out_brelse; | 2696 | goto out_brelse; |
2697 | } | ||
2675 | NEXT_ORPHAN(i_prev) = ino_next; | 2698 | NEXT_ORPHAN(i_prev) = ino_next; |
2676 | err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2); | 2699 | err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2); |
2700 | mutex_unlock(&sbi->s_orphan_lock); | ||
2677 | } | 2701 | } |
2678 | if (err) | 2702 | if (err) |
2679 | goto out_brelse; | 2703 | goto out_brelse; |
2680 | NEXT_ORPHAN(inode) = 0; | 2704 | NEXT_ORPHAN(inode) = 0; |
2681 | err = ext4_mark_iloc_dirty(handle, inode, &iloc); | 2705 | err = ext4_mark_iloc_dirty(handle, inode, &iloc); |
2682 | |||
2683 | out_err: | 2706 | out_err: |
2684 | ext4_std_error(inode->i_sb, err); | 2707 | ext4_std_error(inode->i_sb, err); |
2685 | out: | ||
2686 | mutex_unlock(&EXT4_SB(inode->i_sb)->s_orphan_lock); | ||
2687 | return err; | 2708 | return err; |
2688 | 2709 | ||
2689 | out_brelse: | 2710 | out_brelse: |