虚拟文件系统的数据结构

news2024/10/6 6:42:55

文章目录

  • 虚拟文件系统的数据结构
  • 超级快
  • 挂载描述符
  • 文件系统类型
  • 索引节点
  • 目录项
  • 文件的打开实例和打开文件表

虚拟文件系统的数据结构

虽然不同文件系统类型的物理结构不同,但是虚拟文件系统定义了一套统一的数据结构。

(1)超级块。文件系统的第一块是超级块,描述文件系统的总体信息,挂载文件系统的时候在内存中创建超级块的副本:结构体 super_block。
(2)虚拟文件系统在内存中把目录组织为一棵树。一个文件系统,只有挂载到内存中目录树的一个目录下,进程才能访问这个文件系统。每次挂载文件系统,虚拟文件系统就会创建一个挂载描述符:mount 结构体,并且读取文件系统的超级块,在内存中创建超级块的一个副本。
(3)每种文件系统的超级块的格式不同,需要向虚拟文件系统注册文件系统类型file_system_type,并且实现 mount 方法用来读取和解析超级块。
(4)索引节点。每个文件对应一个索引节点,每个索引节点有一个唯一的编号。当内核访问存储设备上的一个文件时,会在内存中创建索引节点的一个副本:结构体 inode。
(5)目录项。文件系统把目录看作文件的一种类型,目录的数据是由目录项组成的,每个目录项存储一个子目录或文件的名称以及对应的索引节点号。当内核访问存储设备上的一个目录项时,会在内存中创建该目录项的一个副本:结构体 dentry。
(6)当进程打开一个文件的时候,虚拟文件系统就会创建文件的一个打开实例:file结构体,然后在进程的打开文件表中分配一个索引,这个索引称为文件描述符,最后把文件描述符和 file 结构体的映射添加到打开文件表中。

超级快

文件系统的第一块是超级块,用来描述文件系统的总体信息。当我们把文件系统挂载到内存中目录树的一个目录下时,就会读取文件系统的超级块,在内存中创建超级块的副本:结构体 super_block,主要成员如下:

include/linux/fs.h 
struct super_block { 
	struct list_head s_list; 
	dev_t s_dev; 
	unsigned char s_blocksize_bits; 
	unsigned long s_blocksize; 
	loff_t s_maxbytes;
	struct file_system_type *s_type; 
	const struct super_operations *s_op; 
	… 
	unsigned long s_flags; 
	unsigned long s_iflags; /*内部 SB_I_* 标志 */ 
	unsigned long s_magic; 
	struct dentry *s_root; 
	… 
	struct hlist_bl_head s_anon; 
	struct list_head s_mounts; 
	struct block_device *s_bdev; 
	struct backing_dev_info *s_bdi; 
	struct mtd_info *s_mtd; 
	struct hlist_node s_instances;void *s_fs_info;}; 

(1)成员 s_list 用来把所有超级块实例链接到全局链表 super_blocks。
(2)成员 s_dev 和 s_bdev 保存文件系统所在的块设备,前者保存设备号,后者指向内存中的一个 block_device 实例。
(3)成员 s_blocksize 是块长度,成员 s_blocksize_bits 是块长度以 2 为底的对数。
(4)成员 s_maxbytes 是文件系统支持的最大文件长度。
(5)成员 s_flags 是标志位。
(6)成员 s_type 指向文件系统类型。
(7)成员 s_op 指向超级块操作集合。
(8)成员 s_magic 是文件系统类型的魔幻数,每种文件系统类型被分配一个唯一的魔幻数。
(9)成员 s_root 指向根目录的结构体 dentry。
(10)成员 s_fs_info 指向具体文件系统的私有信息。
(11)成员 s_instances 用来把同一个文件系统类型的所有超级块实例链接在一起,链表的头节点是结构体 file_system_type 的成员 fs_supers。

超级块操作集合的数据结构是结构体 super_operations,主要成员如下:

