int smsa_vwrite( SMSA_VIRTUAL_ADDRESS addr, uint32_t len, unsigned char *buf ) { //all of the following variables are used so that we know //where the write should take place. These variables will //form a type of "bounds" for our write, and help us progress //through various loops so that the write can be completed SMSA_DRUM_ID drumStart, drumEnd, currentDrum; SMSA_BLOCK_ID blockStart, blockEnd, currentBlock; uint32_t byteStart, byteEnd, upperBound, lowerBound; unsigned char *temp; //variable to hold the value at the current block unsigned char *cacheLine; int bufferIndex = 0; //holds the current index of the buffer that we are reading from ERROR_SOURCE err = 0; //holds return values of function calls to checkForErrors //get the start and stop positions of the drum, block, and byte err = getDiskBlockParameters ( addr, len, &drumStart, &blockStart, &drumEnd, &blockEnd, &byteStart, &byteEnd ); //current drum and block allow us to move through //the while loop. Set them to the starting positions currentDrum = drumStart; currentBlock = blockStart; if ( DEBUG ) logMessage ( LOG_INFO_LEVEL,"Initialized currentDrum and currentBlock Initialized To drumStart %d, and blockStart %d", drumStart, blockStart ); //since during the while loop below, the drumHead won't //necessarily be set on the first run through, we must set //it here to ensure it is set to the correct position err = seekIfNeedTo ( currentDrum, currentBlock ); //this loop continues while we have not reached the end of (addr + len) //which is the place where the write will extend to. The conditions will //stop the loop, after the last block has been written too while( !( ( currentDrum == drumEnd && currentBlock == blockEnd+1 ) || ( currentDrum == drumEnd + 1 && currentBlock == 0 ) ) ) { //In order for the memory to be presevered through multiple calls of v //v_read/v_write, we must allocate the memory so that it remains on the stack //rather than vanishing when the function returns. temp = (unsigned char*) malloc ( SMSA_BLOCK_SIZE * sizeof ( char ) ); if ( DEBUG ) logMessage ( LOG_INFO_LEVEL, "Successfully Malloced [%d] Bytes of Data To temp", SMSA_BLOCK_SIZE*sizeof( char ) ); //This is where we decide the specific bytes ( letters ) //from the current block values that should be overwritten //this function sets the lowerBound and upperBound to the appropriate //values. err = findMemCpyBounds ( drumStart, blockStart, byteStart, drumEnd, blockEnd, byteEnd, currentDrum, currentBlock, &lowerBound, &upperBound ); //in order to handle a write, sometimes, we must //write only some of a given block. Therefore, we //have to first read whats currently at the block //and then overwrite the part of that block that we //need too using memcpy below. Don't want to waste //time reading if we are writing the entire block. If //we are writing the whole block, read will be skipped if ( !( lowerBound == 0 && upperBound == SMSA_BLOCK_SIZE) ) { //check cache first cacheLine = smsa_get_cache_line ( currentDrum, currentBlock ); if ( cacheLine == NULL ) { //if not in cache perform read //cache miss. read disk. err = readLowLevel ( temp ); //performance stats disk_reads++; } else { //otherwise copy the cache line into our temp //Now cacheLine contains the block that we were looking for //so set temp equal to it temp = cacheLine; //performance stats cache_hits++; } } //If we are writing only part of a block, then first we //need to read whats at that block currently. Then we //have to overwrite the intended bytes of what is currently //in the block. Which bytes must be overwritten is dependent //on findMemCpyBounds above. finally at the end, we write this //new, partially modified, version of the block to the same address. //If the whole block should be overwriten, the bounds will have //been set to completely overwrite temp with buf. memcpy ( &temp[lowerBound], &buf[bufferIndex], upperBound - lowerBound ); if ( DEBUG ) logMessage ( LOG_INFO_LEVEL, "Memcpy ( temp[%d], buf[%d], %d )", bufferIndex, lowerBound, upperBound-lowerBound ); //now that we have copied (upperBound-lowerBound) amount of //bytes into temp, we must make sure that we choose the correct //data to write to the block after this one. That means we need //to increase the position that getting our data from to just //after where we just took from. bufferIndex += upperBound - lowerBound; if ( DEBUG ) logMessage ( LOG_INFO_LEVEL, "BufferIndex Set From [%d] to [%d]", bufferIndex-(upperBound-lowerBound), bufferIndex); //since the block was incremented in the previous //smsa_operation (read) call, we need to set it back //to the desired write postion err = setBlockHead ( currentBlock ); //in all scenarios we write temp back to the current block //location. If only part of the current block should be //overwritten, then temp will contain the partially //modified version. If all of the current block should //be overwritten, then temp will contain 255 characters //from the buffer err = writeLowLevel ( temp ); //update the cache so that it contains our new block err = smsa_put_cache_line ( currentDrum, currentBlock, temp ); //check for errors during the loop, and at the end. This will allow us //to find where the errors occur, since were checking throughout the //entire process. However, we don't want to stop the program unless //a error was found. So, we will return 1, only if checkForErrors results in //one if ( checkForErrors ( err, "_vwrite", addr, len, drumStart, blockStart, currentDrum, currentBlock, drumEnd, blockEnd ) ) return 1; //increment the block currentBlock++; //if the current block is out of the bounds for the //disk size, then set the current block to zero, //and start reading the next disk if ( currentBlock == 256 ) { currentDrum++; currentBlock = 0; } //make sure the drum and block heads are properly set err = seekIfNeedTo( currentDrum, currentBlock ); } //if checkForErrors finds that err is non-zero, it will return 1. //see smsa_driver.h for error enum definition return ( checkForErrors ( err, "_vmount", DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE ) ); }
int smsa_vread( SMSA_VIRTUAL_ADDRESS addr, uint32_t len, unsigned char *buf ) { /* First check if the length is 0 */ // Write nothing and return if so if(len == 0) { return 0; } /* Initialize variables */ int i = 0; int err = 0; int read_bytes = 0; uint32_t offset; SMSA_DRUM_ID drum; SMSA_BLOCK_ID block; SMSA_BLOCK_ID block_orig; unsigned char *smsa_vread_buffer = NULL; drum = find_drum(addr); block = find_block(addr); block_orig = block; offset = addr & 0xff; seek_if_i_must(drum, block); // Loop to iterate through blocks do { /* Bounds checking */ // Check if drum is in bounds if( (drum > SMSA_DISK_ARRAY_SIZE) || (drum < 0) ) { logMessage( LOG_ERROR_LEVEL, "The drum is out of bounds [%d]\n", drum ); return -1; } // Check if block is in bounds if( (block > SMSA_MAX_BLOCK_ID) || (block < 0) ) { logMessage( LOG_ERROR_LEVEL, "The block is out of bounds [%d]\n", block ); return -1; } /* Is it the original block? */ // Yes - begin reading from offset // No - begin reading from beginning if( block == block_orig ) { i = offset; } else { i = 0; } /* Is it last block in the drum? */ if( block == SMSA_BLOCK_SIZE) { // Seek to the beginning of next drum block=0; curBlock = 0; drum++; seek_if_i_must(drum, block); } /* Is it in the cache? */ logMessage(LOG_INFO_LEVEL, "Asking cache at: drum[%d]\tblock[%d]\n", drum, block); smsa_vread_buffer = smsa_get_cache_line(drum, block); // If yes if(smsa_vread_buffer != NULL) { // Read into buf do { buf[read_bytes] = smsa_vread_buffer[i]; read_bytes++; i++; } while( (i<SMSA_BLOCK_SIZE) && (read_bytes<len) ); // seek next block block++; curBlock++; smsa_operation( SEEK_BLOCK, NULL ); } // If no else { // Allocate temp buffer smsa_vread_buffer = (unsigned char *) malloc(SMSA_BLOCK_SIZE * sizeof(unsigned char)); // Read from disk smsa_operation( DISK_READ, smsa_vread_buffer ); // Put into buf bit by bit do { buf[read_bytes] = smsa_vread_buffer[i]; read_bytes++; i++; } while( (i<SMSA_BLOCK_SIZE) && (read_bytes<len) ); // Add temp buffer into cache line logMessage(LOG_INFO_LEVEL, "Finding a place to put the cache entry...\n"); err = smsa_put_cache_line(drum, block, smsa_vread_buffer); block++; curBlock++; } if(err) { logMessage(LOG_ERROR_LEVEL, "Something bad happened in the cache :/\n"); return -1; } } while(read_bytes<len); return 0; }
int smsa_vread( SMSA_VIRTUAL_ADDRESS addr, uint32_t len, unsigned char *buf ) { //all of the following variables are used so that we know //where the read should take place. These variables will //form a type of "bounds" for our read, and help us progress //through various loops so that the write can be completed SMSA_DRUM_ID drumStart, drumEnd, currentDrum; SMSA_BLOCK_ID blockStart, blockEnd, currentBlock; uint32_t byteStart, byteEnd, upperBound, lowerBound; unsigned char *temp; unsigned char *cacheLine; //variable to hold the value at the current block int bufferIndex = 0; //holds the current index of the buffer that we are reading from ERROR_SOURCE err = 0; //holds return values of function calls to checkForErrors //get the start and stop positions of the drum, block and byte err = getDiskBlockParameters ( addr, len, &drumStart, &blockStart, &drumEnd, &blockEnd, &byteStart, &byteEnd ); //current drum and block allow us to move through //the while loop. Set them to the starting positions currentDrum = drumStart; currentBlock = blockStart; if ( DEBUG ) logMessage ( LOG_INFO_LEVEL,"Initialized currentDrum and currentBlock Tnitialized To drumStart %d, and blockStart %d", drumStart, blockStart ); //since during the while loop below, the drumHead won't //necessarily be set on the first run through, we must set //it here to ensure it is set to the correct position err = seekIfNeedTo ( currentDrum, currentBlock ); //this loop continues while we have not reached the end of (addr + len) //which is the place where the read will extend to. The conditions will //stop the loop, after the last block has been read while( !( ( currentDrum == drumEnd && currentBlock == blockEnd+1 ) || ( currentDrum == drumEnd + 1 && currentBlock == 0 ) ) ) { //In order for the memory to be presevered through multiple calls of v //v_read/v_write, we must allocate the memory so that it remains on the stack //rather than vanishing when the function returns. temp = (unsigned char*) malloc ( SMSA_BLOCK_SIZE * sizeof ( char ) ); if ( DEBUG ) logMessage ( LOG_INFO_LEVEL, "Successfully Malloced [%d] Bytes of Data To temp", SMSA_BLOCK_SIZE*sizeof( char ) ); //check cache first cacheLine = smsa_get_cache_line ( currentDrum, currentBlock ); //Since we don't know if the entire block should be //stored in buf, we need to put the entire contents //of the block in a temp, then we can decide which //bytes to copy to bu if ( cacheLine == NULL ) { //Cache miss, now read disk err = readLowLevel ( temp ) ; //Now that this is the most recently used block of memory, we //need to make sure that it is in the cache. err = smsa_put_cache_line ( currentDrum, currentBlock, temp ); //performance stats disk_reads++; } else { //cacheLine contains the block line we are looking for, //so assign this to temp for further use in teh function temp = cacheLine; //performance stats cache_hits++; } //now is where we decide the specific bytes ( letters ) //from the current block values that should be overwritten. //After this function call, lowerBound, and upperBound will be //set to the proper values in order for the memcpy to work err = findMemCpyBounds ( drumStart, blockStart, byteStart, drumEnd, blockEnd, byteEnd, currentDrum, currentBlock, &lowerBound, &upperBound ); //memcopy will copy all of the desired temp to buf. //This is all based on the lower and upper bounds which was //determined by the findMemCpyBounds above. The bufferIndex //will increase throughout each iteration of the while loop //in order to get a buffer of "len" size. How much of the //temp goes into the buffer is determined by the findMemCpyBounds //function above memcpy ( &buf[bufferIndex], &temp[lowerBound], upperBound - lowerBound ); if ( DEBUG ) logMessage ( LOG_INFO_LEVEL, "Memcpy ( buf[%d], temp[%d], %d )", bufferIndex, lowerBound, upperBound-lowerBound ); //now that we have copied (upperBound-lowerBound) amount of //bytes into buf, we must make sure that we do not overwrite //this data when we attempt to copy bytes from the next block. //That means we need to increase the position that were copying to, //to just after where we copied. bufferIndex += upperBound - lowerBound; if ( DEBUG ) logMessage ( LOG_INFO_LEVEL, "BufferIndex Set From [%d] to [%d]", bufferIndex-(upperBound-lowerBound), bufferIndex); //check for errors during the loop, and at the end. This will allow us //to find where the errors occur, since were checking throughout the //entire process. However, we don't want to stop the program unless //a error was found. So, we will return 1, only if checkForErrors results //in one if ( checkForErrors ( err, "_smsa_vread", addr, len, drumStart, blockStart, currentDrum, currentBlock, drumEnd, blockEnd ) ) return 1; //increment the block currentBlock++; //if the current block is out of the bounds for the //disk size (currentBlock > 256), then set the current //block to zero, and start reading the next disk if ( currentBlock == SMSA_BLOCK_SIZE ) { currentDrum++; currentBlock = 0; } //adjust the block and drum head if neccessary err = seekIfNeedTo ( currentDrum, currentBlock ); } //if checkForErrors finds that err is non-zero, it will return 1. //see smsa_driver.h for error enum definition return ( checkForErrors ( err, "_vread", DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE ) ); }
int smsa_vwrite( SMSA_VIRTUAL_ADDRESS addr, uint32_t len, unsigned char *buf ) { // First check if the length is 0 // Write nothing and return if so if(len == 0) { return 0; } /* Initialize variables */ int i; int err = 0; int read_bytes = 0; uint32_t offset; SMSA_DRUM_ID drum; SMSA_BLOCK_ID block; SMSA_BLOCK_ID block_orig; unsigned char *smsa_vwrite_buffer = NULL; drum = find_drum(addr); block = find_block(addr); block_orig = block; offset = addr & 0xff; seek_if_i_must(drum, block); // Loop to iterate through blocks do { /* Bounds Check */ // Check if drum is in bounds if( (drum > SMSA_DISK_ARRAY_SIZE) || (drum < 0) ) { logMessage( LOG_ERROR_LEVEL, "The drum is out of bounds [%d]\n", drum ); return -1; } // Check if block is in bounds if( (block > SMSA_MAX_BLOCK_ID) || (block < 0) ) { logMessage( LOG_ERROR_LEVEL, "The block is out of bounds [%d]\n", block ); return -1; } // Check if original block if( block == block_orig ) { i = offset; } else { i = 0; } // If last block if( (block == SMSA_BLOCK_SIZE) ) { block = 0; curBlock = 0; drum++; seek_if_i_must(drum, block); } /* Is it in the cache? */ logMessage(LOG_INFO_LEVEL, "Asking cache at: drum[%d]\tblock[%d]\n", drum, block); smsa_vwrite_buffer = smsa_get_cache_line(drum, block); // If Yes if(smsa_vwrite_buffer != NULL) { do { smsa_vwrite_buffer[i] = buf[read_bytes]; read_bytes++; i++; } while( (i<SMSA_BLOCK_SIZE) && (read_bytes<len) ); block++; curBlock++; /* smsa_operation( SEEK_BLOCK, NULL ); */ } // If No else { smsa_vwrite_buffer = (unsigned char *) malloc(SMSA_BLOCK_SIZE * sizeof(unsigned char)); // Read from disk smsa_operation( DISK_READ, smsa_vwrite_buffer); // Loop to write into buffer do { smsa_vwrite_buffer[i] = buf[read_bytes]; read_bytes++; i++; } while( (i<SMSA_BLOCK_SIZE) && (read_bytes<len) ); // Put into cache logMessage(LOG_INFO_LEVEL, "Finding a place to put the cache entry...\n"); err = smsa_put_cache_line(drum, block, smsa_vwrite_buffer); block++; curBlock++; } if(err) { logMessage(LOG_ERROR_LEVEL, "Something bad happened in the cache :/\n"); return -1; } // Write to disk smsa_operation( SEEK_PREVIOUS_BLOCK, NULL ); /* if(block == 0) { */ /* smsa_put_cache_line(drum-1, 255, smsa_vwrite_buffer); */ /* } else { */ /* smsa_put_cache_line(drum, block-1, smsa_vwrite_buffer); */ /* } */ smsa_operation( DISK_WRITE, smsa_vwrite_buffer ); } while(read_bytes<len); return 0; }