You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1390 lines
28 KiB
1390 lines
28 KiB
/*
|
|
* Copyright 1996, University Corporation for Atmospheric Research
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
*/
|
|
/* $Id: posixio.c,v 1.6 2005/08/29 17:54:17 andy Exp $ */
|
|
/*#define USE_CWRITE 1 *//*define to use _cwrite instead of write*/
|
|
|
|
#ifdef SGI64
|
|
#define lseek lseek64
|
|
#endif
|
|
|
|
#ifdef __PARAGON__
|
|
#include <nx.h>
|
|
static int netcdf_local_is_file_pfs = 0;
|
|
#endif
|
|
|
|
#include "ncconfig.h"
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#ifndef ENOERR
|
|
#define ENOERR 0
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#ifdef _MSC_VER /* Microsoft Compilers */
|
|
#include <io.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifndef SEEK_SET
|
|
#define SEEK_SET 0
|
|
#define SEEK_CUR 1
|
|
#define SEEK_END 2
|
|
#endif
|
|
|
|
#include "ncio.h"
|
|
#include "fbits.h"
|
|
#include "rnd.h"
|
|
|
|
/* #define INSTRUMENT 1 */
|
|
#if INSTRUMENT /* debugging */
|
|
#undef NDEBUG
|
|
#include <stdio.h>
|
|
#include "instr.h"
|
|
#endif
|
|
|
|
#undef MIN /* system may define MIN somewhere and complain */
|
|
#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
|
|
|
|
#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */
|
|
#define X_ALIGN 4
|
|
#else
|
|
#undef X_ALIGN
|
|
#endif
|
|
|
|
/*
|
|
* Define the following for debugging.
|
|
*/
|
|
/* #define ALWAYS_NC_SHARE 1 */
|
|
|
|
/* Begin OS */
|
|
#ifdef __PARAGON__
|
|
/* #define ALIGN32 32 */
|
|
#ifdef __PUMAGON__
|
|
#define POSIXIO_DEFAULT_PAGESIZE (256*1024)
|
|
#else
|
|
#define POSIXIO_DEFAULT_PAGESIZE (256*1024)
|
|
#endif
|
|
#ifndef HAVE_ST_BLKSIZE
|
|
#define HAVE_ST_BLKSIZE 1
|
|
#endif
|
|
#if defined(_SC_PAGE_SIZE)
|
|
#undef _SC_PAGE_SIZE
|
|
#endif
|
|
#endif /* __PARAGON__ */
|
|
#ifndef POSIXIO_DEFAULT_PAGESIZE
|
|
#define POSIXIO_DEFAULT_PAGESIZE 4096
|
|
#endif
|
|
/*
|
|
* What is the system pagesize?
|
|
*/
|
|
static size_t
|
|
pagesize(void)
|
|
{
|
|
/* Hmm, aren't standards great? */
|
|
#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
|
|
#define _SC_PAGESIZE _SC_PAGE_SIZE
|
|
#endif
|
|
|
|
#ifdef _SC_PAGESIZE
|
|
{
|
|
const long pgsz = sysconf(_SC_PAGESIZE);
|
|
if(pgsz > 0)
|
|
return (size_t) pgsz;
|
|
/* else, silent in the face of error */
|
|
}
|
|
#elif defined(HAVE_GETPAGESIZE)
|
|
return (size_t) getpagesize();
|
|
#endif
|
|
return (size_t) POSIXIO_DEFAULT_PAGESIZE;
|
|
}
|
|
|
|
/*
|
|
* What is the preferred I/O block size?
|
|
*/
|
|
static size_t
|
|
blksize(int fd)
|
|
{
|
|
#if defined(HAVE_ST_BLKSIZE)
|
|
struct stat sb;
|
|
if (fstat(fd, &sb) > -1)
|
|
{
|
|
#ifdef __PARAGON__
|
|
netcdf_local_is_file_pfs = 0;
|
|
if(sb.st_blksize >= 256*1024)
|
|
{
|
|
netcdf_local_is_file_pfs = 1;
|
|
}
|
|
if(sb.st_blksize < POSIXIO_DEFAULT_PAGESIZE)
|
|
{
|
|
return (size_t) POSIXIO_DEFAULT_PAGESIZE;
|
|
}
|
|
else
|
|
{
|
|
return (size_t) sb.st_blksize;
|
|
}
|
|
#else
|
|
return (size_t) sb.st_blksize;
|
|
#endif
|
|
}
|
|
/* else, silent in the face of error */
|
|
#endif
|
|
(void)fd;
|
|
return (size_t) 2 * pagesize();
|
|
}
|
|
|
|
|
|
/*
|
|
* Sortof like ftruncate, except won't make the
|
|
* file shorter.
|
|
*/
|
|
static int
|
|
fgrow(const int fd, const off_t len)
|
|
{
|
|
struct stat sb;
|
|
if (fstat(fd, &sb) < 0)
|
|
return errno;
|
|
if (len < sb.st_size)
|
|
return ENOERR;
|
|
#if defined(HAVE_FTRUNCATE)
|
|
if (ftruncate(fd, len) < 0)
|
|
return errno;
|
|
#else
|
|
{
|
|
const long dumb = 0;
|
|
/* cache current position */
|
|
const off_t pos = lseek(fd, 0, SEEK_CUR);
|
|
if(pos < 0)
|
|
return errno;
|
|
if (lseek(fd, len-sizeof(dumb), SEEK_SET) < 0)
|
|
return errno;
|
|
|
|
if(write(fd, &dumb, sizeof(dumb)) < 0)
|
|
return errno;
|
|
if (lseek(fd, pos, SEEK_SET) < 0)
|
|
return errno;
|
|
}
|
|
#endif /* HAVE_FTRUNCATE */
|
|
/* else */
|
|
return ENOERR;
|
|
}
|
|
|
|
/* End OS */
|
|
/* Begin px */
|
|
|
|
static int
|
|
px_pgout(ncio *const nciop,
|
|
off_t const offset, const size_t extent,
|
|
void *const vp, off_t *posp)
|
|
{
|
|
#ifdef X_ALIGN
|
|
assert(offset % X_ALIGN == 0);
|
|
#endif
|
|
|
|
assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));
|
|
|
|
if(*posp != offset)
|
|
{
|
|
if(lseek(nciop->fd, offset, SEEK_SET) != offset)
|
|
{
|
|
return errno;
|
|
}
|
|
*posp = offset;
|
|
}
|
|
#ifdef __PARAGON__
|
|
if(nciop->is_file_pfs == 1)
|
|
{
|
|
if(_cwrite(nciop->fd, vp, extent) != (ssize_t) extent)
|
|
{
|
|
return errno;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(write(nciop->fd, vp, extent) != (ssize_t) extent)
|
|
{
|
|
return errno;
|
|
}
|
|
}
|
|
|
|
#else
|
|
if(write(nciop->fd, vp, extent) != (ssize_t) extent)
|
|
{
|
|
return errno;
|
|
}
|
|
#endif
|
|
*posp += extent;
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
|
|
static int
|
|
px_pgin(ncio *const nciop,
|
|
off_t const offset, const size_t extent,
|
|
void *const vp, size_t *nreadp, off_t *posp)
|
|
{
|
|
int status;
|
|
ssize_t nread;
|
|
|
|
#ifdef X_ALIGN
|
|
assert(offset % X_ALIGN == 0);
|
|
assert(extent % X_ALIGN == 0);
|
|
#endif
|
|
|
|
assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));
|
|
|
|
if(*posp != offset)
|
|
{
|
|
if(lseek(nciop->fd, offset, SEEK_SET) != offset)
|
|
{
|
|
status = errno;
|
|
return status;
|
|
}
|
|
*posp = offset;
|
|
}
|
|
|
|
errno = 0;
|
|
#ifdef __PARAGON__
|
|
if(nciop->is_file_pfs == 1)
|
|
{
|
|
nread = _cread(nciop->fd, vp, extent);
|
|
}
|
|
else
|
|
{
|
|
nread = read(nciop->fd, vp, extent);
|
|
}
|
|
#else
|
|
nread = read(nciop->fd, vp, extent);
|
|
#endif
|
|
if(nread != (ssize_t) extent)
|
|
{
|
|
status = errno;
|
|
#ifdef __PARAGON__
|
|
if(status == ERDEOF){status=ENOERR;}
|
|
#endif
|
|
if(nread == -1 || status != ENOERR)
|
|
return status;
|
|
/* else it's okay we read less than asked for */
|
|
(void) memset((char *)vp + nread, 0, (ssize_t)extent - nread);
|
|
}
|
|
*nreadp = nread;
|
|
*posp += nread;
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
|
|
typedef struct ncio_px {
|
|
size_t blksz;
|
|
off_t pos;
|
|
/* buffer */
|
|
off_t bf_offset;
|
|
size_t bf_extent;
|
|
size_t bf_cnt;
|
|
void *bf_base;
|
|
int bf_rflags;
|
|
int bf_refcount;
|
|
/* chain for double buffering in px_move */
|
|
struct ncio_px *slave;
|
|
} ncio_px;
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
px_rel(ncio_px *const pxp, off_t offset, int rflags)
|
|
{
|
|
assert(pxp->bf_offset <= offset
|
|
&& offset < pxp->bf_offset + (off_t) pxp->bf_extent);
|
|
assert(pIf(fIsSet(rflags, RGN_MODIFIED),
|
|
fIsSet(pxp->bf_rflags, RGN_WRITE)));
|
|
|
|
(void)offset;
|
|
|
|
if(fIsSet(rflags, RGN_MODIFIED))
|
|
{
|
|
fSet(pxp->bf_rflags, RGN_MODIFIED);
|
|
}
|
|
pxp->bf_refcount--;
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
static int
|
|
ncio_px_rel(ncio *const nciop, off_t offset, int rflags)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
|
|
if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE))
|
|
return EPERM; /* attempt to write readonly file */
|
|
|
|
return px_rel(pxp, offset, rflags);
|
|
}
|
|
|
|
static int
|
|
px_get(ncio *const nciop, ncio_px *const pxp,
|
|
off_t offset, size_t extent,
|
|
int rflags,
|
|
void **const vpp)
|
|
{
|
|
int status = ENOERR;
|
|
|
|
const off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz);
|
|
size_t diff = (size_t)(offset - blkoffset);
|
|
size_t blkextent = _RNDUP(diff + extent, pxp->blksz);
|
|
|
|
assert(extent != 0);
|
|
assert(offset >= 0); /* sanity check */
|
|
|
|
if(2 * pxp->blksz < blkextent)
|
|
return E2BIG; /* TODO: temporary kludge */
|
|
if(pxp->bf_offset == OFF_NONE)
|
|
{
|
|
/* Uninitialized */
|
|
if(pxp->bf_base == NULL)
|
|
{
|
|
assert(pxp->bf_extent == 0);
|
|
assert(blkextent <= 2 * pxp->blksz);
|
|
#ifndef ALIGN32
|
|
pxp->bf_base = malloc(2 * pxp->blksz );
|
|
#else
|
|
pxp->bf_base = malloc(2 * pxp->blksz + ALIGN32);
|
|
pxp->bf_base = (char *)((uint)((char *)pxp->bf_base + ALIGN32 - 1) & ~(ALIGN32 - 1));
|
|
#endif
|
|
if(pxp->bf_base == NULL)
|
|
return ENOMEM;
|
|
}
|
|
goto pgin;
|
|
}
|
|
/* else */
|
|
assert(blkextent <= 2 * pxp->blksz);
|
|
|
|
if(blkoffset == pxp->bf_offset)
|
|
{
|
|
/* hit */
|
|
if(blkextent > pxp->bf_extent)
|
|
{
|
|
/* page in upper */
|
|
void *const middle =
|
|
(void *)((char *)pxp->bf_base + pxp->blksz);
|
|
assert(pxp->bf_extent == pxp->blksz);
|
|
status = px_pgin(nciop,
|
|
pxp->bf_offset + (off_t)pxp->blksz,
|
|
pxp->blksz,
|
|
middle,
|
|
&pxp->bf_cnt,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
pxp->bf_extent = 2 * pxp->blksz;
|
|
pxp->bf_cnt += pxp->blksz;
|
|
}
|
|
goto done;
|
|
}
|
|
/* else */
|
|
|
|
if(pxp->bf_extent > pxp->blksz
|
|
&& blkoffset == (off_t)(pxp->bf_offset + pxp->blksz))
|
|
{
|
|
/* hit in upper half */
|
|
if(blkextent == pxp->blksz)
|
|
{
|
|
/* all in upper half, no fault needed */
|
|
diff += pxp->blksz;
|
|
goto done;
|
|
}
|
|
/* else */
|
|
if(pxp->bf_cnt > pxp->blksz)
|
|
{
|
|
/* data in upper half */
|
|
void *const middle =
|
|
(void *)((char *)pxp->bf_base + pxp->blksz);
|
|
assert(pxp->bf_extent == 2 * pxp->blksz);
|
|
if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
|
|
{
|
|
/* page out lower half */
|
|
assert(pxp->bf_refcount <= 0);
|
|
status = px_pgout(nciop,
|
|
pxp->bf_offset,
|
|
pxp->blksz,
|
|
pxp->bf_base,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
}
|
|
pxp->bf_cnt -= pxp->blksz;
|
|
/* copy upper half into lower half */
|
|
(void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);
|
|
}
|
|
pxp->bf_offset = blkoffset;
|
|
/* pxp->bf_extent = pxp->blksz; */
|
|
|
|
assert(blkextent == 2 * pxp->blksz);
|
|
{
|
|
/* page in upper */
|
|
void *const middle =
|
|
(void *)((char *)pxp->bf_base + pxp->blksz);
|
|
status = px_pgin(nciop,
|
|
pxp->bf_offset + (off_t)pxp->blksz,
|
|
pxp->blksz,
|
|
middle,
|
|
&pxp->bf_cnt,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
pxp->bf_extent = 2 * pxp->blksz;
|
|
pxp->bf_cnt += pxp->blksz;
|
|
}
|
|
goto done;
|
|
}
|
|
/* else */
|
|
|
|
if(blkoffset == (off_t)(pxp->bf_offset - pxp->blksz))
|
|
{
|
|
/* wants the page below */
|
|
void *const middle =
|
|
(void *)((char *)pxp->bf_base + pxp->blksz);
|
|
size_t upper_cnt = 0;
|
|
if(pxp->bf_cnt > pxp->blksz)
|
|
{
|
|
/* data in upper half */
|
|
assert(pxp->bf_extent == 2 * pxp->blksz);
|
|
if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
|
|
{
|
|
/* page out upper half */
|
|
assert(pxp->bf_refcount <= 0);
|
|
status = px_pgout(nciop,
|
|
pxp->bf_offset + (off_t)pxp->blksz,
|
|
pxp->bf_cnt - pxp->blksz,
|
|
middle,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
}
|
|
pxp->bf_cnt = pxp->blksz;
|
|
pxp->bf_extent = pxp->blksz;
|
|
}
|
|
if(pxp->bf_cnt > 0)
|
|
{
|
|
/* copy lower half into upper half */
|
|
(void) memcpy(middle, pxp->bf_base, pxp->blksz);
|
|
upper_cnt = pxp->bf_cnt;
|
|
}
|
|
/* read page below into lower half */
|
|
status = px_pgin(nciop,
|
|
blkoffset,
|
|
pxp->blksz,
|
|
pxp->bf_base,
|
|
&pxp->bf_cnt,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
pxp->bf_offset = blkoffset;
|
|
if(upper_cnt != 0)
|
|
{
|
|
pxp->bf_extent = 2 * pxp->blksz;
|
|
pxp->bf_cnt = pxp->blksz + upper_cnt;
|
|
}
|
|
else
|
|
{
|
|
pxp->bf_extent = pxp->blksz;
|
|
}
|
|
goto done;
|
|
}
|
|
/* else */
|
|
|
|
/* no overlap */
|
|
if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
|
|
{
|
|
assert(pxp->bf_refcount <= 0);
|
|
status = px_pgout(nciop,
|
|
pxp->bf_offset,
|
|
pxp->bf_cnt,
|
|
pxp->bf_base,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
pxp->bf_rflags = 0;
|
|
}
|
|
|
|
pgin:
|
|
status = px_pgin(nciop,
|
|
blkoffset,
|
|
blkextent,
|
|
pxp->bf_base,
|
|
&pxp->bf_cnt,
|
|
&pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
pxp->bf_offset = blkoffset;
|
|
pxp->bf_extent = blkextent;
|
|
|
|
done:
|
|
extent += diff;
|
|
if(pxp->bf_cnt < extent)
|
|
pxp->bf_cnt = extent;
|
|
assert(pxp->bf_cnt <= pxp->bf_extent);
|
|
|
|
pxp->bf_rflags |= rflags;
|
|
pxp->bf_refcount++;
|
|
|
|
*vpp = (char *)pxp->bf_base + diff;
|
|
return ENOERR;
|
|
}
|
|
|
|
static int
|
|
ncio_px_get(ncio *const nciop,
|
|
off_t offset, size_t extent,
|
|
int rflags,
|
|
void **const vpp)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
|
|
if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
|
|
return EPERM; /* attempt to write readonly file */
|
|
|
|
/* reclaim space used in move */
|
|
if(pxp->slave != NULL)
|
|
{
|
|
if(pxp->slave->bf_base != NULL)
|
|
{
|
|
free(pxp->slave->bf_base);
|
|
pxp->slave->bf_base = NULL;
|
|
pxp->slave->bf_extent = 0;
|
|
pxp->slave->bf_offset = OFF_NONE;
|
|
}
|
|
free(pxp->slave);
|
|
pxp->slave = NULL;
|
|
}
|
|
return px_get(nciop, pxp, offset, extent, rflags, vpp);
|
|
}
|
|
|
|
|
|
/* ARGSUSED */
|
|
static int
|
|
px_double_buffer(ncio *const nciop, off_t to, off_t from,
|
|
size_t nbytes, int rflags)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
int status = ENOERR;
|
|
void *src;
|
|
void *dest;
|
|
|
|
(void)rflags;
|
|
|
|
#if 0
|
|
fprintf(stderr, "double_buffr %ld %ld %ld\n",
|
|
(long)to, (long)from, (long)nbytes);
|
|
#endif
|
|
status = px_get(nciop, pxp, to, nbytes, RGN_WRITE,
|
|
&dest);
|
|
if(status != ENOERR)
|
|
return status;
|
|
|
|
if(pxp->slave == NULL)
|
|
{
|
|
pxp->slave = (ncio_px *) malloc(sizeof(ncio_px));
|
|
if(pxp->slave == NULL)
|
|
return ENOMEM;
|
|
|
|
pxp->slave->blksz = pxp->blksz;
|
|
/* pos done below */
|
|
pxp->slave->bf_offset = pxp->bf_offset;
|
|
pxp->slave->bf_extent = pxp->bf_extent;
|
|
pxp->slave->bf_cnt = pxp->bf_cnt;
|
|
#ifndef ALIGN32
|
|
pxp->slave->bf_base = malloc(2 * pxp->blksz);
|
|
#else
|
|
pxp->slave->bf_base = malloc(2 * pxp->blksz + ALIGN32);
|
|
pxp->slave->bf_base = (char *)((uint)((char *)pxp->slave->bf_base + ALIGN32-1) & ~(ALIGN32 - 1));
|
|
#endif
|
|
if(pxp->slave->bf_base == NULL)
|
|
return ENOMEM;
|
|
(void) memcpy(pxp->slave->bf_base, pxp->bf_base,
|
|
pxp->bf_extent);
|
|
pxp->slave->bf_rflags = 0;
|
|
pxp->slave->bf_refcount = 0;
|
|
pxp->slave->slave = NULL;
|
|
}
|
|
|
|
pxp->slave->pos = pxp->pos;
|
|
status = px_get(nciop, pxp->slave, from, nbytes, 0,
|
|
&src);
|
|
if(status != ENOERR)
|
|
return status;
|
|
if(pxp->pos != pxp->slave->pos)
|
|
{
|
|
/* position changed, sync */
|
|
pxp->pos = pxp->slave->pos;
|
|
}
|
|
|
|
(void) memcpy(dest, src, nbytes);
|
|
|
|
(void)px_rel(pxp->slave, from, 0);
|
|
(void)px_rel(pxp, to, RGN_MODIFIED);
|
|
|
|
return status;
|
|
}
|
|
|
|
static int
|
|
ncio_px_move(ncio *const nciop, off_t to, off_t from,
|
|
size_t nbytes, int rflags)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
int status = ENOERR;
|
|
off_t lower;
|
|
off_t upper;
|
|
char *base;
|
|
size_t diff;
|
|
size_t extent;
|
|
|
|
if(to == from)
|
|
return ENOERR; /* NOOP */
|
|
|
|
if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
|
|
return EPERM; /* attempt to write readonly file */
|
|
|
|
rflags &= RGN_NOLOCK; /* filter unwanted flags */
|
|
|
|
if(to > from)
|
|
{
|
|
/* growing */
|
|
lower = from;
|
|
upper = to;
|
|
}
|
|
else
|
|
{
|
|
/* shrinking */
|
|
lower = to;
|
|
upper = from;
|
|
}
|
|
diff = (size_t)(upper - lower);
|
|
extent = diff + nbytes;
|
|
|
|
if(extent > pxp->blksz)
|
|
{
|
|
size_t remaining = nbytes;
|
|
for(;;)
|
|
{
|
|
size_t loopextent = MIN(remaining, pxp->blksz);
|
|
|
|
status = px_double_buffer(nciop, to, from,
|
|
loopextent, rflags) ;
|
|
if(status != ENOERR)
|
|
return status;
|
|
remaining -= loopextent;
|
|
|
|
if(remaining == 0)
|
|
break; /* normal loop exit */
|
|
to += loopextent;
|
|
from += loopextent;
|
|
}
|
|
return ENOERR;
|
|
}
|
|
|
|
#if 0
|
|
fprintf(stderr, "ncio_px_move %ld %ld %ld %ld %ld\n",
|
|
(long)to, (long)from, (long)nbytes, (long)lower, (long)extent);
|
|
#endif
|
|
status = px_get(nciop, pxp, lower, extent, RGN_WRITE|rflags,
|
|
(void **)&base);
|
|
|
|
if(status != ENOERR)
|
|
return status;
|
|
|
|
if(to > from)
|
|
(void) memmove(base + diff, base, nbytes);
|
|
else
|
|
(void) memmove(base, base + diff, nbytes);
|
|
|
|
(void) px_rel(pxp, lower, RGN_MODIFIED);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
static int
|
|
ncio_px_sync(ncio *const nciop)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
int status = ENOERR;
|
|
if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
|
|
{
|
|
assert(pxp->bf_refcount <= 0);
|
|
status = px_pgout(nciop, pxp->bf_offset,
|
|
pxp->bf_cnt,
|
|
pxp->bf_base, &pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
pxp->bf_rflags = 0;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
ncio_px_free(void *const pvt)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)pvt;
|
|
if(pxp == NULL)
|
|
return;
|
|
|
|
if(pxp->slave != NULL)
|
|
{
|
|
if(pxp->slave->bf_base != NULL)
|
|
{
|
|
free(pxp->slave->bf_base);
|
|
pxp->slave->bf_base = NULL;
|
|
pxp->slave->bf_extent = 0;
|
|
pxp->slave->bf_offset = OFF_NONE;
|
|
}
|
|
free(pxp->slave);
|
|
pxp->slave = NULL;
|
|
}
|
|
|
|
if(pxp->bf_base != NULL)
|
|
{
|
|
free(pxp->bf_base);
|
|
pxp->bf_base = NULL;
|
|
pxp->bf_extent = 0;
|
|
pxp->bf_offset = OFF_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
ncio_px_init2(ncio *const nciop, size_t *sizehintp, int isNew)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
const size_t bufsz = 2 * *sizehintp;
|
|
|
|
assert(nciop->fd >= 0);
|
|
|
|
pxp->blksz = *sizehintp;
|
|
|
|
assert(pxp->bf_base == NULL);
|
|
|
|
/* this is separate allocation because it may grow */
|
|
#ifndef ALIGN32
|
|
pxp->bf_base = malloc(bufsz);
|
|
#else
|
|
pxp->bf_base = malloc(bufsz + ALIGN32);
|
|
pxp->bf_base = (char *)((uint)((char *)pxp->bf_base + ALIGN32 - 1) & ~(ALIGN32 - 1));
|
|
#endif
|
|
if(pxp->bf_base == NULL)
|
|
return ENOMEM;
|
|
/* else */
|
|
pxp->bf_cnt = 0;
|
|
if(isNew)
|
|
{
|
|
/* save a read */
|
|
pxp->pos = 0;
|
|
pxp->bf_offset = 0;
|
|
pxp->bf_extent = bufsz;
|
|
(void) memset(pxp->bf_base, 0, pxp->bf_extent);
|
|
}
|
|
return ENOERR;
|
|
}
|
|
|
|
|
|
static void
|
|
ncio_px_init(ncio *const nciop)
|
|
{
|
|
ncio_px *const pxp = (ncio_px *)nciop->pvt;
|
|
|
|
*((ncio_relfunc **)&nciop->rel) = ncio_px_rel; /* cast away const */
|
|
*((ncio_getfunc **)&nciop->get) = ncio_px_get; /* cast away const */
|
|
*((ncio_movefunc **)&nciop->move) = ncio_px_move; /* cast away const */
|
|
*((ncio_syncfunc **)&nciop->sync) = ncio_px_sync; /* cast away const */
|
|
*((ncio_freefunc **)&nciop->free) = ncio_px_free; /* cast away const */
|
|
|
|
pxp->blksz = 0;
|
|
pxp->pos = -1;
|
|
pxp->bf_offset = OFF_NONE;
|
|
pxp->bf_extent = 0;
|
|
pxp->bf_rflags = 0;
|
|
pxp->bf_refcount = 0;
|
|
pxp->bf_base = NULL;
|
|
pxp->slave = NULL;
|
|
|
|
}
|
|
|
|
/* Begin spx */
|
|
|
|
typedef struct ncio_spx {
|
|
off_t pos;
|
|
/* buffer */
|
|
off_t bf_offset;
|
|
size_t bf_extent;
|
|
size_t bf_cnt;
|
|
void *bf_base;
|
|
} ncio_spx;
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
ncio_spx_rel(ncio *const nciop, off_t offset, int rflags)
|
|
{
|
|
ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
|
|
int status = ENOERR;
|
|
|
|
(void)offset;
|
|
|
|
assert(pxp->bf_offset <= offset);
|
|
assert(pxp->bf_cnt != 0);
|
|
assert(pxp->bf_cnt <= pxp->bf_extent);
|
|
#ifdef X_ALIGN
|
|
assert(offset < pxp->bf_offset + X_ALIGN);
|
|
assert(pxp->bf_cnt % X_ALIGN == 0 );
|
|
#endif
|
|
|
|
if(fIsSet(rflags, RGN_MODIFIED))
|
|
{
|
|
if(!fIsSet(nciop->ioflags, NC_WRITE))
|
|
return EPERM; /* attempt to write readonly file */
|
|
|
|
status = px_pgout(nciop, pxp->bf_offset,
|
|
pxp->bf_cnt,
|
|
pxp->bf_base, &pxp->pos);
|
|
/* if error, invalidate buffer anyway */
|
|
}
|
|
pxp->bf_offset = OFF_NONE;
|
|
pxp->bf_cnt = 0;
|
|
return status;
|
|
}
|
|
|
|
|
|
static int
|
|
ncio_spx_get(ncio *const nciop,
|
|
off_t offset, size_t extent,
|
|
int rflags,
|
|
void **const vpp)
|
|
{
|
|
ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
|
|
int status = ENOERR;
|
|
#ifdef X_ALIGN
|
|
size_t rem;
|
|
#endif
|
|
|
|
if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
|
|
return EPERM; /* attempt to write readonly file */
|
|
|
|
assert(extent != 0);
|
|
|
|
assert(pxp->bf_cnt == 0);
|
|
|
|
#ifdef X_ALIGN
|
|
rem = (size_t)(offset % X_ALIGN);
|
|
if(rem != 0)
|
|
{
|
|
offset -= rem;
|
|
extent += rem;
|
|
}
|
|
|
|
{
|
|
const size_t rndup = extent % X_ALIGN;
|
|
if(rndup != 0)
|
|
extent += X_ALIGN - rndup;
|
|
}
|
|
|
|
assert(offset % X_ALIGN == 0);
|
|
assert(extent % X_ALIGN == 0);
|
|
#endif
|
|
|
|
if(pxp->bf_extent < extent)
|
|
{
|
|
if(pxp->bf_base != NULL)
|
|
{
|
|
free(pxp->bf_base);
|
|
pxp->bf_base = NULL;
|
|
pxp->bf_extent = 0;
|
|
}
|
|
assert(pxp->bf_extent == 0);
|
|
pxp->bf_base = malloc(extent);
|
|
if(pxp->bf_base == NULL)
|
|
return ENOMEM;
|
|
pxp->bf_extent = extent;
|
|
}
|
|
|
|
status = px_pgin(nciop, offset,
|
|
extent,
|
|
pxp->bf_base,
|
|
&pxp->bf_cnt, &pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
|
|
pxp->bf_offset = offset;
|
|
|
|
if(pxp->bf_cnt < extent)
|
|
pxp->bf_cnt = extent;
|
|
|
|
#ifdef X_ALIGN
|
|
*vpp = (char *)pxp->bf_base + rem;
|
|
#else
|
|
*vpp = pxp->bf_base;
|
|
#endif
|
|
return ENOERR;
|
|
}
|
|
|
|
|
|
#if 0
|
|
/*ARGSUSED*/
|
|
static int
|
|
strategy(ncio *const nciop, off_t to, off_t offset,
|
|
size_t extent, int rflags)
|
|
{
|
|
static ncio_spx pxp[1];
|
|
int status = ENOERR;
|
|
#ifdef X_ALIGN
|
|
size_t rem;
|
|
#endif
|
|
|
|
assert(extent != 0);
|
|
#if INSTRUMENT
|
|
fprintf(stderr, "strategy %ld at %ld to %ld\n",
|
|
(long)extent, (long)offset, (long)to);
|
|
#endif
|
|
|
|
|
|
#ifdef X_ALIGN
|
|
rem = (size_t)(offset % X_ALIGN);
|
|
if(rem != 0)
|
|
{
|
|
offset -= rem;
|
|
extent += rem;
|
|
}
|
|
|
|
{
|
|
const size_t rndup = extent % X_ALIGN;
|
|
if(rndup != 0)
|
|
extent += X_ALIGN - rndup;
|
|
}
|
|
|
|
assert(offset % X_ALIGN == 0);
|
|
assert(extent % X_ALIGN == 0);
|
|
#endif
|
|
|
|
if(pxp->bf_extent < extent)
|
|
{
|
|
if(pxp->bf_base != NULL)
|
|
{
|
|
free(pxp->bf_base);
|
|
pxp->bf_base = NULL;
|
|
pxp->bf_extent = 0;
|
|
}
|
|
assert(pxp->bf_extent == 0);
|
|
pxp->bf_base = malloc(extent);
|
|
if(pxp->bf_base == NULL)
|
|
return ENOMEM;
|
|
pxp->bf_extent = extent;
|
|
}
|
|
|
|
status = px_pgin(nciop, offset,
|
|
extent,
|
|
pxp->bf_base,
|
|
&pxp->bf_cnt, &pxp->pos);
|
|
if(status != ENOERR)
|
|
return status;
|
|
|
|
pxp->bf_offset = to; /* TODO: XALIGN */
|
|
|
|
if(pxp->bf_cnt < extent)
|
|
pxp->bf_cnt = extent;
|
|
|
|
status = px_pgout(nciop, pxp->bf_offset,
|
|
pxp->bf_cnt,
|
|
pxp->bf_base, &pxp->pos);
|
|
/* if error, invalidate buffer anyway */
|
|
pxp->bf_offset = OFF_NONE;
|
|
pxp->bf_cnt = 0;
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
ncio_spx_move(ncio *const nciop, off_t to, off_t from,
|
|
size_t nbytes, int rflags)
|
|
{
|
|
int status = ENOERR;
|
|
off_t lower = from;
|
|
off_t upper = to;
|
|
char *base;
|
|
size_t diff = (size_t)(upper - lower);
|
|
size_t extent = diff + nbytes;
|
|
|
|
rflags &= RGN_NOLOCK; /* filter unwanted flags */
|
|
|
|
if(to == from)
|
|
return ENOERR; /* NOOP */
|
|
|
|
if(to > from)
|
|
{
|
|
/* growing */
|
|
lower = from;
|
|
upper = to;
|
|
}
|
|
else
|
|
{
|
|
/* shrinking */
|
|
lower = to;
|
|
upper = from;
|
|
}
|
|
|
|
diff = (size_t)(upper - lower);
|
|
extent = diff + nbytes;
|
|
|
|
status = ncio_spx_get(nciop, lower, extent, RGN_WRITE|rflags,
|
|
(void **)&base);
|
|
|
|
if(status != ENOERR)
|
|
return status;
|
|
|
|
if(to > from)
|
|
(void) memmove(base + diff, base, nbytes);
|
|
else
|
|
(void) memmove(base, base + diff, nbytes);
|
|
|
|
(void) ncio_spx_rel(nciop, lower, RGN_MODIFIED);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
ncio_spx_sync(ncio *const nciop)
|
|
{
|
|
(void)nciop;
|
|
/* NOOP */
|
|
return ENOERR;
|
|
}
|
|
|
|
static void
|
|
ncio_spx_free(void *const pvt)
|
|
{
|
|
ncio_spx *const pxp = (ncio_spx *)pvt;
|
|
if(pxp == NULL)
|
|
return;
|
|
|
|
if(pxp->bf_base != NULL)
|
|
{
|
|
free(pxp->bf_base);
|
|
pxp->bf_base = NULL;
|
|
pxp->bf_offset = OFF_NONE;
|
|
pxp->bf_extent = 0;
|
|
pxp->bf_cnt = 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
ncio_spx_init2(ncio *const nciop, const size_t *const sizehintp)
|
|
{
|
|
ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
|
|
|
|
assert(nciop->fd >= 0);
|
|
|
|
pxp->bf_extent = *sizehintp;
|
|
|
|
assert(pxp->bf_base == NULL);
|
|
|
|
/* this is separate allocation because it may grow */
|
|
pxp->bf_base = malloc(pxp->bf_extent);
|
|
if(pxp->bf_base == NULL)
|
|
{
|
|
pxp->bf_extent = 0;
|
|
return ENOMEM;
|
|
}
|
|
/* else */
|
|
return ENOERR;
|
|
}
|
|
|
|
|
|
static void
|
|
ncio_spx_init(ncio *const nciop)
|
|
{
|
|
ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
|
|
|
|
*((ncio_relfunc **)&nciop->rel) = ncio_spx_rel; /* cast away const */
|
|
*((ncio_getfunc **)&nciop->get) = ncio_spx_get; /* cast away const */
|
|
*((ncio_movefunc **)&nciop->move) = ncio_spx_move; /* cast away const */
|
|
*((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync; /* cast away const */
|
|
*((ncio_freefunc **)&nciop->free) = ncio_spx_free; /* cast away const */
|
|
|
|
pxp->pos = -1;
|
|
pxp->bf_offset = OFF_NONE;
|
|
pxp->bf_extent = 0;
|
|
pxp->bf_cnt = 0;
|
|
pxp->bf_base = NULL;
|
|
}
|
|
|
|
|
|
/* */
|
|
|
|
static void
|
|
ncio_free(ncio *nciop)
|
|
{
|
|
if(nciop == NULL)
|
|
return;
|
|
|
|
if(nciop->free != NULL)
|
|
{
|
|
ncio_freefunc* func = (ncio_freefunc*)nciop->free;
|
|
func(nciop->pvt);
|
|
}
|
|
|
|
free(nciop);
|
|
}
|
|
|
|
|
|
static ncio *
|
|
ncio_new(const char *path, int ioflags)
|
|
{
|
|
size_t sz_ncio = M_RNDUP(sizeof(ncio));
|
|
size_t sz_path = M_RNDUP(strlen(path) +1);
|
|
size_t sz_ncio_pvt;
|
|
ncio *nciop;
|
|
|
|
#if ALWAYS_NC_SHARE /* DEBUG */
|
|
fSet(ioflags, NC_SHARE);
|
|
#endif
|
|
|
|
if(fIsSet(ioflags, NC_SHARE))
|
|
sz_ncio_pvt = sizeof(ncio_spx);
|
|
else
|
|
sz_ncio_pvt = sizeof(ncio_px);
|
|
|
|
nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
|
|
if(nciop == NULL)
|
|
return NULL;
|
|
|
|
nciop->ioflags = ioflags;
|
|
*((int *)&nciop->fd) = -1; /* cast away const */
|
|
|
|
nciop->path = (char *) ((char *)nciop + sz_ncio);
|
|
(void) strcpy((char *)nciop->path, path); /* cast away const */
|
|
|
|
/* cast away const */
|
|
*((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);
|
|
|
|
if(fIsSet(ioflags, NC_SHARE))
|
|
ncio_spx_init(nciop);
|
|
else
|
|
ncio_px_init(nciop);
|
|
|
|
return nciop;
|
|
}
|
|
|
|
|
|
/* Public below this point */
|
|
|
|
#define NCIO_MINBLOCKSIZE 256
|
|
#define NCIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */
|
|
|
|
#if defined( S_IRUSR ) && defined( S_IRGRP ) && defined( S_IWGRP ) && defined( S_IROTH ) && defined( S_IWOTH )
|
|
#define NC_DEFAULT_CREAT_MODE \
|
|
(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */
|
|
|
|
#else
|
|
#define NC_DEFAULT_CREAT_MODE 0666
|
|
#endif
|
|
|
|
int
|
|
ncio_create(const char *path, int ioflags,
|
|
size_t initialsz,
|
|
off_t igeto, size_t igetsz, size_t *sizehintp,
|
|
ncio **nciopp, void **const igetvpp)
|
|
{
|
|
ncio *nciop;
|
|
int oflags = (O_RDWR|O_CREAT);
|
|
int fd;
|
|
int status;
|
|
|
|
if(initialsz < (size_t)igeto + igetsz)
|
|
initialsz = (size_t)igeto + igetsz;
|
|
|
|
fSet(ioflags, NC_WRITE);
|
|
|
|
if(path == NULL || *path == 0)
|
|
return EINVAL;
|
|
|
|
nciop = ncio_new(path, ioflags);
|
|
if(nciop == NULL)
|
|
return ENOMEM;
|
|
|
|
if(fIsSet(ioflags, NC_NOCLOBBER))
|
|
fSet(oflags, O_EXCL);
|
|
else
|
|
fSet(oflags, O_TRUNC);
|
|
#ifdef O_BINARY
|
|
fSet(oflags, O_BINARY);
|
|
#endif
|
|
#ifdef vms
|
|
fd = open(path, oflags, NC_DEFAULT_CREAT_MODE, "ctx=stm");
|
|
#else
|
|
/* Should we mess with the mode based on NC_SHARE ?? */
|
|
fd = open(path, oflags, NC_DEFAULT_CREAT_MODE);
|
|
#endif
|
|
#if 0
|
|
(void) fprintf(stderr, "ncio_create(): path=\"%s\"\n", path);
|
|
(void) fprintf(stderr, "ncio_create(): oflags=0x%x\n", oflags);
|
|
#endif
|
|
if(fd < 0)
|
|
{
|
|
status = errno;
|
|
goto unwind_new;
|
|
}
|
|
*((int *)&nciop->fd) = fd; /* cast away const */
|
|
|
|
if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
|
|
{
|
|
/* Use default */
|
|
*sizehintp = blksize(fd);
|
|
}
|
|
else
|
|
{
|
|
*sizehintp = M_RNDUP(*sizehintp);
|
|
}
|
|
#ifdef __PARAGON__
|
|
*((int *)&nciop->is_file_pfs) = netcdf_local_is_file_pfs;
|
|
netcdf_local_is_file_pfs = 0;
|
|
#endif
|
|
|
|
if(fIsSet(nciop->ioflags, NC_SHARE))
|
|
status = ncio_spx_init2(nciop, sizehintp);
|
|
else
|
|
status = ncio_px_init2(nciop, sizehintp, 1);
|
|
|
|
if(status != ENOERR)
|
|
goto unwind_open;
|
|
|
|
if(initialsz != 0)
|
|
{
|
|
status = fgrow(fd, (off_t)initialsz);
|
|
if(status != ENOERR)
|
|
goto unwind_open;
|
|
}
|
|
|
|
if(igetsz != 0)
|
|
{
|
|
status = nciop->get(nciop,
|
|
igeto, igetsz,
|
|
RGN_WRITE,
|
|
igetvpp);
|
|
if(status != ENOERR)
|
|
goto unwind_open;
|
|
}
|
|
|
|
*nciopp = nciop;
|
|
return ENOERR;
|
|
|
|
unwind_open:
|
|
(void) close(fd);
|
|
/* ?? unlink */
|
|
/*FALLTHRU*/
|
|
unwind_new:
|
|
ncio_free(nciop);
|
|
return status;
|
|
}
|
|
|
|
|
|
int
|
|
ncio_open(const char *path,
|
|
int ioflags,
|
|
off_t igeto, size_t igetsz, size_t *sizehintp,
|
|
ncio **nciopp, void **const igetvpp)
|
|
{
|
|
ncio *nciop;
|
|
int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
|
|
int fd;
|
|
int status;
|
|
|
|
if(path == NULL || *path == 0)
|
|
return EINVAL;
|
|
|
|
nciop = ncio_new(path, ioflags);
|
|
if(nciop == NULL)
|
|
return ENOMEM;
|
|
|
|
#ifdef O_BINARY
|
|
fSet(oflags, O_BINARY);
|
|
#endif
|
|
#ifdef vms
|
|
fd = open(path, oflags, 0, "ctx=stm");
|
|
#else
|
|
fd = open(path, oflags, 0);
|
|
#endif
|
|
if(fd < 0)
|
|
{
|
|
status = errno;
|
|
goto unwind_new;
|
|
}
|
|
*((int *)&nciop->fd) = fd; /* cast away const */
|
|
|
|
if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
|
|
{
|
|
/* Use default */
|
|
*sizehintp = blksize(fd);
|
|
}
|
|
else
|
|
{
|
|
*sizehintp = M_RNDUP(*sizehintp);
|
|
}
|
|
|
|
if(fIsSet(nciop->ioflags, NC_SHARE))
|
|
status = ncio_spx_init2(nciop, sizehintp);
|
|
else
|
|
status = ncio_px_init2(nciop, sizehintp, 0);
|
|
|
|
if(status != ENOERR)
|
|
goto unwind_open;
|
|
|
|
if(igetsz != 0)
|
|
{
|
|
status = nciop->get(nciop,
|
|
igeto, igetsz,
|
|
0,
|
|
igetvpp);
|
|
if(status != ENOERR)
|
|
goto unwind_open;
|
|
}
|
|
|
|
*nciopp = nciop;
|
|
return ENOERR;
|
|
|
|
unwind_open:
|
|
(void) close(fd);
|
|
/*FALLTHRU*/
|
|
unwind_new:
|
|
ncio_free(nciop);
|
|
return status;
|
|
}
|
|
|
|
|
|
int
|
|
ncio_close(ncio *nciop, int doUnlink)
|
|
{
|
|
int status = ENOERR;
|
|
|
|
if(nciop == NULL)
|
|
return EINVAL;
|
|
|
|
{
|
|
ncio_syncfunc* func = (ncio_syncfunc*)(nciop->sync);
|
|
status = func(nciop);
|
|
}
|
|
|
|
(void) close(nciop->fd);
|
|
|
|
if(doUnlink)
|
|
(void) unlink(nciop->path);
|
|
|
|
ncio_free(nciop);
|
|
|
|
return status;
|
|
}
|
|
|