close the race in nlmsvc_free_block()
[linux-3.10.git] / fs / lockd / xdr.c
1 /*
2  * linux/fs/lockd/xdr.c
3  *
4  * XDR support for lockd and the lock client.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/nfs.h>
12
13 #include <linux/sunrpc/xdr.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/sunrpc/svc.h>
16 #include <linux/sunrpc/stats.h>
17 #include <linux/lockd/lockd.h>
18
19 #define NLMDBG_FACILITY         NLMDBG_XDR
20
21
22 static inline loff_t
23 s32_to_loff_t(__s32 offset)
24 {
25         return (loff_t)offset;
26 }
27
28 static inline __s32
29 loff_t_to_s32(loff_t offset)
30 {
31         __s32 res;
32         if (offset >= NLM_OFFSET_MAX)
33                 res = NLM_OFFSET_MAX;
34         else if (offset <= -NLM_OFFSET_MAX)
35                 res = -NLM_OFFSET_MAX;
36         else
37                 res = offset;
38         return res;
39 }
40
41 /*
42  * XDR functions for basic NLM types
43  */
44 static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
45 {
46         unsigned int    len;
47
48         len = ntohl(*p++);
49         
50         if(len==0)
51         {
52                 c->len=4;
53                 memset(c->data, 0, 4);  /* hockeypux brain damage */
54         }
55         else if(len<=NLM_MAXCOOKIELEN)
56         {
57                 c->len=len;
58                 memcpy(c->data, p, len);
59                 p+=XDR_QUADLEN(len);
60         }
61         else 
62         {
63                 dprintk("lockd: bad cookie size %d (only cookies under "
64                         "%d bytes are supported.)\n",
65                                 len, NLM_MAXCOOKIELEN);
66                 return NULL;
67         }
68         return p;
69 }
70
71 static inline __be32 *
72 nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
73 {
74         *p++ = htonl(c->len);
75         memcpy(p, c->data, c->len);
76         p+=XDR_QUADLEN(c->len);
77         return p;
78 }
79
80 static __be32 *
81 nlm_decode_fh(__be32 *p, struct nfs_fh *f)
82 {
83         unsigned int    len;
84
85         if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
86                 dprintk("lockd: bad fhandle size %d (should be %d)\n",
87                         len, NFS2_FHSIZE);
88                 return NULL;
89         }
90         f->size = NFS2_FHSIZE;
91         memset(f->data, 0, sizeof(f->data));
92         memcpy(f->data, p, NFS2_FHSIZE);
93         return p + XDR_QUADLEN(NFS2_FHSIZE);
94 }
95
96 static inline __be32 *
97 nlm_encode_fh(__be32 *p, struct nfs_fh *f)
98 {
99         *p++ = htonl(NFS2_FHSIZE);
100         memcpy(p, f->data, NFS2_FHSIZE);
101         return p + XDR_QUADLEN(NFS2_FHSIZE);
102 }
103
104 /*
105  * Encode and decode owner handle
106  */
107 static inline __be32 *
108 nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
109 {
110         return xdr_decode_netobj(p, oh);
111 }
112
113 static inline __be32 *
114 nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
115 {
116         return xdr_encode_netobj(p, oh);
117 }
118
119 static __be32 *
120 nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
121 {
122         struct file_lock        *fl = &lock->fl;
123         s32                     start, len, end;
124
125         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
126                                             &lock->len,
127                                             NLM_MAXSTRLEN))
128          || !(p = nlm_decode_fh(p, &lock->fh))
129          || !(p = nlm_decode_oh(p, &lock->oh)))
130                 return NULL;
131         lock->svid  = ntohl(*p++);
132
133         locks_init_lock(fl);
134         fl->fl_owner = current->files;
135         fl->fl_pid   = (pid_t)lock->svid;
136         fl->fl_flags = FL_POSIX;
137         fl->fl_type  = F_RDLCK;         /* as good as anything else */
138         start = ntohl(*p++);
139         len = ntohl(*p++);
140         end = start + len - 1;
141
142         fl->fl_start = s32_to_loff_t(start);
143
144         if (len == 0 || end < 0)
145                 fl->fl_end = OFFSET_MAX;
146         else
147                 fl->fl_end = s32_to_loff_t(end);
148         return p;
149 }
150
151 /*
152  * Encode result of a TEST/TEST_MSG call
153  */
154 static __be32 *
155 nlm_encode_testres(__be32 *p, struct nlm_res *resp)
156 {
157         s32             start, len;
158
159         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
160                 return NULL;
161         *p++ = resp->status;
162
163         if (resp->status == nlm_lck_denied) {
164                 struct file_lock        *fl = &resp->lock.fl;
165
166                 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
167                 *p++ = htonl(resp->lock.svid);
168
169                 /* Encode owner handle. */
170                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
171                         return NULL;
172
173                 start = loff_t_to_s32(fl->fl_start);
174                 if (fl->fl_end == OFFSET_MAX)
175                         len = 0;
176                 else
177                         len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
178
179                 *p++ = htonl(start);
180                 *p++ = htonl(len);
181         }
182
183         return p;
184 }
185
186
187 /*
188  * First, the server side XDR functions
189  */
190 int
191 nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
192 {
193         u32     exclusive;
194
195         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
196                 return 0;
197
198         exclusive = ntohl(*p++);
199         if (!(p = nlm_decode_lock(p, &argp->lock)))
200                 return 0;
201         if (exclusive)
202                 argp->lock.fl.fl_type = F_WRLCK;
203
204         return xdr_argsize_check(rqstp, p);
205 }
206
207 int
208 nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
209 {
210         if (!(p = nlm_encode_testres(p, resp)))
211                 return 0;
212         return xdr_ressize_check(rqstp, p);
213 }
214
215 int
216 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
217 {
218         u32     exclusive;
219
220         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
221                 return 0;
222         argp->block  = ntohl(*p++);
223         exclusive    = ntohl(*p++);
224         if (!(p = nlm_decode_lock(p, &argp->lock)))
225                 return 0;
226         if (exclusive)
227                 argp->lock.fl.fl_type = F_WRLCK;
228         argp->reclaim = ntohl(*p++);
229         argp->state   = ntohl(*p++);
230         argp->monitor = 1;              /* monitor client by default */
231
232         return xdr_argsize_check(rqstp, p);
233 }
234
235 int
236 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
237 {
238         u32     exclusive;
239
240         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
241                 return 0;
242         argp->block = ntohl(*p++);
243         exclusive = ntohl(*p++);
244         if (!(p = nlm_decode_lock(p, &argp->lock)))
245                 return 0;
246         if (exclusive)
247                 argp->lock.fl.fl_type = F_WRLCK;
248         return xdr_argsize_check(rqstp, p);
249 }
250
251 int
252 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
253 {
254         if (!(p = nlm_decode_cookie(p, &argp->cookie))
255          || !(p = nlm_decode_lock(p, &argp->lock)))
256                 return 0;
257         argp->lock.fl.fl_type = F_UNLCK;
258         return xdr_argsize_check(rqstp, p);
259 }
260
261 int
262 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
263 {
264         struct nlm_lock *lock = &argp->lock;
265
266         memset(lock, 0, sizeof(*lock));
267         locks_init_lock(&lock->fl);
268         lock->svid = ~(u32) 0;
269         lock->fl.fl_pid = (pid_t)lock->svid;
270
271         if (!(p = nlm_decode_cookie(p, &argp->cookie))
272          || !(p = xdr_decode_string_inplace(p, &lock->caller,
273                                             &lock->len, NLM_MAXSTRLEN))
274          || !(p = nlm_decode_fh(p, &lock->fh))
275          || !(p = nlm_decode_oh(p, &lock->oh)))
276                 return 0;
277         argp->fsm_mode = ntohl(*p++);
278         argp->fsm_access = ntohl(*p++);
279         return xdr_argsize_check(rqstp, p);
280 }
281
282 int
283 nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
284 {
285         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
286                 return 0;
287         *p++ = resp->status;
288         *p++ = xdr_zero;                /* sequence argument */
289         return xdr_ressize_check(rqstp, p);
290 }
291
292 int
293 nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
294 {
295         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
296                 return 0;
297         *p++ = resp->status;
298         return xdr_ressize_check(rqstp, p);
299 }
300
301 int
302 nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
303 {
304         struct nlm_lock *lock = &argp->lock;
305
306         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
307                                             &lock->len, NLM_MAXSTRLEN)))
308                 return 0;
309         argp->state = ntohl(*p++);
310         return xdr_argsize_check(rqstp, p);
311 }
312
313 int
314 nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
315 {
316         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
317                 return 0;
318         argp->state = ntohl(*p++);
319         memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
320         p += XDR_QUADLEN(SM_PRIV_SIZE);
321         return xdr_argsize_check(rqstp, p);
322 }
323
324 int
325 nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
326 {
327         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
328                 return 0;
329         resp->status = *p++;
330         return xdr_argsize_check(rqstp, p);
331 }
332
333 int
334 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
335 {
336         return xdr_argsize_check(rqstp, p);
337 }
338
339 int
340 nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
341 {
342         return xdr_ressize_check(rqstp, p);
343 }