当前位置: 首页 > 工具软件 > BabyOS > 使用案例 >

babyos2(26)fs(4), lock

韶镜
2023-12-01

之前为了简化问题,兼之之前没有实现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早期版本

 类似资料: