|
@@ -74,6 +74,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
|
|
|
static int svc_deferred_recv(struct svc_rqst *rqstp);
|
|
|
static struct cache_deferred_req *svc_defer(struct cache_req *req);
|
|
|
|
|
|
+/* apparently the "standard" is that clients close
|
|
|
+ * idle connections after 5 minutes, servers after
|
|
|
+ * 6 minutes
|
|
|
+ * http://www.connectathon.org/talks96/nfstcp.pdf
|
|
|
+ */
|
|
|
+static int svc_conn_age_period = 6*60;
|
|
|
+
|
|
|
/*
|
|
|
* Queue up an idle server thread. Must have serv->sv_lock held.
|
|
|
* Note: this is really a stack rather than a queue, so that we only
|
|
@@ -1220,24 +1227,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
|
|
|
return -EINTR;
|
|
|
|
|
|
spin_lock_bh(&serv->sv_lock);
|
|
|
- if (!list_empty(&serv->sv_tempsocks)) {
|
|
|
- svsk = list_entry(serv->sv_tempsocks.next,
|
|
|
- struct svc_sock, sk_list);
|
|
|
- /* apparently the "standard" is that clients close
|
|
|
- * idle connections after 5 minutes, servers after
|
|
|
- * 6 minutes
|
|
|
- * http://www.connectathon.org/talks96/nfstcp.pdf
|
|
|
- */
|
|
|
- if (get_seconds() - svsk->sk_lastrecv < 6*60
|
|
|
- || test_bit(SK_BUSY, &svsk->sk_flags))
|
|
|
- svsk = NULL;
|
|
|
- }
|
|
|
- if (svsk) {
|
|
|
- set_bit(SK_BUSY, &svsk->sk_flags);
|
|
|
- set_bit(SK_CLOSE, &svsk->sk_flags);
|
|
|
- rqstp->rq_sock = svsk;
|
|
|
- svsk->sk_inuse++;
|
|
|
- } else if ((svsk = svc_sock_dequeue(serv)) != NULL) {
|
|
|
+ if ((svsk = svc_sock_dequeue(serv)) != NULL) {
|
|
|
rqstp->rq_sock = svsk;
|
|
|
svsk->sk_inuse++;
|
|
|
rqstp->rq_reserved = serv->sv_bufsz;
|
|
@@ -1282,13 +1272,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
|
|
|
return -EAGAIN;
|
|
|
}
|
|
|
svsk->sk_lastrecv = get_seconds();
|
|
|
- if (test_bit(SK_TEMP, &svsk->sk_flags)) {
|
|
|
- /* push active sockets to end of list */
|
|
|
- spin_lock_bh(&serv->sv_lock);
|
|
|
- if (!list_empty(&svsk->sk_list))
|
|
|
- list_move_tail(&svsk->sk_list, &serv->sv_tempsocks);
|
|
|
- spin_unlock_bh(&serv->sv_lock);
|
|
|
- }
|
|
|
+ clear_bit(SK_OLD, &svsk->sk_flags);
|
|
|
|
|
|
rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024;
|
|
|
rqstp->rq_chandle.defer = svc_defer;
|
|
@@ -1347,6 +1331,58 @@ svc_send(struct svc_rqst *rqstp)
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Timer function to close old temporary sockets, using
|
|
|
+ * a mark-and-sweep algorithm.
|
|
|
+ */
|
|
|
+static void
|
|
|
+svc_age_temp_sockets(unsigned long closure)
|
|
|
+{
|
|
|
+ struct svc_serv *serv = (struct svc_serv *)closure;
|
|
|
+ struct svc_sock *svsk;
|
|
|
+ struct list_head *le, *next;
|
|
|
+ LIST_HEAD(to_be_aged);
|
|
|
+
|
|
|
+ dprintk("svc_age_temp_sockets\n");
|
|
|
+
|
|
|
+ if (!spin_trylock_bh(&serv->sv_lock)) {
|
|
|
+ /* busy, try again 1 sec later */
|
|
|
+ dprintk("svc_age_temp_sockets: busy\n");
|
|
|
+ mod_timer(&serv->sv_temptimer, jiffies + HZ);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ list_for_each_safe(le, next, &serv->sv_tempsocks) {
|
|
|
+ svsk = list_entry(le, struct svc_sock, sk_list);
|
|
|
+
|
|
|
+ if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
|
|
|
+ continue;
|
|
|
+ if (svsk->sk_inuse || test_bit(SK_BUSY, &svsk->sk_flags))
|
|
|
+ continue;
|
|
|
+ svsk->sk_inuse++;
|
|
|
+ list_move(le, &to_be_aged);
|
|
|
+ set_bit(SK_CLOSE, &svsk->sk_flags);
|
|
|
+ set_bit(SK_DETACHED, &svsk->sk_flags);
|
|
|
+ }
|
|
|
+ spin_unlock_bh(&serv->sv_lock);
|
|
|
+
|
|
|
+ while (!list_empty(&to_be_aged)) {
|
|
|
+ le = to_be_aged.next;
|
|
|
+ /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */
|
|
|
+ list_del_init(le);
|
|
|
+ svsk = list_entry(le, struct svc_sock, sk_list);
|
|
|
+
|
|
|
+ dprintk("queuing svsk %p for closing, %lu seconds old\n",
|
|
|
+ svsk, get_seconds() - svsk->sk_lastrecv);
|
|
|
+
|
|
|
+ /* a thread will dequeue and close it soon */
|
|
|
+ svc_sock_enqueue(svsk);
|
|
|
+ svc_sock_put(svsk);
|
|
|
+ }
|
|
|
+
|
|
|
+ mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Initialize socket for RPC use and create svc_sock struct
|
|
|
* XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
|
|
@@ -1400,6 +1436,13 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
|
|
|
set_bit(SK_TEMP, &svsk->sk_flags);
|
|
|
list_add(&svsk->sk_list, &serv->sv_tempsocks);
|
|
|
serv->sv_tmpcnt++;
|
|
|
+ if (serv->sv_temptimer.function == NULL) {
|
|
|
+ /* setup timer to age temp sockets */
|
|
|
+ setup_timer(&serv->sv_temptimer, svc_age_temp_sockets,
|
|
|
+ (unsigned long)serv);
|
|
|
+ mod_timer(&serv->sv_temptimer,
|
|
|
+ jiffies + svc_conn_age_period * HZ);
|
|
|
+ }
|
|
|
} else {
|
|
|
clear_bit(SK_TEMP, &svsk->sk_flags);
|
|
|
list_add(&svsk->sk_list, &serv->sv_permsocks);
|
|
@@ -1513,7 +1556,8 @@ svc_delete_socket(struct svc_sock *svsk)
|
|
|
|
|
|
spin_lock_bh(&serv->sv_lock);
|
|
|
|
|
|
- list_del_init(&svsk->sk_list);
|
|
|
+ if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags))
|
|
|
+ list_del_init(&svsk->sk_list);
|
|
|
list_del_init(&svsk->sk_ready);
|
|
|
if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags))
|
|
|
if (test_bit(SK_TEMP, &svsk->sk_flags))
|