socket建立后,其他socket 调用都是通过操作得到的文件描述符来操作socket的。
基本上开始都会有这句
sock = sockfd_lookup_light(fd, &err, &fput_needed);//通过fd找到file,进而找到sock
通过文件描述符找到file对象容易理解。但file对象怎么跟socket对象联系起来的呢?
我们进入该函数:
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
struct file *file;
struct socket *sock;
*err = -EBADF;
file = fget_light(fd, fput_needed);
if (file) {
sock = sock_from_file(file, err);
if (sock)
return sock;
fput_light(file, *fput_needed);
}
return NULL;
}
发现得到file对象之后,继而调用sock_from_file
static struct socket *sock_from_file(struct file *file, int *err)
{
if (file->f_op == &socket_file_ops)
return file->private_data; /* set in sock_map_fd */
*err = -ENOTSOCK;
return NULL;
}
发现直接返回file->private_data;private_data 其实是设计用来保存自定义设备结构体的地址的。自定义结构体的地址被保存在private_data后,可以在read ,write 等驱动函数中被传递和调用自定义设备结构体中的成员,在这里用来保存socket对象的地址。那么socket对象的地址是什么时候赋值给了private_data呢?
我们知道在调用socket函数建立socket时,做了两件事:1.建立socket对象;2.建立file对象并和socket绑定。这个绑定的意思就是将socket对象的地址赋值给file对象的private_data成员。我们看具体的代码。调用流程为:
sys_socket-->sock_map_fd--->sock_attach_fd
看sock_attach_fd函数具体代码:
static int sock_attach_fd(struct socket *sock, struct file *file, int flags)
{
struct dentry *dentry;
struct qstr name = { .name = "" };
dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
if (unlikely(!dentry))
return -ENOMEM;
dentry->d_op = &sockfs_dentry_operations;
/*
* We dont want to push this dentry into global dentry hash table.
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
* This permits a working /proc/$pid/fd/XXX on sockets
*/
dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, SOCK_INODE(sock));
sock->file = file;
init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,
&socket_file_ops);
SOCK_INODE(sock)->i_fop = &socket_file_ops;//
file->f_flags = O_RDWR | (flags & O_NONBLOCK);
file->f_pos = 0;
file->private_data = sock;//set sock as private_date,so that we can get sock by struct file
return 0;
}
看到有这句:
file->private_data = sock;//set sock as private_date,so that we can get sock by struct file
现在估计问题就很明了