日期:2014-05-16  浏览次数:20764 次

linux内核中的文件描述符(三)--fd的回收

 linux内核中的文件描述符(三)--fd的回收

Kernel version:2.6.14

CPU architecture:ARM920T

Author:ce123(http://blog.csdn.net/ce123)

1.close函数

上图说明了close(fd)的执行过程,主要包括两部分:释放文件描述符fd,关闭文件file。

//fs/open.c
asmlinkage long sys_close(unsigned int fd)
{
	struct file * filp;
	struct files_struct *files = current->files;//获得当前进程的files结构
	struct fdtable *fdt;

	spin_lock(&files->file_lock);
	fdt = files_fdtable(files);//通过进程的打开文件列表获得文件描述符位图结构
	if (fd >= fdt->max_fds)
		goto out_unlock;
	filp = fdt->fd[fd];
	if (!filp)
		goto out_unlock;
	rcu_assign_pointer(fdt->fd[fd], NULL);
	FD_CLR(fd, fdt->close_on_exec);
	__put_unused_fd(files, fd);//释放文件描述符
	spin_unlock(&files->file_lock);
	return filp_close(filp, files);//关闭文件

out_unlock:
	spin_unlock(&files->file_lock);
	return -EBADF;
}

2.释放文件描述符__put_unused_fd

static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
{
	struct fdtable *fdt = files_fdtable(files);
	__FD_CLR(fd, fdt->open_fds);//清除位图中的相应标记
	if (fd < fdt->next_fd)
		fdt->next_fd = fd;//如果释放的fd小于next_fd,则next_fd = fd,下次分配从next_fd开始。
					//因此释放一个fd后,再打开或创建一个文件放回的可能还是刚释放的fd
}

3.关闭文件filp_close

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)
		retval = filp->f_op->flush(filp);

	dnotify_flush(filp, id);
	locks_remove_posix(filp, id);
	fput(filp);
	return retval;
}
filp_close函数调用fput,在fput中调用release函数。
//fs/file_table.c
void fastcall fput(struct file *file)
{
	if (rcuref_dec_and_test(&file->f_count))
		__fput(file);
}

void fastcall __fput(struct file *file)
{
	struct dentry *dentry = file->f_dentry;
	struct vfsmount *mnt = file->f_vfsmnt;
	struct inode *inode = dentry->d_inode;

	might_sleep();

	fsnotify_close(file);
	/*
	 * The function eventpoll_release() should be the first called
	 * in the file cleanup chain.
	 */
	eventpoll_release(file);
	locks_remove_flock(file);

	if (file->f_op && file->f_op->release)
		file->f_op->release(inode, file);//在这里调用release函数。在socket中即socket_close函数
	security_file_free(file);
	if (unl