/*===========================================================================* * fs_sync * *===========================================================================*/ PUBLIC int fs_sync() { /* Perform the sync() system call. Flush all the tables. * The order in which the various tables are flushed is critical. The * blocks must be flushed last, since rw_inode() leaves its results in * the block cache. */ struct inode *rip; struct buf *bp; int r; assert(nr_bufs > 0); assert(buf); if (superblock->s_rd_only) return(OK); /* nothing to sync */ /* Write all the dirty inodes to the disk. */ for(rip = &inode[0]; rip < &inode[NR_INODES]; rip++) if(rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING); /* Write all the dirty blocks to the disk, one drive at a time. */ for(bp = &buf[0]; bp < &buf[nr_bufs]; bp++) if(bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev); if (superblock->s_dev != NO_DEV) { superblock->s_wtime = clock_time(); write_super(superblock); } return(OK); /* sync() can't fail */ }
struct m_inode* ialloc() //分配空闲磁盘I节点并返回加载到主存的内存I节点 { int num=0; struct f_inode *tmp=NULL; if(super->freeInodeNum<=0)//无空闲I节点 return NULL; if(super->nextFreeInode==0)//直接管理的I节点分配完毕 { tmp=(struct f_inode*)calloc(1,sizeof(struct f_inode)); fseek(virtualDisk,START_POS+SUPERSIZE,SEEK_SET); for(int i=1; i<INODESNUM; i++) { fseek(virtualDisk,START_POS+SUPERSIZE+i*INODE,SEEK_SET); fread(tmp,sizeof(struct f_inode),1,virtualDisk); if(tmp->i_free==0)//查找空闲磁盘I节点 { super->freeInode[num]=i; super->nextFreeInode++; num++; } if(num==INODENUM) break; } } super->nextFreeInode--; super->freeInodeNum--; write_super();//更新超级块信息 return iget(super->freeInode[super->nextFreeInode]);//返回相应磁盘I节点加载到的主存I节点 }
int format_disk(char * path) //初始化虚拟磁盘 { unsigned int group[BLOCKNUM]; // virtualDisk=fopen(path,"w+");//打开虚拟磁盘文件 virtualDisk=fopen(path,"wb+");//打开虚拟磁盘文件 if(virtualDisk==NULL) { return -1; } super=(struct supblock*)calloc(1,sizeof(struct supblock)); //创建超级块 if(super==NULL) return -1; super->flags=1; super->disksize=8*BLOCKSIZE*1024; super->Blocksize=BLOCKSIZE;//初始化空闲块号栈 super->freeBlockNum=BLOCKSNUM; super->nextFreeBlock=BLOCKNUM; for(int i=0; i<BLOCKNUM; i++) super->freeBlock[i]=BLOCKSTART+i; super->freeInodeNum=INODESNUM-1;//初始化I节点号栈 super->nextFreeInode=INODENUM; for(int i=0; i<INODENUM; i++) { super->freeInode[i]=i+1; } write_super(); //更新超级块 fseek(virtualDisk,BLOCKSTART*BLOCKSIZE,SEEK_SET);//重定向到数据块地址 for(int i=0; i<BLOCKNUM; i++) { group[i]=i+BLOCKSTART; } //for(int i=0; i<363; i++) //初始化空闲块索引,构成索引表管理空闲块 for(int i=0; i<(BLOCKSNUM-BLOCKNUM)/BLOCKNUM; i++) { for(int j=0; j<BLOCKNUM; j++) { group[j]+=BLOCKNUM; } // printf("%d\n",BLOCKSTART+i*BLOCKNUM); fseek(virtualDisk,(BLOCKSTART+i*BLOCKNUM)*1024,SEEK_SET); fwrite(group,sizeof(unsigned int),BLOCKNUM,virtualDisk); } struct m_inode * iroot= iget(0);//root I节点 iroot->finode.addr[0]=balloc();//分配root目录磁盘块 iroot->finode.mode=1; iroot->finode.addrnum=1; write_finode(iroot); fclose( virtualDisk); return 0; }
int balloc()//分配空闲磁盘块,采用成组连接法管理 { unsigned int bno; int ret; if(super->freeBlockNum<=0)//无空闲磁盘块 return -1; if(super->nextFreeBlock==1)//直接管理的空闲块使用完则读取空闲块索引表中的空闲块信息到空闲块号栈 { bno=super->freeBlock[--super->nextFreeBlock]; fseek(virtualDisk,super->freeBlock[0]*BLOCKSIZE,SEEK_SET);//重定向到索引表 ret=fread(super->freeBlock,sizeof(unsigned int),BLOCKNUM,virtualDisk);//读取空闲块索引表到空闲块号栈 super->nextFreeBlock=ret; super->freeBlockNum--; write_super(); return bno; } super->freeBlockNum--;//直接管理的空闲块未分配完则分配空闲磁盘块 super->nextFreeBlock--; write_super(); return super->freeBlock[super->nextFreeBlock]; }
int _rmdir(struct m_inode* inode) { struct m_inode * rminode=NULL; dir * dir=(struct dir*)calloc(1,sizeof(struct dir)); for(int addr=0; addr<inode->finode.addrnum; addr++) { bread(dir,inode->finode.addr[addr],0,sizeof(struct dir),1); for(int i=0; i<dir->dirNum; i++) { rminode=iget(dir->direct[i].inodeID); if(rminode->finode.mode==1) { _rmdir(rminode); } else { for(int i=0; i<rminode->finode.addrnum; i++) bfree(rminode->finode.addr[i]); rminode->finode.i_free=0;//标志I节点空闲 super->freeInodeNum++; write_super(); write_finode(rminode); } } } //释放目录本省 for(int i=0; i< inode->finode.addrnum; i++) bfree( inode->finode.addr[i]); inode->finode.i_free=0; super->freeInodeNum++; write_super(); write_finode( inode); return 1; }
/*===========================================================================* * fs_unmount * *===========================================================================*/ PUBLIC int fs_unmount() { /* Unmount a file system by device number. */ int count; struct inode *rip, *root_ip; if(superblock->s_dev != fs_dev) return(EINVAL); /* See if the mounted device is busy. Only 1 inode using it should be * open --the root inode-- and that inode only 1 time. */ count = 0; for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count; if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL) { printf("ext2: couldn't find root inode. Unmount failed.\n"); panic("ext2: couldn't find root inode"); return(EINVAL); } /* Sync fs data before checking count. In some cases VFS can force unmounting * and it will damage unsynced FS. We don't sync before checking root_ip since * if it is missing then something strange happened with FS, so it's better * to not use possibly corrupted data for syncing. */ if (!superblock->s_rd_only) { /* force any cached blocks out of memory */ (void) fs_sync(); } if (count > 1) return(EBUSY); /* can't umount a busy file system */ put_inode(root_ip); if (!superblock->s_rd_only) { superblock->s_wtime = clock_time(); superblock->s_state = EXT2_VALID_FS; write_super(superblock); /* Commit info, we just set above */ } /* Close the device the file system lives on. */ bdev_close(fs_dev); /* Finish off the unmount. */ superblock->s_dev = NO_DEV; unmountdone = TRUE; return(OK); }
int bfree(int bno) //释放磁盘块 { if(super->nextFreeBlock==BLOCKNUM) { bwrite(&super->freeBlock,bno,0,sizeof(unsigned int),BLOCKNUM); super->nextFreeBlock=1; super->freeBlock[0]=bno; } else { super->freeBlock[super->nextFreeBlock]=bno; super->nextFreeBlock++; } super->freeBlockNum++; write_super(); return 1; }
int rmdir(char* filename,struct m_inode* inode) { struct m_inode* rminode=NULL; dir * dir=(struct dir*)calloc(1,sizeof(struct dir)); for(int addr=0; addr<inode->finode.addrnum; addr++) { bread(dir,inode->finode.addr[addr],0,sizeof(struct dir),1); for(int i=0; i<dir->dirNum; i++) { if(strcmp(dir->direct[i].directName,filename)==0) { rminode=iget(dir->direct[i].inodeID); for(int j=i; j<dir->dirNum; j++) dir->direct[j]=dir->direct[j+1]; dir->dirNum--; bwrite(dir,inode->finode.addr[addr],0,sizeof(struct dir),1); break; } } if(rminode) break; } if(rminode==NULL) return -1; else { if(rminode->finode.mode==1)//删除项为目录 _rmdir(rminode);//递归删除 else { for(int i=0; i<rminode->finode.addrnum; i++) bfree(rminode->finode.addr[i]); rminode->finode.i_free=0; super->freeInodeNum++; write_super(); write_finode(rminode); } } inode->finode.fileSize-=sizeof(struct direct); write_finode(inode); return 1; }
/*===========================================================================* * fs_unmount * *===========================================================================*/ PUBLIC int fs_unmount() { /* Unmount a file system by device number. */ int count; struct inode *rip, *root_ip; if(superblock.s_dev != fs_dev) return(EINVAL); /* See if the mounted device is busy. Only 1 inode using it should be * open --the root inode-- and that inode only 1 time. */ count = 0; for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count; if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL) { panic("MFS: couldn't find root inode\n"); return(EINVAL); } if (count > 1) return(EBUSY); /* can't umount a busy file system */ put_inode(root_ip); /* force any cached blocks out of memory */ (void) fs_sync(); /* Mark it clean if we're allowed to write _and_ it was clean originally. */ if(cleanmount && !superblock.s_rd_only) { superblock.s_flags |= MFSFLAG_CLEAN; write_super(&superblock); } /* Close the device the file system lives on. */ bdev_close(fs_dev); /* Finish off the unmount. */ superblock.s_dev = NO_DEV; unmountdone = TRUE; return(OK); }
int main(int argc, char *argv[]) { /* Read file system name from parameters */ if (argc != 2) { printf("\nUsage : format [/dev/sda1]\n\n"); exit(EXIT_FAILURE); } /* Open file system */ fd = open(argv[1], O_RDWR); if (fd <= 0) { perror("error opening filesystem"); exit(EXIT_FAILURE); } if (write_super() < 0) { goto err; } if (write_block_bitmap() < 0) { goto err; } if (write_inode_bitmap() < 0) { goto err; } if (write_inode_table() < 0) { goto err; } close(fd); exit(EXIT_SUCCESS); err: close(fd); exit(EXIT_FAILURE); }
/*===========================================================================* * fs_readsuper * *===========================================================================*/ PUBLIC int fs_readsuper() { /* This function reads the superblock of the partition, gets the root inode * and sends back the details of them. Note, that the FS process does not * know the index of the vmnt object which refers to it, whenever the pathname * lookup leaves a partition an ELEAVEMOUNT error is transferred back * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; int r = OK; int readonly, isroot; u32_t mask; fs_dev = fs_m_in.REQ_DEV; label_gid = fs_m_in.REQ_GRANT; label_len = fs_m_in.REQ_PATH_LEN; readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; if (label_len > sizeof(fs_dev_label)) return(EINVAL); r = sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label, label_len, D); if (r != OK) { printf("%s:%d fs_readsuper: safecopyfrom failed: %d\n", __FILE__, __LINE__, r); return(EINVAL); } /* Map the driver label for this major. */ bdev_driver(fs_dev, fs_dev_label); /* Open the device the file system lives on. */ if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT)) != OK) { return(EINVAL); } /* Fill in the super block. */ STATICINIT(superblock, 1); if (!superblock) panic("Can't allocate memory for superblock."); superblock->s_dev = fs_dev; /* read_super() needs to know which dev */ r = read_super(superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(r); } if (superblock->s_rev_level != EXT2_GOOD_OLD_REV) { struct super_block *sp = superblock; /* just shorter name */ mask = ~SUPPORTED_INCOMPAT_FEATURES; if (HAS_INCOMPAT_FEATURE(sp, mask)) { if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_COMPRESSION & mask)) printf("ext2: fs compression is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_FILETYPE & mask)) printf("ext2: fs in dir filetype is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_RECOVER & mask)) printf("ext2: fs recovery is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_JOURNAL_DEV & mask)) printf("ext2: fs journal dev is not supported by server\n"); if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_META_BG & mask)) printf("ext2: fs meta bg is not supported by server\n"); return(EINVAL); } mask = ~SUPPORTED_RO_COMPAT_FEATURES; if (HAS_RO_COMPAT_FEATURE(sp, mask)) { if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_SPARSE_SUPER & mask)) { printf("ext2: sparse super is not supported by server, \ remount read-only\n"); } if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_LARGE_FILE & mask)) { printf("ext2: large files are not supported by server, \ remount read-only\n"); } if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_BTREE_DIR & mask)) { printf("ext2: dir's btree is not supported by server, \ remount read-only\n"); } return(EINVAL); } } if (superblock->s_state == EXT2_ERROR_FS) { printf("ext2: filesystem wasn't cleanly unmounted previous time\n"); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } set_blocksize(superblock->s_block_size, superblock->s_blocks_count, superblock->s_free_blocks_count, major(fs_dev)); /* Get the root inode of the mounted file system. */ if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { printf("ext2: couldn't get root inode\n"); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if (root_ip != NULL && root_ip->i_mode == 0) { printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); put_inode(root_ip); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if (root_ip != NULL && (root_ip->i_mode & I_TYPE) != I_DIRECTORY) { printf("%s:%d root inode has wrong type, it's not a DIR\n", __FILE__, __LINE__); put_inode(root_ip); superblock->s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } superblock->s_rd_only = readonly; superblock->s_is_root = isroot; if (!readonly) { superblock->s_state = EXT2_ERROR_FS; superblock->s_mnt_count++; superblock->s_mtime = clock_time(); write_super(superblock); /* Commit info, we just set above */ } /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; fs_m_out.RES_MODE = root_ip->i_mode; fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size; fs_m_out.RES_UID = root_ip->i_uid; fs_m_out.RES_GID = root_ip->i_gid; fs_m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ return(r); }
/*===========================================================================* * fs_readsuper * *===========================================================================*/ PUBLIC int fs_readsuper() { /* This function reads the superblock of the partition, gets the root inode * and sends back the details of them. Note, that the FS process does not * know the index of the vmnt object which refers to it, whenever the pathname * lookup leaves a partition an ELEAVEMOUNT error is transferred back * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; int r; int readonly, isroot; fs_dev = (dev_t) fs_m_in.REQ_DEV; label_gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; label_len = (size_t) fs_m_in.REQ_PATH_LEN; readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; if (label_len > sizeof(fs_dev_label)) return(EINVAL); r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0, (vir_bytes) fs_dev_label, label_len, D); if (r != OK) { printf("MFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r); return(EINVAL); } /* Map the driver label for this major. */ bdev_driver(fs_dev, fs_dev_label); /* Open the device the file system lives on. */ if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) { return(EINVAL); } /* Fill in the super block. */ superblock.s_dev = fs_dev; /* read_super() needs to know which dev */ r = read_super(&superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(r); } /* Remember whether we were mounted cleanly so we know what to * do at unmount time */ if(superblock.s_flags & MFSFLAG_CLEAN) cleanmount = 1; /* clean check: if rw and not clean, switch to readonly */ if(!(superblock.s_flags & MFSFLAG_CLEAN) && !readonly) { if(bdev_close(fs_dev) != OK) panic("couldn't bdev_close after found unclean FS"); readonly = 1; if (bdev_open(fs_dev, R_BIT) != OK) { panic("couldn't bdev_open after found unclean FS"); return(EINVAL); } printf("MFS: WARNING: FS 0x%x unclean, mounting readonly\n", fs_dev); } set_blocksize(&superblock); /* Get the root inode of the mounted file system. */ if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { printf("MFS: couldn't get root inode\n"); superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if(root_ip->i_mode == 0) { printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); put_inode(root_ip); superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } superblock.s_rd_only = readonly; superblock.s_is_root = isroot; /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; fs_m_out.RES_MODE = root_ip->i_mode; fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size; fs_m_out.RES_UID = root_ip->i_uid; fs_m_out.RES_GID = root_ip->i_gid; fs_m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ /* Mark it dirty */ if(!superblock.s_rd_only) { superblock.s_flags &= ~MFSFLAG_CLEAN; if(write_super(&superblock) != OK) panic("mounting: couldn't write dirty superblock"); } return(r); }