@ -4379,13 +4379,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
/*
* Block new css_tryget ( ) by deactivating refcnt and mark @ cgrp
* removed . This makes future css_tryget ( ) and child creation
* attempts fail thus maintaining the removal conditions verified
* above .
*
* Note that CGRP_DEAD assertion is depended upon by
* cgroup_next_sibling ( ) to resume iteration after dropping RCU
* read lock . See cgroup_next_sibling ( ) for details .
* removed . This makes future css_tryget ( ) attempts fail which we
* guarantee to - > css_offline ( ) callbacks .
*/
for_each_subsys ( cgrp - > root , ss ) {
struct cgroup_subsys_state * css = cgrp - > subsys [ ss - > subsys_id ] ;
@ -4393,8 +4388,41 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
WARN_ON ( atomic_read ( & css - > refcnt ) < 0 ) ;
atomic_add ( CSS_DEACT_BIAS , & css - > refcnt ) ;
}
/*
* Mark @ cgrp dead . This prevents further task migration and child
* creation by disabling cgroup_lock_live_group ( ) . Note that
* CGRP_DEAD assertion is depended upon by cgroup_next_sibling ( ) to
* resume iteration after dropping RCU read lock . See
* cgroup_next_sibling ( ) for details .
*/
set_bit ( CGRP_DEAD , & cgrp - > flags ) ;
/* CGRP_DEAD is set, remove from ->release_list for the last time */
raw_spin_lock ( & release_list_lock ) ;
if ( ! list_empty ( & cgrp - > release_list ) )
list_del_init ( & cgrp - > release_list ) ;
raw_spin_unlock ( & release_list_lock ) ;
/*
* Remove @ cgrp directory . The removal puts the base ref but we
* aren ' t quite done with @ cgrp yet , so hold onto it .
*/
dget ( d ) ;
cgroup_d_remove_dir ( d ) ;
/*
* Unregister events and notify userspace .
* Notify userspace about cgroup removing only after rmdir of cgroup
* directory to avoid race between userspace and kernelspace .
*/
spin_lock ( & cgrp - > event_list_lock ) ;
list_for_each_entry_safe ( event , tmp , & cgrp - > event_list , list ) {
list_del_init ( & event - > list ) ;
schedule_work ( & event - > remove ) ;
}
spin_unlock ( & cgrp - > event_list_lock ) ;
/* tell subsystems to initate destruction */
for_each_subsys ( cgrp - > root , ss )
offline_css ( ss , cgrp ) ;
@ -4409,34 +4437,15 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
for_each_subsys ( cgrp - > root , ss )
css_put ( cgrp - > subsys [ ss - > subsys_id ] ) ;
raw_spin_lock ( & release_list_lock ) ;
if ( ! list_empty ( & cgrp - > release_list ) )
list_del_init ( & cgrp - > release_list ) ;
raw_spin_unlock ( & release_list_lock ) ;
/* delete this cgroup from parent->children */
list_del_rcu ( & cgrp - > sibling ) ;
list_del_init ( & cgrp - > allcg_node ) ;
dget ( d ) ;
cgroup_d_remove_dir ( d ) ;
dput ( d ) ;
set_bit ( CGRP_RELEASABLE , & parent - > flags ) ;
check_for_release ( parent ) ;
/*
* Unregister events and notify userspace .
* Notify userspace about cgroup removing only after rmdir of cgroup
* directory to avoid race between userspace and kernelspace .
*/
spin_lock ( & cgrp - > event_list_lock ) ;
list_for_each_entry_safe ( event , tmp , & cgrp - > event_list , list ) {
list_del_init ( & event - > list ) ;
schedule_work ( & event - > remove ) ;
}
spin_unlock ( & cgrp - > event_list_lock ) ;
return 0 ;
}