示例#1
0
/*
 * buffer is the start address in memory to be written from
 * if used in inode_write_at, buffer = 'buffer' + bytes_written
 * sector_ofs is the start point to actually write the buffer cache
 * chunk_size is the actual size to be written to buffer cache
 */
void write_via_cache(struct inode *inode, const uint8_t *buffer, 
		block_sector_t sector_idx, int sector_ofs, int chunk_size) {

	//lookup buffer and check if sector_indx exits in buffer cache
      int buffer_arr_indx = lookup_sector(sector_idx);	//lookup result indx for a valid sector in cache
	if (buffer_arr_indx > BUFFER_SIZE) {
		PANIC("lookup_sector wrong\n");
	}
      if (buffer_arr_indx >= 0){ 
		//if yes, just write buffer cache
	void *buffer_cache_start_addr = buffer_vaddr + buffer_arr_indx * BLOCK_SECTOR_SIZE + sector_ofs;
        memcpy (buffer_cache_start_addr, (void *)buffer, chunk_size);
      } else {			//the sector_idx is not in buffer cache
	//check if empty sector exists in buffer cache
	int buffer_indx = lookup_empty_buffer();
	if (buffer_indx == -1) {
		//if no, evict sector from buffer cache, and get its indx 
		//choose a sector to evict
		//lookup_evict contains 'clock algorithm'
		//lookup_evict() takes care of case when buffer_evict_indx == -1
		int buffer_evict_indx = lookup_evict(); 
			//buffer_evict_indx should be a valid indx
		buffer_evict_indx = buffer_evict(buffer_evict_indx); 
		buffer_indx = buffer_evict_indx;
	}
		//buffer_cache_start_addr is the start addr of buffer cache sector
	void *buffer_cache_start_addr = buffer_vaddr + buffer_indx * BLOCK_SECTOR_SIZE;
		//get sector from disk to buffer cache
		//copy the sector from disk to buffer cache

      	if (sector_ofs != 0 || chunk_size != BLOCK_SECTOR_SIZE) {
         		// Write partial sector cache, need to fetch from disk first. 
        	block_read (fs_device, sector_idx, buffer_cache_start_addr);
	}
		//change buffer_cache_start_addr to the offset of buffer cache sector
	buffer_cache_start_addr += sector_ofs;
		//write sector to buffer cache 
		//copy the sector from buffer cache to buffer_read
        memcpy (buffer_cache_start_addr, (void *)buffer, chunk_size);

		//fill the info into buffer_info_array
	buffer_info_array[buffer_indx].sector_num = sector_idx;
	buffer_info_array[buffer_indx].buffer_inode = inode;
	buffer_info_array[buffer_indx].dirty = true;
	buffer_info_array[buffer_indx].recentlyUsed = true;

      }
}
示例#2
0
/*
 * buffer is the start address in memory to be read from
 * if used in inode_read_at, buffer = 'buffer' + bytes_read
 * sector_ofs is the start point to actually read from the buffer cache
 * chunk_size is the actual size to be read to buffer cache
 */
