public inbox for linux-ext4@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] show orphan file inode detail info
@ 2026-04-03  8:25 Ye Bin
  2026-04-03  8:25 ` [PATCH 1/3] ext4: register 'orphan_list' procfs Ye Bin
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Ye Bin @ 2026-04-03  8:25 UTC (permalink / raw)
  To: tytso, adilger.kernel, linux-ext4; +Cc: jack

From: Ye Bin <yebin10@huawei.com>

In actual production environments, the issue of inconsistency between
df and du is frequently encountered. In many cases, the cause of the
problem can be identified through the use of lsof. However, when
overlayfs is combined with project quota configuration, the issue becomes
more complex and troublesome to diagnose. First, to determine the project
ID, one needs to obtain orphaned nodes using `fsck.ext4 -fn /dev/xx`, and
then retrieve file information through `debugfs`. However, the file names
cannot always be obtained, and it is often unclear which files they are.
To identify which files these are, one would need to use crash for online
debugging or use kprobe to gather information incrementally. However, some
customers in production environments do not agree to upload any tools, and
online debugging might impact the business. There are also scenarios where
files are opened in kernel mode, which do not generate file descriptors(fds),
making it impossible to identify which files were deleted but still have
references through lsof. This patchset adds a procfs interface to query
information about orphaned nodes, which can assist in the analysis and
localization of such issues.

Ye Bin (3):
  ext4: register 'orphan_list' procfs
  ext4: show inode orphan list detail information
  ext4: show orphan file inode detail info

 fs/ext4/ext4.h   |   1 +
 fs/ext4/orphan.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/sysfs.c  |   2 +
 3 files changed, 230 insertions(+)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] ext4: register 'orphan_list' procfs
  2026-04-03  8:25 [PATCH 0/3] show orphan file inode detail info Ye Bin
@ 2026-04-03  8:25 ` Ye Bin
  2026-04-03 12:55   ` Theodore Tso
  2026-04-03  8:25 ` [PATCH 2/3] ext4: show inode orphan list detail information Ye Bin
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Ye Bin @ 2026-04-03  8:25 UTC (permalink / raw)
  To: tytso, adilger.kernel, linux-ext4; +Cc: jack

From: Ye Bin <yebin10@huawei.com>

This patch register '/proc/fs/ext4/XXX/orphan_list' procfs for show inode
orphan list about EXT4 file system.
In actual production environments, there may be inconsistencies in df/du,
sometimes due to kernel occupation, making it difficult to find such files,
and it is also difficult to operate in the current network environment. So
add "orphan_list" procfs to quickly query files that have been deleted but
are occupied.

Signed-off-by: Ye Bin <yebin10@huawei.com>
---
 fs/ext4/ext4.h   |  1 +
 fs/ext4/orphan.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/sysfs.c  |  2 ++
 3 files changed, 73 insertions(+)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 876597f8331d..fa38a8380fed 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3873,6 +3873,7 @@ extern void ext4_stop_mmpd(struct ext4_sb_info *sbi);
 extern const struct fsverity_operations ext4_verityops;
 
 /* orphan.c */
+extern const struct proc_ops ext4_orphan_proc_ops;
 extern int ext4_orphan_add(handle_t *, struct inode *);
 extern int ext4_orphan_del(handle_t *, struct inode *);
 extern void ext4_orphan_cleanup(struct super_block *sb,
diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
index 64ea47624233..1d231aeaf282 100644
--- a/fs/ext4/orphan.c
+++ b/fs/ext4/orphan.c
@@ -4,6 +4,8 @@
 #include <linux/fs.h>
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include "ext4.h"
 #include "ext4_jbd2.h"
@@ -657,3 +659,71 @@ int ext4_orphan_file_empty(struct super_block *sb)
 			return 0;
 	return 1;
 }
