2014-08-07 16:39:04 +04:00
# include <linux/fs.h>
# include <linux/slab.h>
# include <linux/fs_pin.h>
2014-05-22 02:22:52 +04:00
# include "internal.h"
2014-08-07 16:39:04 +04:00
# include "mount.h"
static void pin_free_rcu ( struct rcu_head * head )
{
kfree ( container_of ( head , struct fs_pin , rcu ) ) ;
}
static DEFINE_SPINLOCK ( pin_lock ) ;
void pin_put ( struct fs_pin * p )
{
if ( atomic_long_dec_and_test ( & p - > count ) )
call_rcu ( & p - > rcu , pin_free_rcu ) ;
}
void pin_remove ( struct fs_pin * pin )
{
spin_lock ( & pin_lock ) ;
hlist_del ( & pin - > m_list ) ;
hlist_del ( & pin - > s_list ) ;
spin_unlock ( & pin_lock ) ;
}
void pin_insert ( struct fs_pin * pin , struct vfsmount * m )
{
spin_lock ( & pin_lock ) ;
hlist_add_head ( & pin - > s_list , & m - > mnt_sb - > s_pins ) ;
hlist_add_head ( & pin - > m_list , & real_mount ( m ) - > mnt_pins ) ;
spin_unlock ( & pin_lock ) ;
}
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 ;
struct fs_pin * pin ;
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 ;
}
pin = hlist_entry ( p , struct fs_pin , m_list ) ;
if ( ! atomic_long_inc_not_zero ( & pin - > count ) ) {
rcu_read_unlock ( ) ;
cpu_relax ( ) ;
continue ;
}
rcu_read_unlock ( ) ;
pin - > kill ( pin ) ;
}
}
2014-05-22 02:22:52 +04:00
void sb_pin_kill ( struct super_block * sb )
2014-08-07 16:39:04 +04:00
{
while ( 1 ) {
struct hlist_node * p ;
struct fs_pin * pin ;
rcu_read_lock ( ) ;
2014-05-22 02:22:52 +04:00
p = ACCESS_ONCE ( sb - > s_pins . first ) ;
2014-08-07 16:39:04 +04:00
if ( ! p ) {
rcu_read_unlock ( ) ;
break ;
}
pin = hlist_entry ( p , struct fs_pin , s_list ) ;
if ( ! atomic_long_inc_not_zero ( & pin - > count ) ) {
rcu_read_unlock ( ) ;
cpu_relax ( ) ;
continue ;
}
rcu_read_unlock ( ) ;
pin - > kill ( pin ) ;
}
}