brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 0e69dbd Raw
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