Estrutura de dados do sistema de arquivos virtual

Estrutura de dados do sistema de arquivos virtual

Embora as estruturas físicas de diferentes tipos de sistemas de arquivos sejam diferentes, o sistema de arquivos virtual define uma estrutura de dados unificada.

(1) Superbloco. O primeiro bloco do sistema de arquivos é o super bloco, que descreve as informações gerais do sistema de arquivos.Quando o sistema de arquivos é montado, uma cópia do super bloco é criada na memória: a estrutura super_block.
(2) O sistema de arquivos virtual organiza diretórios como uma árvore na memória. Um sistema de arquivos só pode ser acessado por um processo se estiver montado em um diretório na árvore de diretórios na memória. Toda vez que o sistema de arquivos é montado, o sistema de arquivos virtual cria um descritor de montagem: estrutura de montagem, lê o super bloco do sistema de arquivos e cria uma cópia do super bloco na memória.
(3) O formato do super bloco de cada sistema de arquivos é diferente. É necessário registrar o tipo de sistema de arquivos file_system_type com o sistema de arquivos virtual e implementar o método mount para ler e analisar o super bloco.
(4) Nó de índice. Cada arquivo corresponde a um nó de índice e cada nó de índice possui um número exclusivo. Quando o kernel acessa um arquivo em um dispositivo de armazenamento, ele cria uma cópia do inode na memória: a estrutura inode.
(5) Itens de diretório. O sistema de arquivos considera o diretório como um tipo de arquivo, e os dados do diretório são compostos de entradas de diretório, e cada entrada de diretório armazena o nome de um subdiretório ou arquivo e o número do nó de índice correspondente. Quando o kernel acessa uma entrada de diretório no dispositivo de armazenamento, uma cópia da entrada de diretório é criada na memória: a estrutura dentry.
(6) Quando um processo abre um arquivo, o sistema de arquivos virtual criará uma instância aberta do arquivo: a estrutura do arquivo e, em seguida, atribuirá um índice na tabela de arquivos abertos do processo. Esse índice é chamado de descritor de arquivo e, finalmente, o arquivo Um mapa de descritores e estruturas de arquivos é adicionado à tabela de arquivos abertos.

Super rápido

O primeiro bloco do sistema de arquivos é o super bloco, que é usado para descrever as informações gerais do sistema de arquivos. Quando montamos o sistema de arquivos em um diretório da árvore de diretórios na memória, o super bloco do sistema de arquivos será lido e uma cópia do super bloco será criada na memória: a estrutura super_block, os membros principais são do seguinte modo:

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) O membro s_list é usado para vincular todas as instâncias do super bloco à lista global vinculada super_blocks.
(2) Os membros s_dev e s_bdev salvam o dispositivo de bloco onde o sistema de arquivos está localizado, o primeiro salva o número do dispositivo e o último aponta para uma instância block_device na memória.
(3) O membro s_blocksize é o comprimento do bloco e o membro s_blocksize_bits é o logaritmo de base 2 do comprimento do bloco.
(4) O membro s_maxbytes é o comprimento máximo de arquivo suportado pelo sistema de arquivos.
(5) O membro s_flags é um bit de flag.
(6) O membro s_type aponta para o tipo de sistema de arquivos.
(7) O membro s_op aponta para o conjunto de operação do super bloco.
(8) O membro s_magic é o número mágico do tipo de sistema de arquivo, e cada tipo de sistema de arquivo recebe um número mágico exclusivo.
(9) O membro s_root aponta para a estrutura dentry do diretório raiz.
(10) O membro s_fs_info aponta para as informações privadas do sistema de arquivos específico.
(11) O membro s_instances é usado para vincular todas as instâncias do super bloco do mesmo tipo de sistema de arquivos, e o nó principal da lista vinculada é o membro fs_supers da estrutura file_system_type.

A estrutura de dados do conjunto de operações do super bloco é a estrutura super_operations, os membros principais são os seguintes:

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) O membro alloc_inode é usado para alocar e inicializar memória para um nó de índice.
(2) O membro destroy_inode é usado para liberar os contatos do índice na memória.
(3) O membro dirty_inode é usado para marcar o nó de índice como sujo.
(4) O membro write_inode é usado para gravar um nó de índice no dispositivo de armazenamento.
(5) O membro drop_inode é usado para chamar quando a contagem de referência do nó de índice é reduzida a 0.
(6) O membro evict_inode é usado para excluir um nó de índice do sistema de arquivos no dispositivo de armazenamento.
(7) O membro put_super é usado para liberar o bloco super.
(8) O membro sync_fs é usado para sincronizar os dados modificados do sistema de arquivos com o dispositivo de armazenamento.
(9) O membro statfs é usado para ler as informações estatísticas do sistema de arquivos.
(10) O membro remount_fs é usado para chamar ao remontar o sistema de arquivos.
(11) O membro umount_begin é usado para chamar ao desmontar o sistema de arquivos.