include/linux/fs.h 
struct super_operations { 
	struct inode *(*alloc_inode)(struct super_block *sb); 
	void (*destroy_inode)(struct inode *); 
	void (*dirty_inode) (struct inode *, int flags); 
	int (*write_inode) (struct inode *, struct writeback_control *wbc); 
	int (*drop_inode) (struct inode *); 
	void (*evict_inode) (struct inode *); 
	void (*put_super) (struct super_block *); 
	int (*sync_fs)(struct super_block *sb, int wait);int (*statfs) (struct dentry *, struct kstatfs *); 
	int (*remount_fs) (struct super_block *, int *, char *); 
	void (*umount_begin) (struct super_block *);}; 

(1)成员 alloc_inode 用来为一个索引节点分配内存并且初始化。
(2)成员 destroy_inode 用来释放内存中的索引接点。
(3)成员 dirty_inode 用来把索引节点标记为脏。
(4)成员 write_inode 用来把一个索引节点写到存储设备。
(5)成员 drop_inode 用来在索引节点的引用计数减到 0 时调用。
(6)成员 evict_inode 用来从存储设备上的文件系统中删除一个索引节点。
(7)成员 put_super 用来释放超级块。
(8)成员 sync_fs 用来把文件系统修改过的数据同步到存储设备。
(9)成员 statfs 用来读取文件系统的统计信息。
(10)成员 remount_fs 用来在重新挂载文件系统的时候调用。
(11)成员 umount_begin 用来在卸载文件系统的时候调用。

挂载描述符

一个文件系统,只有挂载到内存中目录树的一个目录下,进程才能访问这个文件系统。每次挂载文件系统,虚拟文件系统就会创建一个挂载描述符:mount 结构体。挂载描述符用来描述文件系统的一个挂载实例,同一个存储设备上的文件系统可以多次挂载,每次挂载到不同的目录下。挂载描述符的主要成员如下:

fs/mount.h 
struct mount { 
	struct hlist_node mnt_hash; 
	struct mount *mnt_parent; 
	struct dentry *mnt_mountpoint; 
	struct vfsmount mnt; 
	union { 
		struct rcu_head mnt_rcu; 
		struct llist_node mnt_llist; 
	}; 
#ifdef CONFIG_SMP 
	struct mnt_pcp __percpu *mnt_pcp; 
#else 
	int mnt_count; 
	int mnt_writers; 
#endif 
	struct list_head mnt_mounts; 
	struct list_head mnt_child; 
	struct list_head mnt_instance; 
	const char *mnt_devname; 
	struct list_head mnt_list; 
	… 
	struct mnt_namespace *mnt_ns; 
	struct mountpoint *mnt_mp; 
	struct hlist_node mnt_mp_list;} 

假设我们把文件系统2挂载到目录“/a”下,目录a属于文件系统1。目录a称为挂载点,文件系统2的mount实例是文件系统1的 mount 实例的孩子,文件系统1的 mount 实例是文件系统2的 mount 实例的父亲。

(1)成员 mnt_parent 指向父亲,即文件系统1的 mount 实例。
(2)成员 mnt_mountpoint 指向作为挂载点的目录,即文件系统1的目录a,目录a的dentry实例的成员d_flags设置了标志位DCACHE_MOUNTED。
(3)成员 mnt 的类型如下:

struct vfsmount { 
	struct dentry *mnt_root; 
	struct super_block *mnt_sb; 
	int mnt_flags; 
};

mnt_root 指向文件系统2的根目录,mnt_sb指向文件系统2的超级块。
(4)成员 mnt_hash 用来把挂载描述符加入全局散列表 mount_hashtable,关键字是{父挂载描述符,挂载点}。
(5)成员 mnt_mounts 是孩子链表的头节点。
(6)成员 mnt_child 用来加入父亲的孩子链表。
(7)成员 mnt_instance 用来把挂载描述符添加到超级块的挂载实例链表中,同一个存储设备上的文件系统,可以多次挂载,每次挂载到不同的目录下。
(8)成员 mnt_devname 指向存储设备的名称。
(9)成员 mnt_ns 指向挂载命名空间。
(10)成员 mnt_mp 指向挂载点,类型如下:

