patch-2.1.10 linux/fs/ext2/truncate.c

Next file: linux/include/asm-alpha/bitops.h
Previous file: linux/fs/ext2/super.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.9/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
@@ -11,6 +11,9 @@
  *  linux/fs/minix/truncate.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 /*
@@ -140,7 +143,7 @@
 		if (i < indirect_block)
 			goto repeat;
 		ind = i + (u32 *) ind_bh->b_data;
-		tmp = *ind;
+		tmp = le32_to_cpu(*ind);
 		if (!tmp)
 			continue;
 		bh = get_hash_table (inode->i_dev, tmp,
@@ -149,12 +152,12 @@
 			brelse (bh);
 			goto repeat;
 		}
-		if ((bh && bh->b_count != 1) || tmp != *ind) {
+		if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) {
 			retry = 1;
 			brelse (bh);
 			continue;
 		}
-		*ind = 0;
+		*ind = cpu_to_le32(0);
 		mark_buffer_dirty(ind_bh, 1);
 		bforget(bh);
 		if (free_count == 0) {
@@ -175,7 +178,7 @@
 		ext2_free_blocks (inode, block_to_free, free_count);
 	ind = (u32 *) ind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
-		if (*(ind++))
+		if (le32_to_cpu(*(ind++)))
 			break;
 	if (i >= addr_per_block)
 		if (ind_bh->b_count != 1)
@@ -195,6 +198,93 @@
 	return retry;
 }
 
+static int trunc_indirect_swab32 (struct inode * inode, int offset, u32 * p)
+{
+	int i, tmp;
+	struct buffer_head * bh;
+	struct buffer_head * ind_bh;
+	u32 * ind;
+	unsigned long block_to_free = 0;
+	unsigned long free_count = 0;
+	int retry = 0;
+	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int blocks = inode->i_sb->s_blocksize / 512;
+	int indirect_block = INDIRECT_BLOCK;
+
+	tmp = le32_to_cpu(*p);
+	if (!tmp)
+		return 0;
+	ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != le32_to_cpu(*p)) {
+		brelse (ind_bh);
+		return 1;
+	}
+	if (!ind_bh) {
+		*p = cpu_to_le32(0);
+		return 0;
+	}
+repeat:
+	for (i = indirect_block ; i < addr_per_block ; i++) {
+		if (i < 0)
+			i = 0;
+		if (i < indirect_block)
+			goto repeat;
+		ind = i + (u32 *) ind_bh->b_data;
+		tmp = le32_to_cpu(*ind);
+		if (!tmp)
+			continue;
+		bh = get_hash_table (inode->i_dev, tmp,
+				     inode->i_sb->s_blocksize);
+		if (i < indirect_block) {
+			brelse (bh);
+			goto repeat;
+		}
+		if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) {
+			retry = 1;
+			brelse (bh);
+			continue;
+		}
+		*ind = cpu_to_le32(0);
+		mark_buffer_dirty(ind_bh, 1);
+		bforget(bh);
+		if (free_count == 0) {
+			block_to_free = tmp;
+			free_count++;
+		} else if (free_count > 0 && block_to_free == tmp - free_count)
+			free_count++;
+		else {
+			ext2_free_blocks (inode, block_to_free, free_count);
+			block_to_free = tmp;
+			free_count = 1;
+		}
+/*		ext2_free_blocks (inode, tmp, 1); */
+		inode->i_blocks -= blocks;
+		inode->i_dirt = 1;
+	}
+	if (free_count > 0)
+		ext2_free_blocks (inode, block_to_free, free_count);
+	ind = (u32 *) ind_bh->b_data;
+	for (i = 0; i < addr_per_block; i++)
+		if (le32_to_cpu(*(ind++)))
+			break;
+	if (i >= addr_per_block)
+		if (ind_bh->b_count != 1)
+			retry = 1;
+		else {
+			tmp = le32_to_cpu(*p);
+			*p = cpu_to_le32(0);
+			inode->i_blocks -= blocks;
+			inode->i_dirt = 1;
+			ext2_free_blocks (inode, tmp, 1);
+		}
+	if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
+		ll_rw_block (WRITE, 1, &ind_bh);
+		wait_on_buffer (ind_bh);
+	}
+	brelse (ind_bh);
+	return retry;
+}
+
 static int trunc_dindirect (struct inode * inode, int offset,
 			    u32 * p)
 {
@@ -226,16 +316,16 @@
 		if (i < dindirect_block)
 			goto repeat;
 		dind = i + (u32 *) dind_bh->b_data;
-		tmp = *dind;
+		tmp = le32_to_cpu(*dind);
 		if (!tmp)
 			continue;
-		retry |= trunc_indirect (inode, offset + (i * addr_per_block),
-					  dind);
+		retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
+						dind);
 		mark_buffer_dirty(dind_bh, 1);
 	}
 	dind = (u32 *) dind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
-		if (*(dind++))
+		if (le32_to_cpu(*(dind++)))
 			break;
 	if (i >= addr_per_block)
 		if (dind_bh->b_count != 1)
@@ -255,6 +345,65 @@
 	return retry;
 }
 
+static int trunc_dindirect_swab32 (struct inode * inode, int offset,
+				   u32 * p)
+{
+	int i, tmp;
+	struct buffer_head * dind_bh;
+	u32 * dind;
+	int retry = 0;
+	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int blocks = inode->i_sb->s_blocksize / 512;
+	int dindirect_block = DINDIRECT_BLOCK;
+
+	tmp = le32_to_cpu(*p);
+	if (!tmp)
+		return 0;
+	dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != le32_to_cpu(*p)) {
+		brelse (dind_bh);
+		return 1;
+	}
+	if (!dind_bh) {
+		*p = cpu_to_le32(0);
+		return 0;
+	}
+repeat:
+	for (i = dindirect_block ; i < addr_per_block ; i++) {
+		if (i < 0)
+			i = 0;
+		if (i < dindirect_block)
+			goto repeat;
+		dind = i + (u32 *) dind_bh->b_data;
+		tmp = le32_to_cpu(*dind);
+		if (!tmp)
+			continue;
+		retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
+						dind);
+		mark_buffer_dirty(dind_bh, 1);
+	}
+	dind = (u32 *) dind_bh->b_data;
+	for (i = 0; i < addr_per_block; i++)
+		if (le32_to_cpu(*(dind++)))
+			break;
+	if (i >= addr_per_block)
+		if (dind_bh->b_count != 1)
+			retry = 1;
+		else {
+			tmp = le32_to_cpu(*p);
+			*p = cpu_to_le32(0);
+			inode->i_blocks -= blocks;
+			inode->i_dirt = 1;
+			ext2_free_blocks (inode, tmp, 1);
+		}
+	if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
+		ll_rw_block (WRITE, 1, &dind_bh);
+		wait_on_buffer (dind_bh);
+	}
+	brelse (dind_bh);
+	return retry;
+}
+
 static int trunc_tindirect (struct inode * inode)
 {
 	int i, tmp;
@@ -287,14 +436,14 @@
 		if (i < tindirect_block)
 			goto repeat;
 		tind = i + (u32 *) tind_bh->b_data;
-		retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
-			addr_per_block + (i + 1) * addr_per_block * addr_per_block,
-			tind);
+		retry |= trunc_dindirect_swab32(inode, EXT2_NDIR_BLOCKS +
+			 addr_per_block + (i + 1) * addr_per_block * addr_per_block,
+			 tind);
 		mark_buffer_dirty(tind_bh, 1);
 	}
 	tind = (u32 *) tind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
-		if (*(tind++))
+		if (le32_to_cpu(*(tind++)))
 			break;
 	if (i >= addr_per_block)
 		if (tind_bh->b_count != 1)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov