内核源码:linux-2.6.38.8.tar.bz2

    目标平台:ARM体系结构

 

    在Linux内核中,系统调用close的定义如下所示:

/* fs/open.c */
SYSCALL_DEFINE1(close, unsigned int, fd)
{
	struct file * filp;
	struct files_struct *files = current->files;
	struct fdtable *fdt;
	int retval;

	spin_lock(&files->file_lock);
	fdt = files_fdtable(files);
	if (fd >= fdt->max_fds) //无效的文件描述符
		goto out_unlock;
	filp = fdt->fd[fd]; //获得文件指针
	if (!filp) //filp为NULL
		goto out_unlock;
	rcu_assign_pointer(fdt->fd[fd], NULL); //将fdt->fd[fd]置零
	FD_CLR(fd, fdt->close_on_exec); //清除相应的close_on_exec比特位
	__put_unused_fd(files, fd); //清除相应的open_fds比特位
	spin_unlock(&files->file_lock);
	
	retval = filp_close(filp, files); //执行close的主要操作
	
	if (unlikely(retval == -ERESTARTSYS ||
		     retval == -ERESTARTNOINTR ||
		     retval == -ERESTARTNOHAND ||
		     retval == -ERESTART_RESTARTBLOCK))
		retval = -EINTR;

	return retval;

out_unlock:
	spin_unlock(&files->file_lock);
	return -EBADF;
}
    filp_close函数用于完成close系统调用的主要操作。源代码如下所示:

/* include/linux/fs.h */
typedef struct files_struct *fl_owner_t;

/* fs/open.c */
int filp_close(struct file *filp, fl_owner_t id)
{
	int retval = 0;

	if (!file_count(filp)) { //文件指针的引用计数已经为零
		printk(KERN_ERR "VFS: Close: file count is 0\n");
		return 0;
	}

	if (filp->f_op && filp->f_op->flush) //flush函数指针为真则调用它
		retval = filp->f_op->flush(filp, id);

	dnotify_flush(filp, id); //对于目录文件,释放dnotify mark资源
	locks_remove_posix(filp, id); //清除POSIX文件锁
	fput(filp);
	return retval;
}
    fput函数在文件指针引用计数file->f_count为零时释放在open等系统调用中所使用的资源。源代码如下所示:

/* fs/file_table.c */
void fput(struct file *file)
{
	if (atomic_long_dec_and_test(&file->f_count)) //引用计数为零则执行__fput函数销毁文件指针
		__fput(file);
}

static void __fput(struct file *file)
{
	struct dentry *dentry = file->f_path.dentry;
	struct vfsmount *mnt = file->f_path.mnt;
	struct inode *inode = dentry->d_inode;

	might_sleep(); //可能休眠并记录相应信息以便调试

	fsnotify_close(file); //实现文件系统事件监控的IN_CLOSE_WRITE或IN_CLOSE_NOWRITE事件
	
	eventpoll_release(file); //释放epoll资源
	locks_remove_flock(file); //清除flock文件锁

	if (unlikely(file->f_flags & FASYNC)) { //标志FASYNC通过fcntl系统调用设置
		if (file->f_op && file->f_op->fasync) //当fasync函数指针为真时则调用它,执行异步通知
			file->f_op->fasync(-1, file, 0);
	}
	
	//当release函数指针为真时则调用它,执行与file->f_op->open相反的操作
	if (file->f_op && file->f_op->release)
		file->f_op->release(inode, file);
	security_file_free(file); //安全模块检查
	ima_file_free(file); //释放相应i节点的IMA数据
	if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) //字符设备文件
		cdev_put(inode->i_cdev);
	//处理操作函数模块(当以模块加载时),递增file->f_op->owner->refptr->decs计数,并唤醒等待该模块的进程
	fops_put(file->f_op); 
	put_pid(file->f_owner.pid); //释放捕捉SIGIO信号的进程的相关资源
	file_sb_list_del(file); //从超级块文件指针链表中移除该项
	if (file->f_mode & FMODE_WRITE)
		//递减一些相关的引用计数并将file->f_mnt_write_state从FILE_MNT_WRITE_TAKEN状态更改为FILE_MNT_WRITE_RELEASED
		drop_file_write_access(file); 
	file->f_path.dentry = NULL;
	file->f_path.mnt = NULL;
	file_free(file); //释放file->f_cred和文件指针自身
	dput(dentry); //释放相应的目录项资源(引用计数为零时)
	mntput(mnt); //释放相应的文件系统资源(引用计数为零时)
}

Logo

更多推荐