patch-2.4.6 linux/fs/sysv/balloc.c

Next file: linux/fs/sysv/dir.c
Previous file: linux/fs/sysv/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/fs/sysv/balloc.c linux/fs/sysv/balloc.c
@@ -19,311 +19,201 @@
  *  This file contains code for allocating/freeing blocks.
  */
 
-#include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sysv_fs.h>
-#include <linux/string.h>
 #include <linux/locks.h>
 
 /* We don't trust the value of
-   sb->sv_sbd2->s_tfree = *sb->sv_sb_total_free_blocks
+   sb->sv_sbd2->s_tfree = *sb->sv_free_blocks
    but we nevertheless keep it up to date. */
 
-void sysv_free_block(struct super_block * sb, unsigned int block)
+static inline u32 *get_chunk(struct super_block *sb, struct buffer_head *bh)
+{
+	char *bh_data = bh->b_data;
+
+	if (sb->sv_type == FSTYPE_SYSV4)
+		return (u32*)(bh_data+4);
+	else
+		return (u32*)(bh_data+2);
+}
+
+/* NOTE NOTE NOTE: nr is a block number _as_ _stored_ _on_ _disk_ */
+
+void sysv_free_block(struct super_block * sb, u32 nr)
 {
 	struct buffer_head * bh;
-	char * bh_data;
+	u32 *blocks = sb->sv_bcache;
+	unsigned count;
+	unsigned block = fs32_to_cpu(sb, nr);
 
-	if (!sb) {
-		printk("sysv_free_block: trying to free block on nonexistent device\n");
-		return;
-	}
 	if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
 		printk("sysv_free_block: trying to free block not in datazone\n");
 		return;
 	}
+
 	lock_super(sb);
-	if (*sb->sv_sb_flc_count > sb->sv_flc_size) {
+	count = fs16_to_cpu(sb, *sb->sv_bcache_count);
+
+	if (count > sb->sv_flc_size) {
 		printk("sysv_free_block: flc_count > flc_size\n");
 		unlock_super(sb);
 		return;
 	}
 	/* If the free list head in super-block is full, it is copied
-	 * into this block being freed:
+	 * into this block being freed, ditto if it's completely empty
+	 * (applies only on Coherent).
 	 */
-	if (*sb->sv_sb_flc_count == sb->sv_flc_size) {
-		u16 * flc_count;
-		u32 * flc_blocks;
-
-		bh = sv_getblk(sb, sb->s_dev, block);
+	if (count == sb->sv_flc_size || count == 0) {
+		block += sb->sv_block_base;
+		bh = getblk(sb->s_dev, block, sb->s_blocksize);
 		if (!bh) {
 			printk("sysv_free_block: getblk() failed\n");
 			unlock_super(sb);
 			return;
 		}
-		bh_data = bh->b_data;
-		switch (sb->sv_type) {
-			case FSTYPE_XENIX:
-				flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			case FSTYPE_SYSV4:
-				flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			case FSTYPE_SYSV2:
-				flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			case FSTYPE_COH:
-				flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			default: panic("sysv_free_block: invalid fs type\n");
-		}
-		*flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */
-		memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t));
+		memset(bh->b_data, 0, sb->s_blocksize);
+		*(u16*)bh->b_data = cpu_to_fs16(sb, count);
+		memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t));
 		mark_buffer_dirty(bh);
 		mark_buffer_uptodate(bh, 1);
 		brelse(bh);
-		*sb->sv_sb_flc_count = 0;
-	} else
-	/* If the free list head in super-block is empty, create a new head
-	 * in this block being freed:
-	 */
-	if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */
-		bh = sv_getblk(sb, sb->s_dev, block);
-		if (!bh) {
-			printk("sysv_free_block: getblk() failed\n");
-			unlock_super(sb);
-			return;
-		}
-		memset(bh->b_data, 0, sb->sv_block_size);
-		/* this implies ((struct ..._freelist_chunk *) bh->b_data)->flc_count = 0; */
-		mark_buffer_dirty(bh);
-		mark_buffer_uptodate(bh, 1);
-		brelse(bh);
-		/* still *sb->sv_sb_flc_count = 0 */
-	} else {
-		/* Throw away block's contents */
-		bh = sv_get_hash_table(sb, sb->s_dev, block);
-		if (bh)
-			mark_buffer_clean(bh);
-		brelse(bh);
+		count = 0;
 	}
-	if (sb->sv_convert)
-		block = to_coh_ulong(block);
-	sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)++] = block;
-	if (sb->sv_convert)
-		*sb->sv_sb_total_free_blocks =
-		  to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1);
-	else
-		*sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1;
-	mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
-	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
-	sb->s_dirt = 1; /* and needs time stamp */
+	sb->sv_bcache[count++] = nr;
+
+	*sb->sv_bcache_count = cpu_to_fs16(sb, count);
+	fs32_add(sb, sb->sv_free_blocks, 1);
+	dirty_sb(sb);
 	unlock_super(sb);
 }
 
