linux/fs/sysv/balloc.c
<<
>>
Prefs
   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/buffer_head.h>
  23#include <linux/string.h>
  24#include "sysv.h"
  25
  26/* We don't trust the value of
  27   sb->sv_sbd2->s_tfree = *sb->sv_free_blocks
  28   but we nevertheless keep it up to date. */
  29
  30static inline sysv_zone_t *get_chunk(struct super_block *sb, struct buffer_head *bh)
  31{
  32        char *bh_data = bh->b_data;
  33
  34        if (SYSV_SB(sb)->s_type == FSTYPE_SYSV4)
  35                return (sysv_zone_t*)(bh_data+4);
  36        else
  37                return (sysv_zone_t*)(bh_data+2);
  38}
  39
  40/* NOTE NOTE NOTE: nr is a block number _as_ _stored_ _on_ _disk_ */
  41
  42void sysv_free_block(struct super_block * sb, sysv_zone_t nr)
  43{
  44        struct sysv_sb_info * sbi = SYSV_SB(sb);
  45        struct buffer_head * bh;
  46        sysv_zone_t *blocks = sbi->s_bcache;
  47        unsigned count;
  48        unsigned block = fs32_to_cpu(sbi, nr);
  49
  50        /*
  51         * This code does not work at all for AFS (it has a bitmap
  52         * free list).  As AFS is supposed to be read-only no one
  53         * should call this for an AFS filesystem anyway...
  54         */
  55        if (sbi->s_type == FSTYPE_AFS)
  56                return;
  57
  58        if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
  59                printk("sysv_free_block: trying to free block not in datazone\n");
  60                return;
  61        }
  62
  63        lock_super(sb);
  64        count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
  65
  66        if (count > sbi->s_flc_size) {
  67                printk("sysv_free_block: flc_count > flc_size\n");
  68                unlock_super(sb);
  69                return;
  70        }
  71        /* If the free list head in super-block is full, it is copied
  72         * into this block being freed, ditto if it's completely empty
  73         * (applies only on Coherent).
  74         */
  75        if (count == sbi->s_flc_size || count == 0) {
  76                block += sbi->s_block_base;
  77                bh = sb_getblk(sb, block);
  78                if (!bh) {
  79                        printk("sysv_free_block: getblk() failed\n");
  80                        unlock_super(sb);
  81                        return;
  82                }
  83                memset(bh->b_data, 0, sb->s_blocksize);
  84                *(__fs16*)bh->b_data = cpu_to_fs16(sbi, count);
  85                memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t));
  86                mark_buffer_dirty(bh);
  87                set_buffer_uptodate(bh);
  88                brelse(bh);
  89                count = 0;
  90        }
  91        sbi->s_bcache[count++] = nr;
  92
  93        *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
  94        fs32_add(sbi, sbi->s_free_blocks, 1);
  95        dirty_sb(sb);
  96        unlock_super(sb);
  97}
  98
  99sysv_zone_t sysv_new_block(struct super_block * sb)
 100{
 101        struct sysv_sb_info *sbi = SYSV_SB(sb);
 102        unsigned int block;
 103        sysv_zone_t nr;
 104        struct buffer_head * bh;
 105        unsigned count;
 106
 107        lock_super(sb);
 108        count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
 109
 110        if (count == 0) /* Applies only to Coherent FS */
 111                goto Enospc;
 112        nr = sbi->s_bcache[--count];
 113        if (nr == 0)  /* Applies only to Xenix FS, SystemV FS */
 114                goto Enospc;
 115
 116        block = fs32_to_cpu(sbi, nr);
 117
 118        *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
 119
 120        if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
 121                printk("sysv_new_block: new block %d is not in data zone\n",
 122                        block);
 123                goto Enospc;
 124        }
 125
 126        if (count == 0) { /* the last block continues the free list */
 127                unsigned count;
 128
 129                block += sbi->s_block_base;
 130                if (!(bh = sb_bread(sb, block))) {
 131                        printk("sysv_new_block: cannot read free-list block\n");
 132                        /* retry this same block next time */
 133                        *sbi->s_bcache_count = cpu_to_fs16(sbi, 1);
 134                        goto Enospc;
 135                }
 136                count = fs16_to_cpu(sbi, *(__fs16*)bh->b_data);
 137                if (count > sbi->s_flc_size) {
 138                        printk("sysv_new_block: free-list block with >flc_size entries\n");
 139                        brelse(bh);
 140                        goto Enospc;
 141                }
 142                *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
 143                memcpy(sbi->s_bcache, get_chunk(sb, bh),
 144                                count * sizeof(sysv_zone_t));
 145                brelse(bh);
 146        }
 147        /* Now the free list head in the superblock is valid again. */
 148        fs32_add(sbi, sbi->s_free_blocks, -1);
 149        dirty_sb(sb);
 150        unlock_super(sb);
 151        return nr;
 152
 153Enospc:
 154        unlock_super(sb);
 155        return 0;
 156}
 157
 158unsigned long sysv_count_free_blocks(struct super_block * sb)
 159{
 160        struct sysv_sb_info * sbi = SYSV_SB(sb);
 161        int sb_count;
 162        int count;
 163        struct buffer_head * bh = NULL;
 164        sysv_zone_t *blocks;
 165        unsigned block;
 166        int n;
 167
 168        /*
 169         * This code does not work at all for AFS (it has a bitmap
 170         * free list).  As AFS is supposed to be read-only we just
 171         * lie and say it has no free block at all.
 172         */
 173        if (sbi->s_type == FSTYPE_AFS)
 174                return 0;
 175
 176        lock_super(sb);
 177        sb_count = fs32_to_cpu(sbi, *sbi->s_free_blocks);
 178
 179        if (0)
 180                goto trust_sb;
 181
 182        /* this causes a lot of disk traffic ... */
 183        count = 0;
 184        n = fs16_to_cpu(sbi, *sbi->s_bcache_count);
 185        blocks = sbi->s_bcache;
 186        while (1) {
 187                sysv_zone_t zone;
 188                if (n > sbi->s_flc_size)
 189                        goto E2big;
 190                zone = 0;
 191                while (n && (zone = blocks[--n]) != 0)
 192                        count++;
 193                if (zone == 0)
 194                        break;
 195
 196                block = fs32_to_cpu(sbi, zone);
 197                if (bh)
 198                        brelse(bh);
 199
 200                if (block < sbi->s_firstdatazone || block >= sbi->s_nzones)
 201                        goto Einval;
 202                block += sbi->s_block_base;
 203                bh = sb_bread(sb, block);
 204                if (!bh)
 205                        goto Eio;
 206                n = fs16_to_cpu(sbi, *(__fs16*)bh->b_data);
 207                blocks = get_chunk(sb, bh);
 208        }
 209        if (bh)
 210                brelse(bh);
 211        if (count != sb_count)
 212                goto Ecount;
 213done:
 214        unlock_super(sb);
 215        return count;
 216
 217Einval:
 218        printk("sysv_count_free_blocks: new block %d is not in data zone\n",
 219                block);
 220        goto trust_sb;
 221Eio:
 222        printk("sysv_count_free_blocks: cannot read free-list block\n");
 223        goto trust_sb;
 224E2big:
 225        printk("sysv_count_free_blocks: >flc_size entries in free-list block\n");
 226        if (bh)
 227                brelse(bh);
 228trust_sb:
 229        count = sb_count;
 230        goto done;
 231Ecount:
 232        printk("sysv_count_free_blocks: free block count was %d, "
 233                "correcting to %d\n", sb_count, count);
 234        if (!(sb->s_flags & MS_RDONLY)) {
 235                *sbi->s_free_blocks = cpu_to_fs32(sbi, count);
 236                dirty_sb(sb);
 237        }
 238        goto done;
 239}
 240