>From b32511dbd58c8d9111001a33d253a283943bbf7a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Aug 2009 00:17:35 +0200 Subject: [PATCH] ext3: Debug unlinking of inodes Signed-off-by: Jan Kara --- fs/ext3/inode.c | 28 ++++++++++++++++++++++++++++ fs/ext3/namei.c | 2 +- include/linux/fs.h | 6 ++++++ 3 files changed, 35 insertions(+), 1 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b49908a..dca30a2 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2876,6 +2876,9 @@ bad_inode: return ERR_PTR(ret); } +struct buffer_head *ext3_find_entry(struct inode *dir, + struct qstr *entry, + struct ext3_dir_entry_2 **res_dir); /* * Post the struct inode info into an on-disk inode location in the * buffer-cache. This gobbles the caller's reference to the @@ -2892,6 +2895,31 @@ static int ext3_do_update_inode(handle_t *handle, struct buffer_head *bh = iloc->bh; int err = 0, rc, block; + if (!inode->i_nlink && !inode->i_checked_drop) { + struct dentry *dentry; + struct ext3_dir_entry_2 *de; + struct buffer_head *bh; + + inode->i_checked_drop = 1; + if (list_empty(&inode->i_dentry)) { + printk("No dentry for unlinked inode %lu\nNlink dropped at 0x%lx\n", inode->i_ino, inode->i_dropped); + dump_stack(); + goto next; + } + dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); + if (!dentry->d_parent) { + printk("Dentry %s for unlinked inode %lu has no parent\nNlink dropped at 0x%lx\n", dentry->d_name.name, inode->i_ino, inode->i_dropped); + dump_stack(); + goto next; + } + bh = ext3_find_entry(dentry->d_parent->d_inode, &dentry->d_name, &de); + if (bh && le32_to_cpu(de->inode) == inode->i_ino) { + printk("Found directory entry %s for unlinked inode %lu\nNlink dropped at 0x%lx\n", dentry->d_name.name, inode->i_ino, inode->i_dropped); + brelse(bh); + dump_stack(); + } + } +next: /* For fields not not tracking in the in-memory inode, * initialise them to zero for new inodes. */ if (ei->i_state & EXT3_STATE_NEW) diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 6ff7b97..e66b6c0 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -850,7 +850,7 @@ static inline int search_dirblock(struct buffer_head * bh, * The returned buffer_head has ->b_count elevated. The caller is expected * to brelse() it when appropriate. */ -static struct buffer_head *ext3_find_entry(struct inode *dir, +struct buffer_head *ext3_find_entry(struct inode *dir, struct qstr *entry, struct ext3_dir_entry_2 **res_dir) { diff --git a/include/linux/fs.h b/include/linux/fs.h index a36ffa5..271c51c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -780,6 +780,8 @@ struct inode { struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif + unsigned long i_dropped; + int i_checked_drop; void *i_private; /* fs or device private pointer */ }; @@ -1693,6 +1695,8 @@ static inline void inode_inc_link_count(struct inode *inode) static inline void drop_nlink(struct inode *inode) { inode->i_nlink--; + inode->i_dropped = _THIS_IP_; + inode->i_checked_drop = 0; } /** @@ -1706,6 +1710,8 @@ static inline void drop_nlink(struct inode *inode) static inline void clear_nlink(struct inode *inode) { inode->i_nlink = 0; + inode->i_dropped = _THIS_IP_; + inode->i_checked_drop = 0; } static inline void inode_dec_link_count(struct inode *inode) -- 1.6.0.2