模块如何访问内核子系统VFS的某个static链表变量?

模块如何访问内核子系统VFS的某个static链表变量?

想法: 想要得到目前所有在VFS中注册过的文件系统,并且得到某个文件系统instance的super_block. 以及其自己实现的super_block.

其实cat /proc/filesystems就能查看当前在kernel中已经注册的文件系统. 通过get_fs_type()可以拿到一个文件系统的file_system_type.但是我想要所有的fs type.

思路:

因为VFS通过一个非入侵式的list来存放所有已注册的文件系统,位于fs/filesystems.c中.

该list是static的,那么不妨添加一个non-static函数将其暴露出来.然后使用EXPORT_SYMBOL()导出给模块使用.

还有一点需要知道的是: 当某个文件系统mount后, VFS会将其该类型的所有挂载上的实例(super_block)都加入到struct file_system_typefs_supers成员. fs_supers是一个hlist

步骤:
  1. fs/filesystems.c文件下添加函数

    struct file_system_type *LuChao_getfilesystems() {
            return file_systems;
    }
    EXPORT_SYMBOL(LuChao_getfilesystems);
    
  2. include/linux/fs.h中添加函数声明

    extern struct file_system_type *LuChao_getfilesystems(void);
    
  3. 回到kernel的根目录下编译

    make然后make install

  4. 重新制作启动项然后重启(非UEFI)

    sudo grub2-mkconfig -o /boot/grub2/grub.cfg

  5. 查看是否成功导出符号

    cat /proc/kallsyms | grep LuChao

    [root@localhost linux]# cat /proc/kallsyms | grep LuChao
    ffffffffa50bcb40 T LuChao_getfilesystems
    ffffffffa5f5ebc8 r __ksymtab_LuChao_getfilesystems
    ffffffffa5f852ab r __kstrtab_LuChao_getfilesystems

  6. 最后就是编写一个模块来得到fs instance的super block对象. 以nova file system为例.

    懒得弄头文件包含路径,直接将super_block的定义拷贝过来用.

    super.h

    #ifndef __SUPER_H__
    #define __SUPER_H__
    
    /*
     *  * NOVA super-block data in DRAM
     *   */
    struct nova_sb_info {
    	struct super_block *sb;			/* VFS super block */
    	struct nova_super_block *nova_sb;	/* DRAM copy of SB */
    	struct block_device *s_bdev;
    	struct dax_device *s_dax_dev;
    
    	/*
    	 *	 * base physical and virtual address of NOVA (which is also
    	 *		 * the pointer to the super block)
    	 *			 */
    	phys_addr_t	phys_addr;
    	void		*virt_addr;
    	void		*replica_reserved_inodes_addr;
    	void		*replica_sb_addr;
    
    	unsigned long	num_blocks;
    
    	/* TODO: Remove this, since it's unused */
    	/*
    	 *	 * Backing store option:
    	 *		 * 1 = no load, 2 = no store,
    	 *			 * else do both
    	 *				 */
    	unsigned int	nova_backing_option;
    
    	/* Mount options */
    	unsigned long	bpi;
    	unsigned long	blocksize;
    	unsigned long	initsize;
    	unsigned long	s_mount_opt;
    	kuid_t		uid;    /* Mount uid for root directory */
    	kgid_t		gid;    /* Mount gid for root directory */
    	umode_t		mode;   /* Mount mode for root directory */
    	atomic_t	next_generation;
    	/* inode tracking */
    	unsigned long	s_inodes_used_count;
    	unsigned long	head_reserved_blocks;
    	unsigned long	tail_reserved_blocks;
    
    	struct mutex	s_lock;	/* protects the SB's buffer-head */
    
    	int cpus;
    	struct proc_dir_entry *s_proc;
    
    	/* Snapshot related */
    	struct nova_inode_info	*snapshot_si;
    	struct radix_tree_root	snapshot_info_tree;
    	int num_snapshots;
    	/* Current epoch. volatile guarantees visibility */
    	volatile u64 s_epoch_id;
    	volatile int snapshot_taking;
    
    	int mount_snapshot;
    	u64 mount_snapshot_epoch_id;
    
    	struct task_struct *snapshot_cleaner_thread;
    	wait_queue_head_t snapshot_cleaner_wait;
    	wait_queue_head_t snapshot_mmap_wait;
    	void *curr_clean_snapshot_info;
    
    	/* DAX-mmap snapshot structures */
    	struct mutex vma_mutex;
    	struct list_head mmap_sih_list;
    
    	/* ZEROED page for cache page initialized */
    	void *zeroed_page;
    
    	/* Checksum and parity for zero block */
    	u32 zero_csum[8];
    	void *zero_parity;
    
    	/* Per-CPU journal lock */
    	spinlock_t *journal_locks;
    
    	/* Per-CPU inode map */
    	struct inode_map	*inode_maps;
    
    	/* Decide new inode map id */
    	unsigned long map_id;
    
    	/* Per-CPU free block list */
    	struct free_list *free_lists;
    	unsigned long per_list_blocks;
    };
    
    struct nova_super_block {
    	/* static fields. they never change after file system creation.
    	 *	 * checksum only validates up to s_start_dynamic field below
    	 *		 */
    	__le32		s_sum;			/* checksum of this sb */
    	__le32		s_magic;		/* magic signature */
    	__le32		s_padding32;
    	__le32		s_blocksize;		/* blocksize in bytes */
    	__le64		s_size;			/* total size of fs in bytes */
    	char		s_volume_name[16];	/* volume name */
    
    	/* all the dynamic fields should go here */
    	__le64		s_epoch_id;		/* Epoch ID */
    
    	/* s_mtime and s_wtime should be together and their order should not be
    	 *	 * changed. we use an 8 byte write to update both of them atomically
    	 *		 */
    	__le32		s_mtime;		/* mount time */
    	__le32		s_wtime;		/* write time */
    
    	/* Metadata and data protections */
    	u8		s_padding8;
    	u8		s_metadata_csum;
    	u8		s_data_csum;
    	u8		s_data_parity;
    } __attribute((__packed__));
    
    #endif
    

    模块中实现的代码部分: 比如拿到nova fs的超级块实际所在的kernel space的起始地址.

    	struct file_system_type *cur = LuChao_getfilesystems();
    	struct nova_sb_info *sbi;
    	while (cur) {
    		const char *name = cur->name;
    		const char *module_name = cur->owner->name;
    		
    		if (!strncmp(name, NOVASTR, sizeof(NOVASTR)))
    		{
    			pr_info(DBG "[fs_name = %s\tfs'module_name = %s\tfs_description = %s]", name, module_name, cur->parameters->name);
    			// traverse hlist of instance
    			struct hlist_node *pinstances = cur->fs_supers.first;
    			// get fs instance's super block
    			struct super_block *sb = container_of(pinstances, struct super_block, s_instances);
    			// get fs instance's implement super block
    			sbi = (struct nova_sb_info *)sb->s_fs_info;
    			break;
    		}
    		cur = cur->next;
    	}
    	// testing sbi
    	pr_info("nvmm phys_addr = %llx", (unsigned long long)sbi->phys_addr);
    	struct nova_super_block *nova_sb = sbi->nova_sb;
    	//pr_info("nova_sb. s_mtime = %lu, nova_sb.s_wtime = %lu", nova_sb->s_mtime, nova_sb->s_wtime);
    

你可能感兴趣的:(linux,kernel,linux)