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);
 }
 