+
+struct ext4_proc_orphan {
+	struct ext4_inode_info cursor;
+};
+
+static void *ext4_orphan_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	return NULL;
+}
+
+static void *ext4_orphan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	return NULL;
+}
+
+static int ext4_orphan_seq_show(struct seq_file *seq, void *v)
+{
+	return 0;
+}
+
+static void ext4_orphan_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+const struct seq_operations ext4_orphan_seq_ops = {
+	.start  = ext4_orphan_seq_start,
+	.next   = ext4_orphan_seq_next,
+	.stop   = ext4_orphan_seq_stop,
+	.show   = ext4_orphan_seq_show,
+};
+
+static int ext4_seq_orphan_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	struct seq_file *m;
+	struct ext4_proc_orphan *private;
+
+	rc = seq_open_private(file, &ext4_orphan_seq_ops,
+			      sizeof(struct ext4_proc_orphan));
+	if (!rc) {
+		m = file->private_data;
+		private = m->private;
+		INIT_LIST_HEAD(&private->cursor.i_orphan);
+		private->cursor.vfs_inode.i_ino = 0;
+	}
+
+	return rc;
+}
+
+static int ext4_seq_orphan_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct ext4_proc_orphan *s = seq->private;
+	struct ext4_sb_info *sbi = EXT4_SB(pde_data(inode));
+
+	mutex_lock(&sbi->s_orphan_lock);
+	list_del(&s->cursor.i_orphan);
+	mutex_unlock(&sbi->s_orphan_lock);
+
+	return seq_release_private(inode, file);
+}
+
+const struct proc_ops ext4_orphan_proc_ops = {
+	.proc_open      = ext4_seq_orphan_open,
+	.proc_read      = seq_read,
+	.proc_lseek     = seq_lseek,
+	.proc_release   = ext4_seq_orphan_release,
+};
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
index b87d7bdab06a..324eb6b5900e 100644
--- a/fs/ext4/sysfs.c
+++ b/fs/ext4/sysfs.c
@@ -634,6 +634,8 @@ int ext4_register_sysfs(struct super_block *sb)
 				ext4_seq_mb_stats_show, sb);
 		proc_create_seq_data("mb_structs_summary", 0444, sbi->s_proc,
 				&ext4_mb_seq_structs_summary_ops, sb);
