>From 2f1b1a61742eb0626342e24372c9ccffcfe5eb1f Mon Sep 17 00:00:00 2001 From: T Makphaibulchoke Date: Tue, 15 Apr 2014 11:46:12 -0600 Subject: [PATCH] Orphan patch using i_mutex and removing s_orphan_lock. Signed-off-by: T. Makphaibulchoke --- fs/ext4/ext4.h | 4 +- fs/ext4/namei.c | 140 +++++++++++++++++++++++++++++++++++++------------------- fs/ext4/super.c | 4 +- 3 files changed, 98 insertions(+), 50 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index d3a534f..5222a6b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -77,6 +77,7 @@ #define EXT4_ERROR_FILE(file, block, fmt, a...) \ ext4_error_file((file), __func__, __LINE__, (block), (fmt), ## a) +#define EXT4_ORPHAN_OP_BITS 7 /* data type for block offset of block group */ typedef int ext4_grpblk_t; @@ -1223,7 +1224,8 @@ struct ext4_sb_info { /* Journaling */ struct journal_s *s_journal; struct list_head s_orphan; - struct mutex s_orphan_lock; + spinlock_t s_orphan_lock; + struct mutex s_ondisk_orphan_lock; unsigned long s_resize_flags; /* Flags indicating if there is a resizer */ unsigned long s_commit_interval; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d050e04..4a1a6a0 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2552,11 +2552,16 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) struct super_block *sb = inode->i_sb; struct ext4_iloc iloc; int err = 0, rc; + int lock_mutex = 0; if (!EXT4_SB(sb)->s_journal) return 0; - mutex_lock(&EXT4_SB(sb)->s_orphan_lock); + if (!mutex_is_locked(&inode->i_mutex)) { + lock_mutex = 1; + mutex_lock(&inode->i_mutex); + } + if (!list_empty(&EXT4_I(inode)->i_orphan)) goto out_unlock; @@ -2582,9 +2587,23 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) * orphan list. If so skip on-disk list modification. */ if (NEXT_ORPHAN(inode) && NEXT_ORPHAN(inode) <= - (le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) - goto mem_insert; - + (le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) { + brelse(iloc.bh); + mutex_lock(&EXT4_SB(sb)->s_ondisk_orphan_lock); + ////spin_lock(&EXT4_SB(sb)->s_orphan_lock); + list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)-> + s_orphan); + mutex_unlock(&EXT4_SB(sb)->s_ondisk_orphan_lock); + ////spin_unlock(&EXT4_SB(sb)->s_orphan_lock); + jbd_debug(4, "superblock will point to %lu\n", + inode->i_ino); + jbd_debug(4, "orphan inode %lu will point to %d\n", + inode->i_ino, NEXT_ORPHAN(inode)); + goto out_unlock; + } + + mutex_lock(&EXT4_SB(sb)->s_ondisk_orphan_lock); + //***spin_lock(&EXT4_SB(sb)->s_orphan_lock); /* Insert this inode at the head of the on-disk orphan list... */ NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); @@ -2592,24 +2611,28 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) rc = ext4_mark_iloc_dirty(handle, inode, &iloc); if (!err) err = rc; - - /* Only add to the head of the in-memory list if all the - * previous operations succeeded. If the orphan_add is going to - * fail (possibly taking the journal offline), we can't risk - * leaving the inode on the orphan list: stray orphan-list - * entries can cause panics at unmount time. - * - * This is safe: on error we're going to ignore the orphan list - * anyway on the next recovery. */ -mem_insert: - if (!err) + if (!err) { + /* Only add to the head of the in-memory list if all the + * previous operations succeeded. If the orphan_add is going to + * fail (possibly taking the journal offline), we can't risk + * leaving the inode on the orphan list: stray orphan-list + * entries can cause panics at unmount time. + * + * This is safe: on error we're going to ignore the orphan list + * anyway on the next recovery. */ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); - - jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); - jbd_debug(4, "orphan inode %lu will point to %d\n", + //***spin_unlock(&EXT4_SB(sb)->s_orphan_lock); + jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); + jbd_debug(4, "orphan inode %lu will point to %d\n", inode->i_ino, NEXT_ORPHAN(inode)); + } + //**else + //***spin_unlock(&EXT4_SB(sb)->s_orphan_lock); + mutex_unlock(&EXT4_SB(sb)->s_ondisk_orphan_lock); + out_unlock: - mutex_unlock(&EXT4_SB(sb)->s_orphan_lock); + if (lock_mutex) + mutex_unlock(&inode->i_mutex); ext4_std_error(inode->i_sb, err); return err; } @@ -2622,45 +2645,65 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) { struct list_head *prev; struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_sb_info *sbi; + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); __u32 ino_next; struct ext4_iloc iloc; int err = 0; + int lock_mutex = 0; - if ((!EXT4_SB(inode->i_sb)->s_journal) && - !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) + if ((!sbi->s_journal) && + !(sbi->s_mount_state & EXT4_ORPHAN_FS)) return 0; - mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); - if (list_empty(&ei->i_orphan)) - goto out; - - ino_next = NEXT_ORPHAN(inode); - prev = ei->i_orphan.prev; - sbi = EXT4_SB(inode->i_sb); + if (!mutex_is_locked(&inode->i_mutex)) { + lock_mutex = 1; + mutex_lock(&inode->i_mutex); + } - jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); + if (list_empty(&ei->i_orphan)) { + if (lock_mutex) + mutex_unlock(&inode->i_mutex); + return 0; + } - list_del_init(&ei->i_orphan); /* If we're on an error path, we may not have a valid * transaction handle with which to update the orphan list on * disk, but we still need to remove the inode from the linked * list in memory. */ - if (!handle) - goto out; + if (!handle) { + jbd_debug(4, "remove inode %lu from orphan list\n", + inode->i_ino); + mutex_lock(&sbi->s_ondisk_orphan_lock); + ////spin_lock(&sbi->s_orphan_lock); + list_del_init(&ei->i_orphan); + mutex_unlock(&sbi->s_ondisk_orphan_lock); + ////spin_unlock(&sbi->s_orphan_lock); + } else + err = ext4_reserve_inode_write(handle, inode, &iloc); - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - goto out_err; + if (!handle || err) { + if (lock_mutex) + mutex_unlock(&inode->i_mutex); + goto out_set_err; + } + mutex_lock(&sbi->s_ondisk_orphan_lock); + ino_next = NEXT_ORPHAN(inode); + //***spin_lock(&sbi->s_orphan_lock); + prev = ei->i_orphan.prev; + jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); + list_del_init(&ei->i_orphan); + //***spin_unlock(&sbi->s_orphan_lock); if (prev == &sbi->s_orphan) { jbd_debug(4, "superblock will point to %u\n", ino_next); BUFFER_TRACE(sbi->s_sbh, "get_write_access"); err = ext4_journal_get_write_access(handle, sbi->s_sbh); + if (!err) + sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); + mutex_unlock(&sbi->s_ondisk_orphan_lock); if (err) - goto out_brelse; - sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); + goto brelse; err = ext4_handle_dirty_super(handle, inode->i_sb); } else { struct ext4_iloc iloc2; @@ -2670,25 +2713,28 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) jbd_debug(4, "orphan inode %lu will point to %u\n", i_prev->i_ino, ino_next); err = ext4_reserve_inode_write(handle, i_prev, &iloc2); + if (!err) + NEXT_ORPHAN(i_prev) = ino_next; + mutex_unlock(&sbi->s_ondisk_orphan_lock); if (err) - goto out_brelse; - NEXT_ORPHAN(i_prev) = ino_next; + goto brelse; err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2); } if (err) - goto out_brelse; + goto brelse; NEXT_ORPHAN(inode) = 0; + if (lock_mutex) + mutex_unlock(&inode->i_mutex); err = ext4_mark_iloc_dirty(handle, inode, &iloc); - -out_err: +out_set_err: ext4_std_error(inode->i_sb, err); -out: - mutex_unlock(&EXT4_SB(inode->i_sb)->s_orphan_lock); return err; -out_brelse: +brelse: + if (lock_mutex) + mutex_unlock(&inode->i_mutex); brelse(iloc.bh); - goto out_err; + goto out_set_err; } static int ext4_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 710fed2..ad9c45d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3921,8 +3921,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ - mutex_init(&sbi->s_orphan_lock); - + spin_lock_init(&sbi->s_orphan_lock); + mutex_init(&sbi->s_ondisk_orphan_lock); sb->s_root = NULL; needs_recovery = (es->s_last_orphan != 0 || -- 1.7.11.3