栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

通用文件模型及VFS-VFS结构

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

通用文件模型及VFS-VFS结构

在VFS接口实现中,涉及大量的数据结构。VFS结构由两个部分组成:文件和文件系统,这些都需要管理和抽象。

1.文件表示

inode是Linux内核选择用于表示内容和相关元数据的方法。在抽象对底层文件系统的访问时,并未使用固定的函数,而是使用了函数指针。这函数指针保存在两个结构中,包括了所有相关的函数。
(1)inode操作:创建链接、文件重命名、在目录中生成新文件、删除文件。

const struct inode_operations	*i_op;

(2)文件操作:作用于文件的数据内容。他们包含一些显然的操作(如读和写),还包括如设置文件位置指针和创建内存映射之类的操作。

const struct file_operations	*i_fop;

打开的文件总是分配到系统中一个特定的进程,内核必须在数据结构中存储文件和进程之间的关联,各个文件系统实现也能在VFS inode中存储自身的数据(不通过VFS层操作)。

2.文件系统和超级块信息

VFS支持的文件系统类型通过一种特殊的内核对象链接进来,该对象提供了一种读取超级块的方法。除了文件系统的关键信息(如块长度、最大文件长度等等)之外,超级块还包含了读、写、操作inode的函数指针。
内核还建立了一个链表,包含所有活动文件系统的超级块实例。之所以使用活动(active)这个术语替代已装载(mounted),是因为在某些环境中,有可能使用一个超级块对应几个装载点。
尽管每个文件系统在file_system_type中只出现一次,但所有超级块实例的链表中,可能有几个同一文件系统类型的超级块实例,因为在各个块设备/分区上可能存储了同一类型的几个文件系统。

struct file_system_type {
	const char *name;
	int fs_flags;
#define FS_REQUIRES_DEV		1 
#define FS_BINARY_MOUNTDATA	2
#define FS_HAS_SUBTYPE		4
#define FS_USERNS_MOUNT		8	
#define FS_USERNS_DEV_MOUNT	16 
#define FS_USERNS_VISIBLE	32	
#define FS_RENAME_DOES_D_MOVE	32768	
	struct dentry *(*mount) (struct file_system_type *, int,
		       const char *, void *);
	struct dentry *(*mount2) (struct vfsmount *, struct file_system_type *, int,
			       const char *, void *);
	void *(*alloc_mnt_data) (void);
	void (*kill_sb) (struct super_block *);
	struct module *owner;
	struct file_system_type * next;
	struct hlist_head fs_supers;

	struct lock_class_key s_lock_key;
	struct lock_class_key s_umount_key;
	struct lock_class_key s_vfs_rename_key;
	struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];

	struct lock_class_key i_lock_key;
	struct lock_class_key i_mutex_key;
	struct lock_class_key i_mutex_dir_key;
};
3.VFS的inode结构源码
struct inode {
	umode_t			i_mode;
	unsigned short		i_opflags;
	kuid_t			i_uid;
	kgid_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

	
	unsigned long		i_ino;
	
	union {
		const unsigned int i_nlink;
		unsigned int __i_nlink;
	};
	dev_t			i_rdev;
	loff_t			i_size;
	struct timespec		i_atime;
	struct timespec		i_mtime;
	struct timespec		i_ctime;
	spinlock_t		i_lock;	
	unsigned short          i_bytes;
	unsigned int		i_blkbits;
	enum rw_hint		i_write_hint;
	blkcnt_t		i_blocks;

#ifdef __NEED_I_SIZE_ORDERED
	seqcount_t		i_size_seqcount;
#endif

	
	unsigned long		i_state;
	struct mutex		i_mutex;

	unsigned long		dirtied_when;	
	unsigned long		dirtied_time_when;

	struct hlist_node	i_hash;
	struct list_head	i_io_list;	
#ifdef CONFIG_CGROUP_WRITEBACK
	struct bdi_writeback	*i_wb;		

	
	int			i_wb_frn_winner;
	u16			i_wb_frn_avg_time;
	u16			i_wb_frn_history;
#endif
	struct list_head	i_lru;		
	struct list_head	i_sb_list;
	union {
		struct hlist_head	i_dentry;
		struct rcu_head		i_rcu;
	};
	u64			i_version;
	atomic_t		i_count;
	atomic_t		i_dio_count;
	atomic_t		i_writecount;
#ifdef CONFIG_IMA
	atomic_t		i_readcount; 
#endif
	const struct file_operations	*i_fop;	
	struct file_lock_context	*i_flctx;
	struct address_space	i_data;
	struct list_head	i_devices;
	union {
		struct pipe_inode_info	*i_pipe;
		struct block_device	*i_bdev;
		struct cdev		*i_cdev;
		char			*i_link;
	};

	__u32			i_generation;

#ifdef CONFIG_FSNOTIFY
	__u32			i_fsnotify_mask; 
	struct hlist_head	i_fsnotify_marks;
#endif

#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
	struct fscrypt_info	*i_crypt_info;
#endif
	void			*i_private; 
};
4.VFS与各文件系统的关系

VFS之基本数据结构

VFS支持三种类型的文件系统:基于磁盘的文件系统、特殊的文件系统和网络文件系统。
基于磁盘的文件系统:管理在非易失去介质存储的文件。这种类型的文件系统最多,比如常见的ext2/3/4、fat、ntfs等。
特殊的文件系统:在内核中生成,是一种使用户应用程序与用户通信的方法,比如常见的proc文件系统,它存储于内存,不占用硬件存储空间。
网络文件系统:这种文件系统可以通过网络访问另一台计算机上的数据,相当于连接到本地计算机一样。比如nfs文件系统。

