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

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