Metropoli BBS
VIEWER: buffer.c MODE: TEXT (ASCII)
//
// $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;

}

[ RETURN TO DIRECTORY ]