summaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/netns.h3
-rw-r--r--fs/nfsd/nfsctl.c3
-rw-r--r--fs/nfsd/nfssvc.c14
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
1246out_idmap_error: 1249out_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
348out: 351out:
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);
378out: 383out:
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}