/* * 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; } }
/* * 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; } }
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; }
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; }