Ejemplo n.º 1
0
/*
 * Read TEXT records
 *
 *	Records and blocks are supported only in multiples of 8 bits.
 *	There is no logical limit for the maximum record size.  The 
 *	maximum block size is determined arbitrarily to be 512 words.
 *
 * Parameters:
 *      fio     - Pointer to fdinfo block
 *      bufptr  - bit pointer to where data is to go.
 *      nbytes  - number of bytes to be read
 *      stat    - pointer to status return word
 *      fulp    - full or partial write mode flag
 *      ubc     - pointer to unused bit count (not used)
 */
ssize_t
_txt_read(struct fdinfo *fio, bitptr bufptr, size_t nbytes, struct ffsw *stat,int fulp, int *ubc)
	{
	int64 	nbits, 
		bits,
		movdbits;
	int	ret,
		eorstat;

	nbits = (uint64)nbytes << 3;	/* convert bytes to bits */
	movdbits = 0;
	if (*ubc != 0)		/* ubc should always be zero */
		ERETURN(stat, FDC_ERR_UBC, 0);

	/* read after write error */ 
	if (fio->rwflag == WRITIN) 
		ERETURN(stat, FDC_ERR_RAWR, 0); 

	fio->rwflag = READIN;  /* set operation type */
/*
 * 	If segment is empty, get the next segment.
 */
	fio->ateor = 0;
	if (fio->segbits == 0)
		{
		ret = get_segment(fio, stat);
		/* if EOF or EOD found */
		if (ret > 0)
			return(0);
		if (ret < 0)
			return(ret); /* stat set by get_segment */
		}
/*
 *	Loop until one of the following occurs:
 *		- the caller's request of nbits is satisfied
 *		- an EOR is found
 *		- an EOF is found
 *		- an EOD is found
 */

	eorstat = FFCNT;
	while ( nbits > 0 ) /* while caller is not satisfied */
		{
/*
 *		If more bits are requested than are in the segment, return
 *		segment.  If the scc (segment operation from get_segment())
 *		equals SCCFULL then return (i.e., hit end-of-record (EOR)).
 *		If the scc equals SCCMIDL (i.e., the fio buffer is empty and 
 *		no EOR was hit) subtract the number of bits moved from nbits
 *		and go on.
 */
		bits = nbits;
		if (fio->segbits < nbits)
			bits = fio->segbits;

		GETDATA(bufptr, fio, bits);
		movdbits += bits;
		SET_BPTR(bufptr, INC_BPTR(bufptr, bits));
		nbits -= bits; 

		if (fio->segbits == 0)
			{
			if (fio->scc == SCCFULL)
				{
				nbits = 0; /* return anyway */
				eorstat = FFEOR;
				}
			else
				{
				ret = get_segment(fio, stat);
				/* if EOF or EOD found */
				if (ret > 0)
					return(0);
				if (ret < 0)
					return(ret); /* stat set by get_segment */
				}
			}

		} /* end while */
/*
 *	Set status now, before doing any skip to EOR
 *	Must check EOR status again...
 */
	if ((fio->segbits == 0) && (fio->scc == SCCFULL))
		eorstat = FFEOR;

	fio->recbits += movdbits;
/*
 *	If the mode is FULL and more bits are
 *	available in the current record,  -or- if
 *	the number of bits requested just happpened to
 *      be the number of bits in the record,  skip to the next EOR. 
 *	If EOF/EOD found while skipping, set the status (this is an error)
 *	and return.
 */
	if ((fulp == FULL) || (eorstat == FFEOR))
		{
		ret = skip2eor(fio, stat);
		if (ret > 0) return(0);	/* EOF/EOD */
		if (ret < 0) return(ERR); /* Status should be set */
		fio->last_recbits = fio->recbits;
		fio->recbits = 0;
		}

	SETSTAT(stat, eorstat, (uint64)movdbits >> 3); /* assume CNT */
	return ((uint64)movdbits >> 3);

	} /* end of _txt_read */
