root/fs/sysv/balloc.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sysv_free_block
  2. sysv_new_block
  3. sysv_count_free_blocks

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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                 unsigned short * flc_count;
  56                 unsigned long * 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, 1);
  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, 1);
 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, 1); /* super-block has been modified */
 123         if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 124         sb->s_dirt = 1; /* and needs time stamp */
 125         unlock_super(sb);
 126 }
 127 
 128 int sysv_new_block(struct super_block * sb)
     /* [previous][next][first][last][top][bottom][index][help] */
 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                 unsigned short * flc_count;
 158                 unsigned long * 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 (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, 1);
 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, 1); /* super-block has been modified */
 219         if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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                         unsigned short * flc_count;
 251                         unsigned long * 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, 1); /* 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 

/* [previous][next][first][last][top][bottom][index][help] */