File: /usr/src/linux/fs/sysv/balloc.c

1     /*
2      *  linux/fs/sysv/balloc.c
3      *
4      *  minix/bitmap.c
5      *  Copyright (C) 1991, 1992  Linus Torvalds
6      *
7      *  ext/freelists.c
8      *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
9      *
10      *  xenix/alloc.c
11      *  Copyright (C) 1992  Doug Evans
12      *
13      *  coh/alloc.c
14      *  Copyright (C) 1993  Pascal Haible, Bruno Haible
15      *
16      *  sysv/balloc.c
17      *  Copyright (C) 1993  Bruno Haible
18      *
19      *  This file contains code for allocating/freeing blocks.
20      */
21     
22     #include <linux/fs.h>
23     #include <linux/sysv_fs.h>
24     #include <linux/locks.h>
25     
26     /* We don't trust the value of
27        sb->sv_sbd2->s_tfree = *sb->sv_free_blocks
28        but we nevertheless keep it up to date. */
29     
30     static inline u32 *get_chunk(struct super_block *sb, struct buffer_head *bh)
31     {
32     	char *bh_data = bh->b_data;
33     
34     	if (sb->sv_type == FSTYPE_SYSV4)
35     		return (u32*)(bh_data+4);
36     	else
37     		return (u32*)(bh_data+2);
38     }
39     
40     /* NOTE NOTE NOTE: nr is a block number _as_ _stored_ _on_ _disk_ */
41     
42     void sysv_free_block(struct super_block * sb, u32 nr)
43     {
44     	struct buffer_head * bh;
45     	u32 *blocks = sb->sv_bcache;
46     	unsigned count;
47     	unsigned block = fs32_to_cpu(sb, nr);
48     
49     	/*
50     	 * This code does not work at all for AFS (it has a bitmap
51     	 * free list).  As AFS is supposed to be read-only no one
52     	 * should call this for an AFS filesystem anyway...
53     	 */
54     	if (sb->sv_type == FSTYPE_AFS)
55     		return;
56     
57     	if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
58     		printk("sysv_free_block: trying to free block not in datazone\n");
59     		return;
60     	}
61     
62     	lock_super(sb);
63     	count = fs16_to_cpu(sb, *sb->sv_bcache_count);
64     
65     	if (count > sb->sv_flc_size) {
66     		printk("sysv_free_block: flc_count > flc_size\n");
67     		unlock_super(sb);
68     		return;
69     	}
70     	/* If the free list head in super-block is full, it is copied
71     	 * into this block being freed, ditto if it's completely empty
72     	 * (applies only on Coherent).
73     	 */
74     	if (count == sb->sv_flc_size || count == 0) {
75     		block += sb->sv_block_base;
76     		bh = getblk(sb->s_dev, block, sb->s_blocksize);
77     		if (!bh) {
78     			printk("sysv_free_block: getblk() failed\n");
79     			unlock_super(sb);
80     			return;
81     		}
82     		memset(bh->b_data, 0, sb->s_blocksize);
83     		*(u16*)bh->b_data = cpu_to_fs16(sb, count);
84     		memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t));
85     		mark_buffer_dirty(bh);
86     		mark_buffer_uptodate(bh, 1);
87     		brelse(bh);
88     		count = 0;
89     	}
90     	sb->sv_bcache[count++] = nr;
91     
92     	*sb->sv_bcache_count = cpu_to_fs16(sb, count);
93     	fs32_add(sb, sb->sv_free_blocks, 1);
94     	dirty_sb(sb);
95     	unlock_super(sb);
96     }
97     
98     u32 sysv_new_block(struct super_block * sb)
99     {
100     	unsigned int block;
101     	u32 nr;
102     	struct buffer_head * bh;
103     	unsigned count;
104     
105     	lock_super(sb);
106     	count = fs16_to_cpu(sb, *sb->sv_bcache_count);
107     
108     	if (count == 0) /* Applies only to Coherent FS */
109     		goto Enospc;
110     	nr = sb->sv_bcache[--count];
111     	if (nr == 0)  /* Applies only to Xenix FS, SystemV FS */
112     		goto Enospc;
113     
114     	block = fs32_to_cpu(sb, nr);
115     
116     	*sb->sv_bcache_count = cpu_to_fs16(sb, count);
117     
118     	if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
119     		printk("sysv_new_block: new block %d is not in data zone\n",
120     			block);
121     		goto Enospc;
122     	}
123     
124     	if (count == 0) { /* the last block continues the free list */
125     		unsigned count;
126     
127     		block += sb->sv_block_base;
128     		if (!(bh = bread(sb->s_dev, block, sb->s_blocksize))) {
129     			printk("sysv_new_block: cannot read free-list block\n");
130     			/* retry this same block next time */
131     			*sb->sv_bcache_count = cpu_to_fs16(sb, 1);
132     			goto Enospc;
133     		}
134     		count = fs16_to_cpu(sb, *(u16*)bh->b_data);
135     		if (count > sb->sv_flc_size) {
136     			printk("sysv_new_block: free-list block with >flc_size entries\n");
137     			brelse(bh);
138     			goto Enospc;
139     		}
140     		*sb->sv_bcache_count = cpu_to_fs16(sb, count);
141     		memcpy(sb->sv_bcache, get_chunk(sb, bh),
142     				count * sizeof(sysv_zone_t));
143     		brelse(bh);
144     	}
145     	/* Now the free list head in the superblock is valid again. */
146     	fs32_add(sb, sb->sv_free_blocks, -1);
147     	dirty_sb(sb);
148     	unlock_super(sb);
149     	return nr;
150     
151     Enospc:
152     	unlock_super(sb);
153     	return 0;
154     }
155     
156     unsigned long sysv_count_free_blocks(struct super_block * sb)
157     {
158     	int sb_count;
159     	int count;
160     	struct buffer_head * bh = NULL;
161     	u32 *blocks;
162     	unsigned block;
163     	int n;
164     
165     	/*
166     	 * This code does not work at all for AFS (it has a bitmap
167     	 * free list).  As AFS is supposed to be read-only we just
168     	 * lie and say it has no free block at all.
169     	 */
170     	if (sb->sv_type == FSTYPE_AFS)
171     		return 0;
172     
173     	lock_super(sb);
174     	sb_count = fs32_to_cpu(sb, *sb->sv_free_blocks);
175     
176     	if (0)
177     		goto trust_sb;
178     
179     	/* this causes a lot of disk traffic ... */
180     	count = 0;
181     	n = fs16_to_cpu(sb, *sb->sv_bcache_count);
182     	blocks = sb->sv_bcache;
183     	while (1) {
184     		if (n > sb->sv_flc_size)
185     			goto E2big;
186     		block = 0;
187     		while (n && (block = blocks[--n]) != 0)
188     			count++;
189     		if (block == 0)
190     			break;
191     
192     		block = fs32_to_cpu(sb, block);
193     		if (bh)
194     			brelse(bh);
195     
196     		if (block < sb->sv_firstdatazone || block >= sb->sv_nzones)
197     			goto Einval;
198     		block += sb->sv_block_base;
199     		bh = bread(sb->s_dev, block, sb->s_blocksize);
200     		if (!bh)
201     			goto Eio;
202     		n = fs16_to_cpu(sb, *(u16*)bh->b_data);
203     		blocks = get_chunk(sb, bh);
204     	}
205     	if (bh)
206     		brelse(bh);
207     	if (count != sb_count)
208     		goto Ecount;
209     done:
210     	unlock_super(sb);
211     	return count;
212     
213     Einval:
214     	printk("sysv_count_free_blocks: new block %d is not in data zone\n",
215     		block);
216     	goto trust_sb;
217     Eio:
218     	printk("sysv_count_free_blocks: cannot read free-list block\n");
219     	goto trust_sb;
220     E2big:
221     	printk("sysv_count_free_blocks: >flc_size entries in free-list block\n");
222     	if (bh)
223     		brelse(bh);
224     trust_sb:
225     	count = sb_count;
226     	goto done;
227     Ecount:
228     	printk("sysv_count_free_blocks: free block count was %d, "
229     		"correcting to %d\n", sb_count, count);
230     	if (!(sb->s_flags & MS_RDONLY)) {
231     		*sb->sv_free_blocks = cpu_to_fs32(sb, count);
232     		dirty_sb(sb);
233     	}
234     	goto done;
235     }
236