diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/netns.h | 3 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 14 |
3 files changed, 17 insertions, 3 deletions
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 1c91391f4805..36358d435cb0 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
@@ -119,6 +119,9 @@ struct nfsd_net { | |||
119 | u32 clverifier_counter; | 119 | u32 clverifier_counter; |
120 | 120 | ||
121 | struct svc_serv *nfsd_serv; | 121 | struct svc_serv *nfsd_serv; |
122 | |||
123 | wait_queue_head_t ntf_wq; | ||
124 | atomic_t ntf_refcnt; | ||
122 | }; | 125 | }; |
123 | 126 | ||
124 | /* Simple check to find out if a given net was properly initialized */ | 127 | /* Simple check to find out if a given net was properly initialized */ |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 6493df6b1bd5..d107b4426f7e 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -1241,6 +1241,9 @@ static __net_init int nfsd_init_net(struct net *net) | |||
1241 | nn->nfsd4_grace = 90; | 1241 | nn->nfsd4_grace = 90; |
1242 | nn->clverifier_counter = prandom_u32(); | 1242 | nn->clverifier_counter = prandom_u32(); |
1243 | nn->clientid_counter = prandom_u32(); | 1243 | nn->clientid_counter = prandom_u32(); |
1244 | |||
1245 | atomic_set(&nn->ntf_refcnt, 0); | ||
1246 | init_waitqueue_head(&nn->ntf_wq); | ||
1244 | return 0; | 1247 | return 0; |
1245 | 1248 | ||
1246 | out_idmap_error: | 1249 | out_idmap_error: |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 33117d4ffce0..89cb484f1cfb 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -335,7 +335,8 @@ static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
335 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 335 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
336 | struct sockaddr_in sin; | 336 | struct sockaddr_in sin; |
337 | 337 | ||
338 | if (event != NETDEV_DOWN) | 338 | if ((event != NETDEV_DOWN) || |
339 | !atomic_inc_not_zero(&nn->ntf_refcnt)) | ||
339 | goto out; | 340 | goto out; |
340 | 341 | ||
341 | if (nn->nfsd_serv) { | 342 | if (nn->nfsd_serv) { |
@@ -344,6 +345,8 @@ static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
344 | sin.sin_addr.s_addr = ifa->ifa_local; | 345 | sin.sin_addr.s_addr = ifa->ifa_local; |
345 | svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin); | 346 | svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin); |
346 | } | 347 | } |
348 | atomic_dec(&nn->ntf_refcnt); | ||
349 | wake_up(&nn->ntf_wq); | ||
347 | 350 | ||
348 | out: | 351 | out: |
349 | return NOTIFY_DONE; | 352 | return NOTIFY_DONE; |
@@ -363,7 +366,8 @@ static int nfsd_inet6addr_event(struct notifier_block *this, | |||
363 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 366 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
364 | struct sockaddr_in6 sin6; | 367 | struct sockaddr_in6 sin6; |
365 | 368 | ||
366 | if (event != NETDEV_DOWN) | 369 | if ((event != NETDEV_DOWN) || |
370 | !atomic_inc_not_zero(&nn->ntf_refcnt)) | ||
367 | goto out; | 371 | goto out; |
368 | 372 | ||
369 | if (nn->nfsd_serv) { | 373 | if (nn->nfsd_serv) { |
@@ -374,7 +378,8 @@ static int nfsd_inet6addr_event(struct notifier_block *this, | |||
374 | sin6.sin6_scope_id = ifa->idev->dev->ifindex; | 378 | sin6.sin6_scope_id = ifa->idev->dev->ifindex; |
375 | svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6); | 379 | svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6); |
376 | } | 380 | } |
377 | 381 | atomic_dec(&nn->ntf_refcnt); | |
382 | wake_up(&nn->ntf_wq); | ||
378 | out: | 383 | out: |
379 | return NOTIFY_DONE; | 384 | return NOTIFY_DONE; |
380 | } | 385 | } |
@@ -391,6 +396,7 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | |||
391 | { | 396 | { |
392 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 397 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
393 | 398 | ||
399 | atomic_dec(&nn->ntf_refcnt); | ||
394 | /* check if the notifier still has clients */ | 400 | /* check if the notifier still has clients */ |
395 | if (atomic_dec_return(&nfsd_notifier_refcount) == 0) { | 401 | if (atomic_dec_return(&nfsd_notifier_refcount) == 0) { |
396 | unregister_inetaddr_notifier(&nfsd_inetaddr_notifier); | 402 | unregister_inetaddr_notifier(&nfsd_inetaddr_notifier); |
@@ -398,6 +404,7 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | |||
398 | unregister_inet6addr_notifier(&nfsd_inet6addr_notifier); | 404 | unregister_inet6addr_notifier(&nfsd_inet6addr_notifier); |
399 | #endif | 405 | #endif |
400 | } | 406 | } |
407 | wait_event(nn->ntf_wq, atomic_read(&nn->ntf_refcnt) == 0); | ||
401 | 408 | ||
402 | /* | 409 | /* |
403 | * write_ports can create the server without actually starting | 410 | * write_ports can create the server without actually starting |
@@ -517,6 +524,7 @@ int nfsd_create_serv(struct net *net) | |||
517 | register_inet6addr_notifier(&nfsd_inet6addr_notifier); | 524 | register_inet6addr_notifier(&nfsd_inet6addr_notifier); |
518 | #endif | 525 | #endif |
519 | } | 526 | } |
527 | atomic_inc(&nn->ntf_refcnt); | ||
520 | ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ | 528 | ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ |
521 | return 0; | 529 | return 0; |
522 | } | 530 | } |