1 // SPDX-License-Identifier: GPL-2.0
3 * linux/fs/lockd/xdr4.c
5 * XDR support for lockd and the lock client.
7 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8 * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
11 #include <linux/types.h>
12 #include <linux/sched.h>
13 #include <linux/nfs.h>
15 #include <linux/sunrpc/xdr.h>
16 #include <linux/sunrpc/clnt.h>
17 #include <linux/sunrpc/svc.h>
18 #include <linux/sunrpc/stats.h>
19 #include <linux/lockd/lockd.h>
24 loff_t_to_s64(loff_t offset
)
27 if (offset
> NLM4_OFFSET_MAX
)
28 res
= NLM4_OFFSET_MAX
;
29 else if (offset
< -NLM4_OFFSET_MAX
)
30 res
= -NLM4_OFFSET_MAX
;
36 void nlm4svc_set_file_lock_range(struct file_lock
*fl
, u64 off
, u64 len
)
38 s64 end
= off
+ len
- 1;
41 if (len
== 0 || end
< 0)
42 fl
->fl_end
= OFFSET_MAX
;
48 * NLM file handles are defined by specification to be a variable-length
49 * XDR opaque no longer than 1024 bytes. However, this implementation
50 * limits their length to the size of an NFSv3 file handle.
53 svcxdr_decode_fhandle(struct xdr_stream
*xdr
, struct nfs_fh
*fh
)
58 if (xdr_stream_decode_u32(xdr
, &len
) < 0)
60 if (len
> NFS_MAXFHSIZE
)
63 p
= xdr_inline_decode(xdr
, len
);
67 memcpy(fh
->data
, p
, len
);
68 memset(fh
->data
+ len
, 0, sizeof(fh
->data
) - len
);
74 svcxdr_decode_lock(struct xdr_stream
*xdr
, struct nlm_lock
*lock
)
76 struct file_lock
*fl
= &lock
->fl
;
78 if (!svcxdr_decode_string(xdr
, &lock
->caller
, &lock
->len
))
80 if (!svcxdr_decode_fhandle(xdr
, &lock
->fh
))
82 if (!svcxdr_decode_owner(xdr
, &lock
->oh
))
84 if (xdr_stream_decode_u32(xdr
, &lock
->svid
) < 0)
86 if (xdr_stream_decode_u64(xdr
, &lock
->lock_start
) < 0)
88 if (xdr_stream_decode_u64(xdr
, &lock
->lock_len
) < 0)
92 fl
->c
.flc_type
= F_RDLCK
;
93 nlm4svc_set_file_lock_range(fl
, lock
->lock_start
, lock
->lock_len
);
98 svcxdr_encode_holder(struct xdr_stream
*xdr
, const struct nlm_lock
*lock
)
100 const struct file_lock
*fl
= &lock
->fl
;
104 if (xdr_stream_encode_bool(xdr
, fl
->c
.flc_type
!= F_RDLCK
) < 0)
106 if (xdr_stream_encode_u32(xdr
, lock
->svid
) < 0)
108 if (!svcxdr_encode_owner(xdr
, &lock
->oh
))
110 start
= loff_t_to_s64(fl
->fl_start
);
111 if (fl
->fl_end
== OFFSET_MAX
)
114 len
= loff_t_to_s64(fl
->fl_end
- fl
->fl_start
+ 1);
115 if (xdr_stream_encode_u64(xdr
, start
) < 0)
117 if (xdr_stream_encode_u64(xdr
, len
) < 0)
124 svcxdr_encode_testrply(struct xdr_stream
*xdr
, const struct nlm_res
*resp
)
126 if (!svcxdr_encode_stats(xdr
, resp
->status
))
128 switch (resp
->status
) {
130 if (!svcxdr_encode_holder(xdr
, &resp
->lock
))
139 * Decode Call arguments
143 nlm4svc_decode_void(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
149 nlm4svc_decode_testargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
151 struct nlm_args
*argp
= rqstp
->rq_argp
;
154 if (!svcxdr_decode_cookie(xdr
, &argp
->cookie
))
156 if (xdr_stream_decode_bool(xdr
, &exclusive
) < 0)
158 if (!svcxdr_decode_lock(xdr
, &argp
->lock
))
161 argp
->lock
.fl
.c
.flc_type
= F_WRLCK
;
167 nlm4svc_decode_lockargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
169 struct nlm_args
*argp
= rqstp
->rq_argp
;
172 if (!svcxdr_decode_cookie(xdr
, &argp
->cookie
))
174 if (xdr_stream_decode_bool(xdr
, &argp
->block
) < 0)
176 if (xdr_stream_decode_bool(xdr
, &exclusive
) < 0)
178 if (!svcxdr_decode_lock(xdr
, &argp
->lock
))
181 argp
->lock
.fl
.c
.flc_type
= F_WRLCK
;
182 if (xdr_stream_decode_bool(xdr
, &argp
->reclaim
) < 0)
184 if (xdr_stream_decode_u32(xdr
, &argp
->state
) < 0)
186 argp
->monitor
= 1; /* monitor client by default */
192 nlm4svc_decode_cancargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
194 struct nlm_args
*argp
= rqstp
->rq_argp
;
197 if (!svcxdr_decode_cookie(xdr
, &argp
->cookie
))
199 if (xdr_stream_decode_bool(xdr
, &argp
->block
) < 0)
201 if (xdr_stream_decode_bool(xdr
, &exclusive
) < 0)
203 if (!svcxdr_decode_lock(xdr
, &argp
->lock
))
206 argp
->lock
.fl
.c
.flc_type
= F_WRLCK
;
212 nlm4svc_decode_unlockargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
214 struct nlm_args
*argp
= rqstp
->rq_argp
;
216 if (!svcxdr_decode_cookie(xdr
, &argp
->cookie
))
218 if (!svcxdr_decode_lock(xdr
, &argp
->lock
))
220 argp
->lock
.fl
.c
.flc_type
= F_UNLCK
;
226 nlm4svc_decode_res(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
228 struct nlm_res
*resp
= rqstp
->rq_argp
;
230 if (!svcxdr_decode_cookie(xdr
, &resp
->cookie
))
232 if (!svcxdr_decode_stats(xdr
, &resp
->status
))
239 nlm4svc_decode_reboot(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
241 struct nlm_reboot
*argp
= rqstp
->rq_argp
;
245 if (xdr_stream_decode_u32(xdr
, &len
) < 0)
247 if (len
> SM_MAXSTRLEN
)
249 p
= xdr_inline_decode(xdr
, len
);
253 argp
->mon
= (char *)p
;
254 if (xdr_stream_decode_u32(xdr
, &argp
->state
) < 0)
256 p
= xdr_inline_decode(xdr
, SM_PRIV_SIZE
);
259 memcpy(&argp
->priv
.data
, p
, sizeof(argp
->priv
.data
));
265 nlm4svc_decode_shareargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
267 struct nlm_args
*argp
= rqstp
->rq_argp
;
268 struct nlm_lock
*lock
= &argp
->lock
;
270 locks_init_lock(&lock
->fl
);
271 lock
->svid
= ~(u32
)0;
273 if (!svcxdr_decode_cookie(xdr
, &argp
->cookie
))
275 if (!svcxdr_decode_string(xdr
, &lock
->caller
, &lock
->len
))
277 if (!svcxdr_decode_fhandle(xdr
, &lock
->fh
))
279 if (!svcxdr_decode_owner(xdr
, &lock
->oh
))
281 /* XXX: Range checks are missing in the original code */
282 if (xdr_stream_decode_u32(xdr
, &argp
->fsm_mode
) < 0)
284 if (xdr_stream_decode_u32(xdr
, &argp
->fsm_access
) < 0)
291 nlm4svc_decode_notify(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
293 struct nlm_args
*argp
= rqstp
->rq_argp
;
294 struct nlm_lock
*lock
= &argp
->lock
;
296 if (!svcxdr_decode_string(xdr
, &lock
->caller
, &lock
->len
))
298 if (xdr_stream_decode_u32(xdr
, &argp
->state
) < 0)
306 * Encode Reply results
310 nlm4svc_encode_void(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
316 nlm4svc_encode_testres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
318 struct nlm_res
*resp
= rqstp
->rq_resp
;
320 return svcxdr_encode_cookie(xdr
, &resp
->cookie
) &&
321 svcxdr_encode_testrply(xdr
, resp
);
325 nlm4svc_encode_res(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
327 struct nlm_res
*resp
= rqstp
->rq_resp
;
329 return svcxdr_encode_cookie(xdr
, &resp
->cookie
) &&
330 svcxdr_encode_stats(xdr
, resp
->status
);
334 nlm4svc_encode_shareres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
336 struct nlm_res
*resp
= rqstp
->rq_resp
;
338 if (!svcxdr_encode_cookie(xdr
, &resp
->cookie
))
340 if (!svcxdr_encode_stats(xdr
, resp
->status
))
343 if (xdr_stream_encode_u32(xdr
, 0) < 0)