[PATCH] ext3: Debug unlinking of inodes

From: Jan Kara
Date: Mon Aug 03 2009 - 18:17:35 EST


Signed-off-by: Jan Kara <jack@xxxxxxx>
---
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


--LZvS9be/3tNcYl/X--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/