/*\linux-5.10.x\net\core\sock.c
用于初始化套接字数据结构中的各个字段和锁,以及设置套接字的默认参数。具体功能如下:
1、初始化套接字的读写锁和对等锁
2、设置套接字的对等进程ID和对等进程凭证为NULL,并初始化对等锁
3、设置套接字的待发送数据长度为0,接收缓冲区低水位标记为1,接收超时和发送超时为最大超时值
4、设置套接字的时间戳为默认时间戳值
5、如果BITS_PER_LONG的值是32,初始化套接字的时间戳序列锁
6、设置套接字的零拷贝密钥为0
7、如果配置了网络接收忙碌轮询功能,设置套接字的NAPI ID为0,并从系统变量中读取并设置套接字的忙碌轮询时间
8、设置套接字的最大调度速率和调度速率为最大的无符号长整型值,调度速率的位移为10。将套接字的入站CPU设置为-1
9、清除套接字的接收队列,删除所有已接收但尚未处理的数据包
*/
void sock_init_data(struct socket *sock, struct sock *sk)
{
sk_init_common(sk); //初始化通用的sock数据结构
sk->sk_send_head = NULL; //将发送队列头部指针置为空
timer_setup(&sk->sk_timer, NULL, 0); //设置定时器,使用空回调函数和初始超时值0
sk->sk_allocation = GFP_KERNEL; //设置当前socket的内存分配标志为内核级别的分配
sk->sk_rcvbuf = READ_ONCE(sysctl_rmem_default); //读取系统变量sysctl_rmem_default的值作为接收缓冲区大小
sk->sk_sndbuf = READ_ONCE(sysctl_wmem_default); //读取系统变量sysctl_wmem_default的值作为发送缓冲区大小
sk->sk_state = TCP_CLOSE; //设置socket状态为TCP_CLOSE,表示关闭状态
sk_set_socket(sk, sock); //将sock与sk关联起来
sock_set_flag(sk, SOCK_ZAPPED); //设置SOCK_ZAPPED标志位,表示socket被重置
if (sock) { //如果sock非空
sk->sk_type = sock->type; //将socket类型设置为sock的类型
RCU_INIT_POINTER(sk->sk_wq, &sock->wq); //将socket的等待队列指针赋给sk的等待队列指针
sock->sk = sk; //将sk赋给socket的sk字段
sk->sk_uid = SOCK_INODE(sock)->i_uid; //获取socket所属文件描述符的用户ID,并赋给sk的用户ID
} else { //如果sock为空
RCU_INIT_POINTER(sk->sk_wq, NULL); //初始化sk的等待队列指针为空
sk->sk_uid = make_kuid(sock_net(sk)->user_ns, 0); //将套接字的用户ID设置为make_kuid创建的内核用户ID(root用户ID)
}
rwlock_init(&sk->sk_callback_lock); //对套接字的sk_callback_lock字段进行读写锁的初始化
if (sk->sk_kern_sock) //套接字是否为内核套接字(kern_sock)。kern_sock是一种特殊类型的套接字,它在内核空间中使用,与用户空间无关
lockdep_set_class_and_name( //lockdep_set_class_and_name用于设置锁的类和名称。是内核中的一个调试工具,用于跟踪锁的使用情况
&sk->sk_callback_lock, //要设置的锁对象
af_kern_callback_keys + sk->sk_family,
af_family_kern_clock_key_strings[sk->sk_family]); //将使用af_kern_callback_keys数组中与套接字家族(sk_family)相对应的元素作为锁类
else //如果套接字不是内核套接字
lockdep_set_class_and_name(
&sk->sk_callback_lock,
af_callback_keys + sk->sk_family,
af_family_clock_key_strings[sk->sk_family]); //将使用af_callback_keys数组中与套接字家族(sk_family)相对应的元素作为锁类
sk->sk_state_change = sock_def_wakeup; //套接字状态改变的回调函数,当套接字状态发生改变时,将调用此函数
sk->sk_data_ready = sock_def_readable; //套接字数据就绪的回调函数,当套接字有数据可读时,将调用此函数
sk->sk_write_space = sock_def_write_space; //套接字写空间可用的回调函数,当套接字的写空间可用时,将调用此函数
sk->sk_error_report = sock_def_error_report; //套接字错误报告的回调函数,当套接字发生错误时,将调用此函数
sk->sk_destruct = sock_def_destruct; //套接字析构的回调函数,当套接字被销毁时,将调用此函数
/* 以下字段用于在接收数据时进行分片处理 */
sk->sk_frag.page = NULL; //套接字的分段信息初始化为NULL
sk->sk_frag.offset = 0; //偏移量为0
sk->sk_peek_off = -1; //查看偏移量设置为-1
/* 以下字段和锁用于处理套接字的对等进程信息 */
sk->sk_peer_pid = NULL; //对等进程ID字段
sk->sk_peer_cred = NULL; //对等进程凭证字段
spin_lock_init(&sk->sk_peer_lock); //对对等锁sk_peer_lock进行自旋锁的初始化
/* 以下字段用于控制套接字的发送和接收行为 */
sk->sk_write_pending = 0; //套接字的待发送数据长度字段
sk->sk_rcvlowat = 1; //接收缓冲区低水位标记,表示最小可接收数据量
sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; //接收超时字段设置为最大超时值(MAX_SCHEDULE_TIMEOUT)
sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; //发送超时字段设置为最大超时值(MAX_SCHEDULE_TIMEOUT)
sk->sk_stamp = SK_DEFAULT_STAMP; //套接字的时间戳设置为默认时间戳值。用于记录套接字的最后一次状态改变的时间
#if BITS_PER_LONG==32 // 如果每个长整型数占32位
seqlock_init(&sk->sk_stamp_seq); // 初始化套接字时间戳序列锁
#endif
atomic_set(&sk->sk_zckey, 0); // 设置套接字的零拷贝密钥为0
#ifdef CONFIG_NET_RX_BUSY_POLL
sk->sk_napi_id = 0; // 网络适配器处理标识符初始化为0
sk->sk_ll_usec = READ_ONCE(sysctl_net_busy_read); // 读取网络繁忙忙等待时长
#endif
/* 以下字段用于控制数据包的调度和处理 */
sk->sk_max_pacing_rate = ~0UL; // 设置套接字最大传输速率为最大值
sk->sk_pacing_rate = ~0UL; // 设置套接字传输速率为最大值
WRITE_ONCE(sk->sk_pacing_shift, 10); // 设置套接字传输速率控制参数为10
sk->sk_incoming_cpu = -1; // 设置套接字的所属CPU为-1,表示未分配CPU
sk_rx_queue_clear(sk); // 清空套接字的接收队列,这将删除所有已接收但尚未处理的数据包
/*
* Before updating sk_refcnt, we must commit prior changes to memory
* (Documentation/RCU/rculist_nulls.rst for details)
*/
smp_wmb(); // 在多核系统中确保先前的写操作对于其他CPU可见
refcount_set(&sk->sk_refcnt, 1); // 设置套接字引用计数为1,表示有一个引用
atomic_set(&sk->sk_drops, 0); // 将套接字丢弃数据包计数器重置为0
}
linux内核代码-注释详解:sock_init_data
于 2023-07-06 14:41:30 首次发布