* [PATCH 2/2 V2] Add SEEK_HOLE/SEEK_DATA support
@ 2011-09-28 6:39 Jeff Liu
0 siblings, 0 replies; only message in thread
From: Jeff Liu @ 2011-09-28 6:39 UTC (permalink / raw)
To: linux-ext4; +Cc: Yongqiang Yang, Sunil Mushran
Add SEEK_HOLE/SEEK_DATA support.
Signed-off-by: Jie Liu <jeff.liu@oracle.com>
---
fs/ext4/ext4.h | 4 ++
fs/ext4/ext4_extents.h | 8 +++++
fs/ext4/extents.c | 75
++++++++++++++++++++++++++++++++++++++++++++++++
fs/ext4/file.c | 15 +++++----
4 files changed, 95 insertions(+), 7 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index e717dfd..9eda477 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2222,6 +2222,10 @@ extern int ext4_move_extents(struct file *o_filp,
struct file *d_filp,
__u64 start_orig, __u64 start_donor,
__u64 len, __u64 *moved_len);
+/* extents.c */
+extern int ext4_find_desired_extent(struct inode *inode, loff_t *offset,
+ int origin);
+
/* page-io.c */
extern int __init ext4_init_pageio(void);
extern void ext4_exit_pageio(void);
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index 095c36f..ca7a339 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -116,6 +116,14 @@ struct ext4_ext_path {
};
/*
+ * Structure for retrieving extent offset for SEEK_DATA/SEEK_HOLE.
+ */
+struct ext4_extent_seek_info {
+ unsigned int origin; /* SEEK_DATA or SEEK_HOLE */
+ loff_t offset; /* input/output offset */
+};
+
+/*
* structure for external API
*/
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 06e88d4..4c78061 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4122,6 +4122,81 @@ static int ext4_ext_fiemap_cb(struct inode
*inode, ext4_lblk_t next,
return EXT_CONTINUE;
}
+/*
+ * Callback function called for each extent to gather SEEK_DATA/SEEK_HOLE
+ * information.
+ */
+static int ext4_ext_seek_cb(struct inode *inode, ext4_lblk_t next,
+ struct ext4_ext_cache *newex,
+ struct ext4_extent *ex, void *data)
+{
+ __u64 logical;
+ int ret = 0;
+ unsigned char blksize_bits;
+ struct ext4_extent_seek_info *ext_seek_info = data;
+
+ blksize_bits = inode->i_sb->s_blocksize_bits;
+ logical = (__u64)newex->ec_block << blksize_bits;
+
+ if (newex->ec_start == 0) {
+ ret = ext4_get_delayed_extent(inode, next, newex, &logical, 0);
+ if (ret == EXT_CONTINUE) {
+ /*
+ * A hole found, return EXT_BREAK and fill ext_seek_info
+ * ->offset with logical for SEEK_HOLE, or just return.
+ */
+ if (ext_seek_info->origin == SEEK_HOLE) {
+ ext_seek_info->offset = logical;
+ return EXT_BREAK;
+ } else {
+ return ret;
+ }
+ }
+ /* found a delayed extent */
+ }
+
+ if (ext_seek_info->origin == SEEK_DATA) {
+ ext_seek_info->offset = logical;
+ return EXT_BREAK;
+ }
+
+ return EXT_CONTINUE;
+}
+
+int ext4_find_desired_extent(struct inode *inode, loff_t *offset, int
origin)
+{
+ ext4_lblk_t start_blk;
+ ext4_lblk_t end_blk;
+ ext4_lblk_t len_blks;
+ struct ext4_extent_seek_info ext_seek_info;
+ unsigned int blkbits = inode->i_sb->s_blocksize_bits;
+ int error = 0;
+
+ /*
+ * FIXME: do we need to support old block based file?
+ * Generally, we would like to gather extents info over
+ * SEEK_DATA/SEEK_HOLE interface for efficient sparse file
+ * read only.
+ */
+ if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
+ return -ENOTSUPP;
+
+ start_blk = *offset >> blkbits;
+ if (start_blk >= EXT_MAX_BLOCKS)
+ return -ENXIO;
+
+ end_blk = i_size_read(inode) >> blkbits;
+ len_blks = ((ext4_lblk_t)end_blk) - start_blk + 1;
+
+ ext_seek_info.origin = origin;
+ error = ext4_ext_walk_space(inode, start_blk, len_blks,
+ ext4_ext_seek_cb, &ext_seek_info);
+ if (!error)
+ *offset = ext_seek_info.offset;
+
+ return error;
+}
+
/* fiemap flags we can handle specified here */
#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index e4095e9..58c8c0a 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -219,6 +219,7 @@ loff_t ext4_llseek(struct file *file, loff_t offset,
int origin)
{
struct inode *inode = file->f_mapping->host;
loff_t maxbytes;
+ int ret;
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes;
@@ -241,21 +242,21 @@ loff_t ext4_llseek(struct file *file, loff_t
offset, int origin)
* In the generic case the entire file is data, so as long as
* offset isn't at the end of the file then the offset is data.
*/
- if (offset >= inode->i_size) {
- mutex_unlock(&inode->i_mutex);
- return -ENXIO;
- }
- break;
case SEEK_HOLE:
/*
* There is a virtual hole at the end of the file, so as long as
* offset isn't i_size or larger, return i_size.
*/
- if (offset >= inode->i_size) {
+ if (offset >= i_size_read(inode)) {
mutex_unlock(&inode->i_mutex);
return -ENXIO;
}
- offset = inode->i_size;
+
+ ret = ext4_find_desired_extent(inode, &offset, origin);
+ if (ret) {
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+ }
break;
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2011-09-28 6:39 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-28 6:39 [PATCH 2/2 V2] Add SEEK_HOLE/SEEK_DATA support Jeff Liu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.