📄 socklnd_lib-linux.c
字号:
rc = ksocknal_connsock_addref(conn); if (rc != 0) { LASSERT (conn->ksnc_closing); *txmem = *rxmem = *nagle = 0; return (-ESHUTDOWN); } rc = libcfs_sock_getbuf(sock, txmem, rxmem); if (rc == 0) { len = sizeof(*nagle); set_fs(KERNEL_DS); rc = sock->ops->getsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)nagle, &len); set_fs(oldmm); } ksocknal_connsock_decref(conn); if (rc == 0) *nagle = !*nagle; else *txmem = *rxmem = *nagle = 0; return (rc);}intksocknal_lib_setup_sock (struct socket *sock){ mm_segment_t oldmm = get_fs (); int rc; int option; int keep_idle; int keep_intvl; int keep_count; int do_keepalive; struct linger linger; sock->sk->sk_allocation = GFP_NOFS; /* Ensure this socket aborts active sends immediately when we close * it. */ linger.l_onoff = 0; linger.l_linger = 0; set_fs (KERNEL_DS); rc = sock_setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof (linger)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set SO_LINGER: %d\n", rc); return (rc); } option = -1; set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_LINGER2, (char *)&option, sizeof (option)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set SO_LINGER2: %d\n", rc); return (rc); } if (!*ksocknal_tunables.ksnd_nagle) { option = 1; set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_NODELAY, (char *)&option, sizeof (option)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't disable nagle: %d\n", rc); return (rc); } } rc = libcfs_sock_setbuf(sock, *ksocknal_tunables.ksnd_tx_buffer_size, *ksocknal_tunables.ksnd_rx_buffer_size); if (rc != 0) { CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n", *ksocknal_tunables.ksnd_tx_buffer_size, *ksocknal_tunables.ksnd_rx_buffer_size, rc); return (rc); }/* TCP_BACKOFF_* sockopt tunables unsupported in stock kernels */#ifdef SOCKNAL_BACKOFF if (*ksocknal_tunables.ksnd_backoff_init > 0) { option = *ksocknal_tunables.ksnd_backoff_init; set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_BACKOFF_INIT, (char *)&option, sizeof (option)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set initial tcp backoff %d: %d\n", option, rc); return (rc); } } if (*ksocknal_tunables.ksnd_backoff_max > 0) { option = *ksocknal_tunables.ksnd_backoff_max; set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_BACKOFF_MAX, (char *)&option, sizeof (option)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set maximum tcp backoff %d: %d\n", option, rc); return (rc); } }#endif /* snapshot tunables */ keep_idle = *ksocknal_tunables.ksnd_keepalive_idle; keep_count = *ksocknal_tunables.ksnd_keepalive_count; keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl; do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); option = (do_keepalive ? 1 : 0); set_fs (KERNEL_DS); rc = sock_setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&option, sizeof (option)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); return (rc); } if (!do_keepalive) return (0); set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPIDLE, (char *)&keep_idle, sizeof (keep_idle)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set TCP_KEEPIDLE: %d\n", rc); return (rc); } set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPINTVL, (char *)&keep_intvl, sizeof (keep_intvl)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set TCP_KEEPINTVL: %d\n", rc); return (rc); } set_fs (KERNEL_DS); rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPCNT, (char *)&keep_count, sizeof (keep_count)); set_fs (oldmm); if (rc != 0) { CERROR ("Can't set TCP_KEEPCNT: %d\n", rc); return (rc); } return (0);}#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))struct tcp_opt *sock2tcp_opt(struct sock *sk){ return &(sk->tp_pinfo.af_tcp);}#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10))#define sock2tcp_opt(sk) tcp_sk(sk)#elsestruct tcp_opt *sock2tcp_opt(struct sock *sk){ struct tcp_sock *s = (struct tcp_sock *)sk; return &s->tcp;}#endifvoidksocknal_lib_push_conn (ksock_conn_t *conn){ struct sock *sk;#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)) struct tcp_opt *tp;#else struct tcp_sock *tp;#endif int nonagle; int val = 1; int rc; mm_segment_t oldmm; rc = ksocknal_connsock_addref(conn); if (rc != 0) /* being shut down */ return; sk = conn->ksnc_sock->sk; tp = sock2tcp_opt(sk); lock_sock (sk); nonagle = tp->nonagle; tp->nonagle = 1; release_sock (sk); oldmm = get_fs (); set_fs (KERNEL_DS); rc = sk->sk_prot->setsockopt (sk, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof (val)); LASSERT (rc == 0); set_fs (oldmm); lock_sock (sk); tp->nonagle = nonagle; release_sock (sk); ksocknal_connsock_decref(conn);}extern void ksocknal_read_callback (ksock_conn_t *conn);extern void ksocknal_write_callback (ksock_conn_t *conn);/* * socket call back in Linux */static voidksocknal_data_ready (struct sock *sk, int n){ ksock_conn_t *conn; ENTRY; /* interleave correctly with closing sockets... */ LASSERT(!in_irq()); read_lock (&ksocknal_data.ksnd_global_lock); conn = sk->sk_user_data; if (conn == NULL) { /* raced with ksocknal_terminate_conn */ LASSERT (sk->sk_data_ready != &ksocknal_data_ready); sk->sk_data_ready (sk, n); } else ksocknal_read_callback(conn); read_unlock (&ksocknal_data.ksnd_global_lock); EXIT;}static voidksocknal_write_space (struct sock *sk){ ksock_conn_t *conn; int wspace; int min_wpace; /* interleave correctly with closing sockets... */ LASSERT(!in_irq()); read_lock (&ksocknal_data.ksnd_global_lock); conn = sk->sk_user_data; wspace = SOCKNAL_WSPACE(sk); min_wpace = SOCKNAL_MIN_WSPACE(sk); CDEBUG(D_NET, "sk %p wspace %d low water %d conn %p%s%s%s\n", sk, wspace, min_wpace, conn, (conn == NULL) ? "" : (conn->ksnc_tx_ready ? " ready" : " blocked"), (conn == NULL) ? "" : (conn->ksnc_tx_scheduled ? " scheduled" : " idle"), (conn == NULL) ? "" : (list_empty (&conn->ksnc_tx_queue) ? " empty" : " queued")); if (conn == NULL) { /* raced with ksocknal_terminate_conn */ LASSERT (sk->sk_write_space != &ksocknal_write_space); sk->sk_write_space (sk); read_unlock (&ksocknal_data.ksnd_global_lock); return; } if (wspace >= min_wpace) { /* got enough space */ ksocknal_write_callback(conn); /* Clear SOCK_NOSPACE _after_ ksocknal_write_callback so the * ENOMEM check in ksocknal_transmit is race-free (think about * it). */ clear_bit (SOCK_NOSPACE, &sk->sk_socket->flags); } read_unlock (&ksocknal_data.ksnd_global_lock);}voidksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn){ conn->ksnc_saved_data_ready = sock->sk->sk_data_ready; conn->ksnc_saved_write_space = sock->sk->sk_write_space;}voidksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn){ sock->sk->sk_user_data = conn; sock->sk->sk_data_ready = ksocknal_data_ready; sock->sk->sk_write_space = ksocknal_write_space; return;}voidksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn){ /* Remove conn's network callbacks. * NB I _have_ to restore the callback, rather than storing a noop, * since the socket could survive past this module being unloaded!! */ sock->sk->sk_data_ready = conn->ksnc_saved_data_ready; sock->sk->sk_write_space = conn->ksnc_saved_write_space; /* A callback could be in progress already; they hold a read lock * on ksnd_global_lock (to serialise with me) and NOOP if * sk_user_data is NULL. */ sock->sk->sk_user_data = NULL; return ;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -