2005-04-17 02:20:36 +04:00
/* -*- c -*- --------------------------------------------------------------- *
*
* linux / fs / autofs / inode . c
*
* Copyright 1997 - 1998 Transmeta Corporation - - All Rights Reserved
2006-03-27 13:14:54 +04:00
* Copyright 2005 - 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 .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/file.h>
2006-03-27 13:14:49 +04:00
# include <linux/seq_file.h>
2005-04-17 02:20:36 +04:00
# include <linux/pagemap.h>
# include <linux/parser.h>
# include <linux/bitops.h>
2006-09-24 19:13:19 +04:00
# include <linux/magic.h>
2005-04-17 02:20:36 +04:00
# include "autofs_i.h"
# include <linux/module.h>
struct autofs_info * autofs4_init_ino ( struct autofs_info * ino ,
2011-01-17 01:20:23 +03:00
struct autofs_sb_info * sbi )
2005-04-17 02:20:36 +04:00
{
int reinit = 1 ;
if ( ino = = NULL ) {
reinit = 0 ;
ino = kmalloc ( sizeof ( * ino ) , GFP_KERNEL ) ;
}
if ( ino = = NULL )
return NULL ;
2008-07-24 08:30:12 +04:00
if ( ! reinit ) {
ino - > flags = 0 ;
ino - > dentry = NULL ;
INIT_LIST_HEAD ( & ino - > active ) ;
2009-12-16 03:45:42 +03:00
ino - > active_count = 0 ;
2008-07-24 08:30:12 +04:00
INIT_LIST_HEAD ( & ino - > expiring ) ;
atomic_set ( & ino - > count , 0 ) ;
}
2007-02-21 00:58:10 +03:00
2008-10-16 09:02:52 +04:00
ino - > uid = 0 ;
ino - > gid = 0 ;
2005-04-17 02:20:36 +04:00
ino - > last_used = jiffies ;
ino - > sbi = sbi ;
return ino ;
}
void autofs4_free_ino ( struct autofs_info * ino )
{
if ( ino - > dentry ) {
ino - > dentry - > d_fsdata = NULL ;
ino - > dentry = NULL ;
}
kfree ( ino ) ;
}
2006-10-11 12:22:15 +04:00
void autofs4_kill_sb ( struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
struct autofs_sb_info * sbi = autofs4_sbi ( sb ) ;
2006-11-14 13:03:29 +03:00
/*
* In the event of a failure in get_sb_nodev the superblock
* info is not present so nothing else has been setup , so
2006-12-07 07:39:38 +03:00
* just call kill_anon_super when we are called from
* deactivate_super .
2006-11-14 13:03:29 +03:00
*/
if ( ! sbi )
2006-12-07 07:39:38 +03:00
goto out_kill_sb ;
2006-11-14 13:03:29 +03:00
2008-07-24 08:30:17 +04:00
/* Free wait queues, close pipe */
autofs4_catatonic_mode ( sbi ) ;
2005-04-17 02:20:36 +04:00
2007-02-21 00:58:10 +03:00
sb - > s_fs_info = NULL ;
2005-04-17 02:20:36 +04:00
kfree ( sbi ) ;
2006-12-07 07:39:38 +03:00
out_kill_sb :
2005-04-17 02:20:36 +04:00
DPRINTK ( " shutting down " ) ;
2010-01-24 08:28:52 +03:00
kill_litter_super ( sb ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-27 13:14:49 +04:00
static int autofs4_show_options ( struct seq_file * m , struct vfsmount * mnt )
{
struct autofs_sb_info * sbi = autofs4_sbi ( mnt - > mnt_sb ) ;
2008-02-08 15:21:37 +03:00
struct inode * root_inode = mnt - > mnt_sb - > s_root - > d_inode ;
2006-03-27 13:14:49 +04:00
if ( ! sbi )
return 0 ;
seq_printf ( m , " ,fd=%d " , sbi - > pipefd ) ;
2008-02-08 15:21:37 +03:00
if ( root_inode - > i_uid ! = 0 )
seq_printf ( m , " ,uid=%u " , root_inode - > i_uid ) ;
if ( root_inode - > i_gid ! = 0 )
seq_printf ( m , " ,gid=%u " , root_inode - > i_gid ) ;
2006-03-27 13:14:49 +04:00
seq_printf ( m , " ,pgrp=%d " , sbi - > oz_pgrp ) ;
seq_printf ( m , " ,timeout=%lu " , sbi - > exp_timeout / HZ ) ;
seq_printf ( m , " ,minproto=%d " , sbi - > min_proto ) ;
seq_printf ( m , " ,maxproto=%d " , sbi - > max_proto ) ;
2009-01-07 01:42:08 +03:00
if ( autofs_type_offset ( sbi - > type ) )
2006-03-27 13:14:54 +04:00
seq_printf ( m , " ,offset " ) ;
2009-01-07 01:42:08 +03:00
else if ( autofs_type_direct ( sbi - > type ) )
2006-03-27 13:14:54 +04:00
seq_printf ( m , " ,direct " ) ;
else
seq_printf ( m , " ,indirect " ) ;
2006-03-27 13:14:49 +04:00
return 0 ;
}
2011-01-17 08:47:38 +03:00
static void autofs4_evict_inode ( struct inode * inode )
{
end_writeback ( inode ) ;
kfree ( inode - > i_private ) ;
}
2007-02-12 11:55:41 +03:00
static const struct super_operations autofs4_sops = {
2005-04-17 02:20:36 +04:00
. statfs = simple_statfs ,
2006-03-27 13:14:49 +04:00
. show_options = autofs4_show_options ,
2011-01-17 08:47:38 +03:00
. evict_inode = autofs4_evict_inode ,
2005-04-17 02:20:36 +04:00
} ;
2006-03-27 13:14:54 +04:00
enum { Opt_err , Opt_fd , Opt_uid , Opt_gid , Opt_pgrp , Opt_minproto , Opt_maxproto ,
Opt_indirect , Opt_direct , Opt_offset } ;
2005-04-17 02:20:36 +04:00
2008-10-13 13:46:57 +04:00
static const match_table_t tokens = {
2005-04-17 02:20:36 +04:00
{ Opt_fd , " fd=%u " } ,
{ Opt_uid , " uid=%u " } ,
{ Opt_gid , " gid=%u " } ,
{ Opt_pgrp , " pgrp=%u " } ,
{ Opt_minproto , " minproto=%u " } ,
{ Opt_maxproto , " maxproto=%u " } ,
2006-03-27 13:14:54 +04:00
{ Opt_indirect , " indirect " } ,
{ Opt_direct , " direct " } ,
{ Opt_offset , " offset " } ,
2005-04-17 02:20:36 +04:00
{ Opt_err , NULL }
} ;
static int parse_options ( char * options , int * pipefd , uid_t * uid , gid_t * gid ,
2007-05-11 09:23:06 +04:00
pid_t * pgrp , unsigned int * type , int * minproto , int * maxproto )
2005-04-17 02:20:36 +04:00
{
char * p ;
substring_t args [ MAX_OPT_ARGS ] ;
int option ;
2008-11-14 02:38:46 +03:00
* uid = current_uid ( ) ;
* gid = current_gid ( ) ;
2007-10-19 10:39:46 +04:00
* pgrp = task_pgrp_nr ( current ) ;
2005-04-17 02:20:36 +04:00
* minproto = AUTOFS_MIN_PROTO_VERSION ;
* maxproto = AUTOFS_MAX_PROTO_VERSION ;
* pipefd = - 1 ;
if ( ! options )
return 1 ;
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
switch ( token ) {
case Opt_fd :
if ( match_int ( args , pipefd ) )
return 1 ;
break ;
case Opt_uid :
if ( match_int ( args , & option ) )
return 1 ;
* uid = option ;
break ;
case Opt_gid :
if ( match_int ( args , & option ) )
return 1 ;
* gid = option ;
break ;
case Opt_pgrp :
if ( match_int ( args , & option ) )
return 1 ;
* pgrp = option ;
break ;
case Opt_minproto :
if ( match_int ( args , & option ) )
return 1 ;
* minproto = option ;
break ;
case Opt_maxproto :
if ( match_int ( args , & option ) )
return 1 ;
* maxproto = option ;
break ;
2006-03-27 13:14:54 +04:00
case Opt_indirect :
2009-01-07 01:42:08 +03:00
set_autofs_type_indirect ( type ) ;
2006-03-27 13:14:54 +04:00
break ;
case Opt_direct :
2009-01-07 01:42:08 +03:00
set_autofs_type_direct ( type ) ;
2006-03-27 13:14:54 +04:00
break ;
case Opt_offset :
2009-01-07 01:42:08 +03:00
set_autofs_type_offset ( type ) ;
2006-03-27 13:14:54 +04:00
break ;
2005-04-17 02:20:36 +04:00
default :
return 1 ;
}
}
return ( * pipefd < 0 ) ;
}
int autofs4_fill_super ( struct super_block * s , void * data , int silent )
{
struct inode * root_inode ;
struct dentry * root ;
struct file * pipe ;
int pipefd ;
struct autofs_sb_info * sbi ;
struct autofs_info * ino ;
2007-10-17 10:26:44 +04:00
sbi = kzalloc ( sizeof ( * sbi ) , GFP_KERNEL ) ;
2007-05-11 09:23:06 +04:00
if ( ! sbi )
2005-04-17 02:20:36 +04:00
goto fail_unlock ;
DPRINTK ( " starting up, sbi = %p " , sbi ) ;
s - > s_fs_info = sbi ;
sbi - > magic = AUTOFS_SBI_MAGIC ;
2006-03-27 13:14:49 +04:00
sbi - > pipefd = - 1 ;
2006-11-14 13:03:29 +03:00
sbi - > pipe = NULL ;
sbi - > catatonic = 1 ;
2005-04-17 02:20:36 +04:00
sbi - > exp_timeout = 0 ;
2007-10-19 10:39:46 +04:00
sbi - > oz_pgrp = task_pgrp_nr ( current ) ;
2005-04-17 02:20:36 +04:00
sbi - > sb = s ;
sbi - > version = 0 ;
sbi - > sub_version = 0 ;
2009-01-07 01:42:08 +03:00
set_autofs_type_indirect ( & sbi - > type ) ;
2006-03-27 13:14:49 +04:00
sbi - > min_proto = 0 ;
sbi - > max_proto = 0 ;
2006-03-23 14:00:41 +03:00
mutex_init ( & sbi - > wq_mutex ) ;
2005-05-01 19:59:17 +04:00
spin_lock_init ( & sbi - > fs_lock ) ;
2005-04-17 02:20:36 +04:00
sbi - > queues = NULL ;
2008-07-24 08:30:09 +04:00
spin_lock_init ( & sbi - > lookup_lock ) ;
2008-07-24 08:30:12 +04:00
INIT_LIST_HEAD ( & sbi - > active_list ) ;
2008-07-24 08:30:09 +04:00
INIT_LIST_HEAD ( & sbi - > expiring_list ) ;
2005-04-17 02:20:36 +04:00
s - > s_blocksize = 1024 ;
s - > s_blocksize_bits = 10 ;
s - > s_magic = AUTOFS_SUPER_MAGIC ;
s - > s_op = & autofs4_sops ;
2011-01-15 13:51:57 +03:00
s - > s_d_op = & autofs4_dentry_operations ;
2005-04-17 02:20:36 +04:00
s - > s_time_gran = 1 ;
/*
* Get the root inode and dentry , but defer checking for errors .
*/
2011-01-17 01:20:23 +03:00
ino = autofs4_init_ino ( NULL , sbi ) ;
2005-04-17 02:20:36 +04:00
if ( ! ino )
goto fail_free ;
2011-01-17 01:20:23 +03:00
root_inode = autofs4_get_inode ( s , ino , S_IFDIR | 0755 ) ;
2005-04-17 02:20:36 +04:00
if ( ! root_inode )
2006-03-27 13:14:54 +04:00
goto fail_ino ;
2005-04-17 02:20:36 +04:00
root = d_alloc_root ( root_inode ) ;
if ( ! root )
goto fail_iput ;
2006-03-27 13:14:54 +04:00
pipe = NULL ;
root - > d_fsdata = ino ;
2005-04-17 02:20:36 +04:00
/* Can this call block? */
2007-05-11 09:23:06 +04:00
if ( parse_options ( data , & pipefd , & root_inode - > i_uid , & root_inode - > i_gid ,
& sbi - > oz_pgrp , & sbi - > type , & sbi - > min_proto ,
& sbi - > max_proto ) ) {
2005-04-17 02:20:36 +04:00
printk ( " autofs: called with bogus options \n " ) ;
goto fail_dput ;
}
2011-01-15 13:51:57 +03:00
if ( autofs_type_trigger ( sbi - > type ) )
2011-01-14 21:46:03 +03:00
__managed_dentry_set_managed ( root ) ;
2011-01-14 21:45:58 +03:00
2006-03-27 13:14:54 +04:00
root_inode - > i_fop = & autofs4_root_operations ;
2011-01-14 21:46:14 +03:00
root_inode - > i_op = & autofs4_dir_inode_operations ;
2006-03-27 13:14:54 +04:00
2005-04-17 02:20:36 +04:00
/* Couldn't this be tested earlier? */
2006-03-27 13:14:49 +04:00
if ( sbi - > max_proto < AUTOFS_MIN_PROTO_VERSION | |
sbi - > min_proto > AUTOFS_MAX_PROTO_VERSION ) {
2005-04-17 02:20:36 +04:00
printk ( " autofs: kernel does not match daemon version "
" daemon (%d, %d) kernel (%d, %d) \n " ,
2006-03-27 13:14:49 +04:00
sbi - > min_proto , sbi - > max_proto ,
2005-04-17 02:20:36 +04:00
AUTOFS_MIN_PROTO_VERSION , AUTOFS_MAX_PROTO_VERSION ) ;
goto fail_dput ;
}
2006-03-27 13:14:49 +04:00
/* Establish highest kernel protocol version */
if ( sbi - > max_proto > AUTOFS_MAX_PROTO_VERSION )
sbi - > version = AUTOFS_MAX_PROTO_VERSION ;
else
sbi - > version = sbi - > max_proto ;
2005-04-17 02:20:36 +04:00
sbi - > sub_version = AUTOFS_PROTO_SUBVERSION ;
DPRINTK ( " pipe fd = %d, pgrp = %u " , pipefd , sbi - > oz_pgrp ) ;
pipe = fget ( pipefd ) ;
2007-05-11 09:23:06 +04:00
if ( ! pipe ) {
2005-04-17 02:20:36 +04:00
printk ( " autofs: could not open pipe file descriptor \n " ) ;
goto fail_dput ;
}
2007-05-11 09:23:06 +04:00
if ( ! pipe - > f_op | | ! pipe - > f_op - > write )
2005-04-17 02:20:36 +04:00
goto fail_fput ;
sbi - > pipe = pipe ;
2006-03-27 13:14:49 +04:00
sbi - > pipefd = pipefd ;
2006-11-14 13:03:29 +03:00
sbi - > catatonic = 0 ;
2005-04-17 02:20:36 +04:00
/*
* Success ! Install the root dentry now to indicate completion .
*/
s - > s_root = root ;
return 0 ;
/*
* Failure . . . clean up .
*/
fail_fput :
printk ( " autofs: pipe file descriptor does not contain proper ops \n " ) ;
fput ( pipe ) ;
/* fall through */
fail_dput :
dput ( root ) ;
goto fail_free ;
fail_iput :
printk ( " autofs: get root dentry failed \n " ) ;
iput ( root_inode ) ;
2006-03-27 13:14:54 +04:00
fail_ino :
kfree ( ino ) ;
2005-04-17 02:20:36 +04:00
fail_free :
kfree ( sbi ) ;
2006-11-14 13:03:29 +03:00
s - > s_fs_info = NULL ;
2005-04-17 02:20:36 +04:00
fail_unlock :
return - EINVAL ;
}
struct inode * autofs4_get_inode ( struct super_block * sb ,
2011-01-17 01:20:23 +03:00
struct autofs_info * inf ,
mode_t mode )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = new_inode ( sb ) ;
if ( inode = = NULL )
return NULL ;
2011-01-17 01:20:23 +03:00
inode - > i_mode = mode ;
2005-04-17 02:20:36 +04:00
if ( sb - > s_root ) {
inode - > i_uid = sb - > s_root - > d_inode - > i_uid ;
inode - > i_gid = sb - > s_root - > d_inode - > i_gid ;
}
inode - > i_atime = inode - > i_mtime = inode - > i_ctime = CURRENT_TIME ;
2010-10-23 19:19:54 +04:00
inode - > i_ino = get_next_ino ( ) ;
2005-04-17 02:20:36 +04:00
2011-01-17 01:20:23 +03:00
if ( S_ISDIR ( mode ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_nlink = 2 ;
inode - > i_op = & autofs4_dir_inode_operations ;
inode - > i_fop = & autofs4_dir_operations ;
2011-01-17 01:20:23 +03:00
} else if ( S_ISLNK ( mode ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_op = & autofs4_symlink_inode_operations ;
}
return inode ;
}