/** * kvec_array_init() - initialize a IO vector segment * @new: IO vector to be initialized * @iov: base IO vector * @nr_segs: number of segments in base iov * @bytes: total iovec length so far for read * * Return: Number of IO segments
*/ staticunsignedint kvec_array_init(struct kvec *new, struct kvec *iov, unsignedint nr_segs, size_t bytes)
{
size_t base = 0;
while (bytes || !iov->iov_len) { int copy = min(bytes, iov->iov_len);
bytes -= copy;
base += copy; if (iov->iov_len == base) {
iov++;
nr_segs--;
base = 0;
}
}
/** * get_conn_iovec() - get connection iovec for reading from socket * @t: TCP transport instance * @nr_segs: number of segments in iov * * Return: return existing or newly allocate iovec
*/ staticstruct kvec *get_conn_iovec(struct tcp_transport *t, unsignedint nr_segs)
{ struct kvec *new_iov;
if (t->iov && nr_segs <= t->nr_iov) return t->iov;
/* not big enough -- allocate a new one and release the old */
new_iov = kmalloc_array(nr_segs, sizeof(*new_iov), KSMBD_DEFAULT_GFP); if (new_iov) {
kfree(t->iov);
t->iov = new_iov;
t->nr_iov = nr_segs;
} return new_iov;
}
/** * ksmbd_tcp_new_connection() - create a new tcp session on mount * @client_sk: socket associated with new connection * * whenever a new connection is requested, create a conn thread * (session thread) to handle new incoming smb requests from the connection * * Return: 0 on success, otherwise error
*/ staticint ksmbd_tcp_new_connection(struct socket *client_sk)
{ struct sockaddr *csin; int rc = 0; struct tcp_transport *t; struct task_struct *handler;
t = alloc_transport(client_sk); if (!t) {
sock_release(client_sk); return -ENOMEM;
}
csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn); if (kernel_getpeername(client_sk, csin) < 0) {
pr_err("client ip resolution failed\n");
rc = -EINVAL; goto out_error;
}
/** * ksmbd_kthread_fn() - listen to new SMB connections and callback server * @p: arguments to forker thread * * Return: 0 on success, error number otherwise
*/ staticint ksmbd_kthread_fn(void *p)
{ struct socket *client_sk = NULL; struct interface *iface = (struct interface *)p; struct ksmbd_conn *conn; int ret; unsignedint max_ip_conns;
while (!kthread_should_stop()) {
mutex_lock(&iface->sock_release_lock); if (!iface->ksmbd_socket) {
mutex_unlock(&iface->sock_release_lock); break;
}
ret = kernel_accept(iface->ksmbd_socket, &client_sk,
SOCK_NONBLOCK);
mutex_unlock(&iface->sock_release_lock); if (ret) { if (ret == -EAGAIN) /* check for new connections every 100 msecs */
schedule_timeout_interruptible(HZ / 10); continue;
}
if (!server_conf.max_ip_connections) goto skip_max_ip_conns_limit;
/* * Limits repeated connections from clients with the same IP.
*/
max_ip_conns = 0;
down_read(&conn_list_lock);
list_for_each_entry(conn, &conn_list, conns_list) { #if IS_ENABLED(CONFIG_IPV6) if (client_sk->sk->sk_family == AF_INET6) { if (memcmp(&client_sk->sk->sk_v6_daddr,
&conn->inet6_addr, 16) == 0)
max_ip_conns++;
} elseif (inet_sk(client_sk->sk)->inet_daddr ==
conn->inet_addr)
max_ip_conns++; #else if (inet_sk(client_sk->sk)->inet_daddr ==
conn->inet_addr)
max_ip_conns++; #endif if (server_conf.max_ip_connections <= max_ip_conns) {
ret = -EAGAIN; break;
}
}
up_read(&conn_list_lock); if (ret == -EAGAIN) { /* Per-IP limit hit: release the just-accepted socket. */
sock_release(client_sk); continue;
}
skip_max_ip_conns_limit: if (server_conf.max_connections &&
atomic_inc_return(&active_num_conn) >= server_conf.max_connections) {
pr_info_ratelimited("Limit the maximum number of connections(%u)\n",
atomic_read(&active_num_conn));
atomic_dec(&active_num_conn);
sock_release(client_sk); continue;
}
/** * ksmbd_tcp_run_kthread() - start forker thread * @iface: pointer to struct interface * * start forker thread(ksmbd/0) at module init time to listen * on port 445 for new SMB connection requests. It creates per connection * server threads(ksmbd/x) * * Return: 0 on success or error number
*/ staticint ksmbd_tcp_run_kthread(struct interface *iface)
{ int rc; struct task_struct *kthread;
/** * ksmbd_tcp_readv() - read data from socket in given iovec * @t: TCP transport instance * @iov_orig: base IO vector * @nr_segs: number of segments in base iov * @to_read: number of bytes to read from socket * @max_retries: maximum retry count * * Return: on success return number of bytes read from socket, * otherwise return error number
*/ staticint ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, unsignedint nr_segs, unsignedint to_read, int max_retries)
{ int length = 0; int total_read; unsignedint segs; struct msghdr ksmbd_msg; struct kvec *iov; struct ksmbd_conn *conn = KSMBD_TRANS(t)->conn;
iov = get_conn_iovec(t, nr_segs); if (!iov) return -ENOMEM;
/** * ksmbd_tcp_read() - read data from socket in given buffer * @t: TCP transport instance * @buf: buffer to store read data from socket * @to_read: number of bytes to read from socket * @max_retries: number of retries if reading from socket fails * * Return: on success return number of bytes read from socket, * otherwise return error number
*/ staticint ksmbd_tcp_read(struct ksmbd_transport *t, char *buf, unsignedint to_read, int max_retries)
{ struct kvec iov;
ret = sock_setsockopt(ksmbd_socket,
SOL_SOCKET,
SO_BINDTODEVICE,
KERNEL_SOCKPTR(iface->name),
strlen(iface->name)); if (ret != -ENODEV && ret < 0) {
pr_err("Failed to set SO_BINDTODEVICE: %d\n", ret); goto out_error;
}
if (ipv4)
ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin, sizeof(sin)); else
ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin6, sizeof(sin6)); if (ret) {
pr_err("Failed to bind socket: %d\n", ret); goto out_error;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.