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 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.