From: NeilBrown <[EMAIL PROTECTED]>

When the last thread of nfsd exits, it shuts down all related sockets.
It currently uses svc_close_socket to do this, but that only is
immediately effective if the socket is not SK_BUSY.

If the socket is busy - i.e. if a request has arrived that has not yet
been processes - svc_close_socket is not effective and the shutdown
process spins.

So create a new svc_force_close_socket which removes the SK_BUSY flag
is set and then calls svc_close_socket.

Also change some open-codes loops in svc_destroy to use
list_for_each_entry_safe.

Signed-off-by: Neil Brown <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>


---
 include/linux/sunrpc/svcsock.h |    2 +-
 net/sunrpc/svc.c               |   23 ++++++++++-------------
 net/sunrpc/svcsock.c           |   16 +++++++++++++++-
 3 files changed, 26 insertions(+), 15 deletions(-)

--- linux-2.6.20.1.orig/include/linux/sunrpc/svcsock.h
+++ linux-2.6.20.1/include/linux/sunrpc/svcsock.h
@@ -63,7 +63,7 @@ struct svc_sock {
  * Function prototypes.
  */
 int            svc_makesock(struct svc_serv *, int, unsigned short);
-void           svc_close_socket(struct svc_sock *);
+void           svc_force_close_socket(struct svc_sock *);
 int            svc_recv(struct svc_rqst *, long);
 int            svc_send(struct svc_rqst *);
 void           svc_drop(struct svc_rqst *);
--- linux-2.6.20.1.orig/net/sunrpc/svc.c
+++ linux-2.6.20.1/net/sunrpc/svc.c
@@ -371,6 +371,7 @@ void
 svc_destroy(struct svc_serv *serv)
 {
        struct svc_sock *svsk;
+       struct svc_sock *tmp;
 
        dprintk("RPC: svc_destroy(%s, %d)\n",
                                serv->sv_program->pg_name,
@@ -386,22 +387,18 @@ svc_destroy(struct svc_serv *serv)
 
        del_timer_sync(&serv->sv_temptimer);
 
-       while (!list_empty(&serv->sv_tempsocks)) {
-               svsk = list_entry(serv->sv_tempsocks.next,
-                                 struct svc_sock,
-                                 sk_list);
-               svc_close_socket(svsk);
-       }
+       list_for_each_entry_safe(svsk, tmp, &serv->sv_tempsocks, sk_list)
+               svc_force_close_socket(svsk);
+
        if (serv->sv_shutdown)
                serv->sv_shutdown(serv);
 
-       while (!list_empty(&serv->sv_permsocks)) {
-               svsk = list_entry(serv->sv_permsocks.next,
-                                 struct svc_sock,
-                                 sk_list);
-               svc_close_socket(svsk);
-       }
-       
+       list_for_each_entry_safe(svsk, tmp, &serv->sv_permsocks, sk_list)
+               svc_force_close_socket(svsk);
+
+       BUG_ON(!list_empty(&serv->sv_permsocks));
+       BUG_ON(!list_empty(&serv->sv_tempsocks));
+
        cache_clean_deferred(serv);
 
        /* Unregister service with the portmapper */
--- linux-2.6.20.1.orig/net/sunrpc/svcsock.c
+++ linux-2.6.20.1/net/sunrpc/svcsock.c
@@ -80,6 +80,7 @@ static void           svc_delete_socket(struct sv
 static void            svc_udp_data_ready(struct sock *, int);
 static int             svc_udp_recvfrom(struct svc_rqst *);
 static int             svc_udp_sendto(struct svc_rqst *);
+static void            svc_close_socket(struct svc_sock *svsk);
 
 static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
 static int svc_deferred_recv(struct svc_rqst *rqstp);
@@ -1668,7 +1669,7 @@ svc_delete_socket(struct svc_sock *svsk)
        spin_unlock_bh(&serv->sv_lock);
 }
 
-void svc_close_socket(struct svc_sock *svsk)
+static void svc_close_socket(struct svc_sock *svsk)
 {
        set_bit(SK_CLOSE, &svsk->sk_flags);
        if (test_and_set_bit(SK_BUSY, &svsk->sk_flags))
@@ -1681,6 +1682,19 @@ void svc_close_socket(struct svc_sock *s
        svc_sock_put(svsk);
 }
 
+void svc_force_close_socket(struct svc_sock *svsk)
+{
+       set_bit(SK_CLOSE, &svsk->sk_flags);
+       if (test_bit(SK_BUSY, &svsk->sk_flags)) {
+               /* Waiting to be processed, but no threads left,
+                * So just remove it from the waiting list
+                */
+               list_del_init(&svsk->sk_ready);
+               clear_bit(SK_BUSY, &svsk->sk_flags);
+       }
+       svc_close_socket(svsk);
+}
+
 /*
  * Make a socket for nfsd and lockd
  */

--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to