ftp.nice.ch/pub/next/unix/disk/vmount.0.6a.s.tar.gz#/vmount.0.6a.s/buffers.c

This is buffers.c in view mode; [Download] [Up]

/*
 * Name: buffers.c
 * Description: Functions for buffering disk blocks and inodes.
 * Author: Christian Starkjohann <cs@hal.kph.tuwien.ac.at>
 * Date: 1996-11-14
 * Copyright: GNU-GPL
 * Tabsize: 4
 */

#include <linux/fs.h>
#include <linux/sched.h>
#include "my_defines.h"
#include "cache.h"

/* ------------------------------------------------------------------------- */

extern void	bzero(void *block, int size);

/* ------------------------------------------------------------------------- */

#define	DPRINTF(arg)	if(debug_mode & DEBUG_BUFFERS)	dprintf arg

#define	BLOCKBUFFER_CNT		103
#define	INODEBUFFER_CNT		15

/* ------------------------------------------------------------------------- */

extern void	*malloc(unsigned long size);
extern void	*realloc(void *prev, unsigned long newsize);
extern void	free(void *p);

/* ------------------------------------------------------------------------- */

static struct buffer_head	block_buffer[BLOCKBUFFER_CNT];
static struct inode			inode_buffer[INODEBUFFER_CNT];

/* ------------------------------------------------------------------------- */

struct buffer_head	*getblk(kdev_t dev, int blocknr, int blocksize)
{
int					i, j;
void				*data;
struct buffer_head	*bh;

	i = blocknr;
	for(j=0;j<BLOCKBUFFER_CNT;j++,i++){		/* maybe we have the buffer */
		i %= BLOCKBUFFER_CNT;
		if(block_buffer[i].b_blocknr == blocknr
						&& block_buffer[i].b_size == blocksize){
			block_buffer[i].b_count ++;
			set_bit(BH_Touched, &block_buffer[i].b_state);
			DPRINTF(("getblk(block=%d): returning buffer %d\n", blocknr, i));
			return &block_buffer[i];
		}
	}
	i = blocknr;
	for(j=0;j<BLOCKBUFFER_CNT;j++,i++){
		i %= BLOCKBUFFER_CNT;
		if(buffer_locked(&block_buffer[i]))		/* don't use locked buffers */
			continue;
		if(!block_buffer[i].b_count){
			if(buffer_dirty(&block_buffer[i])){
				bh = &block_buffer[i];
				ll_rw_block(WRITE, 1, &bh);
			}
			data = block_buffer[i].b_data;
			if(block_buffer[i].b_size != blocksize){
				data = data ? realloc(data, blocksize) : malloc(blocksize);
			}
			DPRINTF(("getblk(block=%d): allocating buffer %d\n", blocknr, i));
			bzero(&block_buffer[i], sizeof(struct buffer_head));
			block_buffer[i].b_count = 1;
			block_buffer[i].b_flushtime = 0;
			block_buffer[i].b_state = (1<<BH_Touched);
			block_buffer[i].b_dev = dev;
			block_buffer[i].b_blocknr = blocknr;
			block_buffer[i].b_size = blocksize;
			block_buffer[i].b_data = data;
			return &block_buffer[i];
		}
	}
	panic("no free block buffers\n");
	return NULL;
}

/* ------------------------------------------------------------------------- */

struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
{
int					i, j;

	i = block;
	for(j=0;j<BLOCKBUFFER_CNT;j++,i++){		/* maybe we have the buffer */
		i %= BLOCKBUFFER_CNT;
		if(block_buffer[i].b_blocknr == block){
			if(block_buffer[i].b_size == size){
				block_buffer[i].b_count ++;
				DPRINTF(("get_hash_table(block=%d): buffered\n", block));
				return &block_buffer[i];
			}else{
				eprintf("VFS: Wrong blocksize on device (%ld / %d)\n",
											block_buffer[i].b_size, size);
				return NULL;
			}
		}
	}
	DPRINTF(("get_hash_table(block=%d): not buffered\n", block));
	return NULL;
}

/* ------------------------------------------------------------------------- */

struct buffer_head 	*bread(kdev_t dev, int block, int size)
{
struct buffer_head	*bh = getblk(dev, block, size);

	if(buffer_uptodate(bh)){
		DPRINTF(("bread(block=%d, size=%d): buffered\n", block, size));
		return bh;
	}
	DPRINTF(("bread(block=%d, size=%d): read\n", block, size));
	ll_rw_block(READ, 1, &bh);
	return bh;
}

/* ------------------------------------------------------------------------- */

struct buffer_head	*breada(kdev_t dev, int block, int bufsize,
	unsigned int pos, unsigned int filesize)
{	/* no read ahead implemented */
	return bread(dev, block, bufsize);
}

/* ------------------------------------------------------------------------- */

void	__brelse(struct buffer_head * buf)
{
	DPRINTF(("__brelse(block=%ld)\n", buf->b_blocknr));
	if (buf->b_count) {
		buf->b_count--;
		return;
	}
	eprintf("VFS: brelse: Trying to release free buffer\n");
}

/* ------------------------------------------------------------------------- */

void __bforget(struct buffer_head * buf)
{
	DPRINTF(("** someone uses bforget() .... why???"));
	mark_buffer_clean(buf);
	clear_bit(BH_Protected, &buf->b_state);
	buf->b_count = 0;
	buf->b_blocknr = -1;
}

/* ------------------------------------------------------------------------- */

void mark_buffer_uptodate(struct buffer_head *bh, int on)
{
	if (on){
		set_bit(BH_Uptodate, &bh->b_state);
	}else{
		clear_bit(BH_Uptodate, &bh->b_state);
	}
}

/* ------------------------------------------------------------------------- */

void	my_sync_blocks(void)
{
int					i;
struct buffer_head	*bh;

	for(i=0;i<BLOCKBUFFER_CNT;i++){
		if(block_buffer[i].b_data != NULL && buffer_dirty(&block_buffer[i])){
			bh = &block_buffer[i];
			ll_rw_block(WRITE, 1, &bh);
			clear_bit(BH_Dirty, &block_buffer[i].b_state);
		}
	}
	cache_sync();
}

/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */

static inline struct inode	*find_inode(int ino)
{
int		i, j;

	i = ino;
	for(j=0;j<INODEBUFFER_CNT;j++,i++){
		i %= INODEBUFFER_CNT;
		if(inode_buffer[i].i_ino == ino){
			DPRINTF(("find_inode(ino=%d): found in buffer %d\n", ino, i));
			return &inode_buffer[i];
		}
	}
	DPRINTF(("find_inode(ino=%d): not found\n", ino));
	return NULL;
}

/* ------------------------------------------------------------------------- */

struct inode	*get_empty_inode(void)
{
int			i, released = -1, j;
static int	ino = 0, start = 0;

	j = start++;
	for(i=0;i<INODEBUFFER_CNT;i++,j++){
		j %= INODEBUFFER_CNT;
		if(inode_buffer[j].i_count <= 0){
			released = j;
			if(!inode_buffer[j].i_dirt)
				break;
		}
	}
	if(i >= INODEBUFFER_CNT){
		if(released < 0){
			panic("no free inode buffers\n");
			return NULL;
		}
		i = released;
	}else{
		i = j;
	}
	if (inode_buffer[i].i_dirt) {
		if (!inode_buffer[i].i_sb || !inode_buffer[i].i_sb->s_op
								|| !inode_buffer[i].i_sb->s_op->write_inode) {
			inode_buffer[i].i_dirt = 0;
		}else{
			inode_buffer[i].i_sb->s_op->write_inode(&inode_buffer[i]);
		}
	}
	bzero(&inode_buffer[i], sizeof(struct inode));
	inode_buffer[i].i_count = 1;
	inode_buffer[i].i_nlink = 1;
	inode_buffer[i].i_version = ++event;
	inode_buffer[i].i_sem.count = 1;
	inode_buffer[i].i_ino = ++ino;
	inode_buffer[i].i_dev = 0;
	inode_buffer[i].i_mode = 0777;
	DPRINTF(("get_empty_inode(): using buffer %d\n", i));
	return &inode_buffer[i];
}

/* ------------------------------------------------------------------------- */

void	clear_inode(struct inode *inode)
{
	bzero(inode, sizeof(struct inode));
}

/* ------------------------------------------------------------------------- */

struct inode	*__iget(struct super_block *sb, int nr, int crossmntp)
{
struct inode	*inode;

	DPRINTF(("__iget(ino=%d)\n", nr));
	if (!sb)
		panic("VFS: iget with sb==NULL");
	if((inode = find_inode(nr)) == NULL){
		inode = get_empty_inode();
		inode->i_sb = sb;
		inode->i_dev = sb->s_dev;
		inode->i_ino = nr;
		inode->i_flags = sb->s_flags;
		if (inode->i_sb->s_op && inode->i_sb->s_op->read_inode)
			inode->i_sb->s_op->read_inode(inode);
	}else{
		inode->i_count++;
	}
	return inode;
}

/* ------------------------------------------------------------------------- */

void iput(struct inode * inode)
{
	if (!inode)
		return;
	if (!inode->i_count) {
		eprintf("** iput(): trying to release free inode %ld\n", inode->i_ino);
		return;
	}

	DPRINTF(("iput(ino=%ld)\n", inode->i_ino));
	inode->i_count--;
	if(inode->i_count > 0) {
		return;
	}
	inode->i_count = 0;

	if(inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
		inode->i_count++;	/* operations require retained inode */
		inode->i_sb->s_op->put_inode(inode);
		inode->i_count = 0;
		if (!inode->i_nlink)
			return;
	}
	if(!inode->i_dirt)
		return;
	if(!inode->i_sb || !inode->i_sb->s_op || !inode->i_sb->s_op->write_inode){
		inode->i_dirt = 0;
		return;
	}
	inode->i_count++;	/* operations require retained inode */
	inode->i_sb->s_op->write_inode(inode);
	inode->i_count = 0;
}

/* ------------------------------------------------------------------------- */

void	my_sync_inodes(void)
{
int		i;

	for(i=0;i<INODEBUFFER_CNT;i++){
		if(inode_buffer[i].i_op != NULL && inode_buffer[i].i_dirt){
			if(inode_buffer[i].i_sb && inode_buffer[i].i_sb->s_op
					&& inode_buffer[i].i_sb->s_op->write_inode)
				(inode_buffer[i].i_sb->s_op->write_inode)(&inode_buffer[i]);
			inode_buffer[i].i_dirt = 0;
		}
	}
}

/* ------------------------------------------------------------------------- */

void set_writetime(struct buffer_head * buf, int flag)
{
}

/* ------------------------------------------------------------------------- */

void	buffer_regular(void)
{
}

/* ------------------------------------------------------------------------- */

void	buffer_invalidate(void)
{
int		i;

	for(i=0;i<BLOCKBUFFER_CNT;i++){
		if(block_buffer[i].b_data != NULL)
			free(block_buffer[i].b_data);
	}
	bzero(block_buffer, sizeof(block_buffer));
	bzero(inode_buffer, sizeof(inode_buffer));
}

/* ------------------------------------------------------------------------- */

void	buffer_initialize(int use_small_buffer)
{
	cache_init_buffers(use_small_buffer);
}

/* ------------------------------------------------------------------------- */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.