+		proc_create_data("orphan_list", 0444, sbi->s_proc,
+				 &ext4_orphan_proc_ops, sb);
 	}
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] ext4: show inode orphan list detail information
  2026-04-03  8:25 [PATCH 0/3] show orphan file inode detail info Ye Bin
  2026-04-03  8:25 ` [PATCH 1/3] ext4: register 'orphan_list' procfs Ye Bin
@ 2026-04-03  8:25 ` Ye Bin
  2026-04-03 16:22   ` Andreas Dilger
  2026-04-03  8:25 ` [PATCH 3/3] ext4: show orphan file inode detail info Ye Bin
  2026-04-03 13:03 ` [PATCH 0/3] " Theodore Tso
  3 siblings, 1 reply; 7+ messages in thread
From: Ye Bin @ 2026-04-03  8:25 UTC (permalink / raw)
  To: tytso, adilger.kernel, linux-ext4; +Cc: jack

From: Ye Bin <yebin10@huawei.com>

Some inodes added to the orphan list are due to truncation, while others
are due to deletion.Therefore, we printed the information of inode as
follows: inode number/i_nlink/i_size/i_blocks/projid/file path. By using
this information, it is possible to quickly identify files that have been
deleted but are still being referenced.

Signed-off-by: Ye Bin <yebin10@huawei.com>
---
 fs/ext4/orphan.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
index 1d231aeaf282..272de32d1a47 100644
--- a/fs/ext4/orphan.c
+++ b/fs/ext4/orphan.c
@@ -662,25 +662,108 @@ int ext4_orphan_file_empty(struct super_block *sb)
 
 struct ext4_proc_orphan {
 	struct ext4_inode_info cursor;
+	bool print_title;
 };
 
-static void *ext4_orphan_seq_start(struct seq_file *seq, loff_t *pos)
+static inline bool ext4_is_cursor(struct ext4_inode_info *inode)
+{
+	return (inode->vfs_inode.i_ino == 0);
+}
+
+static struct inode *ext4_list_next(struct list_head *head, struct list_head *p)
 {
+	struct ext4_inode_info *inode;
+
+	list_for_each_continue(p, head) {
+		inode = list_entry(p, typeof(*inode), i_orphan);
+		if (!ext4_is_cursor(inode))
+			return &inode->vfs_inode;
+	}
+
 	return NULL;
 }
 
+static void *ext4_orphan_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	struct ext4_proc_orphan *s = seq->private;
+	struct super_block *sb = pde_data(file_inode(seq->file));
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct list_head *prev;
+
+	mutex_lock(&sbi->s_orphan_lock);
+
+	if (!*pos) {
+		prev = &sbi->s_orphan;
+	} else {
+		prev = &s->cursor.i_orphan;
+		if (list_empty(prev))
+			return NULL;
+	}
+
+	return ext4_list_next(&sbi->s_orphan, prev);
+}
+
 static void *ext4_orphan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	return NULL;
+	struct super_block *sb = pde_data(file_inode(seq->file));
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct inode *inode = v;
+
+	++*pos;
+
+	return ext4_list_next(&sbi->s_orphan, &EXT4_I(inode)->i_orphan);
+}
+
+static void ext4_show_filename(struct seq_file *seq, struct inode *inode)
+{
+	struct dentry *dentry;
+
+	dentry = d_find_alias(inode);
+	if (!dentry)
+		dentry = d_find_any_alias(inode);
+
+	if (dentry)
+		seq_dentry(seq, dentry, "\t\n\\");
+	else
+		seq_puts(seq, "unknown");
+
+	dput(dentry);
+	seq_putc(seq, '\n');
 }
 
 static int ext4_orphan_seq_show(struct seq_file *seq, void *v)
 {
+	struct inode *inode = v;
+	struct ext4_proc_orphan *s = seq->private;
+
+	if (s->print_title) {
+		seq_puts(seq, "INO\tNLINK\tSIZE\tBLOCKS\tPROJID\tPATH\n");
+		s->print_title = false;
+	}
+
+	seq_printf(seq, "%llu\t%u\t%llu\t%llu\t%u\t",
+		   inode->i_ino, inode->i_nlink,
+		   i_size_read(inode), inode->i_blocks,
+		   __kprojid_val(EXT4_I(inode)->i_projid));
+
+	ext4_show_filename(seq, inode);
+
 	return 0;
 }
 
 static void ext4_orphan_seq_stop(struct seq_file *seq, void *v)
 {
+	struct super_block *sb = pde_data(file_inode(seq->file));
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct inode *inode = v;
+	struct ext4_proc_orphan *s = seq->private;
+
+	if (inode)
+		list_move_tail(&s->cursor.i_orphan, &EXT4_I(inode)->i_orphan);
+	else
+		list_del_init(&s->cursor.i_orphan);
+
+	mutex_unlock(&sbi->s_orphan_lock);
 }
 
 const struct seq_operations ext4_orphan_seq_ops = {
@@ -703,6 +786,7 @@ static int ext4_seq_orphan_open(struct inode *inode, struct file *file)
 		private = m->private;
 		INIT_LIST_HEAD(&private->cursor.i_orphan);
 		private->cursor.vfs_inode.i_ino = 0;
+		private->print_title = true;
 	}
 
 	return rc;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] ext4: show orphan file inode detail info
  2026-04-03  8:25 [PATCH 0/3] show orphan file inode detail info Ye Bin
  2026-04-03  8:25 ` [PATCH 1/3] ext4: register 'orphan_list' procfs Ye Bin
  2026-04-03  8:25 ` [PATCH 2/3] ext4: show inode orphan list detail information Ye Bin
@ 2026-04-03  8:25 ` Ye Bin
  2026-04-03 13:03 ` [PATCH 0/3] " Theodore Tso
  3 siblings, 0 replies; 7+ messages in thread
From: Ye Bin @ 2026-04-03  8:25 UTC (permalink / raw)
  To: tytso, adilger.kernel, linux-ext4; +Cc: jack

From: Ye Bin <yebin10@huawei.com>

Support show inode information in orphan file.

Signed-off-by: Ye Bin <yebin10@huawei.com>
---
 fs/ext4/orphan.c | 115 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 94 insertions(+), 21 deletions(-)

diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
index 272de32d1a47..c01887fb496b 100644
--- a/fs/ext4/orphan.c
+++ b/fs/ext4/orphan.c
@@ -663,6 +663,11 @@ int ext4_orphan_file_empty(struct super_block *sb)
 struct ext4_proc_orphan {
 	struct ext4_inode_info cursor;
 	bool print_title;
+	struct ext4_orphan_info *oi;
+	int inodes_per_ob;
+	int block_idx;
+	int offset;
+	bool orphan_file;
 };
 
 static inline bool ext4_is_cursor(struct ext4_inode_info *inode)
@@ -683,24 +688,65 @@ static struct inode *ext4_list_next(struct list_head *head, struct list_head *p)
 	return NULL;
 }
 
+static struct inode *ext4_orphan_file_next(struct ext4_proc_orphan *s,
+					   struct super_block *sb)
+{
+	struct inode *inode;
+	struct ext4_orphan_info *oi = s->oi;
+
+	for (; s->block_idx < oi->of_blocks; s->block_idx++) {
+		__le32 *bdata = (__le32 *)(oi->of_binfo[s->block_idx].ob_bh->b_data);
+
+		if (atomic_read(&oi->of_binfo[s->block_idx].ob_free_entries) ==
+		    s->inodes_per_ob) {
+			s->offset = 0;
+			continue;
+		}
+		for (; s->offset < s->inodes_per_ob; s->offset++) {
+			if (!bdata[s->offset])
+				continue;
+			inode = ext4_iget(sb, le32_to_cpu(bdata[s->offset]),
+					  EXT4_IGET_NORMAL);
+			if (IS_ERR(inode))
+				continue;
+			s->offset++;
+			return inode;
+		}
+		s->offset = 0;
+	}
+
+	return NULL;
+}
+
 static void *ext4_orphan_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	struct ext4_proc_orphan *s = seq->private;
 	struct super_block *sb = pde_data(file_inode(seq->file));
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct list_head *prev;
+	void *ret;
 
-	mutex_lock(&sbi->s_orphan_lock);
+	if (!s->orphan_file) {
+		mutex_lock(&sbi->s_orphan_lock);
+		if (!*pos)
+			prev = &sbi->s_orphan;
+		else
+			prev = &s->cursor.i_orphan;
 
-	if (!*pos) {
-		prev = &sbi->s_orphan;
-	} else {
-		prev = &s->cursor.i_orphan;
-		if (list_empty(prev))
+		if (!list_empty(prev)) {
+			ret = ext4_list_next(&sbi->s_orphan, prev);
+			if (ret)
+				return ret;
+		}
+
+		if (!s->oi)
 			return NULL;
+		list_del_init(&s->cursor.i_orphan);
+		mutex_unlock(&sbi->s_orphan_lock);
+		s->orphan_file = true;
 	}
 
-	return ext4_list_next(&sbi->s_orphan, prev);
+	return ext4_orphan_file_next(s, sb);
 }
 
 static void *ext4_orphan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@@ -708,10 +754,26 @@ static void *ext4_orphan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 	struct super_block *sb = pde_data(file_inode(seq->file));
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct inode *inode = v;
+	struct ext4_proc_orphan *s = seq->private;
+	void *ret;
 
 	++*pos;
 
-	return ext4_list_next(&sbi->s_orphan, &EXT4_I(inode)->i_orphan);
+	if (!s->orphan_file) {
+		ret = ext4_list_next(&sbi->s_orphan, &EXT4_I(inode)->i_orphan);
+		if (ret)
+			return ret;
+		if (!s->oi)
+			return NULL;
+		list_del_init(&s->cursor.i_orphan);
+		mutex_unlock(&sbi->s_orphan_lock);
+		s->orphan_file = true;
+		v = NULL;
+	}
+
+	iput(v);
+
+	return ext4_orphan_file_next(s, sb);
 }
 
 static void ext4_show_filename(struct seq_file *seq, struct inode *inode)
@@ -758,12 +820,16 @@ static void ext4_orphan_seq_stop(struct seq_file *seq, void *v)
 	struct inode *inode = v;
 	struct ext4_proc_orphan *s = seq->private;
 
-	if (inode)
-		list_move_tail(&s->cursor.i_orphan, &EXT4_I(inode)->i_orphan);
-	else
-		list_del_init(&s->cursor.i_orphan);
+	if (!s->orphan_file) {
+		if (inode)
+			list_move_tail(&s->cursor.i_orphan, &EXT4_I(inode)->i_orphan);
+		else
+			list_del_init(&s->cursor.i_orphan);
 
-	mutex_unlock(&sbi->s_orphan_lock);
+		mutex_unlock(&sbi->s_orphan_lock);
+	} else {
+		iput(v);
+	}
 }
 
 const struct seq_operations ext4_orphan_seq_ops = {
@@ -777,16 +843,21 @@ static int ext4_seq_orphan_open(struct inode *inode, struct file *file)
 {
 	int rc;
 	struct seq_file *m;
-	struct ext4_proc_orphan *private;
+	struct ext4_proc_orphan *s;
 
 	rc = seq_open_private(file, &ext4_orphan_seq_ops,
 			      sizeof(struct ext4_proc_orphan));
 	if (!rc) {
+		struct super_block *sb = pde_data(file_inode(file));
 		m = file->private_data;
-		private = m->private;
-		INIT_LIST_HEAD(&private->cursor.i_orphan);
-		private->cursor.vfs_inode.i_ino = 0;
-		private->print_title = true;
+		s = m->private;
+		INIT_LIST_HEAD(&s->cursor.i_orphan);
+		s->cursor.vfs_inode.i_ino = 0;
+		s->print_title = true;
+		if (ext4_has_feature_orphan_file(sb)) {
+			s->oi = &EXT4_SB(sb)->s_orphan_info;
+			s->inodes_per_ob = ext4_inodes_per_orphan_block(sb);
+		}
 	}
 
 	return rc;
@@ -798,9 +869,11 @@ static int ext4_seq_orphan_release(struct inode *inode, struct file *file)
 	struct ext4_proc_orphan *s = seq->private;
 	struct ext4_sb_info *sbi = EXT4_SB(pde_data(inode));
 
-	mutex_lock(&sbi->s_orphan_lock);
-	list_del(&s->cursor.i_orphan);
-	mutex_unlock(&sbi->s_orphan_lock);
+	if (!s->orphan_file) {
+		mutex_lock(&sbi->s_orphan_lock);
+		list_del(&s->cursor.i_orphan);
+		mutex_unlock(&sbi->s_orphan_lock);
+	}
 
 	return seq_release_private(inode, file);
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] ext4: register 'orphan_list' procfs
  2026-04-03  8:25 ` [PATCH 1/3] ext4: register 'orphan_list' procfs Ye Bin
