/* * Initializes the file system manager. */ PUBLIC void fs_init(void) { binit(); inode_init(); superblock_init(); /* Sanity check. */ CHKSIZE(sizeof(struct d_dirent), sizeof(struct dirent)); rootdev = superblock_read(ROOT_DEV); /* Failed to read root super block. */ if (rootdev == NULL) kpanic("failed to mount root file system"); superblock_unlock(rootdev); root = inode_get(ROOT_DEV, 1); /* Failed to read root inode. */ if (root == NULL) kpanic("failed to read root inode"); kprintf("fs: root file system mounted"); /* Hand craft idle process. */ IDLE->pwd = root; IDLE->root = root; root->count += 2; inode_unlock(root); }
/** * @brief Create an indirect block. * * @details Creates a indirect block and saves in @param dest. * * @param dest Destination buffer, It is the corresponding disk block to be changed. * @param ip File to use. * @param offset Offset to be calculated the block. * @param creat If 1, creates an block, otherwise, just return this value. * * @returns If successful, the block number created / obtained, otherwise BLOCK_NULL is * returned. * * @note @p ip must be locked. */ PUBLIC block_t create_indirect_block (struct buffer *dest, struct inode *ip, off_t offset, int create) { block_t phys; /* Physical block number. */ if (((block_t *)buffer_data(dest))[offset] == BLOCK_NULL && create) { /* Allocate an block. */ superblock_lock(ip->sb); phys = block_alloc(ip->sb); superblock_unlock(ip->sb); if (phys != BLOCK_NULL) { ((block_t *)buffer_data(dest))[offset] = phys; buffer_dirty(dest, 1); inode_touch(ip); brelse(dest); return (phys); } else { brelse(dest); return (phys); } } else { brelse(dest); return ((block_t *)buffer_data(dest))[offset]; } }
/** * @brief Create an direct block. * * @details Creates a direct block and saves in @param dest. * * @param ip File to use. * @param offset Offset to be calculated the block. * @param creat If 1, creates an block, otherwise, just return this value. * * @returns If successful, the block number created/obtained, otherwise BLOCK_NULL is * returned. * * @note @p ip must be locked. */ PUBLIC block_t create_direct_block(struct inode *ip, off_t offset, int create) { block_t phys; /* Physical block number. */ if (ip->blocks[offset] == BLOCK_NULL && create) { /* Allocate an block. */ superblock_lock(ip->sb); phys = block_alloc(ip->sb); superblock_unlock(ip->sb); if (phys != BLOCK_NULL) { ip->blocks[offset] = phys; inode_touch(ip); return (phys); } else return (phys); } else return (ip->blocks[offset]); }
/** * @brief Maps a file byte offset in a disk block number. * * @details Maps the offset @p off in the file pointed to by @p ip in a disk * block number. If @p create is not zero and such file by offset is * invalid, the file is expanded accordingly to make it valid. * * @param ip File to use * @param off File byte offset. * @param create Create offset? * * @returns Upon successful completion, the disk block number that is associated * with the file byte offset is returned. Upon failure, #BLOCK_NULL is * returned instead. * * @note @p ip must be locked. */ PUBLIC block_t block_map(struct inode *ip, off_t off, int create) { block_t phys; /* Physical block number. */ block_t logic; /* Logical block number. */ struct buffer *buf; /* Underlying buffer. */ unsigned tmp; /* Logical block number tmp. */ logic = off/BLOCK_SIZE; /* File offset too big. */ if (off >= ip->sb->max_size) { curr_proc->errno = -EFBIG; return (BLOCK_NULL); } /* * Create blocks that are * in a valid offset. */ if (off < ip->size) create = 1; /* Direct block. */ if (logic < NR_ZONES_DIRECT) { /* Create direct block. */ if (ip->blocks[logic] == BLOCK_NULL && create) { superblock_lock(ip->sb); phys = block_alloc(ip->sb); superblock_unlock(ip->sb); if (phys != BLOCK_NULL) { ip->blocks[logic] = phys; inode_touch(ip); } } return (ip->blocks[logic]); } logic -= NR_ZONES_DIRECT; /* Single indirect block. */ if (logic < NR_SINGLE) { /* Create single indirect block. */ if (ip->blocks[ZONE_SINGLE] == BLOCK_NULL && create) { superblock_lock(ip->sb); phys = block_alloc(ip->sb); superblock_unlock(ip->sb); if (phys != BLOCK_NULL) { ip->blocks[ZONE_SINGLE] = phys; inode_touch(ip); } } /* We cannot go any further. */ if ((phys = ip->blocks[ZONE_SINGLE]) == BLOCK_NULL) return (BLOCK_NULL); buf = bread(ip->dev, phys); /* Create direct block. */ if (((block_t *)buffer_data(buf))[logic] == BLOCK_NULL && create) { superblock_lock(ip->sb); phys = block_alloc(ip->sb); superblock_unlock(ip->sb); if (phys != BLOCK_NULL) { ((block_t *)buffer_data(buf))[logic] = phys; buffer_dirty(buf, 1); inode_touch(ip); } } brelse(buf); return (((block_t *)buffer_data(buf))[logic]); } logic = off - REMAINING_OFFSET; /* Double indirect block. */ tmp = logic / BLOCK_SIZE; if (tmp < NR_DOUBLE) { size_t logicSingle = logic / (NR_SINGLE * BLOCK_SIZE); size_t logicDouble = logic / BLOCK_SIZE; /* Create single, double and/or direct block. */ if ( (phys = create_direct_block(ip,ZONE_DOUBLE,create)) != BLOCK_NULL) { buf = bread(ip->dev, phys); if ( (phys = create_indirect_block(buf,ip,logicSingle,create)) != BLOCK_NULL) { buf = bread(ip->dev, phys); if ( (phys = create_indirect_block(buf,ip,logicDouble,create)) != BLOCK_NULL) return (phys); else return (BLOCK_NULL); } else return (BLOCK_NULL); } else return (BLOCK_NULL); } /* Triple indirect zone. */ kpanic("triple indirect zones not supported"); return (BLOCK_NULL); }