linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 4/5] ext4: implement ext4_fiemap
@ 2008-05-25  0:02 Mark Fasheh
  2008-05-25  7:51 ` Andreas Dilger
  0 siblings, 1 reply; 3+ messages in thread
From: Mark Fasheh @ 2008-05-25  0:02 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Eric Sandeen

From: Eric Sandeen <sandeen@redhat.com>

Hook ext4 to the vfs fiemap interface.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/ext4/ext4.h         |    2 +
 fs/ext4/ext4_extents.h |    2 +-
 fs/ext4/extents.c      |  120 +++++++++++++++++++++++++++++++++++++++++++++++-
 fs/ext4/file.c         |    4 ++
 4 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 8158083..55f7ca1 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -383,6 +383,8 @@ struct ext4_inode {
 	__le32  i_version_hi;	/* high 32 bits for 64-bit version */
 };
 
+#define EXT4_FIEMAP_FLAG_INCOMPAT_UNSUPP (FIEMAP_FLAG_INCOMPAT &	\
+					  ~(FIEMAP_FLAG_LUN_OFFSET))
 
 #define EXT4_EPOCH_BITS 2
 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index 20906b7..c9fabb0 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -132,7 +132,7 @@ struct ext4_ext_path {
  */
 typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
 					struct ext4_ext_cache *,
-					void *);
+					struct ext4_extent *, void *);
 
 #define EXT_CONTINUE   0
 #define EXT_BREAK      1
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ea8dd06..fe7687c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <linux/falloc.h>
 #include <asm/uaccess.h>
+#include <linux/fiemap.h>
 #include "ext4_jbd2.h"
 #include "ext4_extents.h"
 
@@ -1664,11 +1665,12 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
 		}
 
 		BUG_ON(cbex.ec_len == 0);
-		err = func(inode, path, &cbex, cbdata);
+		err = func(inode, path, &cbex, ex, cbdata);
 		ext4_ext_drop_refs(path);
 
 		if (err < 0)
 			break;
+
 		if (err == EXT_REPEAT)
 			continue;
 		else if (err == EXT_BREAK) {
@@ -3051,3 +3053,119 @@ retry:
 	mutex_unlock(&inode->i_mutex);
 	return ret > 0 ? ret2 : ret;
 }
+
+struct fiemap_internal {
+	struct fiemap		*fiemap_s;
+	struct fiemap_extent	fm_extent;
+	char			*cur_ext_ptr;
+	int			err;
+};
+
+/*
+ * Callback function called for each extent to gather FIEMAP information.
+ */
+int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
+		       struct ext4_ext_cache *newex, struct ext4_extent *ex,
+		       void *data)
+{
+	struct fiemap_extent_info *fieinfo = data;
+	unsigned long blksize_bits = inode->i_sb->s_blocksize_bits;
+	__u64	logical;
+	__u64	physical;
+	__u64	length;
+	__u32	flags = 0;
+	int	error;
+
+	logical =  (__u64)newex->ec_block << blksize_bits;
+
+	if (newex->ec_type == EXT4_EXT_CACHE_GAP) {
+		pgoff_t offset;
+		struct page *page;
+		struct buffer_head *bh;
+
+		offset = logical >> PAGE_SHIFT;
+		page = find_get_page(inode->i_mapping, offset);
+		if (!page)
+			return EXT_CONTINUE;
+
+		bh = page_buffers(page);
+
+		if (!bh)
+			return EXT_CONTINUE;
+
+		if (buffer_delay(bh)) {
+			flags |= FIEMAP_EXTENT_DELALLOC;
+			page_cache_release(page);
+		} else {
+			page_cache_release(page);
+			return EXT_CONTINUE;
+		}
+	}
+
+	physical = (__u64)newex->ec_start << blksize_bits;
+	length =   (__u64)newex->ec_len << blksize_bits;
+
+	/* Just counting extents? */
+	if (fieinfo->fi_flags & FIEMAP_FLAG_NUM_EXTENTS) {
+		fieinfo->fi_extents_mapped++;
+		return EXT_CONTINUE;
+	}
+
+	if (ex && ext4_ext_is_uninitialized(ex))
+		flags |= FIEMAP_EXTENT_UNWRITTEN;
+
+	/*
+	 * If this extent reaches EXT_MAX_BLOCK, it must be last.
+	 *
+	 * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
+	 * this indicates no more allocated blocks.
+	 *
+	 * XXX this might miss a single-block extent at EXT_MAX_BLOCK
+	 */
+	if (logical + length - 1 == EXT_MAX_BLOCK ||
+	    ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK)
+		flags |= FIEMAP_EXTENT_LAST;
+
+	error = fiemap_fill_next_extent(fieinfo, logical, physical,
+					length, flags, 0);
+	if (error < 0)
+		return error;
+	if (error == 1)
+		return EXT_BREAK;
+
+	return EXT_CONTINUE;
+}
+
+int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		__u64 start, __u64 len)
+{
+	ext4_lblk_t start_blk;
+	ext4_lblk_t len_blks;
+	int err;
+
+	/* fallback to generic here if not extents */
+#warning fix bitmap fallback
+	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+		return -EOPNOTSUPP;
+
+#if 0
+	/* bail on unsupported flags for this fs */
+	if (fiemap_s->fm_flags & EXT4_FIEMAP_FLAG_INCOMPAT_UNSUPP)
+		return -EOPNOTSUPP;
+#endif
+
+	start_blk = start >> inode->i_sb->s_blocksize_bits;
+	len_blks = len >> inode->i_sb->s_blocksize_bits;
+
+	/*
+	 * Walk the extent tree gathering extent information.
+	 * ext4_ext_fiemap_cb will push extents back to user.
+	 */
+	down_write(&EXT4_I(inode)->i_data_sem);
+	err = ext4_ext_walk_space(inode, start_blk, len_blks,
+				  ext4_ext_fiemap_cb, fieinfo);
+	up_write(&EXT4_I(inode)->i_data_sem);
+
+	return err;
+}
+
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 4159be6..99bde24 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -123,6 +123,9 @@ force_commit:
 	return ret;
 }
 
+extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		__u64 start, __u64 len);
+
 const struct file_operations ext4_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
@@ -152,5 +155,6 @@ const struct inode_operations ext4_file_inode_operations = {
 #endif
 	.permission	= ext4_permission,
 	.fallocate	= ext4_fallocate,
+	.fiemap		= ext4_fiemap,
 };
 
-- 
1.5.4.1


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

* Re: [PATCH 4/5] ext4: implement ext4_fiemap
  2008-05-25  0:02 [PATCH 4/5] ext4: implement ext4_fiemap Mark Fasheh
@ 2008-05-25  7:51 ` Andreas Dilger
  2008-05-25 15:26   ` Eric Sandeen
  0 siblings, 1 reply; 3+ messages in thread
From: Andreas Dilger @ 2008-05-25  7:51 UTC (permalink / raw)
  To: Mark Fasheh; +Cc: linux-fsdevel, Eric Sandeen

On May 24, 2008  17:02 -0700, Mark Fasheh wrote:
> +#define EXT4_FIEMAP_FLAG_INCOMPAT_UNSUPP (FIEMAP_FLAG_INCOMPAT &	\
> +					  ~(FIEMAP_FLAG_LUN_OFFSET))

Per discussion with Eric, this needs to be changed:

#define EXT4_FIEMAP_FLAG_SUPP (FIEMAP_FLAG_NUM_EXTENTS | FIEMAP_FLAG_SYNC | \
			       FIEMAP_FLAG_HSM_READ | FIEMAP_FLAG_LUN_ORDER)


> +struct fiemap_internal {
> +	struct fiemap		*fiemap_s;
> +	struct fiemap_extent	fm_extent;
> +	char			*cur_ext_ptr;
> +	int			err;
> +};

This is no longer used and can be removed (now uses fiemap_extent_info).

> +/*
> + * Callback function called for each extent to gather FIEMAP information.
> + */
> +int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
> +		       struct ext4_ext_cache *newex, struct ext4_extent *ex,
> +		       void *data)
> +{
> +	/* Just counting extents? */
> +	if (fieinfo->fi_flags & FIEMAP_FLAG_NUM_EXTENTS) {
> +		fieinfo->fi_extents_mapped++;
> +		return EXT_CONTINUE;
> +	}

This isn't needed anymore, fiemap_fill_next_extent() handles it.


> +int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
> +		__u64 start, __u64 len)
> +{
> +	/* fallback to generic here if not extents */
> +#warning fix bitmap fallback
> +	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
> +		return -EOPNOTSUPP;

	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
		return generic_block_fiemap(inode, fieinfo, start, len,
					    ext4_get_block);

> +#if 0
> +	/* bail on unsupported flags for this fs */
> +	if (fiemap_s->fm_flags & EXT4_FIEMAP_FLAG_INCOMPAT_UNSUPP)
> +		return -EOPNOTSUPP;
> +#endif

This should be reinstated now that we have come to a decision on the flags:

	if (fieinfo->fi_flags & ~EXT4_FIEMAP_FLAG_SUPP) {
		fieinfo->fi_flags &= ~EXT4_FIEMAP_FLAG_SUPP;
		return -EBADF;
	}


Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.


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

* Re: [PATCH 4/5] ext4: implement ext4_fiemap
  2008-05-25  7:51 ` Andreas Dilger