descritor de montagem

Um sistema de arquivos só pode ser acessado por um processo se estiver montado em um diretório na árvore de diretórios da memória. Sempre que o sistema de arquivos for montado, o sistema de arquivos virtual criará um descritor de montagem: estrutura de montagem. O descritor de montagem é usado para descrever uma instância de montagem do sistema de arquivos. O sistema de arquivos no mesmo dispositivo de armazenamento pode ser montado várias vezes e, a cada vez, é montado em um diretório diferente. Os principais membros do descritor de montagem são os seguintes:

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

Suponha que montamos o sistema de arquivos 2 no diretório "/a" e o diretório a pertence ao sistema de arquivos 1. O diretório a é chamado de ponto de montagem, a instância de montagem do sistema de arquivos 2 é filha da instância de montagem do sistema de arquivos 1 e a instância de montagem do sistema de arquivos 1 é o pai da instância de montagem do sistema de arquivos 2.

(1) O membro mnt_parent aponta para o pai, ou seja, a instância de montagem do sistema de arquivos 1.
(2) O membro mnt_mountpoint aponta para o diretório como o ponto de montagem, ou seja, o diretório a do sistema de arquivos 1, e o membro d_flags da instância dentry do diretório a define o bit de sinalizador DCACHE_MOUNTED.
(3) O tipo de membro mnt é o seguinte:

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

mnt_root aponta para o diretório raiz do sistema de arquivos 2 e mnt_sb aponta para o super bloco do sistema de arquivos 2.
(4) O membro mnt_hash é usado para adicionar o descritor de montagem à tabela hash global mount_hashtable, e a palavra-chave é {descritor de montagem pai, ponto de montagem}.
(5) O membro mnt_mounts é o nó principal da lista de filhos.
(6) O membro mnt_child é usado para entrar na lista de filhos do pai.
(7) O membro mnt_instance é usado para adicionar o descritor de montagem à lista encadeada de instâncias de montagem do super bloco. O sistema de arquivos no mesmo dispositivo de armazenamento pode ser montado várias vezes e, a cada vez, é montado em um diretório diferente.
(8) O membro mnt_devname aponta para o nome do dispositivo de armazenamento.
(9) O membro mnt_ns aponta para o namespace mount.
(10) O membro mnt_mp aponta para o ponto de montagem, o tipo é o seguinte:

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

m_dentry aponta para o diretório como o ponto de montagem e m_list é usado para vincular todos os descritores de montagem no mesmo ponto de montagem. Por que existem vários descritores de montagem no mesmo ponto de montagem? Isso tem a ver com a montagem de namespaces.
(11) O membro mnt_mp_list é usado para adicionar o descritor de montagem à lista vinculada do descritor de montagem do mesmo ponto de montagem, e o nó principal da lista vinculada é o membro m_list do membro mnt_mp.

tipo de sistema de arquivos

Como o formato do super bloco de cada sistema de arquivos é diferente, cada sistema de arquivos precisa registrar o tipo de sistema de arquivos file_system_type com o sistema de arquivos virtual e implementar o método mount para ler e analisar o super bloco. A estrutura file_system_type é a seguinte:

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) O nome do membro é o nome do tipo de sistema de arquivos.
(2) O método mount é usado para ler e analisar o super bloco ao montar o sistema de arquivos.
(3) O método kill_sb é usado para liberar o super bloco ao desmontar o sistema de arquivos.
(4) Os tipos de sistemas de arquivos em vários dispositivos de armazenamento podem ser os mesmos, e o membro fs_supers é usado para
vincular os superblocos do mesmo tipo de sistema de arquivos.

nó de índice

No sistema de arquivos, cada arquivo corresponde a um nó de índice e o nó de índice descreve dois tipos de informações.
(1) Os atributos do arquivo, também conhecidos como metadados (metadados), como o comprimento do arquivo, o identificador do usuário que criou o arquivo, a hora do último acesso e a hora da última modificação, e breve.
(2) O local de armazenamento dos dados do arquivo.
Cada inode tem um número único.
Quando o kernel acessa um arquivo no dispositivo de armazenamento, uma cópia do nó de índice será criada na memória: a estrutura inode, os membros principais são os seguintes:

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 é o tipo de arquivo e os direitos de acesso, i_uid é o identificador do usuário que criou o arquivo e i_gid é o identificador do grupo ao qual pertence o usuário que criou o arquivo.

i_ino é o número do inode.

i_size é o tamanho do arquivo; i_blocks é o número de blocos no arquivo, ou seja, o quociente da divisão do tamanho do arquivo pelo tamanho do bloco; i_bytes é o restante da divisão do tamanho do arquivo pelo tamanho do bloco; i_blkbits elevado à potência.

