📄 posixio.c
字号:
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;}/* Request that the region (offset, extent) be made available through *vpp. This function converts a file region specified by an offset and extent to a memory pointer. The region may be locked until the corresponding call to rel(). For POSIX systems, without NC_SHARE. This function gets a page of size extent? This is a wrapper for the function px_get, which does all the heavy lifting. nciop - pointer to ncio struct for this file. offset - offset (from beginning of file?) to the data we want to read. extent - the number of bytes to read from the file. rflags - One of the RGN_* flags defined in ncio.h. vpp - handle to point at data when it's been read.*/static intncio_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 intpx_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; #if INSTRUMENTfprintf(stderr, "\tdouble_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; pxp->slave->bf_base = malloc(2 * pxp->blksz); 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;}/* Like memmove(), safely move possibly overlapping data. Copy one region to another without making anything available to higher layers. May be just implemented in terms of get() and rel(), or may be tricky to be efficient. Only used in by nc_enddef() after redefinition. nciop - pointer to ncio struct with file info. to - src for move? from - dest for move? nbytes - number of bytes to move. rflags - One of the RGN_* flags defined in ncio.h. The only reasonable flag value is RGN_NOLOCK.*/static intncio_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 INSTRUMENTfprintf(stderr, "ncio_px_move %ld %ld %ld %ld %ld\n", (long)to, (long)from, (long)nbytes, (long)lower, (long)extent);#endif if(extent > pxp->blksz) { size_t remaining = nbytes;if(to > from){ off_t frm = from + nbytes; off_t toh = to + nbytes; for(;;) { size_t loopextent = MIN(remaining, pxp->blksz); frm -= loopextent; toh -= loopextent; status = px_double_buffer(nciop, toh, frm, loopextent, rflags) ; if(status != ENOERR) return status; remaining -= loopextent; if(remaining == 0) break; /* normal loop exit */ }}else{ 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 INSTRUMENTfprintf(stderr, "\tncio_px_move small\n");#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;}/* Flush any buffers to disk. May be a no-op on if I/O is unbuffered. This function is used when NC_SHARE is NOT used.*/static intncio_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; } else if (!fIsSet(pxp->bf_rflags, RGN_WRITE)) { /* * The dataset is readonly. Invalidate the buffers so * that the next ncio_px_get() will actually read data. */ pxp->bf_offset = OFF_NONE; pxp->bf_cnt = 0; } return status;}/* Internal function called at close to free up anything hanging off pvt.*/static voidncio_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; }}/* This is the second half of the ncio initialization. This is called after the file has actually been opened. The most important thing that happens is the allocation of a block of memory at pxp->bf_base. This is going to be twice the size of the chunksizehint (rounded up to the nearest sizeof(double)) passed in from nc__create or nc__open. The rounded chunksizehint (passed in here in sizehintp) is going to be stored as pxp->blksize. According to our "contract" we are not allowed to ask for an extent larger than this chunksize/sizehint/blksize from the ncio get function. nciop - pointer to the ncio struct sizehintp - pointer to a size hint that will be rounded up and passed back to the caller. isNew - true if this is being called from ncio_create for a new file.*/static intncio_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 */ pxp->bf_base = malloc(bufsz); 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;}/* This is the first of a two-part initialization of the ncio struct. Here the rel, get, move, sync, and free function pointers are set to their POSIX non-NC_SHARE functions (ncio_px_*). The ncio_px struct is also partially initialized.*/static voidncio_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 *//* This is the struct that gets hung of ncio->pvt(?) when the NC_SHARE flag is used.*/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*//* This function releases the region specified by offset. For POSIX system, with NC_SHARE, this becomes the rel function pointed to by the ncio rel function pointer. It mearly checks for file write permission, then calls px_rel to do everything. nciop - pointer to ncio struct. offset - beginning of region. rflags - One of the RGN_* flags defined in ncio.h. If set to RGN_MODIFIED it means that the data in this region were modified, and it needs to be written out to the disk immediately (since we are not buffering with NC_SHARE on).*/static intncio_spx_rel(ncio *const nciop, off_t offset, int rflags){ ncio_spx *const pxp = (ncio_spx *)nciop->pvt; int status = ENOERR; 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;}/* Request that the region (offset, extent) be made available through *vpp. This function converts a file region specified by an offset and extent to a memory pointer. The region may be locked until the corresponding call to rel(). For POSIX systems, with NC_SHARE. nciop - pointer to ncio struct for this file. offset - offset (from beginning of file?) to the data we want to read. extent - the number of bytes we want. rflags - One of the RGN_* flags defined in ncio.h. May be RGN_NOLOCK. vpp - handle to point at data when it's been read.*/static intncio_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(extent < X_INT_MAX); /* sanity check */ 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 intstrategy(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); assert(extent < X_INT_MAX); /* sanity check */#if INSTRUMENTfprintf(stderr, "strategy %ld at %ld to %ld\n", (long)extent, (long)offset, (long)to);#endif#ifdef X_ALIGN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -