From: Jeff Liu <jeff.liu@oracle.com>
To: xfs@oss.sgi.com
Cc: Christoph Hellwig <hch@infradead.org>,
Chris Mason <chris.mason@oracle.com>,
aelder@sgi.com
Subject: [PATCH] Introduce SEEK_DATA/SEEK_HOLE support to XFS V1
Date: Sat, 19 Nov 2011 16:37:13 +0800 [thread overview]
Message-ID: <4EC76AB9.9030604@oracle.com> (raw)
In-Reply-To: <4EC768F5.4050904@oracle.com>
Signed-off-by: Jie Liu <jeff.liu@oracle.com>
---
fs/xfs/xfs_bmap.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_bmap.h | 1 +
fs/xfs/xfs_file.c | 51 ++++++++++++++++++++++++++++++++-
fs/xfs/xfs_iops.c | 64 +++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_iops.h | 3 ++
5 files changed, 199 insertions(+), 1 deletions(-)
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index c68baeb..04c3930 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -6133,3 +6133,84 @@ next_block:
return error;
}
+
+
+int
+xfs_seek_data_hole(
+ struct xfs_inode *ip,
+ loff_t *start,
+ u32 type)
+{
+ xfs_mount_t *mp = ip->i_mount;
+ xfs_fileoff_t seekoff = *start;
+ xfs_fileoff_t filelen;
+ xfs_extnum_t lastx;
+ xfs_ifork_t *ifp;
+ struct xfs_bmbt_irec got;
+ struct xfs_bmbt_irec prev;
+ u64 extoff;
+ u64 extlen;
+ int eof;
+
+ if (xfs_get_extsz_hint(ip) ||
+ ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) {
+ filelen = XFS_MAXIOFFSET(mp);
+ } else {
+ filelen = ip->i_size;
+ }
+
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+ xfs_bmap_search_extents(ip, XFS_BB_TO_FSBT(mp, BTOBB(*start)),
+ XFS_DATA_FORK, &eof, &lastx, &got, &prev);
+
+ if (type == SEEK_DATA) {
+ extoff = BBTOB(XFS_FSB_TO_BB(mp, got.br_startoff));
+ extlen = BBTOB(XFS_FSB_TO_BB(mp, got.br_blockcount));
+
+ if (eof) {
+ if (seekoff < extoff + extlen)
+ *start = seekoff;
+ else {
+ /*
+ * There is no more data region past the
+ * supplied offset.
+ */
+ return XFS_ERROR(ENXIO);
+ }
+ }
+
+ *start = seekoff < extoff ? extoff : seekoff;
+ } else {
+ for (;;) {
+ extoff = BBTOB(XFS_FSB_TO_BB(mp, got.br_startoff));
+ extlen = BBTOB(XFS_FSB_TO_BB(mp, got.br_blockcount));
+ if (eof) {
+ /*
+ * There might be a hole at the end of the
+ * file, adjust to the file size.
+ */
+ if (seekoff >= extoff) {
+ *start = min_t(xfs_fileoff_t, filelen,
+ (extoff + extlen));
+ }
+ break;
+ }
+
+ /* A hole found */
+ if (seekoff < extoff) {
+ *start = seekoff;
+ break;
+ }
+
+ /* Fetch the next extent */
+ seekoff = extoff + extlen;
+ if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t))
+ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx),
+ &got);
+ else
+ eof = 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 89ee672..964e29b 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -196,6 +196,7 @@ int xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip,
int xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx,
xfs_extnum_t num);
uint xfs_default_attroffset(struct xfs_inode *ip);
+int xfs_seek_data_hole(struct xfs_inode *ip, loff_t *start, u32 type);
#ifdef __KERNEL__
/* bmap to userspace formatter - copy to user & advance pointer */
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 753ed9b..bf5471b 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1141,8 +1141,57 @@ xfs_vm_page_mkwrite(
return block_page_mkwrite(vma, vmf, xfs_get_blocks);
}
+STATIC loff_t
+xfs_file_llseek(
+ struct file *file,
+ loff_t offset,
+ int origin)
+{
+ struct inode *inode = file->f_mapping->host;
+ int ret;
+
+ if (origin != SEEK_DATA && origin != SEEK_HOLE)
+ return generic_file_llseek(file, offset, origin);
+
+ mutex_lock(&inode->i_mutex);
+ switch (origin) {
+ case SEEK_DATA:
+ case SEEK_HOLE:
+ if (offset >= i_size_read(inode)) {
+ ret = -ENXIO;
+ goto error;
+ }
+
+ ret = xfs_find_desired_extent(inode, &offset, origin);
+ if (ret)
+ goto error;
+ }
+
+ if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (offset > inode->i_sb->s_maxbytes) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_version = 0;
+ }
+
+ mutex_unlock(&inode->i_mutex);
+ return offset;
+
+error:
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+}
+
const struct file_operations xfs_file_operations = {
- .llseek = generic_file_llseek,
+ .llseek = xfs_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = xfs_file_aio_read,
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 23ce927..482c1ff 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1030,6 +1030,70 @@ xfs_vn_fiemap(
return 0;
}
+int
+xfs_find_desired_extent(
+ struct inode *inode,
+ loff_t *start,
+ u32 type)
+{
+ xfs_inode_t *ip = XFS_I(inode);
+ xfs_mount_t *mp = ip->i_mount;
+ struct xfs_ifork *ifp;
+ int lock;
+ int error;
+
+ if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
+ ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
+ ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
+ return XFS_ERROR(EINVAL);
+
+ xfs_ilock(ip, XFS_IOLOCK_SHARED);
+
+ /*
+ * Flush the delay alloc blocks. Even after flushing the inode,
+ * there can still be delalloc blocks on the inode beyond EOF
+ * due to speculative preallocation. These are not removed until
+ * the release function is called or the inode is inactivated.
+ * Hence we cannot assert here that ip->i_delayed_blks == 0.
+ */
+ if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) {
+ error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF);
+ if (error)
+ goto out_unlock_iolock;
+ }
+
+ lock = xfs_ilock_map_shared(ip);
+
+ if (XFS_FORCED_SHUTDOWN(mp)) {
+ error = EIO;
+ goto out_unlock_ilock;
+ }
+
+ XFS_STATS_INC(xs_blk_mapr);
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+
+ ASSERT(ifp->if_ext_max ==
+ XFS_IFORK_SIZE(ip, XFS_DATA_FORK) / (uint)sizeof(xfs_bmbt_rec_t));
+
+ if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+ error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+ if (error)
+ goto out_unlock_ilock;
+ }
+
+ error = xfs_seek_data_hole(ip, start, type);
+
+out_unlock_ilock:
+ xfs_iunlock_map_shared(ip, lock);
+out_unlock_iolock:
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+
+ if (error)
+ return -error;
+
+ return 0;
+}
+
static const struct inode_operations xfs_inode_operations = {
.get_acl = xfs_get_acl,
.getattr = xfs_vn_getattr,
diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h
index ef41c92..ea47abd 100644
--- a/fs/xfs/xfs_iops.h
+++ b/fs/xfs/xfs_iops.h
@@ -27,4 +27,7 @@ extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
extern void xfs_setup_inode(struct xfs_inode *);
+extern int xfs_find_desired_extent(struct inode *inode, loff_t *start,
+ u32 type);
+
#endif /* __XFS_IOPS_H__ */
--
1.7.4.1
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next prev parent reply other threads:[~2011-11-19 8:37 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-02 15:04 SEEK_DATA/SEEK_HOLE support Jeff Liu
2011-10-02 15:42 ` Christoph Hellwig
2011-10-02 16:06 ` Jeff Liu
2011-10-02 17:59 ` Christoph Hellwig
2011-10-02 19:11 ` Andi Kleen
2011-10-03 4:04 ` Jeff Liu
2011-10-03 23:43 ` Dave Chinner
2011-10-04 13:02 ` Christoph Hellwig
2011-10-05 4:36 ` Dave Chinner
2011-10-05 5:32 ` Jeff Liu
2011-10-05 9:23 ` Dave Chinner
2011-10-05 13:56 ` Jeff Liu
2011-10-05 7:34 ` Michael Monnerie
2011-10-05 9:36 ` Dave Chinner
2011-10-05 18:22 ` Michael Monnerie
2011-10-06 0:32 ` Dave Chinner
2011-11-14 10:24 ` Christoph Hellwig
2011-11-14 12:47 ` Jeff Liu
2011-11-14 12:50 ` Christoph Hellwig
2011-11-19 8:29 ` XFS SEEK_DATA/SEEK_HOLE support V1 Jeff Liu
2011-11-19 8:34 ` Jeff Liu
2011-11-19 8:37 ` Jeff Liu [this message]
2011-11-19 19:11 ` [PATCH] Introduce SEEK_DATA/SEEK_HOLE support to XFS V1 Christoph Hellwig
2011-11-20 13:15 ` Jeff Liu
2011-11-20 0:30 ` Dave Chinner
2011-11-20 13:59 ` Jeff Liu
2011-11-20 15:30 ` Christoph Hellwig
2011-11-20 22:34 ` Dave Chinner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4EC76AB9.9030604@oracle.com \
--to=jeff.liu@oracle.com \
--cc=aelder@sgi.com \
--cc=chris.mason@oracle.com \
--cc=hch@infradead.org \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox