mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-07 03:00:44 +00:00
scoutfs: have server track connected clients
This extends the notify up and down calls to let the server keep track of connected clients. It adds the notion of per-connection info that is allocated for each connection. It's passed to the notification callbacks so that callers can have per-client storage without having to manage allocations in the callbacks. It adds the node_id argument to the notification callbacks to indicate if the call is for the listening socket itself or an accepted client connection on that listening socket. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -361,7 +361,8 @@ out:
|
||||
* out and fails.
|
||||
*/
|
||||
static void client_notify_down(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn)
|
||||
struct scoutfs_net_connection *conn, void *info,
|
||||
u64 node_id)
|
||||
{
|
||||
struct client_info *client = SCOUTFS_SB(sb)->client_info;
|
||||
|
||||
@@ -404,7 +405,7 @@ int scoutfs_client_setup(struct super_block *sb)
|
||||
scoutfs_client_connect_worker);
|
||||
|
||||
/* client doesn't process any incoming requests yet */
|
||||
client->conn = scoutfs_net_alloc_conn(sb, NULL, client_notify_down,
|
||||
client->conn = scoutfs_net_alloc_conn(sb, NULL, client_notify_down, 0,
|
||||
NULL, "client");
|
||||
if (!client->conn) {
|
||||
ret = -ENOMEM;
|
||||
|
||||
@@ -73,6 +73,7 @@ struct scoutfs_net_connection {
|
||||
struct super_block *sb;
|
||||
scoutfs_net_notify_t notify_up;
|
||||
scoutfs_net_notify_t notify_down;
|
||||
size_t info_size;
|
||||
scoutfs_net_request_t *req_funcs;
|
||||
|
||||
spinlock_t lock;
|
||||
@@ -108,6 +109,8 @@ struct scoutfs_net_connection {
|
||||
/* message_recv proc_work also executes in the conn workq */
|
||||
|
||||
struct scoutfs_tseq_entry tseq_entry;
|
||||
|
||||
u8 info[0] __aligned(sizeof(u64));
|
||||
};
|
||||
|
||||
/* listening and their accepting sockets have a fixed locking order */
|
||||
@@ -418,7 +421,7 @@ static void saw_valid_greeting(struct scoutfs_net_connection *conn, u64 node_id)
|
||||
conn->valid_greeting = 1;
|
||||
conn->node_id = node_id;
|
||||
if (conn->notify_up)
|
||||
conn->notify_up(sb, conn);
|
||||
conn->notify_up(sb, conn, conn->info, node_id);
|
||||
list_splice_tail_init(&conn->resend_queue, &conn->send_queue);
|
||||
queue_work(conn->workq, &conn->send_work);
|
||||
|
||||
@@ -947,7 +950,9 @@ static void scoutfs_net_listen_worker(struct work_struct *work)
|
||||
break;
|
||||
|
||||
/* inherit accepted request funcs from listening conn */
|
||||
acc_conn = scoutfs_net_alloc_conn(sb, NULL, NULL,
|
||||
acc_conn = scoutfs_net_alloc_conn(sb, conn->notify_up,
|
||||
conn->notify_down,
|
||||
conn->info_size,
|
||||
conn->req_funcs, "accepted");
|
||||
if (!acc_conn) {
|
||||
sock_release(acc_sock);
|
||||
@@ -1133,7 +1138,7 @@ static void scoutfs_net_shutdown_worker(struct work_struct *work)
|
||||
|
||||
/* tell the caller that the connection is down */
|
||||
if (conn->notify_down)
|
||||
conn->notify_down(sb, conn);
|
||||
conn->notify_down(sb, conn, conn->info, conn->node_id);
|
||||
|
||||
/* accepted conns are destroyed */
|
||||
if (conn->listening_conn) {
|
||||
@@ -1147,16 +1152,29 @@ static void scoutfs_net_shutdown_worker(struct work_struct *work)
|
||||
trace_scoutfs_net_shutdown_work_exit(sb, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepted connections inherit the callbacks from their listening
|
||||
* connection.
|
||||
*
|
||||
* notify_up is called once a valid greeting is received. node_id is
|
||||
* non-zero on accepted sockets once they've seen a valid greeting.
|
||||
* Connected and listening connections have a node_id of 0.
|
||||
*
|
||||
* notify_down is always called as connections are shut down. It can be
|
||||
* called without notify_up ever being called. The node_id is only
|
||||
* non-zero for accepted connections.
|
||||
*/
|
||||
struct scoutfs_net_connection *
|
||||
scoutfs_net_alloc_conn(struct super_block *sb,
|
||||
scoutfs_net_notify_t notify_up,
|
||||
scoutfs_net_notify_t notify_down,
|
||||
scoutfs_net_notify_t notify_down, size_t info_size,
|
||||
scoutfs_net_request_t *req_funcs, char *name_suffix)
|
||||
{
|
||||
struct net_info *ninf = SCOUTFS_SB(sb)->net_info;
|
||||
struct scoutfs_net_connection *conn;
|
||||
|
||||
conn = kzalloc(sizeof(struct scoutfs_net_connection), GFP_NOFS);
|
||||
conn = kzalloc(offsetof(struct scoutfs_net_connection,
|
||||
info[info_size]), GFP_NOFS);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
@@ -1171,6 +1189,7 @@ scoutfs_net_alloc_conn(struct super_block *sb,
|
||||
conn->sb = sb;
|
||||
conn->notify_up = notify_up;
|
||||
conn->notify_down = notify_down;
|
||||
conn->info_size = info_size;
|
||||
conn->req_funcs = req_funcs;
|
||||
spin_lock_init(&conn->lock);
|
||||
init_waitqueue_head(&conn->waitq);
|
||||
|
||||
@@ -20,12 +20,13 @@ typedef int (*scoutfs_net_response_t)(struct super_block *sb,
|
||||
int error, void *data);
|
||||
|
||||
typedef void (*scoutfs_net_notify_t)(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn);
|
||||
struct scoutfs_net_connection *conn,
|
||||
void *info, u64 node_id);
|
||||
|
||||
struct scoutfs_net_connection *
|
||||
scoutfs_net_alloc_conn(struct super_block *sb,
|
||||
scoutfs_net_notify_t notify_up,
|
||||
scoutfs_net_notify_t notify_down,
|
||||
scoutfs_net_notify_t notify_down, size_t info_size,
|
||||
scoutfs_net_request_t *req_funcs, char *name_suffix);
|
||||
int scoutfs_net_connect(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn,
|
||||
|
||||
@@ -73,11 +73,21 @@ struct server_info {
|
||||
/* server tracks pending frees to be applied during commit */
|
||||
struct rw_semaphore alloc_rwsem;
|
||||
struct list_head pending_frees;
|
||||
|
||||
struct list_head clients;
|
||||
};
|
||||
|
||||
#define DECLARE_SERVER_INFO(sb, name) \
|
||||
struct server_info *name = SCOUTFS_SB(sb)->server_info
|
||||
|
||||
/*
|
||||
* The server tracks each connected client.
|
||||
*/
|
||||
struct server_client_info {
|
||||
u64 node_id;
|
||||
struct list_head head;
|
||||
};
|
||||
|
||||
struct commit_waiter {
|
||||
struct completion comp;
|
||||
struct llist_node node;
|
||||
@@ -1153,13 +1163,37 @@ static scoutfs_net_request_t server_req_funcs[] = {
|
||||
[SCOUTFS_NET_CMD_STATFS] = server_statfs,
|
||||
};
|
||||
|
||||
static void server_notify_down(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn)
|
||||
static void server_notify_up(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn,
|
||||
void *info, u64 node_id)
|
||||
{
|
||||
struct server_client_info *sci = info;
|
||||
DECLARE_SERVER_INFO(sb, server);
|
||||
|
||||
shutdown_server(server);
|
||||
if (node_id != 0) {
|
||||
sci->node_id = node_id;
|
||||
spin_lock(&server->lock);
|
||||
list_add_tail(&sci->head, &server->clients);
|
||||
spin_unlock(&server->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void server_notify_down(struct super_block *sb,
|
||||
struct scoutfs_net_connection *conn,
|
||||
void *info, u64 node_id)
|
||||
{
|
||||
struct server_client_info *sci = info;
|
||||
DECLARE_SERVER_INFO(sb, server);
|
||||
|
||||
if (node_id != 0) {
|
||||
spin_lock(&server->lock);
|
||||
list_del(&sci->head);
|
||||
spin_unlock(&server->lock);
|
||||
} else {
|
||||
shutdown_server(server);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This work is always running or has a delayed timer set while a super
|
||||
* is mounted. It tries to grab the lock to become the server. If it
|
||||
@@ -1193,7 +1227,8 @@ static void scoutfs_server_worker(struct work_struct *work)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
conn = scoutfs_net_alloc_conn(sb, NULL, server_notify_down,
|
||||
conn = scoutfs_net_alloc_conn(sb, server_notify_up, server_notify_down,
|
||||
sizeof(struct server_client_info),
|
||||
server_req_funcs, "server");
|
||||
if (!conn) {
|
||||
ret = -ENOMEM;
|
||||
@@ -1302,6 +1337,7 @@ int scoutfs_server_setup(struct super_block *sb)
|
||||
INIT_LIST_HEAD(&server->pending_seqs);
|
||||
init_rwsem(&server->alloc_rwsem);
|
||||
INIT_LIST_HEAD(&server->pending_frees);
|
||||
INIT_LIST_HEAD(&server->clients);
|
||||
|
||||
server->wq = alloc_workqueue("scoutfs_server", WQ_NON_REENTRANT, 0);
|
||||
if (!server->wq) {
|
||||
|
||||
Reference in New Issue
Block a user