@ 2008-05-25 15:26   ` Eric Sandeen
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Sandeen @ 2008-05-25 15:26 UTC (permalink / raw)
  To: Andreas Dilger; +Cc: Mark Fasheh, linux-fsdevel

Andreas Dilger wrote:
> On May 24, 2008  17:02 -0700, Mark Fasheh wrote:
>> +#define EXT4_FIEMAP_FLAG_INCOMPAT_UNSUPP (FIEMAP_FLAG_INCOMPAT &	\
>> +					  ~(FIEMAP_FLAG_LUN_OFFSET))
> 
> Per discussion with Eric, this needs to be changed:
> 
> #define EXT4_FIEMAP_FLAG_SUPP (FIEMAP_FLAG_NUM_EXTENTS | FIEMAP_FLAG_SYNC | \
> 			       FIEMAP_FLAG_HSM_READ | FIEMAP_FLAG_LUN_ORDER)
> 

Yep, I agree with this and the others, probably should have put "proof
of concept" in the original message; I knew it had warts but didn't want
to hold up Mark's RFE.

Thanks Andreas,

-Eric

>> +struct fiemap_internal {
>> +	struct fiemap		*fiemap_s;
>> +	struct fiemap_extent	fm_extent;
>> +	char			*cur_ext_ptr;
>> +	int			err;
>> +};
> 
> This is no longer used and can be removed (now uses fiemap_extent_info).
> 
>> +/*
>> + * Callback function called for each extent to gather FIEMAP information.
>> + */
>> +int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
>> +		       struct ext4_ext_cache *newex, struct ext4_extent *ex,
>> +		       void *data)
>> +{
>> +	/* Just counting extents? */
>> +	if (fieinfo->fi_flags & FIEMAP_FLAG_NUM_EXTENTS) {
>> +		fieinfo->fi_extents_mapped++;
>> +		return EXT_CONTINUE;
>> +	}
> 
> This isn't needed anymore, fiemap_fill_next_extent() handles it.
> 
> 
>> +int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>> +		__u64 start, __u64 len)
>> +{
>> +	/* fallback to generic here if not extents */
>> +#warning fix bitmap fallback
>> +	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
>> +		return -EOPNOTSUPP;
> 
> 	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
> 		return generic_block_fiemap(inode, fieinfo, start, len,
> 					    ext4_get_block);
> 
>> +#if 0
>> +	/* bail on unsupported flags for this fs */
>> +	if (fiemap_s->fm_flags & EXT4_FIEMAP_FLAG_INCOMPAT_UNSUPP)
>> +		return -EOPNOTSUPP;
>> +#endif
> 
> This should be reinstated now that we have come to a decision on the flags:
> 
> 	if (fieinfo->fi_flags & ~EXT4_FIEMAP_FLAG_SUPP) {
> 		fieinfo->fi_flags &= ~EXT4_FIEMAP_FLAG_SUPP;
> 		return -EBADF;
> 	}
> 
> 
> Cheers, Andreas
> --
> Andreas Dilger
> Sr. Staff Engineer, Lustre Group
> Sun Microsystems of Canada, Inc.
> 


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

end of thread, other threads:[~2008-05-25 15:26 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-25  0:02 [PATCH 4/5] ext4: implement ext4_fiemap Mark Fasheh
2008-05-25  7:51 ` Andreas Dilger
2008-05-25 15:26   ` Eric Sandeen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).