Message ID | 20210213175239.28571-1-ap420073@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | mld: change context from atomic to sleepable | expand |
Context | Check | Description |
---|---|---|
netdev/cover_letter | success | Link |
netdev/fixes_present | success | Link |
netdev/patch_count | success | Link |
netdev/tree_selection | success | Clearly marked for net-next |
netdev/subject_prefix | success | Link |
netdev/cc_maintainers | success | CCed 5 of 5 maintainers |
netdev/source_inline | success | Was 0 now: 0 |
netdev/verify_signedoff | success | Link |
netdev/module_param | success | Was 0 now: 0 |
netdev/build_32bit | fail | Errors and warnings before: 2949 this patch: 2950 |
netdev/kdoc | success | Errors and warnings before: 0 this patch: 0 |
netdev/verify_fixes | success | Link |
netdev/checkpatch | warning | WARNING: line length of 81 exceeds 80 columns |
netdev/build_allmodconfig_warn | fail | Errors and warnings before: 3368 this patch: 3369 |
netdev/header_inline | success | Link |
netdev/stable | success | Stable not CCed |
Hi Taehee, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on net-next/master] url: https://github.com/0day-ci/linux/commits/Taehee-Yoo/mld-change-context-from-atomic-to-sleepable/20210214-015930 base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 3c5a2fd042d0bfac71a2dfb99515723d318df47b config: x86_64-randconfig-s022-20210214 (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-215-g0fb77bb6-dirty # https://github.com/0day-ci/linux/commit/5a21fa32b1401aa428cd0249ee5b02ddb12cff60 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Taehee-Yoo/mld-change-context-from-atomic-to-sleepable/20210214-015930 git checkout 5a21fa32b1401aa428cd0249ee5b02ddb12cff60 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> "sparse warnings: (new ones prefixed by >>)" >> net/ipv6/mcast.c:430:17: sparse: sparse: incompatible types in comparison expression (different address spaces): >> net/ipv6/mcast.c:430:17: sparse: struct ip6_sf_socklist [noderef] __rcu * >> net/ipv6/mcast.c:430:17: sparse: struct ip6_sf_socklist * net/ipv6/mcast.c: note: in included file: include/net/mld.h:32:43: sparse: sparse: array of flexible structures net/ipv6/mcast.c:257:25: sparse: sparse: context imbalance in 'ip6_mc_find_dev_rcu' - different lock contexts for basic block net/ipv6/mcast.c:447:9: sparse: sparse: context imbalance in 'ip6_mc_source' - unexpected unlock net/ipv6/mcast.c:536:9: sparse: sparse: context imbalance in 'ip6_mc_msfilter' - unexpected unlock net/ipv6/mcast.c:583:21: sparse: sparse: context imbalance in 'ip6_mc_msfget' - unexpected unlock net/ipv6/mcast.c:2724:25: sparse: sparse: context imbalance in 'igmp6_mc_get_next' - unexpected unlock net/ipv6/mcast.c:2746:9: sparse: sparse: context imbalance in 'igmp6_mc_get_idx' - wrong count at exit net/ipv6/mcast.c:2773:9: sparse: sparse: context imbalance in 'igmp6_mc_seq_stop' - unexpected unlock net/ipv6/mcast.c:2845:31: sparse: sparse: context imbalance in 'igmp6_mcf_get_next' - unexpected unlock net/ipv6/mcast.c:2877:9: sparse: sparse: context imbalance in 'igmp6_mcf_get_idx' - wrong count at exit net/ipv6/mcast.c:2894:9: sparse: sparse: context imbalance in 'igmp6_mcf_seq_next' - wrong count at exit net/ipv6/mcast.c:2907:17: sparse: sparse: context imbalance in 'igmp6_mcf_seq_stop' - unexpected unlock vim +430 net/ipv6/mcast.c 325 326 int ip6_mc_source(int add, int omode, struct sock *sk, 327 struct group_source_req *pgsr) 328 { 329 struct in6_addr *source, *group; 330 struct ipv6_mc_socklist *pmc; 331 struct inet6_dev *idev; 332 struct ipv6_pinfo *inet6 = inet6_sk(sk); 333 struct ip6_sf_socklist *psl; 334 struct net *net = sock_net(sk); 335 int i, j, rv; 336 int leavegroup = 0; 337 int err; 338 339 source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr; 340 group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr; 341 342 if (!ipv6_addr_is_multicast(group)) 343 return -EINVAL; 344 345 rcu_read_lock(); 346 idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface); 347 if (!idev) { 348 rcu_read_unlock(); 349 return -ENODEV; 350 } 351 352 err = -EADDRNOTAVAIL; 353 354 for_each_pmc_rcu(inet6, pmc) { 355 if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) 356 continue; 357 if (ipv6_addr_equal(&pmc->addr, group)) 358 break; 359 } 360 if (!pmc) { /* must have a prior join */ 361 err = -EINVAL; 362 goto done; 363 } 364 /* if a source filter was set, must be the same mode as before */ 365 if (rcu_access_pointer(pmc->sflist)) { 366 if (pmc->sfmode != omode) { 367 err = -EINVAL; 368 goto done; 369 } 370 } else if (pmc->sfmode != omode) { 371 /* allow mode switches for empty-set filters */ 372 ip6_mc_add_src(idev, group, omode, 0, NULL, 0); 373 ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); 374 pmc->sfmode = omode; 375 } 376 377 psl = rtnl_dereference(pmc->sflist); 378 if (!add) { 379 if (!psl) 380 goto done; /* err = -EADDRNOTAVAIL */ 381 rv = !0; 382 for (i = 0; i < psl->sl_count; i++) { 383 rv = !ipv6_addr_equal(&psl->sl_addr[i], source); 384 if (rv == 0) 385 break; 386 } 387 if (rv) /* source not found */ 388 goto done; /* err = -EADDRNOTAVAIL */ 389 390 /* special case - (INCLUDE, empty) == LEAVE_GROUP */ 391 if (psl->sl_count == 1 && omode == MCAST_INCLUDE) { 392 leavegroup = 1; 393 goto done; 394 } 395 396 /* update the interface filter */ 397 ip6_mc_del_src(idev, group, omode, 1, source, 1); 398 399 for (j = i+1; j < psl->sl_count; j++) 400 psl->sl_addr[j-1] = psl->sl_addr[j]; 401 psl->sl_count--; 402 err = 0; 403 goto done; 404 } 405 /* else, add a new source to the filter */ 406 407 if (psl && psl->sl_count >= sysctl_mld_max_msf) { 408 err = -ENOBUFS; 409 goto done; 410 } 411 if (!psl || psl->sl_count == psl->sl_max) { 412 struct ip6_sf_socklist *newpsl; 413 int count = IP6_SFBLOCK; 414 415 if (psl) 416 count += psl->sl_max; 417 newpsl = sock_kmalloc(sk, IP6_SFLSIZE(count), GFP_ATOMIC); 418 if (!newpsl) { 419 err = -ENOBUFS; 420 goto done; 421 } 422 newpsl->sl_max = count; 423 newpsl->sl_count = count - IP6_SFBLOCK; 424 if (psl) { 425 for (i = 0; i < psl->sl_count; i++) 426 newpsl->sl_addr[i] = psl->sl_addr[i]; 427 atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); 428 kfree_rcu(psl, rcu); 429 } > 430 rcu_assign_pointer(psl, newpsl); 431 rcu_assign_pointer(pmc->sflist, psl); 432 } 433 rv = 1; /* > 0 for insert logic below if sl_count is 0 */ 434 for (i = 0; i < psl->sl_count; i++) { 435 rv = !ipv6_addr_equal(&psl->sl_addr[i], source); 436 if (rv == 0) /* There is an error in the address. */ 437 goto done; 438 } 439 for (j = psl->sl_count-1; j >= i; j--) 440 psl->sl_addr[j+1] = psl->sl_addr[j]; 441 psl->sl_addr[i] = *source; 442 psl->sl_count++; 443 err = 0; 444 /* update the interface list */ 445 ip6_mc_add_src(idev, group, omode, 1, source, 1); 446 done: 447 read_unlock_bh(&idev->lock); 448 rcu_read_unlock(); 449 if (leavegroup) 450 err = ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); 451 return err; 452 } 453 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 21. 2. 14. 오전 4:41, kernel test robot wrote: > Hi Taehee, > > Thank you for the patch! Perhaps something to improve: > > [auto build test WARNING on net-next/master] > > url: https://github.com/0day-ci/linux/commits/Taehee-Yoo/mld-change-context-from-atomic-to-sleepable/20210214-015930 > base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 3c5a2fd042d0bfac71a2dfb99515723d318df47b > config: x86_64-randconfig-s022-20210214 (attached as .config) > compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 > reproduce: > # apt-get install sparse > # sparse version: v0.6.3-215-g0fb77bb6-dirty > # https://github.com/0day-ci/linux/commit/5a21fa32b1401aa428cd0249ee5b02ddb12cff60 > git remote add linux-review https://github.com/0day-ci/linux > git fetch --no-tags linux-review Taehee-Yoo/mld-change-context-from-atomic-to-sleepable/20210214-015930 > git checkout 5a21fa32b1401aa428cd0249ee5b02ddb12cff60 > # save the attached .config to linux build tree > make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64 > > If you fix the issue, kindly add following tag as appropriate > Reported-by: kernel test robot <lkp@intel.com> > > > "sparse warnings: (new ones prefixed by >>)" >>> net/ipv6/mcast.c:430:17: sparse: sparse: incompatible types in comparison expression (different address spaces): >>> net/ipv6/mcast.c:430:17: sparse: struct ip6_sf_socklist [noderef] __rcu * >>> net/ipv6/mcast.c:430:17: sparse: struct ip6_sf_socklist * > net/ipv6/mcast.c: note: in included file: > include/net/mld.h:32:43: sparse: sparse: array of flexible structures > net/ipv6/mcast.c:257:25: sparse: sparse: context imbalance in 'ip6_mc_find_dev_rcu' - different lock contexts for basic block > net/ipv6/mcast.c:447:9: sparse: sparse: context imbalance in 'ip6_mc_source' - unexpected unlock > net/ipv6/mcast.c:536:9: sparse: sparse: context imbalance in 'ip6_mc_msfilter' - unexpected unlock > net/ipv6/mcast.c:583:21: sparse: sparse: context imbalance in 'ip6_mc_msfget' - unexpected unlock > net/ipv6/mcast.c:2724:25: sparse: sparse: context imbalance in 'igmp6_mc_get_next' - unexpected unlock > net/ipv6/mcast.c:2746:9: sparse: sparse: context imbalance in 'igmp6_mc_get_idx' - wrong count at exit > net/ipv6/mcast.c:2773:9: sparse: sparse: context imbalance in 'igmp6_mc_seq_stop' - unexpected unlock > net/ipv6/mcast.c:2845:31: sparse: sparse: context imbalance in 'igmp6_mcf_get_next' - unexpected unlock > net/ipv6/mcast.c:2877:9: sparse: sparse: context imbalance in 'igmp6_mcf_get_idx' - wrong count at exit > net/ipv6/mcast.c:2894:9: sparse: sparse: context imbalance in 'igmp6_mcf_seq_next' - wrong count at exit > net/ipv6/mcast.c:2907:17: sparse: sparse: context imbalance in 'igmp6_mcf_seq_stop' - unexpected unlock > > vim +430 net/ipv6/mcast.c > > 325 > 326 int ip6_mc_source(int add, int omode, struct sock *sk, > 327 struct group_source_req *pgsr) > 328 { > 329 struct in6_addr *source, *group; > 330 struct ipv6_mc_socklist *pmc; > 331 struct inet6_dev *idev; > 332 struct ipv6_pinfo *inet6 = inet6_sk(sk); > 333 struct ip6_sf_socklist *psl; > 334 struct net *net = sock_net(sk); > 335 int i, j, rv; > 336 int leavegroup = 0; > 337 int err; > 338 > 339 source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr; > 340 group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr; > 341 > 342 if (!ipv6_addr_is_multicast(group)) > 343 return -EINVAL; > 344 > 345 rcu_read_lock(); > 346 idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface); > 347 if (!idev) { > 348 rcu_read_unlock(); > 349 return -ENODEV; > 350 } > 351 > 352 err = -EADDRNOTAVAIL; > 353 > 354 for_each_pmc_rcu(inet6, pmc) { > 355 if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) > 356 continue; > 357 if (ipv6_addr_equal(&pmc->addr, group)) > 358 break; > 359 } > 360 if (!pmc) { /* must have a prior join */ > 361 err = -EINVAL; > 362 goto done; > 363 } > 364 /* if a source filter was set, must be the same mode as before */ > 365 if (rcu_access_pointer(pmc->sflist)) { > 366 if (pmc->sfmode != omode) { > 367 err = -EINVAL; > 368 goto done; > 369 } > 370 } else if (pmc->sfmode != omode) { > 371 /* allow mode switches for empty-set filters */ > 372 ip6_mc_add_src(idev, group, omode, 0, NULL, 0); > 373 ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); > 374 pmc->sfmode = omode; > 375 } > 376 > 377 psl = rtnl_dereference(pmc->sflist); > 378 if (!add) { > 379 if (!psl) > 380 goto done; /* err = -EADDRNOTAVAIL */ > 381 rv = !0; > 382 for (i = 0; i < psl->sl_count; i++) { > 383 rv = !ipv6_addr_equal(&psl->sl_addr[i], source); > 384 if (rv == 0) > 385 break; > 386 } > 387 if (rv) /* source not found */ > 388 goto done; /* err = -EADDRNOTAVAIL */ > 389 > 390 /* special case - (INCLUDE, empty) == LEAVE_GROUP */ > 391 if (psl->sl_count == 1 && omode == MCAST_INCLUDE) { > 392 leavegroup = 1; > 393 goto done; > 394 } > 395 > 396 /* update the interface filter */ > 397 ip6_mc_del_src(idev, group, omode, 1, source, 1); > 398 > 399 for (j = i+1; j < psl->sl_count; j++) > 400 psl->sl_addr[j-1] = psl->sl_addr[j]; > 401 psl->sl_count--; > 402 err = 0; > 403 goto done; > 404 } > 405 /* else, add a new source to the filter */ > 406 > 407 if (psl && psl->sl_count >= sysctl_mld_max_msf) { > 408 err = -ENOBUFS; > 409 goto done; > 410 } > 411 if (!psl || psl->sl_count == psl->sl_max) { > 412 struct ip6_sf_socklist *newpsl; > 413 int count = IP6_SFBLOCK; > 414 > 415 if (psl) > 416 count += psl->sl_max; > 417 newpsl = sock_kmalloc(sk, IP6_SFLSIZE(count), GFP_ATOMIC); > 418 if (!newpsl) { > 419 err = -ENOBUFS; > 420 goto done; > 421 } > 422 newpsl->sl_max = count; > 423 newpsl->sl_count = count - IP6_SFBLOCK; > 424 if (psl) { > 425 for (i = 0; i < psl->sl_count; i++) > 426 newpsl->sl_addr[i] = psl->sl_addr[i]; > 427 atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); > 428 kfree_rcu(psl, rcu); > 429 } > > 430 rcu_assign_pointer(psl, newpsl); > 431 rcu_assign_pointer(pmc->sflist, psl); > 432 } > 433 rv = 1; /* > 0 for insert logic below if sl_count is 0 */ > 434 for (i = 0; i < psl->sl_count; i++) { > 435 rv = !ipv6_addr_equal(&psl->sl_addr[i], source); > 436 if (rv == 0) /* There is an error in the address. */ > 437 goto done; > 438 } > 439 for (j = psl->sl_count-1; j >= i; j--) > 440 psl->sl_addr[j+1] = psl->sl_addr[j]; > 441 psl->sl_addr[i] = *source; > 442 psl->sl_count++; > 443 err = 0; > 444 /* update the interface list */ > 445 ip6_mc_add_src(idev, group, omode, 1, source, 1); > 446 done: > 447 read_unlock_bh(&idev->lock); > 448 rcu_read_unlock(); > 449 if (leavegroup) > 450 err = ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); > 451 return err; > 452 } > 453 > > --- > 0-DAY CI Kernel Test Service, Intel Corporation > https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org > I will add __rcu annotation in a v3 patch to avoid sparse warning. Thanks!
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 4d9855be644c..d8507bef0a0c 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -78,6 +78,7 @@ struct inet6_ifaddr { struct ip6_sf_socklist { unsigned int sl_max; unsigned int sl_count; + struct rcu_head rcu; struct in6_addr sl_addr[]; }; @@ -91,8 +92,7 @@ struct ipv6_mc_socklist { int ifindex; unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */ struct ipv6_mc_socklist __rcu *next; - rwlock_t sflock; - struct ip6_sf_socklist *sflist; + struct ip6_sf_socklist __rcu *sflist; struct rcu_head rcu; }; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index e80b78b1a8a7..cffa2eeb88c5 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -178,8 +178,7 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex, mc_lst->ifindex = dev->ifindex; mc_lst->sfmode = mode; - rwlock_init(&mc_lst->sflock); - mc_lst->sflist = NULL; + RCU_INIT_POINTER(mc_lst->sflist, NULL); /* * now add/increase the group membership on the device @@ -335,7 +334,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk, struct net *net = sock_net(sk); int i, j, rv; int leavegroup = 0; - int pmclocked = 0; int err; source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr; @@ -364,7 +362,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, goto done; } /* if a source filter was set, must be the same mode as before */ - if (pmc->sflist) { + if (rcu_access_pointer(pmc->sflist)) { if (pmc->sfmode != omode) { err = -EINVAL; goto done; @@ -376,10 +374,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, pmc->sfmode = omode; } - write_lock(&pmc->sflock); - pmclocked = 1; - - psl = pmc->sflist; + psl = rtnl_dereference(pmc->sflist); if (!add) { if (!psl) goto done; /* err = -EADDRNOTAVAIL */ @@ -429,9 +424,11 @@ int ip6_mc_source(int add, int omode, struct sock *sk, if (psl) { for (i = 0; i < psl->sl_count; i++) newpsl->sl_addr[i] = psl->sl_addr[i]; - sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); + atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); + kfree_rcu(psl, rcu); } - pmc->sflist = psl = newpsl; + rcu_assign_pointer(psl, newpsl); + rcu_assign_pointer(pmc->sflist, psl); } rv = 1; /* > 0 for insert logic below if sl_count is 0 */ for (i = 0; i < psl->sl_count; i++) { @@ -447,8 +444,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk, /* update the interface list */ ip6_mc_add_src(idev, group, omode, 1, source, 1); done: - if (pmclocked) - write_unlock(&pmc->sflock); read_unlock_bh(&idev->lock); rcu_read_unlock(); if (leavegroup) @@ -526,17 +521,16 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf, (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); } - write_lock(&pmc->sflock); - psl = pmc->sflist; + psl = rtnl_dereference(pmc->sflist); if (psl) { (void) ip6_mc_del_src(idev, group, pmc->sfmode, psl->sl_count, psl->sl_addr, 0); - sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); + atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); + kfree_rcu(psl, rcu); } else (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); - pmc->sflist = newpsl; + rcu_assign_pointer(pmc->sflist, newpsl); pmc->sfmode = gsf->gf_fmode; - write_unlock(&pmc->sflock); err = 0; done: read_unlock_bh(&idev->lock); @@ -585,16 +579,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, if (!pmc) /* must have a prior join */ goto done; gsf->gf_fmode = pmc->sfmode; - psl = pmc->sflist; + psl = rtnl_dereference(pmc->sflist); count = psl ? psl->sl_count : 0; read_unlock_bh(&idev->lock); rcu_read_unlock(); copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; gsf->gf_numsrc = count; - /* changes to psl require the socket lock, and a write lock - * on pmc->sflock. We have the socket lock so reading here is safe. - */ + for (i = 0; i < copycount; i++, p++) { struct sockaddr_in6 *psin6; struct sockaddr_storage ss; @@ -630,8 +622,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, rcu_read_unlock(); return np->mc_all; } - read_lock(&mc->sflock); - psl = mc->sflist; + psl = rcu_dereference(mc->sflist); if (!psl) { rv = mc->sfmode == MCAST_EXCLUDE; } else { @@ -646,7 +637,6 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) rv = false; } - read_unlock(&mc->sflock); rcu_read_unlock(); return rv; @@ -2448,19 +2438,21 @@ static void igmp6_join_group(struct ifmcaddr6 *ma) static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, struct inet6_dev *idev) { + struct ip6_sf_socklist *psl; int err; - write_lock_bh(&iml->sflock); - if (!iml->sflist) { + psl = rtnl_dereference(iml->sflist); + + if (!psl) { /* any-source empty exclude case */ err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0); } else { err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode, - iml->sflist->sl_count, iml->sflist->sl_addr, 0); - sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max)); - iml->sflist = NULL; + psl->sl_count, psl->sl_addr, 0); + RCU_INIT_POINTER(iml->sflist, NULL); + atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); + kfree_rcu(psl, rcu); } - write_unlock_bh(&iml->sflock); return err; }
The sflist has been protected by rwlock so that the critical section is atomic context. In order to switch this context, changing locking is needed. The sflist actually already protected by RTNL So if it's converted to use RCU, its control path context can be switched to sleepable. Suggested-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Taehee Yoo <ap420073@gmail.com> --- v1 -> v2: - Separated from previous big one patch. include/net/if_inet6.h | 4 ++-- net/ipv6/mcast.c | 52 ++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 32 deletions(-)