cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

balloc.c (5879B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/fs/sysv/balloc.c
      4 *
      5 *  minix/bitmap.c
      6 *  Copyright (C) 1991, 1992  Linus Torvalds
      7 *
      8 *  ext/freelists.c
      9 *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
     10 *
     11 *  xenix/alloc.c
     12 *  Copyright (C) 1992  Doug Evans
     13 *
     14 *  coh/alloc.c
     15 *  Copyright (C) 1993  Pascal Haible, Bruno Haible
     16 *
     17 *  sysv/balloc.c
     18 *  Copyright (C) 1993  Bruno Haible
     19 *
     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 of
     28   sb->sv_sbd2->s_tfree = *sb->sv_free_blocks
     29   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	else
     38		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 bitmap
     53	 * free list).  As AFS is supposed to be read-only no one
     54	 * 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 copied
     73	 * into this block being freed, ditto if it's completely empty
     74	 * (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 bitmap
    171	 * free list).  As AFS is supposed to be read-only we just
    172	 * 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}