2014-08-07 16:39:04 +04:00
# include <linux/fs.h>
2015-01-11 01:53:21 +03:00
# include <linux/sched.h>
2014-08-07 16:39:04 +04:00
# include <linux/slab.h>
2014-05-22 02:22:52 +04:00
# include "internal.h"
2014-08-07 16:39:04 +04:00
# include "mount.h"
static DEFINE_SPINLOCK ( pin_lock ) ;
void pin_remove ( struct fs_pin * pin )
{
spin_lock ( & pin_lock ) ;
2015-04-03 00:35:48 +03:00
hlist_del_init ( & pin - > m_list ) ;
hlist_del_init ( & pin - > s_list ) ;
2014-08-07 16:39:04 +04:00
spin_unlock ( & pin_lock ) ;
2015-01-11 01:53:21 +03:00
spin_lock_irq ( & pin - > wait . lock ) ;
pin - > done = 1 ;
wake_up_locked ( & pin - > wait ) ;
spin_unlock_irq ( & pin - > wait . lock ) ;
2014-08-07 16:39:04 +04:00
}
2015-01-11 18:57:27 +03:00
void pin_insert_group ( struct fs_pin * pin , struct vfsmount * m , struct hlist_head * p )
2014-08-07 16:39:04 +04:00
{
spin_lock ( & pin_lock ) ;
2015-01-11 18:57:27 +03:00
if ( p )
hlist_add_head ( & pin - > s_list , p ) ;
2014-08-07 16:39:04 +04:00
hlist_add_head ( & pin - > m_list , & real_mount ( m ) - > mnt_pins ) ;
spin_unlock ( & pin_lock ) ;
}
2015-01-11 18:57:27 +03:00
void pin_insert ( struct fs_pin * pin , struct vfsmount * m )
{
pin_insert_group ( pin , m , & m - > mnt_sb - > s_pins ) ;
}
2015-01-11 01:53:21 +03:00
void pin_kill ( struct fs_pin * p )
{
wait_queue_t wait ;
if ( ! p ) {
rcu_read_unlock ( ) ;
return ;
}
init_wait ( & wait ) ;
spin_lock_irq ( & p - > wait . lock ) ;
if ( likely ( ! p - > done ) ) {
p - > done = - 1 ;
spin_unlock_irq ( & p - > wait . lock ) ;
rcu_read_unlock ( ) ;
p - > kill ( p ) ;
return ;
}
if ( p - > done > 0 ) {
spin_unlock_irq ( & p - > wait . lock ) ;
rcu_read_unlock ( ) ;
return ;
}
__add_wait_queue ( & p - > wait , & wait ) ;
while ( 1 ) {
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
spin_unlock_irq ( & p - > wait . lock ) ;
rcu_read_unlock ( ) ;
schedule ( ) ;
rcu_read_lock ( ) ;
if ( likely ( list_empty ( & wait . task_list ) ) )
break ;
/* OK, we know p couldn't have been freed yet */
spin_lock_irq ( & p - > wait . lock ) ;
if ( p - > done > 0 ) {
spin_unlock_irq ( & p - > wait . lock ) ;
break ;
}
}
rcu_read_unlock ( ) ;
}
2014-05-22 02:22:52 +04:00
void mnt_pin_kill ( struct mount * m )
2014-08-07 16:39:04 +04:00
{
while ( 1 ) {
struct hlist_node * p ;
rcu_read_lock ( ) ;
2014-05-22 02:22:52 +04:00
p = ACCESS_ONCE ( m - > mnt_pins . first ) ;
2014-08-07 16:39:04 +04:00
if ( ! p ) {
rcu_read_unlock ( ) ;
break ;
}
2015-01-11 01:53:21 +03:00
pin_kill ( hlist_entry ( p , struct fs_pin , m_list ) ) ;
2014-08-07 16:39:04 +04:00
}
}
2015-01-11 18:57:27 +03:00
void group_pin_kill ( struct hlist_head * p )
2014-08-07 16:39:04 +04:00
{
while ( 1 ) {
2015-01-11 18:57:27 +03:00
struct hlist_node * q ;
2014-08-07 16:39:04 +04:00
rcu_read_lock ( ) ;
2015-01-11 18:57:27 +03:00
q = ACCESS_ONCE ( p - > first ) ;
if ( ! q ) {
2014-08-07 16:39:04 +04:00
rcu_read_unlock ( ) ;
break ;
}
2015-01-11 01:53:21 +03:00
pin_kill ( hlist_entry ( q , struct fs_pin , s_list ) ) ;
2014-08-07 16:39:04 +04:00
}
}