TCP/IP源码学习(47)——socket与VFS的关联(1) 2 http://blog.chinaunix.net/uid-23629988-id-3080166.html
来源:互联网 发布:php中变量的作用域 编辑:程序博客网 时间:2024/06/11 00:48
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
博客: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流程。
0 0
- TCP/IP源码学习(47)——socket与VFS的关联(1) 2 http://blog.chinaunix.net/uid-23629988-id-3080166.html
- socket TCP协议 http://blog.chinaunix.net/uid-22488454-id-3059636.html
- TCP/IP源码学习(47)——socket与VFS的关联
- 平衡树:2-3-4 Tree的实现与分析 http://blog.chinaunix.net/uid-23629988-id-3152495.html
- 高性能网络I/O框架-netmap源码分析(2) http://blog.chinaunix.net/uid-23629988-id-3608622.html
- 高性能网络I/O框架-netmap源码分析(1) http://blog.chinaunix.net/uid-23629988-id-3594118.html
- fork()与vfork()的区别 http://blog.chinaunix.net/uid-18921523-id-265538.html
- rand与srand函数的使用 http://blog.chinaunix.net/uid-25906157-id-3165140.html
- linux socket编程之socket()函数介绍 http://blog.chinaunix.net/uid-20788470-id-1841640.html
- socket选项总结(setsocketopt) http://blog.chinaunix.net/uid-24517549-id-4044883.html
- http://blog.chinaunix.net/uid-22666718-id-1771703.html
- http://blog.chinaunix.net/uid-20322254-id-145835.html
- http://blog.chinaunix.net/uid-25547034-id-3155778.html
- http://blog.chinaunix.net/uid-25750954-id-2956084.html
- http://blog.chinaunix.net/uid-22342564-id-3053393.html
- http://blog.chinaunix.net/uid-25082381-id-3242162.html
- http://blog.chinaunix.net/uid-25737580-id-3182286.html
- http://blog.chinaunix.net/uid-25835268-id-3055356.html--makefile
- 特权模式
- 12bit,24bit,32bit颜色
- Bootstrap typeahead使用问题记录及解决方案
- LeetCode Minimum Path Sum(动态规划)
- Struts2核心工作原理解析
- TCP/IP源码学习(47)——socket与VFS的关联(1) 2 http://blog.chinaunix.net/uid-23629988-id-3080166.html
- 14条职场生涯建议
- 天罗地网——Python爬虫初初初探
- phpcms v9中的$CATEGORYS栏目数组
- js,级联替换(图片)
- cmd 删除系统垃圾文件
- 将浮点型算式的中缀表达式转换成后缀表达式并算出式子结果
- webdriver简单对象的定位_python
- android颜色设置alpha的问题