From 4c3ddd1b8634c06579a4f4e77d93584076e1c5e1 Mon Sep 17 00:00:00 2001
From: Patrick Farrell <pfarrell@whamcloud.com>
Date: Thu, 30 Nov 2023 11:54:34 -0500
Subject: [PATCH] LU-16897 tgt: note 'hole' pages

In order to do sparse reads, we must know which pages
correspond to holes, so we note this when the page is read
from disk.

Note something unusual: We store the hole information in
the lnb, which is a per-IO struct.  This means the hole
information is not present when a page is reused in cache.

So when a region with a hole is first read from disk, the
hole annotation is available for the transfer code, but if
the page cache is in use, this information is not available
on subsequent reads from the same pages.

This can't be avoided because the server does not have any
per-page private information for page cache pages (and ZFS
would not support this).

This isn't too costly for two reasons:
1. We default page cache to off on flash systems
2. Most data is only read once rather than many times in
quick succession

NB: It's not clear how we can efficiently get hole
information from ZFS so this is only for ldiskfs for now.

Signed-off-by: Patrick Farrell <pfarrell@whamcloud.com>
Change-Id: I54b1b0abeb6889163f36b315292d8b6e760d6f78
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/53297
Tested-by: Maloo <maloo@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Cyril Bordage <cbordage@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
---
 lustre/include/obd.h        | 2 ++
 lustre/osd-ldiskfs/osd_io.c | 8 ++++++++
 lustre/target/tgt_handler.c | 4 ++++
 3 files changed, 14 insertions(+)

diff --git a/lustre/include/obd.h b/lustre/include/obd.h
index 8e24a98..fc397e0 100644
--- a/lustre/include/obd.h
+++ b/lustre/include/obd.h
@@ -467,6 +467,8 @@ struct niobuf_local {
 	__u16		lnb_guard_disk:1;
 	/* separate unlock for read path to allow shared access */
 	__u16		lnb_locked:1;
+	/* this lnb corresponds to a hole in the file */
+	__u16		lnb_hole:1;
 };
 
 struct tgt_thread_big_cache {
diff --git a/lustre/osd-ldiskfs/osd_io.c b/lustre/osd-ldiskfs/osd_io.c
index 9c768d2..b3de147 100644
--- a/lustre/osd-ldiskfs/osd_io.c
+++ b/lustre/osd-ldiskfs/osd_io.c
@@ -421,6 +421,13 @@ static int osd_do_bio(struct osd_device *osd, struct inode *inode,
 			nblocks = 1;
 
 			if (blocks[block_idx + i] == 0) {  /* hole */
+				struct niobuf_local *lnb =
+					iobuf->dr_lnbs[page_idx];
+				CDEBUG(D_INODE,
+				       "hole at page_idx %d, block_idx %d, at offset %llu\n",
+				       page_idx, block_idx,
+				       lnb->lnb_file_offset);
+				lnb->lnb_hole = 1;
 				LASSERTF(iobuf->dr_rw == 0,
 					 "page_idx %u, block_idx %u, i %u,"
 					 "start_blocks: %llu, count: %llu, npages: %d\n",
@@ -537,6 +544,7 @@ static int osd_map_remote_to_local(loff_t offset, ssize_t len, int *nrpages,
 		lnb->lnb_guard_rpc = 0;
 		lnb->lnb_guard_disk = 0;
 		lnb->lnb_locked = 0;
+		lnb->lnb_hole = 0;
 
 		LASSERTF(plen <= len, "plen %u, len %lld\n", plen,
 			 (long long) len);
diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c
index c8f24db..27e33a1 100644
--- a/lustre/target/tgt_handler.c
+++ b/lustre/target/tgt_handler.c
@@ -2420,6 +2420,10 @@ int tgt_brw_read(struct tgt_session_info *tsi)
 		nob += page_rc;
 		if (page_rc != 0 && desc != NULL) { /* some data! */
 			LASSERT(local_nb[i].lnb_page != NULL);
+			CDEBUG(D_INODE,
+			       "lnb %d, at offset %llu, hole %d\n", i,
+			       local_nb[i].lnb_file_offset,
+			       local_nb[i].lnb_hole);
 			desc->bd_frag_ops->add_kiov_frag
 			  (desc, local_nb[i].lnb_page,
 			   local_nb[i].lnb_page_offset & ~PAGE_MASK,
-- 
1.8.3.1