Ejemplo n.º 2
0
struct cch_buf *
_cch_getblk(
struct cch_f	*cch_info,	/* cch_f structure for the file */
struct fdinfo	*llfio,		/* ffio file descriptor for underlying layer */
off_t		fileaddr,	/* bit offset within the file of the buffer.
				 * This number must be a multiple of the buffer
				 * size. */
int64		*nblkp,		/* on input, the number of contiguous buffer 
				 * blocks sought.  On output, assigned the 
				 * actual number of contiguous buffer blocks
				 * assigned. */
int		rd,		/* 0 if all of the new blocks may be 
				 * assigned without reading the file page.  
				 * != 0 if the pages must be read. */
int		valid,		/* 0 if the CCH_VALIDBUFFER bit should */
				/* not be set in the new blocks */
struct ffsw	*stat		/* pointer to status return word */
)
{
	int		i, nbu, ret;
	int		bs;
	int		lru_id;		/* buffer number of least recently */
					/* used buffer. */
	int		limit;
	int64		nblk;
	off_t		endaddr, firstpaddr, faddr;
	long		*wptr;
	long		lru_tm;
	struct cch_buf	*cubuf;
	struct cch_buf	*cbufs;
	struct cch_buf	*fb;

	CCH_DEBUG(("_cch_getblk EN: to bit offset %d\n",fileaddr));

	nbu     = cch_info->nbufs;
	cbufs   = cch_info->bufs;
	bs	= cch_info->bsize;
	nblk	= *nblkp;

	if (nblk > 1) {
		/*
		 * Find the first page in the consecutive list of pages which
		 * is buffer-resident. 
		 */
		endaddr  = fileaddr + nblk * bs;

		firstpaddr = endaddr;

		for (i=0; i<nbu; i++) {
			off_t x;
			cubuf = &cbufs[i];
			x = cubuf->filead;
			if (fileaddr <= x && x < firstpaddr) 
				firstpaddr = x;
		}
	
		if (firstpaddr < endaddr)	/* a page is buffer resident */
			nblk = *nblkp = (firstpaddr - fileaddr) / bs;

		if (nblk <= 0)
			return((struct cch_buf *)NULL);	/* shouldn't happen ! */
	}
/*
 *	Find the least-recently accessed sequence of *nblkp contiguous buffers.
 *	Free buffers are counted as if their last access time was 0.
 *	Search the buffers in groups of size nblk to speed this search and
 *	reduce fragmentation of the cache.  When nblk>1, this algorithm
 *	approximates LRU and, most importantly, is deterministic.
 */
	lru_tm  = MAXLONG;	      /* min _rtc() value in upcoming loop */
	lru_id  = 0;
	for (i=0; i<(nbu-nblk+1); i+=nblk) {
		long last_access = 0;    /* free pages have last_access == 0 */
		if (cbufs[i].filead >= 0)
			last_access = cbufs[i].atime;
		if (last_access < lru_tm) {
			lru_tm = last_access;
			lru_id = i;
		}
	}
/*
 *	Use the least recently used page buffer or group of page buffers.  
 *	Flush any of these page buffers which have the dirty bit set.  When
 *	several adjacent buffers are dirty and correspond to adjacent pages
 *	in the file, they can be flushed with one request.
 */
	fb = &cbufs[lru_id];
	for (i=0; i<nblk; i++) {
		int contig = 0;	/* number of contiguous dirty buffers */
	
		faddr = fb[i].filead;
		if (faddr == -1) 
			continue;	/* buffer is free */

		while (i+contig < nblk && (fb[i+contig].flags & CCH_DIRTY) &&
		       fb[i+contig].filead == faddr) {
			if (fb[i+contig].lastdata || fb[i+contig].firstdata) {
				if (contig == 0)
					contig = 1;
				break;
			}
			contig++;
			faddr += bs;
		}
		if (contig > 0) {
			if (faddr  > cch_info->fsize) {
				/* eof is in the last buffer */
				/* clear it if necessary */
				if ((fb[i+contig-1].flags & CCH_ZEROED) == 0){
					bitptr toptr;
					off_t eofaddr;
					int pgoff;
					eofaddr = CCHFLOOR(cch_info->fsize, bs);
					pgoff = cch_info->fsize - eofaddr;	
					SET_BPTR(toptr,
					   INC_BPTR(fb[i+contig-1].buf, 
					   pgoff));
					CCH_MEMCLEAR(toptr,(bs - pgoff));
					fb[i+contig-1].flags |= CCH_ZEROED;
				}
			}
			ret = _cch_wrabuf(cch_info, llfio, &fb[i],
					BITS2BYTES(bs),
				  	BITS2BYTES(fb[i].filead),
					contig,
				  	&cch_info->feof,
#if	defined(__mips) || defined(_LITTLE_ENDIAN)
					's',	/* flush synchronously */
#else
					'a',	/* flush asynchronously */
#endif
					stat);
			if (ret == ERR)
				return((struct cch_buf *)NULL);

			i += contig - 1;
		}
	}
/*
 *	Wait for any active page buffer I/O, and then requisition the buffers 
 *	for the appropriate file pages.
 */
	for (i=0; i<nblk; i++) {
		if (fb[i].flags & (CCH_WRITING | CCH_READING)) {
			CCHWAITIO(llfio,&fb[i],stat,ret);
			if (ret == ERR) 
				return((struct cch_buf *)NULL);
		}
		fb[i].filead  = fileaddr + i * bs;
		fb[i].flags   = CCH_VALID;
		fb[i].firstdata = fb[i].lastdata  = 0;
		if (valid)
			fb[i].flags |= CCH_VALIDBUFFER;
	}
/*
 *	Now start the synchronous reading of the file page into the buffer.  If
 *	all of the pages lie beyond the EOF, then suppress the read.
 */
	if (rd) {
		if (fileaddr < cch_info->feof) {
			int by_tran;
			fb->sw.sw_flag = 0;	/* indicate I/O in progress */
			ret = _cch_rdabuf(cch_info, llfio, fb, BITS2BYTES(bs),
				 	BITS2BYTES(fb->filead), nblk, 's',stat);
			if (ret == ERR)
				return((struct cch_buf *)NULL);

			/*
			 * Zero portions of the buffers past the end of file.
			 */
			by_tran = fb->sw.sw_count;
#ifdef CCH_SDS_SUPPORTED
			if (cch_info->optflags & CCHOPT_SDS) {
				int ret;
				ret = _sdsset(
					(BPTR2CP(fb->buf) - (char*)NULL) +
						by_tran,
					0,
					nblk * BITS2BYTES(bs) - by_tran);
				if (ret == ERR) {
					_SETERROR(stat, errno, 0);
					return((struct cch_buf *)NULL);
				}
			}	
			else
#endif
			{
			    if ((nblk*BITS2BYTES(bs)-by_tran) != 0)
				(void)memset(BPTR2CP(
					fb->buf) + by_tran,
					0,
					nblk * BITS2BYTES(bs) - by_tran);
			}
			for (i=0; i<nblk; i++) {
				fb[i].flags |= CCH_ZEROED;
			}
		}
		else {				/* page lies beyond EOF */
			/*
			 * Zero the entire buffer.  
			 */
#ifdef CCH_SDS_SUPPORTED
			if (cch_info->optflags & CCHOPT_SDS) {
				int ret;
				ret = _sdsset(
					(BPTR2CP(fb->buf) - (char*)NULL),
					0,
					nblk * BITS2BYTES(bs));
				if (ret == ERR) {
					_SETERROR(stat, errno, 0);
					return((struct cch_buf *)NULL);
				}
				for (i=0; i<nblk; i++) {
					fb[i].flags |= CCH_ZEROED;
				}
			}	
			else
#endif
			if (fileaddr < cch_info->fsize){
				/* this block is between cch_info->feof and */
				/* cch_info->fsize, so we must zero it */
				/* Logic in other parts of this layer will */
				/* only zero what is beyond cch_info->fsize */
#ifdef _CRAY1
                                wptr = BPTR2WP(fb->buf);
                                limit = (nblk * bs) >> 6; /* convert to words */
                                /* this loop vectorizes! */
                                for (i=0; i<limit; i++)
                                        wptr[i] = 0;
#else
                          	memset(BPTR2CP(fb->buf), 0,
				 (nblk * BITS2BYTES(bs)));
#endif
				for (i=0; i<nblk; i++) {
					fb[i].flags |= CCH_ZEROED;
				}
			}
		}
	}
Ejemplo n.º 3
0
/* 
 * get_segment grabs another record segment from the data stream.
 * fio->scc will be set as follows:
 *	SCCMIDL		fio->segbits = fio_cnt (all or rest of data in fio
 *			buffer) and no EOR was found
 *	SCCFULL		an EOR was found
 *
 * return values are as follows:
 *	2	encountered end of data -> stat will be set
 *	1	encountered end of file -> stat will be set
 *	0	segment (or part) is received -> stat will NOT be set
 *	ERR	encountered an error -> stat will be set
 */
static int
get_segment(struct fdinfo *fio, struct ffsw *stat)
	{
	long 	tword;
	int	left; 
	ssize_t	ret;

	unsigned char 	*cp;

	bitptr tbptr;

	struct text_f *text_info;

	text_info = (struct text_f *)fio->lyr_info;
	fio->lastscc = fio->scc;
/*
 *	If buffer is empty, or not enough to hold entire EOF marker,
 *	get more data.
 */
	if (fio->_cnt == 0 || fio->_cnt < text_info->eof_len)
		{
/*
 *		If num of bits not enough to hold EOF, move remainder
 *		to base of buffer and read in at base+remainder.  Adjust
 *		pointers and counts accordingly.
 */
		left = 0;
		if (fio->_cnt > 0)
			{
			bitptr tptr;

			left = fio->_cnt;
/*
 *			Move tail of data to the first word of the
 *			buffer (right justified).
 */
			GET_BITS(tword, fio->_ptr, left);
			SET_BPTR(tptr, fio->_base);
			PUT_BITS(tptr, tword, left);
			SET_BPTR(fio->_ptr, INC_BPTR(fio->_base, left));
			}
		else
			fio->_ptr = fio->_base;	/* reset _ptr */
		zero = 0;
		READBLK(ret, fio, (size_t)((uint64)fio->maxblksize >> 3), 
			stat, PARTIAL, &zero);
/*
 *		Add back in the 'extra' data
 */
		fio->_ptr = fio->_base;	/* reset _ptr */
		fio->_cnt = fio->_cnt + left;

		if (ret < (ssize_t)0)
			return(ERR);
		if (zero != 0)
			ERETURN(stat, FDC_ERR_UBC, 0);

		if (fio->_cnt == 0) /* must be at EOD */
			{
			return(setend(fio, stat));
			}
		}
Ejemplo n.º 4
0
/*
 *
 * 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 {
Ejemplo n.º 5
0
/*
 * Write a X class file
 * Parameters:
 *      fio     - Pointer to fdinfo block
 *	bufptr	- bit pointer to where data is to go.
 *	nbytes	- Nuber of bytes to be written
 *	stat	- pointer to status return word
 *	fulp	- full or partial write mode flag
 *	ubc	- pointer to unused bit count (not used for IBM)
 */
ssize_t
_gen_xwrite(
    struct fdinfo	*fio,
    bitptr		bufptr,
    size_t		nbytes,
    struct ffsw	*stat,
    int		fulp,
    int		*ubc)
{
    ssize_t ret;
    int64  nbits, bits, moved;
    long left;

    nbits = (uint64)nbytes << 3;
    if (*ubc != 0)
        ERETURN(stat, FDC_ERR_UBC, 0);

    /*
     *	If we've been reading, then try to switch the buffer into write mode.
     */
    if (fio->rwflag == READIN)
    {
        /*
         * Issue an error if we are not positioned at a record
         * boundary.   ffweof would terminate the current record, but
         * _cos_write overwrites the current record.   We need to
         * decide which is the proper approach before permitting this
         * here.
         */
        if (fio->_cnt > 0)
            ERETURN(stat, FDC_ERR_NOTREC, 0);

        ret = gen_xwrard(fio, stat);
        if (ret < 0) return(ERR);
    }

    fio->rwflag = WRITIN;
    moved = 0;
    /*
     *	Check for record size exceeded.
     */
    if ((fio->maxrecsize > 0) && (fio->recbits + nbits) > fio->maxrecsize)
        ERETURN(stat, FDC_ERR_MXREC, 0);

    /*
     *	loop putting data in buffer and building segments
     */

    while (nbits > 0)
    {
        /*
         *		bits tells when data has been moved.  Set it to zero
         *		unless someone moves some data in the loop
         */
        bits = 0;
        /*
         *		initialize a new segment, if needed.
         */
        if (fio->recbits == 0)
        {
            if (init_seg(fio, stat) != 0)
                return(ERR);
        }
        /*
         *		If enough room for bits, put them in the buffer
         */
        left = fio->_ffbufsiz - fio->_cnt;
        if (left >= nbits)
        {
            bits = nbits;
            PUTDATA(bufptr, fio, bits);
            SET_BPTR(bufptr, INC_BPTR(bufptr, bits));
        }
        else
        {
            /*
             *			There is not enough room to put all of the data.
             */
            if (left == 0)
            {
                ret = put_segment(fio, stat, PARTIAL);
                if (ret != 0) return(ERR);
            }
            else
            {
                bits = nbits;
                if (nbits > left) bits = left;
                PUTDATA(bufptr, fio, bits);
                SET_BPTR(bufptr, INC_BPTR(bufptr, bits));
            }
        }
        nbits -= bits;
        moved += bits;
    }

    fio->recbits += moved;
    if (fulp == FULL)
    {
        /*
         *		Watch out for NULL writes!
         */
        if (fio->recbits == 0)
            if (init_seg(fio, stat) != 0)
                return(ERR);
        ret = put_segment(fio, stat, fulp); /* this will be FULL */
        if (ret != 0)
            return(ERR);

        SETSTAT(stat, FFEOR, (uint64)moved >> 3);
        fio->last_recbits = fio->recbits;
        fio->recbits = 0;
    }
    else
Ejemplo n.º 6
0
			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 {
			SET_BPTR(sqb_info->_ptr, 
				INC_BPTR(sqb_info->_ptr, btomove));
		}
		moved += btomove;
	}
	SETSTAT(stat, FFCNT, (moved + 7) >> 3);
	return ((moved + 7) >> 3);
erret:
	ERETURN(stat, locstat.sw_error, (moved +7) >> 3);

}

/*
 * Description: Flushes buffers if we have been writing. Waits for I/O
 *		to complete.
 * Parameters:
 *		fio     - Pointer to fdinfo block
Ejemplo n.º 7
0
/*
 * _any_sds_fr_mem moves data into a secondary data segment (SDS) from
 *	user memory
 *
 * unlike _sds_fr_mem, _any_sds_fr_mem handles moving a number of bits that
 * may not be a multiple of 512.
 *
 * Returns 0 on normal return, or else -1 with error code in errno.
 */
_any_sds_fr_mem(
bitptr  sdsaddr,	/* SDS bit address of data */
bitptr  ubuf,		/* user buffer to receive data */
int     nbits		/* number of bits to move */
)
{

	int sds_bit_offset;	
	int sds_bit_offset_blk;	
	int rbits;
	char localbuf[BYTPBLOCK];
	bitptr locptr;
	long *uwaddr;
	char *ucaddr;

	sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
	if (sds_bit_offset & (BITPBLOCK -1)) {
		/* The sds address is not on a block boundary. */
		/* Read data from sds to a local buffer. Copy the */
		/* user's memory to the appropriate part of the local */
		/* buffer, and write it back out to sds. */
		sds_bit_offset_blk = (sds_bit_offset & ~(BITPBLOCK - 1));
		if (ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset_blk), 1) == -1) {
			errno = FDC_ERR_SDSIO;
			return(-1);
		}
		rbits = MIN(nbits, BITPBLOCK - (sds_bit_offset -
			sds_bit_offset_blk));
		locptr = CPTR2BP(localbuf);
		SET_BPTR(locptr, INC_BPTR(locptr, sds_bit_offset - sds_bit_offset_blk));
		MOV_BITS(locptr, ubuf, rbits);
		SET_BPTR(ubuf, INC_BPTR(ubuf, rbits));
		nbits -= rbits;
		if(sswrite((int *)localbuf, BITS2BLOCKS(sds_bit_offset_blk), 1) == -1) {
			errno = FDC_ERR_SDSIO;
			return(-1);
		}
		SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits));
		if (nbits == 0)
			return(0);
		
		assert(((SUBT_BPTR(sdsaddr, WPTR2BP(0))) & (BITPBLOCK -1)) == 0);
	}
	sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
	uwaddr	 = BPTR2WP(ubuf);
	ucaddr	 = BPTR2CP(ubuf);
	if ((nbits & (BITPBLOCK-1)) || (ucaddr != (char *)uwaddr)){
		int left;

		locptr = CPTR2BP(localbuf);	

		/* round down nbits to a block boundary */
		rbits = nbits & ~(BITPBLOCK-1);
		if (rbits) {
			if (ucaddr != (char*)uwaddr) {
				/* ubuf is not word aligned. */
				left = rbits;
				sds_bit_offset_blk = BITS2BLOCKS(sds_bit_offset);
				while (left > 0) {
				   if( ssread((int *)localbuf,
				      sds_bit_offset_blk, 1) == -1) {
				      errno = FDC_ERR_SDSIO;
				      return(-1);
				   }
				   MOV_BITS(locptr, ubuf, BITPBLOCK);	
				   SET_BPTR(ubuf, INC_BPTR(ubuf, BITPBLOCK));

				   if( sswrite((int *)localbuf,
				      sds_bit_offset_blk, 1) == -1) {
				      errno = FDC_ERR_SDSIO;
				      return(-1);
				   }
				   SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, BITPBLOCK));
				   sds_bit_offset_blk++;
				   left-= BITPBLOCK;
				
				}
			}
			else {
				if (_sds_fr_mem(sdsaddr, ubuf, rbits) == -1) {
					return(-1);
				}
				SET_BPTR(ubuf, INC_BPTR(ubuf, rbits));
				SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits));
			}
                        sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
		}
		/* Get last block into local memory. Merge in user's memory */
		/* and write it back out to sds. */
	        if( ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset), 1) == -1) {
		      errno = FDC_ERR_SDSIO;
		      return(-1);
		}
		MOV_BITS(locptr, ubuf, nbits - rbits);	
	        if( sswrite((int *)localbuf, BITS2BLOCKS(sds_bit_offset), 1) == -1) {
		        errno = FDC_ERR_SDSIO;
			return(-1);
		}
	}
	else {
		if(sswrite(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(nbits)) == -1) {
			errno = FDC_ERR_SDSIO;
			return(-1);
		}
	}
	return(0);
}
Ejemplo n.º 8
0
/*
 * _any_mem_fr_sds moves data into user memory from a secondary data segment (SDS).
 *
 * unlike _mem_fr_sds, _any_mem_fr_sds handles moving a number of bits that
 * may not be a multiple of 512.
 *
 * Returns 0 on normal return, or else -1 with error code in errno.
 */