struct mountpoint { 
	struct hlist_node m_hash; 
	struct dentry *m_dentry; 
	struct hlist_head m_list; 
	int m_count; 
}; 

m_dentry 指向作为挂载点的目录,m_list 用来把同一个挂载点下的所有挂载描述符链接起来。为什么同一个挂载点下会有多个挂载描述符?这和挂载命名空间有关。
(11)成员 mnt_mp_list 用来把挂载描述符加入同一个挂载点的挂载描述符链表,链表的头节点是成员 mnt_mp 的成员 m_list。

文件系统类型

因为每种文件系统的超级块的格式不同,所以每种文件系统需要向虚拟文件系统注册文件系统类型 file_system_type,并且实现 mount 方法用来读取和解析超级块。结构体 file_system_type 如下:

include/linux/fs.h 
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_RENAME_DOES_D_MOVE 32768 
	struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); 
	void (*kill_sb) (struct super_block *); 
	struct module *owner; 
	struct file_system_type * next; 
	struct hlist_head fs_supers;}; 

(1)成员 name 是文件系统类型的名称。
(2)方法 mount 用来在挂载文件系统的时候读取并且解析超级块。
(3)方法 kill_sb 用来在卸载文件系统的时候释放超级块。
(4)多个存储设备上的文件系统的类型可能相同,成员 fs_supers 用来把相同文件系统
类型的超级块链接起来。

索引节点

在文件系统中,每个文件对应一个索引节点,索引节点描述两类信息。
(1)文件的属性,也称为元数据(metadata),例如文件长度、创建文件的用户的标识符、上一次访问的时间和上一次修改的时间,等等。
(2)文件数据的存储位置。
每个索引节点有一个唯一的编号。
当内核访问存储设备上的一个文件时,会在内存中创建索引节点的一个副本:结构体inode,主要成员如下:

include/linux/fs.h 
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; 
	… 
	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; 
	blkcnt_t i_blocks; 
	… 
	struct hlist_node i_hash; 
	struct list_head i_io_list; 
	… 
	struct list_head i_lru; 
	struct list_head i_sb_list; 
	struct list_head i_wb_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; 
		unsigned i_dir_seq; 
	};void *i_private; 
	}; 

i_mode 是文件类型和访问权限,i_uid 是创建文件的用户的标识符,i_gid 是创建文件的用户所属的组标识符。

i_ino 是索引节点的编号。

i_size 是文件长度;i_blocks 是文件的块数,即文件长度除以块长度的商;i_bytes 是文件长度除以块长度的余数;i_blkbits 是块长度以 2 为底的对数,块长度是 2 的 i_blkbits 次幂。

i_atime(access time)是上一次访问文件的时间,i_mtime(modified time)是上一次修改文件数据的时间,i_ctime(change time)是上一次修改文件索引节点的时间。

i_sb 指向文件所属的文件系统的超级块。

i_mapping 指向文件的地址空间。

i_count 是索引节点的引用计数,i_nlink 是硬链接计数。

如果文件的类型是字符设备文件或块设备文件,那么 i_rdev 是设备号,i_bdev 指向块设备,i_cdev 指向字符设备。

文件分为以下几种类型。
(1)普通文件(regular file):就是我们通常说的文件,是狭义的文件。
(2)目录:目录是一种特殊的文件,这种文件的数据是由目录项组成的,每个目录项
存储一个子目录或文件的名称以及对应的索引节点号。
(3)符号链接(也称为软链接):这种文件的数据是另一个文件的路径。
(4)字符设备文件。
(5)块设备文件。
(6)命名管道(FIFO)。
(7)套接字(socket)。
字符设备文件、块设备文件、命名管道和套接字是特殊的文件,这些文件只有索引节点,没有数据。字符设备文件和块设备文件用来存储设备号,直接把设备号存储在索引节点中。

