您的位置:首页 > 理论基础 > 计算机网络

TCP/IP源码学习(47)——socket与VFS的关联(1) 2 http://blog.chinaunix.net/uid-23629988-id-3080166.html

2015-09-03 09:52 676 查看
TCP/IP源码学习(47)——socket与VFS的关联(1) 2012-02-22
22:38:13

分类: LINUX

作者:gfree.wind@gmail.com

博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================

今天学习一下socket与VFS之间的关系。

对于socket编程,我们都知道socket也是一个文件描述符,那么socket与VFS之间究竟是如何关联的呢?

首先,创建socket的函数,socket.c的函数SYSCALL_DEFINE3(socket, int, family, int, type, int,
protocol)在成功创建了socket以后,通过函数sock_map_fd,将创建的struct socket结构映射为一个文件描述符。

/* sock为成功创建的struct socket *sock类型, 而retval为映射后的文件描述符 */

retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));

if (retval < 0)

goto out_release;

进入sock_map_fd

int sock_map_fd(struct socket *sock, int flags)

{

struct file *newfile;

/* 将sock映射为一个文件描述符fd */

int fd = sock_alloc_file(sock, &newfile, flags);

/* 映射成功后,将fd加入到当前进程的文件描述符表中 */

if (likely(fd >= 0))

fd_install(fd, newfile);

return fd;

}

进入sock_alloc_file,

static int sock_alloc_file(struct socket *sock, struct
file **f, int flags)

{

struct qstr name = { .name = "" };

struct path path;

struct file *file;

int fd;

/*
该函数名字稍微有点晦涩。看上去像是获得fd_flags,但是实际上是获得fd。
我个人觉得名字叫做get_unused_fd_with_flags更好一些,这样还是突出是获得fd
*/

fd = get_unused_fd_flags(flags);

if (unlikely(fd < 0))

return fd;

/*
申请新的dentry,用socket对应的inode——该inode实际上是与socket同时申请下来的,参见struct
socket_ alloc结构,
初始化该dentry。
sock_mnt为一个全局变量,为sockfs的文件系统挂载点。
*/

path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);

if (unlikely(!path.dentry)) {

put_unused_fd(fd);

return -ENOMEM;

}

path.mnt = mntget(sock_mnt);

/*
将sockfs的dentry操作函数,和文件操作函数分别绑定到dentry和inode上。
这样即完成VFS的统一调用。
*/

path.dentry->d_op = &sockfs_dentry_operations;

d_instantiate(path.dentry, SOCK_INODE(sock));

SOCK_INODE(sock)->i_fop = &socket_file_ops;

/* 申请file,并将前面的dentry path与file关联起来 */

file = alloc_file(&path, FMODE_READ | FMODE_WRITE,

&socket_file_ops);

if (unlikely(!file)) {

/* drop dentry, keep inode */

atomic_inc(&path.dentry->d_inode->i_count);

path_put(&path);

put_unused_fd(fd);

return -ENFILE;

}

sock->file = file;

file->f_flags = O_RDWR | (flags & O_NONBLOCK);

file->f_pos = 0;

file->private_data = sock;

*f = file;

return fd;

}

进入get_unused_fd_flags->alloc_fd

*/

int alloc_fd(unsigned start, unsigned flags)

{

struct files_struct *files = current->files;

unsigned int fd;

int error;

struct fdtable *fdt;

spin_lock(&files->file_lock);

repeat:

/* 得到该进程的文件描述符表 */

fdt = files_fdtable(files);

/* 从start开始查找 */

fd = start;

/*

files->next_fd为上一次查找确定的下一个可用空闲的文件描述符。

那么这次可以直接使用next_fd

*/

if (fd < files->next_fd)

fd = files->next_fd;

/* 当fd小于目前进程支持的最大的描述符号,那么可以通过fds_bits位图,从fd位开始查找,
找到下一个0位,即下一个空闲描述符。
*/

if (fd < fdt->max_fds)

fd = find_next_zero_bit(fdt->open_fds->fds_bits,

fdt->max_fds, fd);

/* 如需要则扩展文件描述符表 */

error = expand_files(files, fd);

if (error < 0)

goto out;

/*

* If we needed to expand the fs array we

* might have blocked - try again.

*/

if (error)

goto repeat;

/*
设置next_fd,用于下次加速查找空闲的fd。
当start大于next_fd时,不会设置next_fd以避免文件描述符的不连续
*/

if (start <= files->next_fd)

files->next_fd = fd + 1;

/* 将fd添加到已打开的文件描述符表中 */

FD_SET(fd, fdt->open_fds);

if (flags & O_CLOEXEC)

FD_SET(fd, fdt->close_on_exec);

else

FD_CLR(fd, fdt->close_on_exec);

error = fd;

#if 1

/* Sanity check */

if (rcu_dereference_raw(fdt->fd[fd]) != NULL) {

printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);

rcu_assign_pointer(fdt->fd[fd], NULL);

}

#endif

out:

spin_unlock(&files->file_lock);

return error;

}

今天是socket如何挂载到VFS的流程,还剩下一小部分这个流程的代码。下一次会将剩下的代码学习完毕,以及如何从VFS到socket流程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: