Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1959432
  • 博文数量: 1000
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7921
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-20 09:23
个人简介

storage R&D guy.

文章分类

全部博文(1000)

文章存档

2019年(5)

2017年(47)

2016年(38)

2015年(539)

2014年(193)

2013年(178)

分类: LINUX

2014-05-07 08:37:47

           Linux下的文件系统中宏观上主要分为三层:一是上层的文件系统的系统调用;二是虚拟文件系统VFS(Virtual File System)层,三是挂载到VFS中的各种实际文件系统。

         VFS是一种软件机制,只存在于内存中,每次系统初始化期间Linux都会先在内存中构造一棵VFS的目录树(也就是源码中的namespace)。VFS主要的作用是对上层应用屏蔽底层不同的调用方法,提供一套统一的调用接口,二是便于对不同的文件系统进行组织管理。因此,VFS其实就是文件系统组织管理中的一个抽象层。

EQK69W`U%7%`FRO61DU0R9C

一个典型的VFS目录组织方式如下图所示:

5S_DM2]{U`G]59`AM`TL~33

Superblock:超级块,是文件系统最基本的元数据,它定义了文件系统的类型、大小、状态和其他信息等。Superblock对于文件系统是非常关键的,因此一般文件系统都会冗余存储多份。

~X]L$2J}4}KSS`5OE)MG~`F

struct super_block {
    struct list_head    s_list;        /* 系统将所有文件系统的超级块组成链表*/
    dev_t            s_dev;        /* search index; _not_ kdev_t */
    unsigned long        s_blocksize;
    unsigned char        s_blocksize_bits;
    unsigned char        s_dirt;
    unsigned long long    s_maxbytes;    /* Max file size */
    struct file_system_type    *s_type; //文件系统类型
    const struct super_operations    *s_op; //操作函数集
    struct dquot_operations    *dq_op;
     struct quotactl_ops    *s_qcop;
    struct export_operations *s_export_op;
    unsigned long        s_flags;
    unsigned long        s_magic;
    struct dentry        *s_root; //挂载根目录
    struct rw_semaphore    s_umount;
    struct mutex        s_lock;
    int            s_count;
    int            s_syncing;
    int            s_need_sync_fs;
    atomic_t        s_active;
#ifdef CONFIG_SECURITY
    void                    *s_security; //LSM框架的安全域
#endif
    struct xattr_handler    **s_xattr;

    struct list_head    s_inodes;    /* 所有的inode节点链表*/
    struct list_head    s_dirty;    /* dirty inodes */
    struct list_head    s_io;        /* parked for writeback */
    struct hlist_head    s_anon;        /* anonymous dentries for (nfs) exporting */
    struct list_head    s_files;

    struct block_device    *s_bdev;
    struct list_head    s_instances;
    struct quota_info    s_dquot;    /* Diskquota specific options */

    int            s_frozen;
    wait_queue_head_t    s_wait_unfrozen;

    char s_id[32];                /* Informational name */

    void             *s_fs_info;    /* Filesystem private info */

    /*
     * The next field is for VFS *only*. No filesystems have any business
     * even looking at it. You had been warned.
     */
    struct mutex s_vfs_rename_mutex;    /* Kludge */

    /* Granularity of c/m/atime in ns.
       Cannot be worse than a second */
    u32           s_time_gran;
};

 

inode:包含了一个文件的元数据,如文件所在数据块等。这里需要注意Linux中的所有对象均为文件:实际的文件、目录、设备等等。一个inode基本包含:所有权(用户、组)、访问模式(读、写、执行)和文件类型等,但不包含文件名。

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;  //inode权限
    spinlock_t        i_lock;    /* i_blocks, i_bytes, maybe i_size */
    struct mutex        i_mutex;
    struct rw_semaphore    i_alloc_sem;
    const struct inode_operations    *i_op;  //inode操作函数集
    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; //LSM框架中的安全域
#endif
    void            *i_private; /* fs or device private pointer */
};

inode结构中的i_ino索引节点号在同一个文件系统中是唯一的,但若是系统中挂载了多个文件系统,则inode号可能出现相同的情况。

其中这个 i_mode是16位的无符号整数表示,由9位权限方式位、3位“粘滞”标志位和4位文件类型标志位,它们的具体的定义在 include/linux/stat.h中:

#define S_IFMT   00170000     /* 用于抽取i_mode域中类型部分的屏蔽位 */
#define S_IFSOCK 0140000     /* 套接字类型码 */
#define S_IFLNK    0120000    /* 符号连接类型码 */
#define S_IFREG   0100000    /* 普通文件类型码 */
#define S_IFBLK   0060000    /* 块特别文件类型码 */
#define S_IFDIR   0040000     /* 目录文件类型码 */
#define S_IFCHR   0020000    /* 字符特别文件类型码 */
#define S_IFIFO   0010000     /* 管道或FIFO类型码 */
#define S_ISUID   0004000    /* 用户粘滞位 */
#define S_ISGID   0002000    /* 用户组粘滞位 */
#define S_ISVTX   0001000   /* 粘滞位 */
#define S_IRWXU 00700     /* 用户读写执行 */
#define S_IRUSR 00400      /* 用户读 */
#define S_IWUSR 00200     /* 用户写 */
#define S_IXUSR 00100     /* 用户执行 */
#define S_IRWXG 00070    /* 用户组读写执行 */
#define S_IRGRP 00040    /* 用户组读 */
#define S_IWGRP 00020    /* 用户组写 */
#define S_IXGRP 00010    /* 用户组执行 */
#define S_IRWXO 00007   /* 其他用户读写执行 */
#define S_IROTH 00004    /* 其他用户读 */
#define S_IWOTH 00002   /* 其他用户写 */
#define S_IXOTH 00001   /* 其他用户执行 */
#define S_IRWXUGO     (S_IRWXU|S_IRWXG|S_IRWXO)   /* 全部用户读写执行 */
#define S_IALLUGO      (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO )/* 全部用户全部权限 */
#define S_IRUGO          (S_IRUSR|S_IRGRP|S_IROTH)    /* 全部用户读 */
#define S_IWUGO         (S_IWUSR|S_IWGRP|S_IWOTH)   /* 全部用户写 */
#define S_IXUGO          (S_IXUSR|S_IXGRP|S_IXOTH)    /* 全部用户执行 */

dentry:将inode号和文件名联系起来,dentry还保存目录和其子对象的关系,用于文件系统的变量。dentry还起着缓存的作用,缓存最常使用的文件以便于更快捷的访问。

struct dentry {
    atomic_t d_count; //引用计数
    unsigned int d_flags;        /* protected by d_lock */
    spinlock_t d_lock;        /* per dentry lock */
   struct inode *d_inode;        /* Where the name belongs to - NULL is
                     * negative */
    /*
     * The next three fields are touched by __d_lookup.  Place them here
     * so they all fit in a cache line.
     */
    struct hlist_node d_hash;    /* lookup hash list */
    struct dentry *d_parent;    /* parent directory */
   struct qstr d_name;  //目录项名称,与inode对应起来

    struct list_head d_lru;        /* LRU list */
    /*
     * d_child and d_rcu can share memory
     */
    union {
        struct list_head d_child;    /* child of parent list */ 链入父目录的子目录中
         struct rcu_head d_rcu;
    } d_u;
    struct list_head d_subdirs;    /* our children */ 子目录链表
   struct list_head d_alias;    /* inode alias list */ 链入inode节点的i_dentry链表,因为一个inode可能对应多个dentry(硬链接)
    unsigned long d_time;        /* used by d_revalidate */
    struct dentry_operations *d_op;
    struct super_block *d_sb;    /* The root of the dentry tree */
    void *d_fsdata;            /* fs-specific data */
#ifdef CONFIG_PROFILING
    struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
    int d_mounted;
    unsigned char d_iname[DNAME_INLINE_LEN_MIN];    /* small names */
};

 

在内存中,每个文件都有一个dentry(目录项)和inode(索引节点)结构,dentry记录文件名、父目录、子目录等信息,形成文件树结构。inode结构则包含文件的宿主、创建时间和在存储介质上的位置和分布等信息。其中每个dentry都有一个唯一的inode,而每个inode则可能有多个dentry,这种情况是由ln硬链接产生的。

硬链接:其实就是同一个文件具有多个别名,具有相同inode,而dentry不同。

              1. 文件具有相同的inode和data block;

              2. 只能对已存在的文件进行创建;

              3. 不同交叉文件系统进行硬链接的创建

              4. 不能对目录进行创建,只能对文件创建硬链接

              5. 删除一个硬链接并不影响其他具有相同inode号的文件;

软链接:软链接具有自己的inode,即具有自己的文件,只是这个文件中存放的内容是另一个文件的路径名。因此软链接具有自己的inode号以及用户数据块。

              1. 软链接有自己的文件属性及权限等;

              2. 软链接可以对不存在的文件或目录创建;

              3. 软链接可以交叉文件系统;

              4. 软链接可以对文件或目录创建;

              5. 创建软链接时,链接计数i_nlink不会增加;

              6. 删除软链接不会影响被指向的文件,但若指向的原文件被删除,则成死链接,但重新创建指向 的路径即可恢复为正常的软链接,只是源文件的内容可能变了。

 

%~Q2(70L{@@8W5JY~HE4E~T

 

file:每一个打开的文件都对应一个file结构,还保存文件的打开方式和偏移等。

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;
};

 

P7$3LGPUZ@AKK{{1FFZZ$PI

 

注意:VFS文件系统中的inode和dentry与实际文件系统的inode和dentry有一定的关系,但不能等同。真实磁盘文件的inode和dentry是存在于物理外存上的,但VFS中的inode和dentry是存在于内存中的,系统读取外存中的inode和dentry信息进行一定加工后,生成内存中的inode和dentry。虚拟的文件系统也具有inode和dentry结构,只是这是系统根据相应的规则生成的,不存在于实际外存中。


 

对应外存上的实际文件系统在格式化时就划分出了inode的数目和数据区块的数量,所以有可能inode用完了但数据区块还有剩余空间的情况。即虽然磁盘仍有剩余空间,但不能再创建文件和目录。

阅读(1106) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~