内核支持两种链接。
(1)软链接,也称为符号链接,这种文件的数据是另一个文件的路径。
(2)硬链接,相当于给一个文件取了多个名称,多个文件名称对应同一个索引节点,索引节点的成员 i_nlink 是硬链接计数。

索引节点的成员 i_op 指向索引节点操作集合 inode_operations,成员 i_fop 指向文件操作集合 file_operations。两者的区别是:inode_operations 用来操作目录(在一个目录下创建或删除文件)和文件属性,file_operations 用来访问文件的数据。索引节点操作集合的数据结构是结构体 inode_operations,主要成员如下:

include/linux/fs.h 
struct inode_operations { 
	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); 
	const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *); 
	int (*permission) (struct inode *, int); 
	struct posix_acl * (*get_acl)(struct inode *, int); 
	
	int (*readlink) (struct dentry *, char __user *,int); 
	
	int (*create) (struct inode *,struct dentry *, umode_t, bool); 
	int (*link) (struct dentry *,struct inode *,struct dentry *); 
	int (*unlink) (struct inode *,struct dentry *); 
	int (*symlink) (struct inode *,struct dentry *,const char *); 
	int (*mkdir) (struct inode *,struct dentry *,umode_t); 
	int (*rmdir) (struct inode *,struct dentry *); 
	int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); 
	int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int); 
	int (*setattr) (struct dentry *, struct iattr *); 
	int (*getattr) (const struct path *, struct kstat *, u32, unsigned int); 
	ssize_t (*listxattr) (struct dentry *, char *, size_t); 
	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;

lookup 方法用来在一个目录下查找文件。

系统调用 open 和 creat 调用 create 方法来创建普通文件,系统调用 link 调用 link 方法来创建硬链接,系统调用 symlink 调用 symlink 方法来创建符号链接,系统调用 mkdir 调用 mkdir 方法来创建目录,系统调用 mknod 调用 mknod 方法来创建字符设备文件、块设备文件、命名管道和套接字。

系统调用 unlink 调用 unlink 方法来删除硬链接,系统调用 rmdir 调用 rmdir 方法来删除目录。
系统调用 rename 调用 rename 方法来给文件换一个名字。
系统调用 chmod 调用 setattr 方法来设置文件的属性,系统调用 stat 调用 getattr 方法来读取文件的属性。
系统调用 listxattr 调用 listxattr 方法来列出文件的所有扩展属性。

目录项

文件系统把目录当作文件,这种文件的数据是由目录项组成的,每个目录项存储一个子目录或文件的名称以及对应的索引节点号。

当内核访问存储设备上的一个目录项时,会在内存中创建目录项的一个副本:结构体dentry,主要成员如下:

include/linux/dcache.h 
struct dentry { 
	/* RCU查找访问的字段 */ 
	unsigned int d_flags; 
	seqcount_t d_seq; 
	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; 
	
	union { 
		struct list_head d_lru; 
		wait_queue_head_t *d_wait; 
	}; 
	struct list_head d_child; 
	struct list_head d_subdirs; 
	/*
	* d_alias和d_rcu可以共享内存
	*/ 
	union { 
		struct hlist_node d_alias; 
		struct hlist_bl_node d_in_lookup_hash; 
		struct rcu_head d_rcu; 
	} d_u; 
}; 

d_name 存储文件名称,qstr 是字符串的包装器,存储字符串的地址、长度和散列值;如果文件名称比较短,把文件名称存储在 d_iname;d_inode 指向文件的索引节点。

d_parent 指向父目录,d_child 用来把本目录加入父目录的子目录链表。
d_lockref 是引用计数。
d_op 指向目录项操作集合。
d_subdirs 是子目录链表。
d_hash 用来把目录项加入散列表 dentry_hashtable。
d_lru 用来把目录项加入超级块的最近最少使用(Least Recently Used,LRU)链表 s_dentry_lru 中,当
目录项的引用计数减到 0 时,把目录项添加到超级块的 LRU 链表中。
d_alias 用来把同一个文件的所有硬链接对应的目录项链接起来。

以文件“/a/b.txt”为例,目录项和索引节点的关系如图所示。

在这里插入图片描述

目录项操作集合的数据结构是结构体 dentry_ operations,其代码如下:

include/linux/dcache.h 
struct dentry_operations { 
	int (*d_revalidate)(struct dentry *, unsigned int); 
	int (*d_weak_revalidate)(struct dentry *, unsigned int); 
	int (*d_hash)(const struct dentry *, struct qstr *); 
	int (*d_compare)(const struct dentry *, unsigned int, const char *, const struct qstr *); 
	int (*d_delete)(const struct dentry *); 
	int (*d_init)(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)(const struct path *, bool); 
	struct dentry *(*d_real)(struct dentry *, const struct inode *, unsigned int); 
} ____cacheline_aligned; 

d_revalidate 对网络文件系统很重要,用来确认目录项是否有效。
d_hash 用来计算散列值。
d_compare 用来比较两个目录项的文件名称。
d_delete 用来在目录项的引用计数减到 0 时判断是否可以释放目录项的内存。
d_release 用来在释放目录项的内存之前调用。
d_iput 用来释放目录项关联的索引节点。

文件的打开实例和打开文件表

当进程打开一个文件的时候,虚拟文件系统就会创建文件的一个打开实例:file 结构体,主要成员如下。

include/linux/fs.h 
struct file { 
	union { 
		struct llist_node fu_llist; 
		struct rcu_head fu_rcuhead; 
	} f_u; 
	struct path f_path; 
	struct inode *f_inode; 
	const struct file_operations *f_op; 
	
	spinlock_t f_lock; 
	atomic_long_t f_count; 
	unsigned int f_flags; 
	fmode_t f_mode; 
	struct mutex f_pos_lock; 
	loff_t f_pos; 
	struct fown_struct f_owner; 
	const struct cred *f_cred;void *private_data; 
	… 
	struct address_space *f_mapping; 
} __attribute__((aligned(4)));

(1)f_path 存储文件在目录树中的位置,类型如下:

struct path { 
	struct vfsmount *mnt; 
	struct dentry *dentry; 
}; 

mnt 指向文件所属文件系统的挂载描述符的成员 mnt,dentry 是文件对应的目录项。
(2)f_inode 指向文件的索引节点。
(3)f_op 指向文件操作集合。
(4)f_count 是 file 结构体的引用计数。
(5)f_mode 是访问模式。
(6)f_pos 是文件偏移,即进程当前正在访问的位置。
(7)f_mapping 指向文件的地址空间。

文件的打开实例和索引节点的关系如图所示。

在这里插入图片描述

文件系统信息结构体的主要成员如下:

include/linux/fs_struct.h 
struct fs_struct { 
	… 
	struct path root, pwd; 
};

成员 root 存储进程的根目录,成员 pwd 存储进程的当前工作目录。

假设首先调用系统调用 chroot,把目录“/a”设置为进程的根目录,然后创建子进程,子进程继承父进程的文件系统信息,那么把子进程能看到的目录范围限制为以目录“/a”为根的子树。当子进程打开文件“/b.txt”(文件路径是绝对路径,以“/”开头)时,真实的文件路径是“/a/b.txt”。

假设调用系统调用 chdir,把目录“/c”设置为进程的当前工作目录,当子进程打开文件“d.txt”(文件路径是相对路径,不以“/”开头)时,真实的文件路径是“/c/d.txt”。

打开文件表也称为文件描述符表,数据结构如图所示,结构体 files_struct 是打开文件表的包装器,主要成员如下:

在这里插入图片描述

include/linux/fdtable.h 
struct files_struct { 
	atomic_t count; 
	… 
	
	struct fdtable __rcu *fdt; 
	struct fdtable fdtab; 
	
	spinlock_t file_lock ____cacheline_aligned_in_smp; 
	unsigned int next_fd; 
	unsigned long close_on_exec_init[1]; 
	unsigned long open_fds_init[1]; 
	unsigned long full_fds_bits_init[1]; 
	struct file __rcu * fd_array[NR_OPEN_DEFAULT]; 
};

