2019-05-22 10:51:29 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2018-06-08 03:11:13 +03:00
/*
* Copyright 1997 - 1998 Transmeta Corporation - - All Rights Reserved
* Copyright 1999 - 2000 Jeremy Fitzhardinge < jeremy @ goop . org >
* Copyright 2001 - 2006 Ian Kent < raven @ themaw . net >
*/
# include "autofs_i.h"
/* Check if a dentry can be expired */
static inline int autofs_can_expire ( struct dentry * dentry ,
2018-08-22 07:58:58 +03:00
unsigned long timeout , unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct autofs_info * ino = autofs_dentry_ino ( dentry ) ;
/* dentry in the process of being deleted */
if ( ino = = NULL )
return 0 ;
2018-08-22 07:58:58 +03:00
if ( ! ( how & AUTOFS_EXP_IMMEDIATE ) ) {
2018-06-08 03:11:13 +03:00
/* Too young to die */
2018-08-22 07:58:44 +03:00
if ( ! timeout | | time_after ( ino - > last_used + timeout , jiffies ) )
2018-06-08 03:11:13 +03:00
return 0 ;
}
return 1 ;
}
/* Check a mount point for busyness */
2018-08-22 07:59:01 +03:00
static int autofs_mount_busy ( struct vfsmount * mnt ,
struct dentry * dentry , unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct dentry * top = dentry ;
struct path path = { . mnt = mnt , . dentry = dentry } ;
int status = 1 ;
pr_debug ( " dentry %p %pd \n " , dentry , dentry ) ;
path_get ( & path ) ;
if ( ! follow_down_one ( & path ) )
goto done ;
if ( is_autofs_dentry ( path . dentry ) ) {
struct autofs_sb_info * sbi = autofs_sbi ( path . dentry - > d_sb ) ;
/* This is an autofs submount, we can't expire it */
if ( autofs_type_indirect ( sbi - > type ) )
goto done ;
}
2018-08-22 07:59:01 +03:00
/* Not a submount, has a forced expire been requested */
if ( how & AUTOFS_EXP_FORCED ) {
status = 0 ;
goto done ;
}
2018-06-08 03:11:13 +03:00
/* Update the expiry counter if fs is busy */
if ( ! may_umount_tree ( path . mnt ) ) {
struct autofs_info * ino ;
ino = autofs_dentry_ino ( top ) ;
ino - > last_used = jiffies ;
goto done ;
}
status = 0 ;
done :
pr_debug ( " returning = %d \n " , status ) ;
path_put ( & path ) ;
return status ;
}
2019-07-25 06:01:55 +03:00
/* p->d_lock held */
static struct dentry * positive_after ( struct dentry * p , struct dentry * child )
{
if ( child )
child = list_next_entry ( child , d_child ) ;
else
child = list_first_entry ( & p - > d_subdirs , struct dentry , d_child ) ;
list_for_each_entry_from ( child , & p - > d_subdirs , d_child ) {
spin_lock_nested ( & child - > d_lock , DENTRY_D_LOCK_NESTED ) ;
if ( simple_positive ( child ) ) {
dget_dlock ( child ) ;
spin_unlock ( & child - > d_lock ) ;
return child ;
}
spin_unlock ( & child - > d_lock ) ;
}
return NULL ;
}
2018-06-08 03:11:13 +03:00
/*
* Calculate and dget next entry in the subdirs list under root .
*/
static struct dentry * get_next_positive_subdir ( struct dentry * prev ,
struct dentry * root )
{
struct autofs_sb_info * sbi = autofs_sbi ( root - > d_sb ) ;
struct dentry * q ;
spin_lock ( & sbi - > lookup_lock ) ;
spin_lock ( & root - > d_lock ) ;
2019-07-25 06:01:55 +03:00
q = positive_after ( root , prev ) ;
2018-06-08 03:11:13 +03:00
spin_unlock ( & root - > d_lock ) ;
spin_unlock ( & sbi - > lookup_lock ) ;
dput ( prev ) ;
return q ;
}
/*
* Calculate and dget next entry in top down tree traversal .
*/
static struct dentry * get_next_positive_dentry ( struct dentry * prev ,
struct dentry * root )
{
struct autofs_sb_info * sbi = autofs_sbi ( root - > d_sb ) ;
2019-07-25 06:01:55 +03:00
struct dentry * p = prev , * ret = NULL , * d = NULL ;
2018-06-08 03:11:13 +03:00
if ( prev = = NULL )
return dget ( root ) ;
spin_lock ( & sbi - > lookup_lock ) ;
spin_lock ( & p - > d_lock ) ;
2019-07-25 06:01:55 +03:00
while ( 1 ) {
struct dentry * parent ;
2018-06-08 03:11:13 +03:00
2019-07-25 06:01:55 +03:00
ret = positive_after ( p , d ) ;
if ( ret | | p = = root )
break ;
parent = p - > d_parent ;
2018-06-08 03:11:13 +03:00
spin_unlock ( & p - > d_lock ) ;
2019-07-25 06:01:55 +03:00
spin_lock ( & parent - > d_lock ) ;
d = p ;
p = parent ;
2018-06-08 03:11:13 +03:00
}
spin_unlock ( & p - > d_lock ) ;
spin_unlock ( & sbi - > lookup_lock ) ;
dput ( prev ) ;
return ret ;
}
/*
* Check a direct mount point for busyness .
* Direct mounts have similar expiry semantics to tree mounts .
* The tree is not busy iff no mountpoints are busy and there are no
* autofs submounts .
*/
static int autofs_direct_busy ( struct vfsmount * mnt ,
struct dentry * top ,
unsigned long timeout ,
2018-08-22 07:58:58 +03:00
unsigned int how )
2018-06-08 03:11:13 +03:00
{
pr_debug ( " top %p %pd \n " , top , top ) ;
2018-08-22 07:59:01 +03:00
/* Forced expire, user space handles busy mounts */
if ( how & AUTOFS_EXP_FORCED )
return 0 ;
2018-06-08 03:11:13 +03:00
/* If it's busy update the expiry counters */
if ( ! may_umount_tree ( mnt ) ) {
struct autofs_info * ino ;
ino = autofs_dentry_ino ( top ) ;
if ( ino )
ino - > last_used = jiffies ;
return 1 ;
}
/* Timeout of a direct mount is determined by its top dentry */
2018-08-22 07:58:58 +03:00
if ( ! autofs_can_expire ( top , timeout , how ) )
2018-06-08 03:11:13 +03:00
return 1 ;
return 0 ;
}
/*
* Check a directory tree of mount points for busyness
* The tree is not busy iff no mountpoints are busy
*/
static int autofs_tree_busy ( struct vfsmount * mnt ,
struct dentry * top ,
unsigned long timeout ,
2018-08-22 07:58:58 +03:00
unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct autofs_info * top_ino = autofs_dentry_ino ( top ) ;
struct dentry * p ;
pr_debug ( " top %p %pd \n " , top , top ) ;
/* Negative dentry - give up */
if ( ! simple_positive ( top ) )
return 1 ;
p = NULL ;
while ( ( p = get_next_positive_dentry ( p , top ) ) ) {
pr_debug ( " dentry %p %pd \n " , p , p ) ;
/*
* Is someone visiting anywhere in the subtree ?
* If there ' s no mount we need to check the usage
* count for the autofs dentry .
* If the fs is busy update the expiry counter .
*/
if ( d_mountpoint ( p ) ) {
2018-08-22 07:59:01 +03:00
if ( autofs_mount_busy ( mnt , p , how ) ) {
2018-06-08 03:11:13 +03:00
top_ino - > last_used = jiffies ;
dput ( p ) ;
return 1 ;
}
} else {
struct autofs_info * ino = autofs_dentry_ino ( p ) ;
2019-09-18 06:31:27 +03:00
unsigned int ino_count = READ_ONCE ( ino - > count ) ;
2018-06-08 03:11:13 +03:00
/* allow for dget above and top is already dgot */
if ( p = = top )
ino_count + = 2 ;
else
ino_count + + ;
if ( d_count ( p ) > ino_count ) {
top_ino - > last_used = jiffies ;
dput ( p ) ;
return 1 ;
}
}
}
2018-08-22 07:59:01 +03:00
/* Forced expire, user space handles busy mounts */
if ( how & AUTOFS_EXP_FORCED )
return 0 ;
2018-06-08 03:11:13 +03:00
/* Timeout of a tree mount is ultimately determined by its top dentry */
2018-08-22 07:58:58 +03:00
if ( ! autofs_can_expire ( top , timeout , how ) )
2018-06-08 03:11:13 +03:00
return 1 ;
return 0 ;
}
static struct dentry * autofs_check_leaves ( struct vfsmount * mnt ,
struct dentry * parent ,
unsigned long timeout ,
2018-08-22 07:58:58 +03:00
unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct dentry * p ;
pr_debug ( " parent %p %pd \n " , parent , parent ) ;
p = NULL ;
while ( ( p = get_next_positive_dentry ( p , parent ) ) ) {
pr_debug ( " dentry %p %pd \n " , p , p ) ;
if ( d_mountpoint ( p ) ) {
/* Can we umount this guy */
2018-08-22 07:59:01 +03:00
if ( autofs_mount_busy ( mnt , p , how ) )
2018-06-08 03:11:13 +03:00
continue ;
2018-08-22 07:59:01 +03:00
/* This isn't a submount so if a forced expire
* has been requested , user space handles busy
* mounts */
if ( how & AUTOFS_EXP_FORCED )
return p ;
2018-06-08 03:11:13 +03:00
/* Can we expire this guy */
2018-08-22 07:58:58 +03:00
if ( autofs_can_expire ( p , timeout , how ) )
2018-06-08 03:11:13 +03:00
return p ;
}
}
return NULL ;
}
/* Check if we can expire a direct mount (possibly a tree) */
2018-08-22 07:58:51 +03:00
static struct dentry * autofs_expire_direct ( struct super_block * sb ,
struct vfsmount * mnt ,
struct autofs_sb_info * sbi ,
2018-08-22 07:58:58 +03:00
unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct dentry * root = dget ( sb - > s_root ) ;
struct autofs_info * ino ;
2018-08-22 07:58:58 +03:00
unsigned long timeout ;
2018-06-08 03:11:13 +03:00
if ( ! root )
return NULL ;
timeout = sbi - > exp_timeout ;
2018-08-22 07:58:58 +03:00
if ( ! autofs_direct_busy ( mnt , root , timeout , how ) ) {
2018-06-08 03:11:13 +03:00
spin_lock ( & sbi - > fs_lock ) ;
ino = autofs_dentry_ino ( root ) ;
/* No point expiring a pending mount */
if ( ino - > flags & AUTOFS_INF_PENDING ) {
spin_unlock ( & sbi - > fs_lock ) ;
goto out ;
}
ino - > flags | = AUTOFS_INF_WANT_EXPIRE ;
spin_unlock ( & sbi - > fs_lock ) ;
synchronize_rcu ( ) ;
2018-08-22 07:58:58 +03:00
if ( ! autofs_direct_busy ( mnt , root , timeout , how ) ) {
2018-06-08 03:11:13 +03:00
spin_lock ( & sbi - > fs_lock ) ;
ino - > flags | = AUTOFS_INF_EXPIRING ;
init_completion ( & ino - > expire_complete ) ;
spin_unlock ( & sbi - > fs_lock ) ;
return root ;
}
spin_lock ( & sbi - > fs_lock ) ;
ino - > flags & = ~ AUTOFS_INF_WANT_EXPIRE ;
spin_unlock ( & sbi - > fs_lock ) ;
}
out :
dput ( root ) ;
return NULL ;
}
/* Check if 'dentry' should expire, or return a nearby
* dentry that is suitable .
* If returned dentry is different from arg dentry ,
* then a dget ( ) reference was taken , else not .
*/
static struct dentry * should_expire ( struct dentry * dentry ,
struct vfsmount * mnt ,
unsigned long timeout ,
2018-08-22 07:58:58 +03:00
unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct autofs_info * ino = autofs_dentry_ino ( dentry ) ;
unsigned int ino_count ;
/* No point expiring a pending mount */
if ( ino - > flags & AUTOFS_INF_PENDING )
return NULL ;
/*
* Case 1 : ( i ) indirect mount or top level pseudo direct mount
* ( autofs - 4.1 ) .
* ( ii ) indirect mount with offset mount , check the " / "
* offset ( autofs - 5.0 + ) .
*/
if ( d_mountpoint ( dentry ) ) {
pr_debug ( " checking mountpoint %p %pd \n " , dentry , dentry ) ;
/* Can we umount this guy */
2018-08-22 07:59:01 +03:00
if ( autofs_mount_busy ( mnt , dentry , how ) )
2018-06-08 03:11:13 +03:00
return NULL ;
2018-08-22 07:59:01 +03:00
/* This isn't a submount so if a forced expire
* has been requested , user space handles busy
* mounts */
if ( how & AUTOFS_EXP_FORCED )
return dentry ;
2018-06-08 03:11:13 +03:00
/* Can we expire this guy */
2018-08-22 07:58:58 +03:00
if ( autofs_can_expire ( dentry , timeout , how ) )
2018-06-08 03:11:13 +03:00
return dentry ;
return NULL ;
}
if ( d_really_is_positive ( dentry ) & & d_is_symlink ( dentry ) ) {
pr_debug ( " checking symlink %p %pd \n " , dentry , dentry ) ;
2018-08-22 07:59:01 +03:00
/* Forced expire, user space handles busy mounts */
if ( how & AUTOFS_EXP_FORCED )
return dentry ;
2018-06-08 03:11:13 +03:00
/*
* A symlink can ' t be " busy " in the usual sense so
* just check last used for expire timeout .
*/
2018-08-22 07:58:58 +03:00
if ( autofs_can_expire ( dentry , timeout , how ) )
2018-06-08 03:11:13 +03:00
return dentry ;
return NULL ;
}
if ( simple_empty ( dentry ) )
return NULL ;
/* Case 2: tree mount, expire iff entire tree is not busy */
2018-08-22 07:58:58 +03:00
if ( ! ( how & AUTOFS_EXP_LEAVES ) ) {
2018-08-22 07:59:01 +03:00
/* Not a forced expire? */
if ( ! ( how & AUTOFS_EXP_FORCED ) ) {
/* ref-walk currently on this dentry? */
2019-09-18 06:31:27 +03:00
ino_count = READ_ONCE ( ino - > count ) + 1 ;
2018-08-22 07:59:01 +03:00
if ( d_count ( dentry ) > ino_count )
return NULL ;
}
2018-06-08 03:11:13 +03:00
2018-08-22 07:58:58 +03:00
if ( ! autofs_tree_busy ( mnt , dentry , timeout , how ) )
2018-06-08 03:11:13 +03:00
return dentry ;
/*
* Case 3 : pseudo direct mount , expire individual leaves
* ( autofs - 4.1 ) .
*/
} else {
struct dentry * expired ;
2018-08-22 07:59:01 +03:00
/* Not a forced expire? */
if ( ! ( how & AUTOFS_EXP_FORCED ) ) {
/* ref-walk currently on this dentry? */
2019-09-18 06:31:27 +03:00
ino_count = READ_ONCE ( ino - > count ) + 1 ;
2018-08-22 07:59:01 +03:00
if ( d_count ( dentry ) > ino_count )
return NULL ;
}
2018-06-08 03:11:13 +03:00
2018-08-22 07:58:58 +03:00
expired = autofs_check_leaves ( mnt , dentry , timeout , how ) ;
2018-06-08 03:11:13 +03:00
if ( expired ) {
if ( expired = = dentry )
dput ( dentry ) ;
return expired ;
}
}
return NULL ;
}
/*
* Find an eligible tree to time - out
* A tree is eligible if : -
* - it is unused by any user process
* - it has been unused for exp_timeout time
*/
2018-08-22 07:58:54 +03:00
static struct dentry * autofs_expire_indirect ( struct super_block * sb ,
struct vfsmount * mnt ,
struct autofs_sb_info * sbi ,
2018-08-22 07:58:58 +03:00
unsigned int how )
2018-06-08 03:11:13 +03:00
{
unsigned long timeout ;
struct dentry * root = sb - > s_root ;
struct dentry * dentry ;
struct dentry * expired ;
struct dentry * found ;
struct autofs_info * ino ;
if ( ! root )
return NULL ;
timeout = sbi - > exp_timeout ;
dentry = NULL ;
while ( ( dentry = get_next_positive_subdir ( dentry , root ) ) ) {
spin_lock ( & sbi - > fs_lock ) ;
ino = autofs_dentry_ino ( dentry ) ;
if ( ino - > flags & AUTOFS_INF_WANT_EXPIRE ) {
spin_unlock ( & sbi - > fs_lock ) ;
continue ;
}
spin_unlock ( & sbi - > fs_lock ) ;
2018-08-22 07:58:58 +03:00
expired = should_expire ( dentry , mnt , timeout , how ) ;
2018-06-08 03:11:13 +03:00
if ( ! expired )
continue ;
spin_lock ( & sbi - > fs_lock ) ;
ino = autofs_dentry_ino ( expired ) ;
ino - > flags | = AUTOFS_INF_WANT_EXPIRE ;
spin_unlock ( & sbi - > fs_lock ) ;
synchronize_rcu ( ) ;
/* Make sure a reference is not taken on found if
* things have changed .
*/
2018-08-22 07:58:58 +03:00
how & = ~ AUTOFS_EXP_LEAVES ;
found = should_expire ( expired , mnt , timeout , how ) ;
2019-10-25 07:03:11 +03:00
if ( found ! = expired ) { // something has changed, continue
dput ( found ) ;
2018-06-08 03:11:13 +03:00
goto next ;
2019-10-25 07:03:11 +03:00
}
2018-06-08 03:11:13 +03:00
if ( expired ! = dentry )
dput ( dentry ) ;
spin_lock ( & sbi - > fs_lock ) ;
goto found ;
next :
spin_lock ( & sbi - > fs_lock ) ;
ino - > flags & = ~ AUTOFS_INF_WANT_EXPIRE ;
spin_unlock ( & sbi - > fs_lock ) ;
if ( expired ! = dentry )
dput ( expired ) ;
}
return NULL ;
found :
pr_debug ( " returning %p %pd \n " , expired , expired ) ;
ino - > flags | = AUTOFS_INF_EXPIRING ;
init_completion ( & ino - > expire_complete ) ;
spin_unlock ( & sbi - > fs_lock ) ;
return expired ;
}
int autofs_expire_wait ( const struct path * path , int rcu_walk )
{
struct dentry * dentry = path - > dentry ;
struct autofs_sb_info * sbi = autofs_sbi ( dentry - > d_sb ) ;
struct autofs_info * ino = autofs_dentry_ino ( dentry ) ;
int status ;
int state ;
/* Block on any pending expire */
if ( ! ( ino - > flags & AUTOFS_INF_WANT_EXPIRE ) )
return 0 ;
if ( rcu_walk )
return - ECHILD ;
retry :
spin_lock ( & sbi - > fs_lock ) ;
state = ino - > flags & ( AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING ) ;
if ( state = = AUTOFS_INF_WANT_EXPIRE ) {
spin_unlock ( & sbi - > fs_lock ) ;
/*
* Possibly being selected for expire , wait until
* it ' s selected or not .
*/
schedule_timeout_uninterruptible ( HZ / 10 ) ;
goto retry ;
}
if ( state & AUTOFS_INF_EXPIRING ) {
spin_unlock ( & sbi - > fs_lock ) ;
pr_debug ( " waiting for expire %p name=%pd \n " , dentry , dentry ) ;
status = autofs_wait ( sbi , path , NFY_NONE ) ;
wait_for_completion ( & ino - > expire_complete ) ;
pr_debug ( " expire done status=%d \n " , status ) ;
if ( d_unhashed ( dentry ) )
return - EAGAIN ;
return status ;
}
spin_unlock ( & sbi - > fs_lock ) ;
return 0 ;
}
/* Perform an expiry operation */
int autofs_expire_run ( struct super_block * sb ,
struct vfsmount * mnt ,
struct autofs_sb_info * sbi ,
struct autofs_packet_expire __user * pkt_p )
{
struct autofs_packet_expire pkt ;
struct autofs_info * ino ;
struct dentry * dentry ;
int ret = 0 ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
pkt . hdr . proto_version = sbi - > version ;
pkt . hdr . type = autofs_ptype_expire ;
dentry = autofs_expire_indirect ( sb , mnt , sbi , 0 ) ;
if ( ! dentry )
return - EAGAIN ;
pkt . len = dentry - > d_name . len ;
memcpy ( pkt . name , dentry - > d_name . name , pkt . len ) ;
pkt . name [ pkt . len ] = ' \0 ' ;
if ( copy_to_user ( pkt_p , & pkt , sizeof ( struct autofs_packet_expire ) ) )
ret = - EFAULT ;
spin_lock ( & sbi - > fs_lock ) ;
ino = autofs_dentry_ino ( dentry ) ;
/* avoid rapid-fire expire attempts if expiry fails */
2018-08-22 07:58:44 +03:00
ino - > last_used = jiffies ;
2018-06-08 03:11:13 +03:00
ino - > flags & = ~ ( AUTOFS_INF_EXPIRING | AUTOFS_INF_WANT_EXPIRE ) ;
complete_all ( & ino - > expire_complete ) ;
spin_unlock ( & sbi - > fs_lock ) ;
2019-02-02 01:21:26 +03:00
dput ( dentry ) ;
2018-06-08 03:11:13 +03:00
return ret ;
}
int autofs_do_expire_multi ( struct super_block * sb , struct vfsmount * mnt ,
2018-08-22 07:58:58 +03:00
struct autofs_sb_info * sbi , unsigned int how )
2018-06-08 03:11:13 +03:00
{
struct dentry * dentry ;
int ret = - EAGAIN ;
if ( autofs_type_trigger ( sbi - > type ) )
2018-08-22 07:58:58 +03:00
dentry = autofs_expire_direct ( sb , mnt , sbi , how ) ;
2018-06-08 03:11:13 +03:00
else
2018-08-22 07:58:58 +03:00
dentry = autofs_expire_indirect ( sb , mnt , sbi , how ) ;
2018-06-08 03:11:13 +03:00
if ( dentry ) {
struct autofs_info * ino = autofs_dentry_ino ( dentry ) ;
const struct path path = { . mnt = mnt , . dentry = dentry } ;
/* This is synchronous because it makes the daemon a
* little easier
*/
ret = autofs_wait ( sbi , & path , NFY_EXPIRE ) ;
spin_lock ( & sbi - > fs_lock ) ;
/* avoid rapid-fire expire attempts if expiry fails */
2018-08-22 07:58:44 +03:00
ino - > last_used = jiffies ;
2018-06-08 03:11:13 +03:00
ino - > flags & = ~ ( AUTOFS_INF_EXPIRING | AUTOFS_INF_WANT_EXPIRE ) ;
complete_all ( & ino - > expire_complete ) ;
spin_unlock ( & sbi - > fs_lock ) ;
dput ( dentry ) ;
}
return ret ;
}
/*
* Call repeatedly until it returns - EAGAIN , meaning there ' s nothing
* more to be done .
*/
int autofs_expire_multi ( struct super_block * sb , struct vfsmount * mnt ,
struct autofs_sb_info * sbi , int __user * arg )
{
2018-08-22 07:58:58 +03:00
unsigned int how = 0 ;
2018-06-08 03:11:13 +03:00
2018-08-22 07:58:58 +03:00
if ( arg & & get_user ( how , arg ) )
2018-06-08 03:11:13 +03:00
return - EFAULT ;
2018-08-22 07:58:58 +03:00
return autofs_do_expire_multi ( sb , mnt , sbi , how ) ;
2018-06-08 03:11:13 +03:00
}