i_atime (hora de acesso) é a última vez que o arquivo foi acessado, i_mtime (hora da modificação) é a última vez que os dados do arquivo foram modificados e i_ctime (hora da alteração) é a última vez que o nó de índice do arquivo foi modificado.

i_sb aponta para o superbloco do sistema de arquivos ao qual o arquivo pertence.

i_mapping aponta para o espaço de endereço do arquivo.

i_count é a contagem de referência do inode e i_nlink é a contagem de hard link.

Se o tipo de arquivo for um arquivo de dispositivo de caractere ou um arquivo de dispositivo de bloco, então i_rdev é o número do dispositivo, i_bdev aponta para o dispositivo de bloco e i_cdev aponta para o dispositivo de caractere.

Os arquivos são divididos nos seguintes tipos.
(1) Arquivo comum (arquivo normal): É o que costumamos chamar de arquivo, e é um arquivo em sentido estrito.
(2) Diretório: Um diretório é um arquivo especial cujos dados são compostos de entradas de diretório e cada entrada de diretório
armazena o nome de um subdiretório ou arquivo e o número do nó de índice correspondente.
(3) Link simbólico (também chamado de soft link): Os dados desse tipo de arquivo são o caminho de outro arquivo.
(4) Arquivos de dispositivos de caracteres.
(5) Bloquear arquivos de dispositivos.
(6) Pipes nomeados (FIFOs).
(7) soquete (soquete).
Arquivos de dispositivo de caractere, arquivos de dispositivo de bloco, pipes nomeados e soquetes são arquivos especiais que possuem apenas inodes e nenhum dado. Arquivos de dispositivo de caractere e arquivos de dispositivo de bloco são usados ​​para armazenar números de dispositivo, e os números de dispositivo são armazenados diretamente em inodes.

O kernel suporta dois tipos de ligação.
(1) Soft link, também conhecido como link simbólico, os dados deste arquivo são o caminho de outro arquivo.
(2) Hard links são equivalentes a dar vários nomes a um arquivo, e vários nomes de arquivo correspondem ao mesmo nó de índice, e o membro i_nlink do nó de índice é a contagem de hard link.

O membro i_op do nó de índice aponta para o conjunto de operações do nó de índice inode_operations e o membro i_fop aponta para o conjunto de operações de arquivo file_operations. A diferença entre os dois é: inode_operations é usado para manipular diretórios (criar ou excluir arquivos em um diretório) e atributos de arquivo, e file_operations é usado para acessar dados de arquivo. A estrutura de dados do conjunto de operações do nó de índice é a estrutura inode_operations, os membros principais são os seguintes:

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;

O método de pesquisa é usado para localizar arquivos em um diretório.

As chamadas do sistema open e creat chamam o método create para criar um arquivo comum, a chamada do sistema link chama o método link para criar um hard link, a chamada do sistema symlink chama o método symlink para criar um link simbólico, a chamada do sistema mkdir chama o mkdir para criar um diretório, e a chamada do sistema mknod chama o método mknod para criar arquivos de dispositivo de caracteres, arquivos de dispositivo de bloco, pipes nomeados e soquetes.

A chamada do sistema unlink chama o método unlink para excluir um link físico, e a chamada do sistema rmdir chama o método rmdir para excluir um diretório.
A chamada do sistema rename chama o método rename para renomear um arquivo.
A chamada do sistema chmod chama o método setattr para definir os atributos do arquivo, e a chamada do sistema stat chama o método getattr para ler os atributos do arquivo.
A chamada de sistema listxattr chama o método listxattr para listar todos os atributos estendidos de um arquivo.

entrada de catálogo

O sistema de arquivos considera um diretório como um arquivo, e os dados desse arquivo são compostos de entradas de diretório, e cada entrada de diretório armazena o nome de um subdiretório ou arquivo e o número do nó de índice correspondente.

Quando o kernel acessa uma entrada de diretório no dispositivo de armazenamento, uma cópia da entrada de diretório será criada na memória: a estrutura dentry, os membros principais são os seguintes:

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 armazena o nome do arquivo, qstr é um wrapper de string, armazena o endereço, comprimento e valor de hash da string; se o nome do arquivo for relativamente curto, armazene o nome do arquivo em d_iname; d_inode aponta para o nó de índice do arquivo.

d_parent aponta para o diretório pai e d_child é usado para adicionar esse diretório à lista de subdiretórios do diretório pai.
d_lockref é a referência contada.
d_op aponta para a coleção de operações de entrada de diretório.
d_subdirs é uma lista encadeada de subdiretórios.
d_hash é usado para adicionar entradas de diretório à tabela hash dentry_hashtable.
d_lru é usado para adicionar a entrada de diretório à lista Least Recent Used (LRU) s_dentry_lru do super bloco. Quando a
contagem de referência da entrada de diretório diminui para 0, adicione a entrada de diretório à lista LRU do super bloco.
d_alias é usado para vincular as entradas de diretório correspondentes a todos os hard links do mesmo arquivo.

