Chinaunix首页 | 论坛 | 博客
  • 博客访问: 816881
  • 博文数量: 117
  • 博客积分: 2583
  • 博客等级: 少校
  • 技术积分: 1953
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-06 22:58
个人简介

Coder

文章分类
文章存档

2013年(1)

2012年(10)

2011年(12)

2010年(77)

2009年(13)

2008年(4)

分类: LINUX

2010-08-02 02:02:09

close()系统调用

程序关闭打开的文件使用close()系统调用,它接收的参数为要关闭文件的文件描述符fdsys_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字段相应的位。然后对比fdfiles->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方法或文件中的前一个写操作错误产生。


阅读(2994) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~