home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / sysv / balloc.c next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  9.8 KB  |  334 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. #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)
  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)
  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)
  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.  
  334.