linux open

STEP1:open 

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
      
   
STEP2:实现open(pathname, flags, mod)     open.c  
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
    if (force_o_largefile())
        flags |= O_LARGEFILE;

    return do_sys_open(AT_FDCWD, filename, flags, mode);
}
STEP3: do_sys_open(AT_FDCWD, filename, flags, mode);
   
        filename : const char *pathname
        flags: flags
        mode : mode 
        add: AT_FDCWD 
#define AT_FDCWD        -100    /* Special value used to indicate
                                           openat should use the current
                                           working directory. */
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
    struct open_flags op;
    int fd = build_open_flags(flags, mode, &op);//mode-->op
    struct filename *tmp;

    if (fd)
        return fd;

    tmp = getname(filename);//path(filename)--->filename
    if (IS_ERR(tmp))
        return PTR_ERR(tmp);

    fd = get_unused_fd_flags(flags);//分配一个可用的fd
    if (fd >= 0) {
        struct file *f = do_filp_open(dfd, tmp, &op);//dfd,tmp,op==>分配file
        if (IS_ERR(f)) {
            put_unused_fd(fd);
            fd = PTR_ERR(f);
        } else {
            fsnotify_open(f);//f关联到inode.
            fd_install(fd, f);//补冲说明fd和file的关系.
        }
    }
    putname(tmp);
    return fd;
}
add: fd_install(fd, f)
        -->__fd_install(current->files, fd, file);
/*
 * Install a file pointer in the fd array.
 *
 * The VFS is full of places where we drop the files lock between
 * setting the open_fds bitmap and installing the file in the file
 * array.  At any such point, we are vulnerable to a dup2() race
 * installing a file in the array before us.  We need to detect this and
 * fput() the struct file we are about to overwrite in this case.
 *
 * It should never happen - if we allow dup2() do it, _really_ bad things
 * will follow.
 *
 * NOTE: __fd_install() variant is really, really low-level; don't
 * use it unless you are forced to by truly lousy API shoved down
 * your throat.  'files' *MUST* be either current->files or obtained
 * by get_files_struct(current) done by whoever had given it to you,
 * or really bad things will happen.  Normally you want to use
 * fd_install() instead.
 */
 __fd_install(current->files, fd, file);
void __fd_install(struct files_struct *files, unsigned int fd,
        struct file *file)
{
    struct fdtable *fdt;
    spin_lock(&files->file_lock);
    fdt = files_fdtable(files);
    BUG_ON(fdt->fd[fd] != NULL);
    rcu_assign_pointer(fdt->fd[fd], file);//file关联到fd
    spin_unlock(&files->file_lock);
}
STEP4: 
open();
do_sys_open(AT_FDCWD, filename, flags, mode);
do_filp_open(dfd, tmp, &op);
    -->path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
        -->error = do_last(nd, &path, file, op, &opened, pathname);
            -->error = vfs_open(&nd->path, file, current_cred());  
               -->do_dentry_open(filp, NULL, cred);  注意第二个参数

  
 STEP5: 如何调用到底层的dev->open 
  static int do_dentry_open(struct file *f,
              int (*open)(struct inode *, struct file *),//会回调设备的open
              const struct cred *cred)
 {
    if (!open)
        open = f->f_op->open;//设备对应的open 
    if (open) {
        error = open(inode, f);//对应我们写驱动时,
            
     .............
 }
我们使用char.c中的chardev_open,查看其参数.现在真相已经很显然,只要我们 f->f_op->open = char_open 就会调用.
static int chrdev_open(struct inode *inode, struct file *filp)
1.设备初始化时,就会绑定fops
cdev->ops = fops;
2.初始化fops
const struct file_operations def_chr_fops = {
    .open = chrdev_open,//因此系统调用open就会一直调用到底层的chrdev_open.
    .llseek = noop_llseek,
};
STEP:END
1.int open(const char *pathname, int flags, mode_t mode);
2.SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
3.do_sys_open(AT_FDCWD, filename, flags, mode);
4.
do_sys_open(AT_FDCWD, filename, flags, mode);
do_filp_open(dfd, tmp, &op);
    -->path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
        -->error = do_last(nd, &path, file, op, &opened, pathname);
            -->error = vfs_open(&nd->path, file, current_cred());  
               -->do_dentry_open(filp, NULL, cred);  注意第二个参数
                    调用设备的open;



你可能感兴趣的:(linux open)