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