成员 count 是结构体 files_struct 的引用计数。
成员 fdt 指向打开文件表。
当进程刚刚创建的时候,成员 fdt 指向成员 fdtab。运行一段时间以后,进程打开的文件数量超过NR_OPEN_DEFAULT,就会扩大打开文件表,重新分配 fdtable 结构体,成员fdt 指向新的 fdtable 结构体。
打开文件表的数据结构如下:

include/linux/fdtable.h 
struct fdtable { 
	unsigned int max_fds; 
	struct file __rcu **fd; 
	unsigned long *close_on_exec; 
	unsigned long *open_fds; 
	unsigned long *full_fds_bits; 
	struct rcu_head rcu; 
}; 

(1)成员 max_fds 是打开文件表的当前大小,即成员 fd 指向的 file 指针数组的大小。随着进程打开文件的数量增加,打开文件表逐步扩大。
(2)成员 fd 指向 file 指针数组。当进程调用 open 打开文件的时候,返回的文件描述符是 file 指针数组的索引。
(3)成员 close_on_exec 指向一个位图,指示在执行 execve()以装载新程序的时候需要关闭哪些文件描述符。
(4)成员 open_fds 指向文件描述符位图,指示哪些文件描述符被分配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络2】MII MDC/MDIO

文章目录 1.MII:ISO网络模型中物理层(phy)和数据链路层(mac)属于硬件,其余都属于软件kernel2.MDC/MDIO:不仅管phy,只要支持mdio协议都可以管2.1 BMC速率适配:phy和switch…

二层MAC地址介绍

目录 MAC地址介绍 MAC地址的组成 MAC地址分类 MAC地址的作用 二层交换机介绍 MAC地址表的定义 MAC地址表项类型 二层交换机对数据帧的处理动作 MAC地址介绍 MAC地址(Media Access Control Address),直译为媒体存取控制位地址 MAC地址的组成 MA…

【四、基本shell命令】

1 帮助命令 man 获取帮助信息 [root@redis100 a]# man lshelp 获得shell内置命令的帮助信息 [root@redis100 a]# help cd常用快捷键 2 文件目录类 pwd 显示当前工作目录的绝对路径 pwd:print working directory [root@redis100 ~]# pwd /rootls 列出目录的内容 ls: list…

Hyper-V虚拟机安装和使用

目录 什么是虚拟化技术虚拟化技术有以下几个关键概念:虚拟化技术的优点: 什么是Hyper-V虚拟机Hyper-V虚拟机的关键特点和优势:使用Hyper-V虚拟机我们能做什么 安装Hyper-V系统要求启用Hyper-V功能创建虚拟机安装操作系统 最近在研究人工智能A…

仙境传说RO:NPC对话| mes/next/close函数用法详解

仙境传说RO:NPC对话| mes/next/close函数用法详解 大家好,我是艾西,今天跟大家讲解下仙境传说mes/next/close函数,在游戏中所有的NPC对话都是用mes函数来创建的。 我们先打开官方文档的script _commands.txt文件,搜索*mes searc…

mmdetection调用模型训练

mmdetection调用模型训练 文章目录 mmdetection调用模型训练转化数据集格式从labelme到coco首先data导进来改一下coco.py改一下class_names.py在模型跑了之后看生成文件然后掐了包版本设置PYTHONPATHdiffustiondet模型模型训练跑完了检测模型 yolo模型yolof模型 转化数据集格式…

qemu arm-trusted-firmware atf 的编译

参考网站 ATF (arm-trusted-firmware),可以称之为 Trusted Firmware-A (TF-A),也就是 TF-A https://www.trustedfirmware.org/ https://github.com/ARM-software/arm-trusted-firmware 环境 使用 qemu,就是不需要板子 win10 …

Node.js入门与 Webpack模块打包工具

