aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-08-16 22:06:55 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-08-16 22:06:55 -0400
commit19883bd9658d0dc269fc228b1b39db3615f7c7b0 (patch)
tree06332ad032dc6d8b0af0d505c6e71b3707df58e6
parent0e20270454e45ff54c9f8546159924038e31bfa0 (diff)
ext4: avoid reusing recently deleted inodes in no journal mode
In no journal mode, if an inode has recently been deleted, we shouldn't reuse it right away. Otherwise it's possible, after an unclean shutdown, to hit a situation where a recently deleted inode gets reused for some other purpose before the inode table block has been written to disk. However, if the directory entry has been updated, then the directory entry will be pointing at the old inode contents. E2fsck will make sure the file system is consistent after the unclean shutdown. However, if the recently deleted inode is a character mode device, or an inode with the immutable bit set, even after the file system has been fixed up by e2fsck, it can be possible for a *.pyc file to be pointing at a character mode device, and when python tries to open the *.pyc file, Hilarity Ensues. We could change all of userspace to be very suspicious about stat'ing files before opening them, and clearing the immutable flag if necessary --- or we can just avoid reusing an inode number if it has been recently deleted. Google-Bug-Id: 10017573 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/ialloc.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 8bf5999875ee..666a5ed48bcc 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -625,6 +625,51 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
625} 625}
626 626
627/* 627/*
628 * In no journal mode, if an inode has recently been deleted, we want
629 * to avoid reusing it until we're reasonably sure the inode table
630 * block has been written back to disk. (Yes, these values are
631 * somewhat arbitrary...)
632 */
633#define RECENTCY_MIN 5
634#define RECENTCY_DIRTY 30
635
636static int recently_deleted(struct super_block *sb, ext4_group_t group, int ino)
637{
638 struct ext4_group_desc *gdp;
639 struct ext4_inode *raw_inode;
640 struct buffer_head *bh;
641 unsigned long dtime, now;
642 int inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
643 int offset, ret = 0, recentcy = RECENTCY_MIN;
644
645 gdp = ext4_get_group_desc(sb, group, NULL);
646 if (unlikely(!gdp))
647 return 0;
648
649 bh = sb_getblk(sb, ext4_inode_table(sb, gdp) +
650 (ino / inodes_per_block));
651 if (unlikely(!bh) || !buffer_uptodate(bh))
652 /*
653 * If the block is not in the buffer cache, then it
654 * must have been written out.
655 */
656 goto out;
657
658 offset = (ino % inodes_per_block) * EXT4_INODE_SIZE(sb);
659 raw_inode = (struct ext4_inode *) (bh->b_data + offset);
660 dtime = le32_to_cpu(raw_inode->i_dtime);
661 now = get_seconds();
662 if (buffer_dirty(bh))
663 recentcy += RECENTCY_DIRTY;
664
665 if (dtime && (dtime < now) && (now < dtime + recentcy))
666 ret = 1;
667out:
668 brelse(bh);
669 return ret;
670}
671
672/*
628 * There are two policies for allocating an inode. If the new inode is 673 * There are two policies for allocating an inode. If the new inode is
629 * a directory, then a forward search is made for a block group with both 674 * a directory, then a forward search is made for a block group with both
630 * free space and a low directory-to-inode ratio; if that fails, then of 675 * free space and a low directory-to-inode ratio; if that fails, then of
@@ -741,6 +786,11 @@ repeat_in_this_group:
741 "inode=%lu", ino + 1); 786 "inode=%lu", ino + 1);
742 continue; 787 continue;
743 } 788 }
789 if ((EXT4_SB(sb)->s_journal == NULL) &&
790 recently_deleted(sb, group, ino)) {
791 ino++;
792 goto next_inode;
793 }
744 if (!handle) { 794 if (!handle) {
745 BUG_ON(nblocks <= 0); 795 BUG_ON(nblocks <= 0);
746 handle = __ext4_journal_start_sb(dir->i_sb, line_no, 796 handle = __ext4_journal_start_sb(dir->i_sb, line_no,
@@ -764,6 +814,7 @@ repeat_in_this_group:
764 ino++; /* the inode bitmap is zero-based */ 814 ino++; /* the inode bitmap is zero-based */
765 if (!ret2) 815 if (!ret2)
766 goto got; /* we grabbed the inode! */ 816 goto got; /* we grabbed the inode! */
817next_inode:
767 if (ino < EXT4_INODES_PER_GROUP(sb)) 818 if (ino < EXT4_INODES_PER_GROUP(sb))
768 goto repeat_in_this_group; 819 goto repeat_in_this_group;
769next_group: 820next_group: