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.