2005-04-17 02:20:36 +04:00
/* -*- c -*- --------------------------------------------------------------- *
*
* linux / fs / autofs / root . c
*
* Copyright 1997 - 1998 Transmeta Corporation - - All Rights Reserved
* Copyright 1999 - 2000 Jeremy Fitzhardinge < jeremy @ goop . org >
2006-03-27 13:14:54 +04:00
* Copyright 2001 - 2006 Ian Kent < raven @ themaw . net >
2005-04-17 02:20:36 +04:00
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License , version 2 , or at your
* option , any later version , incorporated herein by reference .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <linux/stat.h>
# include <linux/param.h>
# include <linux/time.h>
# include <linux/smp_lock.h>
# include "autofs_i.h"
static int autofs4_dir_symlink ( struct inode * , struct dentry * , const char * ) ;
static int autofs4_dir_unlink ( struct inode * , struct dentry * ) ;
static int autofs4_dir_rmdir ( struct inode * , struct dentry * ) ;
static int autofs4_dir_mkdir ( struct inode * , struct dentry * , int ) ;
static int autofs4_root_ioctl ( struct inode * , struct file * , unsigned int , unsigned long ) ;
static int autofs4_dir_open ( struct inode * inode , struct file * file ) ;
static int autofs4_dir_close ( struct inode * inode , struct file * file ) ;
static int autofs4_dir_readdir ( struct file * filp , void * dirent , filldir_t filldir ) ;
static int autofs4_root_readdir ( struct file * filp , void * dirent , filldir_t filldir ) ;
static struct dentry * autofs4_lookup ( struct inode * , struct dentry * , struct nameidata * ) ;
2006-03-27 13:14:54 +04:00
static void * autofs4_follow_link ( struct dentry * , struct nameidata * ) ;
2005-04-17 02:20:36 +04:00
2006-03-28 13:56:42 +04:00
const struct file_operations autofs4_root_operations = {
2005-04-17 02:20:36 +04:00
. open = dcache_dir_open ,
. release = dcache_dir_close ,
. read = generic_read_dir ,
. readdir = autofs4_root_readdir ,
. ioctl = autofs4_root_ioctl ,
} ;
2006-03-28 13:56:42 +04:00
const struct file_operations autofs4_dir_operations = {
2005-04-17 02:20:36 +04:00
. open = autofs4_dir_open ,
. release = autofs4_dir_close ,
. read = generic_read_dir ,
. readdir = autofs4_dir_readdir ,
} ;
2006-03-27 13:14:54 +04:00
struct inode_operations autofs4_indirect_root_inode_operations = {
2005-04-17 02:20:36 +04:00
. lookup = autofs4_lookup ,
. unlink = autofs4_dir_unlink ,
. symlink = autofs4_dir_symlink ,
. mkdir = autofs4_dir_mkdir ,
. rmdir = autofs4_dir_rmdir ,
} ;
2006-03-27 13:14:54 +04:00
struct inode_operations autofs4_direct_root_inode_operations = {
. lookup = autofs4_lookup ,
2006-03-27 13:14:58 +04:00
. unlink = autofs4_dir_unlink ,
. mkdir = autofs4_dir_mkdir ,
. rmdir = autofs4_dir_rmdir ,
2006-03-27 13:14:54 +04:00
. follow_link = autofs4_follow_link ,
} ;
2005-04-17 02:20:36 +04:00
struct inode_operations autofs4_dir_inode_operations = {
. lookup = autofs4_lookup ,
. unlink = autofs4_dir_unlink ,
. symlink = autofs4_dir_symlink ,
. mkdir = autofs4_dir_mkdir ,
. rmdir = autofs4_dir_rmdir ,
} ;
static int autofs4_root_readdir ( struct file * file , void * dirent ,
filldir_t filldir )
{
struct autofs_sb_info * sbi = autofs4_sbi ( file - > f_dentry - > d_sb ) ;
int oz_mode = autofs4_oz_mode ( sbi ) ;
DPRINTK ( " called, filp->f_pos = %lld " , file - > f_pos ) ;
/*
* Don ' t set reghost flag if :
* 1 ) f_pos is larger than zero - - we ' ve already been here .
* 2 ) we haven ' t even enabled reghosting in the 1 st place .
* 3 ) this is the daemon doing a readdir
*/
if ( oz_mode & & file - > f_pos = = 0 & & sbi - > reghost_enabled )
sbi - > needs_reghost = 1 ;
DPRINTK ( " needs_reghost = %d " , sbi - > needs_reghost ) ;
2006-03-27 13:14:43 +04:00
return dcache_readdir ( file , dirent , filldir ) ;
2005-04-17 02:20:36 +04:00
}
static int autofs4_dir_open ( struct inode * inode , struct file * file )
{
struct dentry * dentry = file - > f_dentry ;
struct vfsmount * mnt = file - > f_vfsmnt ;
struct autofs_sb_info * sbi = autofs4_sbi ( dentry - > d_sb ) ;
2006-03-27 13:14:43 +04:00
struct dentry * cursor ;
2005-04-17 02:20:36 +04:00
int status ;
2006-03-27 13:14:43 +04:00
status = dcache_dir_open ( inode , file ) ;
if ( status )
goto out ;
cursor = file - > private_data ;
cursor - > d_fsdata = NULL ;
2005-04-17 02:20:36 +04:00
DPRINTK ( " file=%p dentry=%p %.*s " ,
file , dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
if ( autofs4_oz_mode ( sbi ) )
goto out ;
if ( autofs4_ispending ( dentry ) ) {
DPRINTK ( " dentry busy " ) ;
2006-03-27 13:14:43 +04:00
dcache_dir_close ( inode , file ) ;
status = - EBUSY ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2006-03-27 13:14:43 +04:00
status = - ENOENT ;
2005-04-17 02:20:36 +04:00
if ( ! d_mountpoint ( dentry ) & & dentry - > d_op & & dentry - > d_op - > d_revalidate ) {
struct nameidata nd ;
2006-03-27 13:14:43 +04:00
int empty , ret ;
2005-04-17 02:20:36 +04:00
/* In case there are stale directory dentrys from a failed mount */
spin_lock ( & dcache_lock ) ;
empty = list_empty ( & dentry - > d_subdirs ) ;
spin_unlock ( & dcache_lock ) ;
if ( ! empty )
d_invalidate ( dentry ) ;
nd . flags = LOOKUP_DIRECTORY ;
2006-03-27 13:14:43 +04:00
ret = ( dentry - > d_op - > d_revalidate ) ( dentry , & nd ) ;
2005-04-17 02:20:36 +04:00
2006-03-27 13:14:43 +04:00
if ( ! ret ) {
dcache_dir_close ( inode , file ) ;
goto out ;
}
2005-04-17 02:20:36 +04:00
}
if ( d_mountpoint ( dentry ) ) {
struct file * fp = NULL ;
struct vfsmount * fp_mnt = mntget ( mnt ) ;
struct dentry * fp_dentry = dget ( dentry ) ;
2005-06-22 04:16:38 +04:00
if ( ! autofs4_follow_mount ( & fp_mnt , & fp_dentry ) ) {
dput ( fp_dentry ) ;
mntput ( fp_mnt ) ;
2006-03-27 13:14:43 +04:00
dcache_dir_close ( inode , file ) ;
goto out ;
2005-06-22 04:16:38 +04:00
}
2005-04-17 02:20:36 +04:00
fp = dentry_open ( fp_dentry , fp_mnt , file - > f_flags ) ;
status = PTR_ERR ( fp ) ;
if ( IS_ERR ( fp ) ) {
2006-03-27 13:14:43 +04:00
dcache_dir_close ( inode , file ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2006-03-27 13:14:43 +04:00
cursor - > d_fsdata = fp ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
2006-03-27 13:14:43 +04:00
out :
return status ;
2005-04-17 02:20:36 +04:00
}
static int autofs4_dir_close ( struct inode * inode , struct file * file )
{
struct dentry * dentry = file - > f_dentry ;
struct autofs_sb_info * sbi = autofs4_sbi ( dentry - > d_sb ) ;
2006-03-27 13:14:43 +04:00
struct dentry * cursor = file - > private_data ;
int status = 0 ;
2005-04-17 02:20:36 +04:00
DPRINTK ( " file=%p dentry=%p %.*s " ,
file , dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
if ( autofs4_oz_mode ( sbi ) )
goto out ;
if ( autofs4_ispending ( dentry ) ) {
DPRINTK ( " dentry busy " ) ;
2006-03-27 13:14:43 +04:00
status = - EBUSY ;
goto out ;
2005-04-17 02:20:36 +04:00
}
if ( d_mountpoint ( dentry ) ) {
2006-03-27 13:14:43 +04:00
struct file * fp = cursor - > d_fsdata ;
if ( ! fp ) {
status = - ENOENT ;
goto out ;
}
2005-04-17 02:20:36 +04:00
filp_close ( fp , current - > files ) ;
}
out :
2006-03-27 13:14:43 +04:00
dcache_dir_close ( inode , file ) ;
return status ;
2005-04-17 02:20:36 +04:00
}
static int autofs4_dir_readdir ( struct file * file , void * dirent , filldir_t filldir )
{
struct dentry * dentry = file - > f_dentry ;
struct autofs_sb_info * sbi = autofs4_sbi ( dentry - > d_sb ) ;
2006-03-27 13:14:43 +04:00
struct dentry * cursor = file - > private_data ;
2005-04-17 02:20:36 +04:00
int status ;
DPRINTK ( " file=%p dentry=%p %.*s " ,
file , dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
if ( autofs4_oz_mode ( sbi ) )
goto out ;
if ( autofs4_ispending ( dentry ) ) {
DPRINTK ( " dentry busy " ) ;
return - EBUSY ;
}
if ( d_mountpoint ( dentry ) ) {
2006-03-27 13:14:43 +04:00
struct file * fp = cursor - > d_fsdata ;
2005-04-17 02:20:36 +04:00
if ( ! fp )
return - ENOENT ;
if ( ! fp - > f_op | | ! fp - > f_op - > readdir )
goto out ;
status = vfs_readdir ( fp , filldir , dirent ) ;
file - > f_pos = fp - > f_pos ;
if ( status )
autofs4_copy_atime ( file , fp ) ;
return status ;
}
out :
2006-03-27 13:14:43 +04:00
return dcache_readdir ( file , dirent , filldir ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-27 13:14:48 +04:00
static int try_to_fill_dentry ( struct dentry * dentry , int flags )
2005-04-17 02:20:36 +04:00
{
2006-03-27 13:14:48 +04:00
struct autofs_sb_info * sbi = autofs4_sbi ( dentry - > d_sb ) ;
2006-03-27 13:14:42 +04:00
struct autofs_info * ino = autofs4_dentry_ino ( dentry ) ;
2005-04-17 02:20:36 +04:00
int status = 0 ;
/* Block on any pending expiry here; invalidate the dentry
when expiration is done to trigger mount request with a new
dentry */
2006-03-27 13:14:42 +04:00
if ( ino & & ( ino - > flags & AUTOFS_INF_EXPIRING ) ) {
2005-04-17 02:20:36 +04:00
DPRINTK ( " waiting for expire %p name=%.*s " ,
dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
status = autofs4_wait ( sbi , dentry , NFY_NONE ) ;
2006-03-27 13:14:42 +04:00
2005-04-17 02:20:36 +04:00
DPRINTK ( " expire done status=%d " , status ) ;
2006-03-27 13:14:42 +04:00
2005-06-22 04:16:41 +04:00
/*
* If the directory still exists the mount request must
* continue otherwise it can ' t be followed at the right
* time during the walk .
*/
status = d_invalidate ( dentry ) ;
if ( status ! = - EBUSY )
2006-03-27 13:14:54 +04:00
return - ENOENT ;
2005-04-17 02:20:36 +04:00
}
DPRINTK ( " dentry=%p %.*s ino=%p " ,
dentry , dentry - > d_name . len , dentry - > d_name . name , dentry - > d_inode ) ;
2006-03-27 13:14:42 +04:00
/*
* Wait for a pending mount , triggering one if there
* isn ' t one already
*/
2005-04-17 02:20:36 +04:00
if ( dentry - > d_inode = = NULL ) {
DPRINTK ( " waiting for mount name=%.*s " ,
dentry - > d_name . len , dentry - > d_name . name ) ;
status = autofs4_wait ( sbi , dentry , NFY_MOUNT ) ;
2006-03-27 13:14:42 +04:00
2005-04-17 02:20:36 +04:00
DPRINTK ( " mount done status=%d " , status ) ;
if ( status & & dentry - > d_inode )
2006-03-27 13:14:54 +04:00
return status ; /* Try to get the kernel to invalidate this dentry */
2006-03-27 13:14:42 +04:00
2005-04-17 02:20:36 +04:00
/* Turn this into a real negative dentry? */
if ( status = = - ENOENT ) {
spin_lock ( & dentry - > d_lock ) ;
dentry - > d_flags & = ~ DCACHE_AUTOFS_PENDING ;
spin_unlock ( & dentry - > d_lock ) ;
2006-03-27 13:14:54 +04:00
return status ;
2005-04-17 02:20:36 +04:00
} else if ( status ) {
/* Return a negative dentry, but leave it "pending" */
2006-03-27 13:14:54 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
/* Trigger mount for path component or follow link */
} else if ( flags & ( LOOKUP_CONTINUE | LOOKUP_DIRECTORY ) | |
current - > link_count ) {
DPRINTK ( " waiting for mount name=%.*s " ,
dentry - > d_name . len , dentry - > d_name . name ) ;
spin_lock ( & dentry - > d_lock ) ;
dentry - > d_flags | = DCACHE_AUTOFS_PENDING ;
spin_unlock ( & dentry - > d_lock ) ;
status = autofs4_wait ( sbi , dentry , NFY_MOUNT ) ;
DPRINTK ( " mount done status=%d " , status ) ;
if ( status ) {
spin_lock ( & dentry - > d_lock ) ;
dentry - > d_flags & = ~ DCACHE_AUTOFS_PENDING ;
spin_unlock ( & dentry - > d_lock ) ;
2006-03-27 13:14:54 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
}
2006-03-27 13:14:47 +04:00
/* Initialize expiry counter after successful mount */
if ( ino )
ino - > last_used = jiffies ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dentry - > d_lock ) ;
dentry - > d_flags & = ~ DCACHE_AUTOFS_PENDING ;
spin_unlock ( & dentry - > d_lock ) ;
2006-03-27 13:14:54 +04:00
return status ;
}
/* For autofs direct mounts the follow link triggers the mount */
static void * autofs4_follow_link ( struct dentry * dentry , struct nameidata * nd )
{
struct autofs_sb_info * sbi = autofs4_sbi ( dentry - > d_sb ) ;
2006-05-15 20:43:51 +04:00
struct autofs_info * ino = autofs4_dentry_ino ( dentry ) ;
2006-03-27 13:14:54 +04:00
int oz_mode = autofs4_oz_mode ( sbi ) ;
unsigned int lookup_type ;
int status ;
DPRINTK ( " dentry=%p %.*s oz_mode=%d nd->flags=%d " ,
dentry , dentry - > d_name . len , dentry - > d_name . name , oz_mode ,
nd - > flags ) ;
/* If it's our master or we shouldn't trigger a mount we're done */
lookup_type = nd - > flags & ( LOOKUP_CONTINUE | LOOKUP_DIRECTORY ) ;
if ( oz_mode | | ! lookup_type )
goto done ;
2006-05-15 20:43:51 +04:00
/* If an expire request is pending wait for it. */
if ( ino & & ( ino - > flags & AUTOFS_INF_EXPIRING ) ) {
2006-03-27 13:14:58 +04:00
DPRINTK ( " waiting for active request %p name=%.*s " ,
dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
status = autofs4_wait ( sbi , dentry , NFY_NONE ) ;
DPRINTK ( " request done status=%d " , status ) ;
}
2006-03-27 13:14:54 +04:00
2006-03-27 13:14:58 +04:00
/*
* If the dentry contains directories then it is an
* autofs multi - mount with no root mount offset . So
* don ' t try to mount it again .
*/
spin_lock ( & dcache_lock ) ;
if ( ! d_mountpoint ( dentry ) & & list_empty ( & dentry - > d_subdirs ) ) {
spin_unlock ( & dcache_lock ) ;
status = try_to_fill_dentry ( dentry , 0 ) ;
if ( status )
goto out_error ;
/*
* The mount succeeded but if there is no root mount
* it must be an autofs multi - mount with no root offset
* so we don ' t need to follow the mount .
*/
if ( d_mountpoint ( dentry ) ) {
if ( ! autofs4_follow_mount ( & nd - > mnt , & nd - > dentry ) ) {
status = - ENOENT ;
goto out_error ;
}
}
goto done ;
2006-03-27 13:14:54 +04:00
}
2006-03-27 13:14:58 +04:00
spin_unlock ( & dcache_lock ) ;
2006-03-27 13:14:54 +04:00
done :
return NULL ;
out_error :
path_release ( nd ) ;
return ERR_PTR ( status ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Revalidate is called on every cache lookup . Some of those
* cache lookups may actually happen while the dentry is not
* yet completely filled in , and revalidate has to delay such
* lookups . .
*/
2006-03-27 13:14:42 +04:00
static int autofs4_revalidate ( struct dentry * dentry , struct nameidata * nd )
2005-04-17 02:20:36 +04:00
{
2006-03-27 13:14:42 +04:00
struct inode * dir = dentry - > d_parent - > d_inode ;
2005-04-17 02:20:36 +04:00
struct autofs_sb_info * sbi = autofs4_sbi ( dir - > i_sb ) ;
int oz_mode = autofs4_oz_mode ( sbi ) ;
int flags = nd ? nd - > flags : 0 ;
2006-03-27 13:14:54 +04:00
int status = 0 ;
2005-04-17 02:20:36 +04:00
/* Pending dentry */
if ( autofs4_ispending ( dentry ) ) {
if ( ! oz_mode )
2006-03-27 13:14:48 +04:00
status = try_to_fill_dentry ( dentry , flags ) ;
2006-03-27 13:14:54 +04:00
return ! status ;
2005-04-17 02:20:36 +04:00
}
/* Negative dentry.. invalidate if "old" */
if ( dentry - > d_inode = = NULL )
2006-03-27 13:14:44 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/* Check for a non-mountpoint directory with no contents */
spin_lock ( & dcache_lock ) ;
if ( S_ISDIR ( dentry - > d_inode - > i_mode ) & &
! d_mountpoint ( dentry ) & &
2006-03-27 13:14:50 +04:00
__simple_empty ( dentry ) ) {
2005-04-17 02:20:36 +04:00
DPRINTK ( " dentry=%p %.*s, emptydir " ,
dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
spin_unlock ( & dcache_lock ) ;
if ( ! oz_mode )
2006-03-27 13:14:48 +04:00
status = try_to_fill_dentry ( dentry , flags ) ;
2006-03-27 13:14:54 +04:00
return ! status ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & dcache_lock ) ;
return 1 ;
}
2006-03-27 13:14:54 +04:00
void autofs4_dentry_release ( struct dentry * de )
2005-04-17 02:20:36 +04:00
{
struct autofs_info * inf ;
DPRINTK ( " releasing %p " , de ) ;
inf = autofs4_dentry_ino ( de ) ;
de - > d_fsdata = NULL ;
if ( inf ) {
inf - > dentry = NULL ;
inf - > inode = NULL ;
autofs4_free_ino ( inf ) ;
}
}
/* For dentries of directories in the root dir */
static struct dentry_operations autofs4_root_dentry_operations = {
. d_revalidate = autofs4_revalidate ,
. d_release = autofs4_dentry_release ,
} ;
/* For other dentries */
static struct dentry_operations autofs4_dentry_operations = {
. d_revalidate = autofs4_revalidate ,
. d_release = autofs4_dentry_release ,
} ;
/* Lookups in the root directory */
static struct dentry * autofs4_lookup ( struct inode * dir , struct dentry * dentry , struct nameidata * nd )
{
struct autofs_sb_info * sbi ;
int oz_mode ;
DPRINTK ( " name = %.*s " ,
dentry - > d_name . len , dentry - > d_name . name ) ;
2006-03-27 13:14:42 +04:00
/* File name too long to exist */
2005-04-17 02:20:36 +04:00
if ( dentry - > d_name . len > NAME_MAX )
2006-03-27 13:14:42 +04:00
return ERR_PTR ( - ENAMETOOLONG ) ;
2005-04-17 02:20:36 +04:00
sbi = autofs4_sbi ( dir - > i_sb ) ;
oz_mode = autofs4_oz_mode ( sbi ) ;
2006-03-27 13:14:42 +04:00
2005-04-17 02:20:36 +04:00
DPRINTK ( " pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d " ,
current - > pid , process_group ( current ) , sbi - > catatonic , oz_mode ) ;
/*
* Mark the dentry incomplete , but add it . This is needed so
* that the VFS layer knows about the dentry , and we can count
* on catching any lookups through the revalidate .
*
* Let all the hard work be done by the revalidate function that
* needs to be able to do this anyway . .
*
* We need to do this before we release the directory semaphore .
*/
dentry - > d_op = & autofs4_root_dentry_operations ;
if ( ! oz_mode ) {
spin_lock ( & dentry - > d_lock ) ;
dentry - > d_flags | = DCACHE_AUTOFS_PENDING ;
spin_unlock ( & dentry - > d_lock ) ;
}
dentry - > d_fsdata = NULL ;
d_add ( dentry , NULL ) ;
if ( dentry - > d_op & & dentry - > d_op - > d_revalidate ) {
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
( dentry - > d_op - > d_revalidate ) ( dentry , nd ) ;
2006-01-10 02:59:24 +03:00
mutex_lock ( & dir - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
/*
* If we are still pending , check if we had to handle
* a signal . If so we can force a restart . .
*/
if ( dentry - > d_flags & DCACHE_AUTOFS_PENDING ) {
/* See if we were interrupted */
if ( signal_pending ( current ) ) {
sigset_t * sigset = & current - > pending . signal ;
if ( sigismember ( sigset , SIGKILL ) | |
sigismember ( sigset , SIGQUIT ) | |
sigismember ( sigset , SIGINT ) ) {
return ERR_PTR ( - ERESTARTNOINTR ) ;
}
}
}
/*
* If this dentry is unhashed , then we shouldn ' t honour this
* lookup even if the dentry is positive . Returning ENOENT here
* doesn ' t do the right thing for all system calls , but it should
* be OK for the operations we permit from an autofs .
*/
2006-03-27 13:14:42 +04:00
if ( dentry - > d_inode & & d_unhashed ( dentry ) )
2005-04-17 02:20:36 +04:00
return ERR_PTR ( - ENOENT ) ;
return NULL ;
}
static int autofs4_dir_symlink ( struct inode * dir ,
struct dentry * dentry ,
const char * symname )
{
struct autofs_sb_info * sbi = autofs4_sbi ( dir - > i_sb ) ;
struct autofs_info * ino = autofs4_dentry_ino ( dentry ) ;
2006-03-27 13:14:46 +04:00
struct autofs_info * p_ino ;
2005-04-17 02:20:36 +04:00
struct inode * inode ;
char * cp ;
DPRINTK ( " %s <- %.*s " , symname ,
dentry - > d_name . len , dentry - > d_name . name ) ;
if ( ! autofs4_oz_mode ( sbi ) )
return - EACCES ;
ino = autofs4_init_ino ( ino , sbi , S_IFLNK | 0555 ) ;
if ( ino = = NULL )
return - ENOSPC ;
ino - > size = strlen ( symname ) ;
ino - > u . symlink = cp = kmalloc ( ino - > size + 1 , GFP_KERNEL ) ;
if ( cp = = NULL ) {
kfree ( ino ) ;
return - ENOSPC ;
}
strcpy ( cp , symname ) ;
inode = autofs4_get_inode ( dir - > i_sb , ino ) ;
d_instantiate ( dentry , inode ) ;
if ( dir = = dir - > i_sb - > s_root - > d_inode )
dentry - > d_op = & autofs4_root_dentry_operations ;
else
dentry - > d_op = & autofs4_dentry_operations ;
dentry - > d_fsdata = ino ;
ino - > dentry = dget ( dentry ) ;
2006-03-27 13:14:46 +04:00
atomic_inc ( & ino - > count ) ;
p_ino = autofs4_dentry_ino ( dentry - > d_parent ) ;
if ( p_ino & & dentry - > d_parent ! = dentry )
atomic_inc ( & p_ino - > count ) ;
2005-04-17 02:20:36 +04:00
ino - > inode = inode ;
dir - > i_mtime = CURRENT_TIME ;
return 0 ;
}
/*
* NOTE !
*
* Normal filesystems would do a " d_delete() " to tell the VFS dcache
* that the file no longer exists . However , doing that means that the
* VFS layer can turn the dentry into a negative dentry . We don ' t want
* this , because since the unlink is probably the result of an expire .
* We simply d_drop it , which allows the dentry lookup to remount it
* if necessary .
*
* If a process is blocked on the dentry waiting for the expire to finish ,
* it will invalidate the dentry and try to mount with a new one .
*
* Also see autofs4_dir_rmdir ( ) . .
*/
static int autofs4_dir_unlink ( struct inode * dir , struct dentry * dentry )
{
struct autofs_sb_info * sbi = autofs4_sbi ( dir - > i_sb ) ;
struct autofs_info * ino = autofs4_dentry_ino ( dentry ) ;
2006-03-27 13:14:46 +04:00
struct autofs_info * p_ino ;
2005-04-17 02:20:36 +04:00
/* This allows root to remove symlinks */
if ( ! autofs4_oz_mode ( sbi ) & & ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
2006-03-27 13:14:46 +04:00
if ( atomic_dec_and_test ( & ino - > count ) ) {
p_ino = autofs4_dentry_ino ( dentry - > d_parent ) ;
if ( p_ino & & dentry - > d_parent ! = dentry )
atomic_dec ( & p_ino - > count ) ;
}
2005-04-17 02:20:36 +04:00
dput ( ino - > dentry ) ;
dentry - > d_inode - > i_size = 0 ;
dentry - > d_inode - > i_nlink = 0 ;
dir - > i_mtime = CURRENT_TIME ;
d_drop ( dentry ) ;
return 0 ;
}
static int autofs4_dir_rmdir ( struct inode * dir , struct dentry * dentry )
{
struct autofs_sb_info * sbi = autofs4_sbi ( dir - > i_sb ) ;
struct autofs_info * ino = autofs4_dentry_ino ( dentry ) ;
2006-03-27 13:14:46 +04:00
struct autofs_info * p_ino ;
2005-04-17 02:20:36 +04:00
if ( ! autofs4_oz_mode ( sbi ) )
return - EACCES ;
spin_lock ( & dcache_lock ) ;
if ( ! list_empty ( & dentry - > d_subdirs ) ) {
spin_unlock ( & dcache_lock ) ;
return - ENOTEMPTY ;
}
spin_lock ( & dentry - > d_lock ) ;
__d_drop ( dentry ) ;
spin_unlock ( & dentry - > d_lock ) ;
spin_unlock ( & dcache_lock ) ;
2006-03-27 13:14:46 +04:00
if ( atomic_dec_and_test ( & ino - > count ) ) {
p_ino = autofs4_dentry_ino ( dentry - > d_parent ) ;
if ( p_ino & & dentry - > d_parent ! = dentry )
atomic_dec ( & p_ino - > count ) ;
}
2005-04-17 02:20:36 +04:00
dput ( ino - > dentry ) ;
dentry - > d_inode - > i_size = 0 ;
dentry - > d_inode - > i_nlink = 0 ;
if ( dir - > i_nlink )
dir - > i_nlink - - ;
return 0 ;
}
static int autofs4_dir_mkdir ( struct inode * dir , struct dentry * dentry , int mode )
{
struct autofs_sb_info * sbi = autofs4_sbi ( dir - > i_sb ) ;
struct autofs_info * ino = autofs4_dentry_ino ( dentry ) ;
2006-03-27 13:14:46 +04:00
struct autofs_info * p_ino ;
2005-04-17 02:20:36 +04:00
struct inode * inode ;
if ( ! autofs4_oz_mode ( sbi ) )
return - EACCES ;
DPRINTK ( " dentry %p, creating %.*s " ,
dentry , dentry - > d_name . len , dentry - > d_name . name ) ;
ino = autofs4_init_ino ( ino , sbi , S_IFDIR | 0555 ) ;
if ( ino = = NULL )
return - ENOSPC ;
inode = autofs4_get_inode ( dir - > i_sb , ino ) ;
d_instantiate ( dentry , inode ) ;
if ( dir = = dir - > i_sb - > s_root - > d_inode )
dentry - > d_op = & autofs4_root_dentry_operations ;
else
dentry - > d_op = & autofs4_dentry_operations ;
dentry - > d_fsdata = ino ;
ino - > dentry = dget ( dentry ) ;
2006-03-27 13:14:46 +04:00
atomic_inc ( & ino - > count ) ;
p_ino = autofs4_dentry_ino ( dentry - > d_parent ) ;
if ( p_ino & & dentry - > d_parent ! = dentry )
atomic_inc ( & p_ino - > count ) ;
2005-04-17 02:20:36 +04:00
ino - > inode = inode ;
dir - > i_nlink + + ;
dir - > i_mtime = CURRENT_TIME ;
return 0 ;
}
/* Get/set timeout ioctl() operation */
static inline int autofs4_get_set_timeout ( struct autofs_sb_info * sbi ,
unsigned long __user * p )
{
int rv ;
unsigned long ntimeout ;
if ( ( rv = get_user ( ntimeout , p ) ) | |
( rv = put_user ( sbi - > exp_timeout / HZ , p ) ) )
return rv ;
if ( ntimeout > ULONG_MAX / HZ )
sbi - > exp_timeout = 0 ;
else
sbi - > exp_timeout = ntimeout * HZ ;
return 0 ;
}
/* Return protocol version */
static inline int autofs4_get_protover ( struct autofs_sb_info * sbi , int __user * p )
{
return put_user ( sbi - > version , p ) ;
}
/* Return protocol sub version */
static inline int autofs4_get_protosubver ( struct autofs_sb_info * sbi , int __user * p )
{
return put_user ( sbi - > sub_version , p ) ;
}
/*
* Tells the daemon whether we need to reghost or not . Also , clears
* the reghost_needed flag .
*/
static inline int autofs4_ask_reghost ( struct autofs_sb_info * sbi , int __user * p )
{
int status ;
DPRINTK ( " returning %d " , sbi - > needs_reghost ) ;
status = put_user ( sbi - > needs_reghost , p ) ;
if ( status )
return status ;
sbi - > needs_reghost = 0 ;
return 0 ;
}
/*
* Enable / Disable reghosting ioctl ( ) operation
*/
static inline int autofs4_toggle_reghost ( struct autofs_sb_info * sbi , int __user * p )
{
int status ;
int val ;
status = get_user ( val , p ) ;
DPRINTK ( " reghost = %d " , val ) ;
if ( status )
return status ;
/* turn on/off reghosting, with the val */
sbi - > reghost_enabled = val ;
return 0 ;
}
/*
* Tells the daemon whether it can umount the autofs mount .
*/
static inline int autofs4_ask_umount ( struct vfsmount * mnt , int __user * p )
{
int status = 0 ;
2006-03-27 13:14:51 +04:00
if ( may_umount ( mnt ) )
2005-04-17 02:20:36 +04:00
status = 1 ;
DPRINTK ( " returning %d " , status ) ;
status = put_user ( status , p ) ;
return status ;
}
/* Identify autofs4_dentries - this is so we can tell if there's
an extra dentry refcount or not . We only hold a refcount on the
dentry if its non - negative ( ie , d_inode ! = NULL )
*/
int is_autofs4_dentry ( struct dentry * dentry )
{
return dentry & & dentry - > d_inode & &
( dentry - > d_op = = & autofs4_root_dentry_operations | |
dentry - > d_op = = & autofs4_dentry_operations ) & &
dentry - > d_fsdata ! = NULL ;
}
/*
* ioctl ( ) ' s on the root directory is the chief method for the daemon to
* generate kernel reactions
*/
static int autofs4_root_ioctl ( struct inode * inode , struct file * filp ,
unsigned int cmd , unsigned long arg )
{
struct autofs_sb_info * sbi = autofs4_sbi ( inode - > i_sb ) ;
void __user * p = ( void __user * ) arg ;
DPRINTK ( " cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u " ,
cmd , arg , sbi , process_group ( current ) ) ;
if ( _IOC_TYPE ( cmd ) ! = _IOC_TYPE ( AUTOFS_IOC_FIRST ) | |
_IOC_NR ( cmd ) - _IOC_NR ( AUTOFS_IOC_FIRST ) > = AUTOFS_IOC_COUNT )
return - ENOTTY ;
if ( ! autofs4_oz_mode ( sbi ) & & ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
switch ( cmd ) {
case AUTOFS_IOC_READY : /* Wait queue: go ahead and retry */
return autofs4_wait_release ( sbi , ( autofs_wqt_t ) arg , 0 ) ;
case AUTOFS_IOC_FAIL : /* Wait queue: fail with ENOENT */
return autofs4_wait_release ( sbi , ( autofs_wqt_t ) arg , - ENOENT ) ;
case AUTOFS_IOC_CATATONIC : /* Enter catatonic mode (daemon shutdown) */
autofs4_catatonic_mode ( sbi ) ;
return 0 ;
case AUTOFS_IOC_PROTOVER : /* Get protocol version */
return autofs4_get_protover ( sbi , p ) ;
case AUTOFS_IOC_PROTOSUBVER : /* Get protocol sub version */
return autofs4_get_protosubver ( sbi , p ) ;
case AUTOFS_IOC_SETTIMEOUT :
return autofs4_get_set_timeout ( sbi , p ) ;
case AUTOFS_IOC_TOGGLEREGHOST :
return autofs4_toggle_reghost ( sbi , p ) ;
case AUTOFS_IOC_ASKREGHOST :
return autofs4_ask_reghost ( sbi , p ) ;
case AUTOFS_IOC_ASKUMOUNT :
return autofs4_ask_umount ( filp - > f_vfsmnt , p ) ;
/* return a single thing to expire */
case AUTOFS_IOC_EXPIRE :
return autofs4_expire_run ( inode - > i_sb , filp - > f_vfsmnt , sbi , p ) ;
/* same as above, but can send multiple expires through pipe */
case AUTOFS_IOC_EXPIRE_MULTI :
return autofs4_expire_multi ( inode - > i_sb , filp - > f_vfsmnt , sbi , p ) ;
default :
return - ENOSYS ;
}
}