/* * _mr_locsw_set(mr_info, usersw, count) finds an unused entry in the * structure describing outstanding asynchronous I/O * requests, and initializes its values. * Parameters: usersw - address of the status word passed in from the * upper level. * count - number of BITS already completed for this request. * * Returns: pointer to the _lociosw structure to be used. * NULL if error occurred */ _lociosw * _mr_locsw_set( struct mr_f *mr_info, struct ffsw *usersw, int count) { _lociosw *locptr; int i; struct _loclink *loclink; MEM_LOCK(&(mr_info->locsw_lock)); if (mr_info->loclist == NULL) { mr_info->loclist = (struct _loclink *)calloc(1, sizeof(struct _loclink)); if (mr_info->loclist == NULL) { goto nomem; } } loclink = mr_info->loclist; locptr = loclink->loc_first; for (;;) { for (i = 0; i < _FSSASYNUM ; i++) { if (locptr->user_sw == NULL) { goto found ; } else locptr++; } if (loclink->loc_nxt == NULL) { loclink->loc_nxt = (struct _loclink *)calloc(1, sizeof(struct _loclink)); if (loclink->loc_nxt == NULL) { goto nomem; } } loclink = loclink->loc_nxt; locptr = loclink->loc_first; } found: locptr->user_sw = usersw; locptr->sw_count = count; CLRFFSTAT(*usersw); memset(&locptr->local_sw , 0, sizeof(struct ffsw)); #if defined(_ADDR64) || defined(__mips) usersw->sw_sptr = (void *)locptr; #else usersw->sw_sptr = (int)locptr; #endif MEM_UNLOCK(&(mr_info->locsw_lock)); return(locptr); nomem: MEM_UNLOCK(&(mr_info->locsw_lock)); return(NULL); }
int _er90b_writea(struct fdinfo *fio, bitptr bufptr, int nbytes, struct ffsw *retstat, int fulp, int *ubc) { int ret = 0; char *buf; ER90BYT *f; int zero = 0; struct ffsw dumstat; buf = BPTR2CP(bufptr); if ((BPBITOFF(bufptr) & 7) != 0 || *ubc != 0) ERETURN(retstat, FDC_ERR_UBC, 0); if (fio->rwflag == POSITIN) { f = (ER90BYT *)fio->lyr_info; if (f->tpos) { ret = _tape_tpwait(f->fd, &(f->tpos)); if (ret < 0) ERETURN(retstat, errno, 0); } } else if (fio->rwflag == READIN) { /* write after read requires position to zero */ ret = _er90b_pos(fio, FP_RSEEK, &zero, 1, &dumstat); if (ret < 0) { *retstat = dumstat; return(ERR); } } if (nbytes > 0) { CLRFFSTAT(*retstat); /* flag async in progress */ ret= writea(fio->realfd, buf, nbytes, (struct iosw *)retstat, 0); if (ret < 0) ERETURN(retstat, errno, 0); } else if (nbytes < 0) { ERETURN(retstat, FDC_ERR_REQ, 0); } else { /* nbytes == 0 */ retstat->sw_flag = 1; FFSTAT(*retstat) = FFCNT; /* I/O is done, and other stat */ /* fields are already set. */ } fio->rwflag = WRITIN; return (ret); }
/* * _cch_wrabuf * * Flushes to the underlying ffio layer one or more cache page buffers. * The ffsw structure pointed to by stat receives the synchronous or * asynchronous completion status. * If the lastdata or firstdata fields in the buffer control block * are non-zero, then nblk had better be 1. In this case, we write only * the part of the buffer between firstdata and lastdata. * * When nblk > 1, _cch_wrabuf assumes that all page buffers get written to * contiguous parts of the file. * * Return value: * * On normal completion 0 is returned. -1 is returned if an error is * encountered, with the status set in stat. * * Side effects: * * The CCH_DIRTY bit is cleared for all affected buffers. If called * in asynchronous mode, the buffers are placed in CCH_WRITING state. */ _cch_wrabuf( struct cch_f *cch_info, /* cache info */ struct fdinfo *llfio, /* fdinfo pointer for underlying layer */ struct cch_buf *bc, /* buffer control block */ int bytes, /* number of bytes per page buffer */ off_t bytoff, /* byte offset within file */ int64 nblk, /* number of contiguous buffers to flush */ off_t *eof, /* on input, contains the bit size of the * underlying file layer. On output, this * size is updated if the file is extended. */ char syncasync, /* 's' for sync request, 'a' for async */ struct ffsw *stat /* io completion status structure */ ) { int i; ssize_t ret; int ubc; size_t tbytes, bytleft; size_t saveamt = 0; off_t end_of_data; struct fflistreq list_array[1]; char *bufptr; CCH_DEBUG(("_cch_wrabuf EN: bytes=%d (0%o) bytoff=%d (0%o) \n", bytes,bytes,bytoff,bytoff)); if (bc->firstdata || bc->lastdata) { assert(nblk <= 1); tbytes = (size_t)((bc->lastdata - bc->firstdata)/8); bytoff = bytoff + bc->firstdata/8; bufptr = BPTR2CP(bc->buf) + bc->firstdata/8; } else { tbytes = bytes * nblk; bufptr = BPTR2CP(bc->buf); } #ifdef __mips if (cch_info->odirect && tbytes > cch_info->maxiosize){ syncasync = 's'; } #endif ubc = 0; if (syncasync == 'a') { /* * Seek to proper location */ if (XRCALL(llfio,seekrtn) llfio, bytoff, SEEK_SET, stat) == ERR) return(ERR); /* * Start an asynchronous write. */ CLRFFSTAT(bc->sw); ret = XRCALL(llfio,writeartn) llfio, CPTR2BP(bufptr), tbytes, &bc->sw, PARTIAL, &ubc); if (ret == ERR) { ERETURN(stat,bc->sw.sw_error,0); } bc[0].lnkcnt = nblk; /* cnt of linked bufs */ for (i=0; i<nblk; i++) { bc[i].flags |= CCH_WRITING; /* update buffer stat */ bc[i].flags &= ~CCH_DIRTY; /* clear dirty flag */ bc[i].lnk = i; /* chain several bufs */ } } else {
/* * _cca_listio * * Issue a listio request for the cachea layer. * * Return Value: * * On success, nreq is returned, and the contents of the stat structure are * unspecified. * * If an error in setup is encountered, stat is set as follows: * * stat->sw_error = error code * stat->sw_stat = FFERR * stat->sw_flag = 1 * stat->sw_count = 0 * * If an error in I/O request I is detected, the list[I].li_stat * structure will be set as follows: * * list[I].li_stat->sw_error = error code * list[I].li_stat->sw_flag = 1 */ _cca_listio( int cmd, /* LC_START or LC_START */ struct fflistreq *list, /* list of requests (see fflistio) */ int nreq, /* number of requests */ struct ffsw *stat) /* status structure */ { int ret; int i; int n_handled; int status; int zero; int pos; bitptr buf; struct ffsw loc_stat; struct fdinfo *fio; struct fdinfo *oldfio; struct cca_f *cca_info; n_handled = 0; oldfio = GETIOB(list[0].li_fildes); cca_info = (struct cca_f *)oldfio->lyr_info; for (i = 0; i < nreq; i++) { fio = GETIOB(list[i].li_fildes); if (fio != oldfio) { _SETERROR(list[i].li_status, FDC_ERR_LSTIO, 0); continue; } if ( list[i].li_signo != 0 ) { _SETERROR(list[i].li_status, FDC_ERR_REQ, 0); continue; } cca_info = (struct cca_f *)fio->lyr_info; CLRFFSTAT(*(list[i].li_status)); SET_BPTR(buf, CPTR2BP(list[i].li_buf)); if ( list[i].li_nstride > 1 ) { status = _ffcompound(&list[i]); if (status == 0) n_handled++; continue; } if ( list[i].li_flags == LF_LSEEK ) { pos = _cca_seek(fio, list[i].li_offset, SEEK_SET, &loc_stat); if (pos == -1) { *list[i].li_status = loc_stat; continue; } } else if (list[i].li_flags != 0) { _SETERROR(list[i].li_status, FDC_ERR_REQ, 0); } zero = 0; status = 0; if ( cmd == LC_START ) { if ( list[i].li_opcode == LO_READ ) { status = _cca_reada(fio, buf, list[i].li_nbyte, list[i].li_status, FULL, &zero ); } else if (list[i].li_opcode == LO_WRITE ) { status = _cca_writea(fio, buf, list[i].li_nbyte, list[i].li_status, FULL, &zero ); } else { _SETERROR(list[i].li_status, FDC_ERR_REQ, 0); } } else if ( cmd == LC_WAIT ) { if ( list[i].li_opcode == LO_READ ) { status = _cca_read(fio, buf, list[i].li_nbyte, list[i].li_status, FULL, &zero ); } else if (list[i].li_opcode == LO_WRITE ) { status = _cca_write(fio, buf, list[i].li_nbyte, list[i].li_status, FULL, &zero ); } else { _SETERROR(list[i].li_status, FDC_ERR_REQ, 0); } } else { _SETERROR(list[i].li_status, FDC_ERR_REQ, 0); } if (status == ERR) { continue; } n_handled++; } return( n_handled ); }
/* * * Description: * writes nbytes bytes, with *ubc unused bits, from bufptr to * the next lower layer. * Parameters: * fio - Pointer to fdinfo block * bufptr - bit pointer to user's data * nbytes - Number of bytes to be written * stat - pointer to status return word * fulp - full or partial write mode flag * ubc - pointer to unused bit count * Returns: * number of bytes written * -1 if error */ ssize_t _sqb_write( struct fdinfo *fio, bitptr bufptr, size_t nbytes, struct ffsw *stat, int fulp, int *ubc) { int ret; int bs, btomove; uint64 nbits; ssize_t moved; struct sqb_f *sqb_info; struct fdinfo *llfio; struct ffsw locstat; struct sqbio *sqbptr; int zero = 0; nbits = ((uint64)nbytes << 3) - *ubc; sqb_info = (struct sqb_f *)fio->lyr_info; llfio = fio->fioptr; moved = 0; if (fio->rwflag == READIN || fio->rwflag == POSITIN) { /* synchronize physical position with logical position */ if (_sqb_sync(fio, &locstat, 1) < 0) { goto erret; } } fio->rwflag = WRITIN; bs = sqb_info->bufsiz>>3; sqbptr = sqb_info->sqbio_cur; while (nbits != 0) { if (sqbptr->status == IOACTIVE) { /* wait for the outstanding asynch i/o to complete */ while (sqbptr->iostat.sw_flag == 0 || sqbptr->iostat.sw_stat == 0) { ret = XRCALL(llfio,fcntlrtn) llfio, FC_RECALL, &(sqbptr->iostat), &locstat); if (ret < 0) { goto erret; } } if (sqbptr->iostat.sw_error != 0) { ERETURN(stat, sqbptr->iostat.sw_error, 0); } if (sqbptr->iostat.sw_count != sqbptr->_iowritten) { ERETURN(stat, FDC_ERR_WRTERR, 0); } sqbptr->status = EMPTY; sqbptr->_cnt = sqb_info->bufsiz; CLRFFSTAT(sqbptr->iostat); } if (sqbptr->status == EMPTY) { sqbptr->_cnt = sqb_info->bufsiz; } /* * Move data from user to buffer */ btomove = MIN(nbits, sqbptr->_cnt); MOV_BITS(sqb_info->_ptr, bufptr, btomove); SET_BPTR(bufptr, INC_BPTR(bufptr, btomove)); nbits -= btomove; sqbptr->_cnt -= btomove; sqbptr->status = IODATA; if (sqbptr->_cnt == 0) { /* no room left in this buffer; start I/O on it */ CLRFFSTAT(sqbptr->iostat); sqbptr->_iowritten = bs; if( XRCALL(llfio, writeartn) llfio, sqbptr->_base,(size_t) bs, &(sqbptr->iostat), FULL, &zero) < 0) { ERETURN(stat, sqbptr->iostat.sw_error, (moved +7) >> 3); } sqbptr->status = IOACTIVE; sqb_info->sqbio_cur = sqb_info->sqbio_cur->nxt; sqbptr = sqb_info->sqbio_cur; sqb_info->_ptr = sqb_info->sqbio_cur->_base; } else {
int _sqb_pos(struct fdinfo *fio, int cmd, long *arg, int len, struct ffsw *stat) { int ret = 0; struct sqb_f *sqb_info; struct sqbio *sqbptr; struct sqbio *sqborig; struct sqbio *s; struct fdinfo *llfio; int found = 0; int nbits; int sync = -1; llfio = fio->fioptr; sqb_info = (struct sqb_f *)fio->lyr_info; if (fio->rwflag == WRITIN) { /* flush buffers and wait for outstanding I/O to finish. */ if (_sqb_flush(fio, stat) < 0) { return(ERR); } } switch(cmd) { /* For now, this is not supported on SGI systems. */ /* We need to work out what "arg" should be. */ #if !defined(__mips) && !defined(_LITTLE_ENDIAN) case FP_RSEEK: if ((fio->rwflag == READIN) || (fio->rwflag == POSITIN)) { if (*arg < 0) { /* Seeking backwards */ /* Are we seeking within the current */ /* buffer? */ sqbptr = sqb_info->sqbio_cur; if (sqbptr->status == IOACTIVE) { while (sqbptr->iostat.sw_flag == 0 || sqbptr->iostat.sw_stat == 0) { ret = XRCALL(llfio,fcntlrtn) llfio, FC_RECALL, &(sqbptr->iostat), stat); if (ret < 0) { return(ERR); } } if (FFSTAT(sqbptr->iostat) == FFERR) { ERETURN(stat, sqbptr->iostat.sw_error,0); } sqbptr->_cnt = sqbptr->iostat.sw_count<<3; sqbptr->status = IODATA; } if (sqbptr->status == IODATA) { nbits = -(*arg); /* convert to positive */ nbits = nbits<<3; if (nbits <= SUBT_BPTR(sqb_info->_ptr,sqbptr->_base)){ SET_BPTR(sqb_info->_ptr, INC_BPTR(sqb_info->_ptr,-nbits)); sqbptr->_cnt += nbits; break; } } } else { /* seeking forward */ /* Any chance that the position would be in */ /* our buffers? */ nbits = *arg << 3; if (nbits > sqb_info->nbuf * sqb_info->bufsiz){ /* won't be in any of the buffers */ goto a1; } sqbptr = sqb_info->sqbio_cur; sqborig = sqbptr; do { if (sqbptr->status == IOACTIVE) { while (sqbptr->iostat.sw_flag == 0 || sqbptr->iostat.sw_stat == 0) { ret = XRCALL(llfio,fcntlrtn) llfio, FC_RECALL, &(sqbptr->iostat), stat); if (ret < 0) { return(ERR); } } if (FFSTAT(sqbptr->iostat) == FFERR) { ERETURN(stat, sqbptr->iostat.sw_error,0); } sqbptr->_cnt = sqbptr->iostat.sw_count<<3; sqbptr->status = IODATA; } if (sqbptr->status == IODATA) { if (nbits <= sqbptr->_cnt) { /* Desired position is in this buffer */ sqbptr->_cnt -= nbits; /* Clear out buffers that preceeded this */ s = sqborig; for (; s != sqbptr; s= s->nxt) { s->status = EMPTY; CLRFFSTAT(s->iostat); } sqb_info->sqbio_cur = sqbptr; if (sqbptr != sqborig) sqb_info->_ptr = sqbptr->_base; SET_BPTR(sqb_info->_ptr, INC_BPTR(sqb_info->_ptr,nbits)); found = 1; break; } else { nbits -= sqbptr->_cnt; } } else goto a1; /* all out of data */ sqbptr = sqbptr->nxt; } while (sqbptr != sqborig); } }