xref: /openbmc/linux/fs/nfs/callback.c (revision 87c2ce3b)
1 /*
2  * linux/fs/nfs/callback.c
3  *
4  * Copyright (C) 2004 Trond Myklebust
5  *
6  * NFSv4 callback handling
7  */
8 
9 #include <linux/config.h>
10 #include <linux/completion.h>
11 #include <linux/ip.h>
12 #include <linux/module.h>
13 #include <linux/smp_lock.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/sunrpc/svcsock.h>
16 #include <linux/nfs_fs.h>
17 
18 #include <net/inet_sock.h>
19 
20 #include "nfs4_fs.h"
21 #include "callback.h"
22 
23 #define NFSDBG_FACILITY NFSDBG_CALLBACK
24 
25 struct nfs_callback_data {
26 	unsigned int users;
27 	struct svc_serv *serv;
28 	pid_t pid;
29 	struct completion started;
30 	struct completion stopped;
31 };
32 
33 static struct nfs_callback_data nfs_callback_info;
34 static DECLARE_MUTEX(nfs_callback_sema);
35 static struct svc_program nfs4_callback_program;
36 
37 unsigned int nfs_callback_set_tcpport;
38 unsigned short nfs_callback_tcpport;
39 
40 /*
41  * This is the callback kernel thread.
42  */
43 static void nfs_callback_svc(struct svc_rqst *rqstp)
44 {
45 	struct svc_serv *serv = rqstp->rq_server;
46 	int err;
47 
48 	__module_get(THIS_MODULE);
49 	lock_kernel();
50 
51 	nfs_callback_info.pid = current->pid;
52 	daemonize("nfsv4-svc");
53 	/* Process request with signals blocked, but allow SIGKILL.  */
54 	allow_signal(SIGKILL);
55 
56 	complete(&nfs_callback_info.started);
57 
58 	while (nfs_callback_info.users != 0 || !signalled()) {
59 		/*
60 		 * Listen for a request on the socket
61 		 */
62 		err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT);
63 		if (err == -EAGAIN || err == -EINTR)
64 			continue;
65 		if (err < 0) {
66 			printk(KERN_WARNING
67 					"%s: terminating on error %d\n",
68 					__FUNCTION__, -err);
69 			break;
70 		}
71 		dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
72 				NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
73 		svc_process(serv, rqstp);
74 	}
75 
76 	nfs_callback_info.pid = 0;
77 	complete(&nfs_callback_info.stopped);
78 	unlock_kernel();
79 	module_put_and_exit(0);
80 }
81 
82 /*
83  * Bring up the server process if it is not already up.
84  */
85 int nfs_callback_up(void)
86 {
87 	struct svc_serv *serv;
88 	struct svc_sock *svsk;
89 	int ret = 0;
90 
91 	lock_kernel();
92 	down(&nfs_callback_sema);
93 	if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
94 		goto out;
95 	init_completion(&nfs_callback_info.started);
96 	init_completion(&nfs_callback_info.stopped);
97 	serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
98 	ret = -ENOMEM;
99 	if (!serv)
100 		goto out_err;
101 	/* FIXME: We don't want to register this socket with the portmapper */
102 	ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport);
103 	if (ret < 0)
104 		goto out_destroy;
105 	if (!list_empty(&serv->sv_permsocks)) {
106 		svsk = list_entry(serv->sv_permsocks.next,
107 				struct svc_sock, sk_list);
108 		nfs_callback_tcpport = ntohs(inet_sk(svsk->sk_sk)->sport);
109 		dprintk ("Callback port = 0x%x\n", nfs_callback_tcpport);
110 	} else
111 		BUG();
112 	ret = svc_create_thread(nfs_callback_svc, serv);
113 	if (ret < 0)
114 		goto out_destroy;
115 	nfs_callback_info.serv = serv;
116 	wait_for_completion(&nfs_callback_info.started);
117 out:
118 	up(&nfs_callback_sema);
119 	unlock_kernel();
120 	return ret;
121 out_destroy:
122 	svc_destroy(serv);
123 out_err:
124 	nfs_callback_info.users--;
125 	goto out;
126 }
127 
128 /*
129  * Kill the server process if it is not already up.
130  */
131 int nfs_callback_down(void)
132 {
133 	int ret = 0;
134 
135 	lock_kernel();
136 	down(&nfs_callback_sema);
137 	if (--nfs_callback_info.users || nfs_callback_info.pid == 0)
138 		goto out;
139 	kill_proc(nfs_callback_info.pid, SIGKILL, 1);
140 	wait_for_completion(&nfs_callback_info.stopped);
141 out:
142 	up(&nfs_callback_sema);
143 	unlock_kernel();
144 	return ret;
145 }
146 
147 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
148 {
149 	struct in_addr *addr = &rqstp->rq_addr.sin_addr;
150 	struct nfs4_client *clp;
151 
152 	/* Don't talk to strangers */
153 	clp = nfs4_find_client(addr);
154 	if (clp == NULL)
155 		return SVC_DROP;
156 	dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
157 	nfs4_put_client(clp);
158 	switch (rqstp->rq_authop->flavour) {
159 		case RPC_AUTH_NULL:
160 			if (rqstp->rq_proc != CB_NULL)
161 				return SVC_DENIED;
162 			break;
163 		case RPC_AUTH_UNIX:
164 			break;
165 		case RPC_AUTH_GSS:
166 			/* FIXME: RPCSEC_GSS handling? */
167 		default:
168 			return SVC_DENIED;
169 	}
170 	return SVC_OK;
171 }
172 
173 /*
174  * Define NFS4 callback program
175  */
176 extern struct svc_version nfs4_callback_version1;
177 
178 static struct svc_version *nfs4_callback_version[] = {
179 	[1] = &nfs4_callback_version1,
180 };
181 
182 static struct svc_stat nfs4_callback_stats;
183 
184 static struct svc_program nfs4_callback_program = {
185 	.pg_prog = NFS4_CALLBACK,			/* RPC service number */
186 	.pg_nvers = ARRAY_SIZE(nfs4_callback_version),	/* Number of entries */
187 	.pg_vers = nfs4_callback_version,		/* version table */
188 	.pg_name = "NFSv4 callback",			/* service name */
189 	.pg_class = "nfs",				/* authentication class */
190 	.pg_stats = &nfs4_callback_stats,
191 	.pg_authenticate = nfs_callback_authenticate,
192 };
193