@ 2026-04-03 12:55   ` Theodore Tso
  0 siblings, 0 replies; 7+ messages in thread
From: Theodore Tso @ 2026-04-03 12:55 UTC (permalink / raw)
  To: Ye Bin; +Cc: adilger.kernel, linux-ext4, jack

On Fri, Apr 03, 2026 at 04:25:05PM +0800, Ye Bin wrote:
> +		proc_create_data("orphan_list", 0444, sbi->s_proc,
> +				 &ext4_orphan_proc_ops, sb);

This should really be mode 0400, especially once the file path is made
available, since otherwise the kernel might end up leaking private
user's information.  Even in a data center use case, in a multi-user
container use case (Docker, Kubernetes, etc.) leaking information
about one user's file names could be a real problem.

      	  	      	    	     - Ted

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/3] show orphan file inode detail info
  2026-04-03  8:25 [PATCH 0/3] show orphan file inode detail info Ye Bin
                   ` (2 preceding siblings ...)
  2026-04-03  8:25 ` [PATCH 3/3] ext4: show orphan file inode detail info Ye Bin
@ 2026-04-03 13:03 ` Theodore Tso
  3 siblings, 0 replies; 7+ messages in thread
From: Theodore Tso @ 2026-04-03 13:03 UTC (permalink / raw)
  To: Ye Bin; +Cc: adilger.kernel, linux-ext4, jack

