Example #1
0
/*
 * _sds_fr_mem moves data into SDS from user memory.
 *
 * Returns 0 on normal return, or else -1 with error code in errno.
 */
_sds_fr_mem(
bitptr  sdsaddr,	/* SDS bit address where data will be received */
bitptr  ubuf,		/* user buffer containing data */
int     nbits		/* number of bits to move */
)
{
	long sds_bit_offset;
	char *ucaddr;
	long *uwaddr;
	int  ret;
	
	if (nbits & (BITPBLOCK - 1)) {
		errno = FDC_ERR_GRAN;	/* must be block multiple */
		return -1;
	}

	ucaddr	 = BPTR2CP(ubuf);
	uwaddr	 = BPTR2WP(ubuf);
	if (ucaddr != (char*)uwaddr) {
		errno = FDC_ERR_SDSWB;	/* must be word-aligned */
		return -1;
	}

	sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0));
	if (sds_bit_offset & (BITPBLOCK - 1)) {
		errno = FDC_ERR_GRAN;	/* must be block multiple */
		return -1;
	}

	ret = sswrite(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(nbits));
	if (ret == -1)
		errno = FDC_ERR_SDSIO;
	return ret;
}
Example #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;
				}
			}
		}
	}
Example #3
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);
}
Example #4
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);
}