_any_mem_fr_sds(
bitptr  ubuf,		/* user buffer to receive data */
bitptr  sdsaddr,	/* SDS bit address of data */
int     nbits		/* number of bits to move */
)
{

	int sds_bit_offset;	
	int sds_bit_offset_blk;	
	int rbits;
	char localbuf[BYTPBLOCK];
	bitptr locptr;
	long *uwaddr;
	char *ucaddr;

	sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
	if (sds_bit_offset & (BITPBLOCK -1)) {
		/* The sds address is not on a block boundary. */
		/* Read data from sds to a local buffer. Copy the */
		/* appropriate part of the local buffer to user's memory. */
		sds_bit_offset_blk = (sds_bit_offset & ~(BITPBLOCK - 1));
		if(ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset_blk), 1) == -1) {
			errno = FDC_ERR_SDSIO;
			return(-1);
		}
		rbits = MIN(nbits, BITPBLOCK - (sds_bit_offset -
			sds_bit_offset_blk));
		locptr = CPTR2BP(localbuf);
		SET_BPTR(locptr, INC_BPTR(locptr, sds_bit_offset - sds_bit_offset_blk));
		MOV_BITS(ubuf, locptr, rbits);
		SET_BPTR(ubuf, INC_BPTR(ubuf, rbits));
		nbits -= rbits;
		SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits));
		if (nbits == 0)
			return(0);
		
		/* Verify that our sds address is now on a block boundary */
		assert (((SUBT_BPTR(sdsaddr, WPTR2BP(0))) & (BITPBLOCK -1)) == 0);
	}
	sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
	uwaddr	 = BPTR2WP(ubuf);
	ucaddr	 = BPTR2CP(ubuf);
	if ((nbits & (BITPBLOCK-1)) || (ucaddr != (char *)uwaddr)){
		int  left;

		/* Either we are not reading in a multiple of blocks or */
		/* the user's address is not word-aligned. */
		/* Round nbits down to a block boundary and */
		/* move those to user's memory. */

		locptr = CPTR2BP(localbuf);	
		rbits = nbits & ~(BITPBLOCK-1);
		if (rbits) {
			if (ucaddr != (char*)uwaddr) {
				/* ubuf is not word aligned. */
				/* Read the data from sds into a local */
				/* buffer and copy to the user's memory */
				left = rbits;
				sds_bit_offset_blk = BITS2BLOCKS(sds_bit_offset);
				while (left > 0) {
				   if (ssread((int *)localbuf,
				       sds_bit_offset_blk, 1) == -1) {
					errno = FDC_ERR_SDSIO;
					return(-1);
				   }
				   MOV_BITS(ubuf, locptr, BITPBLOCK);	
				   SET_BPTR(ubuf, INC_BPTR(ubuf, BITPBLOCK));
				   SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, BITPBLOCK));
				   sds_bit_offset_blk++;
				   left-= BITPBLOCK;
				}
			}
			else {
				if (ssread(uwaddr, BITS2BLOCKS(sds_bit_offset),
				   BITS2BLOCKS(rbits)) == -1) {
					errno = FDC_ERR_SDSIO;
					return(-1);
				}
				SET_BPTR(ubuf, INC_BPTR(ubuf, rbits));
				SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits));
			}
			sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
		}
		/* get last block into local memory and */
		/* transfer to 	user's memory */
		if (ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset), 1) == -1) {
			errno = FDC_ERR_SDSIO;
			return(-1);
		}
		assert((nbits - rbits) < BITPBLOCK);
		MOV_BITS(ubuf, locptr, nbits - rbits);	
	}
	else {
		if(ssread(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(nbits)) == -1) {
			errno = FDC_ERR_SDSIO;
			return(-1);
		}
	}
	return(0);
}
Ejemplo n.º 9
0
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);
			   }
			   }
