Commit af2f0033 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] RPCSEC upcall mechanism [3/6]

This patch provides the upcall mechanism that will be used for communicating
with the RPCSEC client user daemons.

It sets up a 'ramfs' style filesystem (rpc_pipefs) that is populated with
named pipes. Each time the kernel initializes a new NFS, lockd, statd or
portmapper client, a directory automatically gets set up in this fs.
The directory is initially only populated with a single file "info"
that provides information such as the server IP address, the port number
and the RPC service for the benefit of the user daemon.

When an RPCSEC_GSS mechanism needs to communicate with the daemon, it
is provided with a toolkit for setting up a named pipe in the same
directory. It can then perform upcalls/downcalls in order to talk to the
daemon in much the same way as is done by CODA.

The NFSv4 client will also need to use this same filesystem to communicate
with its user daemon in order to do name-to-uid/name-from-uid and
name-to-gid/name-from-gid translation.
parent 6d52fdcb
......@@ -28,6 +28,8 @@ struct rpc_portmap {
__u16 pm_port;
};
struct rpc_inode;
/*
* The high-level client handle
*/
......@@ -58,6 +60,8 @@ struct rpc_clnt {
int cl_nodelen; /* nodename length */
char cl_nodename[UNX_MAXNODENAME];
char cl_pathname[30];/* Path in rpc_pipe_fs */
struct dentry * cl_dentry; /* inode */
};
#define cl_timeout cl_xprt->timeout
#define cl_prog cl_pmap.pm_prog
......
#ifndef _LINUX_SUNRPC_RPC_PIPE_FS_H
#define _LINUX_SUNRPC_RPC_PIPE_FS_H
#ifdef __KERNEL__
struct rpc_pipe_msg {
struct list_head list;
void *data;
size_t len;
size_t copied;
int errno;
};
struct rpc_pipe_ops {
ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char *, size_t);
ssize_t (*downcall)(struct file *, const char *, size_t);
void (*destroy_msg)(struct rpc_pipe_msg *);
};
struct rpc_inode {
struct inode vfs_inode;
void *private;
struct list_head pipe;
int pipelen;
int nreaders;
wait_queue_head_t waitq;
struct rpc_pipe_ops *ops;
};
static inline struct rpc_inode *
RPC_I(struct inode *inode)
{
return container_of(inode, struct rpc_inode, vfs_inode);
}
extern void rpc_inode_setowner(struct inode *, void *);
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
extern int rpc_rmdir(char *);
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *);
extern int rpc_unlink(char *);
void __rpc_purge_current_upcall(struct file *);
#endif
#endif
......@@ -10,6 +10,6 @@ sunrpc-y := clnt.o xprt.o sched.o \
auth.o auth_null.o auth_unix.o \
svc.o svcsock.o svcauth.o svcauth_unix.o \
pmap_clnt.o timer.o xdr.o \
sunrpc_syms.o cache.o
sunrpc_syms.o cache.o rpc_pipe.o
sunrpc-$(CONFIG_PROC_FS) += stats.o
sunrpc-$(CONFIG_SYSCTL) += sysctl.o
......@@ -30,6 +30,7 @@
#include <linux/utsname.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/nfs.h>
......@@ -108,8 +109,19 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
rpc_init_rtt(&clnt->cl_rtt, xprt->timeout.to_initval);
if (!rpcauth_create(flavor, clnt))
snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname),
"/%s/clnt%p", clnt->cl_protname, clnt);
clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt);
if (IS_ERR(clnt->cl_dentry)) {
printk(KERN_INFO "RPC: Couldn't create pipefs entry %s\n",
clnt->cl_pathname);
goto out_no_path;
}
if (!rpcauth_create(flavor, clnt)) {
printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
flavor);
goto out_no_auth;
}
/* save the nodename */
clnt->cl_nodelen = strlen(system_utsname.nodename);
......@@ -123,8 +135,8 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
printk(KERN_INFO "RPC: out of memory in rpc_create_client\n");
goto out;
out_no_auth:
printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
flavor);
rpc_rmdir(clnt->cl_pathname);
out_no_path:
kfree(clnt);
clnt = NULL;
goto out;
......@@ -176,6 +188,7 @@ rpc_destroy_client(struct rpc_clnt *clnt)
rpcauth_destroy(clnt->cl_auth);
clnt->cl_auth = NULL;
}
rpc_rmdir(clnt->cl_pathname);
if (clnt->cl_xprt) {
xprt_destroy(clnt->cl_xprt);
clnt->cl_xprt = NULL;
......@@ -801,13 +814,23 @@ call_refresh(struct rpc_task *task)
static void
call_refreshresult(struct rpc_task *task)
{
int status = task->tk_status;
dprintk("RPC: %4d call_refreshresult (status %d)\n",
task->tk_pid, task->tk_status);
if (task->tk_status < 0)
rpc_exit(task, -EACCES);
else
task->tk_action = call_reserve;
task->tk_status = 0;
task->tk_action = call_reserve;
if (status >= 0)
return;
switch (status) {
case -EPIPE:
rpc_delay(task, 3*HZ);
case -ETIMEDOUT:
task->tk_action = call_refresh;
break;
default:
rpc_exit(task, -EACCES);
}
}
/*
......
This diff is collapsed.
......@@ -22,6 +22,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
/* RPC scheduler */
......@@ -42,6 +43,7 @@ EXPORT_SYMBOL(rpc_release_task);
EXPORT_SYMBOL(rpc_create_client);
EXPORT_SYMBOL(rpc_destroy_client);
EXPORT_SYMBOL(rpc_shutdown_client);
EXPORT_SYMBOL(rpc_release_client);
EXPORT_SYMBOL(rpc_killall_tasks);
EXPORT_SYMBOL(rpc_call_sync);
EXPORT_SYMBOL(rpc_call_async);
......@@ -51,6 +53,11 @@ EXPORT_SYMBOL(rpc_clnt_sigunmask);
EXPORT_SYMBOL(rpc_delay);
EXPORT_SYMBOL(rpc_restart_call);
EXPORT_SYMBOL(rpc_setbufsize);
EXPORT_SYMBOL(rpc_unlink);
EXPORT_SYMBOL(rpc_wake_up);
EXPORT_SYMBOL(rpc_queue_upcall);
EXPORT_SYMBOL(rpc_mkpipe);
EXPORT_SYMBOL(__rpc_purge_current_upcall);
/* Client transport */
EXPORT_SYMBOL(xprt_create_proto);
......@@ -126,11 +133,18 @@ EXPORT_SYMBOL(nfsd_debug);
EXPORT_SYMBOL(nlm_debug);
#endif
extern int register_rpc_pipefs(void);
extern void unregister_rpc_pipefs(void);
static int __init
init_sunrpc(void)
{
if (rpc_init_mempool() != 0)
return -ENOMEM;
int err = register_rpc_pipefs();
if (err)
goto out;
err = rpc_init_mempool() != 0;
if (err)
goto out;
#ifdef RPC_DEBUG
rpc_register_sysctl();
#endif
......@@ -139,12 +153,14 @@ init_sunrpc(void)
#endif
cache_register(&auth_domain_cache);
cache_register(&ip_map_cache);
return 0;
out:
return err;
}
static void __exit
cleanup_sunrpc(void)
{
unregister_rpc_pipefs();
rpc_destroy_mempool();
cache_unregister(&auth_domain_cache);
cache_unregister(&ip_map_cache);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment