//
// $Header: D:/ext2-os2/vfs/RCS/buffer.c,v 1.16 1995/08/16 17:30:01 Willm Exp Willm $
//
// Linux ext2 file system driver for OS/2 2.x and WARP - Allows OS/2 to
// access your Linux ext2fs partitions as normal drive letters.
// OS/2 implementation : Copyright (C) 1995 Matthieu WILLM
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// This is a REWRITE of bread(), brelse() ...
#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h> // From the "Developer Connection Device Driver Kit" version 2.0
#include <fsd.h>
#include <fsh.h>
#ifdef FS_CHECK_BUFS
#include <stdio.h>
#endif
#include <os2/types.h>
#include <os2/errors.h>
#include <linux/fs.h>
#include <linux/fs_proto.h>
#include <os2/os2proto.h>
#include <os2/log.h> /* Prototypes des fonctions de log.c */
#include <linux/sched.h>
#include <linux/locks.h>
#include <os2/volume.h>
void __wait_on_buffer(struct buffer_head * bh)
{
#ifdef FS_TRACE_LOCKS
kernel_printf("wait_on_buffer(%lu)", &(bh->b_wait));
#endif
cli();
while (bh->b_lock) {
FS_DevHelp_ProcBlock((unsigned long)(&(bh->b_wait)));
cli();
}
sti();
}
#ifdef FS_CHECK_BUFS
void checkbuffers(struct super_block * p_volume) {
struct buffer_head * bh;
unsigned long i;
char msg[256];
i = 0;
for (bh = p_volume->usedbuffers; bh != 0; bh = bh->pnext) {
if (bh->status != STATUS_FILEBUF_USED) {
sprintf(msg, "PANIC in ext2-os2.ifs : %d in used buf list but not marked used\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh->b_count == 0) {
sprintf(msg, "PANIC in ext2-os2.ifs : %d in used buf list use count = 0\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh->pprevious != 0) {
if (bh->pprevious->pnext != bh) {
sprintf(msg, "PANIC in ext2-os2 : block %d in used buf list bh->pprevious->pnext != bh\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
} else {
if (i != 0) {
sprintf(msg, "PANIC in ext2-os2 : block %d in used buf list bh->pprevious = 0 but i != 0\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh != p_volume->usedbuffers) {
sprintf(msg, "PANIC in ext2-os2 : block %d in used buf list bh->pprevious = 0 but bh != p_volume->usedbuffers\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
}
if (bh->pnext != 0) {
if (bh->pnext->pprevious != bh) {
sprintf(msg, "PANIC in ext2-os2 : block %d in used buf list bh->pnext->pprevious != bh\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
} else {
if (i != p_volume->nusedbufs - 1) {
sprintf(msg, "PANIC in ext2-os2 : block %d in used buf list bh->pnext = 0 but i != p_volume->nusedbufs - 1\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
}
i++;
}
if (i != p_volume->nusedbufs) {
sprintf(msg, "PANIC in ext2-os2 : found %d used bufs - should have been %d\n", i, p_volume->nusedbufs);
FSH_INTERR(msg, strlen(msg));
}
i = 0;
for (bh = p_volume->LRU_freebuffers; bh != 0; bh = bh->pnext) {
if (bh->status != STATUS_FILEBUF_FREE) {
sprintf(msg, "PANIC in ext2-os2.ifs : %d in free buf list but not marked free\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh->b_count != 0) {
sprintf(msg, "PANIC in ext2-os2.ifs : %d in free buf list but use count != 0\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh->pprevious != 0) {
if (bh->pprevious->pnext != bh) {
sprintf(msg, "PANIC in ext2-os2 : block %d in free buf list bh->pprevious->pnext != bh\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
} else {
if (i != 0) {
sprintf(msg, "PANIC in ext2-os2 : block %d in free buf list bh->pprevious = 0 but i != 0\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh != p_volume->LRU_freebuffers) {
sprintf(msg, "PANIC in ext2-os2 : block %d in free buf list bh->pprevious = 0 but bh != p_volume->LRU_freebuffers\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
}
if (bh->pnext != 0) {
if (bh->pnext->pprevious != bh) {
sprintf(msg, "PANIC in ext2-os2 : block %d in free buf list bh->pnext->pprevious != bh\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
} else {
if (i != p_volume->nfreebufs - 1) {
sprintf(msg, "PANIC in ext2-os2 : block %d in free buf list bh->pnext = 0 but i != p_volume->nfreebufs - 1\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
if (bh != p_volume->MRU_freebuffers) {
sprintf(msg, "PANIC in ext2-os2 : block %d in free buf list bh->pnext = 0 but bh != p_volume->MRU_freebuffers\n", bh->b_blocknr);
FSH_INTERR(msg, strlen(msg));
}
}
i++;
}
if (i != p_volume->nfreebufs) {
sprintf(msg, "PANIC in ext2-os2 : found %d free bufs - should have been %d\n", i, p_volume->nfreebufs);
FSH_INTERR(msg, strlen(msg));
}
}
#endif
unsigned long cache_size = 256L * 1024L; // Default cache size is 256 Kb
//
// Initialization of the per volume disk cache. For the moment it is a simple LRU list
//
int init_bufs(struct super_block * p_volume) {
UINT32 nbufs;
UINT32 i;
pchar pTmp[32];
UINT32 nsegs;
unsigned long cache;
//
// WARNING !!!!!!!! We *MUST AVOID* buffers to reach segment boundaries, because many routines
// in ext2/namei.c (ext2_add_entry perticularly) do some pointer arithmetics that don't work
// in a 16:16 memory model
//
cache = ((cache_size + 65536 - p_volume->block_size -1) / (65536 - p_volume->block_size))* (65536 - p_volume->block_size);
nbufs = cache / p_volume->block_size;
nsegs = cache / (65536 - p_volume->block_size);
if (nbufs * sizeof(struct buffer_head) > 65536) {
nbufs = 65536 / sizeof(struct buffer_head);
}
kernel_printf("\tinit_bufs() - Allocating %lu buffers", nbufs);
kernel_printf("\tinit_bufs() - (max nr of buffers is %lu", 65536 / sizeof(struct buffer_head));
p_volume->nbufs = nbufs;
p_volume->nfreebufs = nbufs;
p_volume->nusedbufs = 0;
for (i = 0 ; i < nsegs ; i++) {
if ((pTmp[i] = G_malloc(65536 - p_volume->block_size)) == 0) {
kernel_printf("init_bufs() - Error in G_malloc");
while (i > 0) {
i--;
G_free(pTmp[i]);
}
return ERROR_NOT_ENOUGH_MEMORY;
} /* end if */
p_volume->GDTsels[i + p_volume->nb_allocated_sel] = (UINT32)pTmp[i];
}
p_volume->nb_allocated_sel += (int)nsegs;
if ((p_volume->LRU_freebuffers = (struct buffer_head *)G_malloc(nbufs * sizeof(struct buffer_head))) == 0) {
kernel_printf("init_bufs() - Error in G_malloc");
for (i = 0 ; i < nsegs ; i++) {
G_free(pTmp[i]);
}
return ERROR_NOT_ENOUGH_MEMORY;
} /* end if */
p_volume->GDTsels[p_volume->nb_allocated_sel] = (UINT32)p_volume->LRU_freebuffers;
p_volume->nb_allocated_sel ++;
memset(p_volume->LRU_freebuffers, 0, nbufs * sizeof(struct buffer_head));
p_volume->usedbuffers = 0;
p_volume->MRU_freebuffers = p_volume->LRU_freebuffers + nbufs - 1;
for (i = 0 ; i < nbufs ; i++) {
p_volume->LRU_freebuffers[i].pnext = (i == nbufs - 1 ? 0 : &(p_volume->LRU_freebuffers[i + 1]));
p_volume->LRU_freebuffers[i].pprevious = (i == 0 ? 0 : &(p_volume->LRU_freebuffers[i - 1]));
// p_volume->LRU_freebuffers[i].b_data = pTmp + i * p_volume->block_size;
p_volume->LRU_freebuffers[i].b_data = pTmp[(i * (UINT32)(p_volume->block_size)) / (65536UL - p_volume->block_size)] + (i * (UINT32)(p_volume->block_size)) % (65536UL - p_volume->block_size);
p_volume->LRU_freebuffers[i].b_blocknr = ~0;
p_volume->LRU_freebuffers[i].b_count = 0;
p_volume->LRU_freebuffers[i].status = STATUS_FILEBUF_FREE;
p_volume->LRU_freebuffers[i].b_dirt = 0; // clean
p_volume->LRU_freebuffers[i].dev = 0;
/* FSH_SEMCLEAR(&(p_volume->LRU_freebuffers[i].b_lock)); */
p_volume->LRU_freebuffers[i].b_lock = 0;
p_volume->LRU_freebuffers[i].b_wait = 0;
}
return NO_ERROR;
}
/*****************************************************************************************/
/*** alloc_filebuf() ***/
/*** ***/
/*** Disconnects pbuf from the free buf list and connects it to the used buf list ***/
/*** ***/
/*****************************************************************************************/
struct buffer_head * alloc_filebuf0(struct super_block * p_volume, struct buffer_head * pbuf) {
struct buffer_head * curfree, * nextfree,* previousfree,* curused,* nextused, * previousused;
/*
fs_log("alloc_filebuf()");
*/
if (p_volume->nfreebufs == 0) {
fs_log("alloc_filebuf() : No more buffers");
return 0;
}
curfree = pbuf; // buffer to be taken from free buf list
curused = p_volume->usedbuffers; // beginning of used buf list
nextfree = (curfree == 0 ? 0 : curfree->pnext);
nextused = (curused == 0 ? 0 : curused->pnext);
previousfree = (curfree == 0 ? 0 : curfree->pprevious);
previousused = (curused == 0 ? 0 : curused->pprevious);
/*********************************************************/
/*** Connects buf to used buffer list and disconnects ***/
/*** it from free buffer list ***/
/*********************************************************/
p_volume->usedbuffers = curfree; /* 3 */
curfree->pnext = curused; /* 4 */
curfree->pprevious = 0; /* 6 */
if (curused != 0) {
curused->pprevious = curfree; /* 5 */
} /* endif */
if (nextfree != 0) {
nextfree->pprevious = previousfree; /* 2 */
} else {
p_volume->MRU_freebuffers = previousfree;
} /* endif */
if (previousfree != 0) {
previousfree->pnext = nextfree; /* 2 */
} else {
p_volume->LRU_freebuffers = nextfree;
} /* endif */
/*********************************************************/
p_volume->usedbuffers->status = STATUS_FILEBUF_USED;
p_volume->usedbuffers->dev = p_volume;
p_volume->nusedbufs++;
p_volume->nfreebufs--;
return p_volume->usedbuffers;
}
struct buffer_head * alloc_filebuf(struct super_block * p_volume) {
// kernel_printf("alloc_filebuf() - free = %lu - used = %lu", p_volume->nfreebufs, p_volume->nusedbufs);
return alloc_filebuf0(p_volume, p_volume->LRU_freebuffers);
}
// free_filebuf()
//
// Input
// struct super_block * p_volume : pointer to volume descriptor
// struct buffer_head * pbuf : buffer to be freed
// Output
// none
// Return value
// NO_ERROR : OK
// other : error code
//
// Disconnect a buffer from the used buffer list and connects it to the
// end of free buffer list (ie : most recently used buffers)
//
int free_filebuf(struct super_block * p_volume, struct buffer_head * pbuf) {
struct buffer_head * curfree, *nextfree, *previousfree, *curused, *nextused, *previousused;
curfree = p_volume->MRU_freebuffers;
curused = pbuf;
nextfree = 0;
nextused = (curused == 0 ? 0 : pbuf->pnext);
previousfree = (curfree == 0 ? 0 : p_volume->MRU_freebuffers->pprevious);
previousused = (curused == 0 ? 0 : pbuf->pprevious);
/*********************************************************/
/*** Connects buf to free buffer list and disconnects ***/
/*** it from used buffer list ***/
/*********************************************************/
if (curfree != 0) {
curfree->pnext = curused; // (1)
} else {
p_volume->MRU_freebuffers = curused;
p_volume->LRU_freebuffers = curused;
}
curused->pprevious = curfree; // (2)
curused->pnext = 0; // (3)
p_volume->MRU_freebuffers = curused; // (4)
if (previousused != 0) { // (5)
previousused->pnext = nextused;
} else {
p_volume->usedbuffers = nextused;
}
if (nextused != 0) { // (6)
nextused->pprevious = previousused;
}
/*********************************************************/
p_volume->MRU_freebuffers->status = STATUS_FILEBUF_FREE;
p_volume->nusedbufs--;
p_volume->nfreebufs++;
return NO_ERROR;
}
int init_hfiles(struct super_block * p_volume) {
UINT32 nhfiles;
UINT32 i;
nhfiles = 65536 / sizeof(struct file);
p_volume->nhfiles = nhfiles;
p_volume->nfreehfiles = nhfiles;
p_volume->nusedhfiles = 0;
if ((p_volume->freehfiles = (pfile)G_malloc(nhfiles * sizeof(struct file))) == 0) {
return ERROR_NOT_ENOUGH_MEMORY;
} /* end if */
p_volume->GDTsels[p_volume->nb_allocated_sel] = (UINT32)p_volume->freehfiles;
p_volume->nb_allocated_sel ++;
p_volume->usedhfiles = 0;
for (i = 0 ; i < nhfiles ; i++) {
p_volume->freehfiles[i].pnext = (i == nhfiles - 1 ? 0 : &(p_volume->freehfiles[i + 1]));
p_volume->freehfiles[i].pprevious = (i == 0 ? 0 : &(p_volume->freehfiles[i - 1]));
p_volume->freehfiles[i].status = STATUS_HFILE_FREE;
}
return NO_ERROR;
}
pfile alloc_hfile(struct super_block * p_volume) {
pfile curfree, nextfree, previousfree, curused, nextused, previousused;
/*
fs_log("alloc_hfile()");
*/
if (p_volume->nfreehfiles == 0) {
fs_log("alloc_hfile() : No more hfile");
return 0;
}
curfree = p_volume->freehfiles;
curused = p_volume->usedhfiles;
nextfree = (curfree == 0 ? 0 : p_volume->freehfiles->pnext);
nextused = (curused == 0 ? 0 : p_volume->usedhfiles->pnext);
previousfree = (curfree == 0 ? 0 : p_volume->freehfiles->pprevious);
previousused = (curused == 0 ? 0 : p_volume->usedhfiles->pprevious);
/*********************************************************/
/*** Connects buf to used buffer list and disconnects ***/
/*** it from free buffer list ***/
/*********************************************************/
p_volume->usedhfiles = curfree;
p_volume->usedhfiles->pnext = curused;
p_volume->usedhfiles->pprevious = 0;
p_volume->freehfiles = nextfree;
if (nextfree != 0) {
p_volume->freehfiles->pprevious = 0;
} /* endif */
if (curused != 0) {
curused->pprevious = curfree; /* (5) */
} /* endif */
/*********************************************************/
p_volume->usedhfiles->status = STATUS_HFILE_USED;
p_volume->nusedhfiles++;
p_volume->nfreehfiles--;
return p_volume->usedhfiles;
}
int free_hfile(struct super_block * p_volume, pfile p_file) {
pfile curfree, nextfree, previousfree, curused, nextused, previousused;
/*
fs_log("free_hfile()");
*/
curfree = p_volume->freehfiles;
curused = p_file;
nextfree = (curfree == 0 ? 0 : p_volume->freehfiles->pnext);
nextused = (curused == 0 ? 0 : p_file->pnext);
previousfree = (curfree == 0 ? 0 : p_volume->freehfiles->pprevious);
previousused = (curused == 0 ? 0 : p_file->pprevious);
/*********************************************************/
/*** Connects buf to free buffer list and disconnects ***/
/*** it from used buffer list ***/
/*********************************************************/
p_volume->freehfiles = curused;
p_volume->freehfiles->pnext = curfree;
p_volume->freehfiles->pprevious = 0;
if (previousused != 0) {
previousused->pnext = nextused;
} else {
p_volume->usedhfiles = nextused; /* (7) */
}
if (nextused != 0) {
nextused->pprevious = previousused;
}
if (curfree != 0) {
curfree->pprevious = curused; /* (6) */
}
/*********************************************************/
p_volume->freehfiles->status = STATUS_HFILE_FREE;
p_volume->nusedhfiles--;
p_volume->nfreehfiles++;
return NO_ERROR;
}
#if 0
int get_filebuf(struct super_block * p_volume, blk_t block, struct buffer_head ** ppbuf)
{
struct buffer_head * pbuf;
int rc;
rc = NO_ERROR;
pbuf = p_volume->usedbuffers; // ************** We must first verify != 0 !!! *******
while ((pbuf->b_blocknr != block) && (pbuf->pnext != 0)) {
pbuf = pbuf->pnext;
}
//
// Buffer found in used buffer list
//
if (pbuf->b_blocknr == block) {
rc = ERROR_INTERRUPT;
while (rc == ERROR_INTERRUPT) {
#ifdef FS_TRACE_LOCKS
kernel_printf("get_filebuf - waiting for used block %lu", block);
#endif
if ((rc = FSH_SEMREQUEST(&(pbuf->b_lock), TO_INFINITE)) != NO_ERROR) {
fs_err(FUNC_BREAD, FUNC_FSH_SEMREQUEST, rc, FILE_BUFMGMT_C, __LINE__);
}
}
//
// WARNING ! We must test if the block is still in use, since it could have been freed
// while we were waiting on the semaphore.
//
if (pbuf->status == STATUS_FILEBUF_USED) {
pbuf->b_count ++;
*ppbuf = pbuf;
#ifdef FS_TRACE_LOCKS
kernel_printf("get_filebuf() - block %lu locked", block);
#endif
return NO_ERROR;
} else {
FSH_SEMCLEAR(&(pbuf->b_lock));
#ifdef FS_TRACE_LOCKS
kernel_printf("get_filebuf - Unlocked used block %lu", block);
#endif
}
}
//
// Buffer not found in used buffer list
//
//
// here code to find if the block is into the cache
//
pbuf = p_volume->MRU_freebuffers;
while ((pbuf->b_blocknr != block) && (pbuf->pprevious != 0)) {
pbuf = pbuf->pprevious;
}
if (pbuf->b_blocknr == block) {
if ((pbuf = alloc_filebuf0(p_volume, pbuf)) == 0) {
fs_err(FUNC_BREAD, FUNC_ALLOC_FILEBUF, ERROR_NOT_ENOUGH_MEMORY, FILE_BUFMGMT_C, __LINE__);
return rc;
}
#ifdef FS_TRACE_LOCKS
kernel_printf("get_filebuf - Locking cache hit block %lu", block);
#endif
if ((rc = FSH_SEMSET(&(pbuf->b_lock))) != NO_ERROR) {
fs_err(FUNC_BREAD, FUNC_FSH_SEMSET, rc, FILE_BUFMGMT_C, __LINE__);
free_filebuf(p_volume, pbuf);
return rc;
}
pbuf->b_count++;
} else {
if ((pbuf = alloc_filebuf(p_volume)) == 0) {
fs_err(FUNC_BREAD, FUNC_ALLOC_FILEBUF, ERROR_NOT_ENOUGH_MEMORY, FILE_BUFMGMT_C, __LINE__);
return rc;
}
// pbuf->b_blocknr = 0;
#ifdef FS_TRACE_LOCKS
kernel_printf("get_filebuf - Locking cache miss block %lu", block);
#endif
if ((rc = FSH_SEMSET(&(pbuf->b_lock))) != NO_ERROR) {
fs_err(FUNC_BREAD, FUNC_FSH_SEMSET, rc, FILE_BUFMGMT_C, __LINE__);
free_filebuf(p_volume, pbuf);
return rc;
}
if (pbuf->b_dirt) {
ll_rw_block(WRITE, 1, &pbuf);
wait_on_buffer(pbuf);
}
pbuf->b_blocknr = block;
pbuf->b_count = 1;
pbuf->b_dirt = 0; // clean
pbuf->b_size = p_volume->block_size;
pbuf->b_uptodate = 0;
pbuf->b_dev = p_volume->s_dev; // System halt si absent
}
*ppbuf = pbuf;
return NO_ERROR;
}
#else
int get_filebuf(struct super_block * p_volume, blk_t block, struct buffer_head ** ppbuf)
{
struct buffer_head * pbuf;
int rc;
rc = NO_ERROR;
pbuf = p_volume->usedbuffers;
if (pbuf) {
while ((pbuf->b_blocknr != block) && (pbuf->pnext != 0)) {
pbuf = pbuf->pnext;
}
//
// Buffer found in used buffer list
//
if (pbuf->b_blocknr == block) {
pbuf->b_count ++;
*ppbuf = pbuf;
return NO_ERROR;
}
}
//
// Buffer not found in used buffer list
//
//
// here code to find if the block is into the cache
//
pbuf = p_volume->MRU_freebuffers;
if (!pbuf) {
kernel_printf("get_filebuf() - No more buffers !");
return ERROR_NOT_ENOUGH_MEMORY;
}
while ((pbuf->b_blocknr != block) && (pbuf->pprevious != 0)) {
pbuf = pbuf->pprevious;
}
if (pbuf->b_blocknr == block) {
if ((pbuf = alloc_filebuf0(p_volume, pbuf)) == 0) {
fs_err(FUNC_BREAD, FUNC_ALLOC_FILEBUF, ERROR_NOT_ENOUGH_MEMORY, FILE_BUFMGMT_C, __LINE__);
return rc;
}
pbuf->b_count++;
} else {
retry:
if ((pbuf = alloc_filebuf(p_volume)) == 0) {
fs_err(FUNC_BREAD, FUNC_ALLOC_FILEBUF, ERROR_NOT_ENOUGH_MEMORY, FILE_BUFMGMT_C, __LINE__);
return rc;
}
if (pbuf->b_dirt) {
ll_rw_block(WRITE, 1, &pbuf);
wait_on_buffer(pbuf);
}
if (pbuf->b_count) {
kernel_printf("The buffer %lu has been used while written !!!", pbuf->b_blocknr);
// brelse(pbuf);
goto retry;
}
pbuf->b_blocknr = block;
pbuf->b_count = 1;
pbuf->b_dirt = 0; // clean
pbuf->b_size = p_volume->block_size;
pbuf->b_uptodate = 0;
pbuf->b_dev = p_volume->s_dev; // System halt si absent
}
*ppbuf = pbuf;
return NO_ERROR;
}
#endif
int unget_filebuf(struct super_block * p_volume, struct buffer_head * pbuf) {
int rc = NO_ERROR;
if (pbuf->b_count == 0) {
kernel_printf("unget_filebuf() - WARNING bh->b_count = 0");
return NO_ERROR;
}
pbuf->b_count--;
if (pbuf->b_count == 0) {
free_filebuf(p_volume, pbuf);
}
#if 0 // No more mutex ...
#ifdef FS_TRACE_LOCKS
kernel_printf("unget_filebuf - Unlocking block %lu", pbuf->b_blocknr);
#endif
if ((rc = FSH_SEMCLEAR(&(pbuf->b_lock))) != NO_ERROR) {
kernel_printf("ERROR in unget_filebuf() - FSH_SEMCLEAR returned %d", rc);
}
#endif
return rc;
}
#if 0 // No longer used
int waitandlock_filebuf(struct buffer_head * pbuf) {
int rc = ERROR_INTERRUPT;
#ifdef FS_TRACE_LOCKS
kernel_printf("waitandlock_filebuf(%lu)", pbuf->b_blocknr);
#endif
while (rc == ERROR_INTERRUPT) {
if ((rc = FSH_SEMREQUEST(&(pbuf->b_lock), TO_INFINITE)) != NO_ERROR) {
kernel_printf("waitandlock_filebuf() - FSH_SEMREQUEST() returned %d", rc);
}
}
return rc;
}
int unlock_filebuf(struct buffer_head * pbuf) {
#ifdef FS_TRACE_LOCKS
kernel_printf("unlock_filebuf(%lu)", pbuf->b_blocknr);
#endif
return FSH_SEMCLEAR(&(pbuf->b_lock));
}
#endif
void brelse(struct buffer_head * buf)
{
if (!buf) // It's OK to try to free a NULL buffer according to
return; // brelse() in /usr/src/linux-1.2.1/fs/buffer.c
wait_on_buffer(buf);
unget_filebuf(buf->dev, buf);
#ifdef FS_CHECK_BUFS
checkbuffers(buf->dev);
#endif
}
struct buffer_head *bread(struct super_block * dev, blk_t block, fileptr_t size) {
struct buffer_head *bh;
int rc;
if (block == 0) {
kernel_printf("******* WARNING Attempt to read disk block 0");
}
if ((rc = get_filebuf(dev, block, &bh)) != NO_ERROR) {
return 0;
}
#ifdef FS_CHECK_BUFS
checkbuffers(sb);
#endif
if (bh->b_uptodate)
return bh;
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return NULL;
}
struct buffer_head *getblk(dev_t dev, blk_t block, blk_t size) {
struct buffer_head *bh;
struct super_block *sb = getvolume(dev);
int rc;
if ((rc = get_filebuf(sb, block, &bh)) != NO_ERROR) {
return NULL;
}
return bh;
}