Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] knfsd: fix recently introduced problem with shutting down a busy NFS server

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 <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

NeilBrown and committed by
Linus Torvalds
cda1fd4a 5a05ed73

+25 -14
+1 -1
include/linux/sunrpc/svcsock.h
··· 66 66 * Function prototypes. 67 67 */ 68 68 int svc_makesock(struct svc_serv *, int, unsigned short, int flags); 69 - void svc_close_socket(struct svc_sock *); 69 + void svc_force_close_socket(struct svc_sock *); 70 70 int svc_recv(struct svc_rqst *, long); 71 71 int svc_send(struct svc_rqst *); 72 72 void svc_drop(struct svc_rqst *);
+9 -12
net/sunrpc/svc.c
··· 367 367 svc_destroy(struct svc_serv *serv) 368 368 { 369 369 struct svc_sock *svsk; 370 + struct svc_sock *tmp; 370 371 371 372 dprintk("svc: svc_destroy(%s, %d)\n", 372 373 serv->sv_program->pg_name, ··· 383 382 384 383 del_timer_sync(&serv->sv_temptimer); 385 384 386 - while (!list_empty(&serv->sv_tempsocks)) { 387 - svsk = list_entry(serv->sv_tempsocks.next, 388 - struct svc_sock, 389 - sk_list); 390 - svc_close_socket(svsk); 391 - } 385 + list_for_each_entry_safe(svsk, tmp, &serv->sv_tempsocks, sk_list) 386 + svc_force_close_socket(svsk); 387 + 392 388 if (serv->sv_shutdown) 393 389 serv->sv_shutdown(serv); 394 390 395 - while (!list_empty(&serv->sv_permsocks)) { 396 - svsk = list_entry(serv->sv_permsocks.next, 397 - struct svc_sock, 398 - sk_list); 399 - svc_close_socket(svsk); 400 - } 391 + list_for_each_entry_safe(svsk, tmp, &serv->sv_permsocks, sk_list) 392 + svc_force_close_socket(svsk); 393 + 394 + BUG_ON(!list_empty(&serv->sv_permsocks)); 395 + BUG_ON(!list_empty(&serv->sv_tempsocks)); 401 396 402 397 cache_clean_deferred(serv); 403 398
+15 -1
net/sunrpc/svcsock.c
··· 82 82 static void svc_udp_data_ready(struct sock *, int); 83 83 static int svc_udp_recvfrom(struct svc_rqst *); 84 84 static int svc_udp_sendto(struct svc_rqst *); 85 + static void svc_close_socket(struct svc_sock *svsk); 85 86 86 87 static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk); 87 88 static int svc_deferred_recv(struct svc_rqst *rqstp); ··· 1788 1787 spin_unlock_bh(&serv->sv_lock); 1789 1788 } 1790 1789 1791 - void svc_close_socket(struct svc_sock *svsk) 1790 + static void svc_close_socket(struct svc_sock *svsk) 1792 1791 { 1793 1792 set_bit(SK_CLOSE, &svsk->sk_flags); 1794 1793 if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) ··· 1799 1798 svc_delete_socket(svsk); 1800 1799 clear_bit(SK_BUSY, &svsk->sk_flags); 1801 1800 svc_sock_put(svsk); 1801 + } 1802 + 1803 + void svc_force_close_socket(struct svc_sock *svsk) 1804 + { 1805 + set_bit(SK_CLOSE, &svsk->sk_flags); 1806 + if (test_bit(SK_BUSY, &svsk->sk_flags)) { 1807 + /* Waiting to be processed, but no threads left, 1808 + * So just remove it from the waiting list 1809 + */ 1810 + list_del_init(&svsk->sk_ready); 1811 + clear_bit(SK_BUSY, &svsk->sk_flags); 1812 + } 1813 + svc_close_socket(svsk); 1802 1814 } 1803 1815 1804 1816 /**