之前为了简化问题,兼之之前没有实现semaphore,文件系统的操作未加锁。上次为了实现读取硬盘时睡眠等待,实现了一个sem类,所以为babyos2文件系统加锁的时机已经成熟。
主要用类三个锁:
1.inode table的锁
2.file table的锁
3.inode的锁。
前面两个比较简单,占用锁时间不会太长,用的自选锁,inode可能持有锁时间比较长,所以用的semaphore。
babyos2的整个文件系统参考的是XV6,所以加锁时机也类似,但babyos2的锁是参考的linux,锁的实现和使用跟XV6完全不同。
1.
inode_t* file_system_t::get_inode(uint32 dev, uint32 inum)
{
inode_t* inode = NULL;
inode_t* empty = NULL;
m_inodes_lock.lock();
for (int i = 0; i < MAX_INODE_CACHE; i++) {
if (m_inodes[i].m_ref > 0 && m_inodes[i].m_dev == dev && m_inodes[i].m_inum == inum) {
inode = &m_inodes[i];
inode->m_ref++;
m_inodes_lock.unlock();
return inode;
}
if (empty == NULL && m_inodes[i].m_ref == 0) {
empty = &m_inodes[i]; }
}
if (empty != NULL) {
inode = empty;
inode->m_dev = dev;
inode->m_inum = inum;
inode->m_ref = 1;
inode->m_valid = 0;
inode->m_sem.init(1);
inode->m_size = 0;
for (int i = 0; i < NDIRECT+1; i++) {
inode->m_addrs[i] = 0;
}
}
m_inodes_lock.unlock();
return inode;
}
void file_system_t::put_inode(inode_t* inode)
{
inode->lock();
if (inode->m_valid && inode->m_nlinks == 0) {
if (inode->m_ref == 1) {
inode->m_type = 0;
for (int i = 0; i < NDIRECT; i++) {
if (inode->m_addrs[i] != 0) {
free_block(inode->m_dev, inode->m_addrs[i]);
inode->m_addrs[i] = 0;
}
}
if (inode->m_addrs[NDIRECT] != 0) {
io_buffer_t* b = os()->get_block_dev()->read(inode->m_addrs[NDIRECT]);
uint32* addrs = (uint32 *) b->m_buffer;
for (int i = 0; i < NINDIRECT; i++) {
free_block(inode->m_dev, addrs[i]);
addrs[i] = 0;
}
os()->get_block_dev()->write(b);
os()->get_block_dev()->release_block(b);
free_block(inode->m_dev, inode->m_addrs[NDIRECT]);
inode->m_addrs[NDIRECT] = 0;
}
inode->m_size = 0;
update_disk_inode(inode);
inode->m_valid = 0;
}
}
inode->unlock();
m_inodes_lock.lock();
inode->m_ref--;
m_inodes_lock.unlock();
}
inode_t* file_system_t::dup_inode(inode_t* inode)
{
m_inodes_lock.lock();
inode->m_ref++;
m_inodes_lock.unlock();
return inode;
}
2.
file_t* file_system_t::alloc_file()
{
m_file_table_lock.lock();
for (int i = 0; i < MAX_FILE_NUM; i++) {
if (m_file_table[i].m_type == file_t::TYPE_NONE) {
m_file_table_lock.unlock();
return &m_file_table[i];
}
}
m_file_table_lock.unlock();
return NULL;
}
int file_system_t::close_file(file_t* file)
{
m_file_table_lock.lock();
if (file->m_ref < 1) {
m_file_table_lock.unlock();
return -1;
}
if (--file->m_ref > 0) {
m_file_table_lock.unlock();
return 0;
}
m_file_table_lock.unlock();
if (file->m_type == file_t::TYPE_INODE) {
file->m_type = file_t::TYPE_NONE;
put_inode(file->m_inode);
}
}
file_t* file_system_t::dup_file(file_t* file)
{
m_file_table_lock.lock();
file->m_ref++;
m_file_table_lock.unlock();
return file;
}
3.
inode_t* file_system_t::create(const char* path, uint16 type, uint16 major, uint16 minor)
{
char name[MAX_PATH] = {0};
inode_t* inode_dir = NULL;
if ((inode_dir = nameiparent(path, name)) == NULL) {
return NULL;
}
inode_dir->lock();
inode_t* inode = NULL;
unsigned offset = 0;
if ((inode = dir_lookup(inode_dir, name, offset)) != NULL) {
inode_dir->unlock();
put_inode(inode_dir);
inode->lock();
if (inode->m_type == inode_t::I_TYPE_FILE && type == inode_t::I_TYPE_FILE) {
return inode;
}
inode->unlock();
put_inode(inode);
return NULL;
}
if ((inode = alloc_inode(inode_dir->m_dev, type)) == NULL) {
inode_dir->unlock();
return NULL;
}
inode->lock();
inode->m_major = major;
inode->m_minor = minor;
inode->m_nlinks = 1;
inode->m_type = type;
update_disk_inode(inode);
if (inode->m_type == inode_t::I_TYPE_DIR) {
inode_dir->m_nlinks++;
update_disk_inode(inode_dir);
if (dir_link(inode, (char *) ".", inode->m_inum) < 0 ||
dir_link(inode, (char *) "..", inode->m_inum) < 0) {
inode->unlock();
inode_dir->unlock();
return NULL;
}
}
dir_link(inode_dir, name, inode->m_inum);
inode_dir->unlock();
put_inode(inode_dir);
return inode;
}
int file_system_t::do_link(const char* path_old, const char* path_new)
{
inode_t* inode = NULL;
inode_t* dir = NULL;
if ((inode = namei(path_old)) == NULL) {
return -1;
}
inode->lock();
if (inode->m_type == inode_t::I_TYPE_DIR) {
inode->unlock();
put_inode(inode);
return -1;
}
inode->m_nlinks++;
update_disk_inode(inode);
inode->unlock();
char name[MAX_PATH] = {0};
if ((dir = nameiparent(path_new, name)) == NULL) {
goto failed;
}
dir->lock();
if (dir->m_dev != inode->m_dev || dir_link(dir, name, inode->m_inum) < 0) {
dir->unlock();
put_inode(dir);
goto failed;
}
dir->unlock();
put_inode(dir);
put_inode(inode);
return 0;
failed:
inode->lock();
inode->m_nlinks--;
update_disk_inode(inode);
inode->unlock();
return -1;
}
其他操作inode加锁的代码不一一列举。
下一步的计划:
1.文件系统对pipe的支持
2.shell对pipe的支持
3.shell支持重定向
参考xv6.
4.socket,AF_UNIX
参考linux早期版本