forked from Minki/linux
f7b422b17e
As fs/nfs/inode.c is rather large, heterogenous and unwieldy, the attached patch splits it up into a number of files: (*) fs/nfs/inode.c Strictly inode specific functions. (*) fs/nfs/super.c Superblock management functions for NFS and NFS4, normal access, clones and referrals. The NFS4 superblock functions _could_ move out into a separate conditionally compiled file, but it's probably not worth it as there're so many common bits. (*) fs/nfs/namespace.c Some namespace-specific functions have been moved here. (*) fs/nfs/nfs4namespace.c NFS4-specific namespace functions (this could be merged into the previous file). This file is conditionally compiled. (*) fs/nfs/internal.h Inter-file declarations, plus a few simple utility functions moved from fs/nfs/inode.c. Additionally, all the in-.c-file externs have been moved here, and those files they were moved from now includes this file. For the most part, the functions have not been changed, only some multiplexor functions have changed significantly. I've also: (*) Added some extra banner comments above some functions. (*) Rearranged the function order within the files to be more logical and better grouped (IMO), though someone may prefer a different order. (*) Reduced the number of #ifdefs in .c files. (*) Added missing __init and __exit directives. Signed-Off-By: David Howells <dhowells@redhat.com>
200 lines
4.7 KiB
C
200 lines
4.7 KiB
C
/*
|
|
* linux/fs/nfs/callback.c
|
|
*
|
|
* Copyright (C) 2004 Trond Myklebust
|
|
*
|
|
* NFSv4 callback handling
|
|
*/
|
|
|
|
#include <linux/config.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/module.h>
|
|
#include <linux/smp_lock.h>
|
|
#include <linux/sunrpc/svc.h>
|
|
#include <linux/sunrpc/svcsock.h>
|
|
#include <linux/nfs_fs.h>
|
|
#include <linux/mutex.h>
|
|
|
|
#include <net/inet_sock.h>
|
|
|
|
#include "nfs4_fs.h"
|
|
#include "callback.h"
|
|
|
|
#define NFSDBG_FACILITY NFSDBG_CALLBACK
|
|
|
|
struct nfs_callback_data {
|
|
unsigned int users;
|
|
struct svc_serv *serv;
|
|
pid_t pid;
|
|
struct completion started;
|
|
struct completion stopped;
|
|
};
|
|
|
|
static struct nfs_callback_data nfs_callback_info;
|
|
static DEFINE_MUTEX(nfs_callback_mutex);
|
|
static struct svc_program nfs4_callback_program;
|
|
|
|
unsigned int nfs_callback_set_tcpport;
|
|
unsigned short nfs_callback_tcpport;
|
|
|
|
/*
|
|
* This is the callback kernel thread.
|
|
*/
|
|
static void nfs_callback_svc(struct svc_rqst *rqstp)
|
|
{
|
|
struct svc_serv *serv = rqstp->rq_server;
|
|
int err;
|
|
|
|
__module_get(THIS_MODULE);
|
|
lock_kernel();
|
|
|
|
nfs_callback_info.pid = current->pid;
|
|
daemonize("nfsv4-svc");
|
|
/* Process request with signals blocked, but allow SIGKILL. */
|
|
allow_signal(SIGKILL);
|
|
|
|
complete(&nfs_callback_info.started);
|
|
|
|
for(;;) {
|
|
if (signalled()) {
|
|
if (nfs_callback_info.users == 0)
|
|
break;
|
|
flush_signals(current);
|
|
}
|
|
/*
|
|
* Listen for a request on the socket
|
|
*/
|
|
err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT);
|
|
if (err == -EAGAIN || err == -EINTR)
|
|
continue;
|
|
if (err < 0) {
|
|
printk(KERN_WARNING
|
|
"%s: terminating on error %d\n",
|
|
__FUNCTION__, -err);
|
|
break;
|
|
}
|
|
dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
|
|
NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
|
|
svc_process(serv, rqstp);
|
|
}
|
|
|
|
svc_exit_thread(rqstp);
|
|
nfs_callback_info.pid = 0;
|
|
complete(&nfs_callback_info.stopped);
|
|
unlock_kernel();
|
|
module_put_and_exit(0);
|
|
}
|
|
|
|
/*
|
|
* Bring up the server process if it is not already up.
|
|
*/
|
|
int nfs_callback_up(void)
|
|
{
|
|
struct svc_serv *serv;
|
|
struct svc_sock *svsk;
|
|
int ret = 0;
|
|
|
|
lock_kernel();
|
|
mutex_lock(&nfs_callback_mutex);
|
|
if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
|
|
goto out;
|
|
init_completion(&nfs_callback_info.started);
|
|
init_completion(&nfs_callback_info.stopped);
|
|
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
|
|
ret = -ENOMEM;
|
|
if (!serv)
|
|
goto out_err;
|
|
/* FIXME: We don't want to register this socket with the portmapper */
|
|
ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport);
|
|
if (ret < 0)
|
|
goto out_destroy;
|
|
if (!list_empty(&serv->sv_permsocks)) {
|
|
svsk = list_entry(serv->sv_permsocks.next,
|
|
struct svc_sock, sk_list);
|
|
nfs_callback_tcpport = ntohs(inet_sk(svsk->sk_sk)->sport);
|
|
dprintk ("Callback port = 0x%x\n", nfs_callback_tcpport);
|
|
} else
|
|
BUG();
|
|
ret = svc_create_thread(nfs_callback_svc, serv);
|
|
if (ret < 0)
|
|
goto out_destroy;
|
|
nfs_callback_info.serv = serv;
|
|
wait_for_completion(&nfs_callback_info.started);
|
|
out:
|
|
mutex_unlock(&nfs_callback_mutex);
|
|
unlock_kernel();
|
|
return ret;
|
|
out_destroy:
|
|
svc_destroy(serv);
|
|
out_err:
|
|
nfs_callback_info.users--;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* Kill the server process if it is not already up.
|
|
*/
|
|
int nfs_callback_down(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
lock_kernel();
|
|
mutex_lock(&nfs_callback_mutex);
|
|
nfs_callback_info.users--;
|
|
do {
|
|
if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0)
|
|
break;
|
|
if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0)
|
|
break;
|
|
} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
|
|
mutex_unlock(&nfs_callback_mutex);
|
|
unlock_kernel();
|
|
return ret;
|
|
}
|
|
|
|
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
|
|
{
|
|
struct in_addr *addr = &rqstp->rq_addr.sin_addr;
|
|
struct nfs4_client *clp;
|
|
|
|
/* Don't talk to strangers */
|
|
clp = nfs4_find_client(addr);
|
|
if (clp == NULL)
|
|
return SVC_DROP;
|
|
dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
|
|
nfs4_put_client(clp);
|
|
switch (rqstp->rq_authop->flavour) {
|
|
case RPC_AUTH_NULL:
|
|
if (rqstp->rq_proc != CB_NULL)
|
|
return SVC_DENIED;
|
|
break;
|
|
case RPC_AUTH_UNIX:
|
|
break;
|
|
case RPC_AUTH_GSS:
|
|
/* FIXME: RPCSEC_GSS handling? */
|
|
default:
|
|
return SVC_DENIED;
|
|
}
|
|
return SVC_OK;
|
|
}
|
|
|
|
/*
|
|
* Define NFS4 callback program
|
|
*/
|
|
static struct svc_version *nfs4_callback_version[] = {
|
|
[1] = &nfs4_callback_version1,
|
|
};
|
|
|
|
static struct svc_stat nfs4_callback_stats;
|
|
|
|
static struct svc_program nfs4_callback_program = {
|
|
.pg_prog = NFS4_CALLBACK, /* RPC service number */
|
|
.pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */
|
|
.pg_vers = nfs4_callback_version, /* version table */
|
|
.pg_name = "NFSv4 callback", /* service name */
|
|
.pg_class = "nfs", /* authentication class */
|
|
.pg_stats = &nfs4_callback_stats,
|
|
.pg_authenticate = nfs_callback_authenticate,
|
|
};
|