2005-04-17 02:20:36 +04:00
/*
* net / sunrpc / rpc_pipe . c
*
* Userland / kernel interface for rpcauth_gss .
* Code shamelessly plagiarized from fs / nfsd / nfsctl . c
2005-09-02 10:59:25 +04:00
* and fs / sysfs / inode . c
2005-04-17 02:20:36 +04:00
*
* Copyright ( c ) 2002 , Trond Myklebust < trond . myklebust @ fys . uio . no >
*
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/pagemap.h>
# include <linux/mount.h>
# include <linux/namei.h>
2007-06-08 06:44:34 +04:00
# include <linux/fsnotify.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <asm/ioctls.h>
# include <linux/fs.h>
# include <linux/poll.h>
# include <linux/wait.h>
# include <linux/seq_file.h>
# include <linux/sunrpc/clnt.h>
# include <linux/workqueue.h>
# include <linux/sunrpc/rpc_pipe_fs.h>
2009-08-09 23:14:30 +04:00
# include <linux/sunrpc/cache.h>
2011-12-26 16:39:04 +04:00
# include <linux/nsproxy.h>
2011-12-26 16:39:13 +04:00
# include <linux/notifier.h>
2011-12-26 16:39:04 +04:00
# include "netns.h"
2011-12-26 16:39:13 +04:00
# include "sunrpc.h"
2005-04-17 02:20:36 +04:00
2010-07-25 01:48:30 +04:00
static struct vfsmount * rpc_mnt __read_mostly ;
2005-04-17 02:20:36 +04:00
static int rpc_mount_count ;
static struct file_system_type rpc_pipe_fs_type ;
2006-12-07 07:33:20 +03:00
static struct kmem_cache * rpc_inode_cachep __read_mostly ;
2005-04-17 02:20:36 +04:00
# define RPC_UPCALL_TIMEOUT (30*HZ)
2011-12-26 16:39:13 +04:00
static BLOCKING_NOTIFIER_HEAD ( rpc_pipefs_notifier_list ) ;
int rpc_pipefs_notifier_register ( struct notifier_block * nb )
{
return blocking_notifier_chain_cond_register ( & rpc_pipefs_notifier_list , nb ) ;
}
EXPORT_SYMBOL_GPL ( rpc_pipefs_notifier_register ) ;
void rpc_pipefs_notifier_unregister ( struct notifier_block * nb )
{
blocking_notifier_chain_unregister ( & rpc_pipefs_notifier_list , nb ) ;
}
EXPORT_SYMBOL_GPL ( rpc_pipefs_notifier_unregister ) ;
2006-02-01 20:18:44 +03:00
static void rpc_purge_list ( struct rpc_inode * rpci , struct list_head * head ,
void ( * destroy_msg ) ( struct rpc_pipe_msg * ) , int err )
2005-04-17 02:20:36 +04:00
{
struct rpc_pipe_msg * msg ;
2006-02-01 20:18:44 +03:00
if ( list_empty ( head ) )
return ;
do {
2005-11-26 01:10:11 +03:00
msg = list_entry ( head - > next , struct rpc_pipe_msg , list ) ;
2010-09-13 03:55:25 +04:00
list_del_init ( & msg - > list ) ;
2005-04-17 02:20:36 +04:00
msg - > errno = err ;
2005-11-26 01:10:11 +03:00
destroy_msg ( msg ) ;
2006-02-01 20:18:44 +03:00
} while ( ! list_empty ( head ) ) ;
2005-04-17 02:20:36 +04:00
wake_up ( & rpci - > waitq ) ;
}
static void
2006-11-22 17:55:48 +03:00
rpc_timeout_upcall_queue ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-02-01 20:18:44 +03:00
LIST_HEAD ( free_list ) ;
2006-11-22 17:55:48 +03:00
struct rpc_inode * rpci =
container_of ( work , struct rpc_inode , queue_timeout . work ) ;
2005-04-17 02:20:36 +04:00
struct inode * inode = & rpci - > vfs_inode ;
2006-02-01 20:18:44 +03:00
void ( * destroy_msg ) ( struct rpc_pipe_msg * ) ;
2005-04-17 02:20:36 +04:00
2006-02-01 20:18:44 +03:00
spin_lock ( & inode - > i_lock ) ;
if ( rpci - > ops = = NULL ) {
spin_unlock ( & inode - > i_lock ) ;
return ;
}
destroy_msg = rpci - > ops - > destroy_msg ;
if ( rpci - > nreaders = = 0 ) {
list_splice_init ( & rpci - > pipe , & free_list ) ;
rpci - > pipelen = 0 ;
}
spin_unlock ( & inode - > i_lock ) ;
rpc_purge_list ( rpci , & free_list , destroy_msg , - ETIMEDOUT ) ;
2005-04-17 02:20:36 +04:00
}
2011-09-23 05:50:10 +04:00
ssize_t rpc_pipe_generic_upcall ( struct file * filp , struct rpc_pipe_msg * msg ,
char __user * dst , size_t buflen )
{
char * data = ( char * ) msg - > data + msg - > copied ;
size_t mlen = min ( msg - > len - msg - > copied , buflen ) ;
unsigned long left ;
left = copy_to_user ( dst , data , mlen ) ;
if ( left = = mlen ) {
msg - > errno = - EFAULT ;
return - EFAULT ;
}
mlen - = left ;
msg - > copied + = mlen ;
msg - > errno = 0 ;
return mlen ;
}
EXPORT_SYMBOL_GPL ( rpc_pipe_generic_upcall ) ;
2007-11-06 21:06:03 +03:00
/**
2010-02-15 09:35:47 +03:00
* rpc_queue_upcall - queue an upcall message to userspace
2007-11-06 21:06:03 +03:00
* @ inode : inode of upcall pipe on which to queue given message
* @ msg : message to queue
*
* Call with an @ inode created by rpc_mkpipe ( ) to queue an upcall .
* A userspace process may then later read the upcall by performing a
* read on an open file for this inode . It is up to the caller to
* initialize the fields of @ msg ( other than @ msg - > list ) appropriately .
*/
2005-04-17 02:20:36 +04:00
int
rpc_queue_upcall ( struct inode * inode , struct rpc_pipe_msg * msg )
{
struct rpc_inode * rpci = RPC_I ( inode ) ;
2005-10-28 06:12:46 +04:00
int res = - EPIPE ;
2005-04-17 02:20:36 +04:00
2006-02-01 20:18:44 +03:00
spin_lock ( & inode - > i_lock ) ;
2005-10-28 06:12:46 +04:00
if ( rpci - > ops = = NULL )
goto out ;
2005-04-17 02:20:36 +04:00
if ( rpci - > nreaders ) {
list_add_tail ( & msg - > list , & rpci - > pipe ) ;
rpci - > pipelen + = msg - > len ;
2005-10-28 06:12:46 +04:00
res = 0 ;
2005-04-17 02:20:36 +04:00
} else if ( rpci - > flags & RPC_PIPE_WAIT_FOR_OPEN ) {
if ( list_empty ( & rpci - > pipe ) )
2006-03-20 21:44:08 +03:00
queue_delayed_work ( rpciod_workqueue ,
& rpci - > queue_timeout ,
2005-04-17 02:20:36 +04:00
RPC_UPCALL_TIMEOUT ) ;
list_add_tail ( & msg - > list , & rpci - > pipe ) ;
rpci - > pipelen + = msg - > len ;
2005-10-28 06:12:46 +04:00
res = 0 ;
}
out :
2006-02-01 20:18:44 +03:00
spin_unlock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
wake_up ( & rpci - > waitq ) ;
return res ;
}
2008-12-23 23:21:31 +03:00
EXPORT_SYMBOL_GPL ( rpc_queue_upcall ) ;
2005-04-17 02:20:36 +04:00
2005-10-28 06:12:46 +04:00
static inline void
rpc_inode_setowner ( struct inode * inode , void * private )
{
RPC_I ( inode ) - > private = private ;
}
2005-04-17 02:20:36 +04:00
static void
rpc_close_pipes ( struct inode * inode )
{
struct rpc_inode * rpci = RPC_I ( inode ) ;
2009-08-09 23:14:15 +04:00
const struct rpc_pipe_ops * ops ;
2008-12-24 00:09:47 +03:00
int need_release ;
2005-04-17 02:20:36 +04:00
2006-01-10 02:59:24 +03:00
mutex_lock ( & inode - > i_mutex ) ;
2006-02-01 20:18:44 +03:00
ops = rpci - > ops ;
if ( ops ! = NULL ) {
LIST_HEAD ( free_list ) ;
spin_lock ( & inode - > i_lock ) ;
2008-12-24 00:09:47 +03:00
need_release = rpci - > nreaders ! = 0 | | rpci - > nwriters ! = 0 ;
2005-04-17 02:20:36 +04:00
rpci - > nreaders = 0 ;
2006-02-01 20:18:44 +03:00
list_splice_init ( & rpci - > in_upcall , & free_list ) ;
list_splice_init ( & rpci - > pipe , & free_list ) ;
rpci - > pipelen = 0 ;
2005-04-17 02:20:36 +04:00
rpci - > ops = NULL ;
2006-02-01 20:18:44 +03:00
spin_unlock ( & inode - > i_lock ) ;
rpc_purge_list ( rpci , & free_list , ops - > destroy_msg , - EPIPE ) ;
rpci - > nwriters = 0 ;
2008-12-24 00:09:47 +03:00
if ( need_release & & ops - > release_pipe )
2006-02-01 20:18:44 +03:00
ops - > release_pipe ( inode ) ;
2007-08-07 23:33:01 +04:00
cancel_delayed_work_sync ( & rpci - > queue_timeout ) ;
2005-04-17 02:20:36 +04:00
}
2005-10-28 06:12:46 +04:00
rpc_inode_setowner ( inode , NULL ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
static struct inode *
rpc_alloc_inode ( struct super_block * sb )
{
struct rpc_inode * rpci ;
2006-12-07 07:33:17 +03:00
rpci = ( struct rpc_inode * ) kmem_cache_alloc ( rpc_inode_cachep , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpci )
return NULL ;
return & rpci - > vfs_inode ;
}
static void
2011-01-07 09:49:49 +03:00
rpc_i_callback ( struct rcu_head * head )
2005-04-17 02:20:36 +04:00
{
2011-01-07 09:49:49 +03:00
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( rpc_inode_cachep , RPC_I ( inode ) ) ;
}
2011-01-07 09:49:49 +03:00
static void
rpc_destroy_inode ( struct inode * inode )
{
call_rcu ( & inode - > i_rcu , rpc_i_callback ) ;
}
2005-04-17 02:20:36 +04:00
static int
rpc_pipe_open ( struct inode * inode , struct file * filp )
{
struct rpc_inode * rpci = RPC_I ( inode ) ;
2008-12-24 00:08:32 +03:00
int first_open ;
2005-04-17 02:20:36 +04:00
int res = - ENXIO ;
2006-01-10 02:59:24 +03:00
mutex_lock ( & inode - > i_mutex ) ;
2008-12-24 00:08:32 +03:00
if ( rpci - > ops = = NULL )
goto out ;
first_open = rpci - > nreaders = = 0 & & rpci - > nwriters = = 0 ;
if ( first_open & & rpci - > ops - > open_pipe ) {
res = rpci - > ops - > open_pipe ( inode ) ;
if ( res )
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-12-24 00:08:32 +03:00
if ( filp - > f_mode & FMODE_READ )
rpci - > nreaders + + ;
if ( filp - > f_mode & FMODE_WRITE )
rpci - > nwriters + + ;
res = 0 ;
out :
2006-01-10 02:59:24 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static int
rpc_pipe_release ( struct inode * inode , struct file * filp )
{
2006-01-03 11:55:36 +03:00
struct rpc_inode * rpci = RPC_I ( inode ) ;
2005-04-17 02:20:36 +04:00
struct rpc_pipe_msg * msg ;
2008-12-24 00:09:47 +03:00
int last_close ;
2005-04-17 02:20:36 +04:00
2006-01-10 02:59:24 +03:00
mutex_lock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( rpci - > ops = = NULL )
goto out ;
2010-09-05 05:52:53 +04:00
msg = filp - > private_data ;
2005-04-17 02:20:36 +04:00
if ( msg ! = NULL ) {
2006-02-01 20:18:44 +03:00
spin_lock ( & inode - > i_lock ) ;
2005-12-20 01:11:22 +03:00
msg - > errno = - EAGAIN ;
2010-09-13 03:55:25 +04:00
list_del_init ( & msg - > list ) ;
2006-02-01 20:18:44 +03:00
spin_unlock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
rpci - > ops - > destroy_msg ( msg ) ;
}
if ( filp - > f_mode & FMODE_WRITE )
rpci - > nwriters - - ;
2006-02-01 20:18:44 +03:00
if ( filp - > f_mode & FMODE_READ ) {
2005-04-17 02:20:36 +04:00
rpci - > nreaders - - ;
2006-02-01 20:18:44 +03:00
if ( rpci - > nreaders = = 0 ) {
LIST_HEAD ( free_list ) ;
spin_lock ( & inode - > i_lock ) ;
list_splice_init ( & rpci - > pipe , & free_list ) ;
rpci - > pipelen = 0 ;
spin_unlock ( & inode - > i_lock ) ;
rpc_purge_list ( rpci , & free_list ,
rpci - > ops - > destroy_msg , - EAGAIN ) ;
}
}
2008-12-24 00:09:47 +03:00
last_close = rpci - > nwriters = = 0 & & rpci - > nreaders = = 0 ;
if ( last_close & & rpci - > ops - > release_pipe )
2005-04-17 02:20:36 +04:00
rpci - > ops - > release_pipe ( inode ) ;
out :
2006-01-10 02:59:24 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static ssize_t
rpc_pipe_read ( struct file * filp , char __user * buf , size_t len , loff_t * offset )
{
2006-12-08 13:37:42 +03:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
struct rpc_inode * rpci = RPC_I ( inode ) ;
struct rpc_pipe_msg * msg ;
int res = 0 ;
2006-01-10 02:59:24 +03:00
mutex_lock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( rpci - > ops = = NULL ) {
res = - EPIPE ;
goto out_unlock ;
}
msg = filp - > private_data ;
if ( msg = = NULL ) {
2006-02-01 20:18:44 +03:00
spin_lock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
if ( ! list_empty ( & rpci - > pipe ) ) {
msg = list_entry ( rpci - > pipe . next ,
struct rpc_pipe_msg ,
list ) ;
list_move ( & msg - > list , & rpci - > in_upcall ) ;
rpci - > pipelen - = msg - > len ;
filp - > private_data = msg ;
msg - > copied = 0 ;
}
2006-02-01 20:18:44 +03:00
spin_unlock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
if ( msg = = NULL )
goto out_unlock ;
}
/* NOTE: it is up to the callback to update msg->copied */
res = rpci - > ops - > upcall ( filp , msg , buf , len ) ;
if ( res < 0 | | msg - > len = = msg - > copied ) {
filp - > private_data = NULL ;
2006-02-01 20:18:44 +03:00
spin_lock ( & inode - > i_lock ) ;
2010-09-13 03:55:25 +04:00
list_del_init ( & msg - > list ) ;
2006-02-01 20:18:44 +03:00
spin_unlock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
rpci - > ops - > destroy_msg ( msg ) ;
}
out_unlock :
2006-01-10 02:59:24 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static ssize_t
rpc_pipe_write ( struct file * filp , const char __user * buf , size_t len , loff_t * offset )
{
2006-12-08 13:37:42 +03:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
struct rpc_inode * rpci = RPC_I ( inode ) ;
int res ;
2006-01-10 02:59:24 +03:00
mutex_lock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
res = - EPIPE ;
if ( rpci - > ops ! = NULL )
res = rpci - > ops - > downcall ( filp , buf , len ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static unsigned int
rpc_pipe_poll ( struct file * filp , struct poll_table_struct * wait )
{
struct rpc_inode * rpci ;
unsigned int mask = 0 ;
2006-12-08 13:37:42 +03:00
rpci = RPC_I ( filp - > f_path . dentry - > d_inode ) ;
2005-04-17 02:20:36 +04:00
poll_wait ( filp , & rpci - > waitq , wait ) ;
mask = POLLOUT | POLLWRNORM ;
if ( rpci - > ops = = NULL )
mask | = POLLERR | POLLHUP ;
2007-11-06 21:05:36 +03:00
if ( filp - > private_data | | ! list_empty ( & rpci - > pipe ) )
2005-04-17 02:20:36 +04:00
mask | = POLLIN | POLLRDNORM ;
return mask ;
}
2010-10-04 23:18:23 +04:00
static long
rpc_pipe_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2010-10-04 23:18:23 +04:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
struct rpc_inode * rpci = RPC_I ( inode ) ;
2005-04-17 02:20:36 +04:00
int len ;
switch ( cmd ) {
case FIONREAD :
2010-10-04 23:18:23 +04:00
spin_lock ( & inode - > i_lock ) ;
if ( rpci - > ops = = NULL ) {
spin_unlock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
return - EPIPE ;
2010-10-04 23:18:23 +04:00
}
2005-04-17 02:20:36 +04:00
len = rpci - > pipelen ;
if ( filp - > private_data ) {
struct rpc_pipe_msg * msg ;
2010-09-05 05:52:53 +04:00
msg = filp - > private_data ;
2005-04-17 02:20:36 +04:00
len + = msg - > len - msg - > copied ;
}
2010-10-04 23:18:23 +04:00
spin_unlock ( & inode - > i_lock ) ;
2005-04-17 02:20:36 +04:00
return put_user ( len , ( int __user * ) arg ) ;
default :
return - EINVAL ;
}
}
2007-02-12 11:55:36 +03:00
static const struct file_operations rpc_pipe_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. llseek = no_llseek ,
. read = rpc_pipe_read ,
. write = rpc_pipe_write ,
. poll = rpc_pipe_poll ,
2010-05-19 17:08:17 +04:00
. unlocked_ioctl = rpc_pipe_ioctl ,
2005-04-17 02:20:36 +04:00
. open = rpc_pipe_open ,
. release = rpc_pipe_release ,
} ;
static int
rpc_show_info ( struct seq_file * m , void * v )
{
struct rpc_clnt * clnt = m - > private ;
seq_printf ( m , " RPC server: %s \n " , clnt - > cl_server ) ;
seq_printf ( m , " service: %s (%d) version %d \n " , clnt - > cl_protname ,
clnt - > cl_prog , clnt - > cl_vers ) ;
2006-08-23 04:06:19 +04:00
seq_printf ( m , " address: %s \n " , rpc_peeraddr2str ( clnt , RPC_DISPLAY_ADDR ) ) ;
seq_printf ( m , " protocol: %s \n " , rpc_peeraddr2str ( clnt , RPC_DISPLAY_PROTO ) ) ;
2007-09-26 22:38:09 +04:00
seq_printf ( m , " port: %s \n " , rpc_peeraddr2str ( clnt , RPC_DISPLAY_PORT ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int
rpc_info_open ( struct inode * inode , struct file * file )
{
2010-09-13 03:55:25 +04:00
struct rpc_clnt * clnt = NULL ;
2005-04-17 02:20:36 +04:00
int ret = single_open ( file , rpc_show_info , NULL ) ;
if ( ! ret ) {
struct seq_file * m = file - > private_data ;
2010-09-13 03:55:25 +04:00
spin_lock ( & file - > f_path . dentry - > d_lock ) ;
if ( ! d_unhashed ( file - > f_path . dentry ) )
clnt = RPC_I ( inode ) - > private ;
if ( clnt ! = NULL & & atomic_inc_not_zero ( & clnt - > cl_count ) ) {
spin_unlock ( & file - > f_path . dentry - > d_lock ) ;
2005-04-17 02:20:36 +04:00
m - > private = clnt ;
} else {
2010-09-13 03:55:25 +04:00
spin_unlock ( & file - > f_path . dentry - > d_lock ) ;
2005-04-17 02:20:36 +04:00
single_release ( inode , file ) ;
ret = - EINVAL ;
}
}
return ret ;
}
static int
rpc_info_release ( struct inode * inode , struct file * file )
{
struct seq_file * m = file - > private_data ;
struct rpc_clnt * clnt = ( struct rpc_clnt * ) m - > private ;
if ( clnt )
rpc_release_client ( clnt ) ;
return single_release ( inode , file ) ;
}
2007-02-12 11:55:36 +03:00
static const struct file_operations rpc_info_operations = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = rpc_info_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = rpc_info_release ,
} ;
/*
* Description of fs contents .
*/
struct rpc_filelist {
2009-08-09 23:14:20 +04:00
const char * name ;
2006-03-28 13:56:41 +04:00
const struct file_operations * i_fop ;
2009-08-09 23:14:16 +04:00
umode_t mode ;
2005-04-17 02:20:36 +04:00
} ;
2006-03-20 21:44:49 +03:00
struct vfsmount * rpc_get_mount ( void )
2005-04-17 02:20:36 +04:00
{
2006-03-20 21:44:49 +03:00
int err ;
2010-07-25 01:48:30 +04:00
err = simple_pin_fs ( & rpc_pipe_fs_type , & rpc_mnt , & rpc_mount_count ) ;
2006-03-20 21:44:49 +03:00
if ( err ! = 0 )
return ERR_PTR ( err ) ;
2010-07-25 01:48:30 +04:00
return rpc_mnt ;
2005-04-17 02:20:36 +04:00
}
2009-08-20 02:12:27 +04:00
EXPORT_SYMBOL_GPL ( rpc_get_mount ) ;
2005-04-17 02:20:36 +04:00
2006-03-20 21:44:49 +03:00
void rpc_put_mount ( void )
2005-04-17 02:20:36 +04:00
{
2010-07-25 01:48:30 +04:00
simple_release_fs ( & rpc_mnt , & rpc_mount_count ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-20 02:12:27 +04:00
EXPORT_SYMBOL_GPL ( rpc_put_mount ) ;
2005-04-17 02:20:36 +04:00
2011-01-07 09:49:23 +03:00
static int rpc_delete_dentry ( const struct dentry * dentry )
2007-06-08 22:14:46 +04:00
{
return 1 ;
}
2009-02-20 09:02:22 +03:00
static const struct dentry_operations rpc_dentry_operations = {
2007-06-08 22:14:46 +04:00
. d_delete = rpc_delete_dentry ,
} ;
2005-04-17 02:20:36 +04:00
static struct inode *
2009-08-09 23:14:16 +04:00
rpc_get_inode ( struct super_block * sb , umode_t mode )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = new_inode ( sb ) ;
if ( ! inode )
return NULL ;
2010-10-23 19:19:54 +04:00
inode - > i_ino = get_next_ino ( ) ;
2005-04-17 02:20:36 +04:00
inode - > i_mode = mode ;
inode - > i_atime = inode - > i_mtime = inode - > i_ctime = CURRENT_TIME ;
2011-07-01 13:43:12 +04:00
switch ( mode & S_IFMT ) {
case S_IFDIR :
inode - > i_fop = & simple_dir_operations ;
inode - > i_op = & simple_dir_inode_operations ;
inc_nlink ( inode ) ;
default :
break ;
2005-04-17 02:20:36 +04:00
}
return inode ;
}
2009-08-09 23:14:17 +04:00
static int __rpc_create_common ( struct inode * dir , struct dentry * dentry ,
umode_t mode ,
const struct file_operations * i_fop ,
void * private )
{
struct inode * inode ;
kernel panic when mount NFSv4
On Tue, 2010-12-14 at 16:58 +0800, Mi Jinlong wrote:
> Hi,
>
> When testing NFSv4 at RHEL6 with kernel 2.6.32, I got a kernel panic
> at NFS client's __rpc_create_common function.
>
> The panic place is:
> rpc_mkpipe
> __rpc_lookup_create() <=== find pipefile *idmap*
> __rpc_mkpipe() <=== pipefile is *idmap*
> __rpc_create_common()
> ****** BUG_ON(!d_unhashed(dentry)); ****** *panic*
>
> It means that the dentry's d_flags have be set DCACHE_UNHASHED,
> but it should not be set here.
>
> Is someone known this bug? or give me some idea?
>
> A reproduce program is append, but it can't reproduce the bug every time.
> the export is: "/nfsroot *(rw,no_root_squash,fsid=0,insecure)"
>
> And the panic message is append.
>
> ============================================================================
> #!/bin/sh
>
> LOOPTOTAL=768
> LOOPCOUNT=0
> ret=0
>
> while [ $LOOPCOUNT -ne $LOOPTOTAL ]
> do
> ((LOOPCOUNT += 1))
> service nfs restart
> /usr/sbin/rpc.idmapd
> mount -t nfs4 127.0.0.1:/ /mnt|| return 1;
> ls -l /var/lib/nfs/rpc_pipefs/nfs/*/
> umount /mnt
> echo $LOOPCOUNT
> done
>
> ===============================================================================
> Code: af 60 01 00 00 89 fa 89 f0 e8 64 cf 89 f0 e8 5c 7c 64 cf 31 c0 8b 5c 24 10 8b
> 74 24 14 8b 7c 24 18 8b 6c 24 1c 83 c4 20 c3 <0f> 0b eb fc 8b 46 28 c7 44 24 08 20
> de ee f0 c7 44 24 04 56 ea
> EIP:[<f0ee92ea>] __rpc_create_common+0x8a/0xc0 [sunrpc] SS:ESP 0068:eccb5d28
> ---[ end trace 8f5606cd08928ed2]---
> Kernel panic - not syncing: Fatal exception
> Pid:7131, comm: mount.nfs4 Tainted: G D -------------------2.6.32 #1
> Call Trace:
> [<c080ad18>] ? panic+0x42/0xed
> [<c080e42c>] ? oops_end+0xbc/0xd0
> [<c040b090>] ? do_invalid_op+0x0/0x90
> [<c040b10f>] ? do_invalid_op+0x7f/0x90
> [<f0ee92ea>] ? __rpc_create_common+0x8a/0xc0[sunrpc]
> [<f0edc433>] ? rpc_free_task+0x33/0x70[sunrpc]
> [<f0ed6508>] ? prc_call_sync+0x48/0x60[sunrpc]
> [<f0ed656e>] ? rpc_ping+0x4e/0x60[sunrpc]
> [<f0ed6eaf>] ? rpc_create+0x38f/0x4f0[sunrpc]
> [<c080d80b>] ? error_code+0x73/0x78
> [<f0ee92ea>] ? __rpc_create_common+0x8a/0xc0[sunrpc]
> [<c0532bda>] ? d_lookup+0x2a/0x40
> [<f0ee94b1>] ? rpc_mkpipe+0x111/0x1b0[sunrpc]
> [<f10a59f4>] ? nfs_create_rpc_client+0xb4/0xf0[nfs]
> [<f10d6c6d>] ? nfs_fscache_get_client_cookie+0x1d/0x50[nfs]
> [<f10d3fcb>] ? nfs_idmap_new+0x7b/0x140[nfs]
> [<c05e76aa>] ? strlcpy+0x3a/0x60
> [<f10a60ca>] ? nfs4_set_client+0xea/0x2b0[nfs]
> [<f10a6d0c>] ? nfs4_create_server+0xac/0x1b0[nfs]
> [<c04f1400>] ? krealloc+0x40/0x50
> [<f10b0e8b>] ? nfs4_remote_get_sb+0x6b/0x250[nfs]
> [<c04f14ec>] ? kstrdup+0x3c/0x60
> [<c0520739>] ? vfs_kern_mount+0x69/0x170
> [<f10b1a3c>] ? nfs_do_root_mount+0x6c/0xa0[nfs]
> [<f10b1b47>] ? nfs4_try_mount+0x37/0xa0[nfs]
> [<f10afe6d>] ? nfs4_validate_text_mount_data+-x7d/0xf0[nfs]
> [<f10b1c42>] ? nfs4_get_sb+0x92/0x2f0
> [<c0520739>] ? vfs_kern_mount+0x69/0x170
> [<c05366d2>] ? get_fs_type+0x32/0xb0
> [<c052089f>] ? do_kern_mount+0x3f/0xe0
> [<c053954f>] ? do_mount+0x2ef/0x740
> [<c0537740>] ? copy_mount_options+0xb0/0x120
> [<c0539a0e>] ? sys_mount+0x6e/0xa0
Hi,
Does the following patch fix the problem?
Cheers
Trond
--------------------------
SUNRPC: Fix a BUG in __rpc_create_common
From: Trond Myklebust <Trond.Myklebust@netapp.com>
Mi Jinlong reports:
When testing NFSv4 at RHEL6 with kernel 2.6.32, I got a kernel panic
at NFS client's __rpc_create_common function.
The panic place is:
rpc_mkpipe
__rpc_lookup_create() <=== find pipefile *idmap*
__rpc_mkpipe() <=== pipefile is *idmap*
__rpc_create_common()
****** BUG_ON(!d_unhashed(dentry)); ****** *panic*
The test is wrong: we can find ourselves with a hashed negative dentry here
if the idmapper tried to look up the file before we got round to creating
it.
Just replace the BUG_ON() with a d_drop(dentry).
Reported-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
2010-12-21 00:19:26 +03:00
d_drop ( dentry ) ;
2009-08-09 23:14:17 +04:00
inode = rpc_get_inode ( dir - > i_sb , mode ) ;
if ( ! inode )
goto out_err ;
inode - > i_ino = iunique ( dir - > i_sb , 100 ) ;
if ( i_fop )
inode - > i_fop = i_fop ;
if ( private )
rpc_inode_setowner ( inode , private ) ;
d_add ( dentry , inode ) ;
return 0 ;
out_err :
printk ( KERN_WARNING " %s: %s failed to allocate inode for dentry %s \n " ,
__FILE__ , __func__ , dentry - > d_name . name ) ;
dput ( dentry ) ;
return - ENOMEM ;
}
2009-08-09 23:14:20 +04:00
static int __rpc_create ( struct inode * dir , struct dentry * dentry ,
umode_t mode ,
const struct file_operations * i_fop ,
void * private )
{
int err ;
err = __rpc_create_common ( dir , dentry , S_IFREG | mode , i_fop , private ) ;
if ( err )
return err ;
fsnotify_create ( dir , dentry ) ;
return 0 ;
}
2009-08-09 23:14:17 +04:00
static int __rpc_mkdir ( struct inode * dir , struct dentry * dentry ,
umode_t mode ,
const struct file_operations * i_fop ,
void * private )
{
int err ;
err = __rpc_create_common ( dir , dentry , S_IFDIR | mode , i_fop , private ) ;
if ( err )
return err ;
inc_nlink ( dir ) ;
fsnotify_mkdir ( dir , dentry ) ;
return 0 ;
}
static int __rpc_mkpipe ( struct inode * dir , struct dentry * dentry ,
umode_t mode ,
const struct file_operations * i_fop ,
void * private ,
const struct rpc_pipe_ops * ops ,
int flags )
{
struct rpc_inode * rpci ;
int err ;
err = __rpc_create_common ( dir , dentry , S_IFIFO | mode , i_fop , private ) ;
if ( err )
return err ;
rpci = RPC_I ( dentry - > d_inode ) ;
rpci - > private = private ;
rpci - > flags = flags ;
rpci - > ops = ops ;
fsnotify_create ( dir , dentry ) ;
return 0 ;
}
2009-08-09 23:14:20 +04:00
static int __rpc_rmdir ( struct inode * dir , struct dentry * dentry )
{
int ret ;
dget ( dentry ) ;
ret = simple_rmdir ( dir , dentry ) ;
d_delete ( dentry ) ;
dput ( dentry ) ;
return ret ;
}
2009-08-09 23:14:18 +04:00
static int __rpc_unlink ( struct inode * dir , struct dentry * dentry )
{
int ret ;
dget ( dentry ) ;
ret = simple_unlink ( dir , dentry ) ;
d_delete ( dentry ) ;
dput ( dentry ) ;
return ret ;
}
static int __rpc_rmpipe ( struct inode * dir , struct dentry * dentry )
{
struct inode * inode = dentry - > d_inode ;
rpc_close_pipes ( inode ) ;
return __rpc_unlink ( dir , dentry ) ;
}
2011-11-08 16:09:19 +04:00
static struct dentry * __rpc_lookup_create_exclusive ( struct dentry * parent ,
2009-08-09 23:14:20 +04:00
struct qstr * name )
{
struct dentry * dentry ;
dentry = d_lookup ( parent , name ) ;
if ( ! dentry ) {
dentry = d_alloc ( parent , name ) ;
2011-11-08 16:09:19 +04:00
if ( ! dentry )
return ERR_PTR ( - ENOMEM ) ;
2009-08-09 23:14:20 +04:00
}
2011-11-08 16:09:19 +04:00
if ( dentry - > d_inode = = NULL ) {
2011-01-07 09:49:55 +03:00
d_set_d_op ( dentry , & rpc_dentry_operations ) ;
2009-08-09 23:14:20 +04:00
return dentry ;
2011-11-08 16:09:19 +04:00
}
2009-08-09 23:14:20 +04:00
dput ( dentry ) ;
return ERR_PTR ( - EEXIST ) ;
}
2005-04-17 02:20:36 +04:00
/*
* FIXME : This probably has races .
*/
2009-08-09 23:14:20 +04:00
static void __rpc_depopulate ( struct dentry * parent ,
const struct rpc_filelist * files ,
int start , int eof )
2005-04-17 02:20:36 +04:00
{
struct inode * dir = parent - > d_inode ;
2009-08-09 23:14:20 +04:00
struct dentry * dentry ;
struct qstr name ;
int i ;
2005-04-17 02:20:36 +04:00
2009-08-09 23:14:20 +04:00
for ( i = start ; i < eof ; i + + ) {
name . name = files [ i ] . name ;
name . len = strlen ( files [ i ] . name ) ;
name . hash = full_name_hash ( name . name , name . len ) ;
dentry = d_lookup ( parent , & name ) ;
if ( dentry = = NULL )
2007-06-08 22:14:46 +04:00
continue ;
2009-08-09 23:14:20 +04:00
if ( dentry - > d_inode = = NULL )
goto next ;
switch ( dentry - > d_inode - > i_mode & S_IFMT ) {
default :
BUG ( ) ;
case S_IFREG :
__rpc_unlink ( dir , dentry ) ;
2005-04-17 02:20:36 +04:00
break ;
2009-08-09 23:14:20 +04:00
case S_IFDIR :
__rpc_rmdir ( dir , dentry ) ;
}
next :
dput ( dentry ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-09 23:14:20 +04:00
}
static void rpc_depopulate ( struct dentry * parent ,
const struct rpc_filelist * files ,
int start , int eof )
{
struct inode * dir = parent - > d_inode ;
mutex_lock_nested ( & dir - > i_mutex , I_MUTEX_CHILD ) ;
__rpc_depopulate ( parent , files , start , eof ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-09 23:14:20 +04:00
static int rpc_populate ( struct dentry * parent ,
const struct rpc_filelist * files ,
int start , int eof ,
void * private )
2005-04-17 02:20:36 +04:00
{
2009-08-09 23:14:20 +04:00
struct inode * dir = parent - > d_inode ;
2005-04-17 02:20:36 +04:00
struct dentry * dentry ;
2009-08-09 23:14:20 +04:00
int i , err ;
2005-04-17 02:20:36 +04:00
2006-01-10 02:59:24 +03:00
mutex_lock ( & dir - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
for ( i = start ; i < eof ; i + + ) {
2009-08-09 23:14:20 +04:00
struct qstr q ;
q . name = files [ i ] . name ;
q . len = strlen ( files [ i ] . name ) ;
q . hash = full_name_hash ( q . name , q . len ) ;
dentry = __rpc_lookup_create_exclusive ( parent , & q ) ;
err = PTR_ERR ( dentry ) ;
if ( IS_ERR ( dentry ) )
2005-04-17 02:20:36 +04:00
goto out_bad ;
2009-08-09 23:14:20 +04:00
switch ( files [ i ] . mode & S_IFMT ) {
default :
BUG ( ) ;
case S_IFREG :
err = __rpc_create ( dir , dentry ,
files [ i ] . mode ,
files [ i ] . i_fop ,
private ) ;
break ;
case S_IFDIR :
err = __rpc_mkdir ( dir , dentry ,
files [ i ] . mode ,
NULL ,
private ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-09 23:14:20 +04:00
if ( err ! = 0 )
goto out_bad ;
2005-04-17 02:20:36 +04:00
}
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
out_bad :
2009-08-09 23:14:20 +04:00
__rpc_depopulate ( parent , files , start , eof ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " %s: %s failed to populate directory %s \n " ,
2008-03-06 07:47:47 +03:00
__FILE__ , __func__ , parent - > d_name . name ) ;
2009-08-09 23:14:20 +04:00
return err ;
2005-09-23 19:08:25 +04:00
}
2005-04-17 02:20:36 +04:00
2009-08-09 23:14:26 +04:00
static struct dentry * rpc_mkdir_populate ( struct dentry * parent ,
struct qstr * name , umode_t mode , void * private ,
int ( * populate ) ( struct dentry * , void * ) , void * args_populate )
2005-09-23 19:08:25 +04:00
{
struct dentry * dentry ;
2009-08-09 23:14:23 +04:00
struct inode * dir = parent - > d_inode ;
2005-09-23 19:08:25 +04:00
int error ;
2009-08-09 23:14:23 +04:00
mutex_lock_nested ( & dir - > i_mutex , I_MUTEX_PARENT ) ;
dentry = __rpc_lookup_create_exclusive ( parent , name ) ;
2005-09-23 19:08:25 +04:00
if ( IS_ERR ( dentry ) )
2009-08-09 23:14:23 +04:00
goto out ;
error = __rpc_mkdir ( dir , dentry , mode , NULL , private ) ;
2009-08-09 23:14:17 +04:00
if ( error ! = 0 )
goto out_err ;
2009-08-09 23:14:26 +04:00
if ( populate ! = NULL ) {
error = populate ( dentry , args_populate ) ;
if ( error )
goto err_rmdir ;
}
2005-09-23 19:08:25 +04:00
out :
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2006-07-30 01:37:40 +04:00
return dentry ;
2009-08-09 23:14:20 +04:00
err_rmdir :
2005-09-23 19:08:25 +04:00
__rpc_rmdir ( dir , dentry ) ;
2009-08-09 23:14:17 +04:00
out_err :
2005-09-23 19:08:25 +04:00
dentry = ERR_PTR ( error ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2009-08-09 23:14:26 +04:00
static int rpc_rmdir_depopulate ( struct dentry * dentry ,
void ( * depopulate ) ( struct dentry * ) )
2005-04-17 02:20:36 +04:00
{
2006-08-01 01:17:18 +04:00
struct dentry * parent ;
2005-09-23 19:08:25 +04:00
struct inode * dir ;
int error ;
2005-07-25 02:53:01 +04:00
2006-08-01 01:17:18 +04:00
parent = dget_parent ( dentry ) ;
dir = parent - > d_inode ;
2006-07-03 11:25:16 +04:00
mutex_lock_nested ( & dir - > i_mutex , I_MUTEX_PARENT ) ;
2009-08-09 23:14:26 +04:00
if ( depopulate ! = NULL )
depopulate ( dentry ) ;
2005-09-23 19:08:25 +04:00
error = __rpc_rmdir ( dir , dentry ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2006-08-01 01:17:18 +04:00
dput ( parent ) ;
2005-09-23 19:08:25 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
2007-11-06 21:06:03 +03:00
/**
* rpc_mkpipe - make an rpc_pipefs file for kernel < - > userspace communication
* @ parent : dentry of directory to create new " pipe " in
* @ name : name of pipe
* @ private : private data to associate with the pipe , for the caller ' s use
* @ ops : operations defining the behavior of the pipe : upcall , downcall ,
2008-12-24 00:08:32 +03:00
* release_pipe , open_pipe , and destroy_msg .
2008-02-14 02:03:23 +03:00
* @ flags : rpc_inode flags
2007-11-06 21:06:03 +03:00
*
* Data is made available for userspace to read by calls to
* rpc_queue_upcall ( ) . The actual reads will result in calls to
* @ ops - > upcall , which will be called with the file pointer ,
* message , and userspace buffer to copy to .
*
* Writes can come at any time , and do not necessarily have to be
* responses to upcalls . They will result in calls to @ msg - > downcall .
*
* The @ private argument passed here will be available to all these methods
* from the file pointer , via RPC_I ( file - > f_dentry - > d_inode ) - > private .
*/
2009-08-09 23:14:15 +04:00
struct dentry * rpc_mkpipe ( struct dentry * parent , const char * name ,
void * private , const struct rpc_pipe_ops * ops ,
int flags )
2005-04-17 02:20:36 +04:00
{
struct dentry * dentry ;
2009-08-09 23:14:17 +04:00
struct inode * dir = parent - > d_inode ;
2009-08-09 23:14:16 +04:00
umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR ;
2009-08-09 23:14:20 +04:00
struct qstr q ;
2009-08-09 23:14:17 +04:00
int err ;
2009-08-09 23:14:16 +04:00
if ( ops - > upcall = = NULL )
umode & = ~ S_IRUGO ;
if ( ops - > downcall = = NULL )
umode & = ~ S_IWUGO ;
2005-04-17 02:20:36 +04:00
2009-08-09 23:14:20 +04:00
q . name = name ;
q . len = strlen ( name ) ;
q . hash = full_name_hash ( q . name , q . len ) ,
mutex_lock_nested ( & dir - > i_mutex , I_MUTEX_PARENT ) ;
2011-11-08 16:09:19 +04:00
dentry = __rpc_lookup_create_exclusive ( parent , & q ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( dentry ) )
2009-08-09 23:14:20 +04:00
goto out ;
2009-08-09 23:14:17 +04:00
err = __rpc_mkpipe ( dir , dentry , umode , & rpc_pipe_fops ,
2009-08-09 23:14:18 +04:00
private , ops , flags ) ;
2009-08-09 23:14:17 +04:00
if ( err )
goto out_err ;
2005-09-23 19:08:25 +04:00
out :
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2006-07-30 01:37:40 +04:00
return dentry ;
2009-08-09 23:14:17 +04:00
out_err :
dentry = ERR_PTR ( err ) ;
2006-08-24 09:03:17 +04:00
printk ( KERN_WARNING " %s: %s() failed to create pipe %s/%s (errno = %d) \n " ,
2008-03-06 07:47:47 +03:00
__FILE__ , __func__ , parent - > d_name . name , name ,
2009-08-09 23:14:17 +04:00
err ) ;
2005-09-23 19:08:25 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-12-23 23:21:31 +03:00
EXPORT_SYMBOL_GPL ( rpc_mkpipe ) ;
2005-04-17 02:20:36 +04:00
2007-11-06 21:06:03 +03:00
/**
* rpc_unlink - remove a pipe
* @ dentry : dentry for the pipe , as returned from rpc_mkpipe
*
* After this call , lookups will no longer find the pipe , and any
* attempts to read or write using preexisting opens of the pipe will
* return - EPIPE .
*/
2005-09-23 19:08:25 +04:00
int
2006-08-01 01:11:48 +04:00
rpc_unlink ( struct dentry * dentry )
2005-04-17 02:20:36 +04:00
{
2006-08-01 01:11:48 +04:00
struct dentry * parent ;
2005-09-23 19:08:25 +04:00
struct inode * dir ;
2006-08-01 01:11:48 +04:00
int error = 0 ;
2005-04-17 02:20:36 +04:00
2006-08-01 01:11:48 +04:00
parent = dget_parent ( dentry ) ;
dir = parent - > d_inode ;
2006-07-03 11:25:16 +04:00
mutex_lock_nested ( & dir - > i_mutex , I_MUTEX_PARENT ) ;
2009-08-09 23:14:18 +04:00
error = __rpc_rmpipe ( dir , dentry ) ;
2006-01-10 02:59:24 +03:00
mutex_unlock ( & dir - > i_mutex ) ;
2006-08-01 01:11:48 +04:00
dput ( parent ) ;
2005-09-23 19:08:25 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
2008-12-23 23:21:31 +03:00
EXPORT_SYMBOL_GPL ( rpc_unlink ) ;
2005-04-17 02:20:36 +04:00
2009-08-09 23:14:26 +04:00
enum {
RPCAUTH_info ,
RPCAUTH_EOF
} ;
static const struct rpc_filelist authfiles [ ] = {
[ RPCAUTH_info ] = {
. name = " info " ,
. i_fop = & rpc_info_operations ,
. mode = S_IFREG | S_IRUSR ,
} ,
} ;
static int rpc_clntdir_populate ( struct dentry * dentry , void * private )
{
return rpc_populate ( dentry ,
authfiles , RPCAUTH_info , RPCAUTH_EOF ,
private ) ;
}
static void rpc_clntdir_depopulate ( struct dentry * dentry )
{
rpc_depopulate ( dentry , authfiles , RPCAUTH_info , RPCAUTH_EOF ) ;
}
2009-08-09 23:14:23 +04:00
/**
* rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
2009-09-23 22:36:38 +04:00
* @ dentry : dentry from the rpc_pipefs root to the new directory
* @ name : & struct qstr for the name
2009-08-09 23:14:23 +04:00
* @ rpc_client : rpc client to associate with this directory
*
* This creates a directory at the given @ path associated with
* @ rpc_clnt , which will contain a file named " info " with some basic
* information about the client , together with any " pipes " that may
* later be created using rpc_mkpipe ( ) .
*/
2009-08-09 23:14:25 +04:00
struct dentry * rpc_create_client_dir ( struct dentry * dentry ,
2009-08-09 23:14:26 +04:00
struct qstr * name ,
struct rpc_clnt * rpc_client )
{
return rpc_mkdir_populate ( dentry , name , S_IRUGO | S_IXUGO , NULL ,
rpc_clntdir_populate , rpc_client ) ;
}
/**
* rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir ( )
* @ dentry : directory to remove
*/
int rpc_remove_client_dir ( struct dentry * dentry )
2009-08-09 23:14:23 +04:00
{
2009-08-09 23:14:26 +04:00
return rpc_rmdir_depopulate ( dentry , rpc_clntdir_depopulate ) ;
2009-08-09 23:14:23 +04:00
}
2009-08-09 23:14:30 +04:00
static const struct rpc_filelist cache_pipefs_files [ 3 ] = {
[ 0 ] = {
. name = " channel " ,
. i_fop = & cache_file_operations_pipefs ,
2009-08-20 02:12:21 +04:00
. mode = S_IFREG | S_IRUSR | S_IWUSR ,
2009-08-09 23:14:30 +04:00
} ,
[ 1 ] = {
. name = " content " ,
. i_fop = & content_file_operations_pipefs ,
. mode = S_IFREG | S_IRUSR ,
} ,
[ 2 ] = {
. name = " flush " ,
. i_fop = & cache_flush_operations_pipefs ,
. mode = S_IFREG | S_IRUSR | S_IWUSR ,
} ,
} ;
static int rpc_cachedir_populate ( struct dentry * dentry , void * private )
{
return rpc_populate ( dentry ,
cache_pipefs_files , 0 , 3 ,
private ) ;
}
static void rpc_cachedir_depopulate ( struct dentry * dentry )
{
rpc_depopulate ( dentry , cache_pipefs_files , 0 , 3 ) ;
}
struct dentry * rpc_create_cache_dir ( struct dentry * parent , struct qstr * name ,
2011-07-25 08:35:13 +04:00
umode_t umode , struct cache_detail * cd )
2009-08-09 23:14:30 +04:00
{
return rpc_mkdir_populate ( parent , name , umode , NULL ,
rpc_cachedir_populate , cd ) ;
}
void rpc_remove_cache_dir ( struct dentry * dentry )
{
rpc_rmdir_depopulate ( dentry , rpc_cachedir_depopulate ) ;
}
2005-04-17 02:20:36 +04:00
/*
* populate the filesystem
*/
2009-09-22 04:01:09 +04:00
static const struct super_operations s_ops = {
2005-04-17 02:20:36 +04:00
. alloc_inode = rpc_alloc_inode ,
. destroy_inode = rpc_destroy_inode ,
. statfs = simple_statfs ,
} ;
# define RPCAUTH_GSSMAGIC 0x67596969
2009-08-09 23:14:21 +04:00
/*
* We have a single directory with 1 node in it .
*/
enum {
RPCAUTH_lockd ,
RPCAUTH_mount ,
RPCAUTH_nfs ,
RPCAUTH_portmap ,
RPCAUTH_statd ,
RPCAUTH_nfsd4_cb ,
2009-08-20 02:12:27 +04:00
RPCAUTH_cache ,
2009-08-09 23:14:21 +04:00
RPCAUTH_RootEOF
} ;
static const struct rpc_filelist files [ ] = {
[ RPCAUTH_lockd ] = {
. name = " lockd " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
[ RPCAUTH_mount ] = {
. name = " mount " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
[ RPCAUTH_nfs ] = {
. name = " nfs " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
[ RPCAUTH_portmap ] = {
. name = " portmap " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
[ RPCAUTH_statd ] = {
. name = " statd " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
[ RPCAUTH_nfsd4_cb ] = {
. name = " nfsd4_cb " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
2009-08-20 02:12:27 +04:00
[ RPCAUTH_cache ] = {
. name = " cache " ,
. mode = S_IFDIR | S_IRUGO | S_IXUGO ,
} ,
2009-08-09 23:14:21 +04:00
} ;
2011-12-26 16:39:22 +04:00
/*
* This call can be used only in RPC pipefs mount notification hooks .
*/
struct dentry * rpc_d_lookup_sb ( const struct super_block * sb ,
const unsigned char * dir_name )
{
struct qstr dir = {
. name = dir_name ,
. len = strlen ( dir_name ) ,
. hash = full_name_hash ( dir_name , strlen ( dir_name ) ) ,
} ;
return d_lookup ( sb - > s_root , & dir ) ;
}
EXPORT_SYMBOL_GPL ( rpc_d_lookup_sb ) ;
2005-04-17 02:20:36 +04:00
static int
rpc_fill_super ( struct super_block * sb , void * data , int silent )
{
struct inode * inode ;
struct dentry * root ;
2011-12-26 16:38:56 +04:00
struct net * net = data ;
2011-12-26 16:39:30 +04:00
struct sunrpc_net * sn = net_generic ( net , sunrpc_net_id ) ;
2011-12-26 16:39:13 +04:00
int err ;
2005-04-17 02:20:36 +04:00
sb - > s_blocksize = PAGE_CACHE_SIZE ;
sb - > s_blocksize_bits = PAGE_CACHE_SHIFT ;
sb - > s_magic = RPCAUTH_GSSMAGIC ;
sb - > s_op = & s_ops ;
sb - > s_time_gran = 1 ;
inode = rpc_get_inode ( sb , S_IFDIR | 0755 ) ;
if ( ! inode )
return - ENOMEM ;
2010-01-26 02:30:38 +03:00
sb - > s_root = root = d_alloc_root ( inode ) ;
2005-04-17 02:20:36 +04:00
if ( ! root ) {
iput ( inode ) ;
return - ENOMEM ;
}
2009-08-09 23:14:20 +04:00
if ( rpc_populate ( root , files , RPCAUTH_lockd , RPCAUTH_RootEOF , NULL ) )
2010-01-26 02:30:38 +03:00
return - ENOMEM ;
2011-12-26 16:39:13 +04:00
err = blocking_notifier_call_chain ( & rpc_pipefs_notifier_list ,
RPC_PIPEFS_MOUNT ,
sb ) ;
if ( err )
goto err_depopulate ;
2011-12-26 16:39:04 +04:00
sb - > s_fs_info = get_net ( net ) ;
2011-12-26 16:39:30 +04:00
sn - > pipefs_sb = sb ;
2005-04-17 02:20:36 +04:00
return 0 ;
2011-12-26 16:39:13 +04:00
err_depopulate :
blocking_notifier_call_chain ( & rpc_pipefs_notifier_list ,
RPC_PIPEFS_UMOUNT ,
sb ) ;
__rpc_depopulate ( root , files , RPCAUTH_lockd , RPCAUTH_RootEOF ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2010-07-25 01:48:30 +04:00
static struct dentry *
rpc_mount ( struct file_system_type * fs_type ,
int flags , const char * dev_name , void * data )
2005-04-17 02:20:36 +04:00
{
2011-12-26 16:38:56 +04:00
return mount_ns ( fs_type , flags , current - > nsproxy - > net_ns , rpc_fill_super ) ;
2005-04-17 02:20:36 +04:00
}
2011-12-26 16:39:04 +04:00
void rpc_kill_sb ( struct super_block * sb )
{
struct net * net = sb - > s_fs_info ;
2011-12-26 16:39:30 +04:00
struct sunrpc_net * sn = net_generic ( net , sunrpc_net_id ) ;
2011-12-26 16:39:04 +04:00
2011-12-26 16:39:30 +04:00
sn - > pipefs_sb = NULL ;
2011-12-26 16:39:04 +04:00
put_net ( net ) ;
2011-12-26 16:39:13 +04:00
blocking_notifier_call_chain ( & rpc_pipefs_notifier_list ,
RPC_PIPEFS_UMOUNT ,
sb ) ;
2011-12-26 16:39:04 +04:00
kill_litter_super ( sb ) ;
}
2005-04-17 02:20:36 +04:00
static struct file_system_type rpc_pipe_fs_type = {
. owner = THIS_MODULE ,
. name = " rpc_pipefs " ,
2010-07-25 01:48:30 +04:00
. mount = rpc_mount ,
2011-12-26 16:39:04 +04:00
. kill_sb = rpc_kill_sb ,
2005-04-17 02:20:36 +04:00
} ;
static void
2008-07-26 06:45:34 +04:00
init_once ( void * foo )
2005-04-17 02:20:36 +04:00
{
struct rpc_inode * rpci = ( struct rpc_inode * ) foo ;
2007-05-17 09:10:57 +04:00
inode_init_once ( & rpci - > vfs_inode ) ;
rpci - > private = NULL ;
rpci - > nreaders = 0 ;
rpci - > nwriters = 0 ;
INIT_LIST_HEAD ( & rpci - > in_upcall ) ;
2007-06-07 23:31:36 +04:00
INIT_LIST_HEAD ( & rpci - > in_downcall ) ;
2007-05-17 09:10:57 +04:00
INIT_LIST_HEAD ( & rpci - > pipe ) ;
rpci - > pipelen = 0 ;
init_waitqueue_head ( & rpci - > waitq ) ;
INIT_DELAYED_WORK ( & rpci - > queue_timeout ,
rpc_timeout_upcall_queue ) ;
rpci - > ops = NULL ;
2005-04-17 02:20:36 +04:00
}
int register_rpc_pipefs ( void )
{
2007-05-09 13:34:51 +04:00
int err ;
2005-04-17 02:20:36 +04:00
rpc_inode_cachep = kmem_cache_create ( " rpc_inode_cache " ,
2006-03-24 14:16:06 +03:00
sizeof ( struct rpc_inode ) ,
0 , ( SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD ) ,
2007-07-20 05:11:58 +04:00
init_once ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpc_inode_cachep )
return - ENOMEM ;
2007-05-09 13:34:51 +04:00
err = register_filesystem ( & rpc_pipe_fs_type ) ;
if ( err ) {
kmem_cache_destroy ( rpc_inode_cachep ) ;
return err ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
void unregister_rpc_pipefs ( void )
{
2006-09-27 12:49:40 +04:00
kmem_cache_destroy ( rpc_inode_cachep ) ;
2005-04-17 02:20:36 +04:00
unregister_filesystem ( & rpc_pipe_fs_type ) ;
}
2011-07-02 02:47:12 +04:00
/* Make 'mount -t rpc_pipefs ...' autoload this module. */
MODULE_ALIAS ( " rpc_pipefs " ) ;