struct file_operations 的进一步理解(转)

我的理解是这样的:

两个主要数据结构如下:
struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    int (*readdir) (struct file *, void *, filldir_t);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, struct dentry *, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
     ... 
};

struct file {
    /*
     * fu_list becomes invalid after file_free is called and queued via
     * fu_rcuhead for RCU freeing
     */
    union {
        struct list_head    fu_list;
        struct rcu_head     fu_rcuhead;
    } f_u;
    struct path        f_path;
#define f_dentry    f_path.dentry
#define f_vfsmnt    f_path.mnt
    const struct file_operations    *f_op;
    atomic_t        f_count;
    unsigned int         f_flags;
    mode_t            f_mode;
    loff_t            f_pos;
    struct fown_struct    f_owner;
    unsigned int        f_uid, f_gid;
    struct file_ra_state    f_ra;

    unsigned long        f_version;
#ifdef CONFIG_SECURITY
    void            *f_security;
#endif
    /* needed for tty driver, and maybe others */
    void            *private_data;

#ifdef CONFIG_EPOLL
    /* Used by fs/eventpoll.c to link all the hooks to this file */
    struct list_head    f_ep_links;
    spinlock_t        f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
    struct address_space    *f_mapping;
};

当访问文件时,首先open("",??),
open函数通过系统调用sys_open进入内核空间, sysopen又调用do_sys_open,

long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
    char *tmp = getname(filename);
    int fd = PTR_ERR(tmp);

    if (!IS_ERR(tmp)) {
        fd = get_unused_fd();
        if (fd >= 0) {
            struct file *f = do_filp_open(dfd, tmp, flags, mode);
            if (IS_ERR(f)) {
                put_unused_fd(fd);
                fd = PTR_ERR(f);
            } else {
                fsnotify_open(f->f_path.dentry);
                fd_install(fd, f);
            }
        }
        putname(tmp);
    }
    return fd;
}

int get_unused_fd(void)
{
    struct files_struct * files = current->files;
    int fd, error;
    struct fdtable *fdt;

      error = -EMFILE;
    spin_lock(&files->file_lock);

repeat:
    fdt = files_fdtable(files);
    fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
                files->next_fd);

    /*
     * N.B. For clone tasks sharing a files structure, this test
     * will limit the total number of files that can be opened.
     */
    if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
        goto out;

    /* Do we need to expand the fd array or fd set?  */
    error = expand_files(files, fd);
    if (error < 0)
        goto out;

    if (error) {
        /*
          * If we needed to expand the fs array we
         * might have blocked - try again.
         */
        error = -EMFILE;
        goto repeat;
    }

    FD_SET(fd, fdt->open_fds);
    FD_CLR(fd, fdt->close_on_exec);
    files->next_fd = fd + 1;
#if 1
    /* Sanity check */
    if (fdt->fd[fd] != NULL) {
        printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
        fdt->fd[fd] = NULL;
    }
#endif
    error = fd;

out:
    spin_unlock(&files->file_lock);
    return error;
}

do_sys_open 通过get_unused_fd(),在当前进程空间内的struct file结构数组中,
找一个空的struct file{}结构,并返回一个数组的下标号,

之后do_sys_open又调用do_filp_open,do_filp_open调用nameidata_to_filp,
nameidata_to_filp调用__dentry_open,

static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
                    int flags, struct file *f,
                    int (*open)(struct inode *, struct file *))
{
    struct inode *inode;
    int error;

    f->f_flags = flags;
    f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK |
                FMODE_PREAD | FMODE_PWRITE;
    inode = dentry->d_inode;
    if (f->f_mode & FMODE_WRITE) {
        error = get_write_access(inode);
        if (error)
            goto cleanup_file;
    }

    f->f_mapping = inode->i_mapping;
    f->f_path.dentry = dentry;
    f->f_path.mnt = mnt;
    f->f_pos = 0;
    f->f_op = fops_get(inode->i_fop);
    file_move(f, &inode->i_sb->s_files);

    if (!open && f->f_op)
        open = f->f_op->open;
    if (open) {
        error = open(inode, f);
        if (error)
            goto cleanup_all;
    }

    f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

    file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);

    /* NB: we're sure to have correct a_ops only after f_op->open */
    if (f->f_flags & O_DIRECT) {
        if (!f->f_mapping->a_ops ||
            ((!f->f_mapping->a_ops->direct_IO) &&
            (!f->f_mapping->a_ops->get_xip_page))) {
            fput(f);
            f = ERR_PTR(-EINVAL);
        }
    }

    return f;

