All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: linux-fsdevel@vger.kernel.org
Cc: Evgeniy Dushistov <dushistov@mail.ru>,
	"Fabio M. De Francesco" <fmdefrancesco@gmail.com>
Subject: [PATCH 12/12] clean ufs_trunc_direct() up a bit...
Date: Wed, 13 Dec 2023 03:18:27 +0000	[thread overview]
Message-ID: <20231213031827.2767531-12-viro@zeniv.linux.org.uk> (raw)
In-Reply-To: <20231213031827.2767531-1-viro@zeniv.linux.org.uk>

For short files (== no indirect blocks needed) UFS allows the last
block to be a partial one.  That creates some complications for
truncation down to "short file" lengths.  ufs_trunc_direct() is
called when we'd already made sure that new EOF is not in a hole;
nothing needs to be done if we are extending the file and in
case we are shrinking the file it needs to
	* shrink or free the old final block.
	* free all full direct blocks between the new and old EOF.
	* possibly shrink the new final block.

The logics is needlessly complicated by trying to keep all cases
handled by the same sequence of operations.
	if not shrinking
		nothing to do
	else if number of full blocks unchanged
		free the tail of possibly partial last block
	else
		free the tail of (full) new last block
		free all present (full) blocks in between
		free the (possibly partial) old last block

is easier to follow than the result of trying to unify these
cases.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/ufs/inode.c | 124 ++++++++++++++++++++++++-------------------------
 1 file changed, 60 insertions(+), 64 deletions(-)

diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index e1c736409af8..c573f444afd4 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -875,91 +875,87 @@ static inline void free_data(struct to_free *ctx, u64 from, unsigned count)
 
 #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
 
+/*
+ * used only for truncation down to direct blocks.
+ */
 static void ufs_trunc_direct(struct inode *inode)
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
+	struct super_block *sb = inode->i_sb;
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
 	void *p;
-	u64 frag1, frag2, frag3, frag4, block1, block2;
+	u64 frag1, frag4, block1, block2;
+	unsigned old_partial, new_partial, old_blocks, new_blocks;
 	struct to_free ctx = {.inode = inode};
 	unsigned i, tmp;
 
 	UFSD("ENTER: ino %lu\n", inode->i_ino);
 
-	sb = inode->i_sb;
-	uspi = UFS_SB(sb)->s_uspi;
-
 	frag1 = DIRECT_FRAGMENT;
+	// frag1 = first fragment past the new EOF
 	frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
-	frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
-	frag3 = frag4 & ~uspi->s_fpbmask;
-	block1 = block2 = 0;
-	if (frag2 > frag3) {
-		frag2 = frag4;
-		frag3 = frag4 = 0;
-	} else if (frag2 < frag3) {
-		block1 = ufs_fragstoblks (frag2);
-		block2 = ufs_fragstoblks (frag3);
-	}
-
-	UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu,"
-	     " frag3 %llu, frag4 %llu\n", inode->i_ino,
-	     (unsigned long long)frag1, (unsigned long long)frag2,
-	     (unsigned long long)block1, (unsigned long long)block2,
-	     (unsigned long long)frag3, (unsigned long long)frag4);
-
-	if (frag1 >= frag2)
-		goto next1;
+	// frag4 = first fragment past the old EOF or covered by indirects
 
-	/*
-	 * Free first free fragments
-	 */
-	p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1));
-	tmp = ufs_data_ptr_to_cpu(sb, p);
-	if (!tmp )
-		ufs_panic (sb, "ufs_trunc_direct", "internal error");
-	frag2 -= frag1;
-	frag1 = ufs_fragnum (frag1);
+	if (frag1 >= frag4)	 // expanding - nothing to free
+		goto next3;
 
-	ufs_free_fragments(inode, tmp + frag1, frag2);
+	old_partial = ufs_fragnum(frag4);
+	old_blocks = ufs_fragstoblks(frag4);
+	new_partial = ufs_fragnum(frag1);
+	new_blocks = ufs_fragstoblks(frag1);
 
-next1:
-	/*
-	 * Free whole blocks
-	 */
-	for (i = block1 ; i < block2; i++) {
-		p = ufs_get_direct_data_ptr(uspi, ufsi, i);
+	if (old_blocks == new_blocks) {
+		p = ufs_get_direct_data_ptr(uspi, ufsi, new_blocks);
 		tmp = ufs_data_ptr_to_cpu(sb, p);
 		if (!tmp)
-			continue;
-		write_seqlock(&ufsi->meta_lock);
-		ufs_data_ptr_clear(uspi, p);
-		write_sequnlock(&ufsi->meta_lock);
+			ufs_panic (sb, "ufs_trunc_direct", "internal error");
+		if (!new_partial) {
+			write_seqlock(&ufsi->meta_lock);
+			ufs_data_ptr_clear(uspi, p);
+			write_sequnlock(&ufsi->meta_lock);
+		}
+		ufs_free_fragments(inode, tmp + new_partial,
+			old_partial - new_partial);
+	} else {
+		block1 = new_blocks;
+		block2 = old_partial ? old_blocks-1 : old_blocks;
+
+		if (new_partial) {
+			p = ufs_get_direct_data_ptr(uspi, ufsi, new_blocks);
+			tmp = ufs_data_ptr_to_cpu(sb, p);
+			if (!tmp)
+				ufs_panic (sb, "ufs_trunc_direct", "internal error");
+			ufs_free_fragments(inode, tmp + new_partial,
+						uspi->s_fpb - new_partial);
+			block1++;
+		}
+		for (i = block1 ; i < block2; i++) {
+			p = ufs_get_direct_data_ptr(uspi, ufsi, i);
+			tmp = ufs_data_ptr_to_cpu(sb, p);
+			if (!tmp)
+				continue;
+			write_seqlock(&ufsi->meta_lock);
+			ufs_data_ptr_clear(uspi, p);
+			write_sequnlock(&ufsi->meta_lock);
 
-		free_data(&ctx, tmp, uspi->s_fpb);
-	}
+			free_data(&ctx, tmp, uspi->s_fpb);
+		}
 
-	free_data(&ctx, 0, 0);
+		free_data(&ctx, 0, 0);
 
-	if (frag3 >= frag4)
-		goto next3;
+		if (old_partial) {
+			p = ufs_get_direct_data_ptr(uspi, ufsi, old_blocks);
+			tmp = ufs_data_ptr_to_cpu(sb, p);
+			if (!tmp)
+				ufs_panic(sb, "ufs_truncate_direct", "internal error");
+			write_seqlock(&ufsi->meta_lock);
+			ufs_data_ptr_clear(uspi, p);
+			write_sequnlock(&ufsi->meta_lock);
 
-	/*
-	 * Free last free fragments
-	 */
-	p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3));
-	tmp = ufs_data_ptr_to_cpu(sb, p);
-	if (!tmp )
-		ufs_panic(sb, "ufs_truncate_direct", "internal error");
-	frag4 = ufs_fragnum (frag4);
-	write_seqlock(&ufsi->meta_lock);
-	ufs_data_ptr_clear(uspi, p);
-	write_sequnlock(&ufsi->meta_lock);
-
-	ufs_free_fragments (inode, tmp, frag4);
+			ufs_free_fragments(inode, tmp, old_partial);
+		}
+	}
  next3:
-
 	UFSD("EXIT: ino %lu\n", inode->i_ino);
 }
 
-- 
2.39.2


  parent reply	other threads:[~2023-12-13  3:18 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-13  3:16 [patches][cft] ufs stuff Al Viro
2023-12-13  3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
2023-12-13  3:18   ` [PATCH 02/12] fs/ufs: Change the signature of ufs_get_page() Al Viro
2023-12-13  3:18   ` [PATCH 03/12] fs/ufs: Use ufs_put_page() in ufs_rename() Al Viro
2023-12-13  3:18   ` [PATCH 04/12] fs/ufs: Replace kmap() with kmap_local_page() Al Viro
2023-12-13  3:18   ` [PATCH 05/12] ufs: fix handling of delete_entry and set_link failures Al Viro
2023-12-13  3:18   ` [PATCH 06/12] ufs: untangle ubh_...block...() macros, part 1 Al Viro
2023-12-13  3:18   ` [PATCH 07/12] ufs: untangle ubh_...block...(), part 2 Al Viro
2023-12-13  3:18   ` [PATCH 08/12] ufs: untangle ubh_...block...(), part 3 Al Viro
2023-12-13  3:18   ` [PATCH 09/12] ufs_clusteracct(): switch to passing fragment number Al Viro
2023-12-13  3:18   ` [PATCH 10/12] ufs_inode_getfrag(): remove junk comment Al Viro
2023-12-13  3:18   ` [PATCH 11/12] ufs: get rid of ubh_{ubhcpymem,memcpyubh}() Al Viro
2023-12-13  3:18   ` Al Viro [this message]
2023-12-13  6:53 ` [patches][cft] ufs stuff Al Viro

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=20231213031827.2767531-12-viro@zeniv.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=dushistov@mail.ru \
    --cc=fmdefrancesco@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    /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.