On Fri, Apr 03, 2026 at 04:25:04PM +0800, Ye Bin wrote:
> From: Ye Bin <yebin10@huawei.com>
> 
> In actual production environments, the issue of inconsistency between
> df and du is frequently encountered. In many cases, the cause of the
> problem can be identified through the use of lsof. However, when
> overlayfs is combined with project quota configuration, the issue becomes
> more complex and troublesome to diagnose. First, to determine the project
> ID, one needs to obtain orphaned nodes using `fsck.ext4 -fn /dev/xx`, and
> then retrieve file information through `debugfs`. However, the file names
> cannot always be obtained, and it is often unclear which files they are.
> To identify which files these are, one would need to use crash for online
> debugging or use kprobe to gather information incrementally. However, some
> customers in production environments do not agree to upload any tools, and
> online debugging might impact the business. There are also scenarios where
> files are opened in kernel mode, which do not generate file descriptors(fds),
> making it impossible to identify which files were deleted but still have
> references through lsof. This patchset adds a procfs interface to query
> information about orphaned nodes, which can assist in the analysis and
> localization of such issues.

There are some concens which were noted by Sashiko review, including
races with unmountings, a potential deadlock, and some issues relating
to long pathnames, and a TOCTOU race that might lead to a file system
erroneously being declared corrupted.  PTAL:

https://sashiko.dev/#/patchset/20260403082507.1882703-1-yebin%40huaweicloud.com

Thanks!

						- Ted

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] ext4: show inode orphan list detail information
  2026-04-03  8:25 ` [PATCH 2/3] ext4: show inode orphan list detail information Ye Bin
@ 2026-04-03 16:22   ` Andreas Dilger
  0 siblings, 0 replies; 7+ messages in thread
From: Andreas Dilger @ 2026-04-03 16:22 UTC (permalink / raw)
  To: Ye Bin; +Cc: tytso, linux-ext4, jack

On Apr 3, 2026, at 02:25, Ye Bin <yebin@huaweicloud.com> wrote:
> 
> From: Ye Bin <yebin10@huawei.com>
> 
> Some inodes added to the orphan list are due to truncation, while others
> are due to deletion.Therefore, we printed the information of inode as
> follows: inode number/i_nlink/i_size/i_blocks/projid/file path. By using
> this information, it is possible to quickly identify files that have been
> deleted but are still being referenced.

Since the format of this output is still flexible, I would request that
it be formatted in a way that is more easily understood and parsed instead
of just an unformatted list of numbers.

Using YAML combines both human and machine readable properties, without
a lot of overhead, something like:

- ino: INUM, link: NLINK, size: SIZE, blocks: BLOCKS, proj: PROJID, path: "PATH"
- ino: ...
- ino: ...

The PATH should derfinitely be quoted to avoid issues with spaces and
other special characters in the filename.

Cheers, Andreas

> 
> Signed-off-by: Ye Bin <yebin10@huawei.com>
> ---
> fs/ext4/orphan.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
> index 1d231aeaf282..272de32d1a47 100644
> --- a/fs/ext4/orphan.c
> +++ b/fs/ext4/orphan.c
> @@ -662,25 +662,108 @@ int ext4_orphan_file_empty(struct super_block *sb)
> 
> struct ext4_proc_orphan {
> struct ext4_inode_info cursor;
> + bool print_title;
> };
> 
> -static void *ext4_orphan_seq_start(struct seq_file *seq, loff_t *pos)
> +static inline bool ext4_is_cursor(struct ext4_inode_info *inode)
> +{
> + return (inode->vfs_inode.i_ino == 0);
> +}
> +
> +static struct inode *ext4_list_next(struct list_head *head, struct list_head *p)
> {
> + struct ext4_inode_info *inode;
> +
> + list_for_each_continue(p, head) {
> + inode = list_entry(p, typeof(*inode), i_orphan);
> + if (!ext4_is_cursor(inode))
> + return &inode->vfs_inode;
> + }
> +
> return NULL;
> }
> 
> +static void *ext4_orphan_seq_start(struct seq_file *seq, loff_t *pos)
> +{
> + struct ext4_proc_orphan *s = seq->private;
> + struct super_block *sb = pde_data(file_inode(seq->file));
> + struct ext4_sb_info *sbi = EXT4_SB(sb);
> + struct list_head *prev;
> +
> + mutex_lock(&sbi->s_orphan_lock);
> +
> + if (!*pos) {
> + prev = &sbi->s_orphan;
> + } else {
> + prev = &s->cursor.i_orphan;
> + if (list_empty(prev))
> + return NULL;
> + }
> +
> + return ext4_list_next(&sbi->s_orphan, prev);
> +}
> +
> static void *ext4_orphan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
> {
> - return NULL;
> + struct super_block *sb = pde_data(file_inode(seq->file));
> + struct ext4_sb_info *sbi = EXT4_SB(sb);
> + struct inode *inode = v;
> +
> + ++*pos;
> +
> + return ext4_list_next(&sbi->s_orphan, &EXT4_I(inode)->i_orphan);
> +}
> +
> +static void ext4_show_filename(struct seq_file *seq, struct inode *inode)
> +{
> + struct dentry *dentry;
> +
> + dentry = d_find_alias(inode);
> + if (!dentry)
> + dentry = d_find_any_alias(inode);
> +
> + if (dentry)
> + seq_dentry(seq, dentry, "\t\n\\");
> + else
> + seq_puts(seq, "unknown");
> +
> + dput(dentry);
> + seq_putc(seq, '\n');
> }
> 
> static int ext4_orphan_seq_show(struct seq_file *seq, void *v)
> {
> + struct inode *inode = v;
> + struct ext4_proc_orphan *s = seq->private;
> +
> + if (s->print_title) {
> + seq_puts(seq, "INO\tNLINK\tSIZE\tBLOCKS\tPROJID\tPATH\n");
> + s->print_title = false;
> + }
> +
> + seq_printf(seq, "%llu\t%u\t%llu\t%llu\t%u\t",
> +   inode->i_ino, inode->i_nlink,
> +   i_size_read(inode), inode->i_blocks,
> +   __kprojid_val(EXT4_I(inode)->i_projid));
> +
> + ext4_show_filename(seq, inode);
> +
> return 0;
> }
> 
> static void ext4_orphan_seq_stop(struct seq_file *seq, void *v)
> {
> + struct super_block *sb = pde_data(file_inode(seq->file));
> + struct ext4_sb_info *sbi = EXT4_SB(sb);
> + struct inode *inode = v;
> + struct ext4_proc_orphan *s = seq->private;
> +
> + if (inode)
> + list_move_tail(&s->cursor.i_orphan, &EXT4_I(inode)->i_orphan);
> + else
> + list_del_init(&s->cursor.i_orphan);
> +
> + mutex_unlock(&sbi->s_orphan_lock);
> }
> 
> const struct seq_operations ext4_orphan_seq_ops = {
> @@ -703,6 +786,7 @@ static int ext4_seq_orphan_open(struct inode *inode, struct file *file)
> private = m->private;
> INIT_LIST_HEAD(&private->cursor.i_orphan);
> private->cursor.vfs_inode.i_ino = 0;
> + private->print_title = true;
> }
> 
> return rc;
> -- 
> 2.34.1
> 


Cheers, Andreas






^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-04-03 16:23 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-03  8:25 [PATCH 0/3] show orphan file inode detail info Ye Bin
2026-04-03  8:25 ` [PATCH 1/3] ext4: register 'orphan_list' procfs Ye Bin
2026-04-03 12:55   ` Theodore Tso
2026-04-03  8:25 ` [PATCH 2/3] ext4: show inode orphan list detail information Ye Bin
2026-04-03 16:22   ` Andreas Dilger
2026-04-03  8:25 ` [PATCH 3/3] ext4: show orphan file inode detail info Ye Bin
2026-04-03 13:03 ` [PATCH 0/3] " Theodore Tso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox