久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux內(nèi)核VFS的open

 wythe 2023-05-24 發(fā)布于廣東

VFS介紹

在跟蹤流程open流程之前我們首先了解一下VFS,,Linux 內(nèi)核中的 VFS(Virtual File System)是一個(gè)抽象層,,它隱藏了基礎(chǔ)文件系統(tǒng)(如 ext4,、NTFS 等)的實(shí)現(xiàn)細(xì)節(jié),并提供一個(gè)統(tǒng)一的文件系統(tǒng)接口給用戶空間和內(nèi)核使用,。VFS 可以讓應(yīng)用程序在使用不同的底層文件系統(tǒng)時(shí)不必了解底層文件系統(tǒng)的細(xì)節(jié),,這樣可以方便用戶使用并提高文件系統(tǒng)的靈活性、可擴(kuò)展性,。

VFS 在內(nèi)核中的位置是 fs/vfs 目錄,,它包含了各種文件系統(tǒng)操作的定義和實(shí)現(xiàn),例如文件創(chuàng)建,、文件打開,、讀寫文件等。VFS 定義了一系列文件相關(guān)的結(jié)構(gòu)體,,如文件描述符(file descriptor),、超級(jí)塊(superblock)、索引節(jié)點(diǎn)(inode)等,,這些結(jié)構(gòu)體描述了一個(gè)文件在內(nèi)核中的屬性和狀態(tài),,并提供了相應(yīng)的操作函數(shù)。這些操作函數(shù)在不同的底層文件系統(tǒng)中都具有類似的功能,,但底層實(shí)現(xiàn)可能會(huì)不同,。

VFS 也提供了一些虛擬文件系統(tǒng),比如 tmpfs,、proc,、sysfs 等,它們?cè)趦?nèi)存中創(chuàng)建了一個(gè)文件系統(tǒng),,并提供了一些虛擬文件和目錄,,用于映射內(nèi)核狀態(tài)或特定設(shè)備的信息。

總的來說,,VFS 是一個(gè)非常重要的組件,,在 Linux 內(nèi)核中起到了連接用戶空間和底層文件系統(tǒng)的橋梁作用。

open系統(tǒng)調(diào)用定義

open系統(tǒng)調(diào)用定義在內(nèi)核源碼目錄fs/open.c里面

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
	if (force_o_largefile())
		flags |= O_LARGEFILE;

	return do_sys_open(AT_FDCWD, filename, flags, mode);
}

SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
		umode_t, mode)
{
	if (force_o_largefile())
		flags |= O_LARGEFILE;

	return do_sys_open(dfd, filename, flags, mode);
}

參數(shù):

    dfd 文件描述符

    filename 文件具體路徑名字

    flags打開文件標(biāo)志位,,方式

    mode 權(quán)限控制位

open跟蹤

由上面系統(tǒng)調(diào)用定義可以知道,,不管調(diào)用那種方式打開文件,最后都會(huì)調(diào)用到一個(gè)函數(shù)中去do_sys_open中,。

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
	struct open_flags op;
	int fd = build_open_flags(flags, mode, &op);
	struct filename *tmp;

	if (fd)
		return fd;

	tmp = getname(filename); //1
	if (IS_ERR(tmp))
		return PTR_ERR(tmp);

	fd = get_unused_fd_flags(flags);//2
	if (fd >= 0) {
		struct file *f = do_filp_open(dfd, tmp, &op);//3
		if (IS_ERR(f)) {
			put_unused_fd(fd);
			fd = PTR_ERR(f);
		} else {
			fsnotify_open(f);
			fd_install(fd, f);// 4
		}
	}
	putname(tmp);
	return fd; //5
}

流程說明:

    1.從用戶空間獲取文件名字,,路徑,;

    2.根據(jù)當(dāng)前進(jìn)程打開文件描述表(也就是一個(gè)文件描述符數(shù)組 stdin stdout stderr類似)獲取         一個(gè)空閑的文件描述符fd;

    3.調(diào)用真正打開文件流程;

    4.把當(dāng)前進(jìn)程的打開文件與fd安裝到,,進(jìn)程描述表中,,類似讓fd與file綁定;

    5.把當(dāng)前打開文件獲取到描述符返回用戶空間,;

接下來重點(diǎn)跟蹤do_filp_open,,它是打開文件程序主流程

struct file *do_filp_open(int dfd, struct filename *pathname,
		const struct open_flags *op)
{
	struct nameidata nd;
	int flags = op->lookup_flags;
	struct file *filp;

	set_nameidata(&nd, dfd, pathname);
	filp = path_openat(&nd, op, flags | LOOKUP_RCU);//1
	if (unlikely(filp == ERR_PTR(-ECHILD)))
		filp = path_openat(&nd, op, flags);
	if (unlikely(filp == ERR_PTR(-ESTALE)))
		filp = path_openat(&nd, op, flags | LOOKUP_REVAL);
	restore_nameidata();
	return filp;
}

調(diào)用到path_openat函數(shù)中

static struct file *path_openat(struct nameidata *nd,
			const struct open_flags *op, unsigned flags)
{
	const char *s;
	struct file *file;
	int opened = 0;
	int error;

	file = get_empty_filp(); //1
	if (IS_ERR(file))
		return file;

	file->f_flags = op->open_flag;

	if (unlikely(file->f_flags & __O_TMPFILE)) {
		error = do_tmpfile(nd, flags, op, file, &opened);
		goto out2;
	}

	if (unlikely(file->f_flags & O_PATH)) {
		error = do_o_path(nd, flags, file);
		if (!error)
			opened |= FILE_OPENED;
		goto out2;
	}

	s = path_init(nd, flags);//2
	if (IS_ERR(s)) {
		put_filp(file);
		return ERR_CAST(s);
	}
	while (!(error = link_path_walk(s, nd)) &&
		(error = do_last(nd, file, op, &opened)) > 0) {//3
		nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
		s = trailing_symlink(nd);
		if (IS_ERR(s)) {
			error = PTR_ERR(s);
			break;
		}
	}
	terminate_walk(nd);
out2:
	if (!(opened & FILE_OPENED)) {
		BUG_ON(!error);
		put_filp(file);
	}
	if (unlikely(error)) {
		if (error == -EOPENSTALE) {
			if (flags & LOOKUP_RCU)
				error = -ECHILD;
			else
				error = -ESTALE;
		}
		file = ERR_PTR(error);
	}
	return file;
}

  1. 申請(qǐng)file結(jié)構(gòu)體內(nèi)存;

  2. path_init()是一個(gè)函數(shù),,定義在 Linux 內(nèi)核的 fs/namei.c文件中,。它的作用是初始化一個(gè) struct path類型的變量,該變量用于描述一個(gè)文件系統(tǒng)路徑,;

   3. do_last() 是 Linux 內(nèi)核在進(jìn)行打開文件操作時(shí)的一個(gè)重要函數(shù),,定義在 fs/namei.c 中。  它的作用是在 VFS 中進(jìn)行文件名到文件描述符的轉(zhuǎn)換,,并構(gòu)建一個(gè)表示打開文件的 struct file 結(jié)構(gòu)體,;

/*
 * Handle the last step of open()
 */
static int do_last(struct nameidata *nd,
		   struct file *file, const struct open_flags *op,
		   int *opened)
{
	struct dentry *dir = nd->path.dentry;
	kuid_t dir_uid = nd->inode->i_uid;
	umode_t dir_mode = nd->inode->i_mode;
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
	bool got_write = false;
	int acc_mode = op->acc_mode;
	unsigned seq;
	struct inode *inode;
	struct path path;
	int error;

	nd->flags &= ~LOOKUP_PARENT;
	nd->flags |= op->intent;

	if (nd->last_type != LAST_NORM) {
		error = handle_dots(nd, nd->last_type);
		if (unlikely(error))
			return error;
		goto finish_open;
	}

	if (!(open_flag & O_CREAT)) {
		if (nd->last.name[nd->last.len])
			nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
		/* we _can_ be in RCU mode here */
		error = lookup_fast(nd, &path, &inode, &seq);
		if (likely(error > 0))
			goto finish_lookup;

		if (error < 0)
			return error;

		BUG_ON(nd->inode != dir->d_inode);
		BUG_ON(nd->flags & LOOKUP_RCU);
	} else {
		/* create side of things */
		/*
		 * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED
		 * has been cleared when we got to the last component we are
		 * about to look up
		 */
		error = complete_walk(nd);
		if (error)
			return error;

		audit_inode(nd->name, dir, LOOKUP_PARENT);
		/* trailing slashes? */
		if (unlikely(nd->last.name[nd->last.len]))
			return -EISDIR;
	}

	if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
		error = mnt_want_write(nd->path.mnt);
		if (!error)
			got_write = true;
		/*
		 * do _not_ fail yet - we might not need that or fail with
		 * a different error; let lookup_open() decide; we'll be
		 * dropping this one anyway.
		 */
	}
	if (open_flag & O_CREAT)
		inode_lock(dir->d_inode);
	else
		inode_lock_shared(dir->d_inode);
	error = lookup_open(nd, &path, file, op, got_write, opened);
	if (open_flag & O_CREAT)
		inode_unlock(dir->d_inode);
	else
		inode_unlock_shared(dir->d_inode);

	if (error <= 0) {
		if (error)
			goto out;

		if ((*opened & FILE_CREATED) ||
		    !S_ISREG(file_inode(file)->i_mode))
			will_truncate = false;

		audit_inode(nd->name, file->f_path.dentry, 0);
		goto opened;
	}

	if (*opened & FILE_CREATED) {
		/* Don't check for write permission, don't truncate */
		open_flag &= ~O_TRUNC;
		will_truncate = false;
		acc_mode = 0;
		path_to_nameidata(&path, nd);
		goto finish_open_created;
	}

	/*
	 * If atomic_open() acquired write access it is dropped now due to
	 * possible mount and symlink following (this might be optimized away if
	 * necessary...)
	 */
	if (got_write) {
		mnt_drop_write(nd->path.mnt);
		got_write = false;
	}

	error = follow_managed(&path, nd);
	if (unlikely(error < 0))
		return error;

	if (unlikely(d_is_negative(path.dentry))) {
		path_to_nameidata(&path, nd);
		return -ENOENT;
	}

	/*
	 * create/update audit record if it already exists.
	 */
	audit_inode(nd->name, path.dentry, 0);

	if (unlikely((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
		path_to_nameidata(&path, nd);
		return -EEXIST;
	}

	seq = 0;	/* out of RCU mode, so the value doesn't matter */
	inode = d_backing_inode(path.dentry);
finish_lookup:
	error = step_into(nd, &path, 0, inode, seq);
	if (unlikely(error))
		return error;
finish_open:
	/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
	error = complete_walk(nd);
	if (error)
		return error;
	audit_inode(nd->name, nd->path.dentry, 0);
	if (open_flag & O_CREAT) {
		error = -EISDIR;
		if (d_is_dir(nd->path.dentry))
			goto out;
		error = may_create_in_sticky(dir_mode, dir_uid,
					     d_backing_inode(nd->path.dentry));
		if (unlikely(error))
			goto out;
	}
	error = -ENOTDIR;
	if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
		goto out;
	if (!d_is_reg(nd->path.dentry))
		will_truncate = false;

	if (will_truncate) {
		error = mnt_want_write(nd->path.mnt);
		if (error)
			goto out;
		got_write = true;
	}
finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);
	if (error)
		goto out;
	BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
	error = vfs_open(&nd->path, file, current_cred());
	if (error)
		goto out;
	*opened |= FILE_OPENED;
opened:
	error = open_check_o_direct(file);
	if (!error)
		error = ima_file_check(file, op->acc_mode, *opened);
	if (!error && will_truncate)
		error = handle_truncate(file);
out:
	if (unlikely(error) && (*opened & FILE_OPENED))
		fput(file);
	if (unlikely(error > 0)) {
		WARN_ON(1);
		error = -EINVAL;
	}
	if (got_write)
		mnt_drop_write(nd->path.mnt);
	return error;
}

代碼比較長(zhǎng),我們只需要抓住主干,,vfs_open

finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);//這里會(huì)有權(quán)限檢查
	if (error)
		goto out;
	BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
	error = vfs_open(&nd->path, file, current_cred());
	if (error)
		goto out;
	*opened |= FILE_OPENED;

error = lookup_open(nd, &path, file, op, got_write, opened)

lookup_open()是 Linux 內(nèi)核中處理文件打開的一個(gè)重要函數(shù),,定義在文件 fs/namei.c 中。該函數(shù)的作用是根據(jù)給定的路徑名(由 nameidata結(jié)構(gòu)體表示)查找文件或者目錄并打開它,,最終返回一個(gè)打開的文件描述符,。

首先,lookup_open() 函數(shù)調(diào)用 path_lookupat() 函數(shù)來查找路徑名所對(duì)應(yīng)的 inode, 這個(gè) inode 中記錄了該文件詳細(xì)信息和路徑,,如果查找不到相關(guān)的 inode,,表示文件不存在,函數(shù)返回一個(gè)錯(cuò)誤值(例如,,ENOENT),。接下來,文件系統(tǒng)會(huì)帶上 file->f_path.dentry->d_inode(dentry 表示“路徑”中的目錄項(xiàng))與操作標(biāo)記 op 進(jìn)入 combine_open() 函數(shù),,進(jìn)一步進(jìn)行打開文件操作,。如果找到了文件 inode,lookup_open() 函數(shù)會(huì)檢查文件訪問權(quán)限并打開文件,。如果打開文件失敗,,函數(shù)會(huì)返回一個(gè)錯(cuò)誤指針,否則返回打開的文件描述符,。

需要注意的是,,lookup_open() 函數(shù)的作用是打開一個(gè)文件(或目錄),而不是創(chuàng)建文件。若需要?jiǎng)?chuàng)建文件,,應(yīng)該使用稍有不同的函數(shù),如 vfs_create() 或 vfs_mkdir().

vfs_open是直接調(diào)用到了虛擬文件系統(tǒng)的標(biāo)準(zhǔn)接口去

int vfs_open(const struct path *path, struct file *file,
	     const struct cred *cred)
{
	struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);

	if (IS_ERR(dentry))
		return PTR_ERR(dentry);

	file->f_path = *path;
	return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
}

inode與file file_operations三者數(shù)據(jù)結(jié)構(gòu)的關(guān)系

struct inode,、struct file 和 struct file_operations 是 Linux 內(nèi)核中與文件相關(guān)的三個(gè)重要結(jié)構(gòu)體,,它們之間存在緊密的關(guān)系:

struct inode結(jié)構(gòu)體描述一個(gè)文件在內(nèi)核中的屬性和狀態(tài),例如文件所有者,、文件權(quán)限,、文件大小等。每個(gè)打開的文件都有一個(gè)對(duì)應(yīng)的 struct inode結(jié)構(gòu)體,。struct file 結(jié)構(gòu)體的 f_inode成員指向?qū)?yīng)的 struct inode 結(jié)構(gòu)體,。

struct file結(jié)構(gòu)體表示一個(gè)打開的文件描述符,它包含了一些與文件操作相關(guān)的信息,,例如當(dāng)前文件位置,、讀寫操作指針、文件打開方式等,。struct file_operations結(jié)構(gòu)體包含了一些操作文件的函數(shù)指針,,如 read()、write(),、open(),、release() 等。struct file 結(jié)構(gòu)體中的 f_op 成員指向?qū)?yīng)的 struct file_operations結(jié)構(gòu)體,。

當(dāng)應(yīng)用程序通過系統(tǒng)調(diào)用打開一個(gè)文件時(shí),,Linux 內(nèi)核會(huì)首先在文件系統(tǒng)中查找對(duì)應(yīng)的 struct inode結(jié)構(gòu)體。然后,,內(nèi)核會(huì)為打開的文件創(chuàng)建一個(gè)對(duì)應(yīng)的 struct file 結(jié)構(gòu)體,,并將其與 struct inode結(jié)構(gòu)體關(guān)聯(lián)起來。最后,,內(nèi)核會(huì)為打開的文件選擇一個(gè)合適的 struct file_operations結(jié)構(gòu)體,,它包含了對(duì)該文件進(jìn)行操作的函數(shù)指針。

因此,,struct inode,、struct file 和 struct file_operations都是文件系統(tǒng) VFS 層面的結(jié)構(gòu)體,它們分別表示文件的屬性和狀態(tài),、文件描述符以及文件操作的接口函數(shù),。這三個(gè)結(jié)構(gòu)體是 Linux 內(nèi)核中文件操作的基礎(chǔ)。

struct file

struct file {
	union {
		struct llist_node	fu_llist;
		struct rcu_head 	fu_rcuhead;
	} f_u;
	struct path		f_path;
	struct inode		*f_inode;	/* cached value *///關(guān)鍵成員
	const struct file_operations	*f_op; ////關(guān)鍵成員

	/*
	 * Protects f_ep_links, f_flags.
	 * Must not be taken from IRQ context.
	 */
	spinlock_t		f_lock;
	enum rw_hint		f_write_hint;
	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;
	struct file_ra_state	f_ra;

	u64			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;
	struct list_head	f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
	struct address_space	*f_mapping;
	errseq_t		f_wb_err;
} __randomize_layout
  __attribute__((aligned(4)));	/* lest something weird decides that 2 is OK */

struct file_operations

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
	int (*iterate) (struct file *, struct dir_context *);
	int (*iterate_shared) (struct file *, struct dir_context *);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **, void **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
	void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
	unsigned (*mmap_capabilities)(struct file *);
#endif
	ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
			loff_t, size_t, unsigned int);
	int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
			u64);
	ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
			u64);
} __randomize_layout;

struct 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

	/* Stat data, not accessed from path walking */
	unsigned long		i_ino;
	/*
	 * Filesystems may only read i_nlink directly.  They shall use the
	 * following functions for modification:
	 *
	 *    (set|clear|inc|drop)_nlink
	 *    inode_(inc|dec)_link_count
	 */
	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;	/* i_blocks, i_bytes, maybe i_size */
	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

	/* Misc */
	unsigned long		i_state;
	struct rw_semaphore	i_rwsem;

	unsigned long		dirtied_when;	/* jiffies of first dirtying */
	unsigned long		dirtied_time_when;

	struct hlist_node	i_hash;
	struct list_head	i_io_list;	/* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
	struct bdi_writeback	*i_wb;		/* the associated cgroup wb */

	/* foreign inode detection, see wbc_detach_inode() */
	int			i_wb_frn_winner;
	u16			i_wb_frn_avg_time;
	u16			i_wb_frn_history;
#endif
	struct list_head	i_lru;		/* inode LRU list */
	struct list_head	i_sb_list;
	struct list_head	i_wb_list;	/* backing dev writeback 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; /* struct files open RO */
#endif
	const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
	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;
	};

	__u32			i_generation;

#ifdef CONFIG_FSNOTIFY
	__u32			i_fsnotify_mask; /* all events this inode cares about */
	struct fsnotify_mark_connector __rcu	*i_fsnotify_marks;
#endif

#ifdef CONFIG_FS_ENCRYPTION
	struct fscrypt_info	*i_crypt_info;
#endif

	void			*i_private; /* fs or device private pointer */
} __randomize_layout;

繼續(xù)跟蹤主流程



static int do_dentry_open(struct file *f,
			  struct inode *inode,
			  int (*open)(struct inode *, struct file *),
			  const struct cred *cred)
{
	static const struct file_operations empty_fops = {};
	int error;

	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
				FMODE_PREAD | FMODE_PWRITE;

	path_get(&f->f_path);
	f->f_inode = inode;
	f->f_mapping = inode->i_mapping;

	/* Ensure that we skip any errors that predate opening of the file */
	f->f_wb_err = filemap_sample_wb_err(f->f_mapping);

	if (unlikely(f->f_flags & O_PATH)) {
		f->f_mode = FMODE_PATH;
		f->f_op = &empty_fops;
		return 0;
	}

	/* Any file opened for execve()/uselib() has to be a regular file. */
	if (unlikely(f->f_flags & FMODE_EXEC && !S_ISREG(inode->i_mode))) {
		error = -EACCES;
		goto cleanup_file;
	}

	if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
		error = get_write_access(inode);
		if (unlikely(error))
			goto cleanup_file;
		error = __mnt_want_write(f->f_path.mnt);
		if (unlikely(error)) {
			put_write_access(inode);
			goto cleanup_file;
		}
		f->f_mode |= FMODE_WRITER;
	}

	/* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))
		f->f_mode |= FMODE_ATOMIC_POS;

	f->f_op = fops_get(inode->i_fop);//1
	if (unlikely(WARN_ON(!f->f_op))) {
		error = -ENODEV;
		goto cleanup_all;
	}

	error = security_file_open(f, cred); //2
	if (error)
		goto cleanup_all;

	error = break_lease(locks_inode(f), f->f_flags);
	if (error)
		goto cleanup_all;

	if (!open)
		open = f->f_op->open;
	if (open) {
		error = open(inode, f);//3
		if (error)
			goto cleanup_all;
	}
	if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
		i_readcount_inc(inode);
	if ((f->f_mode & FMODE_READ) &&
	     likely(f->f_op->read || f->f_op->read_iter))
		f->f_mode |= FMODE_CAN_READ;
	if ((f->f_mode & FMODE_WRITE) &&
	     likely(f->f_op->write || f->f_op->write_iter))
		f->f_mode |= FMODE_CAN_WRITE;

	f->f_write_hint = WRITE_LIFE_NOT_SET;
	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

	file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);

	return 0;

cleanup_all:
	fops_put(f->f_op);
	if (f->f_mode & FMODE_WRITER) {
		put_write_access(inode);
		__mnt_drop_write(f->f_path.mnt);
	}
cleanup_file:
	path_put(&f->f_path);
	f->f_path.mnt = NULL;
	f->f_path.dentry = NULL;
	f->f_inode = NULL;
	return error;
}

  1. fops_get通常在 Linux 內(nèi)核中處理文件系統(tǒng)相關(guān)操作時(shí)使用,,它用于將一個(gè) inode 對(duì)象的操作函數(shù)指針賦值給一個(gè)打開的文件的操作函數(shù)指針,。

  2. security_file_open() 是一個(gè) Linux 內(nèi)核中的安全模塊 hook 函數(shù),用于在打開文件時(shí)進(jìn)行安全檢查,以保證系統(tǒng)的安全性,。該函數(shù)定義在 /security/security.c 文件中,。其中,struct file是內(nèi)核用來表示打開文件的結(jié)構(gòu)體,,它包含了打開的文件描述符,、VMA 以及操作指針等數(shù)據(jù)。security_file_open()函數(shù)在打開文件時(shí)被調(diào)用,,可以對(duì)該文件的訪問進(jìn)行必要的安全性檢查,。如果安全模塊判斷文件打開請(qǐng)求有安全問題,可以在此處拒絕該請(qǐng)求并報(bào)告錯(cuò)誤,。

  3. 安全模塊的 hook 函數(shù)在內(nèi)核中扮演著重要的角色,。它可以進(jìn)行訪問權(quán)限的檢查、進(jìn)程識(shí)別以及文件標(biāo)簽等相關(guān)的安全檢查,。在 Linux 中,,安全模塊 hook 函數(shù)作為內(nèi)核和用戶空間的接口,可以定制一些安全策略以允許或拒絕對(duì)系統(tǒng)的訪問,。

    需要注意的是,,在進(jìn)行文件訪問控制時(shí),除了安全模塊 hook 函數(shù)外,,還有 SELinux,、AppArmor 等不同的安全模塊可以用于提供強(qiáng)大的安全保護(hù),這些模塊也可以通過其相應(yīng)的 hook 函數(shù)來進(jìn)行安全檢查,。

  4. 最后調(diào)用struct file_operations 中的int (*open) (struct inode *, struct file *)成員,。

到此,打開文件的整個(gè)流程分析介紹,。小弟才疏學(xué)淺,,如有錯(cuò)誤請(qǐng)大神指正!?。,。。,。,。?/p>

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多