PUBLIC int search_file(char *path) { /* 获得文件所在目录的 inode */ char filename[MAX_PATH]; memset(filename, 0, MAX_FILENAME_LEN); struct inode *dir_inode; if (strip_path(filename, path, &dir_inode) != 0) return 0; if (filename[0] == 0) return dir_inode->i_num; /* 根据这个 inode 找到对应扇区 */ int dir_blk0_nr = dir_inode->i_start_sect; // 目录起始扇区 int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE; // 占用几个扇区(至少一个) int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; // 一共有几个条目 int m = 0; struct dir_entry *pde; for (int i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; for (int j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++, pde++) { if (memcmp(filename, pde->name, MAX_FILENAME_LEN) == 0) return pde->inode_nr; // 文件存在 if (++m > nr_dir_entries) break; } if (m > nr_dir_entries) break; } return 0; // 文件不存在 }
/** * Allocate a bit in inode-map. * * @param dev In which device the inode-map is located. * * @return I-node nr. *****************************************************************************/ PRIVATE int alloc_imap_bit(int dev) { int inode_nr = 0; int i, j, k; int imap_blk0_nr = 1 + 1; /* 1 boot sector & 1 super block */ struct super_block * sb = get_super_block(dev); for (i = 0; i < sb->nr_imap_sects; i++) { RD_SECT(dev, imap_blk0_nr + i); for (j = 0; j < SECTOR_SIZE; j++) { /* skip `11111111' bytes */ if (fsbuf[j] == 0xFF) continue; /* skip `1' bits */ for (k = 0; ((fsbuf[j] >> k) & 1) != 0; k++) {} /* i: sector index; j: byte index; k: bit index */ inode_nr = (i * SECTOR_SIZE + j) * 8 + k; fsbuf[j] |= (1 << k); /* write the bit to imap */ WR_SECT(dev, imap_blk0_nr + i); break; } return inode_nr; } /* no free bit in imap */ panic("inode-map is probably full.\n"); return 0; }
PRIVATE int alloc_imap_bit(int dev) { int inode_nr = 0; int imap_blk0_nr = 1 + 1; // boot sector + super block struct super_block *sb = get_super_block(dev); for (int i = 0; i < sb->nr_imap_sects; i++) { // 逐扇区遍历 inode map RD_SECT(dev, imap_blk0_nr + i); for (int j = 0; j < SECTOR_SIZE; j++) { // 逐字节 /* 跳过已经使用的(1:使用;0:未使用) */ if (fsbuf[j] == 0xFF) continue; int k = 0; for (k = 0; ((fsbuf[j] >> k) & 1) != 0; k++); // 逐位(一位代表一个 inode) inode_nr = (i * SECTOR_SIZE + j) * 8 + k; fsbuf[j] |= (1 << k); /* 将更新后的 inode map 写入磁盘 */ WR_SECT(dev, imap_blk0_nr + i); break; } return inode_nr; } panic("inode-map is probably full.\n"); return 0; }
PRIVATE int alloc_imap_bit(int dev) { int inode_nr = 0; int i, j, k; int imap_blk0_nr = 2; assert(dev == ROOT_DEV); struct super_block *sb = get_super_block(dev); for (i=0; i<sb -> nr_imap_sects; i++) { RD_SECT(dev, imap_blk0_nr+i); for (j=0; j<SECTOR_SIZE; j++) { if (fsbuf[j] == 0xFF) continue; for (k=0; (fsbuf[j] & (1<<k))!=0; k++) ; inode_nr = (i*SECTOR_SIZE + j)*8 + k; fsbuf[j] |= (1<<k); WR_SECT(dev, imap_blk0_nr+i); return inode_nr; } } panic("Inode map is full.\n"); return 0; }
/** * Write a new entry into the directory. * * @param dir_inode I-node of the directory. * @param inode_nr I-node nr of the new file. * @param filename Filename of the new file. *****************************************************************************/ PRIVATE void new_dir_entry(struct inode * dir_inode, int inode_nr, char * filename) { /* struct super_block * sb = get_super_block(dir_inode->i_dev); */ /* write the dir_entry */ int dir_blk0_nr = dir_inode->i_start_sect; /* printl("n_1st_sect:0x%x, dir_blk0_nr:0x%x\n", */ /* sb->n_1st_sect, dir_blk0_nr); */ int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE; int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; /** * including unused slots * (the file has been * deleted but the slot * is still there) */ int m = 0; struct dir_entry * pde; struct dir_entry * new_de = 0; int i, j; for (i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { if (++m > nr_dir_entries) break; if (pde->inode_nr == 0) { /* it's a free slot */ new_de = pde; break; } } if (m > nr_dir_entries ||/* all entries have been iterated or */ new_de) /* free slot is found */ break; } /* printm("FS::in create_file: nr_dir_blks:%d, i:%d\n", nr_dir_blks, i); */ if (!new_de) { /* reached the end of the dir */ new_de = pde; dir_inode->i_size += DIR_ENTRY_SIZE; } new_de->inode_nr = inode_nr; strcpy(new_de->name, filename); /* write dir block -- ROOT dir block */ WR_SECT(dir_inode->i_dev, dir_blk0_nr + i); /* update dir inode */ sync_inode(dir_inode); }
PUBLIC struct inode *get_inode(int dev, int num) { struct inode *q = 0; /* 第 0 号 inode 为系统保留 */ if (num == 0) return 0; /* 先在内存中的 inode_table 里查找 */ for (struct inode *p = &inode_table[0]; p < &inode_table[NR_INODE]; p++) { if (p->i_cnt) { /* 如果找到了就直接返回 */ if ((p->i_dev == dev) && (p->i_num == num)) { p->i_cnt++; return p; } } else if (!q) q = p; } /* inode_table 已经满员了 */ if (!q) panic("the inode table is full"); /* 找到第 num 个 inode 所在的扇区 */ struct super_block *sb = get_super_block(dev); int blk_nr = 1 + 1 // boot sector + super block + sb->nr_imap_sects // + inode map + sb->nr_smap_sects // + sector map + ((num - 1) / (SECTOR_SIZE / INODE_SIZE)); /* 读取这个扇区然后找到第 num 个 inode */ RD_SECT(dev, blk_nr); struct inode *pinode = (struct inode *)((u8 *)fsbuf + ((num - 1) % (SECTOR_SIZE / INODE_SIZE)) * INODE_SIZE); /* 准备一个新的 inode */ q->i_mode = pinode->i_mode; q->i_size = pinode->i_size; q->i_start_sect = pinode->i_start_sect; q->i_nr_sects = pinode->i_nr_sects; q->i_dev = dev; q->i_num = num; q->i_cnt = 1; return q; }
//when inode is changed , write it to disk void sync_inode(struct inode *p) { struct inode *pinode; struct super_block * get_super_block(int dev); struct super_block *sb = get_super_block(p->i_dev); int blk_nr = 2+sb->nr_imap_sects + sb->nr_smap_sects+ ((p->i_num-1)/(SECTOR_SIZE /INODE_SIZE));//inode_nr==0 is not used RD_SECT(p->i_dev, blk_nr); pinode = (struct inode *)((t_8*)fsbuf + ((p->i_num-1)%(SECTOR_SIZE/INODE_SIZE)) *INODE_SIZE); pinode->i_mode = p->i_mode; pinode->i_size = p->i_size; pinode->i_start_sect = p->i_start_sect; pinode->i_nr_sects = p->i_nr_sects; WR_SECT(p->i_dev, blk_nr); }
/** * Allocate a bit in sector-map. * * @param dev In which device the sector-map is located. * @param nr_sects_to_alloc How many sectors are allocated. * * @return The 1st sector nr allocated. *****************************************************************************/ PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc) { /* int nr_sects_to_alloc = NR_DEFAULT_FILE_SECTS; */ int i; /* sector index */ int j; /* byte index */ int k; /* bit index */ struct super_block * sb = get_super_block(dev); int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; int free_sect_nr = 0; for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */ RD_SECT(dev, smap_blk0_nr + i); /* byte offset in current sect */ for (j = 0; j < SECTOR_SIZE && nr_sects_to_alloc > 0; j++) { k = 0; if (!free_sect_nr) { /* loop until a free bit is found */ if (fsbuf[j] == 0xFF) continue; for (; ((fsbuf[j] >> k) & 1) != 0; k++) {} free_sect_nr = (i * SECTOR_SIZE + j) * 8 + k - 1 + sb->n_1st_sect; } for (; k < 8; k++) { /* repeat till enough bits are set */ assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= (1 << k); if (--nr_sects_to_alloc == 0) break; } } if (free_sect_nr) /* free bit found, write the bits to smap */ WR_SECT(dev, smap_blk0_nr + i); if (nr_sects_to_alloc == 0) break; } assert(nr_sects_to_alloc == 0); return free_sect_nr; }
/** * <Ring 1> Write the inode back to the disk. Commonly invoked as soon as the * inode is changed. * * @param p I-node ptr. *****************************************************************************/ PUBLIC void sync_inode(struct inode * p) { struct inode * pinode; struct super_block * sb = get_super_block(p->i_dev); int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects + ((p->i_num - 1) / (SECTOR_SIZE / INODE_SIZE)); RD_SECT(p->i_dev, blk_nr); pinode = (struct inode*)((u8*)fsbuf + (((p->i_num - 1) % (SECTOR_SIZE / INODE_SIZE)) * INODE_SIZE)); pinode->i_mode = p->i_mode; pinode->i_size = p->i_size; pinode->i_start_sect = p->i_start_sect; pinode->i_nr_sects = p->i_nr_sects; WR_SECT(p->i_dev, blk_nr); }
/************************************************************************************************** * get_inode ************************************************************************************************** * <Ring 1> Get the inode pointer of given inode nr. A cache 'inode_table[]' is maintained to make * things faster. If the inode requested is already there, just return it. Otherwise the inode * will be read from the disk. * * @param dev Device nr. * @param num Inode nr. * * @return The inode pointer requested. *************************************************************************************************/ PUBLIC struct inode* get_inode(int dev, int num){ if(num == 0){ return 0; } struct inode* p; struct inode* q = 0; for(p=&inode_table[0]; p<&inode_table[NR_INODE]; p++){ if(p->i_cnt){ /* not a free slot */ if((p->i_dev == dev) && (p->i_num == num)){ /* this is the inode we want */ p->i_cnt++; return p; } }else{ /* a free slot */ if(!q){ /* q hasn't been assigned yet */ q = p; /* q <- the 1st free slot */ } } } if(!q){ panic("the inode table is full"); } q->i_dev = dev; q->i_num = num; q->i_cnt = 1; struct super_block* sb = get_super_block(dev); int nr_blk = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects + ((num - 1) / (SECTOR_SIZE / INODE_SIZE)); RD_SECT(dev, nr_blk); struct inode* pinode = (struct inode*) ((u8*)fsbuf + ((num - 1) % (SECTOR_SIZE / INODE_SIZE)) * INODE_SIZE); q->i_mode = pinode->i_mode; q->i_size = pinode->i_size; q->i_start_sect = pinode->i_start_sect; q->i_nr_sects = pinode->i_nr_sects; return q; }
/************************************************************************************************** * alloc_smap_bit ************************************************************************************************** * Allocate a bit in sector-map. * * @param dev In which device the sector-map is located. * @param nr_sects_to_alloc How many sectors are allocated. * * @return The 1st sector nr allocated. *************************************************************************************************/ PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc){ int i, j, k; /* i: sector index j: byte index k: bit index */ int nr_free_sect = 0; struct super_block* sb = get_super_block(dev); int nr_smap_blk0 = 1 + 1 + sb->nr_imap_sects; for(i=0; i<sb->nr_smap_sects; i++){ RD_SECT(dev, nr_smap_blk0 + i); for(j=0; j<SECTOR_SIZE && nr_sects_to_alloc > 0; j++){ k = 0; if(!nr_free_sect){ /* loop untill a free bit is found. */ if(fsbuf[j] == 0xff){ continue; } for(; ((fsbuf[j] >> k) & 1) != 0; k++){} nr_free_sect = (i * SECTOR_SIZE + j) * 8 + k - 1 + sb->n_1st_sect; } /* repeat till enough bits are set */ for(; k < 8; k++){ assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= (1 << k); if(--nr_sects_to_alloc == 0){ break; } } } /* free bit was found, write the bit to smap */ if(nr_free_sect){ WR_SECT(dev, nr_smap_blk0 + i); } if(nr_sects_to_alloc == 0){ break; } } assert(nr_sects_to_alloc == 0); return nr_free_sect; }
PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc) { int i, j, k; assert(dev == ROOT_DEV); assert(nr_sects_to_alloc == NR_DEFAULT_FILE_SECTS); struct super_block* sb = get_super_block(dev); assert(sb -> nr_smap_sects); int smap_blk0_nr = 2 + sb -> nr_imap_sects; int free_sect_nr = 0; for (i=0; i<sb -> nr_smap_sects; i++) { RD_SECT(dev, smap_blk0_nr + i); for (j=0; j<SECTOR_SIZE && nr_sects_to_alloc>0; j++) { k = 0; if(!free_sect_nr) { /* 找到第一个空闲的扇区 */ /* 由于文件最大长度固定,并不需要考虑空洞,找到就可以了 */ if (fsbuf[j] == 0xFF) continue; for(; (fsbuf[j] & (1<<k)) != 0; k++) ; free_sect_nr = (i*SECTOR_SIZE + j) * 8 + k - 1 + sb -> n_1st_sect; } for(; k<8; k++) { assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= 1<<k; if (--nr_sects_to_alloc == 0) break; } } if (free_sect_nr) WR_SECT(dev, smap_blk0_nr+i); if (nr_sects_to_alloc == 0) break; } if (nr_sects_to_alloc != 0) { panic("Don't have enough space.\n"); } return free_sect_nr; }
PUBLIC int do_ls() { int i, j; /*printl("DO something \n");*/ /*char pathname[MAX_PATH] = "passwd";*/ /*int inode_nr = search_file(pathname);*/ struct inode * dir_inode = root_inode; int dir_blk0_nr = dir_inode->i_start_sect; int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE; int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; int m = 0; struct dir_entry * pde; printl("\ninode filename\n"); printl("============================\n"); for (i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++, pde++) { /*struct inode *n = find_inode(pde->inode_nr);*/ printl(" %2d %s\n", pde->inode_nr , pde->name); if (++m >= nr_dir_entries){ printl("\n"); break; } } if (m > nr_dir_entries) //[> all entries have been iterated <] break; } printl("============================\n"); return 0; }
PRIVATE void new_dir_entry(struct inode *dir_inode, int inode_nr, char *filename) { /* write the dir_entry */ int dir_blk0_nr = dir_inode->i_start_sect; // 目录文件的起始扇区 int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE; // 目录文件所占扇区数 int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; // 目录项数 int m = 0; struct dir_entry *pde; struct dir_entry *new_de = 0; int i; for (i = 0; i < nr_dir_blks; i++) { // 逐扇区 RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; for (int j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++, pde++) { // 逐目录项 if (++m > nr_dir_entries) break; if (pde->inode_nr == 0) { /* it's a free slot */ new_de = pde; break; } } if (m > nr_dir_entries || // all entries have been iterated or */ new_de) // free slot is found */ break; } if (!new_de) { /* reached the end of the dir */ new_de = pde; dir_inode->i_size += DIR_ENTRY_SIZE; } new_de->inode_nr = inode_nr; strcpy(new_de->name, filename); /* write dir block -- ROOT dir block */ WR_SECT(dir_inode->i_dev, dir_blk0_nr + i); /* update dir inode */ sync_inode(dir_inode); }
/************************************************************************************************** * new_dir_entry ************************************************************************************************** * Write a new entry into the directory. * * @param dir_inode Inode of the directory. * @param nr_inode Inode nr of the new file. * @param filename File name of the new file. *************************************************************************************************/ PRIVATE void new_dir_entry(struct inode* dir_inode, int nr_inode, char* filename){ /* Write the dir_entry */ int nr_dir_blk0 = dir_inode->i_start_sect; int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE; /* including unused slots (the file has been deleted but the slot is still there) */ int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; int m = 0; int i, j; struct dir_entry* pde; struct dir_entry* new_de = 0; for(i=0; i<nr_dir_blks; i++){ RD_SECT(dir_inode->i_dev, nr_dir_blk0 + i); pde = (struct dir_entry*) fsbuf; for(j=0; j<SECTOR_SIZE / DIR_ENTRY_SIZE; j++, pde++){ if(++m > nr_dir_entries){ break; } if(pde->inode_nr == 0){ /* it's a free slot */ new_de = pde; break; } } if(m > nr_dir_entries || new_de){/* all entries have been iterated or */ break; /* free slot is found */ } } if(!new_de){ /* reached the end of the dir */ new_de = pde; dir_inode->i_size += DIR_ENTRY_SIZE; } new_de->inode_nr = nr_inode; strcpy(new_de->name, filename); /* Write dir block -- ROOT dir block */ WR_SECT(dir_inode->i_dev, nr_dir_blk0 + i); /* update dir inode */ sync_inode(dir_inode); }
/** * Search the file and return the inode_nr. * * @param[in] path The full path of the file to search. * @return Ptr to the i-node of the file if successful, otherwise zero. * * @see open() * @see do_open() *****************************************************************************/ PUBLIC int search_file(char * path) { int i, j; char filename[MAX_PATH]; memset(filename, 0, MAX_FILENAME_LEN); struct inode * dir_inode; if (strip_path(filename, path, &dir_inode) != 0) return 0; if (filename[0] == 0) /* path: "/" */ return dir_inode->i_num; /** * Search the dir for the file. */ int dir_blk0_nr = dir_inode->i_start_sect; int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE; int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; /** * including unused slots * (the file has been deleted * but the slot is still there) */ int m = 0; struct dir_entry * pde; for (i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { if (memcmp(filename, pde->name, MAX_FILENAME_LEN) == 0) return pde->inode_nr; if (++m > nr_dir_entries) break; } if (m > nr_dir_entries) /* all entries have been iterated */ break; } /* file not found */ return 0; }
/** * <Ring 1> Do some preparation. * *****************************************************************************/ PRIVATE void init_fs() { int i; /* f_desc_table[] */ for (i = 0; i < NR_FILE_DESC; i++) memset(&f_desc_table[i], 0, sizeof(struct file_desc)); /* inode_table[] */ for (i = 0; i < NR_INODE; i++) memset(&inode_table[i], 0, sizeof(struct inode)); /* super_block[] */ struct super_block * sb = super_block; for (; sb < &super_block[NR_SUPER_BLOCK]; sb++) sb->sb_dev = NO_DEV; /* open the device: hard disk */ MESSAGE driver_msg; driver_msg.type = DEV_OPEN; driver_msg.DEVICE = MINOR(ROOT_DEV); assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg); /* read the super block of ROOT DEVICE */ RD_SECT(ROOT_DEV, 1); sb = (struct super_block *)fsbuf; if (sb->magic != MAGIC_V1) { printl("{FS} mkfs\n"); mkfs(); /* make FS */ } /* load super block of ROOT */ read_super_block(ROOT_DEV); sb = get_super_block(ROOT_DEV); assert(sb->magic == MAGIC_V1); root_inode = get_inode(ROOT_DEV, ROOT_INODE); }
//dev : //num :the no of inodg //return :the ptr to the inode struct inode * get_inode(int dev, int num) { // RD_SECT(dev , 0); if(num == 0) return 0; struct inode *p; struct inode *q =0; for(p = &inode_table[0]; p< &inode_table[NR_INODE]; p++) { if(p->i_cnt) { //we find it in inode table if((p->i_dev == dev )&& (p->i_num == num)) { p->i_cnt++; return p; } } else { //p->i_cnt==0 if(!q) { //the first cnt=0 inode q=p; } } } // if(!q) panic("the inode talbe is full\n"); q->i_dev = dev; q->i_num = num; q->i_cnt = 1; struct super_block * get_super_block(int dev); struct super_block *sb = get_super_block(dev); int blk_nr = 2+sb->nr_imap_sects + sb->nr_smap_sects+ ((num-1)/(SECTOR_SIZE /INODE_SIZE));//inode_nr==0 is not used RD_SECT(dev, blk_nr); struct inode *pinode= (struct inode *)((t_8 *)fsbuf + ((num-1)%(SECTOR_SIZE / INODE_SIZE))*INODE_SIZE ); q->i_mode = pinode->i_mode; q->i_size = pinode->i_size; q->i_start_sect = pinode ->i_start_sect; q->i_nr_sects = pinode->i_nr_sects; return q; }
PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc) { struct super_block *sb = get_super_block(dev); int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; // boot sector + super block + inode map int free_sect_nr = 0; // 空闲 sector 起始号 for (int i = 0; i < sb->nr_smap_sects; i++) { // 逐扇区遍历 sector map RD_SECT(dev, smap_blk0_nr + i); for (int j = 0; j < SECTOR_SIZE && nr_sects_to_alloc > 0; j++) { // 逐字节 int k = 0; if (!free_sect_nr) { if (fsbuf[j] == 0xFF) continue; for (; ((fsbuf[j] >> k) & 1) != 0; k++); // 逐位(一位代表一个扇区) free_sect_nr = (i * SECTOR_SIZE + j) * 8 + k - 1 + sb->n_1st_sect; } for (; k < 8; k++) { assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= (1 << k); if (--nr_sects_to_alloc == 0) break; } } /* 将更新后的 sector map 扇区写入磁盘 */ if (free_sect_nr) WR_SECT(dev, smap_blk0_nr + i); if (nr_sects_to_alloc == 0) break; } assert(nr_sects_to_alloc == 0); return free_sect_nr; }
/* dir_inode: root_node */ PRIVATE void new_dir_entry(struct inode* dir_inode, int inode_nr, char* filename) { int dir_blk0_nr = dir_inode -> i_start_sect; int nr_dir_blks = (dir_inode -> i_size + SECTOR_SIZE) / SECTOR_SIZE; int nr_dir_entries = dir_inode -> i_size / DIR_ENTRY_SIZE; int i, j; int m = 0; struct dir_entry* p_dir_entry; struct dir_entry* new_entry = 0; for(i=0; i<nr_dir_blks; i++) { RD_SECT(dir_inode -> i_dev, dir_blk0_nr + i); p_dir_entry = (struct dir_entry*)fsbuf; for (j = 0; j<SECTOR_SIZE / DIR_ENTRY_SIZE; j++, p_dir_entry++) { if (++m > nr_dir_entries) break; if (p_dir_entry -> inode_nr == 0) { /* 之前被删除的文件留下来的entry */ /* 如果文件删除了,dir_inode -> i_size不会改变 */ new_entry = p_dir_entry; break; } } if (m > nr_dir_entries || new_entry) break; } if (!new_entry) { new_entry = p_dir_entry; dir_inode -> i_size += DIR_ENTRY_SIZE; } new_entry -> inode_nr = inode_nr; strcpy(new_entry -> name, filename); WR_SECT(dir_inode -> i_dev, dir_blk0_nr+i); sync_inode(dir_inode); }
/** * Allocate a bit in sector-map. * * @param dev In which device the sector-map is located. * @param nr_sects_to_alloc How many sectors are allocated. * @param i_zone the zone of the inode * * @return The 1st sector nr allocated. *****************************************************************************/ PRIVATE int alloc_bit(int dev) { int i; /* sector index */ int j; /* byte index */ int k; /* bit index */ struct super_block * sb = get_super_block(dev); int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; int flag_bit_alloc = 0; int bit_alloc = 0; for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */ RD_SECT(dev, smap_blk0_nr + i); /* byte offset in current sect */ for (j = 0; j < SECTOR_SIZE ; j++) { /* loop until a free bit is found */ if (fsbuf[j] != 0xFF) { k = 0; for (; ((fsbuf[j] >> k) & 1) != 0; k++) {} assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= (1 << k); flag_bit_alloc = 1; //1 byte = 8 bit ~ stand for 8 sector bit_alloc = i * SECTOR_SIZE * 8 + j * 8 + k - 1 + sb->n_1st_sect; break; } } if (flag_bit_alloc) { /* free bit found, write the bits to smap */ WR_SECT(dev, smap_blk0_nr + i); break; } }
//path:the full name of the file //return:inode num of the file if success, otherwise zero int search_file(char *path) { #ifdef DEBUG_rw printl("search_file : path =%s|\n", path ); #endif int i,j; char filename[MAX_PATH_LEN]; memset(filename , 0, MAX_FILENAME_LEN); struct inode *dir_inode; if(strip_path(filename, path, &dir_inode)!=0) return 0; #ifdef DEBUG_rw printl("search_file : filename =%s|\n", filename ); #endif if(filename[0]== 0)//path '/' return dir_inode->i_num; //search the dir for the file int dir_sects0_index = dir_inode->i_start_sect; int nr_dir_sects = (dir_inode->i_size +SECTOR_SIZE -1)/SECTOR_SIZE; int nr_dir_dentries = (dir_inode->i_size)/DIR_ENTRY_SIZE; int m= 0; struct dir_entry *pde; for (i = 0; i < nr_dir_sects; ++i) { //里面有空的 RD_SECT(dir_inode->i_dev, dir_sects0_index +i); pde = (struct dir_entry *)fsbuf; for(j=0; j<SECTOR_SIZE/DIR_ENTRY_SIZE; j++ , pde++) { if(memcmp(filename , pde->name, MAX_FILENAME_LEN) == 0) return pde->inode_nr; if(++m >nr_dir_dentries) break; } if(m> nr_dir_dentries) break; } return 0; }
/** * Remove a file. * * @note We clear the i-node in inode_array[] although it is not really needed. * We don't clear the data bytes so the file is recoverable. * * @return On success, zero is returned. On error, -1 is returned. *****************************************************************************/ PUBLIC int do_unlink() { char pathname[MAX_PATH]; /* get parameters from the message */ int name_len = fs_msg.NAME_LEN; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(name_len < MAX_PATH); phys_copy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; if (strcmp(pathname , "/") == 0) { printl("FS:do_unlink():: cannot unlink the root\n"); return -1; } int inode_nr = search_file(pathname); if (inode_nr == INVALID_INODE) { /* file not found */ printl("FS::do_unlink():: search_file() returns " "invalid inode: %s\n", pathname); return -1; } char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; struct inode * pin = get_inode(dir_inode->i_dev, inode_nr); if (pin->i_mode != I_REGULAR) { /* can only remove regular files */ printl("cannot remove file %s, because " "it is not a regular file.\n", pathname); return -1; } if (pin->i_cnt > 1) { /* the file was opened */ printl("cannot remove file %s, because pin->i_cnt is %d.\n", pathname, pin->i_cnt); return -1; } struct super_block * sb = get_super_block(pin->i_dev); /*************************/ /* free the bit in i-map */ /*************************/ int byte_idx = inode_nr / 8; int bit_idx = inode_nr % 8; assert(byte_idx < SECTOR_SIZE); /* we have only one i-map sector */ /* read sector 2 (skip bootsect and superblk): */ RD_SECT(pin->i_dev, 2); assert(fsbuf[byte_idx % SECTOR_SIZE] & (1 << bit_idx)); fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << bit_idx); WR_SECT(pin->i_dev, 2); /**************************/ /* free the bits in s-map */ /**************************/ /* * bit_idx: bit idx in the entire i-map * ... ____|____ * \ .-- byte_cnt: how many bytes between * \ | the first and last byte * +-+-+-+-+-+-+-+-+ V +-+-+-+-+-+-+-+-+ * ... | | | | | |*|*|*|...|*|*|*|*| | | | | * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 * ...__/ * byte_idx: byte idx in the entire i-map */ bit_idx = pin->i_start_sect - sb->n_1st_sect + 1; byte_idx = bit_idx / 8; int bits_left = pin->i_nr_sects; int byte_cnt = (bits_left - (8 - (bit_idx % 8))) / 8; /* current sector nr. */ int s = 2 /* 2: bootsect + superblk */ + sb->nr_imap_sects + byte_idx / SECTOR_SIZE; RD_SECT(pin->i_dev, s); int i; /* clear the first byte */ for (i = bit_idx % 8; (i < 8) && bits_left; i++,bits_left--) { //assert((fsbuf[byte_idx % SECTOR_SIZE] >> i & 1) == 1); fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << i); } /* clear bytes from the second byte to the second to last */ int k; i = (byte_idx % SECTOR_SIZE) + 1; /* the second byte */ for (k = 0; k < byte_cnt; k++,i++,bits_left-=8) { if (i == SECTOR_SIZE) { i = 0; WR_SECT(pin->i_dev, s); RD_SECT(pin->i_dev, ++s); } //assert(fsbuf[i] == 0xFF); fsbuf[i] = 0; } /* clear the last byte */ if (i == SECTOR_SIZE) { i = 0; WR_SECT(pin->i_dev, s); RD_SECT(pin->i_dev, ++s); } unsigned char mask = ~((unsigned char)(~0) << bits_left); //assert((fsbuf[i] & mask) == mask); fsbuf[i] &= (~0) << bits_left; WR_SECT(pin->i_dev, s); /***************************/ /* clear the i-node itself */ /***************************/ pin->i_mode = 0; pin->i_size = 0; pin->i_start_sect = 0; pin->i_nr_sects = 0; sync_inode(pin); /* release slot in inode_table[] */ put_inode(pin); /************************************************/ /* set the inode-nr to 0 in the directory entry */ /************************************************/ int dir_blk0_nr = dir_inode->i_start_sect; int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE; int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; /* including unused slots * (the file has been * deleted but the slot * is still there) */ int m = 0; struct dir_entry * pde = 0; int flg = 0; int dir_size = 0; for (i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; int j; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { if (++m > nr_dir_entries) break; if (pde->inode_nr == inode_nr) { /* pde->inode_nr = 0; */ memset(pde, 0, DIR_ENTRY_SIZE); WR_SECT(dir_inode->i_dev, dir_blk0_nr + i); flg = 1; break; } if (pde->inode_nr != INVALID_INODE) dir_size += DIR_ENTRY_SIZE; } if (m > nr_dir_entries || /* all entries have been iterated OR */ flg) /* file is found */ break; } assert(flg); if (m == nr_dir_entries) { /* the file is the last one in the dir */ dir_inode->i_size = dir_size; sync_inode(dir_inode); } return 0; }
/** * <Ring 1> Make a available Orange'S FS in the disk. It will * - Write a super block to sector 1. * - Create three special files: dev_tty0, dev_tty1, dev_tty2 * - Create a file cmd.tar * - Create the inode map * - Create the sector map * - Create the inodes of the files * - Create `/', the root directory *****************************************************************************/ PRIVATE void mkfs() { MESSAGE driver_msg; int i, j; /************************/ /* super block */ /************************/ /* get the geometry of ROOTDEV */ struct part_info geo; driver_msg.type = DEV_IOCTL; driver_msg.DEVICE = MINOR(ROOT_DEV); driver_msg.REQUEST = DIOCTL_GET_GEO; driver_msg.BUF = &geo; driver_msg.PROC_NR = TASK_FS; assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg); printl("{FS} dev size: 0x%x sectors\n", geo.size); int bits_per_sect = SECTOR_SIZE * 8; /* 8 bits per byte */ /* generate a super block */ struct super_block sb; sb.magic = MAGIC_V1; /* 0x111 */ sb.nr_inodes = bits_per_sect; sb.nr_inode_sects = sb.nr_inodes * INODE_SIZE / SECTOR_SIZE; sb.nr_sects = geo.size; /* partition size in sector */ sb.nr_imap_sects = 1; sb.nr_smap_sects = sb.nr_sects / bits_per_sect + 1; sb.n_1st_sect = 1 + 1 + /* boot sector & super block */ sb.nr_imap_sects + sb.nr_smap_sects + sb.nr_inode_sects; sb.root_inode = ROOT_INODE; sb.inode_size = INODE_SIZE; struct inode x; sb.inode_isize_off= (int)&x.i_size - (int)&x; sb.inode_start_off= (int)&x.i_start_sect - (int)&x; sb.dir_ent_size = DIR_ENTRY_SIZE; struct dir_entry de; sb.dir_ent_inode_off = (int)&de.inode_nr - (int)&de; sb.dir_ent_fname_off = (int)&de.name - (int)&de; memset(fsbuf, 0x90, SECTOR_SIZE); memcpy(fsbuf, &sb, SUPER_BLOCK_SIZE); /* write the super block */ WR_SECT(ROOT_DEV, 1); printl("{FS} devbase:0x%x00, sb:0x%x00, imap:0x%x00, smap:0x%x00\n" " inodes:0x%x00, 1st_sector:0x%x00\n", geo.base * 2, (geo.base + 1) * 2, (geo.base + 1 + 1) * 2, (geo.base + 1 + 1 + sb.nr_imap_sects) * 2, (geo.base + 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects) * 2, (geo.base + sb.n_1st_sect) * 2); /************************/ /* inode map */ /************************/ memset(fsbuf, 0, SECTOR_SIZE); for (i = 0; i < (NR_CONSOLES + 3); i++) fsbuf[0] |= 1 << i; assert(fsbuf[0] == 0x3F);/* 0011 1111 : * || |||| * || |||`--- bit 0 : reserved * || ||`---- bit 1 : the first inode, * || || which indicates `/' * || |`----- bit 2 : /dev_tty0 * || `------ bit 3 : /dev_tty1 * |`-------- bit 4 : /dev_tty2 * `--------- bit 5 : /cmd.tar */ WR_SECT(ROOT_DEV, 2); /************************/ /* secter map */ /************************/ memset(fsbuf, 0, SECTOR_SIZE); int nr_sects = NR_DEFAULT_FILE_SECTS + 1; /* ~~~~~~~~~~~~~~~~~~~|~ | * | `--- bit 0 is reserved * `-------- for `/' */ for (i = 0; i < nr_sects / 8; i++) fsbuf[i] = 0xFF; for (j = 0; j < nr_sects % 8; j++) fsbuf[i] |= (1 << j); WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects); /* zeromemory the rest sector-map */ memset(fsbuf, 0, SECTOR_SIZE); for (i = 1; i < sb.nr_smap_sects; i++) WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + i); /* cmd.tar */ /* make sure it'll not be overwritten by the disk log */ assert(INSTALL_START_SECT + INSTALL_NR_SECTS < sb.nr_sects - NR_SECTS_FOR_LOG); int bit_offset = INSTALL_START_SECT - sb.n_1st_sect + 1; /* sect M <-> bit (M - sb.n_1stsect + 1) */ int bit_off_in_sect = bit_offset % (SECTOR_SIZE * 8); int bit_left = INSTALL_NR_SECTS; int cur_sect = bit_offset / (SECTOR_SIZE * 8); RD_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); while (bit_left) { int byte_off = bit_off_in_sect / 8; /* this line is ineffecient in a loop, but I don't care */ fsbuf[byte_off] |= 1 << (bit_off_in_sect % 8); bit_left--; bit_off_in_sect++; if (bit_off_in_sect == (SECTOR_SIZE * 8)) { WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); cur_sect++; RD_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); bit_off_in_sect = 0; } } WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); /************************/ /* inodes */ /************************/ /* inode of `/' */ memset(fsbuf, 0, SECTOR_SIZE); struct inode * pi = (struct inode*)fsbuf; pi->i_mode = I_DIRECTORY; pi->i_size = DIR_ENTRY_SIZE * 5; /* 5 files: * `.', * `dev_tty0', `dev_tty1', `dev_tty2', * `cmd.tar' */ pi->i_start_sect = sb.n_1st_sect; pi->i_nr_sects = NR_DEFAULT_FILE_SECTS; /* inode of `/dev_tty0~2' */ for (i = 0; i < NR_CONSOLES; i++) { pi = (struct inode*)(fsbuf + (INODE_SIZE * (i + 1))); pi->i_mode = I_CHAR_SPECIAL; pi->i_size = 0; pi->i_start_sect = MAKE_DEV(DEV_CHAR_TTY, i); pi->i_nr_sects = 0; } /* inode of `/cmd.tar' */ pi = (struct inode*)(fsbuf + (INODE_SIZE * (NR_CONSOLES + 1))); pi->i_mode = I_REGULAR; pi->i_size = INSTALL_NR_SECTS * SECTOR_SIZE; pi->i_start_sect = INSTALL_START_SECT; pi->i_nr_sects = INSTALL_NR_SECTS; WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + sb.nr_smap_sects); /************************/ /* `/' */ /************************/ memset(fsbuf, 0, SECTOR_SIZE); struct dir_entry * pde = (struct dir_entry *)fsbuf; pde->inode_nr = 1; strcpy(pde->name, "."); /* dir entries of `/dev_tty0~2' */ for (i = 0; i < NR_CONSOLES; i++) { pde++; pde->inode_nr = i + 2; /* dev_tty0's inode_nr is 2 */ sprintf(pde->name, "dev_tty%d", i); } (++pde)->inode_nr = NR_CONSOLES + 2; sprintf(pde->name, "cmd.tar", i); WR_SECT(ROOT_DEV, sb.n_1st_sect); }
PRIVATE void mkfs() { MESSAGE driver_msg; int bits_per_sect = SECTOR_SIZE * 8; struct part_info geo; driver_msg.type = DEV_IOCTL; driver_msg.DEVICE = MINOR(ROOT_DEV); driver_msg.REQUEST = DIOCTL_GET_GEO; driver_msg.BUF = &geo; driver_msg.PROC_NR = TASK_FS; assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg); printl("dev base: 0x%x, dev size: 0x%x sectors\n", geo.base, geo.size); /***********************/ /* super block */ /***********************/ struct super_block sb; sb.magic = MAGIC_V1; sb.nr_inodes = bits_per_sect; sb.nr_sects = geo.size; sb.nr_imap_sects = 1; sb.nr_smap_sects = sb.nr_sects / bits_per_sect + 1; sb.nr_inode_sects = sb.nr_inodes * INODE_SIZE / SECTOR_SIZE; sb.n_1st_sect = 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects + sb.nr_inode_sects; sb.root_inode = ROOT_INODE; sb.inode_size = INODE_SIZE; sb.inode_isize_off = offsetof(struct inode, i_size); sb.inode_start_off = offsetof(struct inode, i_start_sect); sb.dir_ent_size = DIR_ENTRY_SIZE; sb.dir_ent_inode_off = offsetof(struct dir_entry, inode_nr); sb.dir_ent_fname_off = offsetof(struct dir_entry, name); memset(fsbuf, 0x90, SECTOR_SIZE); memcpy(fsbuf, &sb, SUPER_BLOCK_SIZE); WR_SECT(ROOT_DEV, 1); // write the super block printl( "devbase: 0x%x00, sb: 0x%x00, imap: 0x%x00, smap: 0x%x00\n" " inodes: 0x%x00, 1st_sector: 0x%x00\n", geo.base * 2, (geo.base + 1) * 2, (geo.base + 1 + 1) * 2, (geo.base + 1 + 1 + sb.nr_imap_sects) * 2, (geo.base + 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects) * 2, (geo.base + sb.n_1st_sect) * 2 ); /***********************/ /* inode Map */ /***********************/ memset(fsbuf, 0x0, SECTOR_SIZE); for (int i = 0; i < (NR_CONSOLES + 3); i++) fsbuf[0] |= 1 << i; assert(fsbuf[0] == 0x3F); /* 0011 1111 * || |||`- bit 0 : reserved * || ||`-- bit 1 : the frist inode which indicates '/' * || |`--- bit 2 : /dev_tty0 * || `---- bit 3 : /dev_tty1 * |`------ bit 4 : /dev_tty2 * `------- bit 5 : /cmd.tar */ WR_SECT(ROOT_DEV, 2); /***********************/ /* sector Map */ /***********************/ memset(fsbuf, 0x0, SECTOR_SIZE); int nr_sects = NR_DEFAULT_FILE_SECTS + 1; int i; for (i = 0; i < nr_sects / 8; i++) fsbuf[i] = 0xFF; for (int j = 0; j < nr_sects % 8; j++) fsbuf[i] |= (1 << i); WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects); memset(fsbuf, 0x0, SECTOR_SIZE); for (int i = 1; i < sb.nr_smap_sects; i++) WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + i); /* cmd.tar */ int bit_offset = INSTALL_START_SECT - sb.n_1st_sect + 1; // sect M <-> bit (M - sb.n_1stsect + 1) int bit_off_in_sect = bit_offset % (SECTOR_SIZE * 8); int bit_left = INSTALL_NR_SECTS; int cur_sect = bit_offset / (SECTOR_SIZE * 8); RD_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); while (bit_left) { int byte_off = bit_off_in_sect / 8; /* this line is ineffecient in a loop, but I don't care */ fsbuf[byte_off] |= 1 << (bit_off_in_sect % 8); bit_left--; bit_off_in_sect++; if (bit_off_in_sect == (SECTOR_SIZE * 8)) { WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); cur_sect++; RD_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); bit_off_in_sect = 0; } } WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect); /***********************/ /* inodes */ /***********************/ memset(fsbuf, 0x0, SECTOR_SIZE); struct inode *pi = (struct inode *)fsbuf; pi->i_mode = I_DIRECTORY; pi->i_size = DIR_ENTRY_SIZE * 5; // 5 files pi->i_start_sect = sb.n_1st_sect; pi->i_nr_sects = NR_DEFAULT_FILE_SECTS; for (int i = 0; i < NR_CONSOLES; i++) { pi = (struct inode *)(fsbuf + (INODE_SIZE * (i + 1))); pi->i_mode = I_CHAR_SPECIAL; pi->i_size = 0; pi->i_start_sect = MAKE_DEV(DEV_CHAR_TTY, i); pi->i_nr_sects = 0; } /* inode of `/cmd.tar' */ pi = (struct inode*)(fsbuf + (INODE_SIZE * (NR_CONSOLES + 1))); pi->i_mode = I_REGULAR; pi->i_size = INSTALL_NR_SECTS * SECTOR_SIZE; pi->i_start_sect = INSTALL_START_SECT; pi->i_nr_sects = INSTALL_NR_SECTS; WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + sb.nr_smap_sects); /***********************/ /* '/' */ /***********************/ memset(fsbuf, 0x0, SECTOR_SIZE); struct dir_entry *pde = (struct dir_entry *)fsbuf; pde->inode_nr = 1; strcpy(pde->name, "."); for (int i = 0; i < NR_CONSOLES; i++) { pde++; pde->inode_nr = i + 2; sprintf(pde->name, "dev_tty%d", i); } (++pde)->inode_nr = NR_CONSOLES + 2; strcpy(pde->name, "cmd.tar"); WR_SECT(ROOT_DEV, sb.n_1st_sect); }
/** * Allocate a bit in sector-map. * * @param dev In which device the sector-map is located. * @param nr_sects_to_alloc How many sectors are allocated. * * @return The 1st sector nr allocated. *****************************************************************************/ PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc) { /* int nr_sects_to_alloc = NR_DEFAULT_FILE_SECTS; */ int i; /* sector index */ int j; /* byte index */ int k; /* bit index */ struct super_block * sb = get_super_block(dev); int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; int free_sect_nr = 0; for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */ RD_SECT(dev, smap_blk0_nr + i); /* byte offset in current sect */ for (j = 0; j < SECTOR_SIZE && nr_sects_to_alloc > 0; j++) { k = 0; if (!free_sect_nr) { /* loop until a free bit is found */ if (fsbuf[j] == 0xFF) continue; for (; ((fsbuf[j] >> k) & 1) != 0; k++) {} free_sect_nr = (i * SECTOR_SIZE + j) * 8 + k - 1 + sb->n_1st_sect; if (free_sect_nr + nr_sects_to_alloc > sb->nr_sects) { /* FIXME: instead of halting the system, * telling the caller to handle this * will be better */ panic("disk is full"); } } for (; k < 8; k++) { /* repeat till enough bits are set */ assert(nr_sects_to_alloc > 0); /* * this assert will fail if the disk is full * (we would be overwriting "cmd.tar" to * create the new file) * * for example, if we have a 80MB hard disk, * we may not be able to create more than 14 * regulare files * * @see doc/README::"cmd.tar" for details */ assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= (1 << k); if (--nr_sects_to_alloc == 0) break; } } if (free_sect_nr) /* free bit found, write the bits to smap */ WR_SECT(dev, smap_blk0_nr + i); if (nr_sects_to_alloc == 0) break; } assert(nr_sects_to_alloc == 0); return free_sect_nr; }
/** * <Ring 1> This routine handles the DEV_LOG message. * * @param p Ptr to the MESSAGE. *****************************************************************************/ PUBLIC int disklog(char * logstr) { int device = root_inode->i_dev; struct super_block * sb = get_super_block(device); int nr_log_blk0_nr = sb->nr_sects - NR_SECTS_FOR_LOG; /* 0x9D41-0x800=0x9541 */ static int pos = 0; if (!pos) { /* first time invoking this routine */ #ifdef SET_LOG_SECT_SMAP_AT_STARTUP /* * set sector-map so that other files cannot use the log sectors */ int bits_per_sect = SECTOR_SIZE * 8; /* 4096 */ int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; /* 3 */ int sect_nr = smap_blk0_nr + nr_log_blk0_nr / bits_per_sect; /* 3+9=12 */ int byte_off = (nr_log_blk0_nr % bits_per_sect) / 8; /* 168 */ int bit_off = (nr_log_blk0_nr % bits_per_sect) % 8; /* 1 */ int sect_cnt = NR_SECTS_FOR_LOG / bits_per_sect + 2; /* 1 */ int bits_left= NR_SECTS_FOR_LOG; /* 2048 */ int i; for (i = 0; i < sect_cnt; i++) { RD_SECT(device, sect_nr + i); /* RD_SECT(?, 12) */ for (; byte_off < SECTOR_SIZE && bits_left > 0; byte_off++) { for (; bit_off < 8; bit_off++) { /* repeat till enough bits are set */ assert(((fsbuf[byte_off] >> bit_off) & 1) == 0); fsbuf[byte_off] |= (1 << bit_off); if (--bits_left == 0) break; } bit_off = 0; } byte_off = 0; bit_off = 0; WR_SECT(device, sect_nr + i); if (bits_left == 0) break; } assert(bits_left == 0); #endif /* SET_LOG_SECT_SMAP_AT_STARTUP */ pos = 0x40; #ifdef MEMSET_LOG_SECTS /* write padding stuff to log sectors */ int chunk = min(MAX_IO_BYTES, FSBUF_SIZE >> SECTOR_SIZE_SHIFT); assert(chunk == 256); int sects_left = NR_SECTS_FOR_LOG; for (i = nr_log_blk0_nr; i < nr_log_blk0_nr + NR_SECTS_FOR_LOG; i += chunk) { memset(fsbuf, 0x20, chunk*SECTOR_SIZE); rw_sector(DEV_WRITE, device, i * SECTOR_SIZE, chunk * SECTOR_SIZE, TASK_FS, fsbuf); sects_left -= chunk; } if (sects_left != 0) panic("sects_left should be 0, current: %d.", sects_left); #endif /* MEMSET_LOG_SECTS */ }
/* * === FUNCTION ====================================================================== * Name: alloc_zone * Description: alloc zone * @param dev : In which device the sector-map is located. * @param alloc_start: the start sect of the buf * @param alloc_nr: the amount of the sect of the buf * @param i_zone: the zone of the inode * @return: the amount of allocated zones * ===================================================================================== */ PRIVATE int alloc_zone (int dev, int alloc_start, int alloc_nr, zone_t * i_zone) { int i; int flag_no_zone = 0; int nr_sect = alloc_start + alloc_nr; if (alloc_start < NR_DIRECT_ZONE) { //the sectors are only in the direct zone int flag_direct_zone = 1; //asumpt the amount of the sect is less than direct zone int direct_alloc_nr = alloc_nr; if (nr_sect > NR_DIRECT_ZONE) { //the amount of sects is less than the direct zone flag_direct_zone = 0; direct_alloc_nr = NR_DIRECT_ZONE - alloc_start; alloc_nr -= direct_alloc_nr; } for (i = 0; i < direct_alloc_nr; i++) { if (NO_ZONE == i_zone[alloc_start + i]) { alloc_sect(dev, &i_zone[alloc_start + i]); } } if (flag_direct_zone) { return nr_sect - alloc_start; } } //the first level indirect zone zone_t sectors[NR_ZONE_PER_SECT]; if (alloc_start < NR_SECOND_LEVEL_ZONE) { int second_level_start = NR_DIRECT_ZONE; if (alloc_start > second_level_start) { second_level_start = alloc_start; } //the sectors are only reach the second level int flag_second_level = 1; int second_alloc_nr = alloc_nr; if (nr_sect > NR_SECOND_LEVEL_ZONE) { //the amount of sects is less than the second level zone flag_second_level = 0; second_alloc_nr = NR_SECOND_LEVEL_ZONE - second_level_start; alloc_nr -= second_alloc_nr; } //get the begin and end in second level zone second_level_start -= NR_DIRECT_ZONE; //if the inode has second level zone flag_no_zone = 0; if (NO_ZONE == i_zone[SECOND_LEVEL_ZONE]) { //the second level zone is not available yet alloc_sect(dev, &i_zone[SECOND_LEVEL_ZONE]); flag_no_zone = 1; } RD_SECT(dev, i_zone[SECOND_LEVEL_ZONE]); memcpy((void *)sectors, (void *)fsbuf, NR_SECT_PER_SECOND_LEVEL_ZONE * sizeof(int) ); if (flag_no_zone) { for (i = 0; i < NR_SECT_PER_SECOND_LEVEL_ZONE; i++) { sectors[i] = NO_ZONE; } } for (i = 0; i < second_alloc_nr; i++) { if (NO_ZONE == sectors[second_level_start + i]) { alloc_sect(dev, §ors[second_level_start + i]); } } //sync to disk memcpy((void *)fsbuf, (void *)sectors, NR_SECT_PER_SECOND_LEVEL_ZONE * sizeof(int) ); WR_SECT(dev, i_zone[SECOND_LEVEL_ZONE]); //if the zones only reach second level if (flag_second_level) { return nr_sect - alloc_start; } } if (alloc_start < NR_THIRD_LEVEL_ZONE) { //less than the third level indirect zone int third_level_start = NR_SECOND_LEVEL_ZONE; if (alloc_start > third_level_start) { third_level_start = alloc_start; } //the sectors are only reach the third level int flag_third_level = 1; int third_alloc_nr = alloc_nr; if (nr_sect > NR_THIRD_LEVEL_ZONE) { //the amount of sects is less than the third level zone flag_third_level = 0; third_alloc_nr = NR_THIRD_LEVEL_ZONE - third_level_start; alloc_nr -= third_alloc_nr; } //get the start and end in third level zone third_level_start -= NR_SECOND_LEVEL_ZONE; //if the inode has third level zone flag_no_zone = 0; if (NO_ZONE == i_zone[THIRD_LEVEL_ZONE]) { //the third level zone is not available yet alloc_sect(dev, &i_zone[THIRD_LEVEL_ZONE]); flag_no_zone = 1; } RD_SECT(dev, i_zone[THIRD_LEVEL_ZONE]); memcpy((void *)sectors, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); if (flag_no_zone) { for (i = 0; i < NR_ZONE_PER_SECT; i++) { sectors[i] = NO_ZONE; } } int current_second_level_zone = NO_ZONE; zone_t current_zones[NR_ZONE_PER_SECT]; for (i = 0; i < third_alloc_nr; i++) { int second_level_index = (third_level_start + i) / NR_SECT_PER_SECOND_LEVEL_ZONE; int third_level_index = (third_level_start + i) % NR_SECT_PER_SECOND_LEVEL_ZONE; if (NO_ZONE == current_second_level_zone || current_second_level_zone != second_level_index){ if (NO_ZONE != current_second_level_zone) { //the previous zone is done for writing //sync to disk memcpy((void *)fsbuf, (void *)current_zones, NR_ZONE_PER_SECT * sizeof(int) ); WR_SECT(dev, current_second_level_zone); } //the second level zone is a slot flag_no_zone = 0; if (NO_ZONE == sectors[second_level_index]) { flag_no_zone = 1; alloc_sect(dev, §ors[second_level_index]); } current_second_level_zone = sectors[second_level_index]; RD_SECT(dev, sectors[second_level_index]); memcpy((void *)current_zones, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); //if the second level zone is a slot, get to init if (flag_no_zone) { for (i = 0; i < NR_ZONE_PER_SECT; i++) { current_zones[i] = NO_ZONE; } } } if (NO_ZONE == current_zones[third_level_index]) { alloc_sect(dev, ¤t_zones[third_level_index]); } } //sync the rest second level zone to disk if (NO_ZONE != current_second_level_zone) { //the previous zone is done for writing //sync to disk memcpy((void *)fsbuf, (void *)current_zones, NR_ZONE_PER_SECT * sizeof(int) ); WR_SECT(dev, current_second_level_zone); } //sync to disk memcpy((void *)fsbuf, (void *)sectors, NR_ZONE_PER_SECT * sizeof(int) ); WR_SECT(dev, i_zone[THIRD_LEVEL_ZONE]); //if the zones only reach third level if (flag_third_level) { return nr_sect - alloc_start; } } if (nr_sect > NR_THIRD_LEVEL_ZONE) { //do not support zones larger than third level panic("file is too large"); } return -1; } /* ----- end of function alloc_zone ----- */
/* * === FUNCTION ====================================================================== * Name: rdwt_zones * Description: read of write the buf to the zones * @param pos: the current position in the file * @param buf_len: the length of the buf * @param src: the source of the buf * @param buf: the buf should be read or written * @param i_nr_sects: the current amount of the sects of the file * @param i_zone: the i_zone of this inode * @param mode: READ or WRITE * @return : how many bytes writed or read * ===================================================================================== */ PRIVATE int rdwt_zones ( int pos, int len, int src, char * buf, struct inode * pin, int mode) { //check if the mode is right assert(WRITE == mode || READ == mode); int i; int align = 0; int pos_end = pos + len; //larger than file in read mode if (READ == mode) { if (pos > pin->i_size) { //read start is larger than the file, get nothing return 0; } else if (pos_end > pin->i_size) { //read end is larger than the file, just end at the EOF len -= (pos_end - pin->i_size); pos_end = pin->i_size; } } //how many sects does the buf need to take int nr_sect_start = pos >> SECTOR_SIZE_SHIFT; int nr_rw_sect = len >> SECTOR_SIZE_SHIFT; int off = pos_end % SECTOR_SIZE; //if the buf is not n * SECTOR_SIZE, just give one more sector if (off > 0) { nr_rw_sect ++; } int nr_sect = nr_sect_start + nr_rw_sect; //if the sects in the file is not enough if (nr_sect > pin->i_nr_sects) { //allocate the sectors that needed assert(WRITE == mode); u32 zone_amount = alloc_zone(pin->i_dev, pin->i_nr_sects, nr_sect - pin->i_nr_sects, pin->i_zone); assert(nr_sect - pin->i_nr_sects == zone_amount); pin->i_nr_sects += zone_amount; } if (nr_sect_start < NR_DIRECT_ZONE) { //the sectors are only in the direct zone int flag_direct_zone = 1; //asumpt the amount of the sect is less than direct zone int direct_nr_rw_sect = nr_rw_sect; if (nr_sect > NR_DIRECT_ZONE) { //the amount of sects is more than the direct zone flag_direct_zone = 0; direct_nr_rw_sect = NR_DIRECT_ZONE - nr_sect_start; nr_rw_sect -= direct_nr_rw_sect; } for (i = 0; i < direct_nr_rw_sect; i++, align++) { if (WRITE == mode) { phys_copy((void*)va2la(TASK_FS, fsbuf), (void*)va2la(src, buf + align * SECTOR_SIZE), SECTOR_SIZE); WR_SECT(pin->i_dev, pin->i_zone[nr_sect_start + i]); } else if (READ == mode) { RD_SECT(pin->i_dev, pin->i_zone[nr_sect_start + i]); phys_copy((void*)va2la(src, buf + align * SECTOR_SIZE), (void*)va2la(TASK_FS, fsbuf), SECTOR_SIZE); } } if (flag_direct_zone) { return len; } } //the first level indirect zone zone_t sectors[NR_ZONE_PER_SECT]; if (nr_sect_start < NR_SECOND_LEVEL_ZONE) { int second_level_start = NR_DIRECT_ZONE; if (nr_sect_start > second_level_start) { second_level_start = nr_sect_start; } //the sectors are only reach the second level int flag_second_level = 1; int second_nr_rw_sect = nr_rw_sect; if (nr_sect > NR_SECOND_LEVEL_ZONE) { //the amount of sects is more than the second level zone flag_second_level = 0; second_nr_rw_sect = NR_SECOND_LEVEL_ZONE - second_level_start; nr_rw_sect -= second_nr_rw_sect; } //get the begin and end in second level zone second_level_start -= NR_DIRECT_ZONE; RD_SECT(pin->i_dev, pin->i_zone[SECOND_LEVEL_ZONE]); memcpy((void *)sectors, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); for (i = 0; i < second_nr_rw_sect; i++, align++) { if (WRITE == mode) { phys_copy((void*)va2la(TASK_FS, fsbuf), (void*)va2la(src, buf + align * SECTOR_SIZE), SECTOR_SIZE); WR_SECT(pin->i_dev, sectors[second_level_start + i]); } else if(READ == mode) { RD_SECT(pin->i_dev, sectors[second_level_start + i]); phys_copy((void*)va2la(src, buf + align * SECTOR_SIZE), (void*)va2la(TASK_FS, fsbuf), SECTOR_SIZE); } } //if the zones only reach second level if (flag_second_level) { return len; } } if (nr_sect_start < NR_THIRD_LEVEL_ZONE) { //less than the third level indirect zone int third_level_start = NR_SECOND_LEVEL_ZONE; if (nr_sect_start > third_level_start) { third_level_start = nr_sect_start; } //the sectors are only reach the third level int flag_third_level = 1; int third_nr_rw_sect = nr_rw_sect; if (nr_sect > NR_THIRD_LEVEL_ZONE) { //the amount of sects is more than the third level zone flag_third_level = 0; third_nr_rw_sect = NR_THIRD_LEVEL_ZONE - third_level_start; nr_rw_sect -= third_nr_rw_sect; } //get the start and end in third level zone third_level_start -= NR_SECOND_LEVEL_ZONE; RD_SECT(pin->i_dev, pin->i_zone[THIRD_LEVEL_ZONE]); memcpy((void *)sectors, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); int current_second_level_zone = NO_ZONE; zone_t current_zones[NR_ZONE_PER_SECT]; for (i = 0; i < third_nr_rw_sect; i++, align++) { int second_level_index = (third_level_start + i) / NR_SECT_PER_SECOND_LEVEL_ZONE; int third_level_index = (third_level_start + i) % NR_SECT_PER_SECOND_LEVEL_ZONE; if (NO_ZONE == current_second_level_zone || current_second_level_zone != sectors[second_level_index]){ RD_SECT(pin->i_dev, sectors[second_level_index]); memcpy((void *)current_zones, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); } //record the current second level zone for compare in next time //to comfirm if that the current second level zone is finished current_second_level_zone = sectors[second_level_index]; if (WRITE == mode) { phys_copy((void*)va2la(TASK_FS, fsbuf), (void*)va2la(src, buf + align * SECTOR_SIZE), SECTOR_SIZE); WR_SECT(pin->i_dev, current_zones[third_level_index]); } else if(READ == mode) { RD_SECT(pin->i_dev, current_zones[third_level_index]); phys_copy((void*)va2la(src, buf + align * SECTOR_SIZE), (void*)va2la(TASK_FS, fsbuf), SECTOR_SIZE); } } //if the zones only reach third level if (flag_third_level) { return len; } } if (nr_sect > NR_THIRD_LEVEL_ZONE) { //do not support zones larger than third level panic("buf is too large"); } return -1; } /* ----- end of function rdwt_zones ----- */