system call open()

from: http://linux2fork.blogspot.com/2013/04/system-call-open.html
 
今天review linux character driver的時候,發現往往定義的file_operations的.open成員,參數擁有file以及inode參數,可是這個參數哪邊來的?

其實會對open()有好奇,主要也是之前一直在trace linux kernel source內一些socket的東西,socket本身由sockfs支援,不使用open()而用socket()來開啟inode,所以想說兩者的區別是?

kernel內用 inode 結構體用來表示data。因此,它和 file structure 用來表示一個打開了的fd並不相同。對於一個inde,可能會有多個 file structure 對應著多個已打開的多個fd,但是這都只能指向同一個 inode 結構。

回頭看open(),大多數的system call使用interrupt 0x80,所以很快地追蹤到sys_open()是理所當然的入口

簡化整個call stack為sys_open()=>filp_open()=>dentry_open()=>dentry_open()
在呼叫register_chrdev()的時候將有覆寫的file_operations賦予device
底下是一些重要的工作,完整的source code就不列了
sys_open() : 配置fd
filp_open() : 依賴路徑取得nameidata結構,跟著呼叫dentry_open()取回file instance
dentry_open() : 配置file instance,nameidata結構內包含了inode instance,此時將一些必要資料由inode拷貝到file instance,f->f_op = fops_get(inode->i_fop);,此時f->f_op->open(inode,f)就是當時register_chrdev()所註冊的file_operations。
file struct里的f_op是inode里的i_fop,文件系统的read_iter/write_iter等file_operations函数集合是先赋值给inode的i_fop成员,然后在dentry_open()里将inode.i_fop赋值给file的f_op. 如下是ext4 fs file_operations函数集赋值给inode.i_fop:
fs/ext4/namei.c
static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
               bool excl)
{
    handle_t *handle;
    struct inode *inode;
    int err, credits, retries = 0;

    err = dquot_initialize(dir);
    if (err)
        return err;

    credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
           EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
retry:
    inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0,
                        NULL, EXT4_HT_DIR, credits);
    handle = ext4_journal_current_handle();
    err = PTR_ERR(inode);
    if (!IS_ERR(inode)) {
        inode->i_op = &ext4_file_inode_operations;
        inode->i_fop = &ext4_file_operations;
        ext4_set_aops(inode);
        err = ext4_add_nondir(handle, dentry, inode);
        if (!err && IS_DIRSYNC(dir))
            ext4_handle_sync(handle);
    }
    if (handle)
        ext4_journal_stop(handle);
    if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
        goto retry;
    return err;
}

vfs_read

如果file.f_op.read没有实现,实现了file.f_op.read_iter,则vfs_read会调用new_sync_read(),在这个函数里,会构建一个kiocb struct,其中的ki_pos即是ppos,即read file的offset:

fs/read_write.c

static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
    struct iovec iov = { .iov_base = buf, .iov_len = len };
    struct kiocb kiocb;
    struct iov_iter iter;
    ssize_t ret;

    init_sync_kiocb(&kiocb, filp);
    kiocb.ki_pos = *ppos;
    iov_iter_init(&iter, READ, &iov, 1, len);

    ret = call_read_iter(filp, &kiocb, &iter);
    BUG_ON(ret == -EIOCBQUEUED);
    *ppos = kiocb.ki_pos;
    return ret;
}


參考資料:
http://hi.baidu.com/potyzhang/item/ae9993a919e86f17a8cfb793
http://hi.baidu.com/heiyebujianwo/item/fa7fe543d99b73ab61d7b9cb
原文地址:https://www.cnblogs.com/aspirs/p/14706645.html