patch-1.3.54 linux/fs/minix/truncate.c

Next file: linux/fs/msdos/file.c
Previous file: linux/fs/minix/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.53/linux/fs/minix/truncate.c linux/fs/minix/truncate.c
@@ -2,6 +2,9 @@
  *  linux/fs/truncate.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Copyright (C) 1996  Gertjan van Wingerde (gertjan@cs.vu.nl)
+ *	Minix V2 fs support.
  */
 
 #include <linux/errno.h>
@@ -10,6 +13,11 @@
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 
+#define DIRECT_BLOCK		((inode->i_size + 1023) >> 10)
+#define INDIRECT_BLOCK(offset)	(DIRECT_BLOCK-offset)
+#define DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
+#define TINDIRECT_BLOCK(offset)	((DIRECT_BLOCK-(offset))>>9)
+
 /*
  * Truncate has the most races in the whole filesystem: coding it is
  * a pain in the a**. Especially as I don't do any locking...
@@ -23,17 +31,19 @@
  * general case (size = XXX). I hope.
  */
 
-static int trunc_direct(struct inode * inode)
+/*
+ * The functions for minix V1 fs truncation.
+ */
+static int V1_trunc_direct(struct inode * inode)
 {
 	unsigned short * p;
 	struct buffer_head * bh;
 	int i, tmp;
 	int retry = 0;
-#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
 
 repeat:
 	for (i = DIRECT_BLOCK ; i < 7 ; i++) {
-		p = i + inode->u.minix_i.i_data;
+		p = i + inode->u.minix_i.u.i1_data;
 		if (!(tmp = *p))
 			continue;
 		bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
@@ -57,14 +67,13 @@
 	return retry;
 }
 
-static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
+static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
 {
 	struct buffer_head * bh;
 	int i, tmp;
 	struct buffer_head * ind_bh;
 	unsigned short * ind;
 	int retry = 0;
-#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
 
 	tmp = *p;
 	if (!tmp)
@@ -79,17 +88,17 @@
 		return 0;
 	}
 repeat:
-	for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
+	for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
 		if (i < 0)
 			i = 0;
-		if (i < INDIRECT_BLOCK)
+		if (i < INDIRECT_BLOCK(offset))
 			goto repeat;
 		ind = i+(unsigned short *) ind_bh->b_data;
 		tmp = *ind;
 		if (!tmp)
 			continue;
 		bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
-		if (i < INDIRECT_BLOCK) {
+		if (i < INDIRECT_BLOCK(offset)) {
 			brelse(bh);
 			goto repeat;
 		}
@@ -118,16 +127,14 @@
 	brelse(ind_bh);
 	return retry;
 }
-		
-static int trunc_dindirect(struct inode * inode)
+
+static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
 {
 	int i, tmp;
 	struct buffer_head * dind_bh;
-	unsigned short * dind, * p;
+	unsigned short * dind;
 	int retry = 0;
-#define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
 
-	p = 8 + inode->u.minix_i.i_data;
 	if (!(tmp = *p))
 		return 0;
 	dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
@@ -140,13 +147,13 @@
 		return 0;
 	}
 repeat:
-	for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
+	for (i = DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
 		if (i < 0)
 			i = 0;
-		if (i < DINDIRECT_BLOCK)
+		if (i < DINDIRECT_BLOCK(offset))
 			goto repeat;
 		dind = i+(unsigned short *) dind_bh->b_data;
-		retry |= trunc_indirect(inode,7+512+(i<<9),dind);
+		retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
 		mark_buffer_dirty(dind_bh, 1);
 	}
 	dind = (unsigned short *) dind_bh->b_data;
@@ -165,8 +172,215 @@
 	brelse(dind_bh);
 	return retry;
 }
-		
-void minix_truncate(struct inode * inode)
+
+void V1_minix_truncate(struct inode * inode)
+{
+	int retry;
+
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+	     S_ISLNK(inode->i_mode)))
+		return;
+	while (1) {
+		retry = V1_trunc_direct(inode);
+		retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
+		retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
+		if (!retry)
+			break;
+		current->counter = 0;
+		schedule();
+	}
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_dirt = 1;
+}
+
+/*
+ * The functions for minix V2 fs truncation.
+ */
+static int V2_trunc_direct(struct inode * inode)
+{
+	unsigned long * p;
+	struct buffer_head * bh;
+	int i, tmp;
+	int retry = 0;
+
+repeat:
+	for (i = DIRECT_BLOCK ; i < 7 ; i++) {
+		p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
+		if (!(tmp = *p))
+			continue;
+		bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
+		if (i < DIRECT_BLOCK) {
+			brelse(bh);
+			goto repeat;
+		}
+		if ((bh && bh->b_count != 1) || tmp != *p) {
+			retry = 1;
+			brelse(bh);
+			continue;
+		}
+		*p = 0;
+		inode->i_dirt = 1;
+		if (bh) {
+			mark_buffer_clean(bh);
+			brelse(bh);
+		}
+		minix_free_block(inode->i_sb,tmp);
+	}
+	return retry;
+}
+
+static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
+{
+	struct buffer_head * bh;
+	int i, tmp;
+	struct buffer_head * ind_bh;
+	unsigned long * ind;
+	int retry = 0;
+
+	tmp = *p;
+	if (!tmp)
+		return 0;
+	ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
+	if (tmp != *p) {
+		brelse(ind_bh);
+		return 1;
+	}
+	if (!ind_bh) {
+		*p = 0;
+		return 0;
+	}
+repeat:
+	for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
+		if (i < 0)
+			i = 0;
+		if (i < INDIRECT_BLOCK(offset))
+			goto repeat;
+		ind = i+(unsigned long *) ind_bh->b_data;
+		tmp = *ind;
+		if (!tmp)
+			continue;
+		bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
+		if (i < INDIRECT_BLOCK(offset)) {
+			brelse(bh);
+			goto repeat;
+		}
+		if ((bh && bh->b_count != 1) || tmp != *ind) {
+			retry = 1;
+			brelse(bh);
+			continue;
+		}
+		*ind = 0;
+		mark_buffer_dirty(ind_bh, 1);
+		brelse(bh);
+		minix_free_block(inode->i_sb,tmp);
+	}
+	ind = (unsigned long *) ind_bh->b_data;
+	for (i = 0; i < 256; i++)
+		if (*(ind++))
+			break;
+	if (i >= 256)
+		if (ind_bh->b_count != 1)
+			retry = 1;
+		else {
+			tmp = *p;
+			*p = 0;
+			minix_free_block(inode->i_sb,tmp);
+		}
+	brelse(ind_bh);
+	return retry;
+}
+
+static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
+{
+	int i, tmp;
+	struct buffer_head * dind_bh;
+	unsigned long * dind;
+	int retry = 0;
+
+	if (!(tmp = *p))
+		return 0;
+	dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
+	if (tmp != *p) {
+		brelse(dind_bh);
+		return 1;
+	}
+	if (!dind_bh) {
+		*p = 0;
+		return 0;
+	}
+repeat:
+	for (i = DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
+		if (i < 0)
+			i = 0;
+		if (i < DINDIRECT_BLOCK(offset))
+			goto repeat;
+		dind = i+(unsigned long *) dind_bh->b_data;
+		retry |= V2_trunc_indirect(inode,offset+(i<<9),dind);
+		mark_buffer_dirty(dind_bh, 1);
+	}
+	dind = (unsigned long *) dind_bh->b_data;
+	for (i = 0; i < 256; i++)
+		if (*(dind++))
+			break;
+	if (i >= 256)
+		if (dind_bh->b_count != 1)
+			retry = 1;
+		else {
+			tmp = *p;
+			*p = 0;
+			inode->i_dirt = 1;
+			minix_free_block(inode->i_sb,tmp);
+		}
+	brelse(dind_bh);
+	return retry;
+}
+
+static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
+{
+        int i, tmp;
+        struct buffer_head * tind_bh;
+        unsigned long * tind;
+        int retry = 0;
+
+        if (!(tmp = *p))
+                return 0;
+        tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
+        if (tmp != *p) {
+                brelse(tind_bh);
+                return 1;
+	}
+        if (!tind_bh) {
+                *p = 0;
+                return 0;
+	}
+repeat:
+        for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
+                if (i < 0)
+                        i = 0;
+                if (i < TINDIRECT_BLOCK(offset))
+                        goto repeat;
+                tind = i+(unsigned long *) tind_bh->b_data;
+                retry |= V2_trunc_dindirect(inode,offset+(i<<9),tind);
+                mark_buffer_dirty(tind_bh, 1);
+	}
+        tind = (unsigned long *) tind_bh->b_data;
+        for (i = 0; i < 256; i++)
+                if (*(tind++))
+                        break;
+        if (i >= 256)
+                if (tind_bh->b_count != 1)
+                        retry = 1;
+                else {
+                        tmp = *p;
+                        *p = 0;
+                        inode->i_dirt = 1;
+                        minix_free_block(inode->i_sb,tmp);
+		}
+        brelse(tind_bh);
+        return retry;
+}
+
+static void V2_minix_truncate(struct inode * inode)
 {
 	int retry;
 
@@ -174,9 +388,13 @@
 	     S_ISLNK(inode->i_mode)))
 		return;
 	while (1) {
-		retry = trunc_direct(inode);
-		retry |= trunc_indirect(inode,7,inode->u.minix_i.i_data+7);
-		retry |= trunc_dindirect(inode);
+		retry = V2_trunc_direct(inode);
+		retry |= V2_trunc_indirect(inode,7,
+			(unsigned long *) inode->u.minix_i.u.i2_data + 7);
+		retry |= V2_trunc_dindirect(inode, 7+256, 
+			(unsigned long *) inode->u.minix_i.u.i2_data + 8);
+		retry |= V2_trunc_tindirect(inode, 7+256+256*256, 
+			(unsigned long *) inode->u.minix_i.u.i2_data + 9);
 		if (!retry)
 			break;
 		current->counter = 0;
@@ -184,4 +402,15 @@
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	inode->i_dirt = 1;
+}
+
+/*
+ * The function that is called for file truncation.
+ */
+void minix_truncate(struct inode * inode)
+{
+	if (INODE_VERSION(inode) == MINIX_V1)
+		V1_minix_truncate(inode);
+	else
+		V2_minix_truncate(inode);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this