Marc G. Fournier 896a42a5a7 From: Maurice Gittens <mgittens@david.gits.nl>
After applying the following patch there remain two
probable buffer overruns detected by Electric Fence during
the regression test.
I'll try find out what causes the remain two ones.

This patch also corrects a typo in smgr.c.
1998-04-01 15:35:33 +00:00

413 lines
9.2 KiB
C

/*-------------------------------------------------------------------------
*
* smgr.c--
* public interface routines to storage manager switch.
*
* All file system operations in POSTGRES dispatch through these
* routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.14 1998/04/01 15:35:33 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "storage/ipc.h"
#include "storage/block.h"
#include "storage/smgr.h"
#include "utils/rel.h"
#include "utils/palloc.h"
static void smgrshutdown(int dummy);
typedef struct f_smgr
{
int (*smgr_init) ();/* may be NULL */
int (*smgr_shutdown) (); /* may be NULL */
int (*smgr_create) ();
int (*smgr_unlink) ();
int (*smgr_extend) ();
int (*smgr_open) ();
int (*smgr_close) ();
int (*smgr_read) ();
int (*smgr_write) ();
int (*smgr_flush) ();
int (*smgr_blindwrt) ();
int (*smgr_nblocks) ();
int (*smgr_truncate) ();
int (*smgr_commit) (); /* may be NULL */
int (*smgr_abort) (); /* may be NULL */
} f_smgr;
/*
* The weird placement of commas in this init block is to keep the compiler
* happy, regardless of what storage managers we have (or don't have).
*/
static f_smgr smgrsw[] = {
/* magnetic disk */
{mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
mdread, mdwrite, mdflush, mdblindwrt, mdnblocks, mdtruncate,
mdcommit, mdabort},
#ifdef MAIN_MEMORY
/* main memory */
{mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose,
mmread, mmwrite, mmflush, mmblindwrt, mmnblocks, NULL,
mmcommit, mmabort},
#endif /* MAIN_MEMORY */
};
/*
* This array records which storage managers are write-once, and which
* support overwrite. A 'true' entry means that the storage manager is
* write-once. In the best of all possible worlds, there would be no
* write-once storage managers.
*/
static bool smgrwo[] = {
false, /* magnetic disk */
#ifdef MAIN_MEMORY
false, /* main memory */
#endif /* MAIN_MEMORY */
};
static int NSmgr = lengthof(smgrsw);
/*
* smgrinit(), smgrshutdown() -- Initialize or shut down all storage
* managers.
*
*/
int
smgrinit()
{
int i;
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_init)
{
if ((*(smgrsw[i].smgr_init)) () == SM_FAIL)
elog(FATAL, "initialization failed on %s", smgrout(i));
}
}
/* register the shutdown proc */
on_exitpg(smgrshutdown, 0);
return (SM_SUCCESS);
}
static void
smgrshutdown(int dummy)
{
int i;
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_shutdown)
{
if ((*(smgrsw[i].smgr_shutdown)) () == SM_FAIL)
elog(FATAL, "shutdown failed on %s", smgrout(i));
}
}
}
/*
* smgrcreate() -- Create a new relation.
*
* This routine takes a reldesc, creates the relation on the appropriate
* device, and returns a file descriptor for it.
*/
int
smgrcreate(int16 which, Relation reln)
{
int fd;
if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0)
elog(ERROR, "cannot create %s",
&(reln->rd_rel->relname.data[0]));
return (fd);
}
/*
* smgrunlink() -- Unlink a relation.
*
* The relation is removed from the store.
*/
int
smgrunlink(int16 which, Relation reln)
{
int status;
if ((status = (*(smgrsw[which].smgr_unlink)) (reln)) == SM_FAIL)
elog(ERROR, "cannot unlink %s",
&(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrextend() -- Add a new block to a file.
*
* Returns SM_SUCCESS on success; aborts the current transaction on
* failure.
*/
int
smgrextend(int16 which, Relation reln, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_extend)) (reln, buffer);
if (status == SM_FAIL)
elog(ERROR, "%s: cannot extend",
&(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgropen() -- Open a relation using a particular storage manager.
*
* Returns the fd for the open relation on success, aborts the
* transaction on failure.
*/
int
smgropen(int16 which, Relation reln)
{
int fd;
if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
elog(ERROR, "cannot open %s",
&(reln->rd_rel->relname.data[0]));
return (fd);
}
/*
* smgrclose() -- Close a relation.
*
* NOTE: mdclose frees fd vector! It may be re-used for other relation!
* reln should be flushed from cache after closing !..
* Currently, smgrclose is calling by
* relcache.c:RelationPurgeLocalRelation() only.
* It would be nice to have smgrfree(), but because of
* smgrclose is called from single place... - vadim 05/22/97
*
* Returns SM_SUCCESS on success, aborts on failure.
*/
int
smgrclose(int16 which, Relation reln)
{
if ((*(smgrsw[which].smgr_close)) (reln) == SM_FAIL)
elog(ERROR, "cannot close %s",
&(reln->rd_rel->relname.data[0]));
return (SM_SUCCESS);
}
/*
* smgrread() -- read a particular block from a relation into the supplied
* buffer.
*
* This routine is called from the buffer manager in order to
* instantiate pages in the shared buffer cache. All storage managers
* return pages in the format that POSTGRES expects. This routine
* dispatches the read. On success, it returns SM_SUCCESS. On failure,
* the current transaction is aborted.
*/
int
smgrread(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_read)) (reln, blocknum, buffer);
if (status == SM_FAIL)
elog(ERROR, "cannot read block %d of %s",
blocknum, &(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrwrite() -- Write the supplied buffer out.
*
* This is not a synchronous write -- the interface for that is
* smgrflush(). The buffer is written out via the appropriate
* storage manager. This routine returns SM_SUCCESS or aborts
* the current transaction.
*/
int
smgrwrite(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_write)) (reln, blocknum, buffer);
if (status == SM_FAIL)
elog(ERROR, "cannot write block %d of %s",
blocknum, &(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrflush() -- A synchronous smgrwrite().
*/
int
smgrflush(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_flush)) (reln, blocknum, buffer);
if (status == SM_FAIL)
elog(ERROR, "cannot flush block %d of %s to stable store",
blocknum, &(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrblindwrt() -- Write a page out blind.
*
* In some cases, we may find a page in the buffer cache that we
* can't make a reldesc for. This happens, for example, when we
* want to reuse a dirty page that was written by a transaction
* that has not yet committed, which created a new relation. In
* this case, the buffer manager will call smgrblindwrt() with
* the name and OID of the database and the relation to which the
* buffer belongs. Every storage manager must be able to force
* this page down to stable storage in this circumstance.
*/
int
smgrblindwrt(int16 which,
char *dbname,
char *relname,
Oid dbid,
Oid relid,
BlockNumber blkno,
char *buffer)
{
char *dbstr;
char *relstr;
int status;
dbstr = pstrdup(dbname);
relstr = pstrdup(relname);
status = (*(smgrsw[which].smgr_blindwrt)) (dbstr, relstr, dbid, relid,
blkno, buffer);
if (status == SM_FAIL)
elog(ERROR, "cannot write block %d of %s [%s] blind",
blkno, relstr, dbstr);
pfree(dbstr);
pfree(relstr);
return (status);
}
/*
* smgrnblocks() -- Calculate the number of POSTGRES blocks in the
* supplied relation.
*
* Returns the number of blocks on success, aborts the current
* transaction on failure.
*/
int
smgrnblocks(int16 which, Relation reln)
{
int nblocks;
if ((nblocks = (*(smgrsw[which].smgr_nblocks)) (reln)) < 0)
elog(ERROR, "cannot count blocks for %s",
&(reln->rd_rel->relname.data[0]));
return (nblocks);
}
/*
* smgrtruncate() -- Truncate supplied relation to a specified number
* of blocks
*
* Returns the number of blocks on success, aborts the current
* transaction on failure.
*/
int
smgrtruncate(int16 which, Relation reln, int nblocks)
{
int newblks;
newblks = nblocks;
if (smgrsw[which].smgr_truncate)
{
if ((newblks = (*(smgrsw[which].smgr_truncate)) (reln, nblocks)) < 0)
elog(ERROR, "cannot truncate %s to %d blocks",
&(reln->rd_rel->relname.data[0]), nblocks);
}
return (newblks);
}
/*
* smgrcommit(), smgrabort() -- Commit or abort changes made during the
* current transaction.
*/
int
smgrcommit()
{
int i;
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_commit)
{
if ((*(smgrsw[i].smgr_commit)) () == SM_FAIL)
elog(FATAL, "transaction commit failed on %s", smgrout(i));
}
}
return (SM_SUCCESS);
}
#ifdef NOT_USED
int
smgrabort()
{
int i;
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_abort)
{
if ((*(smgrsw[i].smgr_abort)) () == SM_FAIL)
elog(FATAL, "transaction abort failed on %s", smgrout(i));
}
}
return (SM_SUCCESS);
}
#endif
bool
smgriswo(int16 smgrno)
{
if (smgrno < 0 || smgrno >= NSmgr)
elog(ERROR, "illegal storage manager number %d", smgrno);
return (smgrwo[smgrno]);
}