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

file.c (5030B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *	fs/bfs/file.c
      4 *	BFS file operations.
      5 *	Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com>
      6 *
      7 *	Make the file block allocation algorithm understand the size
      8 *	of the underlying block device.
      9 *	Copyright (C) 2007 Dmitri Vorobiev <dmitri.vorobiev@gmail.com>
     10 *
     11 */
     12
     13#include <linux/fs.h>
     14#include <linux/buffer_head.h>
     15#include "bfs.h"
     16
     17#undef DEBUG
     18
     19#ifdef DEBUG
     20#define dprintf(x...)	printf(x)
     21#else
     22#define dprintf(x...)
     23#endif
     24
     25const struct file_operations bfs_file_operations = {
     26	.llseek 	= generic_file_llseek,
     27	.read_iter	= generic_file_read_iter,
     28	.write_iter	= generic_file_write_iter,
     29	.mmap		= generic_file_mmap,
     30	.splice_read	= generic_file_splice_read,
     31};
     32
     33static int bfs_move_block(unsigned long from, unsigned long to,
     34					struct super_block *sb)
     35{
     36	struct buffer_head *bh, *new;
     37
     38	bh = sb_bread(sb, from);
     39	if (!bh)
     40		return -EIO;
     41	new = sb_getblk(sb, to);
     42	memcpy(new->b_data, bh->b_data, bh->b_size);
     43	mark_buffer_dirty(new);
     44	bforget(bh);
     45	brelse(new);
     46	return 0;
     47}
     48
     49static int bfs_move_blocks(struct super_block *sb, unsigned long start,
     50				unsigned long end, unsigned long where)
     51{
     52	unsigned long i;
     53
     54	dprintf("%08lx-%08lx->%08lx\n", start, end, where);
     55	for (i = start; i <= end; i++)
     56		if(bfs_move_block(i, where + i, sb)) {
     57			dprintf("failed to move block %08lx -> %08lx\n", i,
     58								where + i);
     59			return -EIO;
     60		}
     61	return 0;
     62}
     63
     64static int bfs_get_block(struct inode *inode, sector_t block,
     65			struct buffer_head *bh_result, int create)
     66{
     67	unsigned long phys;
     68	int err;
     69	struct super_block *sb = inode->i_sb;
     70	struct bfs_sb_info *info = BFS_SB(sb);
     71	struct bfs_inode_info *bi = BFS_I(inode);
     72
     73	phys = bi->i_sblock + block;
     74	if (!create) {
     75		if (phys <= bi->i_eblock) {
     76			dprintf("c=%d, b=%08lx, phys=%09lx (granted)\n",
     77                                create, (unsigned long)block, phys);
     78			map_bh(bh_result, sb, phys);
     79		}
     80		return 0;
     81	}
     82
     83	/*
     84	 * If the file is not empty and the requested block is within the
     85	 * range of blocks allocated for this file, we can grant it.
     86	 */
     87	if (bi->i_sblock && (phys <= bi->i_eblock)) {
     88		dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 
     89				create, (unsigned long)block, phys);
     90		map_bh(bh_result, sb, phys);
     91		return 0;
     92	}
     93
     94	/* The file will be extended, so let's see if there is enough space. */
     95	if (phys >= info->si_blocks)
     96		return -ENOSPC;
     97
     98	/* The rest has to be protected against itself. */
     99	mutex_lock(&info->bfs_lock);
    100
    101	/*
    102	 * If the last data block for this file is the last allocated
    103	 * block, we can extend the file trivially, without moving it
    104	 * anywhere.
    105	 */
    106	if (bi->i_eblock == info->si_lf_eblk) {
    107		dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 
    108				create, (unsigned long)block, phys);
    109		map_bh(bh_result, sb, phys);
    110		info->si_freeb -= phys - bi->i_eblock;
    111		info->si_lf_eblk = bi->i_eblock = phys;
    112		mark_inode_dirty(inode);
    113		err = 0;
    114		goto out;
    115	}
    116
    117	/* Ok, we have to move this entire file to the next free block. */
    118	phys = info->si_lf_eblk + 1;
    119	if (phys + block >= info->si_blocks) {
    120		err = -ENOSPC;
    121		goto out;
    122	}
    123
    124	if (bi->i_sblock) {
    125		err = bfs_move_blocks(inode->i_sb, bi->i_sblock, 
    126						bi->i_eblock, phys);
    127		if (err) {
    128			dprintf("failed to move ino=%08lx -> fs corruption\n",
    129								inode->i_ino);
    130			goto out;
    131		}
    132	} else
    133		err = 0;
    134
    135	dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n",
    136                create, (unsigned long)block, phys);
    137	bi->i_sblock = phys;
    138	phys += block;
    139	info->si_lf_eblk = bi->i_eblock = phys;
    140
    141	/*
    142	 * This assumes nothing can write the inode back while we are here
    143	 * and thus update inode->i_blocks! (XXX)
    144	 */
    145	info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
    146	mark_inode_dirty(inode);
    147	map_bh(bh_result, sb, phys);
    148out:
    149	mutex_unlock(&info->bfs_lock);
    150	return err;
    151}
    152
    153static int bfs_writepage(struct page *page, struct writeback_control *wbc)
    154{
    155	return block_write_full_page(page, bfs_get_block, wbc);
    156}
    157
    158static int bfs_read_folio(struct file *file, struct folio *folio)
    159{
    160	return block_read_full_folio(folio, bfs_get_block);
    161}
    162
    163static void bfs_write_failed(struct address_space *mapping, loff_t to)
    164{
    165	struct inode *inode = mapping->host;
    166
    167	if (to > inode->i_size)
    168		truncate_pagecache(inode, inode->i_size);
    169}
    170
    171static int bfs_write_begin(struct file *file, struct address_space *mapping,
    172			loff_t pos, unsigned len,
    173			struct page **pagep, void **fsdata)
    174{
    175	int ret;
    176
    177	ret = block_write_begin(mapping, pos, len, pagep, bfs_get_block);
    178	if (unlikely(ret))
    179		bfs_write_failed(mapping, pos + len);
    180
    181	return ret;
    182}
    183
    184static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
    185{
    186	return generic_block_bmap(mapping, block, bfs_get_block);
    187}
    188
    189const struct address_space_operations bfs_aops = {
    190	.dirty_folio	= block_dirty_folio,
    191	.invalidate_folio = block_invalidate_folio,
    192	.read_folio	= bfs_read_folio,
    193	.writepage	= bfs_writepage,
    194	.write_begin	= bfs_write_begin,
    195	.write_end	= generic_write_end,
    196	.bmap		= bfs_bmap,
    197};
    198
    199const struct inode_operations bfs_file_inops;