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

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