root/fs/sysv/balloc.c

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

DEFINITIONS

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

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