目录 Node.js入门 fs模块-读写文件 path模块-路径处理 压缩前端html 认识URL中的端口号 http模块-创建Web服务 体验 Web 服务除了接口数据以外,还能返回网页资源等 Node.js模块化 ECMAScript标准-默认导出和导入 ECMAScript标准-命名导出和导入 包的…

攻防世界-Reverse-Game

题目描述:下载附件,得到一个exe程序,运行该程序,可以看到如下的界面 根据描述信息说明: a. 这是一个电路,有8个开关,只有8个开关全部闭合,才能够获取到flag; b. 其中n表…

Unity shader - 纹理采样

目录 1.什么是UV 2.凹凸纹理 3.渐变纹理映射 4.遮罩纹理 1.什么是UV 对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标。什么是UV?简单的…

关于机器人精度的总结(重复精度和绝对精度区分)

ABB系列某款机器人精度参数表 机械臂是工业生产中的重要设备,在焊接码垛 以及 非 接触测量等 领域中有 着重要应 用。然而由于机械臂本体制造中存在机械制造公差装配误差导致的运动学参数误差以及电机转角与关节转角间减速比误差等,导致机械臂存在重复性定位精度较高(0.05 mm …

EMQ的介绍及整合SpringBoot的使用

首先先了解一下底层的协议: 1. MQTT MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅 (publish/subscribe)模式的"轻量级"通讯协议,该协议构建…

python实现递归算法解决年龄问题

一、问题描述 有5个人坐在一起,问第5个人多少岁,他说比第4个人大2岁。问第4个人多少岁,他说比第3个人大2岁。问第3人多少岁,他说比第2个人大2岁。问第2个人多少岁,他说比第1个人大2岁。最后问第1个人多少岁&#xff0…

ALLEGRO之SHAPE

ALLEGRO中的SHAPE菜单对应AD中的Polygon Pour,即铺铜操作。 1. Polygon:铺铜,在Options选择对应子层(例如Etch-Top),选择Dynamic copper(动态铺铜,会自动避让过孔,Static…

MIT 6.S081 教材第五章内容 -- 中断与设备驱动--上

MIT 6.S081 教材第五章内容 -- 中断与设备驱动--上 引言真实操作系统内存使用情况(上一节回顾)中断和设备驱动Interrupt硬件部分设备驱动概述在XV6中设置中断UART驱动的top部分UART驱动的bottom部分Interrupt相关的并发UART读取键盘输入Interrupt的演进小结代码:控制…

VanillaNet 原理与代码解读

paper:VanillaNet: the Power of Minimalism in Deep Learning official implementation: GitHub - huawei-noah/VanillaNet 存在的问题 虽然复杂网络的性能很好,但它们日益增加的复杂性给部署带来了挑战。例如,ResNets中的sh…

浏览器工作原理

浏览器(也称为网络浏览器或互联网浏览器)是安装在我们设备上的软件应用程序,使我们能够访问万维网。在阅读这篇文字时,你实际上正在使用一个浏览器。 有许多浏览器正在被使用,截至2022年,使用最多的是&…

为了找到好工作,花2个月时间整理了3.5W字的自动化测试面试题(答案+学习路线)!

从5月初开始找工作到现在,先后面试了阿里巴巴、字节跳动、网易、快手的测试开发岗。 大公司对于测试开发的要求相比来说高很多,要求掌握的知识点的广度和深度层次也比较高,遂整理了这两个月的面试题目文档供大家参考,同时也是为了…

基于java+swing+mysql商城购物系统

基于javaswingmysql商城购物系统 一、系统介绍二、功能展示1.项目骨架2.主界面3.用户登陆4.添加商品类别5、添加商品6、商品管理 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目类型:Java SE项目 项目名称:商城购物系统 用户类型:双…

【C++学习】线程库 | IO流 | 空间配置器

🐱作者:一只大喵咪1201 🐱专栏:《C学习》 🔥格言:你只管努力,剩下的交给时间! 一、线程库 在C11之前,涉及到多线程问题,都是和平台相关的,比如w…