内核源码: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); //释放相应的文件系统资源(引用计数为零时)
}