void Unmount(void) { /* * precondition : usage ) Unmount(void); * postcondition : 가상 디스크의 파일 시스템을 종료한다. * 메모리상에 있는 버퍼에 변경된 데이터와 메타데이터를 디스크와 * 동기화 하고 언마운트 한다. */ int i = 0; Buf* pBuf = NULL; // fileSysInfo 갱신 pBuf = BufRead(0); BufWrite(pBuf, &fileSysInfo, sizeof(fileSysInfo) - sizeof(char*) * 2); // fileSysInfo.pInodeBitmap 갱신 for ( i = fileSysInfo.inodeBitmapStart ; i < fileSysInfo.inodeBitmapStart + inodeBitmapSize ; i++ ) { pBuf = BufRead(i); BufWrite(pBuf, fileSysInfo.pInodeBitmap + (i - fileSysInfo.inodeBitmapStart) * BLOCK_SIZE, 512); } // fileSysInfo.pBlockBitmap 갱신 for ( i = fileSysInfo.blockBitmapStart ; i < fileSysInfo.blockBitmapStart + blockBitmapSize ; i++ ) { pBuf = BufRead(i); BufWrite(pBuf, fileSysInfo.pBlockBitmap + (i - fileSysInfo.blockBitmapStart) * BLOCK_SIZE, 512); } BufSync(); }
void ReadDirBlock(DirBlock* dirBlock, int blockNo) { /* * precondition : * postcondition : 인자 blockNo는 block number이다. * 해당 block number의 block을 디스크에서 읽어 온다. */ Buf* pBuf = NULL; pBuf = BufRead(blockNo); memcpy(dirBlock, (DirBlock*)pBuf->pMem, sizeof(DirBlock)); }
void WriteDirBlock(DirBlock* dirBlock, int blockNo) { /* * precondition : * postcondition : 인자 blockNo는 dirBlock의 block number이다. * dirBlock을 디스크에 저장한다. */ Buf* pBuf = NULL; pBuf = BufRead(blockNo); BufWrite(pBuf, dirBlock, sizeof(DirBlock)); }
static int __find_dentry_and_remove(tiny_inode* out_inode, tiny_inode *parent_inode, const char *entry_name) { int qid = OpenMQ(5000); tiny_dirblk *dirblk; tiny_dentry *dentry; Buf *buf; int i, j; int isEmpty = 1; int find = 0; int dirblkno; int parent_inodeno; int target_inodeno; for (i = 0; i < parent_inode->i_nblk; i++) { buf = BufRead(parent_inode->i_block[i]); dirblk = __get_dirblk_from_buf(buf); dirblkno = parent_inode->i_block[i]; isEmpty = 1; for (j = 0; j < NUM_OF_DIRENT_IN_1BLK; j++) { dentry = &dirblk->dirEntries[j]; if ( i == 0 && j == 0 ) { parent_inodeno = dentry[0].inodeNum; } if (strncmp(entry_name, dentry->name, NAME_LEN_MAX) == 0) { ReadInode(out_inode, dentry->inodeNum); strncpy(dentry->name, "", NAME_LEN_MAX); target_inodeno = dentry->inodeNum; find = 1; } else if (strncmp(dentry->name, "", NAME_LEN_MAX) != 0) { isEmpty = 0; } } if (find) { if (isEmpty) { SetBlockAllocToFree(dirblkno); parent_inode->i_block[i] = parent_inode->i_block[--parent_inode->i_nblk]; WriteInode(parent_inode, parent_inodeno); } else { WriteDirBlock(dirblk, dirblkno); } return target_inodeno; } } return -1; }
int ReadFile(int fileDesc, char* pBuffer, int length) { /* * precondition : usage) ReadFile(fileDesc, pBuffer, length); * fileDesc : file descriptor * pBuffer : 저장할 데이터를 포함하는 메모리의 주소 * length : 저장될 데이터의 길이 * postcondition : open된 파일에서 데이터를 읽는다. * 성공하면 읽은 데이터의 길이 값을 리턴한다. 실패 했을때는 -1을 리턴한다. */ int i = 0, j = 0; int block = fileDescTable.file[fileDesc].offset / BLOCK_SIZE; int offset = fileDescTable.file[fileDesc].offset % BLOCK_SIZE; int exsist = 0; int wrote = length; Buf* pBuf = NULL; InodeInfo inodeInfo; DirBlock dirBlock; ReadInode(&inodeInfo, fileDescTable.file[fileDesc].inodeNo); // 첫번째 블락에서 data 읽고 pBuffer에 적재 pBuf = BufRead(inodeInfo.i_block[block]); memcpy(pBuffer, (char*)pBuf->pMem + offset, BLOCK_SIZE - offset); wrote = length < BLOCK_SIZE - offset ? length : BLOCK_SIZE - offset ; fileDescTable.file[fileDesc].offset = wrote; if ( length <= 512 ) return wrote; // 두번째 블락부터 data 읽고 pBuffer에 적재 for ( j = block + 1 ; j < (length / BLOCK_SIZE) + block ; j++ ) { if (NUM_OF_INDIRECT_BLOCK == j) return wrote; // indirect block 12개가 모두 사용중이면 write한 만큼만 리턴 pBuf = BufRead(inodeInfo.i_block[j]); memcpy(pBuffer + BLOCK_SIZE * ((j - (block + 1)) + 1), pBuf->pMem, length - wrote > BLOCK_SIZE ? BLOCK_SIZE : length - wrote); wrote = wrote + (length - wrote > BLOCK_SIZE ? BLOCK_SIZE : length - wrote); fileDescTable.file[fileDesc].offset = wrote; if ( wrote == length ) return wrote; } }
void ReadInode(InodeInfo* inodeInfo, int inodeNo) { /* * precondition : * postcondition : 인자 inodeNo는 inode number이다. * 해당 inode number를 가진 inodeInfo를 디스크에서 읽어온다. */ Buf* pBuf = NULL; InodeInfo* pMem = NULL; int block = fileSysInfo.inodeListStart + inodeNo / NUM_OF_INODE_IN_1BLK; // inodeNo가 위치한 블럭 int inode = inodeNo % NUM_OF_INODE_IN_1BLK; // 해당 block에서 inode가 위치한 순서 pBuf = BufRead(block); pMem = pBuf->pMem; pMem = pMem + inode; memcpy(inodeInfo, pMem/*(InodeInfo*)pBuf->pMem + inode*/, sizeof(InodeInfo)); }
void WriteInode(InodeInfo* inodeInfo, int inodeNo) { /* * precondition : * postcondition : 인자 inodeNo는 inodeInfo의 inode number이다. * inodeInfo를 디스크에 저장한다. */ Buf* pBuf = NULL; void* pMem = malloc(BLOCK_SIZE); InodeInfo* pCur = pMem; int block = fileSysInfo.inodeListStart + inodeNo / NUM_OF_INODE_IN_1BLK; int inode = inodeNo % NUM_OF_INODE_IN_1BLK; pBuf = BufRead(block); memcpy(pMem, pBuf->pMem, BLOCK_SIZE); pCur = pCur + inode; memcpy(pCur, inodeInfo, sizeof(InodeInfo)); BufWrite(pBuf, pMem, BLOCK_SIZE); free(pMem); }
void BufWrite(int blkno, void* pData) { Buf* pBuf; pBuf = BufFind(blkno); if( pBuf == NULL ) { char ptr_tmp_data[BLOCK_SIZE]; BufRead(blkno, ptr_tmp_data); pBuf = BufFind(blkno); } removeClean(blkno); if( ! existDirty(blkno) ) { insertDirty(pBuf); } removeLru(blkno); insertLru(pBuf); copyBlock((char*)pData, (char*)pBuf->pMem); }
void Mount(MountType type) { /* * precondition : usage ) Mount(MT_TYPE_FORMAT); * postcondition : 가상 디스크의 파일 시스템을 초기화 한다. * (1) MT_TYPE_FORMAT : 가상 디스크, 즉, 디스크를 에뮬레이션할 파일을 생성하고, * 그 파일을 파일 시스템이 인식할 수 있도록 organize 함. * 즉, 디스크 포맷처럼 가상 디스크 역할을 담당하는 파일 내에 * superblock, inode bitmap, block bitmap, inode list * 등을 초기화한다. 이때, 생성될 가상디스크의 크기는 10MB로 한다. * (2) MT_TYPE_READWRITE : MT_TYPE_FORMAT과 달리 가상 디스크를 포맷하지 않으며, * 파일 시스템 unmount 되기 이전의 디스크 사용 상태를 유지시키면서 * 파일 시스템을 초기화한다. 이때, 내부적으로 가상 디스크용 파일을 * 리눅스의 “open” system call을 사용하여 파일 열기를 수행하며, * file system info, inode bitmap, block bitmap을 * 정의된 in-memory data structure에 load한다. */ int i = 0; Buf* pBuf = NULL; InodeInfo inodeInfo; DirBlock dirBlock; ////////////////////////////////////////////////////////////////////// // 모두 block 단위임 inodeBitmapSize = (FS_INODE_COUNT / 8/*1byte*/ / BLOCK_SIZE == 0) ? 1 : (int)(ceil((double)FS_INODE_COUNT / (double)8 / (double)BLOCK_SIZE));// FS_INODE_COUNT / 8/*1byte*/ / BLOCK_SIZE + 1; // block 단위 inodeListSize = (int)(ceil((double)FS_INODE_COUNT / (double)NUM_OF_INODE_IN_1BLK)); // block 단위 dataRegionSize = (FS_DISK_CAPACITY / BLOCK_SIZE - 1/*FileSysInfo block*/ /* - 1*//*BlockBitmap block*/ - (double)inodeBitmapSize - (double)inodeListSize); blockBitmapSize = ceil(dataRegionSize / 8/*1byte*/ / BLOCK_SIZE); // block 단위 dataRegionSize = dataRegionSize - blockBitmapSize; // ////////////////////////////////////////////////////////////////////// memset(&fileDescTable, NULL, sizeof(FileDescTable)); Init(); // 버퍼캐시 생성 및 초기화 switch(type) { case MT_TYPE_FORMAT: DevInit(); // 디스크 초기화 fileSysInfo.blocks = BLOCK_SIZE; fileSysInfo.rootInodeNum = 0; // 수정해야함 fileSysInfo.diskCapacity = dataRegionSize; // 수퍼블락을 제외한 순수 data rigion의 블록사이즈 fileSysInfo.numAllocBlocks = 0; fileSysInfo.numFreeBlocks = fileSysInfo.diskCapacity; fileSysInfo.numInodes = FS_INODE_COUNT; fileSysInfo.numAllocInodes = 0; fileSysInfo.numFreeInodes = FS_INODE_COUNT; fileSysInfo.inodeBitmapStart = 1; // inode bitmap이 저장된 블록번호 fileSysInfo.blockBitmapStart = fileSysInfo.inodeBitmapStart + inodeBitmapSize; // block bitmap이 저장된 블록 번호 fileSysInfo.inodeListStart = fileSysInfo.blockBitmapStart + blockBitmapSize; // inode list를 저장하는 영역의 시작 블록 번호 fileSysInfo.dataStart = fileSysInfo.inodeListStart + inodeListSize; // data region의 시작 블록 번호 fileSysInfo.pInodeBitmap = malloc(inodeBitmapSize * BLOCK_SIZE); fileSysInfo.pBlockBitmap = malloc((int)blockBitmapSize * BLOCK_SIZE); memset(fileSysInfo.pInodeBitmap, 0xFF, inodeBitmapSize * BLOCK_SIZE); memset(fileSysInfo.pBlockBitmap, 0xFF, (int)blockBitmapSize * BLOCK_SIZE); memset(&inodeInfo, 0x0, sizeof(InodeInfo)); memset(&dirBlock, 0x0, sizeof(DirBlock)); //////////////////////////////////////////////////// // root 생성 // // inode 데이터 대입 inodeInfo.size = 0; inodeInfo.type = FILE_TYPE_DIR; inodeInfo.mode = FILE_MODE_READONLY; inodeInfo.blocks = 1; inodeInfo.i_block[0] = fileSysInfo.dataStart; // inode 저장 pBuf = BufRead(fileSysInfo.inodeListStart); BufWrite(pBuf, &inodeInfo, sizeof(InodeInfo)); // inode 사용현황 변경 if ( SetInodeFreeToAlloc() == WRONG_VALUE ) fprintf(stderr, "* SetInodeFreeToAlloc() error!\n"); // Directory Block 생성 strncpy(dirBlock.dirEntries[0].name, ".", NAME_LEN_MAX); dirBlock.dirEntries[0].inodeNum = 0; dirBlock.dirEntries[0].type = FILE_TYPE_DIR; // dir block 저장 pBuf = BufRead(fileSysInfo.dataStart); BufWrite(pBuf, &dirBlock, sizeof(DirBlock)); // block 사용현황 변경 if ( SetBlockFreeToAlloc() == WRONG_VALUE ) fprintf(stderr, "* SetBlockFreeToAlloc() error!\n"); // //////////////////////////////////////////////////// break; case MT_TYPE_READWRITE: // 버퍼캐시 생성 및 초기 DevLoad(); // 디스크 로 pBuf = BufRead(0); /* FileSysInfo */ memcpy(&fileSysInfo, pBuf->pMem, sizeof(fileSysInfo) - sizeof(char*) * 2 /*포인터변수 2개*/); fileSysInfo.pInodeBitmap = malloc(inodeBitmapSize * BLOCK_SIZE); fileSysInfo.pBlockBitmap = malloc((int)blockBitmapSize * BLOCK_SIZE); memset(fileSysInfo.pInodeBitmap, NULL, inodeBitmapSize * BLOCK_SIZE); memset(fileSysInfo.pBlockBitmap, NULL, (int)blockBitmapSize * BLOCK_SIZE); // inodeBitmap 로드 for ( i = fileSysInfo.inodeBitmapStart ; i < fileSysInfo.inodeBitmapStart + inodeBitmapSize ; i++ ) { pBuf = BufRead(i); memcpy(fileSysInfo.pInodeBitmap + (i - fileSysInfo.inodeBitmapStart) * BLOCK_SIZE, pBuf->pMem, BLOCK_SIZE); } // blockBitmap 로드 for ( i = fileSysInfo.blockBitmapStart ; i < fileSysInfo.blockBitmapStart + blockBitmapSize ; i++ ) { pBuf = BufRead(i); memcpy(fileSysInfo.pBlockBitmap + (i - fileSysInfo.blockBitmapStart) * BLOCK_SIZE, pBuf->pMem, BLOCK_SIZE); } break; } }
int WriteFile(int fileDesc, char* pBuffer, int length) { /* * precondition : usage) WriteFile(fileDesc, pBuffer, length); * fileDesc : file descriptor * pBuffer : 저장할 데이터를 포함하는 메모리의 주소 * length : 저장될 데이터의 길이 * postcondition : open된 파일에 데이터를 저장한다. * 성공하면 저장된 데이터의 길이 값을 리턴한다. 실패 했을때는 -1을 리턴한다. */ int i = 0, j = 0; int block = fileDescTable.file[fileDesc].offset / BLOCK_SIZE; int offset = fileDescTable.file[fileDesc].offset % BLOCK_SIZE; int exsist = 0; int remain = length; char buf[BLOCK_SIZE] = {NULL,}; Buf* pBuf = NULL; InodeInfo inodeInfo; DirBlock dirBlock; if ( fileDescTable.file[fileDesc].valid_bit != 1 ) return WRONG_VALUE; ReadInode(&inodeInfo, fileDescTable.file[fileDesc].inodeNo); // lseek 함수가 없기 때문에 inode에 저장된 indirect block 갯수보다 // 위에서 계산된 block(fd[].offset / BLOCK_SIZE)이 클수가 없음 // 따라서 예외처리 안해도 됨 // 첫번째 블락에 pBuffer 쓰기 pBuf = BufRead(inodeInfo.i_block[block]); memcpy(&buf, pBuf->pMem, BLOCK_SIZE); memcpy(&buf + offset, pBuffer, (remain + offset >= BLOCK_SIZE) ? BLOCK_SIZE - offset : remain); BufWrite(pBuf, &buf, BLOCK_SIZE); if ( inodeInfo.size < (remain - offset) ) inodeInfo.size = remain - offset; fileDescTable.file[fileDesc].offset += (remain + offset >= BLOCK_SIZE) ? BLOCK_SIZE - offset : remain; remain -= (BLOCK_SIZE - offset); if ( remain <= 0 ) return length; // 두번째 블락부터 pBuffer 쓰기 for ( j = block + 1 ; j < (length / BLOCK_SIZE + 1) + block ; j++ ) { // inodeInfo.blocks가 모자르면 새로 할당해줘야함 if ( j == inodeInfo.blocks && inodeInfo.blocks < NUM_OF_INDIRECT_BLOCK ) { inodeInfo.i_block[inodeInfo.blocks++] = GetFreeBlock(); SetBlockFreeToAlloc(); } if ( j == NUM_OF_INDIRECT_BLOCK ) { // indirect block 부족으로 쓰기 실패 WriteInode(&inodeInfo, fileDescTable.file[fileDesc].inodeNo); return length - remain; } pBuf = BufRead(inodeInfo.i_block[j]); BufWrite(pBuf, pBuffer + BLOCK_SIZE * ((j - (block + 1) + 1)), remain > BLOCK_SIZE ? BLOCK_SIZE : remain); fileDescTable.file[fileDesc].offset += (remain > BLOCK_SIZE ? BLOCK_SIZE : remain); remain = remain - BLOCK_SIZE; if ( remain <= 0 ) { inodeInfo.size += BLOCK_SIZE + remain; WriteInode(&inodeInfo, fileDescTable.file[fileDesc].inodeNo); return length; } else inodeInfo.size += BLOCK_SIZE; } return 0; }
int tiny_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int qid = OpenMQ(5000); int target_inodeno = (int)fi->fh; tiny_inode target_inode; Buf* pBuf; int blkno_start = offset / BLOCK_SIZE; int blkno_end = (offset + size) / BLOCK_SIZE; int nblk_read = blkno_end - blkno_start + 1; int offset_in_blk_start = offset % BLOCK_SIZE; int offset_in_blk_end = (offset + size) % BLOCK_SIZE; int ntoread = 0; int nread = 0; int nread_cur = 0; int i; ReadInode(&target_inode, target_inodeno); ntoread = target_inode.i_size - offset; ntoread = ntoread > size ? size : ntoread; if (ntoread < 0) { return -EIO; } //TODO: read first block pBuf = BufRead( target_inode.i_block[blkno_start] ); nread_cur = BLOCK_SIZE - offset_in_blk_start; if (nread_cur > ntoread) nread_cur = ntoread; memcpy( buf, pBuf->pMem + offset_in_blk_start, nread_cur); ntoread -= nread_cur; nread += nread_cur; if (ntoread == 0) goto read_all; if (nblk_read > 1) { //TODO: read middle blocks for (i = blkno_start + 1; i < blkno_end; i++) { pBuf = BufRead( target_inode.i_block[i] ); nread_cur = BLOCK_SIZE; if (nread_cur > ntoread) nread_cur = ntoread; memcpy( buf + nread, pBuf->pMem, nread_cur); ntoread -= nread_cur; nread += nread_cur; if (ntoread == 0) goto read_all; } //TODO: read last block pBuf = BufRead( target_inode.i_block[blkno_end] ); nread_cur = offset_in_blk_end; if (nread_cur > ntoread) nread_cur = ntoread; memcpy( buf + nread, pBuf->pMem, nread_cur); ntoread -= nread_cur; nread += nread_cur; } read_all: if(qid < 0) { printf("q open fail\n"); return ; } SuperBlk_t sb; sb.fsi = tiny_superblk; if(SendMQ(qid, MSG_SUPER_BLOCK, &sb) < 0) { printf("superblk send fail\n"); return ; } InodeBitmap_t ibm; ibm.size = tiny_superblk.s_ninode / 8; /*byte*/ memcpy(ibm.s_ibitmap_ptr, tiny_superblk.s_ibitmap_ptr, ibm.size); if(SendMQ(qid, MSG_INODE_BITMAP, &ibm) < 0) { printf("ibm send fail\n"); return ; } BlockBitmap_t bbm; bbm.size = tiny_superblk.s_datablk_size / 8; /*byte*/ memcpy(bbm.s_dbitmap_ptr, tiny_superblk.s_dbitmap_ptr, bbm.size); if(SendMQ(qid, MSG_BLOCK_BITMAP, &bbm) < 0) { printf("bbm send fail\n"); return ; } FileIO_t fio; memcpy(&fio.inode, &target_inode, sizeof(tiny_inode)); fio.dentry.inodeNum = target_inodeno; fio.flag = 'r'; fio.size = nread; if(SendMQ(qid, MSG_FILEIO, &fio) < 0) { printf("fio send fail\n"); return ; } return nread; }