1 /*
2 * linux/fs/lockd/svc4proc.c
3 *
4 * Lockd server procedures. We don't implement the NLM_*_RES
5 * procedures because we don't use the async procedures.
6 *
7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8 */
9
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #include <linux/malloc.h>
13 #include <linux/in.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/sunrpc/clnt.h>
16 #include <linux/nfsd/nfsd.h>
17 #include <linux/lockd/lockd.h>
18 #include <linux/lockd/share.h>
19 #include <linux/lockd/sm_inter.h>
20
21
22 #define NLMDBG_FACILITY NLMDBG_CLIENT
23
24 static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
25 static void nlm4svc_callback_exit(struct rpc_task *);
26
27 /*
28 * Obtain client and file from arguments
29 */
30 static u32
31 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
32 struct nlm_host **hostp, struct nlm_file **filp)
33 {
34 struct nlm_host *host = NULL;
35 struct nlm_file *file = NULL;
36 struct nlm_lock *lock = &argp->lock;
37 u32 error = 0;
38
39 /* nfsd callbacks must have been installed for this procedure */
40 if (!nlmsvc_ops)
41 return nlm_lck_denied_nolocks;
42
43 /* Obtain handle for client host */
44 if (rqstp->rq_client == NULL) {
45 printk(KERN_NOTICE
46 "lockd: unauthenticated request from (%08x:%d)\n",
47 ntohl(rqstp->rq_addr.sin_addr.s_addr),
48 ntohs(rqstp->rq_addr.sin_port));
49 return nlm_lck_denied_nolocks;
50 }
51
52 /* Obtain host handle */
53 if (!(host = nlmsvc_lookup_host(rqstp))
54 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
55 goto no_locks;
56 *hostp = host;
57
58 /* Obtain file pointer. Not used by FREE_ALL call. */
59 if (filp != NULL) {
60 if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
61 goto no_locks;
62 *filp = file;
63
64 /* Set up the missing parts of the file_lock structure */
65 lock->fl.fl_file = &file->f_file;
66 lock->fl.fl_owner = (fl_owner_t) host;
67 }
68
69 return 0;
70
71 no_locks:
72 if (host)
73 nlm_release_host(host);
74 if (error)
75 return error;
76 return nlm_lck_denied_nolocks;
77 }
78
79 /*
80 * NULL: Test for presence of service
81 */
82 static int
83 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
84 {
85 dprintk("lockd: NULL called\n");
86 return rpc_success;
87 }
88
89 /*
90 * TEST: Check for conflicting lock
91 */
92 static int
93 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
94 struct nlm_res *resp)
95 {
96 struct nlm_host *host;
97 struct nlm_file *file;
98
99 dprintk("lockd: TEST4 called\n");
100 resp->cookie = argp->cookie;
101
102 /* Don't accept test requests during grace period */
103 if (nlmsvc_grace_period) {
104 resp->status = nlm_lck_denied_grace_period;
105 return rpc_success;
106 }
107
108 /* Obtain client and file */
109 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
110 return rpc_success;
111
112 /* Now check for conflicting locks */
113 resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
114
115 dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
116 nlm_release_host(host);
117 nlm_release_file(file);
118 return rpc_success;
119 }
120
121 static int
122 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
123 struct nlm_res *resp)
124 {
125 struct nlm_host *host;
126 struct nlm_file *file;
127
128 dprintk("lockd: LOCK called\n");
129
130 resp->cookie = argp->cookie;
131
132 /* Don't accept new lock requests during grace period */
133 if (nlmsvc_grace_period && !argp->reclaim) {
134 resp->status = nlm_lck_denied_grace_period;
135 return rpc_success;
136 }
137
138 /* Obtain client and file */
139 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
140 return rpc_success;
141
142 #if 0
143 /* If supplied state doesn't match current state, we assume it's
144 * an old request that time-warped somehow. Any error return would
145 * do in this case because it's irrelevant anyway.
146 *
147 * NB: We don't retrieve the remote host's state yet.
148 */
149 if (host->h_nsmstate && host->h_nsmstate != argp->state) {
150 resp->status = nlm_lck_denied_nolocks;
151 } else
152 #endif
153
154 /* Now try to lock the file */
155 resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
156 argp->block, &argp->cookie);
157
158 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
159 nlm_release_host(host);
160 nlm_release_file(file);
161 return rpc_success;
162 }
163
164 static int
165 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
166 struct nlm_res *resp)
167 {
168 struct nlm_host *host;
169 struct nlm_file *file;
170
171 dprintk("lockd: CANCEL called\n");
172
173 resp->cookie = argp->cookie;
174
175 /* Don't accept requests during grace period */
176 if (nlmsvc_grace_period) {
177 resp->status = nlm_lck_denied_grace_period;
178 return rpc_success;
179 }
180
181 /* Obtain client and file */
182 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
183 return rpc_success;
184
185 /* Try to cancel request. */
186 resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
187
188 dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
189 nlm_release_host(host);
190 nlm_release_file(file);
191 return rpc_success;
192 }
193
194 /*
195 * UNLOCK: release a lock
196 */
197 static int
198 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
199 struct nlm_res *resp)
200 {
201 struct nlm_host *host;
202 struct nlm_file *file;
203
204 dprintk("lockd: UNLOCK called\n");
205
206 resp->cookie = argp->cookie;
207
208 /* Don't accept new lock requests during grace period */
209 if (nlmsvc_grace_period) {
210 resp->status = nlm_lck_denied_grace_period;
211 return rpc_success;
212 }
213
214 /* Obtain client and file */
215 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
216 return rpc_success;
217
218 /* Now try to remove the lock */
219 resp->status = nlmsvc_unlock(file, &argp->lock);
220
221 dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
222 nlm_release_host(host);
223 nlm_release_file(file);
224 return rpc_success;
225 }
226
227 /*
228 * GRANTED: A server calls us to tell that a process' lock request
229 * was granted
230 */
231 static int
232 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
233 struct nlm_res *resp)
234 {
235 resp->cookie = argp->cookie;
236
237 dprintk("lockd: GRANTED called\n");
238 resp->status = nlmclnt_grant(&argp->lock);
239 dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
240 return rpc_success;
241 }
242
243 /*
244 * `Async' versions of the above service routines. They aren't really,
245 * because we send the callback before the reply proper. I hope this
246 * doesn't break any clients.
247 */
248 static int
249 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
250 void *resp)
251 {
252 struct nlm_res res;
253 u32 stat;
254
255 dprintk("lockd: TEST_MSG called\n");
256
257 if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
258 stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
259 return stat;
260 }
261
262 static int
263 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
264 void *resp)
265 {
266 struct nlm_res res;
267 u32 stat;
268
269 dprintk("lockd: LOCK_MSG called\n");
270
271 if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
272 stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
273 return stat;
274 }
275
276 static int
277 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
278 void *resp)
279 {
280 struct nlm_res res;
281 u32 stat;
282
283 dprintk("lockd: CANCEL_MSG called\n");
284
285 if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
286 stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
287 return stat;
288 }
289
290 static int
291 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
292 void *resp)
293 {
294 struct nlm_res res;
295 u32 stat;
296
297 dprintk("lockd: UNLOCK_MSG called\n");
298
299 if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
300 stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
301 return stat;
302 }
303
304 static int
305 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
306 void *resp)
307 {
308 struct nlm_res res;
309 u32 stat;
310
311 dprintk("lockd: GRANTED_MSG called\n");
312
313 if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
314 stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
315 return stat;
316 }
317
318 /*
319 * SHARE: create a DOS share or alter existing share.
320 */
321 static int
322 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
323 struct nlm_res *resp)
324 {
325 struct nlm_host *host;
326 struct nlm_file *file;
327
328 dprintk("lockd: SHARE called\n");
329
330 resp->cookie = argp->cookie;
331
332 /* Don't accept new lock requests during grace period */
333 if (nlmsvc_grace_period && !argp->reclaim) {
334 resp->status = nlm_lck_denied_grace_period;
335 return rpc_success;
336 }
337
338 /* Obtain client and file */
339 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
340 return rpc_success;
341
342 /* Now try to create the share */
343 resp->status = nlmsvc_share_file(host, file, argp);
344
345 dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
346 nlm_release_host(host);
347 nlm_release_file(file);
348 return rpc_success;
349 }
350
351 /*
352 * UNSHARE: Release a DOS share.
353 */
354 static int
355 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
356 struct nlm_res *resp)
357 {
358 struct nlm_host *host;
359 struct nlm_file *file;
360
361 dprintk("lockd: UNSHARE called\n");
362
363 resp->cookie = argp->cookie;
364
365 /* Don't accept requests during grace period */
366 if (nlmsvc_grace_period) {
367 resp->status = nlm_lck_denied_grace_period;
368 return rpc_success;
369 }
370
371 /* Obtain client and file */
372 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
373 return rpc_success;
374
375 /* Now try to lock the file */
376 resp->status = nlmsvc_unshare_file(host, file, argp);
377
378 dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
379 nlm_release_host(host);
380 nlm_release_file(file);
381 return rpc_success;
382 }
383
384 /*
385 * NM_LOCK: Create an unmonitored lock
386 */
387 static int
388 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
389 struct nlm_res *resp)
390 {
391 dprintk("lockd: NM_LOCK called\n");
392
393 argp->monitor = 0; /* just clean the monitor flag */
394 return nlm4svc_proc_lock(rqstp, argp, resp);
395 }
396
397 /*
398 * FREE_ALL: Release all locks and shares held by client
399 */
400 static int
401 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
402 void *resp)
403 {
404 struct nlm_host *host;
405
406 /* Obtain client */
407 if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
408 return rpc_success;
409
410 nlmsvc_free_host_resources(host);
411 nlm_release_host(host);
412 return rpc_success;
413 }
414
415 /*
416 * SM_NOTIFY: private callback from statd (not part of official NLM proto)
417 */
418 static int
419 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
420 void *resp)
421 {
422 struct sockaddr_in saddr = rqstp->rq_addr;
423 struct nlm_host *host;
424
425 dprintk("lockd: SM_NOTIFY called\n");
426 if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
427 || ntohs(saddr.sin_port) >= 1024) {
428 printk(KERN_WARNING
429 "lockd: rejected NSM callback from %08x:%d\n",
430 ntohl(rqstp->rq_addr.sin_addr.s_addr),
431 ntohs(rqstp->rq_addr.sin_port));
432 return rpc_system_err;
433 }
434
435 /* Obtain the host pointer for this NFS server and try to
436 * reclaim all locks we hold on this server.
437 */
438 saddr.sin_addr.s_addr = argp->addr;
439 if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
440 nlmclnt_recovery(host, argp->state);
441 nlm_release_host(host);
442 }
443
444 /* If we run on an NFS server, delete all locks held by the client */
445 if (nlmsvc_ops != NULL) {
446 struct svc_client *clnt;
447 saddr.sin_addr.s_addr = argp->addr;
448 if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
449 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
450 nlmsvc_free_host_resources(host);
451 }
452 nlm_release_host(host);
453 }
454
455 return rpc_success;
456 }
457
458 /*
459 * This is the generic lockd callback for async RPC calls
460 */
461 static u32
462 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
463 {
464 struct nlm_host *host;
465 struct nlm_rqst *call;
466
467 if (!(call = nlmclnt_alloc_call()))
468 return rpc_system_err;
469
470 host = nlmclnt_lookup_host(&rqstp->rq_addr,
471 rqstp->rq_prot, rqstp->rq_vers);
472 if (!host) {
473 kfree(call);
474 return rpc_system_err;
475 }
476
477 call->a_flags = RPC_TASK_ASYNC;
478 call->a_host = host;
479 memcpy(&call->a_args, resp, sizeof(*resp));
480
481 if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
482 goto error;
483
484 return rpc_success;
485 error:
486 kfree(call);
487 nlm_release_host(host);
488 return rpc_system_err;
489 }
490
491 static void
492 nlm4svc_callback_exit(struct rpc_task *task)
493 {
494 struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
495
496 if (task->tk_status < 0) {
497 dprintk("lockd: %4d callback failed (errno = %d)\n",
498 task->tk_pid, -task->tk_status);
499 }
500 nlm_release_host(call->a_host);
501 kfree(call);
502 }
503
504 /*
505 * NLM Server procedures.
506 */
507
508 #define nlm4svc_encode_norep nlm4svc_encode_void
509 #define nlm4svc_decode_norep nlm4svc_decode_void
510 #define nlm4svc_decode_testres nlm4svc_decode_void
511 #define nlm4svc_decode_lockres nlm4svc_decode_void
512 #define nlm4svc_decode_unlockres nlm4svc_decode_void
513 #define nlm4svc_decode_cancelres nlm4svc_decode_void
514 #define nlm4svc_decode_grantedres nlm4svc_decode_void
515
516 #define nlm4svc_proc_none nlm4svc_proc_null
517 #define nlm4svc_proc_test_res nlm4svc_proc_null
518 #define nlm4svc_proc_lock_res nlm4svc_proc_null
519 #define nlm4svc_proc_cancel_res nlm4svc_proc_null
520 #define nlm4svc_proc_unlock_res nlm4svc_proc_null
521 #define nlm4svc_proc_granted_res nlm4svc_proc_null
522
523 struct nlm_void { int dummy; };
524
525 #define PROC(name, xargt, xrest, argt, rest) \
526 { (svc_procfunc) nlm4svc_proc_##name, \
527 (kxdrproc_t) nlm4svc_decode_##xargt, \
528 (kxdrproc_t) nlm4svc_encode_##xrest, \
529 NULL, \
530 sizeof(struct nlm_##argt), \
531 sizeof(struct nlm_##rest), \
532 0, \
533 0 \
534 }
535 struct svc_procedure nlmsvc_procedures4[] = {
536 PROC(null, void, void, void, void),
537 PROC(test, testargs, testres, args, res),
538 PROC(lock, lockargs, res, args, res),
539 PROC(cancel, cancargs, res, args, res),
540 PROC(unlock, unlockargs, res, args, res),
541 PROC(granted, testargs, res, args, res),
542 PROC(test_msg, testargs, norep, args, void),
543 PROC(lock_msg, lockargs, norep, args, void),
544 PROC(cancel_msg, cancargs, norep, args, void),
545 PROC(unlock_msg, unlockargs, norep, args, void),
546 PROC(granted_msg, testargs, norep, args, void),
547 PROC(test_res, testres, norep, res, void),
548 PROC(lock_res, lockres, norep, res, void),
549 PROC(cancel_res, cancelres, norep, res, void),
550 PROC(unlock_res, unlockres, norep, res, void),
551 PROC(granted_res, grantedres, norep, res, void),
552 PROC(none, void, void, void, void),
553 PROC(none, void, void, void, void),
554 PROC(none, void, void, void, void),
555 PROC(none, void, void, void, void),
556 PROC(share, shareargs, shareres, args, res),
557 PROC(unshare, shareargs, shareres, args, res),
558 PROC(nm_lock, lockargs, res, args, res),
559 PROC(free_all, notify, void, args, void),
560
561 /* statd callback */
562 PROC(sm_notify, reboot, void, reboot, void),
563 };
564
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.