5.VFS基本数据结构

VFS通用文件模型包含有4种基本的数据结构,通过这几个数据结构实现将硬盘上的文件抽象到内存中:

超级块目录项索引节点文件
6.inode操作

内核提供了大量函数对inode进行操作。为此定义了一个函数指针的集合,以抽象这些操作,因为实际数据是通过具体的文件系统的实现操作的,调用接口不变,但实际工作是由特定实现函数完成的。

struct inode_operations {
	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);//根据文件系统对象的名称(表示为字符串)查找其inode实例
	const char * (*follow_link) (struct dentry *, void **);
	int (*permission) (struct inode *, int);
	int (*permission2) (struct vfsmount *, struct inode *, int);
	struct posix_acl * (*get_acl)(struct inode *, int);

	int (*readlink) (struct dentry *, char __user *,int);
	void (*put_link) (struct inode *, void *);

	int (*create) (struct inode *,struct dentry *, umode_t, bool);//VFS通过系统调用create()和open()来调用该函数,从而为dentey对象创建一个新的索引节点,在创建时使用inode指定初始的一个模式。
	int (*link) (struct dentry *,struct inode *,struct dentry *);
	//该函数被系统调用link()调用,用来创建硬链接,硬链接名称由dentry指定,链接对象是dir目录中old_dentry目录项所指定。
	int (*unlink) (struct inode *,struct dentry *);//该函数被系统调用unlink()调用,从目录dir中删除有目录项dentry指定的索引节点对象。
	int (*symlink) (struct inode *,struct dentry *,const char *);
	int (*mkdir) (struct inode *,struct dentry *,umode_t);//系统调用mkdir()调用,创建一个新的目录,创建时使用mode指定初始模式。
	int (*rmdir) (struct inode *,struct dentry *);//系统调用rmdir调用,创建一个新的目录,创建时使用mode指定初始模式。
	int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
	int (*rename) (struct inode *, struct dentry *,
			struct inode *, struct dentry *);
	int (*rename2) (struct inode *, struct dentry *,
			struct inode *, struct dentry *, unsigned int);
	int (*setattr) (struct dentry *, struct iattr *);
	int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *);
	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
	ssize_t (*listxattr) (struct dentry *, char *, size_t);
	int (*removexattr) (struct dentry *, const char *);
	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
		      u64 len);
	int (*update_time)(struct inode *, struct timespec *, int);
	int (*atomic_open)(struct inode *, struct dentry *,
			   struct file *, unsigned open_flag,
			   umode_t create_mode, int *opened);
	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
	int (*set_acl)(struct inode *, struct posix_acl *, int);
} ____cacheline_aligned;

inode结构有两个指针(i_op和i_fop),file_operations用于操作文件中包含的数据,inode_operations负责管理结构性的操作(删除一个文件)和文件相关的元数据(属性等)。
inode_operations介绍

7.目录项缓存

由于块设备速度较慢,可能需要很长时间才能找到与一个文件名关联的inode,即使设备数据已经在页缓存。linux使用目录项缓存(简称dentry缓存)来快速访问此前的查找操作的结果。该缓存围绕着struct dentry建立。
在VFS连同文件系统实现读取的一个目录项(目录或文件)的数据之后,则创建一个dentry实例,以缓存找到的数据。

struct dentry {
	
	//由d_lock保护,目录项缓存标识
	unsigned int d_flags;		
	seqcount_t d_seq;		
	//内核使用dentry_hashtable对detry进程管理
	struct hlist_bl_node d_hash;	
	//父目录的目录项
	struct dentry *d_parent;	
	//目录项名称
	struct qstr d_name;
	//存放短的文件名称
	struct inode *d_inode;		
	unsigned char d_iname[DNAME_INLINE_LEN];	

	
	struct lockref d_lockref;	
	const struct dentry_operations *d_op;
	struct super_block *d_sb;	
	unsigned long d_time;		
	void *d_fsdata;			

	struct list_head d_lru;		
	struct list_head d_child;	
	struct list_head d_subdirs;	
	
	union {
		struct hlist_node d_alias;	
	 	struct rcu_head d_rcu;
	} d_u;
};
缓存的组织

dentry结构不仅使得易于处理文件系统,对提高系统性能也很关键。dentry对象在内存中的组织,涉及下面两个部分。
(1)一个散列表(dentry_hashtable)包含了所有的dentry对象。
(2)一个LRU(最近最少使用,least recently used)链表,其中不再使用的对象将授予一个最后宽期限,宽期限过后才从内存移除。

dentry操作

dentry_operation结构保存了一些指向各种特定文件系统可以对dentry对象执行的操作函数指针。

struct dentry_operations {
	int (*d_revalidate)(struct dentry *, unsigned int);
	int (*d_weak_revalidate)(struct dentry *, unsigned int);
	//计算散列值,该值用于将对象放置到dentry散列表中。
	int (*d_hash)(const struct dentry *, struct qstr *);
	//比较两个dentry对象的文件名称
	int (*d_compare)(const struct dentry *, const struct dentry *,
	unsigned int, const char *, const struct qstr *);
	int (*d_delete)(const struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_prune)(struct dentry *);
	void (*d_iput)(struct dentry *, struct inode *);
	char *(*d_dname)(struct dentry *, char *, int);
	struct vfsmount *(*d_automount)(struct path *);
	int (*d_manage)(struct dentry *, bool);
	struct inode *(*d_select_inode)(struct dentry *, unsigned);
	void (*d_canonical_path)(const struct path *, struct path *);
	struct dentry *(*d_real)(struct dentry *, struct inode *);
} ____cacheline_aligned;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/729776.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号