-int sysv_new_block(struct super_block * sb)
+u32 sysv_new_block(struct super_block * sb)
 {
 	unsigned int block;
+	u32 nr;
 	struct buffer_head * bh;
-	char * bh_data;
+	unsigned count;
 
-	if (!sb) {
-		printk("sysv_new_block: trying to get new block from nonexistent device\n");
-		return 0;
-	}
 	lock_super(sb);
-	if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */
-		unlock_super(sb);
-		return 0;		/* no blocks available */
-	}
-	block = sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)-1];
-	if (sb->sv_convert)
-		block = from_coh_ulong(block);
-	if (block == 0) { /* Applies only to Xenix FS, SystemV FS */
-		unlock_super(sb);
-		return 0;		/* no blocks available */
-	}
-	(*sb->sv_sb_flc_count)--;
+	count = fs16_to_cpu(sb, *sb->sv_bcache_count);
+
+	if (count == 0) /* Applies only to Coherent FS */
+		goto Enospc;
+	nr = sb->sv_bcache[--count];
+	if (nr == 0)  /* Applies only to Xenix FS, SystemV FS */
+		goto Enospc;
+
+	block = fs32_to_cpu(sb, nr);
+
+	*sb->sv_bcache_count = cpu_to_fs16(sb, count);
+
 	if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
-		printk("sysv_new_block: new block %d is not in data zone\n",block);
-		unlock_super(sb);
-		return 0;
+		printk("sysv_new_block: new block %d is not in data zone\n",
+			block);
+		goto Enospc;
 	}
-	if (*sb->sv_sb_flc_count == 0) { /* the last block continues the free list */
-		u16 * flc_count;
-		u32 * flc_blocks;
 
-		if (!(bh = sv_bread(sb, sb->s_dev, block))) {
+	if (count == 0) { /* the last block continues the free list */
+		unsigned count;
+
+		block += sb->sv_block_base;
+		if (!(bh = bread(sb->s_dev, block, sb->s_blocksize))) {
 			printk("sysv_new_block: cannot read free-list block\n");
 			/* retry this same block next time */
-			(*sb->sv_sb_flc_count)++;
-			unlock_super(sb);
-			return 0;
-		}
-		bh_data = bh->b_data;
-		switch (sb->sv_type) {
-			case FSTYPE_XENIX:
-				flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			case FSTYPE_SYSV4:
-				flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			case FSTYPE_SYSV2:
-				flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			case FSTYPE_COH:
-				flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree;
-				flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0];
-				break;
-			default: panic("sysv_new_block: invalid fs type\n");
+			*sb->sv_bcache_count = cpu_to_fs16(sb, 1);
+			goto Enospc;
 		}
-		if (*flc_count > sb->sv_flc_size) {
+		count = fs16_to_cpu(sb, *(u16*)bh->b_data);
+		if (count > sb->sv_flc_size) {
 			printk("sysv_new_block: free-list block with >flc_size entries\n");
 			brelse(bh);
-			unlock_super(sb);
-			return 0;
+			goto Enospc;
 		}
-		*sb->sv_sb_flc_count = *flc_count;
-		memcpy(sb->sv_sb_flc_blocks, flc_blocks, *flc_count * sizeof(sysv_zone_t));
+		*sb->sv_bcache_count = cpu_to_fs16(sb, count);
+		memcpy(sb->sv_bcache, get_chunk(sb, bh),
+				count * sizeof(sysv_zone_t));
 		brelse(bh);
 	}
 	/* Now the free list head in the superblock is valid again. */
-	bh = sv_getblk(sb, sb->s_dev, block);
-	if (!bh) {
-		printk("sysv_new_block: getblk() failed\n");
-		unlock_super(sb);
-		return 0;
-	}
-	if (atomic_read(&bh->b_count) != 1) {
-		printk("sysv_new_block: block already in use\n");
-		unlock_super(sb);
-		return 0;
-	}
-	memset(bh->b_data, 0, sb->sv_block_size);
-	mark_buffer_dirty(bh);
-	mark_buffer_uptodate(bh, 1);
-	brelse(bh);
-	if (sb->sv_convert)
-		*sb->sv_sb_total_free_blocks =
-		  to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1);
-	else
-		*sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1;
-	mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
-	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
-	sb->s_dirt = 1; /* and needs time stamp */
+	fs32_add(sb, sb->sv_free_blocks, -1);
+	dirty_sb(sb);
+	unlock_super(sb);
+	return nr;
+
+Enospc:
 	unlock_super(sb);
-	return block;
+	return 0;
 }
 
 unsigned long sysv_count_free_blocks(struct super_block * sb)
 {
-#if 1 /* test */
-	int count, old_count;
-	unsigned int block;
-	struct buffer_head * bh;
-	char * bh_data;
-	int i;
+	int sb_count;
+	int count;
+	struct buffer_head * bh = NULL;
+	u32 *blocks;
+	unsigned block;
+	int n;
+
+	lock_super(sb);
+	sb_count = fs32_to_cpu(sb, *sb->sv_free_blocks);
+
+	if (0)
+		goto trust_sb;
 
 	/* this causes a lot of disk traffic ... */
 	count = 0;
-	lock_super(sb);
-	if (*sb->sv_sb_flc_count > 0) {
-		for (i = *sb->sv_sb_flc_count ; /* i > 0 */ ; ) {
-			block = sb->sv_sb_flc_blocks[--i];
-			if (sb->sv_convert)
-				block = from_coh_ulong(block);
-			if (block == 0) /* block 0 terminates list */
-				goto done;
+	n = fs16_to_cpu(sb, *sb->sv_bcache_count);
+	blocks = sb->sv_bcache;
+	while (1) {
+		if (n > sb->sv_flc_size)
+			goto E2big;
+		block = 0;
+		while (n && (block = blocks[--n]) != 0)
 			count++;
-			if (i == 0)
-				break;
-		}
-		/* block = sb->sv_sb_flc_blocks[0], the last block continues the free list */
-		while (1) {
-			u16 * flc_count;
-			u32 * flc_blocks;
-
-			if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
-				printk("sysv_count_free_blocks: new block %d is not in data zone\n",block);
-				break;
-			}
-			if (!(bh = sv_bread(sb, sb->s_dev, block))) {
-				printk("sysv_count_free_blocks: cannot read free-list block\n");
-				break;
-			}
-			bh_data = bh->b_data;
-			switch (sb->sv_type) {
-				case FSTYPE_XENIX:
-					flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
-					flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0];
-					break;
-				case FSTYPE_SYSV4:
-					flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree;
-					flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0];
-					break;
-				case FSTYPE_SYSV2:
-					flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree;
-					flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0];
-					break;
-				case FSTYPE_COH:
-					flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree;
-					flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0];
-					break;
-				default: panic("sysv_count_free_blocks: invalid fs type\n");
-			}
-			if (*flc_count > sb->sv_flc_size) {
-				printk("sysv_count_free_blocks: free-list block with >flc_size entries\n");
-				brelse(bh);
-				break;
-			}
-			if (*flc_count == 0) { /* Applies only to Coherent FS */
-				brelse(bh);
-				break;
-			}
-			for (i = *flc_count ; /* i > 0 */ ; ) {
-				block = flc_blocks[--i];
-				if (sb->sv_convert)
-					block = from_coh_ulong(block);
-				if (block == 0) /* block 0 terminates list */
-					break;
-				count++;
-				if (i == 0)
-					break;
-			}
-			/* block = flc_blocks[0], the last block continues the free list */
+		if (block == 0)
+			break;
+
+		block = fs32_to_cpu(sb, block);
+		if (bh)
 			brelse(bh);
-			if (block == 0) /* Applies only to Xenix FS and SystemV FS */
-				break;
-		}
-		done: ;
-	}
-	old_count = *sb->sv_sb_total_free_blocks;
-	if (sb->sv_convert)
-		old_count = from_coh_ulong(old_count);
-	if (count != old_count) {
-		printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count);
-		if (!(sb->s_flags & MS_RDONLY)) {
-			*sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count);
-			mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */
-			sb->s_dirt = 1; /* and needs time stamp */
-		}
+
+		if (block < sb->sv_firstdatazone || block >= sb->sv_nzones)
+			goto Einval;
+		block += sb->sv_block_base;
+		bh = bread(sb->s_dev, block, sb->s_blocksize);
+		if (!bh)
+			goto Eio;
+		n = fs16_to_cpu(sb, *(u16*)bh->b_data);
+		blocks = get_chunk(sb, bh);
 	}
+	if (bh)
+		brelse(bh);
+	if (count != sb_count)
+		goto Ecount;
+done:
 	unlock_super(sb);
 	return count;
-#else
-	int count;
 
-	count = *sb->sv_sb_total_free_blocks;
-	if (sb->sv_convert)
-		count = from_coh_ulong(count);
-	return count;
-#endif
+Einval:
+	printk("sysv_count_free_blocks: new block %d is not in data zone\n",
+		block);
+	goto trust_sb;
+Eio:
+	printk("sysv_count_free_blocks: cannot read free-list block\n");
+	goto trust_sb;
+E2big:
+	printk("sysv_count_free_blocks: >flc_size entries in free-list block\n");
+	if (bh)
+		brelse(bh);
+trust_sb:
+	count = sb_count;
+	goto done;
+Ecount:
+	printk("sysv_count_free_blocks: free block count was %d, "
+		"correcting to %d\n", sb_count, count);
+	if (!(sb->s_flags & MS_RDONLY)) {
+		*sb->sv_free_blocks = cpu_to_fs32(sb, count);
+		dirty_sb(sb);
+	}
+	goto done;
 }
-

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)