diff usr/src/uts/common/fs/zfs/dmu.c @ 7385:f69ff8507427

6727817 ZFS assertion failure (zero length arc_buf_alloc) during NFS I/O 6734875 assertion failed: list_head(&osi->os_meta_dnode->dn_dbufs) == 0L 6728399 [f]truncate(2) to non-zero offset broken on ZFS for files < max-blocksize 6730750 pool shows disk space in used but no related files/dirs 6737329 dmu_offset_next() does not find holes
author Mark Maybee <Mark.Maybee@Sun.COM>
date Thu, 21 Aug 2008 14:27:33 -0600
parents cdba25672122
children 23915842aa09
line wrap: on
line diff
--- a/usr/src/uts/common/fs/zfs/dmu.c	Thu Aug 21 11:46:39 2008 -0700
+++ b/usr/src/uts/common/fs/zfs/dmu.c	Thu Aug 21 14:27:33 2008 -0600
@@ -368,23 +368,24 @@
 static int
 get_next_chunk(dnode_t *dn, uint64_t *offset, uint64_t limit)
 {
-	uint64_t len = limit - *offset;
+	uint64_t len = *offset - limit;
 	uint64_t chunk_len = dn->dn_datablksz * DMU_MAX_DELETEBLKCNT;
-	uint64_t dn_used;
-	int err;
+	uint64_t subchunk =
+	    dn->dn_datablksz * EPB(dn->dn_indblkshift, SPA_BLKPTRSHIFT);
 
 	ASSERT(limit <= *offset);
 
-	dn_used = dn->dn_phys->dn_used <<
-	    (dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES ? 0 : DEV_BSHIFT);
-	if (len <= chunk_len || dn_used <= chunk_len) {
+	if (len <= chunk_len) {
 		*offset = limit;
 		return (0);
 	}
 
+	ASSERT(ISP2(subchunk));
+
 	while (*offset > limit) {
-		uint64_t initial_offset = *offset;
+		uint64_t initial_offset = P2ROUNDUP(*offset, subchunk);
 		uint64_t delta;
+		int err;
 
 		/* skip over allocated data */
 		err = dnode_next_offset(dn,
@@ -395,6 +396,7 @@
 			return (err);
 
 		ASSERT3U(*offset, <=, initial_offset);
+		*offset = P2ALIGN(*offset, subchunk);
 		delta = initial_offset - *offset;
 		if (delta >= chunk_len) {
 			*offset += delta - chunk_len;
@@ -454,14 +456,15 @@
 
 		dnode_free_range(dn, start, trunc ? -1 : len, tx);
 
-		if (start == 0 && trunc && free_dnode)
+		if (start == 0 && free_dnode) {
+			ASSERT(trunc);
 			dnode_free(dn, tx);
+		}
 
 		length -= end - start;
 
 		dmu_tx_commit(tx);
 		end = start;
-		trunc = FALSE;
 	}
 	return (0);
 }