// Writing the indirect block to disk void update_inode_pointers(int inode_index, int *array_blockptr, int num_pointers){ if(num_pointers <= INODE_POINTERS-1){ //direct pointers only 1-12 int i; for(i=0;i<num_pointers-1;i++){ inodes[inode_index].pointers[i]=array_blockptr[i]; } } else{//hanles the indirect pointer int i; for(i=0;i<INODE_POINTERS-1;i++){ inodes[inode_index].pointers[i]=array_blockptr[i]; } int buffer[BLOCKSIZE/sizeof(int)]; memset(buffer,0,BLOCKSIZE); if(inodes[inode_index].pointers[INODE_POINTERS-1]!=0){ //append indirect pointer read_blocks(inodes[inode_index].pointers[INODE_POINTERS-1],1,buffer); int initial_number_of_indirects=get_num_pointers_inode(inode_index)-INODE_POINTERS; int final_number_of_indirects=num_pointers-INODE_POINTERS+1; int k; for(k=0;k<(final_number_of_indirects-initial_number_of_indirects)-1;k++){ buffer[k+initial_number_of_indirects]=array_blockptr[(INODE_POINTERS-1)+initial_number_of_indirects+k]; } write_blocks(inodes[inode_index].pointers[INODE_POINTERS-1],1,buffer); } else { //find a free block for indirect pointer int free_block=findfreeblock(); inodes[inode_index].pointers[INODE_POINTERS-1]=free_block; markfreeblock(free_block); //mark it as occupied //write inodes pointer into that block int j; for(j=0;j<(num_pointers-INODE_POINTERS+1)-1;j++){ buffer[j]=array_blockptr[(INODE_POINTERS-1)+j]; } write_blocks(free_block,1,buffer); } } }
int sfs_fwrite(int fileID, const char *buf, int length){ int inode_index = dir_table[fileID].inode_number; int num_bytes_to_be_written=0; //index of rw pointers which points to the current block of inode int rw_index = file_des_t[fileID].rw_pointer/BLOCKSIZE+1; //rw pointer offset within its current block int rw_offset = file_des_t[fileID].rw_pointer%BLOCKSIZE; //calculate number of blocks to be written int num_blocks; if(length<BLOCKSIZE-rw_offset){ num_blocks=1; } else{ num_blocks=(length-(BLOCKSIZE-rw_offset))/BLOCKSIZE+2; //+2 for the first & last partial blocks } //writing to an empty file. if(inodes[inode_index].pointers[0]==0){ //If file is empty all inode pointers will be zero int num_bytes_to_be_written = 0; int inode_index=dir_table[fileID].inode_number; int num_blocks=length/(BLOCKSIZE)+1; if(num_blocks<=(INODE_POINTERS-1)){ //don't need the indirect pointer int j; char write_block_buffer[BLOCKSIZE]; for(j=0;j<num_blocks-1;j++){ //reset buffer memset(write_block_buffer,0,BLOCKSIZE); memcpy(write_block_buffer,buf,BLOCKSIZE); inodes[inode_index].pointers[j]=findfreeblock(); int flag = write_blocks(inodes[inode_index].pointers[j],1,write_block_buffer); if(flag){ //if write into disk successfully,count the number of bytes written num_bytes_to_be_written = num_bytes_to_be_written + BLOCKSIZE; } //upodate the bitmap markfreeblock(inodes[inode_index].pointers[j]); } //last block could be a partial block char direct_pointer_buf_last[BLOCKSIZE]; memset(direct_pointer_buf_last,0,BLOCKSIZE); memcpy(direct_pointer_buf_last, buf+(num_blocks-1)*BLOCKSIZE, length % BLOCKSIZE); //find a free block for the last direct pointer int last_direct_pointer = findfreeblock(); markfreeblock(last_direct_pointer); inodes[inode_index].pointers[num_blocks-1] = last_direct_pointer; //if write into disk successfully then count the number of bytes int flag = write_blocks(last_direct_pointer,1,direct_pointer_buf_last); if(flag){ num_bytes_to_be_written = num_bytes_to_be_written + length%BLOCKSIZE; } //update the information in file descriptor table file_des_t[fileID].rw_pointer = file_des_t[fileID].rw_pointer + length; inodes[inode_index].size = inodes[inode_index].size + num_bytes_to_be_written; //update info on the disk int inode_number = inode_index; int block_of_inode=inode_number/8+1; char inode_update_buf[BLOCKSIZE]; memset(inode_update_buf,0, BLOCKSIZE); read_blocks(block_of_inode, 1, inode_update_buf); memcpy((void *)inode_update_buf+(inode_number%8)*sizeof(INODE),(const void *) &inodes[inode_number], sizeof(INODE)); write_blocks(block_of_inode, 1, inode_update_buf); write_blocks(TOTAL_NUM_BLOCKS-1,1,free_bitmap); return num_bytes_to_be_written; } else{ //else need the indirect pointer int m; char write_block_buffer[BLOCKSIZE]; //handle all the direct pointer firstly,similar as the above for(m=0;m<INODE_POINTERS-1;m++){ memset(write_block_buffer,0,BLOCKSIZE); memcpy(write_block_buffer,buf,BLOCKSIZE); inodes[inode_index].pointers[m]=findfreeblock(); int flag=write_blocks(inodes[inode_index].pointers[m],1,write_block_buffer); if(flag){num_bytes_to_be_written+=BLOCKSIZE;} markfreeblock(inodes[inode_index].pointers[m]); } //now let's handle the indirect pointer int num_indirect_pointers = num_blocks-(INODE_POINTERS-1); //get free blocks for indirect pointer int freeblock_indirect = findfreeblock(); markfreeblock(freeblock_indirect); int arr_of_indirectptr[num_indirect_pointers]; int k; //write the remaining data to the indirect blocks char indirect_pointer_buf[BLOCKSIZE]; for(k=0;k<num_indirect_pointers-1;k++){ arr_of_indirectptr[k] = findfreeblock(); memset(indirect_pointer_buf,0,BLOCKSIZE); memcpy(indirect_pointer_buf, buf+(INODE_POINTERS-1)*BLOCKSIZE + k*BLOCKSIZE, BLOCKSIZE); int flag=write_blocks(arr_of_indirectptr[k],1,indirect_pointer_buf); if(flag){num_bytes_to_be_written+=BLOCKSIZE;} markfreeblock(arr_of_indirectptr[k]); } //handle partial indirect block int last_indirect_pointers = findfreeblock(); arr_of_indirectptr[num_indirect_pointers-1] = last_indirect_pointers; markfreeblock(last_indirect_pointers); char last_indirect_pointer_buf[BLOCKSIZE]; memset(last_indirect_pointer_buf,0,BLOCKSIZE); memcpy(last_indirect_pointer_buf,buf+(INODE_POINTERS-1)*BLOCKSIZE+(num_indirect_pointers-1)*BLOCKSIZE,length%BLOCKSIZE); int flag = write_blocks(arr_of_indirectptr[num_indirect_pointers-1],1,last_indirect_pointer_buf); if(flag){ num_bytes_to_be_written = num_bytes_to_be_written + length%BLOCKSIZE; } //Write the indirect pointers to the indirect block char indirect_buffer[BLOCKSIZE]; memset(indirect_buffer,0,BLOCKSIZE); memcpy(indirect_buffer,arr_of_indirectptr,num_indirect_pointers*sizeof(int)); write_blocks(freeblock_indirect,1,indirect_buffer); inodes[inode_index].pointers[INODE_POINTERS-1]=freeblock_indirect; file_des_t[fileID].rw_pointer = file_des_t[fileID].rw_pointer + length; inodes[inode_index].size = inodes[inode_index].size + num_bytes_to_be_written; //update all the info into the disk int inode_number = inode_index; int block_of_inode = inode_number/8+1; char inode_update_buf[BLOCKSIZE]; memset(inode_update_buf,0, BLOCKSIZE); read_blocks(block_of_inode, 1, inode_update_buf); memcpy((void *)inode_update_buf+(inode_number%8)*sizeof(INODE),(const void *) &inodes[inode_number], sizeof(INODE)); write_blocks(block_of_inode, 1, inode_update_buf); write_blocks(TOTAL_NUM_BLOCKS-1,1,free_bitmap); return num_bytes_to_be_written; } } //file not empty int number_pointers; if(get_num_pointers_inode(inode_index)>INODE_POINTERS-1){ //first ignore the indrect pointers if it is used number_pointers = get_num_pointers_inode(inode_index)-1; } else{ number_pointers = get_num_pointers_inode(inode_index); } int array_blockptr[number_pointers]; get_pointers(inode_index,array_blockptr,number_pointers); int num_unchanged_blocks = rw_index; //Update all those blocks int updated_array_blockptr[num_blocks + num_unchanged_blocks]; memset(updated_array_blockptr,0,num_blocks*sizeof(int)); //Copy the unchanged blocks int p; for(p = 0; p < rw_index-1; p++){ updated_array_blockptr[p] = array_blockptr[p]; } int s; for(s=rw_index-1; s<((num_blocks+num_unchanged_blocks)-1); s++){ //Allocate additional free blocks when s>total intial blocks if(s>number_pointers-1){ //free block is not enough, find more if(s==(num_blocks+num_unchanged_blocks-2)){ //last block need to do a partial write int free_block = findfreeblock(); updated_array_blockptr[s] = free_block; markfreeblock(free_block); if(num_blocks==1){ update_block(updated_array_blockptr[s],(char*)(buf+(BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index-1)),0,length); num_bytes_to_be_written=num_bytes_to_be_written+length; } else{ if((BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index)<0){ return -1;//write in last block } update_block(updated_array_blockptr[s],(char*)(buf+(BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index)),0,(length-(BLOCKSIZE-rw_offset))%BLOCKSIZE); num_bytes_to_be_written = num_bytes_to_be_written + (length-(BLOCKSIZE-rw_offset)) % BLOCKSIZE; } } else{ int free_block = findfreeblock(); updated_array_blockptr[s] = free_block; markfreeblock(free_block); update_block(updated_array_blockptr[s],(char*)(buf+(BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index)),0,BLOCKSIZE); num_bytes_to_be_written = num_bytes_to_be_written + BLOCKSIZE; } } else{ markfreeblock(array_blockptr[s]); updated_array_blockptr[s] = array_blockptr[s]; if(s==rw_index-1){ //Overwriting the first block of write if(num_blocks==1){ //if only updating one block - will not be filling the first block of the write. update_block(array_blockptr[s],(char*)buf,rw_offset,length); num_bytes_to_be_written = num_bytes_to_be_written + length; } else{ update_block(array_blockptr[s],(char*)buf,rw_offset,BLOCKSIZE-rw_offset); num_bytes_to_be_written = num_bytes_to_be_written + BLOCKSIZE-rw_offset; } } else if(s==(num_blocks + num_unchanged_blocks-2)){ //last block may be partial if(num_blocks==1){ //special case for one block write. update_block(updated_array_blockptr[s],(char*)(buf+(BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index-1)),0,length); num_bytes_to_be_written = num_bytes_to_be_written+length; } else{ update_block(updated_array_blockptr[s],(char*)(buf+(BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index-1)),0,(length-(BLOCKSIZE-rw_offset))%BLOCKSIZE); num_bytes_to_be_written = num_bytes_to_be_written+(length-(BLOCKSIZE-rw_offset))%BLOCKSIZE; } } else{ //overwriting a full block update_block(array_blockptr[s],(char *)(buf+(BLOCKSIZE-rw_offset)+BLOCKSIZE*(s-rw_index-1)),0,BLOCKSIZE); num_bytes_to_be_written = num_bytes_to_be_written+BLOCKSIZE; } } } //storing the block pointers and put updated_array_blockptr into inode update_inode_pointers(inode_index,updated_array_blockptr,num_blocks+num_unchanged_blocks); int f_num_pointers = get_num_pointers_inode(inode_index); if(f_num_pointers > INODE_POINTERS-1){ //exclude superblock if it is used f_num_pointers--; } int final_inode_pointers[f_num_pointers]; get_pointers(inode_index,final_inode_pointers,f_num_pointers); file_des_t[fileID].rw_pointer+=length; inodes[inode_index].size = return_filesize(inode_index); //writing into disk int inode_number = inode_index; int block_of_inode=inode_number/8+1; char inode_update_buf[BLOCKSIZE]; memset(inode_update_buf,0, BLOCKSIZE); read_blocks(block_of_inode, 1, inode_update_buf); memcpy((void *)inode_update_buf+(inode_number%8)*sizeof(INODE),(const void *) &inodes[inode_number], sizeof(INODE)); write_blocks(block_of_inode, 1, inode_update_buf); write_blocks(TOTAL_NUM_BLOCKS-1,1,free_bitmap); return num_bytes_to_be_written; }
OSCL_EXPORT_REF void OsclMemPoolResizableAllocator::deallocate(OsclAny* aPtr) { // Check that the returned pointer is from the memory pool if (validateblock(aPtr) == false) { OSCL_LEAVE(OsclErrArgument); } // Retrieve the block info header and validate the info uint8* byteptr = (uint8*)aPtr; MemPoolBlockInfo* retblock = (MemPoolBlockInfo*)(byteptr - iBlockInfoAlignedSize); OSCL_ASSERT(retblock != NULL); OSCL_ASSERT(retblock->iBlockPreFence == OSCLMEMPOOLRESIZABLEALLOCATOR_PREFENCE_PATTERN); OSCL_ASSERT(retblock->iBlockPostFence == OSCLMEMPOOLRESIZABLEALLOCATOR_POSTFENCE_PATTERN); // Return the block to the memory pool buffer deallocateblock(*retblock); --(retblock->iParentBuffer->iNumOutstanding); // Check if user needs to be notified when block becomes available if (iCheckNextAvailable) { // Check if user is waiting for certain size if (iRequestedNextAvailableSize == 0) { // No so just make the callback iCheckNextAvailable = false; if (iObserver) { iObserver->freeblockavailable(iNextAvailableContextData); } } else { // Check if the requested size is available now if (findfreeblock(iRequestedNextAvailableSize + iBlockInfoAlignedSize) != NULL) { iCheckNextAvailable = false; if (iObserver) { iObserver->freeblockavailable(iNextAvailableContextData); } } else if (iRequestedNextAvailableSize > iMemPoolBufferSize) { // The requested size is bigger than the set buffer size // Check if there is space to grow the buffer, if (iMemPoolBufferNumLimit == 0 || iMemPoolBufferList.size() < iMemPoolBufferNumLimit) { // Available iCheckNextAvailable = false; if (iObserver) { iObserver->freeblockavailable(iNextAvailableContextData); } } else { // Not available so see if there is a buffer with // no outstanding buffers which can be destroyed // in the next allocate() call. bool emptybufferfound = false; for (uint32 j = 0; j < iMemPoolBufferList.size(); ++j) { if (iMemPoolBufferList[j]->iNumOutstanding == 0) { emptybufferfound = true; break; } } if (emptybufferfound) { iCheckNextAvailable = false; if (iObserver) { iObserver->freeblockavailable(iNextAvailableContextData); } } } } } } if (iCheckFreeMemoryAvailable) { if (iRequestedAvailableFreeMemSize == 0) { // No so just make the callback iCheckFreeMemoryAvailable = false; if (iFreeMemPoolObserver) { iFreeMemPoolObserver->freememoryavailable(iFreeMemContextData); } } else { // Check if the requested size is available now if (getAvailableSize() >= iRequestedAvailableFreeMemSize) { iCheckFreeMemoryAvailable = false; if (iFreeMemPoolObserver) { iFreeMemPoolObserver->freememoryavailable(iFreeMemContextData); } } } } // Decrement the refcount since deallocating succeeded removeRef(); }
OSCL_EXPORT_REF OsclAny* OsclMemPoolResizableAllocator::allocate(const uint32 aNumBytes) { MemPoolBlockInfo* freeblock = NULL; uint32 alignednumbytes = oscl_mem_aligned_size(aNumBytes); if (aNumBytes == 0) { OSCL_LEAVE(OsclErrArgument); // OSCL_UNUSED_RETURN(NULL); This statement was removed to avoid compiler warning for Unreachable Code } // Find a free block that would accomodate the requested size with a block info header freeblock = findfreeblock(alignednumbytes + iBlockInfoAlignedSize); if (freeblock == NULL) { //We could not find a free buffer of requested size. This could be due to: //1) We have not created even a single parent chunk (or in other words this is the first allocation) //2) We are out of memory and might need to expand // Check if the requested size is bigger than the specified buffer size // Some of the users of this allocator, count on the allocator to expand beyond the original size // specified in the constructor. These users do NOT use setMaxSzForNewMemPoolBuffer to control expansion size. // If they did then it is wrong usage and we fail the allocation. // For example the allocator was intialized with 200KB size, // and overtime a request is made for say 300KB. Users of the allocator expect the allocator to do one of the following: // 1) If iMemPoolBufferNumLimit has been set and it has been reached then see // if one of older blocks can be freed up and we allocate a new block of 300KB. If we cannot then alloc will fail. // 2) If iMemPoolBufferNumLimit has not set then simply allocate a new block of 300 KB. Note that if iMemPoolBufferNumLimit // is not set allocator expands indefinitely. if (alignednumbytes > iMemPoolBufferSize) { if (iMaxNewMemPoolBufferSz != 0) { //wrong usage - fail allocation if (iEnableNullPtrReturn) { return NULL; } else { // Leave with resource limitation OSCL_LEAVE(OsclErrNoResources); } } // Would need to create a new buffer to accomodate this request // Check if another buffer can be created if (iMemPoolBufferNumLimit > 0 && iMemPoolBufferList.size() >= iMemPoolBufferNumLimit) { // Check if there is a memory pool buffer that has no outstanding buffers // If present then remove it so a new one can be added bool emptybufferfound = false; for (uint32 j = 0; j < iMemPoolBufferList.size(); ++j) { if (iMemPoolBufferList[j]->iNumOutstanding == 0) { // Free the memory if (iMemPoolBufferAllocator) { iMemPoolBufferAllocator->deallocate((OsclAny*)iMemPoolBufferList[j]); } else { OSCL_FREE((OsclAny*)iMemPoolBufferList[j]); } // Remove the mempool buffer from the list iMemPoolBufferList.erase(iMemPoolBufferList.begin() + j); emptybufferfound = true; break; } } // Need to leave and return if empty buffer not found if (!emptybufferfound) { if (iEnableNullPtrReturn) { return NULL; } else { // Leave with resource limitation OSCL_LEAVE(OsclErrNoResources); } } // Continue on to create a new buffer OSCL_ASSERT(iMemPoolBufferList.size() < iMemPoolBufferNumLimit); } // Determine the size of memory pool buffer and create one uint32 buffersize = alignednumbytes + iBufferInfoAlignedSize; if (iExpectedNumBlocksPerBuffer > 0) { buffersize += (iExpectedNumBlocksPerBuffer * iBlockInfoAlignedSize); } else { buffersize += (OSCLMEMPOOLRESIZABLEALLOCATOR_DEFAULT_NUMBLOCKPERBUFFER * iBlockInfoAlignedSize); } MemPoolBufferInfo* newbuffer = addnewmempoolbuffer(buffersize); OSCL_ASSERT(newbuffer != NULL); OSCL_ASSERT(newbuffer->iNextFreeBlock != NULL); freeblock = (MemPoolBlockInfo*)(newbuffer->iNextFreeBlock); OSCL_ASSERT(freeblock != NULL); OSCL_ASSERT(freeblock->iBlockSize >= alignednumbytes); } else { // Check if another buffer can be created if (iMemPoolBufferNumLimit > 0 && iMemPoolBufferList.size() >= iMemPoolBufferNumLimit) { if (iEnableNullPtrReturn) { return NULL; } else { // Leave with resource limitation OSCL_LEAVE(OsclErrNoResources); } } // Determine the size of memory pool buffer and create one // By default this allocator expands by iMemPoolBufferSize. // iMaxNewMemPoolBufferSz could specify the amount by which this allocator expands. // setMaxSzForNewMemPoolBuffer API can be used to control the expansion size. uint32 expansion_size = iMemPoolBufferSize; if (iMaxNewMemPoolBufferSz != 0) { expansion_size = iMaxNewMemPoolBufferSz; } //if alignednumbytes is larger than expansion_size, we cannot satisfy the request, so fail the allocation if (alignednumbytes > expansion_size) { if (iEnableNullPtrReturn) { return NULL; } else { // Leave with resource limitation OSCL_LEAVE(OsclErrNoResources); } } uint32 buffersize = oscl_mem_aligned_size(expansion_size) + iBufferInfoAlignedSize; if (iExpectedNumBlocksPerBuffer > 0) { buffersize += (iExpectedNumBlocksPerBuffer * iBlockInfoAlignedSize); } else { buffersize += (OSCLMEMPOOLRESIZABLEALLOCATOR_DEFAULT_NUMBLOCKPERBUFFER * iBlockInfoAlignedSize); } MemPoolBufferInfo* newbuffer = addnewmempoolbuffer(buffersize); OSCL_ASSERT(newbuffer != NULL); OSCL_ASSERT(newbuffer->iNextFreeBlock != NULL); freeblock = (MemPoolBlockInfo*)(newbuffer->iNextFreeBlock); OSCL_ASSERT(freeblock != NULL); OSCL_ASSERT(freeblock->iBlockSize >= alignednumbytes); } } // Use the free block and return the buffer pointer OsclAny* bufptr = allocateblock(*freeblock, alignednumbytes); if (bufptr) { addRef(); ++(freeblock->iParentBuffer->iNumOutstanding); } return bufptr; }