cleanup_all:
    fops_put(f->f_op);
    if (f->f_mode & FMODE_WRITE)
        put_write_access(inode);
    file_kill(f);
    f->f_path.dentry = NULL;
    f->f_path.mnt = NULL;
cleanup_file:
    put_filp(f);
    dput(dentry);
    mntput(mnt);
    return ERR_PTR(error);
}

struct inode {
    struct hlist_node    i_hash;
    struct list_head    i_list;
    struct list_head    i_sb_list;
    struct list_head    i_dentry;
    unsigned long        i_ino;
    atomic_t        i_count;
    unsigned int        i_nlink;
    uid_t            i_uid;
    gid_t            i_gid;
    dev_t            i_rdev;
    unsigned long        i_version;
    loff_t            i_size;
#ifdef __NEED_I_SIZE_ORDERED
    seqcount_t        i_size_seqcount;
#endif
    struct timespec        i_atime;
    struct timespec        i_mtime;
    struct timespec        i_ctime;
    unsigned int        i_blkbits;
    blkcnt_t        i_blocks;
    unsigned short          i_bytes;
    umode_t            i_mode;
    spinlock_t        i_lock;    /* i_blocks, i_bytes, maybe i_size */
    struct mutex        i_mutex;
    struct rw_semaphore    i_alloc_sem;
    struct inode_operations    *i_op;
    const struct file_operations    *i_fop;    /* former ->i_op->default_file_ops */
    struct super_block    *i_sb;
    struct file_lock    *i_flock;
    struct address_space    *i_mapping;
    struct address_space    i_data;
#ifdef CONFIG_QUOTA
    struct dquot        *i_dquot[MAXQUOTAS];
#endif
    struct list_head    i_devices;
    union {
        struct pipe_inode_info    *i_pipe;
        struct block_device    *i_bdev;
        struct cdev        *i_cdev;
    };
    int            i_cindex;

    __u32            i_generation;

#ifdef CONFIG_DNOTIFY
    unsigned long        i_dnotify_mask; /* Directory notify events */
    struct dnotify_struct    *i_dnotify; /* for directory notifications */
#endif

#ifdef CONFIG_INOTIFY
    struct list_head    inotify_watches; /* watches on this inode */
    struct mutex        inotify_mutex;    /* protects the watches list */
#endif

    unsigned long        i_state;
    unsigned long        dirtied_when;    /* jiffies of first dirtying */

    unsigned int        i_flags;

    atomic_t        i_writecount;
#ifdef CONFIG_SECURITY
    void            *i_security;
#endif
    void            *i_private; /* fs or device private pointer */
};

#define fops_get(fops) \
    (((fops) && try_module_get((fops)->owner) ? (fops) : NULL))

我们一般加载模块
#else /*!CONFIG_MODULE_UNLOAD*/
static inline int try_module_get(struct module *module)
{
    return !module || module_is_live(module);
}

在__dentry_open,通过关键语句,f->f_op = fops_get(inode->i_fop);
得到了具有一个指向struct file_operations结构的指针的struct file结构指针,
之后通过语句

    if (!open && f->f_op)
        open = f->f_op->open;
    if (open) {
        error = open(inode, f);
        if (error)
            goto cleanup_all;
    }
调用我们编写的struct file_operations中的xxxopen()

其他操作类似,
read调用顺序如下:
read()->sys_read()->vfs_read()->{file->f_op->read}

用户空间的read、write---linux系统调用---间接调用设备驱动程序中file_operations结构中的函数
整个调用过程是这样一个顺序的。

posted @ 2011-01-09 19:35  羽落无声  阅读(2867)  评论(0编辑  收藏  举报