Skip to contentSkip to conversation

zonefs: Fix active zone accounting

PATCH New [email protected] 1 participant 4 messages May 5, 2023 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 14/24 zonefs: Fix active zone accounting

From: Damien Le Moal <[email protected]>

If a file zone transitions to the offline or readonly state from an active state, we must clear the zone active flag and decrement the active seq file counter. Do so in zonefs_account_active() using the new zonefs inode flags ZONEFS_ZONE_OFFLINE and ZONEFS_ZONE_READONLY. These flags are set if necessary in zonefs_check_zone_condition() based on the result of report zones operation after an IO error.

Fixes 87c9ce3ffec9 ("zonefs: Add active seq file accounting")
(cherry picked from commit db58653ce0c7cf4d155727852607106f890005c0)

Orabug: 35351356

---
 fs/zonefs/super.c  | 11 +++++++++++
 fs/zonefs/zonefs.h |  6 ++++--
 2 files changed, 15 insertions(+), 2 deletions(-)
fs/zonefs/super.c +11 -0
index 355f2da12374..0552c103fcd8 100644
@@ -40,6 +40,13 @@ static void zonefs_account_active(struct inode *inode)
 	if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
 		return;
 
+	/*
+	 * For zones that transitioned to the offline or readonly condition,
+	 * we only need to clear the active state.
+	 */
+	if (zi->i_flags & (ZONEFS_ZONE_OFFLINE | ZONEFS_ZONE_READONLY))
+		goto out;
+
 	/*
 	 * If the zone is active, that is, if it is explicitly open or
 	 * partially written, check if it was already accounted as active.
@@ -53,6 +60,7 @@ static void zonefs_account_active(struct inode *inode)
 		return;
 	}
 
+out:
 	/* The zone is not active. If it was, update the active count */
 	if (zi->i_flags & ZONEFS_ZONE_ACTIVE) {
 		zi->i_flags &= ~ZONEFS_ZONE_ACTIVE;
@@ -324,6 +332,7 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
 		inode->i_flags |= S_IMMUTABLE;
 		inode->i_mode &= ~0777;
 		zone->wp = zone->start;
+		zi->i_flags |= ZONEFS_ZONE_OFFLINE;
 		return 0;
 	case BLK_ZONE_COND_READONLY:
 		/*
@@ -342,8 +351,10 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
 			zone->cond = BLK_ZONE_COND_OFFLINE;
 			inode->i_mode &= ~0777;
 			zone->wp = zone->start;
+			zi->i_flags |= ZONEFS_ZONE_OFFLINE;
 			return 0;
 		}
+		zi->i_flags |= ZONEFS_ZONE_READONLY;
 		inode->i_mode &= ~0222;
 		return i_size_read(inode);
 	case BLK_ZONE_COND_FULL:
fs/zonefs/zonefs.h +4 -2
index 4b3de66c3233..1dbe78119ff1 100644
@@ -39,8 +39,10 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
 	return ZONEFS_ZTYPE_SEQ;
 }
 
-#define ZONEFS_ZONE_OPEN	(1 << 0)
-#define ZONEFS_ZONE_ACTIVE	(1 << 1)
+#define ZONEFS_ZONE_OPEN	(1U << 0)
+#define ZONEFS_ZONE_ACTIVE	(1U << 1)
+#define ZONEFS_ZONE_OFFLINE	(1U << 2)
+#define ZONEFS_ZONE_READONLY	(1U << 3)
 
 /*
  * In-memory inode data.
Signature · 1 line
2.31.1
#2 lore raw

PATCH 22/24 zonefs: Fix error message in zonefs_file_dio_append()

In reply to a message not in the archive

From: Damien Le Moal <[email protected]>

Since the expected write location in a sequential file is always at the end of the file (append write), when an invalid write append location is detected in zonefs_file_dio_append(), print the invalid written location instead of the expected write location.

Fixes a608da3bd730 ("zonefs: Detect append writes at invalid locations")
(cherry picked from commit 88b170088ad2c3e27086fe35769aa49f8a512564)

Orabug: 35351356

---
 fs/zonefs/file.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/zonefs/file.c +1 -1
index 82f608d57a84..5708c54cda69 100644
@@ -428,7 +428,7 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
 		if (bio->bi_iter.bi_sector != wpsector) {
 			zonefs_warn(inode->i_sb,
 				"Corrupted write pointer %llu for zone at %llu\n",
-				wpsector, z->z_sector);
+				bio->bi_iter.bi_sector, z->z_sector);
 			ret = -EIO;
 		}
 	}
Signature · 1 line
2.31.1
#3 lore raw

PATCH 23/24 zonefs: Always invalidate last cached page on append write

In reply to a message not in the archive

From: Damien Le Moal <[email protected]>

When a direct append write is executed, the append offset may correspond to the last page of a sequential file inode which might have been cached already by buffered reads, page faults with mmap-read or non-direct readahead. To ensure that the on-disk and cached data is consistant for such last cached page, make sure to always invalidate it in zonefs_file_dio_append(). If the invalidation fails, return -EBUSY to userspace to differentiate from IO errors.

This invalidation will always be a no-op when the FS block size (device zone write granularity) is equal to the page size (e.g. 4K).

Fixes 02ef12a663c7 ("zonefs: use REQ_OP_ZONE_APPEND for sync DIO")
(cherry picked from commit c1976bd8f23016d8706973908f2bb0ac0d852a8f)

Orabug: 35351356

---
 fs/zonefs/file.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
fs/zonefs/file.c +14 -0
index 5708c54cda69..49b934c98c5a 100644
@@ -382,6 +382,7 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
 	struct zonefs_zone *z = zonefs_inode_zone(inode);
 	struct block_device *bdev = inode->i_sb->s_bdev;
 	unsigned int max = bdev_max_zone_append_sectors(bdev);
+	pgoff_t start, end;
 	struct bio *bio;
 	ssize_t size = 0;
 	int nr_pages;
@@ -390,6 +391,19 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
 	max = ALIGN_DOWN(max << SECTOR_SHIFT, inode->i_sb->s_blocksize);
 	iov_iter_truncate(from, max);
 
+	/*
+	 * If the inode block size (zone write granularity) is smaller than the
+	 * page size, we may be appending data belonging to the last page of the
+	 * inode straddling inode->i_size, with that page already cached due to
+	 * a buffered read or readahead. So make sure to invalidate that page.
+	 * This will always be a no-op for the case where the block size is
+	 * equal to the page size.
+	 */
+	start = iocb->ki_pos >> PAGE_SHIFT;
+	end = (iocb->ki_pos + iov_iter_count(from) - 1) >> PAGE_SHIFT;
+	if (invalidate_inode_pages2_range(inode->i_mapping, start, end))
+		return -EBUSY;
+
 	nr_pages = iov_iter_npages(from, BIO_MAX_VECS);
 	if (!nr_pages)
 		return 0;
Signature · 1 line
2.31.1
#4 lore raw

PATCH 24/24 zonefs: Do not propagate iomap_dio_rw() ENOTBLK error to user space

In reply to a message not in the archive

From: Damien Le Moal <[email protected]>

The call to invalidate_inode_pages2_range() in __iomap_dio_rw() may fail, in which case -ENOTBLK is returned and this error code is propagated back to user space trhough iomap_dio_rw() -> zonefs_file_dio_write() return chain. This error code is fairly obscure and may confuse the user. Avoid this and be consistent with the behavior of zonefs_file_dio_append() for similar invalidate_inode_pages2_range() errors by returning -EBUSY to user space when iomap_dio_rw() returns -ENOTBLK.

Fixes 8dcc1a9d90c1 ("fs: New zonefs file system")
(cherry picked from commit 77af13ba3c7f91d91c377c7e2d122849bbc17128)

Orabug: 35351356

Conflicts:
fs/zonefs/file.c

small conflicts due to old api for iomap_dio_rw()

---
 fs/zonefs/file.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
fs/zonefs/file.c +11 -2
index 49b934c98c5a..27cd84c5e5d0 100644
@@ -583,11 +583,20 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
 		append = sync;
 	}
 
-	if (append)
+	if (append) {
 		ret = zonefs_file_dio_append(iocb, from);
-	else
+	} else {
+		/*
+		 * iomap_dio_rw() may return ENOTBLK if there was an issue with
+		 * page invalidation. Overwrite that error code with EBUSY to
+		 * be consistent with zonefs_file_dio_append() return value for
+		 * similar issues.
+		 */
 		ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
 				   &zonefs_write_dio_ops, 0, 0);
+		if (ret == -ENOTBLK)
+			ret = -EBUSY;
+	}
 
 	if (zonefs_zone_is_seq(z) &&
 	    (ret > 0 || ret == -EIOCBQUEUED)) {
Signature · 1 line
2.31.1