Tomando o arquivo "/a/b.txt" como exemplo, a relação entre entradas de diretório e nós de índice é mostrada na figura.

insira a descrição da imagem aqui

A estrutura de dados do conjunto de operações de entrada de diretório é a estrutura dentry_operations e seu código é o seguinte:

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 é importante para sistemas de arquivos de rede para confirmar se as entradas de diretório são válidas.
d_hash é usado para calcular o valor de hash.
d_compare é usado para comparar os nomes de arquivo de duas entradas de diretório.
d_delete é usado para julgar se a memória da entrada do diretório pode ser liberada quando a contagem de referência da entrada do diretório é reduzida a 0.
d_release é usado para chamar antes de liberar memória para uma entrada de diretório.
d_iput é usado para liberar o inode associado à entrada do diretório.

Abra a instância do arquivo e abra a tabela de arquivos

Quando um processo abre um arquivo, o sistema de arquivos virtual criará uma instância aberta do arquivo: estrutura do arquivo, os membros principais são os seguintes.

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 armazena a localização do arquivo na árvore de diretórios, os tipos são os seguintes:

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

mnt aponta para o membro mnt do descritor de montagem do sistema de arquivos ao qual o arquivo pertence e dentry é a entrada de diretório correspondente ao arquivo.
(2) f_inode aponta para o nó de índice do arquivo.
(3) f_op aponta para a coleção de operações de arquivo.
(4) f_count é a contagem de referência da estrutura do arquivo.
(5) f_mode é o modo de acesso.
(6) f_pos é o deslocamento do arquivo, ou seja, a posição que o processo está acessando no momento.
(7) f_mapping aponta para o espaço de endereço do arquivo.

A relação entre a instância aberta do arquivo e o nó de índice é mostrada na figura.

insira a descrição da imagem aqui

Os principais membros da estrutura de informações do sistema de arquivos são os seguintes:

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

O membro raiz armazena o diretório raiz do processo e o membro pwd armazena o diretório de trabalho atual do processo.

Supondo que a chamada do sistema chroot seja chamada primeiro, o diretório "/a" é definido como o diretório raiz do processo e, em seguida, um processo filho é criado e o processo filho herda as informações do sistema de arquivos do processo pai e, em seguida, o intervalo de diretórios que o processo filho pode ver é limitado ao diretório "/a" como a subárvore raiz. Quando o processo filho abre o arquivo "/b.txt" (o caminho do arquivo é um caminho absoluto começando com "/"), o caminho real do arquivo é "/a/b.txt".

Assuma que a chamada do sistema chdir é chamada e o diretório "/c" é definido como o diretório de trabalho atual do processo. Quando o processo filho abre o arquivo "d.txt" (o caminho do arquivo é um caminho relativo e não comece com "/"), o caminho real do arquivo é "/c/d.txt".

A tabela de arquivo aberto também é chamada de tabela de descritor de arquivo. A estrutura de dados é mostrada na figura. A estrutura files_struct é um wrapper para a tabela de arquivo aberto. Os membros principais são os seguintes:

insira a descrição da imagem aqui

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

A contagem de membros é a contagem de referência da estrutura files_struct.
O membro fdt aponta para a tabela de arquivos abertos.
Quando o processo acaba de ser criado, o membro fdt aponta para o membro fdtab. Depois de executar por um período de tempo, se o número de arquivos abertos pelo processo exceder NR_OPEN_DEFAULT, a tabela de arquivos abertos será expandida e a estrutura fdtable será redistribuída, e o membro fdt apontará para a nova estrutura fdtable.
A estrutura de dados da tabela de arquivos abertos é a seguinte:

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) O membro max_fds é o tamanho atual da tabela de arquivo aberto, ou seja, o tamanho da matriz de ponteiro de arquivo apontada pelo membro fd. À medida que o número de arquivos abertos do processo aumenta, a tabela de arquivos abertos se expande gradualmente.
(2) O membro fd aponta para o array de ponteiros de arquivo. Quando um processo chama open para abrir um arquivo, o descritor de arquivo retornado é um índice no array de ponteiros de arquivo.
(3) O membro close_on_exec aponta para um bitmap indicando quais descritores de arquivo precisam ser fechados ao executar execve() para carregar um novo programa.
(4) O membro open_fds aponta para o bitmap do descritor de arquivo, indicando quais descritores de arquivo estão alocados.

Acho que você gosta

Origin blog.csdn.net/weixin_43912621/article/details/131363802
Recomendado
Clasificación