Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
svc4proc.c
Go to the documentation of this file.
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 <[email protected]>
8  */
9 
10 #include <linux/types.h>
11 #include <linux/time.h>
12 #include <linux/lockd/lockd.h>
13 #include <linux/lockd/share.h>
14 #include <linux/sunrpc/svc_xprt.h>
15 
16 #define NLMDBG_FACILITY NLMDBG_CLIENT
17 
18 /*
19  * Obtain client and file from arguments
20  */
21 static __be32
22 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
23  struct nlm_host **hostp, struct nlm_file **filp)
24 {
25  struct nlm_host *host = NULL;
26  struct nlm_file *file = NULL;
27  struct nlm_lock *lock = &argp->lock;
28  __be32 error = 0;
29 
30  /* nfsd callbacks must have been installed for this procedure */
31  if (!nlmsvc_ops)
33 
34  /* Obtain host handle */
35  if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
36  || (argp->monitor && nsm_monitor(host) < 0))
37  goto no_locks;
38  *hostp = host;
39 
40  /* Obtain file pointer. Not used by FREE_ALL call. */
41  if (filp != NULL) {
42  if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
43  goto no_locks;
44  *filp = file;
45 
46  /* Set up the missing parts of the file_lock structure */
47  lock->fl.fl_file = file->f_file;
48  lock->fl.fl_owner = (fl_owner_t) host;
49  lock->fl.fl_lmops = &nlmsvc_lock_operations;
50  }
51 
52  return 0;
53 
54 no_locks:
55  nlmsvc_release_host(host);
56  if (error)
57  return error;
59 }
60 
61 /*
62  * NULL: Test for presence of service
63  */
64 static __be32
65 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
66 {
67  dprintk("lockd: NULL called\n");
68  return rpc_success;
69 }
70 
71 /*
72  * TEST: Check for conflicting lock
73  */
74 static __be32
75 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
76  struct nlm_res *resp)
77 {
78  struct nlm_host *host;
79  struct nlm_file *file;
80  __be32 rc = rpc_success;
81 
82  dprintk("lockd: TEST4 called\n");
83  resp->cookie = argp->cookie;
84 
85  /* Obtain client and file */
86  if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
87  return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
88 
89  /* Now check for conflicting locks */
90  resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
91  if (resp->status == nlm_drop_reply)
92  rc = rpc_drop_reply;
93  else
94  dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
95 
96  nlmsvc_release_host(host);
97  nlm_release_file(file);
98  return rc;
99 }
100 
101 static __be32
102 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
103  struct nlm_res *resp)
104 {
105  struct nlm_host *host;
106  struct nlm_file *file;
107  __be32 rc = rpc_success;
108 
109  dprintk("lockd: LOCK called\n");
110 
111  resp->cookie = argp->cookie;
112 
113  /* Obtain client and file */
114  if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
115  return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
116 
117 #if 0
118  /* If supplied state doesn't match current state, we assume it's
119  * an old request that time-warped somehow. Any error return would
120  * do in this case because it's irrelevant anyway.
121  *
122  * NB: We don't retrieve the remote host's state yet.
123  */
124  if (host->h_nsmstate && host->h_nsmstate != argp->state) {
126  } else
127 #endif
128 
129  /* Now try to lock the file */
130  resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
131  argp->block, &argp->cookie,
132  argp->reclaim);
133  if (resp->status == nlm_drop_reply)
134  rc = rpc_drop_reply;
135  else
136  dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
137 
138  nlmsvc_release_host(host);
139  nlm_release_file(file);
140  return rc;
141 }
142 
143 static __be32
144 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
145  struct nlm_res *resp)
146 {
147  struct nlm_host *host;
148  struct nlm_file *file;
149 
150  dprintk("lockd: CANCEL called\n");
151 
152  resp->cookie = argp->cookie;
153 
154  /* Don't accept requests during grace period */
155  if (locks_in_grace(SVC_NET(rqstp))) {
157  return rpc_success;
158  }
159 
160  /* Obtain client and file */
161  if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
162  return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
163 
164  /* Try to cancel request. */
165  resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock);
166 
167  dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
168  nlmsvc_release_host(host);
169  nlm_release_file(file);
170  return rpc_success;
171 }
172 
173 /*
174  * UNLOCK: release a lock
175  */
176 static __be32
177 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
178  struct nlm_res *resp)
179 {
180  struct nlm_host *host;
181  struct nlm_file *file;
182 
183  dprintk("lockd: UNLOCK called\n");
184 
185  resp->cookie = argp->cookie;
186 
187  /* Don't accept new lock requests during grace period */
188  if (locks_in_grace(SVC_NET(rqstp))) {
190  return rpc_success;
191  }
192 
193  /* Obtain client and file */
194  if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
195  return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
196 
197  /* Now try to remove the lock */
198  resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock);
199 
200  dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
201  nlmsvc_release_host(host);
202  nlm_release_file(file);
203  return rpc_success;
204 }
205 
206 /*
207  * GRANTED: A server calls us to tell that a process' lock request
208  * was granted
209  */
210 static __be32
211 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
212  struct nlm_res *resp)
213 {
214  resp->cookie = argp->cookie;
215 
216  dprintk("lockd: GRANTED called\n");
217  resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
218  dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
219  return rpc_success;
220 }
221 
222 /*
223  * This is the generic lockd callback for async RPC calls
224  */
225 static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
226 {
227  dprintk("lockd: %5u callback returned %d\n", task->tk_pid,
228  -task->tk_status);
229 }
230 
231 static void nlm4svc_callback_release(void *data)
232 {
233  nlmsvc_release_call(data);
234 }
235 
236 static const struct rpc_call_ops nlm4svc_callback_ops = {
237  .rpc_call_done = nlm4svc_callback_exit,
238  .rpc_release = nlm4svc_callback_release,
239 };
240 
241 /*
242  * `Async' versions of the above service routines. They aren't really,
243  * because we send the callback before the reply proper. I hope this
244  * doesn't break any clients.
245  */
246 static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
247  __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
248 {
249  struct nlm_host *host;
250  struct nlm_rqst *call;
251  __be32 stat;
252 
253  host = nlmsvc_lookup_host(rqstp,
254  argp->lock.caller,
255  argp->lock.len);
256  if (host == NULL)
257  return rpc_system_err;
258 
259  call = nlm_alloc_call(host);
260  nlmsvc_release_host(host);
261  if (call == NULL)
262  return rpc_system_err;
263 
264  stat = func(rqstp, argp, &call->a_res);
265  if (stat != 0) {
266  nlmsvc_release_call(call);
267  return stat;
268  }
269 
270  call->a_flags = RPC_TASK_ASYNC;
271  if (nlm_async_reply(call, proc, &nlm4svc_callback_ops) < 0)
272  return rpc_system_err;
273  return rpc_success;
274 }
275 
276 static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
277  void *resp)
278 {
279  dprintk("lockd: TEST_MSG called\n");
280  return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test);
281 }
282 
283 static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
284  void *resp)
285 {
286  dprintk("lockd: LOCK_MSG called\n");
287  return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock);
288 }
289 
290 static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
291  void *resp)
292 {
293  dprintk("lockd: CANCEL_MSG called\n");
294  return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel);
295 }
296 
297 static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
298  void *resp)
299 {
300  dprintk("lockd: UNLOCK_MSG called\n");
301  return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock);
302 }
303 
304 static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
305  void *resp)
306 {
307  dprintk("lockd: GRANTED_MSG called\n");
308  return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlm4svc_proc_granted);
309 }
310 
311 /*
312  * SHARE: create a DOS share or alter existing share.
313  */
314 static __be32
315 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
316  struct nlm_res *resp)
317 {
318  struct nlm_host *host;
319  struct nlm_file *file;
320 
321  dprintk("lockd: SHARE called\n");
322 
323  resp->cookie = argp->cookie;
324 
325  /* Don't accept new lock requests during grace period */
326  if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
328  return rpc_success;
329  }
330 
331  /* Obtain client and file */
332  if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
333  return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
334 
335  /* Now try to create the share */
336  resp->status = nlmsvc_share_file(host, file, argp);
337 
338  dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
339  nlmsvc_release_host(host);
340  nlm_release_file(file);
341  return rpc_success;
342 }
343 
344 /*
345  * UNSHARE: Release a DOS share.
346  */
347 static __be32
348 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
349  struct nlm_res *resp)
350 {
351  struct nlm_host *host;
352  struct nlm_file *file;
353 
354  dprintk("lockd: UNSHARE called\n");
355 
356  resp->cookie = argp->cookie;
357 
358  /* Don't accept requests during grace period */
359  if (locks_in_grace(SVC_NET(rqstp))) {
361  return rpc_success;
362  }
363 
364  /* Obtain client and file */
365  if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
366  return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
367 
368  /* Now try to lock the file */
369  resp->status = nlmsvc_unshare_file(host, file, argp);
370 
371  dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
372  nlmsvc_release_host(host);
373  nlm_release_file(file);
374  return rpc_success;
375 }
376 
377 /*
378  * NM_LOCK: Create an unmonitored lock
379  */
380 static __be32
381 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
382  struct nlm_res *resp)
383 {
384  dprintk("lockd: NM_LOCK called\n");
385 
386  argp->monitor = 0; /* just clean the monitor flag */
387  return nlm4svc_proc_lock(rqstp, argp, resp);
388 }
389 
390 /*
391  * FREE_ALL: Release all locks and shares held by client
392  */
393 static __be32
394 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
395  void *resp)
396 {
397  struct nlm_host *host;
398 
399  /* Obtain client */
400  if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
401  return rpc_success;
402 
404  nlmsvc_release_host(host);
405  return rpc_success;
406 }
407 
408 /*
409  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
410  */
411 static __be32
412 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
413  void *resp)
414 {
415  dprintk("lockd: SM_NOTIFY called\n");
416 
417  if (!nlm_privileged_requester(rqstp)) {
418  char buf[RPC_MAX_ADDRBUFLEN];
419  printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
420  svc_print_addr(rqstp, buf, sizeof(buf)));
421  return rpc_system_err;
422  }
423 
424  nlm_host_rebooted(argp);
425  return rpc_success;
426 }
427 
428 /*
429  * client sent a GRANTED_RES, let's remove the associated block
430  */
431 static __be32
432 nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
433  void *resp)
434 {
435  if (!nlmsvc_ops)
436  return rpc_success;
437 
438  dprintk("lockd: GRANTED_RES called\n");
439 
440  nlmsvc_grant_reply(&argp->cookie, argp->status);
441  return rpc_success;
442 }
443 
444 
445 /*
446  * NLM Server procedures.
447  */
448 
449 #define nlm4svc_encode_norep nlm4svc_encode_void
450 #define nlm4svc_decode_norep nlm4svc_decode_void
451 #define nlm4svc_decode_testres nlm4svc_decode_void
452 #define nlm4svc_decode_lockres nlm4svc_decode_void
453 #define nlm4svc_decode_unlockres nlm4svc_decode_void
454 #define nlm4svc_decode_cancelres nlm4svc_decode_void
455 #define nlm4svc_decode_grantedres nlm4svc_decode_void
456 
457 #define nlm4svc_proc_none nlm4svc_proc_null
458 #define nlm4svc_proc_test_res nlm4svc_proc_null
459 #define nlm4svc_proc_lock_res nlm4svc_proc_null
460 #define nlm4svc_proc_cancel_res nlm4svc_proc_null
461 #define nlm4svc_proc_unlock_res nlm4svc_proc_null
462 
463 struct nlm_void { int dummy; };
464 
465 #define PROC(name, xargt, xrest, argt, rest, respsize) \
466  { .pc_func = (svc_procfunc) nlm4svc_proc_##name, \
467  .pc_decode = (kxdrproc_t) nlm4svc_decode_##xargt, \
468  .pc_encode = (kxdrproc_t) nlm4svc_encode_##xrest, \
469  .pc_release = NULL, \
470  .pc_argsize = sizeof(struct nlm_##argt), \
471  .pc_ressize = sizeof(struct nlm_##rest), \
472  .pc_xdrressize = respsize, \
473  }
474 #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */
475 #define No (1+1024/4) /* netobj */
476 #define St 1 /* status */
477 #define Rg 4 /* range (offset + length) */
479  PROC(null, void, void, void, void, 1),
480  PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg),
481  PROC(lock, lockargs, res, args, res, Ck+St),
482  PROC(cancel, cancargs, res, args, res, Ck+St),
483  PROC(unlock, unlockargs, res, args, res, Ck+St),
484  PROC(granted, testargs, res, args, res, Ck+St),
485  PROC(test_msg, testargs, norep, args, void, 1),
486  PROC(lock_msg, lockargs, norep, args, void, 1),
487  PROC(cancel_msg, cancargs, norep, args, void, 1),
488  PROC(unlock_msg, unlockargs, norep, args, void, 1),
489  PROC(granted_msg, testargs, norep, args, void, 1),
490  PROC(test_res, testres, norep, res, void, 1),
491  PROC(lock_res, lockres, norep, res, void, 1),
492  PROC(cancel_res, cancelres, norep, res, void, 1),
493  PROC(unlock_res, unlockres, norep, res, void, 1),
494  PROC(granted_res, res, norep, res, void, 1),
495  /* statd callback */
496  PROC(sm_notify, reboot, void, reboot, void, 1),
497  PROC(none, void, void, void, void, 0),
498  PROC(none, void, void, void, void, 0),
499  PROC(none, void, void, void, void, 0),
500  PROC(share, shareargs, shareres, args, res, Ck+St+1),
501  PROC(unshare, shareargs, shareres, args, res, Ck+St+1),
502  PROC(nm_lock, lockargs, res, args, res, Ck+St),
503  PROC(free_all, notify, void, args, void, 1),
504 
505 };