Ejemplo n.º 10
0
/*
 * _cch_write
 *
 * Process write requests for the cache layer.
 *
 * Return value:
 *
 *	The number of bytes transferred is returned upon successful completion.
 *	If an error occurs, -1 is returned.
 *
 *	The stat->sw_stat field is set to FFCNT upon normal return.
 */
ssize_t
_cch_write(
    struct fdinfo	*fio, 		/* ffio file descriptor. */
    bitptr		datptr,		/* bit pointer to the user's data. */
    size_t		nbytes,		/* Nuber of bytes to be written. */
    struct ffsw	*stat,		/* pointer to status return word */
    int		fulp,		/* full or partial write mode flag */
    int		*ubcp 		/* pointer to unused bit count.  On return, */
    /* *ubcp is updated to contain the unused bit */
    /* count in the data returned. */
)
{
    off_t		cpos;		/* bit position in file */
    int64		moved;		/* number of bits transfered */
    int64		bytes_moved;	/* number of bytes transfered */
    int64		morebits;	/* bits moved in current iteration */
    int64		numblocks;	/* num of pages to process this iter */
    int		pgoff;
    off_t		fileaddr;
    off_t		eofaddr;
    int		gb_rd;		/* nonzero if pages must be read */
    int		valid;		/* nonzero if CCH_VALIDBUFFER should */
    /* be set */
    int64		nbits;
    int64		i;
    int		bs, nbu;
    off_t		olpos, endpos, endoff;
    bitptr		toptr;
    struct ffsw	locstat;
    struct fdinfo	*llfio;
    struct cch_f	*cch_info;
    struct cch_buf	*cubuf;
    int		err;
    short		firsteof = 0;
    short		setfirst;

    CCH_DEBUG(("_cch_write EN: nbytes=%d fulp=%d ubc=%d\n",nbytes,fulp,
               *ubcp));
    CLRSTAT(locstat);
    cch_info = (struct cch_f *)fio->lyr_info;
    nbits = BYTES2BITS(nbytes) - *ubcp;

    fio->rwflag = WRITIN;
#if	defined(__mips) || defined(_LITTLE_ENDIAN)
    /* Although this layer is capable of handling non-zero ubc */
    /* and bitptrs that aren't on a byte boundary, we are not */
    /* supporting this right now on mips systems. */
    if (*ubcp != 0) {
        err = FDC_ERR_UBC;
        goto err1_ret;
    }
    if ((BPBITOFF(datptr) & 07) != 0) {
        err = FDC_ERR_REQ;
        goto err1_ret;
    }
#endif

    if (nbits == 0) {			/* quick return for nbits == 0*/
        SETSTAT(stat, FFCNT, 0);
        return(0);
    }

    /*
     *	Move data from user to buffer
     */
    llfio	 = fio->fioptr;
    bs	 = cch_info->bsize;	/* bit size of each buffer */
    cpos	 = cch_info->cpos;	/* current file position */
    olpos    = cpos;		/* save original position */
    fileaddr = CCHFLOOR(cpos,bs);	/* bit offset within the file of the
					 * start of the current page */

    if (cpos > cch_info->fsize) {

        firsteof = 1;

        /* Is the page with eof in memory? */
        /* If so, zero out the portion beyond eof. */
        eofaddr = CCHFLOOR(cch_info->fsize, bs);
        CCH_FINDBLK(cch_info, eofaddr, cubuf);
        if (cubuf != NULL && (cubuf->flags & CCH_ZEROED) == 0) {
#ifdef CCH_SDS_SUPPORTED
            if (cch_info->optflags & CCHOPT_SDS) {
                /* should never happen */
                ERETURN(stat, FDC_ERR_INTERR, 0);
            }
#endif
            pgoff = cch_info->fsize - eofaddr; /* offset of eof */
            /* within the page */
            SET_BPTR(toptr, INC_BPTR(cubuf->buf, pgoff));
            morebits = bs - pgoff;
            if (morebits != 0) {
                CCH_MEMCLEAR(toptr, morebits);
            }
            cubuf->flags |= CCH_ZEROED;
        }
    }
    while (nbits > 0) {
        /*
         * Find the cache buffer assigned to the current page.  If
         * no buffer is currently assigned, then _cch_getblk assigns
         * one.
         */
        pgoff	  = cpos - fileaddr;	/* offset within the page */
        numblocks = 1;			/* number of of pages to prcess
						 * in this iteration */

        CCH_FINDBLK(cch_info, fileaddr, cubuf);

        if (cubuf == NULL) {	/* if data not buffer-resident*/

            if (nbits > cch_info->bypasssize
#ifdef CCH_SDS_SUPPORTED
                    && !(cch_info->optflags & CCHOPT_SDS)
#endif
               ) {
                /* Maybe we can bypass buffering */
                if ((morebits= _cch_bypass(cch_info, nbits, cpos,
                                           datptr, fileaddr, 'w', llfio, &locstat))>0)
                    goto adjust;
                else if (morebits < 0) {
                    /* Is it right to return the count */
                    /* in locstat? Because we might */
                    /* have read some data... */
                    goto er1;
                }
                /* we weren't able to bypass buffering */
            }

            morebits = nbits;
            endpos = cpos + morebits; /*1 bit past the end*/
            endoff = endpos - CCHFLOOR(endpos,bs);

            if (endpos > fileaddr + bs) {
                numblocks = (endpos-fileaddr-1)/bs + 1;
                nbu	  = cch_info->nbufs;
                /*
                 * Handle at most a cache full at a time
                 */
                if (numblocks > nbu) {
                    numblocks = nbu;
                    endpos    = fileaddr + nbu * bs;
                    endoff    = 0;
                    morebits  = endpos - cpos;
                }
            }

            /*
             * It is possible that the first or last
             * page must be read because the transfer
             * fills only part of these pages.  In each
             * iteration, _cch_getblk requires that
             * consecutive buffer pages must all be read,
             * or else all be assigned without pre-reading.
             * The following code breaks off the current
             * portion of the transfer when necessary to
             * accomplish this.
             */

            if (numblocks > 1) {

                if (numblocks == 2) {
                    if ((pgoff == 0) != (endoff == 0)) {
                        /* process only first page */
                        numblocks  = 1;
                        endoff     = 0;
                        morebits   = bs - pgoff;
                    }
                }
                else {
                    if (pgoff) {
                        /* process only first page */
                        numblocks  = 1;
                        endoff     = 0;
                        morebits   = bs - pgoff;
                    }
                    else if (endoff) {
                        /* process all but last page */
                        numblocks -= 1;
                        endoff     = 0;
                        morebits  -= endoff;
                    }
                }
            }

            /*
             * Request that _cch_getblk read in the file
             * pages if partial pages of data will be
             * written.
             */

            gb_rd = (pgoff || endoff);
            /* The pages will be valid if we do not */
            /* have to read them. That's because */
            /* we will be writing to the entire page */
            /* The page will also be valid if we do read it */
            valid = 1;
            setfirst = 0;
            if (gb_rd &&
#ifdef CCH_SDS_SUPPORTED
                    !(cch_info->optflags & CCHOPT_SDS) &&
#endif
                    (numblocks == 1) &&
                    ((fileaddr+bs) < cch_info->feof) &&
                    (_CCH_ALIGN(pgoff) && _CCH_ALIGN(endoff))) {
                /* do we really need to read the page in? */
                /* if pgoff and endoff are properly aligned, */
                /* we do not */
                /* Note that if any part of the page is */
                /* beyond feof, we want to read it in. */
                /* That's because code in _cch_rdabuf */
                /* that handles having a partially dirty */
                /* page expects to be able to read the */
                /* data preceding the dirty data */
                gb_rd = 0;
                valid = 0;	/* the page will not be valid */
                setfirst = 1;
            }
            cubuf = _cch_getblk(cch_info, llfio, fileaddr,
                                &numblocks, gb_rd, valid, &locstat);
            if (cubuf == NULL) {
                goto er1;
            }
            if (setfirst) {
                cubuf->firstdata = pgoff;
                if (endoff == 0)
                    cubuf->lastdata = bs;
                else
                    cubuf->lastdata = endoff;
            }

            if (firsteof  && pgoff != 0) {
                /* There is a gap between the eof and */
                /* this data. Zero it if necessary. */
                if ((cubuf->flags & CCH_ZEROED) == 0) {
                    int zbits;
#ifdef CCH_SDS_SUPPORTED
                    if (cch_info->optflags & CCHOPT_SDS) {
                        /* should never happen */
                        ERETURN(stat, FDC_ERR_INTERR, 0);
                    }
#endif
                    if ((eofaddr == fileaddr)) {
                        /* the eof is on this page */

                        zbits = bs - (cch_info->fsize - eofaddr);
                        SET_BPTR(toptr, INC_BPTR(cubuf->buf,
                                                 (cch_info->fsize - eofaddr)));
                    }
                    else {
                        /* the eof is not on this page */
                        /* zero the entire page */
                        zbits = bs;
                        toptr = cubuf->buf;
                    }
                    CCH_MEMCLEAR(toptr, zbits);
                    cubuf->flags |= CCH_ZEROED;
                }
            }
            morebits  = MIN(nbits, bs * numblocks - pgoff);

            /* remember the last buffer page for next time */
            cch_info->cubuf = cubuf + numblocks - 1;
        }
        else {
            morebits	= MIN(nbits, bs - pgoff);

            if (!(cubuf->flags & CCH_VALIDBUFFER)) {
                /* The buffer is there, but it */
                /* is not entirely valid, because */
                /* we never read into it. */
                /* We can continue to just dirty it, */
                /* provided that the dirty part is */
                /* contiguous, and is properly aligned */

                endoff = pgoff + morebits;
                if ((pgoff == cubuf->lastdata &&
                        _CCH_ALIGN(endoff))|| (endoff ==
                                               cubuf->firstdata && _CCH_ALIGN(pgoff))
                        || (pgoff >= cubuf->firstdata &&
                            endoff <=  cubuf->lastdata)) {
                    cubuf->firstdata = MIN(pgoff,
                                           cubuf->firstdata);
                    cubuf->lastdata = MAX(endoff,
                                          cubuf->lastdata);
                    if (cubuf->firstdata == 0 &&
                            cubuf->lastdata == bs) {
                        cubuf->lastdata = 0;
                        cubuf->flags |=CCH_VALIDBUFFER;
                    }
                } else {

                    /* We can't just keep on putting */
                    /* stuff in the buffer without  */
                    /* prereading it. So, we will call */
                    /* _cch_rdabuf, which has the */
                    /* smarts to read only the non-dirty */
                    /* parts */
                    if (_cch_rdabuf(cch_info, llfio, cubuf,
                                    BITS2BYTES(cch_info->bsize),
                                    BITS2BYTES(cubuf->filead), 1, 's',
                                    &locstat)) {
                        goto er1;
                    }
                }
            }
        }

        for (i=0; i<numblocks; i++) {
            /* adjust last access time */
            CCH_CHRONOMETER(cubuf[i],cch_info);
            cubuf[i].flags |= CCH_DIRTY;
        }

        SET_BPTR(toptr, INC_BPTR(cubuf->buf, pgoff));

#ifdef CCH_SDS_SUPPORTED
        if (cch_info->optflags & CCHOPT_SDS) {
            if (_sds_fr_mem(toptr, datptr, morebits) == ERR)
                ERETURN(stat, errno, 0);
        }
        else
            _CCH_MOV_BITS(toptr, datptr, morebits); /* contiguous bufs */
#else
        _CCH_MOV_BITS(toptr, datptr, morebits); /* contiguous bufs */
#endif
adjust:

        SET_BPTR(datptr, INC_BPTR(datptr, morebits));

        cpos  += morebits;
        nbits -= morebits;
        fileaddr = CCHFLOOR(cpos,bs);
        /* bit offset within the file of the page */
        firsteof = 0;
        if (cpos > cch_info->fsize) {
            cch_info->fsize = cpos;
        }
    }
    cch_info->cpos   = cpos;
    moved		 = cpos - olpos;
    fio->recbits	+= moved;


    bytes_moved = BITS2BYTES(moved);
    SETSTAT(stat, FFCNT, bytes_moved);
    return(bytes_moved);
err1_ret:
    ERETURN(stat, err, 0);
er1:
    *stat = locstat;
    return(ERR);
}