~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/sysv/balloc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/kernel.h>
 23 #include <linux/fs.h>
 24 #include <linux/sysv_fs.h>
 25 #include <linux/string.h>
 26 #include <linux/locks.h>
 27 
 28 /* We don't trust the value of
 29    sb->sv_sbd2->s_tfree = *sb->sv_sb_total_free_blocks
 30    but we nevertheless keep it up to date. */
 31 
 32 void sysv_free_block(struct super_block * sb, unsigned int block)
 33 {
 34         struct buffer_head * bh;
 35         char * bh_data;
 36 
 37         if (!sb) {
 38                 printk("sysv_free_block: trying to free block on nonexistent device\n");
 39                 return;
 40         }
 41         if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
 42                 printk("sysv_free_block: trying to free block not in datazone\n");
 43                 return;
 44         }
 45         lock_super(sb);
 46         if (*sb->sv_sb_flc_count > sb->sv_flc_size) {
 47                 printk("sysv_free_block: flc_count > flc_size\n");
 48                 unlock_super(sb);
 49                 return;
 50         }
 51         /* If the free list head in super-block is full, it is copied
 52          * into this block being freed:
 53          */
 54         if (*sb->sv_sb_flc_count == sb->sv_flc_size) {
 55                 u16 * flc_count;
 56                 u32 * flc_blocks;
 57 
 58                 bh = sv_getblk(sb, sb->s_dev, block);
 59                 if (!bh) {
 60                         printk("sysv_free_block: getblk() failed\n");
 61                         unlock_super(sb);
 62                         return;
 63                 }
 64                 bh_data = bh->b_data;
 65                 switch (sb->sv_type) {
 66                         case FSTYPE_XENIX:
 67                                 flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
 68                                 flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0];
 69                                 break;
 70                         case FSTYPE_SYSV4:
 71                                 flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree;
 72                                 flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0];
 73                                 break;
 74                         case FSTYPE_SYSV2:
 75                                 flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree;
 76                                 flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0];
 77                                 break;
 78                         case FSTYPE_COH:
 79                                 flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree;
 80                                 flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0];
 81                                 break;
 82                         default: panic("sysv_free_block: invalid fs type\n");
 83                 }
 84                 *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */
 85                 memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t));
 86                 mark_buffer_dirty(bh);
 87                 mark_buffer_uptodate(bh, 1);
 88                 brelse(bh);
 89                 *sb->sv_sb_flc_count = 0;
 90         } else
 91         /* If the free list head in super-block is empty, create a new head
 92          * in this block being freed:
 93          */
 94         if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */
 95                 bh = sv_getblk(sb, sb->s_dev, block);
 96                 if (!bh) {
 97                         printk("sysv_free_block: getblk() failed\n");
 98                         unlock_super(sb);
 99                         return;
100                 }
101                 memset(bh->b_data, 0, sb->sv_block_size);
102                 /* this implies ((struct ..._freelist_chunk *) bh->b_data)->flc_count = 0; */
103                 mark_buffer_dirty(bh);
104                 mark_buffer_uptodate(bh, 1);
105                 brelse(bh);
106                 /* still *sb->sv_sb_flc_count = 0 */
107         } else {
108                 /* Throw away block's contents */
109                 bh = sv_get_hash_table(sb, sb->s_dev, block);
110                 if (bh)
111                         mark_buffer_clean(bh);
112                 brelse(bh);
113         }
114         if (sb->sv_convert)
115                 block = to_coh_ulong(block);
116         sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)++] = block;
117         if (sb->sv_convert)
118                 *sb->sv_sb_total_free_blocks =
119                   to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1);
120         else
121                 *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1;
122         mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
123         if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
124         sb->s_dirt = 1; /* and needs time stamp */
125         unlock_super(sb);
126 }
127 
128 int sysv_new_block(struct super_block * sb)
129 {
130         unsigned int block;
131         struct buffer_head * bh;
132         char * bh_data;
133 
134         if (!sb) {
135                 printk("sysv_new_block: trying to get new block from nonexistent device\n");
136                 return 0;
137         }
138         lock_super(sb);
139         if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */
140                 unlock_super(sb);
141                 return 0;               /* no blocks available */
142         }
143         block = sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)-1];
144         if (sb->sv_convert)
145                 block = from_coh_ulong(block);
146         if (block == 0) { /* Applies only to Xenix FS, SystemV FS */
147                 unlock_super(sb);
148                 return 0;               /* no blocks available */
149         }
150         (*sb->sv_sb_flc_count)--;
151         if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
152                 printk("sysv_new_block: new block %d is not in data zone\n",block);
153                 unlock_super(sb);
154                 return 0;
155         }
156         if (*sb->sv_sb_flc_count == 0) { /* the last block continues the free list */
157                 u16 * flc_count;
158                 u32 * flc_blocks;
159 
160                 if (!(bh = sv_bread(sb, sb->s_dev, block))) {
161                         printk("sysv_new_block: cannot read free-list block\n");
162                         /* retry this same block next time */
163                         (*sb->sv_sb_flc_count)++;
164                         unlock_super(sb);
165                         return 0;
166                 }
167                 bh_data = bh->b_data;
168                 switch (sb->sv_type) {
169                         case FSTYPE_XENIX:
170                                 flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
171                                 flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0];
172                                 break;
173                         case FSTYPE_SYSV4:
174                                 flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree;
175                                 flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0];
176                                 break;
177                         case FSTYPE_SYSV2:
178                                 flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree;
179                                 flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0];
180                                 break;
181                         case FSTYPE_COH:
182                                 flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree;
183                                 flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0];
184                                 break;
185                         default: panic("sysv_new_block: invalid fs type\n");
186                 }
187                 if (*flc_count > sb->sv_flc_size) {
188                         printk("sysv_new_block: free-list block with >flc_size entries\n");
189                         brelse(bh);
190                         unlock_super(sb);
191                         return 0;
192                 }
193                 *sb->sv_sb_flc_count = *flc_count;
194                 memcpy(sb->sv_sb_flc_blocks, flc_blocks, *flc_count * sizeof(sysv_zone_t));
195                 brelse(bh);
196         }
197         /* Now the free list head in the superblock is valid again. */
198         bh = sv_getblk(sb, sb->s_dev, block);
199         if (!bh) {
200                 printk("sysv_new_block: getblk() failed\n");
201                 unlock_super(sb);
202                 return 0;
203         }
204         if (atomic_read(&bh->b_count) != 1) {
205                 printk("sysv_new_block: block already in use\n");
206                 unlock_super(sb);
207                 return 0;
208         }
209         memset(bh->b_data, 0, sb->sv_block_size);
210         mark_buffer_dirty(bh);
211         mark_buffer_uptodate(bh, 1);
212         brelse(bh);
213         if (sb->sv_convert)
214                 *sb->sv_sb_total_free_blocks =
215                   to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1);
216         else
217                 *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1;
218         mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
219         if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
220         sb->s_dirt = 1; /* and needs time stamp */
221         unlock_super(sb);
222         return block;
223 }
224 
225 unsigned long sysv_count_free_blocks(struct super_block * sb)
226 {
227 #if 1 /* test */
228         int count, old_count;
229         unsigned int block;
230         struct buffer_head * bh;
231         char * bh_data;
232         int i;
233 
234         /* this causes a lot of disk traffic ... */
235         count = 0;
236         lock_super(sb);
237         if (*sb->sv_sb_flc_count > 0) {
238                 for (i = *sb->sv_sb_flc_count ; /* i > 0 */ ; ) {
239                         block = sb->sv_sb_flc_blocks[--i];
240                         if (sb->sv_convert)
241                                 block = from_coh_ulong(block);
242                         if (block == 0) /* block 0 terminates list */
243                                 goto done;
244                         count++;
245                         if (i == 0)
246                                 break;
247                 }
248                 /* block = sb->sv_sb_flc_blocks[0], the last block continues the free list */
249                 while (1) {
250                         u16 * flc_count;
251                         u32 * flc_blocks;
252 
253                         if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
254                                 printk("sysv_count_free_blocks: new block %d is not in data zone\n",block);
255                                 break;
256                         }
257                         if (!(bh = sv_bread(sb, sb->s_dev, block))) {
258                                 printk("sysv_count_free_blocks: cannot read free-list block\n");
259                                 break;
260                         }
261                         bh_data = bh->b_data;
262                         switch (sb->sv_type) {
263                                 case FSTYPE_XENIX:
264                                         flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
265                                         flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0];
266                                         break;
267                                 case FSTYPE_SYSV4:
268                                         flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree;
269                                         flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0];
270                                         break;
271                                 case FSTYPE_SYSV2:
272                                         flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree;
273                                         flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0];
274                                         break;
275                                 case FSTYPE_COH:
276                                         flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree;
277                                         flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0];
278                                         break;
279                                 default: panic("sysv_count_free_blocks: invalid fs type\n");
280                         }
281                         if (*flc_count > sb->sv_flc_size) {
282                                 printk("sysv_count_free_blocks: free-list block with >flc_size entries\n");
283                                 brelse(bh);
284                                 break;
285                         }
286                         if (*flc_count == 0) { /* Applies only to Coherent FS */
287                                 brelse(bh);
288                                 break;
289                         }
290                         for (i = *flc_count ; /* i > 0 */ ; ) {
291                                 block = flc_blocks[--i];
292                                 if (sb->sv_convert)
293                                         block = from_coh_ulong(block);
294                                 if (block == 0) /* block 0 terminates list */
295                                         break;
296                                 count++;
297                                 if (i == 0)
298                                         break;
299                         }
300                         /* block = flc_blocks[0], the last block continues the free list */
301                         brelse(bh);
302                         if (block == 0) /* Applies only to Xenix FS and SystemV FS */
303                                 break;
304                 }
305                 done: ;
306         }
307         old_count = *sb->sv_sb_total_free_blocks;
308         if (sb->sv_convert)
309                 old_count = from_coh_ulong(old_count);
310         if (count != old_count) {
311                 printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count);
312                 if (!(sb->s_flags & MS_RDONLY)) {
313                         *sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count);
314                         mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */
315                         sb->s_dirt = 1; /* and needs time stamp */
316                 }
317         }
318         unlock_super(sb);
319         return count;
320 #else
321         int count;
322 
323         count = *sb->sv_sb_total_free_blocks;
324         if (sb->sv_convert)
325                 count = from_coh_ulong(count);
326         return count;
327 #endif
328 }
329 
330 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.