Documentation

📑

filp_close 的 async 逻辑

  • VFS 关闭文件的逻辑并不是顺序执行的,而是存在一个 delay 操作:
int filp_close(struct file *filp, fl_owner_t id)
{
	int retval;
 
	retval = filp_flush(filp, id); // flush operation, call filp->f_op->flush
	fput(filp); // real close logic
 
	return retval;
}
EXPORT_SYMBOL(filp_close);
 
void fput(struct file *file)
{
	if (atomic_long_dec_and_test(&file->f_count)) {
		struct task_struct *task = current;
 
		if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
			init_task_work(&file->f_rcuhead, ____fput); // <- real task
			if (!task_work_add(task, &file->f_rcuhead, TWA_RESUME))
				return;
			/*
			 * After this task has run exit_task_work(),
			 * task_work_add() will fail.  Fall through to delayed
			 * fput to avoid leaking *file.
			 */
		}
 
		// put task to workqueue
		if (llist_add(&file->f_llist, &delayed_fput_list))
			schedule_delayed_work(&delayed_fput_work, 1); // 1 is delayed jiffies
	}
}
  • 然而,对于真正的 close 系统调用,却并不使用这样的 delay 逻辑:
SYSCALL_DEFINE1(close, unsigned int, fd)
{
	int retval;
	struct file *file;
 
	file = close_fd_get_file(fd);
	if (!file)
		return -EBADF;
 
	retval = filp_flush(file, current->files);
 
	/*
	 * We're returning to user space. Don't bother
	 * with any delayed fput() cases.
	 */
	__fput_sync(file); // <- __fput_sync 是同步操作,没有delay
 
	/* can't restart close syscall because file table entry was cleared */
	if (unlikely(retval == -ERESTARTSYS ||
		     retval == -ERESTARTNOINTR ||
		     retval == -ERESTARTNOHAND ||
		     retval == -ERESTART_RESTARTBLOCK))
		retval = -EINTR;
 
	return retval;
}