void read_via_cache(struct inode *inode, uint8_t *buffer, 
		block_sector_t sector_idx, int sector_ofs, int chunk_size) {

	//printf("sector_idx %d, size %d\n", sector_idx, size);
      int buffer_arr_indx = lookup_sector(sector_idx);	//lookup result indx for a valid sector in cache
	if (buffer_arr_indx > BUFFER_SIZE) {
		PANIC("lookup_sector wrong\n");
	}
//	printf("sector_idx %d\n", sector_idx);
      if (buffer_arr_indx >= 0){ 
//	printf("indx %d, sector_idx %d size %d\n", buffer_arr_indx, sector_idx, size);
	
	void *buffer_cache_start_addr = buffer_vaddr + buffer_arr_indx * BLOCK_SECTOR_SIZE + sector_ofs;
	memcpy((void *)buffer, buffer_cache_start_addr, chunk_size);
      } else {			//the sector_idx is not in buffer cache
	//printf("new start\n");
	int buffer_indx = lookup_empty_buffer();
	if (buffer_indx == -1) {
		//choose a sector to evict
		//lookup_evict contains 'clock algorithm'
		//lookup_evict() takes care of case when buffer_evict_indx == -1
		int buffer_evict_indx = lookup_evict(); 
			//buffer_evict_indx should be a valid indx
		buffer_evict_indx = buffer_evict(buffer_evict_indx); 
		buffer_indx = buffer_evict_indx;
		//printf("evicting!\n");
	}
		//buffer_cache_start_addr is the start addr of buffer cache sector
	void *buffer_cache_start_addr = buffer_vaddr + buffer_indx * BLOCK_SECTOR_SIZE;
		//copy the sector from disk to buffer cache
        block_read (fs_device, sector_idx, buffer_cache_start_addr);
		//change buffer_cache_start_addr to the offset of buffer cache sector
	buffer_cache_start_addr += sector_ofs;
		//copy the sector from buffer cache to buffer_read
        memcpy ((void *)buffer, buffer_cache_start_addr, chunk_size);

		//fill the info into buffer_info_array
	if(sector_idx < -2)
	buffer_info_array[buffer_indx].sector_num = sector_idx;
	buffer_info_array[buffer_indx].buffer_inode = inode;
	buffer_info_array[buffer_indx].dirty = false;
	buffer_info_array[buffer_indx].recentlyUsed = true;
      }

}
示例#3
0
dsk_err_t ldbsdisk_xwrite(DSK_DRIVER *pdriver, const DSK_GEOMETRY *geom, 
			  const void *buf, 
			  dsk_pcyl_t cylinder,   dsk_phead_t head, 
			  dsk_pcyl_t cyl_expect, dsk_phead_t head_expect,
			  dsk_psect_t sector, size_t size_expect,
			  int deleted)
{
	dsk_err_t err;
	LDBSDISK_DSK_DRIVER *self;
	int n;
	size_t size_actual = size_expect;
	int allsame;
	LDBS_SECTOR_ENTRY *cursec;
	unsigned char *data = (unsigned char *)buf;
	
	if (!buf || !geom || !pdriver) return DSK_ERR_BADPTR;
	DC_CHECK(pdriver)
	self = (LDBSDISK_DSK_DRIVER *)pdriver;
	
	if (self->ld_readonly) return DSK_ERR_RDONLY;

	/* See if the requested sector contains all the same values */
	allsame = 1;
	for (n = 1; n < (int)size_expect; n++)
	{
		if (data[n] != data[0]) 
		{
			allsame = 0;
			break;
		}
	}

	/* See if the requested cylinder exists */
	err = ldbsdisk_select_track(self, cylinder, head);
	if (err) return err;	

	if (!self->ld_cur_track) return DSK_ERR_NOADDR;

	/* Check the track was recorded with the requested density and
	 * recording mode */
	err = check_density(self, geom);
	if (err) return err;

	err = lookup_sector(self, cyl_expect, head_expect, sector,
					size_expect, &size_actual, &cursec);

	if (err != DSK_ERR_DATAERR && err != DSK_ERR_OK) return err;

	/* Sector found! */
	if (allsame)
	{
		/* This is a blank sector. Record it as blank in the header,
		 * and wipe it from the disk file */
		cursec->filler = data[0];
		cursec->copies = 0;
		if (cursec->blockid != LDBLOCKID_NULL)
		{
			err = ldbs_delblock(self->ld_store, cursec->blockid);
			cursec->blockid = LDBLOCKID_NULL;
		}
	}
	else
	{
		/* This is a non-blank sector. Write it to the file. */
		char type[4];

		type[0] = 'S';
		type[1] = cylinder;
		type[2] = head;
		type[3] = sector;

		cursec->copies = 1;	/* We don't support multiple copies */
		cursec->trail  = 0;	/* We don't support trailing bytes */
		err = ldbs_putblock(self->ld_store, &cursec->blockid, type,
				buf, size_expect);
	}

	self->ld_cur_track->dirty = 1;
	return err;
}
示例#4
0
dsk_err_t ldbsdisk_xread(DSK_DRIVER *pdriver, const DSK_GEOMETRY *geom, void *buf, 
		       dsk_pcyl_t cylinder,   dsk_phead_t head, 
		       dsk_pcyl_t cyl_expect, dsk_phead_t head_expect,
		       dsk_psect_t sector, size_t size_expect, int *deleted)
{
	dsk_err_t err;
	LDBSDISK_DSK_DRIVER *self;
	int n;
	int rdeleted = 0;
	size_t size_actual = size_expect;
	int try_again = 0;
	LDBS_SECTOR_ENTRY *cursec = NULL;
	unsigned char *result = (unsigned char *)buf;
	
	if (!buf || !geom || !pdriver) return DSK_ERR_BADPTR;
	DC_CHECK(pdriver)
	self = (LDBSDISK_DSK_DRIVER *)pdriver;

	/* See if the requested cylinder exists */
	err = ldbsdisk_select_track(self, cylinder, head);
	if (err) return err;	

	if (!self->ld_cur_track) return DSK_ERR_NOADDR;

	/* Check the track was recorded with the requested density and
	 * recording mode */
	err = check_density(self, geom);
	if (err) return err;

	/* Check if we're supposed to be reading deleted sectors */
	if (deleted && *deleted) rdeleted = 0x40;

	do
	{
		err = lookup_sector(self, cyl_expect, head_expect, sector,
					size_expect, &size_actual, &cursec);

/* Are we retrying because we are looking for deleted data and found 
 * nondeleted or vice versa?
 *
 * If so, and we have run out of sectors in this track, AND we are on head 0,
 * AND the disc has 2 heads, AND we are in multitrack mode, then look on head 1
 * as well. Amazing.
 * */
                if (try_again == 1 && !cursec)
                {
                        err = DSK_ERR_NODATA;
                        if ((!geom->dg_nomulti) && head == 0)
                        {
/* OK, we're in multitrack mode and on head 0. Try to load headers for 
 * head 1 */
                                head++;
				err = ldbsdisk_select_track(self, cylinder, head);
				if (err) return err;	
				err = check_density(self, geom);
				if (err) return err;
				if (!self->ld_cur_track) return DSK_ERR_NOADDR;
                                sector = geom->dg_secbase;
                                continue;
                        }
                }
		try_again = 0;
		if (err == DSK_ERR_NOADDR) self->ld_sector = 0;

		/* If we couldn't find the sector at all, don't try to
		 * read it */
		if (err != DSK_ERR_DATAERR && err != DSK_ERR_OK)
			return err;

		if (deleted) *deleted = 0;

		if (rdeleted != (cursec->st1 & 0x40))
		{
			/* We want non-deleted and got deleted, or vice versa */
			if (geom->dg_noskip)
			{
				if (deleted) *deleted = 0;
			}
			else
			{
				try_again = 1;
				++sector;
				continue;
			}
		}

		/* OK. cursec does appear to be pointing at an 
		 * actual sector. Is the sector blank? */
		if (cursec->copies == 0 || cursec->blockid == LDBLOCKID_NULL)
		{
			for (n = 0; n < (int)size_actual; n++)
			{
				result[n] = cursec->filler;
			}	
		}
		else
		{
			/* Sector really exists. Load it. */
			unsigned char *secbuf;
			size_t sblen;
			size_t offset = 0;
			char sbtype[4];
			dsk_err_t err2;		
	
			err2 = ldbs_getblock_a(self->ld_store, cursec->blockid,
					sbtype, (void **)&secbuf, &sblen);
			if (err2) return err2;

			/* Size on disk is smaller than expected size? */
			if (size_actual > sblen)
			{
				size_actual = sblen;
				if (!err) err = DSK_ERR_DATAERR;
			}
			/* Offset for multiple copies */
			if (cursec->copies > 1)
			{
				offset = (rand() % cursec->copies) * 
					(128 << cursec->id_psh);
			}
			/* Should never happen! */
			if (offset + size_actual > sblen)
			{
				offset = 0;
			}	
		
			memcpy(result, secbuf + offset, size_actual);
			ldbs_free(secbuf);	
		}

		/* LDBS disks, like CPCEMU disks, can record errors made at
		 * the time of imaging */
		if (err == DSK_ERR_OK && 
			((cursec->st1 & 0x01) || (cursec->st2 & 0x01)))
		{
			err = DSK_ERR_NOADDR;
		}
		if (err == DSK_ERR_OK && (cursec->st1 & 0x04))
		{
			err = DSK_ERR_NODATA;
		}
		if (err == DSK_ERR_OK && 
			((cursec->st1 & 0x20) || (cursec->st2 & 0x20)))
		{
			err = DSK_ERR_DATAERR;
		}

	}
	while (try_again);
	return err;

}