home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / sysv / balloc.c next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  10.8 KB  |  350 lines

  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)
  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)
  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.         bh->b_dirt = 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.         bh->b_dirt = 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.     sb->sv_bh->b_dirt = 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)
  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.     bh->b_dirt = 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.     sb->sv_bh->b_dirt = 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)
  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.             sb->sv_bh->b_dirt = 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.  
  350.