// Test that the block cache works, by smashing the superblock and // reading it back. static void check_bc(void) { struct Super backup; // back up super block memmove(&backup, diskaddr(1), sizeof backup); // smash it strcpy(diskaddr(1), "OOPS!\n"); flush_block(diskaddr(1)); assert(va_is_mapped(diskaddr(1))); assert(!va_is_dirty(diskaddr(1))); // clear it out sys_page_unmap(0, diskaddr(1)); assert(!va_is_mapped(diskaddr(1))); // read it back in assert(strcmp(diskaddr(1), "OOPS!\n") == 0); // fix it memmove(diskaddr(1), &backup, sizeof backup); flush_block(diskaddr(1)); cprintf("block cache is good\n"); }
int file_data_write(struct File *f, char *buf, size_t count, int block_no) { int err; int pblk, hash_addr; int addr; int hash_second_table_addr; int second_table_offset; int flag = 0; uint32_t hash = generate_hash(buf, BLKSIZE); int hash_first_table_addr = HashBlock_Start + (hash & HashLowBits); fseek(fp,hash_first_table_addr,SEEK_SET); fread(&addr, sizeof(int), 1, fp); if(addr == 0) { if(alloc_block(&hash_addr) < 0) { printf("\n error in block allocation for write"); return -1; } fseek(fp,hash_first_table_addr,SEEK_SET); fwrite(&hash_addr, sizeof(int), 1, fp); flush_block(hash_addr); if((err = file_get_block(f, block_no, &pblk)) < 0) { printf("\n error in getting block for write"); return -1; } flush_block(pblk); fseek(fp,pblk,SEEK_SET); fwrite(buf, count, 1, fp); f->f_size += count; f->f_written += count; f->n_blocks += 1; super->total_blocks+=1; super->written_blocks+=1; second_table_offset = (hash & HashHighBits) >> 25; hash_second_table_addr = (int)((int *)hash_addr + second_table_offset); fseek(fp,hash_second_table_addr,SEEK_SET); fwrite(&pblk, sizeof(int), 1, fp); } else {
// Set *blk to point at the filebno'th block in file 'f'. // Allocate the block if it doesn't yet exist. // // Returns 0 on success, < 0 on error. Errors are: // -E_NO_DISK if a block needed to be allocated but the disk is full. // -E_INVAL if filebno is out of range. // // Hint: Use file_block_walk and alloc_block. int file_get_block(struct File *f, uint32_t filebno, char **blk) { // LAB 5: Your code here. int r; uint32_t *pblkno; if ((r = file_block_walk(f, filebno, &pblkno, 1)) < 0){ return r; } // if not exist if (*pblkno == 0){ if ((r = alloc_block()) < 0){ return -E_NO_DISK; } *pblkno = r; // Clear this block memset(diskaddr(r), 0, BLKSIZE); // flush this empty block into disk flush_block(diskaddr(r)); } *blk = diskaddr(*pblkno); return 0; }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. uint32_t i, j, blockno; for (i = 0; i < BLKBITSIZE / 32; i++){ if ((bitmap[i] & 0xffffffff) != 0){ break; } } if (i == BLKBITSIZE / 32){ return -E_NO_DISK; } blockno = i * 32; for (j = 0; j < 32; j++){ if (bitmap[i] & (1<<j)){ break; } } blockno += j; bitmap[i] ^= (1<<j); flush_block(bitmap); return blockno; }
static BLOCK *find_free_slot(FS *fs) { int attempts = 0, max = 3; while (attempts < max) { BLOCK *ptr = fs->cache_tail; attempts++; while (ptr != NULL) { if (!(ptr->flags & F_CACHED) || (!(ptr->flags & F_DIRTY) && ptr->pins == 0)) { flush_block(fs, ptr); remove_block_from_hash(fs, ptr); ptr->flags = 0; set_flag(ptr, F_CACHED); ptr->pins = 0; return ptr; } ptr = ptr->prev; } flush_fs(fs); } error("No more free slots in cache -- increase size or find bug"); return NULL; }
int fs_mkdir(const char *path, mode_t mode) { struct inode *dir; time_t curtime; struct fuse_context *ctxt; int r; if ((r = inode_create(path, &dir)) < 0) return r; dir->i_size = 0; dir->i_mode = S_IFDIR | (mode & 0777); dir->i_nlink = 1; curtime = time(NULL); dir->i_atime = curtime; dir->i_ctime = curtime; dir->i_mtime = curtime; ctxt = fuse_get_context(); dir->i_owner = ctxt->uid; dir->i_group = ctxt->gid; flush_block(dir); return 0; }
int fs_mknod(const char *path, mode_t mode, dev_t rdev) { struct inode *ino; time_t curtime; struct fuse_context *ctxt; int r; if ((r = inode_create(path, &ino)) < 0) return r; ino->i_size = 0; ino->i_mode = mode; ino->i_nlink = 1; ino->i_rdev = rdev; curtime = time(NULL); ino->i_atime = curtime; ino->i_ctime = curtime; ino->i_mtime = curtime; ctxt = fuse_get_context(); ino->i_owner = ctxt->uid; ino->i_group = ctxt->gid; flush_block(ino); return 0; }
void TextMan::flush_lines(int l1, int l2) { l1 *= CHAR_LINES; l2 *= CHAR_LINES; l2 += CHAR_LINES - 1; flush_block(0, l1, GFX_WIDTH - 1, l2); }
// Set *blk to point at the filebno'th block in file 'f'. // Allocate the block if it doesn't yet exist. // // Returns 0 on success, < 0 on error. Errors are: // -E_NO_DISK if a block needed to be allocated but the disk is full. // -E_INVAL if filebno is out of range. // // Hint: Use file_block_walk and alloc_block. int file_get_block(struct File *f, uint32_t filebno, char **blk) { // LAB 5: Your code here. //panic("file_get_block not implemented"); uint32_t *pdiskbno; int result; if((result=file_block_walk(f, filebno, &pdiskbno, 1)) < 0) { return result; } if(*pdiskbno == 0) { if((result=alloc_block()) < 0) { return -E_NO_DISK; } else { *pdiskbno=result; memset(diskaddr(result), 0, BLKSIZE); flush_block(diskaddr (result)); } } *blk=diskaddr(*pdiskbno); return 0; }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. // LAB 5: Your code here. //panic("alloc_block not implemented"); uint32_t blockno; int flag; flag=0; for(blockno=0; blockno<super->s_nblocks; blockno++) { if(block_is_free(blockno)) { bitmap[blockno/32] ^= 1<<(blockno%32); flush_block(bitmap); flag=1; break; } } if(flag == 1) { return blockno; } else { return -E_NO_DISK; } }
void pick_block(int16_t page) { if (page == current_page) { return; } if (current_page != -1) { flush_block(); } if (page >= pages_initialized) { uint8_t buf[16]; for (int16_t i = 0; i < 16; ++i) { buf[i] = 0xff; } for (int16_t i = 0; i < 512; i += 16) { flash_buf_write(0, i, buf, 16); } for ( ; pages_initialized <= page; ) { flash_put_buffer(0, pages_initialized); pages_initialized++; } eeprom_write(EEP_MAXPAGE_L, (uint8_t)(pages_initialized & 0xff)); eeprom_write(EEP_MAXPAGE_H, (uint8_t)(pages_initialized >> 8)); putProg("Pages initialized: "); putInt(pages_initialized); putCRLF(); }
// Flush the contents and metadata of file f out to disk. // Loop over all the blocks in file. // Translate the file block number into a disk block number // and then check whether that disk block is dirty. If so, write it out. void file_flush(struct File *f) { int i; uint32_t *pdiskbno; for (i = 0; i < (f->f_size + BLKSIZE - 1) / BLKSIZE; i++) { if (file_block_walk(f, i, &pdiskbno, 0) < 0 || pdiskbno == NULL || *pdiskbno == 0) continue; flush_block(diskaddr(*pdiskbno)); } flush_block(f); if (f->f_indirect) flush_block(diskaddr(f->f_indirect)); }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. // code for lab 5 -M.G // panic("alloc_block not implemented"); uint32_t i,j; for (i = 0; i < super->s_nblocks/32; i++) { for (j = 0; j < 32; j++) { uint32_t mark_bit = (1 << j); if (bitmap[i] & mark_bit) { bitmap[i] &= ~mark_bit; flush_block(diskaddr((i * 32 | j)/BLKBITSIZE + 2)); return (i * 32) | j; } } } return -E_NO_DISK; }
// Find the disk block number slot for the 'filebno'th block in file 'f'. // Set '*ppdiskbno' to point to that slot. // The slot will be one of the f->f_direct[] entries, // or an entry in the indirect block. // When 'alloc' is set, this function will allocate an indirect block // if necessary. // // Returns: // 0 on success (but note that *ppdiskbno might equal 0). // -E_NOT_FOUND if the function needed to allocate an indirect block, but // alloc was 0. // -E_NO_DISK if there's no space on the disk for an indirect block. // -E_INVAL if filebno is out of range (it's >= NDIRECT + NINDIRECT). // // Analogy: This is like pgdir_walk for files. // Hint: Don't forget to clear any block you allocate. static int file_block_walk(struct File *f, uint32_t filebno, uint32_t **ppdiskbno, bool alloc) { // LAB 5: Your code here. int r; void *addr = NULL; if (filebno >= NDIRECT + NINDIRECT){ return -E_INVAL; } if (filebno < NDIRECT){ *ppdiskbno = &f->f_direct[filebno]; return 0; } if (f->f_indirect == 0){ if (!alloc){ return -E_NOT_FOUND; } if((r = alloc_block()) == -E_NO_DISK){ return -E_NO_DISK; } f->f_indirect = r; // Clear this indirect block memset(diskaddr(r), 0, BLKSIZE); flush_block(diskaddr(r)); } // Remember fileno - NDIRECT addr = diskaddr(f->f_indirect); *ppdiskbno = ((uint32_t *)addr + filebno - NDIRECT); return 0; }
// Sync the entire file system. A big hammer. void fs_sync(void) { int i; for (i = 1; i < super->s_nblocks; i++) flush_block(diskaddr(i)); }
/* Called when there is no enough free memory. */ void flush_block_buffer(void) { struct block *block; while (!list_empty(&block_buffer_list)) { block = list_first_entry(&block_buffer_list, struct block, b_list); flush_block(block); free_block(block); } }
// Set the size of file f, truncating or extending as necessary. int file_set_size(struct File *f, off_t newsize) { if (f->f_size > newsize) file_truncate_blocks(f, newsize); f->f_size = newsize; flush_block(f); return 0; }
void minix_sync_inode(struct inode *inode) { /* synchronize inode */ flush_block(i2mi(inode)->m_iblock); /* synchronize dirty blocks */ inode_sync_dbc(inode); /* free dirty blocks */ inode_free_dbc(inode); }
// Test that the block cache works, by smashing the superblock and // reading it back. static void check_bc(void) { cprintf("Starting..\n"); struct Super backup; // back up super block memmove(&backup, diskaddr(1), sizeof(backup)); BC_DEBUG("Wrote superblock to disk ram block..\n"); BC_DEBUG("in memory magic number: %08x\n", ((struct Super*)diskaddr(1))->s_magic); // smash it strcpy(diskaddr(1), "OOPS!\n"); flush_block(diskaddr(1)); assert(va_is_mapped(diskaddr(1))); assert(!va_is_dirty(diskaddr(1))); cprintf("Smashed disk superblock..\n"); // clear it out sys_page_unmap(0, diskaddr(1)); assert(!va_is_mapped(diskaddr(1))); cprintf("Unmapped superblock va..\n"); // read it back in assert(strcmp(diskaddr(1), "OOPS!\n") == 0); cprintf("re-read superblock va..\n"); // fix it memmove(diskaddr(1), &backup, sizeof(backup)); assert(memcmp(diskaddr(1), &backup, sizeof(backup)) == 0); flush_block(diskaddr(1)); assert(memcmp(diskaddr(1), &backup, sizeof(backup)) == 0); BC_DEBUG("backup magic number : %08x\n", backup.s_magic); BC_DEBUG("in memory magic number: %08x\n", ((struct Super*)diskaddr(1))->s_magic); BC_DEBUG("expected magic value : %08x\n", FS_MAGIC); cprintf("Fixed superblock..\n"); cprintf("block cache is good\n"); }
void sync_blocks(void) { struct hlist_head *head = block_htable; int i = BLOCK_HASH_SIZE; struct hlist_node *node; struct block *block; while (i > 0) { hlist_for_each_entry(block, node, head, b_hnode) flush_block(block); head++; i--; } }
int fs_utimens(const char *path, const struct timespec tv[2]) { struct inode *ino; int r; if ((r = inode_open(path, &ino)) < 0) return r; ino->i_atime = tv[0].tv_sec; ino->i_mtime = tv[1].tv_sec; ino->i_ctime = time(NULL); flush_block(ino); return 0; }
int fs_chmod(const char *path, mode_t mode) { struct inode *ino; int r; if ((r = inode_open(path, &ino)) < 0) return r; if (ino == diskaddr(super->s_root)) return -EPERM; ino->i_mode = mode; ino->i_ctime = time(NULL); flush_block(ino); return 0; }
// Remove a file by truncating it and then zeroing the name. int file_remove(const char *path) { int r; struct File *f; if ((r = walk_path(path, 0, &f, 0)) < 0) return r; file_truncate_blocks(f, 0); f->f_name[0] = '\0'; f->f_size = 0; flush_block(f); return 0; }
// Find the disk block number slot for the 'filebno'th block in file 'f'. // Set '*ppdiskbno' to point to that slot. // The slot will be one of the f->f_direct[] entries, // or an entry in the indirect block. // When 'alloc' is set, this function will allocate an indirect block // if necessary. // // Returns: // 0 on success (but note that *ppdiskbno might equal 0). // -E_NOT_FOUND if the function needed to allocate an indirect block, but // alloc was 0. // -E_NO_DISK if there's no space on the disk for an indirect block. // -E_INVAL if filebno is out of range (it's >= NDIRECT + NINDIRECT). // // Analogy: This is like pgdir_walk for files. // Hint: Don't forget to clear any block you allocate. static int file_block_walk(struct File *f, uint32_t filebno, uint32_t **ppdiskbno, bool alloc) { // LAB 5: Your code here. //panic("file_block_walk not implemented"); int result; if(filebno >= NDIRECT+NINDIRECT) { return -E_INVAL; } if(filebno < NDIRECT) { if(ppdiskbno) { *ppdiskbno=(f->f_direct+filebno); } return 0; } if(!f->f_indirect && !alloc) { return -E_NOT_FOUND; } if(!f->f_indirect) { if((result=alloc_block()) < 0) { return -E_NO_DISK; } f->f_indirect=result; memset(diskaddr(result), 0, BLKSIZE); flush_block(diskaddr(result)); } if(ppdiskbno) { *ppdiskbno=(uint32_t *)diskaddr(f->f_indirect)+filebno-NDIRECT; } return 0; }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. // LAB 5: Your code here. int i; for (i = 0; i < super->s_nblocks; ++i) if (block_is_free(i)) { bitmap[i/32] &= (~(1<<(i%32))); flush_block(&bitmap[i/32]); return i; } return -E_NO_DISK; }
int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { struct inode *dir = (struct inode *)fi->fh; struct dirent dent; int r; while ((r = inode_read(dir, &dent, sizeof(dent), offset)) > 0) { offset += r; if (dent.d_name[0] == '\0') continue; if (filler(buf, dent.d_name, NULL, offset) != 0) return 0; } dir->i_atime = time(NULL); flush_block(dir); return 0; }
int fs_chown(const char *path, uid_t uid, gid_t gid) { struct inode *ino; int r; if ((r = inode_open(path, &ino)) < 0) return r; if (ino == diskaddr(super->s_root)) return -EPERM; if (uid != -1) ino->i_owner = uid; if (gid != -1) ino->i_group = gid; ino->i_ctime = time(NULL); flush_block(ino); return 0; }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. // LAB 5: Your code here. // panic("alloc_block not implemented"); int blkno; for (blkno = 1; blkno < super->s_nblocks; blkno++) { if (block_is_free(blkno)) { bitmap[blkno/32] &= ~(1<<(blkno%32)); flush_block(&bitmap[blkno/32]); return blkno; } } return -E_NO_DISK; }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. // LAB 5: Your code here. uint32_t blockno; for(blockno = 1; blockno < super->s_nblocks; blockno++) if(block_is_free(blockno)) { bitmap[blockno/32] ^= (1<<(blockno%32)); flush_block(diskaddr(2)); assert(!block_is_free(blockno)); return blockno; } return -E_NO_DISK; }
// Search the bitmap for a free block and allocate it. When you // allocate a block, immediately flush the changed bitmap block // to disk. // // Return block number allocated on success, // -E_NO_DISK if we are out of blocks. // // Hint: use free_block as an example for manipulating the bitmap. int alloc_block(void) { // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. // LAB 5: Your code here. uint32_t i; for (i = 0; i < super->s_nblocks; i++) { if (bitmap[i / 32] & (1 << (i%32))) { bitmap[i/32] &= ~(1<<(i%32)); flush_block(bitmap); return i; } } return -E_NO_DISK; }