• 文件存储结构inode与RAM结构建立联系


    linux下一切皆文件,大致可分为以下几类:目录、普通文件、硬连接、软连接、字符设备、块设备、FIFO、Socket,其在物理存储体内存储按inode和数据块存储,inode代表元数据,是除实际数据外的所有(属性)数据。根据不同的文件类型有以下几种情况:

    》对于常规文件,文件的数据存储在数据块中,其他数据(即属性)存储在inode中。

    》对于目录,该目录下的所有文件名和目录名存储在数据块中,注意文件名保存在它所在目录的数据块中,除文件名之外,ls -l命令看到的其它信息都保存在该文件的inode中。注意这个概念:目录也是一种文件,是一种特殊类型的文件。

    对于硬链接,其只是在硬链接所在目录的数据块中增加或修改文件名,并修改硬链接目标inode的链接数(ls显示属性的第二项),并不会增加inode或数据块。

    》对于符号链接,如果目标路径名较短则直接保存在inode中以便更快地查找,如果目标路径名较长则分配一个数据块来保存。

    》设备文件、FIFO和socket等特殊文件没有数据块,设备文件的主设备号和次设备号保存在inode中

    inode结构体定义在linux/fs.h中:

    /*
     * Keep mostly read-only and often accessed (especially for
     * the RCU path lookup and 'stat' data) fields at the beginning
     * of the 'struct inode'
     */
    struct inode {
        umode_t         i_mode;
        unsigned short      i_opflags;
        uid_t           i_uid;
        gid_t           i_gid;
        unsigned int        i_flags;
    
    #ifdef CONFIG_FS_POSIX_ACL
        struct posix_acl    *i_acl;
        struct posix_acl    *i_default_acl;
    #endif
    
        const struct inode_operations   *i_op;
        struct super_block  *i_sb;
        struct address_space    *i_mapping;
    
    #ifdef CONFIG_SECURITY
        void            *i_security;
    #endif
    
        /* Stat data, not accessed from path walking */
        unsigned long       i_ino;
        /*
         * Filesystems may only read i_nlink directly.  They shall use the
         * following functions for modification:
         *
         *    (set|clear|inc|drop)_nlink
         *    inode_(inc|dec)_link_count
         */
        union {
            const unsigned int i_nlink;
            unsigned int __i_nlink;
        };
        dev_t           i_rdev;    /* 若是设备文件,此字段将记录设备的设备号 */
        struct timespec     i_atime;
        struct timespec     i_mtime;
        struct timespec     i_ctime;
        spinlock_t      i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned short          i_bytes;
        blkcnt_t        i_blocks;
        loff_t          i_size;
    
    #ifdef __NEED_I_SIZE_ORDERED
        seqcount_t      i_size_seqcount;
    #endif
    
        /* Misc */
        unsigned long       i_state;
        struct mutex        i_mutex;
    
        unsigned long       dirtied_when;   /* jiffies of first dirtying */
    
        struct hlist_node   i_hash;
        struct list_head    i_wb_list;  /* backing dev IO list */
        struct list_head    i_lru;      /* inode LRU list */
        struct list_head    i_sb_list;
        union {
            struct list_head    i_dentry;
            struct rcu_head     i_rcu;
        };
        atomic_t        i_count;
        unsigned int        i_blkbits;
        u64         i_version;
        atomic_t        i_dio_count;
        atomic_t        i_writecount;
        const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
        struct file_lock    *i_flock;
        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;   /* 若是块设备,为其对应的block_device结构体指针 */
            struct cdev     *i_cdev;  /* 若是字符设备,为其对应的cdev结构体指针 */
        };
    
        __u32           i_generation;
    
    #ifdef CONFIG_FSNOTIFY
        __u32           i_fsnotify_mask; /* all events this inode cares about */
        struct hlist_head   i_fsnotify_marks;
    #endif
    
    #ifdef CONFIG_IMA
        atomic_t        i_readcount; /* struct files open RO */
    #endif
        void            *i_private; /* fs or device private pointer */
    };

     inode是linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。

    ls -li显示属性各字段含义介绍

    stat函数读取文件的inode,然后把inode中的各种文件属性填入一个struct stat结构体传出给调用者。ls或stat可查看inode属性。

    struct stat {
                   dev_t     st_dev;     /* ID of device containing file */
                   ino_t     st_ino;     /* inode number */
                   mode_t    st_mode;    /* protection */
                   nlink_t   st_nlink;   /* number of hard links */
                   uid_t     st_uid;     /* user ID of owner */
                   gid_t     st_gid;     /* group ID of owner */
                   dev_t     st_rdev;    /* device ID (if special file) */
                   off_t     st_size;    /* total size, in bytes */
                   blksize_t st_blksize; /* blocksize for file system I/O */
                   blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
                   time_t    st_atime;   /* time of last access */
                   time_t    st_mtime;   /* time of last modification */
                   time_t    st_ctime;   /* time of last status change */
               };

    普通文件

    ~$ls -li wang
    588946 -rw-rw-r-- 1 yuxi yuxi 9045 Feb 12 18:37 wang 

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_size  st_mtime  file_name 

    目录 

     712708 drwxrwxr-x 2 yuxi yuxi    4096 Oct  6 15:52 file

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_size  st_mtime  dir_name

    硬链接

    ~$ln wang hard_wang
    ~$ls -li wang hard_wang
    588946 -rwxrwxr-x 2 yuxi yuxi 9045 Feb 12 18:37 hard_wang
    588946 -rwxrwxr-x 2 yuxi yuxi 9045 Feb 12 18:37 wang

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_size  st_mtime  file_name

    符号链接

    2011 lrwxrwxrwx  1 root root          15 Mar 19 10:01 stdout -> /proc/self/fd/1

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_size(软链接文件名大小)  st_mtime  file_name 

    字符设备

    1904 crw-rw-rw-  1 root tty       5,   0 Mar 19 10:01 tty

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_rdev  st_mtime  dev_name

    块设备

    7502 brw-rw----  1 root disk      8,   0 Mar 19 10:01 sda

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_rdev  st_mtime  dev_name

    socket

    9252 srw-rw-rw-  1 root root           0 Mar 19 10:01 log

    st_ino  file_type  st_mode  st_nlink  st_uid  st_gid  st_size  st_mtime  file_name

    inode与RAM建立连接

    所有文件都是通过open或类open函数将inode与file建立联系,release将file结构体的修改更新inode。用inode填充file结构体(file为RAM结构体),实现了物理结构体与RAM结构体的分离,之后的read、write等file_operations函数直接操作file结构体即可完成对文件的所有更改

    int (*open) (struct inode *, struct file *);
    extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, const struct cred *);
    extern int dcache_dir_open(struct inode *, struct file *);
    int (*release) (struct inode *, struct file *);

    file结构体定义于linux/fs.h,如下:

    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;
    
        /*   
         * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
         * Must not be taken from IRQ context.
         */
        spinlock_t      f_lock;
    #ifdef CONFIG_SMP
        int         f_sb_list_cpu;
    #endif
        atomic_long_t       f_count;
        unsigned int        f_flags;
        fmode_t         f_mode;
        loff_t          f_pos;
        struct fown_struct  f_owner;
        const struct cred   *f_cred;
        struct file_ra_state    f_ra;
    
        u64         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;
    #endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
    #ifdef CONFIG_DEBUG_WRITECOUNT
        unsigned long f_mnt_write_state;
    #endif
    };

    字符文件open函数调用过程记录:

    在用户空间调用的open()函数传入的参数是文件路径,通过文件路径可以找到文件的inode节点,实际上inode与文件路径间建立了一一映射关系。

    一个路径是/opt/file,则查找的顺序是:

    1. 读出inode表中第2项,也就是根目录的inode,从中找出根目录数据块的位置

    2. 从根目录的数据块中找出文件名为opt的记录,从记录中读出它的inode号

    3. 读出opt目录的inode,从中找出它的数据块的位置

    4. 从opt目录的数据块中找出文件名为file的记录,从记录中读出它的inode号

    5. 读出file文件的inode 

     file即表示一个进程内打开的文件,它是与进程对应的。已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。

    linux文件系统与设备驱动

    应用程序和VFS之间的接口是系统调用,而VFS与磁盘文件系统以及普通设备之间的接口是file_operations结构体成员函数,这个结构体包含对文件进行打开、关闭、读写、控制的一系列函数。

    由于字符设备的上层没有磁盘文件系统,所以字符设备的file_operations成员函数就直接由设备驱动提供,file_operations正是字符设备驱动的核心。

    而对于块存储设备而言,ext2、fat、jffs2等文件系统中会实现针对VFS的file_operations成员函数,设备驱动层将看不到file_operations的存在。磁盘文件系统和设备驱动会将对磁盘上文件的访问最终转换成对磁盘上柱面和扇区的访问。

    在设备驱动程序的设计中,一般而言,会关心结构体file和inode。

    本节摘自《linux设备驱动开发详解》--宋宝华。

    参考:

    1. linux虚拟文件系统vfs

    2. ext2文件系统了解

    3. inode表原数据,存储在物理存储体上

    4. 解析 Linux 中的 VFS 文件系统机制

  • 相关阅读:
    awk统计命令(求和、求平均、求最大值、求最小值)(转)
    高性能跨平台网络IO(Reactor、epoll、iocp)总结
    进程通信和同步(转)
    C++11原子操作与无锁编程(转)
    在线代码编译运行工具
    linux ps 命令的查看
    转: linux sed 命令的使用
    转:利用Eclipse CDT 阅读C/C++代码
    转:Raft一致性选举算法的ppt与视频
    转:ffmpeg time_base详解
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/6579679.html
Copyright © 2020-2023  润新知