[RFC PATCH 02/17] vfs: Implement a FIEMAP callback

David Howells posted 17 patches 1 month, 1 week ago
[RFC PATCH 02/17] vfs: Implement a FIEMAP callback
Posted by David Howells 1 month, 1 week ago
Implement a callback in the internal kernel FIEMAP API so that kernel users
can make use of it as the filler function expects to write to userspace.
This allows the FIEMAP data to be captured and parsed.  This is useful for
cachefiles and also potentially for knfsd and ksmbd to implement their
equivalents of FIEMAP remotely rather than using SEEK_DATA/SEEK_HOLE.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: Christoph Hellwig <hch@infradead.org>
cc: Steve French <sfrench@samba.org>
cc: Namjae Jeon <linkinjeon@kernel.org>
cc: Tom Talpey <tom@talpey.com>
cc: Chuck Lever <chuck.lever@oracle.com>
cc: linux-cifs@vger.kernel.org
cc: linux-nfs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/ioctl.c             | 29 ++++++++++++++++++++---------
 include/linux/fiemap.h |  3 +++
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/fs/ioctl.c b/fs/ioctl.c
index 1c152c2b1b67..f0513e282eb7 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -93,6 +93,21 @@ static int ioctl_fibmap(struct file *filp, int __user *p)
 	return error;
 }
 
+static int fiemap_fill(struct fiemap_extent_info *fieinfo,
+		       const struct fiemap_extent *extent)
+{
+	struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
+
+	dest += fieinfo->fi_extents_mapped;
+	if (copy_to_user(dest, extent, sizeof(*extent)))
+		return -EFAULT;
+
+	fieinfo->fi_extents_mapped++;
+	if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
+		return 1;
+	return 0;
+}
+
 /**
  * fiemap_fill_next_extent - Fiemap helper function
  * @fieinfo:	Fiemap context passed into ->fiemap
@@ -112,7 +127,7 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
 			    u64 phys, u64 len, u32 flags)
 {
 	struct fiemap_extent extent;
-	struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
+	int ret;
 
 	/* only count the extents */
 	if (fieinfo->fi_extents_max == 0) {
@@ -140,13 +155,9 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
 	extent.fe_length = len;
 	extent.fe_flags = flags;
 
-	dest += fieinfo->fi_extents_mapped;
-	if (copy_to_user(dest, &extent, sizeof(extent)))
-		return -EFAULT;
-
-	fieinfo->fi_extents_mapped++;
-	if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
-		return 1;
+	ret = fieinfo->fi_fill(fieinfo, &extent);
+	if (ret != 0)
+		return ret; /* 1 to stop. */
 	return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
 }
 EXPORT_SYMBOL(fiemap_fill_next_extent);
@@ -199,7 +210,7 @@ EXPORT_SYMBOL(fiemap_prep);
 static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
 {
 	struct fiemap fiemap;
-	struct fiemap_extent_info fieinfo = { 0, };
+	struct fiemap_extent_info fieinfo = { .fi_fill = fiemap_fill, };
 	struct inode *inode = file_inode(filp);
 	int error;
 
diff --git a/include/linux/fiemap.h b/include/linux/fiemap.h
index 966092ffa89a..01929ca4b834 100644
--- a/include/linux/fiemap.h
+++ b/include/linux/fiemap.h
@@ -11,12 +11,15 @@
  * @fi_extents_mapped:	Number of mapped extents
  * @fi_extents_max:	Size of fiemap_extent array
  * @fi_extents_start:	Start of fiemap_extent array
+ * @fi_fill:		Function to fill the extents array
  */
 struct fiemap_extent_info {
 	unsigned int fi_flags;
 	unsigned int fi_extents_mapped;
 	unsigned int fi_extents_max;
 	struct fiemap_extent __user *fi_extents_start;
+	int (*fi_fill)(struct fiemap_extent_info *fiefinfo,
+		       const struct fiemap_extent *extent);
 };
 
 int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
Re: [RFC PATCH 02/17] vfs: Implement a FIEMAP callback
Posted by Christoph Hellwig 1 month, 1 week ago
On Wed, Mar 04, 2026 at 02:03:09PM +0000, David Howells wrote:
> Implement a callback in the internal kernel FIEMAP API so that kernel users
> can make use of it as the filler function expects to write to userspace.
> This allows the FIEMAP data to be captured and parsed.  This is useful for
> cachefiles and also potentially for knfsd and ksmbd to implement their
> equivalents of FIEMAP remotely rather than using SEEK_DATA/SEEK_HOLE.

Hell no.  FIEMAP is purely a debugging toool and must not get anywhere
near a data path.  NAK to all of this.
Re: [RFC PATCH 02/17] vfs: Implement a FIEMAP callback
Posted by David Howells 1 month, 1 week ago
Christoph Hellwig <hch@infradead.org> wrote:

> On Wed, Mar 04, 2026 at 02:03:09PM +0000, David Howells wrote:
> > Implement a callback in the internal kernel FIEMAP API so that kernel users
> > can make use of it as the filler function expects to write to userspace.
> > This allows the FIEMAP data to be captured and parsed.  This is useful for
> > cachefiles and also potentially for knfsd and ksmbd to implement their
> > equivalents of FIEMAP remotely rather than using SEEK_DATA/SEEK_HOLE.
> 
> Hell no.  FIEMAP is purely a debugging toool and must not get anywhere
> near a data path.  NAK to all of this.

So I have to stick with SEEK_DATA/SEEK_HOLE for this?

(Before you ask, yes, I do want to keep track of this myself, but working out
the best way to do that without reinventing the filesystem is the issue -
well, that and finding time to do it).

David
Re: [RFC PATCH 02/17] vfs: Implement a FIEMAP callback
Posted by Christoph Hellwig 1 month, 1 week ago
On Wed, Mar 04, 2026 at 02:21:54PM +0000, David Howells wrote:
> Christoph Hellwig <hch@infradead.org> wrote:
> 
> > On Wed, Mar 04, 2026 at 02:03:09PM +0000, David Howells wrote:
> > > Implement a callback in the internal kernel FIEMAP API so that kernel users
> > > can make use of it as the filler function expects to write to userspace.
> > > This allows the FIEMAP data to be captured and parsed.  This is useful for
> > > cachefiles and also potentially for knfsd and ksmbd to implement their
> > > equivalents of FIEMAP remotely rather than using SEEK_DATA/SEEK_HOLE.
> > 
> > Hell no.  FIEMAP is purely a debugging toool and must not get anywhere
> > near a data path.  NAK to all of this.
> 
> So I have to stick with SEEK_DATA/SEEK_HOLE for this?

Yes.  Why do you even want to move away from that?  It's the far
better API.  Of course like all other reporting APIs it still is
racy, but has far less problems than fiemap.
Re: [RFC PATCH 02/17] vfs: Implement a FIEMAP callback
Posted by David Howells 1 month, 1 week ago
Christoph Hellwig <hch@infradead.org> wrote:

> > So I have to stick with SEEK_DATA/SEEK_HOLE for this?
> 
> Yes.  Why do you even want to move away from that?  It's the far
> better API.  Of course like all other reporting APIs it still is
> racy, but has far less problems than fiemap.

To find the next two extents of data, say, I have to make four calls into the
backing filesystem rather than one - with all the context set up and locking
those might incur.

Granted, the vast majority of files aren't sparse, so one pair of
SEEK_DATA/SEEK_HOLE should be able to establish that.

David