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 to XFS V2
Date: Tue, 22 Nov 2011 16:19:45 +0800 [thread overview]
Message-ID: <4ECB5B21.7080508@oracle.com> (raw)
Hello,
This is the V2 attempt to add SEEK_DATA/SEEK_HOLE to XFS.
Changes:
========
1. Merge xfs_find_desired_extent() and xfs_seek_data_hole() into xfs_seek_extent(), and place it at xfs_file.c.
2. Using two different routines xfs_seek_data()/xfs_seek_hole() to handle SEEK_DATA/SEEK_HOLE requests respectively.
3. Remove some worthless result checking code from xfs_file_llseek().
4. s/xfs_mount_t/struct xfs_mount/g.
Tests:
======
In addition to the seek_test.c I have used previously, I have also done a large sparse file copy tests, it works to me.
Hope I have not made obvious stupid mistakes this time. :-P.
Any comments are appreciated!
Signed-off-by: Jie Liu <jeff.liu@oracle.com>
---
fs/xfs/xfs_file.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 187 insertions(+), 1 deletions(-)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 753ed9b..bb2be00 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1141,8 +1141,194 @@ xfs_vm_page_mkwrite(
return block_page_mkwrite(vma, vmf, xfs_get_blocks);
}
+STATIC int
+xfs_seek_data(
+ struct xfs_inode *ip,
+ loff_t *start)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp;
+ xfs_fileoff_t fsbno;
+ xfs_filblks_t len;
+ loff_t startoff = *start;
+ int error = 0;
+
+ fsbno = XFS_B_TO_FSBT(mp, *start);
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+ len = XFS_B_TO_FSB(mp, ip->i_size);
+
+ for (;;) {
+ struct xfs_bmbt_irec map[2];
+ int nmap = 2;
+ loff_t seekoff;
+
+ error = xfs_bmapi_read(ip, fsbno, len - fsbno, map, &nmap,
+ XFS_BMAPI_ENTIRE);
+ if (error)
+ break;
+
+ /* No extents at given offset, must be beyond EOF */
+ if (!nmap) {
+ error = ENXIO;
+ break;
+ }
+
+ seekoff = XFS_FSB_TO_B(mp, fsbno);
+
+ /*
+ * Hole handling for unwritten extents landed in a hole.
+ * If the next extent is a data extent, then return the
+ * start of it, otherwise we need to move the start offset
+ * and map more blocks.
+ */
+ if (map[0].br_startblock == HOLESTARTBLOCK) {
+ if (map[1].br_startblock == HOLESTARTBLOCK) {
+ fsbno = map[1].br_startoff +
+ map[1].br_blockcount;
+ } else {
+ *start = max_t(loff_t, seekoff,
+ XFS_FSB_TO_B(mp, map[1].br_startoff));
+ break;
+ }
+ }
+
+ /*
+ * Landed in an in-memory data extent or in an allocated
+ * extent.
+ */
+ if (map[0].br_startoff == DELAYSTARTBLOCK ||
+ map[0].br_state == XFS_EXT_NORM) {
+ *start = max_t(loff_t, seekoff,
+ XFS_FSB_TO_B(mp, map[0].br_startoff));
+ break;
+ }
+
+ /* return ENXIO if beyond eof */
+ if (XFS_FSB_TO_B(mp, fsbno) > ip->i_size) {
+ error = ENXIO;
+ break;
+ }
+ }
+
+ if (*start < startoff)
+ *start = startoff;
+
+ return error;
+}
+
+STATIC int
+xfs_seek_hole(
+ struct xfs_inode *ip,
+ loff_t *start)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ int error = 0;
+ loff_t seekoff = *start;
+ loff_t holeoff;
+ xfs_fileoff_t fsbno;
+
+ fsbno = XFS_B_TO_FSBT(mp, *start);
+ error = xfs_bmap_first_unused(NULL, ip, 1, &fsbno, XFS_DATA_FORK);
+ if (error)
+ return error;
+
+ holeoff = XFS_FSB_TO_B(mp, fsbno);
+ if (holeoff <= seekoff)
+ *start = seekoff;
+ else
+ *start = min_t(loff_t, holeoff, ip->i_size);
+
+ return error;
+}
+
+STATIC int
+xfs_seek_extent(
+ struct inode *inode,
+ loff_t *start,
+ u32 type)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp;
+ int lock;
+ int error = 0;
+
+ 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);
+
+ lock = xfs_ilock_map_shared(ip);
+
+ if (XFS_FORCED_SHUTDOWN(mp)) {
+ error = EIO;
+ goto out_lock;
+ }
+
+ 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_lock;
+ }
+
+ if (type == SEEK_HOLE)
+ error = xfs_seek_hole(ip, start);
+ else
+ error = xfs_seek_data(ip, start);
+
+out_lock:
+ xfs_iunlock_map_shared(ip, lock);
+
+ if (error)
+ return -error;
+
+ return 0;
+}
+
+STATIC loff_t
+xfs_file_llseek(
+ struct file *file,
+ loff_t offset,
+ int origin)
+{
+ struct inode *inode = file->f_mapping->host;
+ int ret;
+
+ switch (origin) {
+ case SEEK_END:
+ case SEEK_CUR:
+ offset = generic_file_llseek(file, offset, origin);
+ goto out;
+ case SEEK_DATA:
+ case SEEK_HOLE:
+ if (offset >= i_size_read(inode)) {
+ ret = -ENXIO;
+ goto error;
+ }
+
+ ret = xfs_seek_extent(inode, &offset, origin);
+ if (ret)
+ goto error;
+ }
+
+ if (offset != file->f_pos)
+ file->f_pos = offset;
+
+out:
+ return offset;
+
+error:
+ 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,
--
1.7.4.1
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next reply other threads:[~2011-11-22 8:20 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-22 8:19 Jeff Liu [this message]
2011-11-22 8:30 ` [PATCH] Introduce SEEK_DATA/SEEK_HOLE to XFS V2 Jeff Liu
2011-11-23 9:40 ` Christoph Hellwig
2011-11-23 14:00 ` Jeff Liu
2011-11-24 3:23 ` Dave Chinner
2011-11-24 9:02 ` Christoph Hellwig
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=4ECB5B21.7080508@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.