Coder
分类: LINUX
2010-08-02 02:02:09
close()系统调用
程序关闭打开的文件使用close()系统调用,它接收的参数为要关闭文件的文件描述符fd。sys_close()服务例程定义如下:
---------------------------------------------------------------------
fs/open.c
/*
* Careful here! We test whether the file
pointer is NULL before
* releasing the fd. This ensures that one
clone task can't release
* an fd while another clone is opening it.
*/
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)
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);
retval = filp_close(filp, files);
/* 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;
out_unlock:
spin_unlock(&files->file_lock);
return -EBADF;
}
---------------------------------------------------------------------
sys_close()服务例程执行下列操作:
1、获得存放在当前进程current->files->fdt->fd[fd]中的文件对象,如果它为NULL,则返回-EBADF
2、把current->files->fdt->fd[fd]置为NULL。释放文件描述符fd,这是通过清除current->files->fdt->close_on_exec字段相应的位及调用__put_unused_fd(files, fd)函数来进行的。__put_unused_fd()定义如下:
---------------------------------------------------------------------
fs/open.c
static
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 < files->next_fd)
files->next_fd = fd;
}
---------------------------------------------------------------------
这个函数清除current->files->fdt-> open_fds字段相应的位。然后对比fd和files->next_fd,如果前者更小,则更新后者为前者。由此可见files_struct结构的next_fd中存放的是文件描述表中可用的最小的文件描述符。这个字段,一来可以为文件描述符的快速分配提供支持,二来则有助于缩小所需搜索的可用的文件描述符的范围。
3、调用filp_close(),该函数定义如下:
---------------------------------------------------------------------
fs/open.c
/*
* "id" is the POSIX thread ID. We
use the
* files pointer for this..
*/
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,
id);
dnotify_flush(filp, id);
locks_remove_posix(filp, id);
fput(filp);
return retval;
}
---------------------------------------------------------------------
该函数执行下列操作:
a.判断文件的引用计数是否为0,若是,则返回0。
b.调用文件操作的flush方法(如果已定义)。
c.释放文件上的任何强制锁。参见后面“文件加锁”部分。
d.调用fput(filp)释放文件对象,该函数定义为:
---------------------------------------------------------------------
fs/file_table.c
/*
__fput is called from task context when aio completion releases the last
* last use of a struct file *. Do not use otherwise.
*/
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);
/*
* The
function eventpoll_release() should be the first called
* in
the file cleanup chain.
*/
eventpoll_release(file);
locks_remove_flock(file);
if (unlikely(file->f_flags & FASYNC))
{
if (file->f_op &&
file->f_op->fasync)
file->f_op->fasync(-1, file,
0);
}
if (file->f_op &&
file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
ima_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode)
&& inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
put_pid(file->f_owner.pid);
file_kill(file);
if (file->f_mode & FMODE_WRITE)
drop_file_write_access(file);
file->f_path.dentry = NULL;
file->f_path.mnt = NULL;
file_free(file);
dput(dentry);
mntput(mnt);
}
void
fput(struct file *file)
{
if
(atomic_long_dec_and_test(&file->f_count))
__fput(file);
}
---------------------------------------------------------------------
在这个函数中,监测与文件有关的file对象、目录项对象及vfsmount对象的引用计数,若引用计数为0,且条件合适,则将它们归还给相应的slab缓存。
4、返回0,或一个出错码。出错码可由flush方法或文件中的前一个写操作错误产生。