Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6
[sfrench/cifs-2.6.git] / fs / nfs / callback.c
1 /*
2  * linux/fs/nfs/callback.c
3  *
4  * Copyright (C) 2004 Trond Myklebust
5  *
6  * NFSv4 callback handling
7  */
8
9 #include <linux/completion.h>
10 #include <linux/ip.h>
11 #include <linux/module.h>
12 #include <linux/smp_lock.h>
13 #include <linux/sunrpc/svc.h>
14 #include <linux/sunrpc/svcsock.h>
15 #include <linux/nfs_fs.h>
16 #include <linux/mutex.h>
17 #include <linux/freezer.h>
18 #include <linux/kthread.h>
19 #include <linux/sunrpc/svcauth_gss.h>
20 #if defined(CONFIG_NFS_V4_1)
21 #include <linux/sunrpc/bc_xprt.h>
22 #endif
23
24 #include <net/inet_sock.h>
25
26 #include "nfs4_fs.h"
27 #include "callback.h"
28 #include "internal.h"
29
30 #define NFSDBG_FACILITY NFSDBG_CALLBACK
31
32 struct nfs_callback_data {
33         unsigned int users;
34         struct svc_serv *serv;
35         struct svc_rqst *rqst;
36         struct task_struct *task;
37 };
38
39 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
40 static DEFINE_MUTEX(nfs_callback_mutex);
41 static struct svc_program nfs4_callback_program;
42
43 unsigned int nfs_callback_set_tcpport;
44 unsigned short nfs_callback_tcpport;
45 unsigned short nfs_callback_tcpport6;
46 #define NFS_CALLBACK_MAXPORTNR (65535U)
47
48 static int param_set_portnr(const char *val, struct kernel_param *kp)
49 {
50         unsigned long num;
51         int ret;
52
53         if (!val)
54                 return -EINVAL;
55         ret = strict_strtoul(val, 0, &num);
56         if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR)
57                 return -EINVAL;
58         *((unsigned int *)kp->arg) = num;
59         return 0;
60 }
61
62 static int param_get_portnr(char *buffer, struct kernel_param *kp)
63 {
64         return param_get_uint(buffer, kp);
65 }
66 #define param_check_portnr(name, p) __param_check(name, p, unsigned int);
67
68 module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
69
70 /*
71  * This is the NFSv4 callback kernel thread.
72  */
73 static int
74 nfs4_callback_svc(void *vrqstp)
75 {
76         int err, preverr = 0;
77         struct svc_rqst *rqstp = vrqstp;
78
79         set_freezable();
80
81         while (!kthread_should_stop()) {
82                 /*
83                  * Listen for a request on the socket
84                  */
85                 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
86                 if (err == -EAGAIN || err == -EINTR) {
87                         preverr = err;
88                         continue;
89                 }
90                 if (err < 0) {
91                         if (err != preverr) {
92                                 printk(KERN_WARNING "%s: unexpected error "
93                                         "from svc_recv (%d)\n", __func__, err);
94                                 preverr = err;
95                         }
96                         schedule_timeout_uninterruptible(HZ);
97                         continue;
98                 }
99                 preverr = err;
100                 svc_process(rqstp);
101         }
102         return 0;
103 }
104
105 /*
106  * Prepare to bring up the NFSv4 callback service
107  */
108 struct svc_rqst *
109 nfs4_callback_up(struct svc_serv *serv)
110 {
111         int ret;
112
113         ret = svc_create_xprt(serv, "tcp", PF_INET,
114                                 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
115         if (ret <= 0)
116                 goto out_err;
117         nfs_callback_tcpport = ret;
118         dprintk("NFS: Callback listener port = %u (af %u)\n",
119                         nfs_callback_tcpport, PF_INET);
120
121         ret = svc_create_xprt(serv, "tcp", PF_INET6,
122                                 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
123         if (ret > 0) {
124                 nfs_callback_tcpport6 = ret;
125                 dprintk("NFS: Callback listener port = %u (af %u)\n",
126                                 nfs_callback_tcpport6, PF_INET6);
127         } else if (ret == -EAFNOSUPPORT)
128                 ret = 0;
129         else
130                 goto out_err;
131
132         return svc_prepare_thread(serv, &serv->sv_pools[0]);
133
134 out_err:
135         if (ret == 0)
136                 ret = -ENOMEM;
137         return ERR_PTR(ret);
138 }
139
140 #if defined(CONFIG_NFS_V4_1)
141 /*
142  * The callback service for NFSv4.1 callbacks
143  */
144 static int
145 nfs41_callback_svc(void *vrqstp)
146 {
147         struct svc_rqst *rqstp = vrqstp;
148         struct svc_serv *serv = rqstp->rq_server;
149         struct rpc_rqst *req;
150         int error;
151         DEFINE_WAIT(wq);
152
153         set_freezable();
154
155         while (!kthread_should_stop()) {
156                 prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
157                 spin_lock_bh(&serv->sv_cb_lock);
158                 if (!list_empty(&serv->sv_cb_list)) {
159                         req = list_first_entry(&serv->sv_cb_list,
160                                         struct rpc_rqst, rq_bc_list);
161                         list_del(&req->rq_bc_list);
162                         spin_unlock_bh(&serv->sv_cb_lock);
163                         dprintk("Invoking bc_svc_process()\n");
164                         error = bc_svc_process(serv, req, rqstp);
165                         dprintk("bc_svc_process() returned w/ error code= %d\n",
166                                 error);
167                 } else {
168                         spin_unlock_bh(&serv->sv_cb_lock);
169                         schedule();
170                 }
171                 finish_wait(&serv->sv_cb_waitq, &wq);
172         }
173         return 0;
174 }
175
176 /*
177  * Bring up the NFSv4.1 callback service
178  */
179 struct svc_rqst *
180 nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
181 {
182         struct svc_xprt *bc_xprt;
183         struct svc_rqst *rqstp = ERR_PTR(-ENOMEM);
184
185         dprintk("--> %s\n", __func__);
186         /* Create a svc_sock for the service */
187         bc_xprt = svc_sock_create(serv, xprt->prot);
188         if (!bc_xprt)
189                 goto out;
190
191         /*
192          * Save the svc_serv in the transport so that it can
193          * be referenced when the session backchannel is initialized
194          */
195         serv->bc_xprt = bc_xprt;
196         xprt->bc_serv = serv;
197
198         INIT_LIST_HEAD(&serv->sv_cb_list);
199         spin_lock_init(&serv->sv_cb_lock);
200         init_waitqueue_head(&serv->sv_cb_waitq);
201         rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
202         if (IS_ERR(rqstp))
203                 svc_sock_destroy(bc_xprt);
204 out:
205         dprintk("--> %s return %p\n", __func__, rqstp);
206         return rqstp;
207 }
208
209 static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
210                 struct svc_serv *serv, struct rpc_xprt *xprt,
211                 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
212 {
213         if (minorversion) {
214                 *rqstpp = nfs41_callback_up(serv, xprt);
215                 *callback_svc = nfs41_callback_svc;
216         }
217         return minorversion;
218 }
219
220 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
221                 struct nfs_callback_data *cb_info)
222 {
223         if (minorversion)
224                 xprt->bc_serv = cb_info->serv;
225 }
226 #else
227 static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
228                 struct svc_serv *serv, struct rpc_xprt *xprt,
229                 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
230 {
231         return 0;
232 }
233
234 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
235                 struct nfs_callback_data *cb_info)
236 {
237 }
238 #endif /* CONFIG_NFS_V4_1 */
239
240 /*
241  * Bring up the callback thread if it is not already up.
242  */
243 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
244 {
245         struct svc_serv *serv = NULL;
246         struct svc_rqst *rqstp;
247         int (*callback_svc)(void *vrqstp);
248         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
249         char svc_name[12];
250         int ret = 0;
251         int minorversion_setup;
252
253         mutex_lock(&nfs_callback_mutex);
254         if (cb_info->users++ || cb_info->task != NULL) {
255                 nfs_callback_bc_serv(minorversion, xprt, cb_info);
256                 goto out;
257         }
258         serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
259         if (!serv) {
260                 ret = -ENOMEM;
261                 goto out_err;
262         }
263
264         minorversion_setup =  nfs_minorversion_callback_svc_setup(minorversion,
265                                         serv, xprt, &rqstp, &callback_svc);
266         if (!minorversion_setup) {
267                 /* v4.0 callback setup */
268                 rqstp = nfs4_callback_up(serv);
269                 callback_svc = nfs4_callback_svc;
270         }
271
272         if (IS_ERR(rqstp)) {
273                 ret = PTR_ERR(rqstp);
274                 goto out_err;
275         }
276
277         svc_sock_update_bufs(serv);
278
279         sprintf(svc_name, "nfsv4.%u-svc", minorversion);
280         cb_info->serv = serv;
281         cb_info->rqst = rqstp;
282         cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name);
283         if (IS_ERR(cb_info->task)) {
284                 ret = PTR_ERR(cb_info->task);
285                 svc_exit_thread(cb_info->rqst);
286                 cb_info->rqst = NULL;
287                 cb_info->task = NULL;
288                 goto out_err;
289         }
290 out:
291         /*
292          * svc_create creates the svc_serv with sv_nrthreads == 1, and then
293          * svc_prepare_thread increments that. So we need to call svc_destroy
294          * on both success and failure so that the refcount is 1 when the
295          * thread exits.
296          */
297         if (serv)
298                 svc_destroy(serv);
299         mutex_unlock(&nfs_callback_mutex);
300         return ret;
301 out_err:
302         dprintk("NFS: Couldn't create callback socket or server thread; "
303                 "err = %d\n", ret);
304         cb_info->users--;
305         goto out;
306 }
307
308 /*
309  * Kill the callback thread if it's no longer being used.
310  */
311 void nfs_callback_down(int minorversion)
312 {
313         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
314
315         mutex_lock(&nfs_callback_mutex);
316         cb_info->users--;
317         if (cb_info->users == 0 && cb_info->task != NULL) {
318                 kthread_stop(cb_info->task);
319                 svc_exit_thread(cb_info->rqst);
320                 cb_info->serv = NULL;
321                 cb_info->rqst = NULL;
322                 cb_info->task = NULL;
323         }
324         mutex_unlock(&nfs_callback_mutex);
325 }
326
327 static int check_gss_callback_principal(struct nfs_client *clp,
328                                         struct svc_rqst *rqstp)
329 {
330         struct rpc_clnt *r = clp->cl_rpcclient;
331         char *p = svc_gss_principal(rqstp);
332
333         /*
334          * It might just be a normal user principal, in which case
335          * userspace won't bother to tell us the name at all.
336          */
337         if (p == NULL)
338                 return SVC_DENIED;
339
340         /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
341
342         if (memcmp(p, "nfs@", 4) != 0)
343                 return SVC_DENIED;
344         p += 4;
345         if (strcmp(p, r->cl_server) != 0)
346                 return SVC_DENIED;
347         return SVC_OK;
348 }
349
350 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
351 {
352         struct nfs_client *clp;
353         RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
354         int ret = SVC_OK;
355
356         /* Don't talk to strangers */
357         clp = nfs_find_client(svc_addr(rqstp), 4);
358         if (clp == NULL)
359                 return SVC_DROP;
360
361         dprintk("%s: %s NFSv4 callback!\n", __func__,
362                         svc_print_addr(rqstp, buf, sizeof(buf)));
363
364         switch (rqstp->rq_authop->flavour) {
365                 case RPC_AUTH_NULL:
366                         if (rqstp->rq_proc != CB_NULL)
367                                 ret = SVC_DENIED;
368                         break;
369                 case RPC_AUTH_UNIX:
370                         break;
371                 case RPC_AUTH_GSS:
372                         ret = check_gss_callback_principal(clp, rqstp);
373                         break;
374                 default:
375                         ret = SVC_DENIED;
376         }
377         nfs_put_client(clp);
378         return ret;
379 }
380
381 /*
382  * Define NFS4 callback program
383  */
384 static struct svc_version *nfs4_callback_version[] = {
385         [1] = &nfs4_callback_version1,
386         [4] = &nfs4_callback_version4,
387 };
388
389 static struct svc_stat nfs4_callback_stats;
390
391 static struct svc_program nfs4_callback_program = {
392         .pg_prog = NFS4_CALLBACK,                       /* RPC service number */
393         .pg_nvers = ARRAY_SIZE(nfs4_callback_version),  /* Number of entries */
394         .pg_vers = nfs4_callback_version,               /* version table */
395         .pg_name = "NFSv4 callback",                    /* service name */
396         .pg_class = "nfs",                              /* authentication class */
397         .pg_stats = &nfs4_callback_stats,
398         .pg_authenticate = nfs_callback_authenticate,
399 };