| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/fs/lockd/clnt4xdr.c | 
 | 3 |  * | 
 | 4 |  * XDR functions to encode/decode NLM version 4 RPC arguments and results. | 
 | 5 |  * | 
 | 6 |  * NLM client-side only. | 
 | 7 |  * | 
 | 8 |  * Copyright (C) 2010, Oracle.  All rights reserved. | 
 | 9 |  */ | 
 | 10 |  | 
 | 11 | #include <linux/types.h> | 
 | 12 | #include <linux/sunrpc/xdr.h> | 
 | 13 | #include <linux/sunrpc/clnt.h> | 
 | 14 | #include <linux/sunrpc/stats.h> | 
 | 15 | #include <linux/lockd/lockd.h> | 
 | 16 |  | 
 | 17 | #define NLMDBG_FACILITY		NLMDBG_XDR | 
 | 18 |  | 
 | 19 | #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) | 
 | 20 | #  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" | 
 | 21 | #endif | 
 | 22 |  | 
 | 23 | #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) | 
 | 24 | #  error "NLM host name cannot be larger than NLM's maximum string length!" | 
 | 25 | #endif | 
 | 26 |  | 
 | 27 | /* | 
 | 28 |  * Declare the space requirements for NLM arguments and replies as | 
 | 29 |  * number of 32bit-words | 
 | 30 |  */ | 
 | 31 | #define NLM4_void_sz		(0) | 
 | 32 | #define NLM4_cookie_sz		(1+(NLM_MAXCOOKIELEN>>2)) | 
 | 33 | #define NLM4_caller_sz		(1+(NLMCLNT_OHSIZE>>2)) | 
 | 34 | #define NLM4_owner_sz		(1+(NLMCLNT_OHSIZE>>2)) | 
 | 35 | #define NLM4_fhandle_sz		(1+(NFS3_FHSIZE>>2)) | 
 | 36 | #define NLM4_lock_sz		(5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz) | 
 | 37 | #define NLM4_holder_sz		(6+NLM4_owner_sz) | 
 | 38 |  | 
 | 39 | #define NLM4_testargs_sz	(NLM4_cookie_sz+1+NLM4_lock_sz) | 
 | 40 | #define NLM4_lockargs_sz	(NLM4_cookie_sz+4+NLM4_lock_sz) | 
 | 41 | #define NLM4_cancargs_sz	(NLM4_cookie_sz+2+NLM4_lock_sz) | 
 | 42 | #define NLM4_unlockargs_sz	(NLM4_cookie_sz+NLM4_lock_sz) | 
 | 43 |  | 
 | 44 | #define NLM4_testres_sz		(NLM4_cookie_sz+1+NLM4_holder_sz) | 
 | 45 | #define NLM4_res_sz		(NLM4_cookie_sz+1) | 
 | 46 | #define NLM4_norep_sz		(0) | 
 | 47 |  | 
 | 48 |  | 
 | 49 | static s64 loff_t_to_s64(loff_t offset) | 
 | 50 | { | 
 | 51 | 	s64 res; | 
 | 52 |  | 
 | 53 | 	if (offset >= NLM4_OFFSET_MAX) | 
 | 54 | 		res = NLM4_OFFSET_MAX; | 
 | 55 | 	else if (offset <= -NLM4_OFFSET_MAX) | 
 | 56 | 		res = -NLM4_OFFSET_MAX; | 
 | 57 | 	else | 
 | 58 | 		res = offset; | 
 | 59 | 	return res; | 
 | 60 | } | 
 | 61 |  | 
 | 62 | static void nlm4_compute_offsets(const struct nlm_lock *lock, | 
 | 63 | 				 u64 *l_offset, u64 *l_len) | 
 | 64 | { | 
 | 65 | 	const struct file_lock *fl = &lock->fl; | 
 | 66 |  | 
 | 67 | 	BUG_ON(fl->fl_start > NLM4_OFFSET_MAX); | 
 | 68 | 	BUG_ON(fl->fl_end > NLM4_OFFSET_MAX && | 
 | 69 | 				fl->fl_end != OFFSET_MAX); | 
 | 70 |  | 
 | 71 | 	*l_offset = loff_t_to_s64(fl->fl_start); | 
 | 72 | 	if (fl->fl_end == OFFSET_MAX) | 
 | 73 | 		*l_len = 0; | 
 | 74 | 	else | 
 | 75 | 		*l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); | 
 | 76 | } | 
 | 77 |  | 
 | 78 | /* | 
 | 79 |  * Handle decode buffer overflows out-of-line. | 
 | 80 |  */ | 
 | 81 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 
 | 82 | { | 
 | 83 | 	dprintk("lockd: %s prematurely hit the end of our receive buffer. " | 
 | 84 | 		"Remaining buffer length is %tu words.\n", | 
 | 85 | 		func, xdr->end - xdr->p); | 
 | 86 | } | 
 | 87 |  | 
 | 88 |  | 
 | 89 | /* | 
 | 90 |  * Encode/decode NLMv4 basic data types | 
 | 91 |  * | 
 | 92 |  * Basic NLMv4 data types are defined in Appendix II, section 6.1.4 | 
 | 93 |  * of RFC 1813: "NFS Version 3 Protocol Specification" and in Chapter | 
 | 94 |  * 10 of X/Open's "Protocols for Interworking: XNFS, Version 3W". | 
 | 95 |  * | 
 | 96 |  * Not all basic data types have their own encoding and decoding | 
 | 97 |  * functions.  For run-time efficiency, some data types are encoded | 
 | 98 |  * or decoded inline. | 
 | 99 |  */ | 
 | 100 |  | 
 | 101 | static void encode_bool(struct xdr_stream *xdr, const int value) | 
 | 102 | { | 
 | 103 | 	__be32 *p; | 
 | 104 |  | 
 | 105 | 	p = xdr_reserve_space(xdr, 4); | 
 | 106 | 	*p = value ? xdr_one : xdr_zero; | 
 | 107 | } | 
 | 108 |  | 
 | 109 | static void encode_int32(struct xdr_stream *xdr, const s32 value) | 
 | 110 | { | 
 | 111 | 	__be32 *p; | 
 | 112 |  | 
 | 113 | 	p = xdr_reserve_space(xdr, 4); | 
 | 114 | 	*p = cpu_to_be32(value); | 
 | 115 | } | 
 | 116 |  | 
 | 117 | /* | 
 | 118 |  *	typedef opaque netobj<MAXNETOBJ_SZ> | 
 | 119 |  */ | 
 | 120 | static void encode_netobj(struct xdr_stream *xdr, | 
 | 121 | 			  const u8 *data, const unsigned int length) | 
 | 122 | { | 
 | 123 | 	__be32 *p; | 
 | 124 |  | 
 | 125 | 	BUG_ON(length > XDR_MAX_NETOBJ); | 
 | 126 | 	p = xdr_reserve_space(xdr, 4 + length); | 
 | 127 | 	xdr_encode_opaque(p, data, length); | 
 | 128 | } | 
 | 129 |  | 
 | 130 | static int decode_netobj(struct xdr_stream *xdr, | 
 | 131 | 			 struct xdr_netobj *obj) | 
 | 132 | { | 
 | 133 | 	u32 length; | 
 | 134 | 	__be32 *p; | 
 | 135 |  | 
 | 136 | 	p = xdr_inline_decode(xdr, 4); | 
 | 137 | 	if (unlikely(p == NULL)) | 
 | 138 | 		goto out_overflow; | 
 | 139 | 	length = be32_to_cpup(p++); | 
 | 140 | 	if (unlikely(length > XDR_MAX_NETOBJ)) | 
 | 141 | 		goto out_size; | 
 | 142 | 	obj->len = length; | 
 | 143 | 	obj->data = (u8 *)p; | 
 | 144 | 	return 0; | 
 | 145 | out_size: | 
 | 146 | 	dprintk("NFS: returned netobj was too long: %u\n", length); | 
 | 147 | 	return -EIO; | 
 | 148 | out_overflow: | 
 | 149 | 	print_overflow_msg(__func__, xdr); | 
 | 150 | 	return -EIO; | 
 | 151 | } | 
 | 152 |  | 
 | 153 | /* | 
 | 154 |  *	netobj cookie; | 
 | 155 |  */ | 
 | 156 | static void encode_cookie(struct xdr_stream *xdr, | 
 | 157 | 			  const struct nlm_cookie *cookie) | 
 | 158 | { | 
 | 159 | 	BUG_ON(cookie->len > NLM_MAXCOOKIELEN); | 
 | 160 | 	encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); | 
 | 161 | } | 
 | 162 |  | 
 | 163 | static int decode_cookie(struct xdr_stream *xdr, | 
 | 164 | 			     struct nlm_cookie *cookie) | 
 | 165 | { | 
 | 166 | 	u32 length; | 
 | 167 | 	__be32 *p; | 
 | 168 |  | 
 | 169 | 	p = xdr_inline_decode(xdr, 4); | 
 | 170 | 	if (unlikely(p == NULL)) | 
 | 171 | 		goto out_overflow; | 
 | 172 | 	length = be32_to_cpup(p++); | 
 | 173 | 	/* apparently HPUX can return empty cookies */ | 
 | 174 | 	if (length == 0) | 
 | 175 | 		goto out_hpux; | 
 | 176 | 	if (length > NLM_MAXCOOKIELEN) | 
 | 177 | 		goto out_size; | 
 | 178 | 	p = xdr_inline_decode(xdr, length); | 
 | 179 | 	if (unlikely(p == NULL)) | 
 | 180 | 		goto out_overflow; | 
 | 181 | 	cookie->len = length; | 
 | 182 | 	memcpy(cookie->data, p, length); | 
 | 183 | 	return 0; | 
 | 184 | out_hpux: | 
 | 185 | 	cookie->len = 4; | 
 | 186 | 	memset(cookie->data, 0, 4); | 
 | 187 | 	return 0; | 
 | 188 | out_size: | 
 | 189 | 	dprintk("NFS: returned cookie was too long: %u\n", length); | 
 | 190 | 	return -EIO; | 
 | 191 | out_overflow: | 
 | 192 | 	print_overflow_msg(__func__, xdr); | 
 | 193 | 	return -EIO; | 
 | 194 | } | 
 | 195 |  | 
 | 196 | /* | 
 | 197 |  *	netobj fh; | 
 | 198 |  */ | 
 | 199 | static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) | 
 | 200 | { | 
 | 201 | 	BUG_ON(fh->size > NFS3_FHSIZE); | 
 | 202 | 	encode_netobj(xdr, (u8 *)&fh->data, fh->size); | 
 | 203 | } | 
 | 204 |  | 
 | 205 | /* | 
 | 206 |  *	enum nlm4_stats { | 
 | 207 |  *		NLM4_GRANTED = 0, | 
 | 208 |  *		NLM4_DENIED = 1, | 
 | 209 |  *		NLM4_DENIED_NOLOCKS = 2, | 
 | 210 |  *		NLM4_BLOCKED = 3, | 
 | 211 |  *		NLM4_DENIED_GRACE_PERIOD = 4, | 
 | 212 |  *		NLM4_DEADLCK = 5, | 
 | 213 |  *		NLM4_ROFS = 6, | 
 | 214 |  *		NLM4_STALE_FH = 7, | 
 | 215 |  *		NLM4_FBIG = 8, | 
 | 216 |  *		NLM4_FAILED = 9 | 
 | 217 |  *	}; | 
 | 218 |  * | 
 | 219 |  *	struct nlm4_stat { | 
 | 220 |  *		nlm4_stats stat; | 
 | 221 |  *	}; | 
 | 222 |  * | 
 | 223 |  * NB: we don't swap bytes for the NLM status values.  The upper | 
 | 224 |  * layers deal directly with the status value in network byte | 
 | 225 |  * order. | 
 | 226 |  */ | 
 | 227 | static void encode_nlm4_stat(struct xdr_stream *xdr, | 
 | 228 | 			     const __be32 stat) | 
 | 229 | { | 
 | 230 | 	__be32 *p; | 
 | 231 |  | 
 | 232 | 	BUG_ON(be32_to_cpu(stat) > NLM_FAILED); | 
 | 233 | 	p = xdr_reserve_space(xdr, 4); | 
 | 234 | 	*p = stat; | 
 | 235 | } | 
 | 236 |  | 
 | 237 | static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat) | 
 | 238 | { | 
 | 239 | 	__be32 *p; | 
 | 240 |  | 
 | 241 | 	p = xdr_inline_decode(xdr, 4); | 
 | 242 | 	if (unlikely(p == NULL)) | 
 | 243 | 		goto out_overflow; | 
 | 244 | 	if (unlikely(*p > nlm4_failed)) | 
 | 245 | 		goto out_bad_xdr; | 
 | 246 | 	*stat = *p; | 
 | 247 | 	return 0; | 
 | 248 | out_bad_xdr: | 
 | 249 | 	dprintk("%s: server returned invalid nlm4_stats value: %u\n", | 
 | 250 | 			__func__, be32_to_cpup(p)); | 
 | 251 | 	return -EIO; | 
 | 252 | out_overflow: | 
 | 253 | 	print_overflow_msg(__func__, xdr); | 
 | 254 | 	return -EIO; | 
 | 255 | } | 
 | 256 |  | 
 | 257 | /* | 
 | 258 |  *	struct nlm4_holder { | 
 | 259 |  *		bool	exclusive; | 
 | 260 |  *		int32	svid; | 
 | 261 |  *		netobj	oh; | 
 | 262 |  *		uint64	l_offset; | 
 | 263 |  *		uint64	l_len; | 
 | 264 |  *	}; | 
 | 265 |  */ | 
 | 266 | static void encode_nlm4_holder(struct xdr_stream *xdr, | 
 | 267 | 			       const struct nlm_res *result) | 
 | 268 | { | 
 | 269 | 	const struct nlm_lock *lock = &result->lock; | 
 | 270 | 	u64 l_offset, l_len; | 
 | 271 | 	__be32 *p; | 
 | 272 |  | 
 | 273 | 	encode_bool(xdr, lock->fl.fl_type == F_RDLCK); | 
 | 274 | 	encode_int32(xdr, lock->svid); | 
 | 275 | 	encode_netobj(xdr, lock->oh.data, lock->oh.len); | 
 | 276 |  | 
 | 277 | 	p = xdr_reserve_space(xdr, 4 + 4); | 
 | 278 | 	nlm4_compute_offsets(lock, &l_offset, &l_len); | 
 | 279 | 	p = xdr_encode_hyper(p, l_offset); | 
 | 280 | 	xdr_encode_hyper(p, l_len); | 
 | 281 | } | 
 | 282 |  | 
 | 283 | static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) | 
 | 284 | { | 
 | 285 | 	struct nlm_lock *lock = &result->lock; | 
 | 286 | 	struct file_lock *fl = &lock->fl; | 
 | 287 | 	u64 l_offset, l_len; | 
 | 288 | 	u32 exclusive; | 
 | 289 | 	int error; | 
 | 290 | 	__be32 *p; | 
 | 291 | 	s32 end; | 
 | 292 |  | 
 | 293 | 	memset(lock, 0, sizeof(*lock)); | 
 | 294 | 	locks_init_lock(fl); | 
 | 295 |  | 
 | 296 | 	p = xdr_inline_decode(xdr, 4 + 4); | 
 | 297 | 	if (unlikely(p == NULL)) | 
 | 298 | 		goto out_overflow; | 
 | 299 | 	exclusive = be32_to_cpup(p++); | 
 | 300 | 	lock->svid = be32_to_cpup(p); | 
 | 301 | 	fl->fl_pid = (pid_t)lock->svid; | 
 | 302 |  | 
 | 303 | 	error = decode_netobj(xdr, &lock->oh); | 
 | 304 | 	if (unlikely(error)) | 
 | 305 | 		goto out; | 
 | 306 |  | 
 | 307 | 	p = xdr_inline_decode(xdr, 8 + 8); | 
 | 308 | 	if (unlikely(p == NULL)) | 
 | 309 | 		goto out_overflow; | 
 | 310 |  | 
 | 311 | 	fl->fl_flags = FL_POSIX; | 
 | 312 | 	fl->fl_type  = exclusive != 0 ? F_WRLCK : F_RDLCK; | 
 | 313 | 	p = xdr_decode_hyper(p, &l_offset); | 
 | 314 | 	xdr_decode_hyper(p, &l_len); | 
 | 315 | 	end = l_offset + l_len - 1; | 
 | 316 |  | 
 | 317 | 	fl->fl_start = (loff_t)l_offset; | 
 | 318 | 	if (l_len == 0 || end < 0) | 
 | 319 | 		fl->fl_end = OFFSET_MAX; | 
 | 320 | 	else | 
 | 321 | 		fl->fl_end = (loff_t)end; | 
 | 322 | 	error = 0; | 
 | 323 | out: | 
 | 324 | 	return error; | 
 | 325 | out_overflow: | 
 | 326 | 	print_overflow_msg(__func__, xdr); | 
 | 327 | 	return -EIO; | 
 | 328 | } | 
 | 329 |  | 
 | 330 | /* | 
 | 331 |  *	string caller_name<LM_MAXSTRLEN>; | 
 | 332 |  */ | 
 | 333 | static void encode_caller_name(struct xdr_stream *xdr, const char *name) | 
 | 334 | { | 
 | 335 | 	/* NB: client-side does not set lock->len */ | 
 | 336 | 	u32 length = strlen(name); | 
 | 337 | 	__be32 *p; | 
 | 338 |  | 
 | 339 | 	BUG_ON(length > NLM_MAXSTRLEN); | 
 | 340 | 	p = xdr_reserve_space(xdr, 4 + length); | 
 | 341 | 	xdr_encode_opaque(p, name, length); | 
 | 342 | } | 
 | 343 |  | 
 | 344 | /* | 
 | 345 |  *	struct nlm4_lock { | 
 | 346 |  *		string	caller_name<LM_MAXSTRLEN>; | 
 | 347 |  *		netobj	fh; | 
 | 348 |  *		netobj	oh; | 
 | 349 |  *		int32	svid; | 
 | 350 |  *		uint64	l_offset; | 
 | 351 |  *		uint64	l_len; | 
 | 352 |  *	}; | 
 | 353 |  */ | 
 | 354 | static void encode_nlm4_lock(struct xdr_stream *xdr, | 
 | 355 | 			     const struct nlm_lock *lock) | 
 | 356 | { | 
 | 357 | 	u64 l_offset, l_len; | 
 | 358 | 	__be32 *p; | 
 | 359 |  | 
 | 360 | 	encode_caller_name(xdr, lock->caller); | 
 | 361 | 	encode_fh(xdr, &lock->fh); | 
 | 362 | 	encode_netobj(xdr, lock->oh.data, lock->oh.len); | 
 | 363 |  | 
 | 364 | 	p = xdr_reserve_space(xdr, 4 + 8 + 8); | 
 | 365 | 	*p++ = cpu_to_be32(lock->svid); | 
 | 366 |  | 
 | 367 | 	nlm4_compute_offsets(lock, &l_offset, &l_len); | 
 | 368 | 	p = xdr_encode_hyper(p, l_offset); | 
 | 369 | 	xdr_encode_hyper(p, l_len); | 
 | 370 | } | 
 | 371 |  | 
 | 372 |  | 
 | 373 | /* | 
 | 374 |  * NLMv4 XDR encode functions | 
 | 375 |  * | 
 | 376 |  * NLMv4 argument types are defined in Appendix II of RFC 1813: | 
 | 377 |  * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's | 
 | 378 |  * "Protocols for Interworking: XNFS, Version 3W". | 
 | 379 |  */ | 
 | 380 |  | 
 | 381 | /* | 
 | 382 |  *	struct nlm4_testargs { | 
 | 383 |  *		netobj cookie; | 
 | 384 |  *		bool exclusive; | 
 | 385 |  *		struct nlm4_lock alock; | 
 | 386 |  *	}; | 
 | 387 |  */ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 388 | static void nlm4_xdr_enc_testargs(struct rpc_rqst *req, | 
 | 389 | 				  struct xdr_stream *xdr, | 
 | 390 | 				  const struct nlm_args *args) | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 391 | { | 
 | 392 | 	const struct nlm_lock *lock = &args->lock; | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 393 |  | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 394 | 	encode_cookie(xdr, &args->cookie); | 
 | 395 | 	encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | 
 | 396 | 	encode_nlm4_lock(xdr, lock); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 397 | } | 
 | 398 |  | 
 | 399 | /* | 
 | 400 |  *	struct nlm4_lockargs { | 
 | 401 |  *		netobj cookie; | 
 | 402 |  *		bool block; | 
 | 403 |  *		bool exclusive; | 
 | 404 |  *		struct nlm4_lock alock; | 
 | 405 |  *		bool reclaim; | 
 | 406 |  *		int state; | 
 | 407 |  *	}; | 
 | 408 |  */ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 409 | static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req, | 
 | 410 | 				  struct xdr_stream *xdr, | 
 | 411 | 				  const struct nlm_args *args) | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 412 | { | 
 | 413 | 	const struct nlm_lock *lock = &args->lock; | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 414 |  | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 415 | 	encode_cookie(xdr, &args->cookie); | 
 | 416 | 	encode_bool(xdr, args->block); | 
 | 417 | 	encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | 
 | 418 | 	encode_nlm4_lock(xdr, lock); | 
 | 419 | 	encode_bool(xdr, args->reclaim); | 
 | 420 | 	encode_int32(xdr, args->state); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 421 | } | 
 | 422 |  | 
 | 423 | /* | 
 | 424 |  *	struct nlm4_cancargs { | 
 | 425 |  *		netobj cookie; | 
 | 426 |  *		bool block; | 
 | 427 |  *		bool exclusive; | 
 | 428 |  *		struct nlm4_lock alock; | 
 | 429 |  *	}; | 
 | 430 |  */ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 431 | static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req, | 
 | 432 | 				  struct xdr_stream *xdr, | 
 | 433 | 				  const struct nlm_args *args) | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 434 | { | 
 | 435 | 	const struct nlm_lock *lock = &args->lock; | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 436 |  | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 437 | 	encode_cookie(xdr, &args->cookie); | 
 | 438 | 	encode_bool(xdr, args->block); | 
 | 439 | 	encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | 
 | 440 | 	encode_nlm4_lock(xdr, lock); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 441 | } | 
 | 442 |  | 
 | 443 | /* | 
 | 444 |  *	struct nlm4_unlockargs { | 
 | 445 |  *		netobj cookie; | 
 | 446 |  *		struct nlm4_lock alock; | 
 | 447 |  *	}; | 
 | 448 |  */ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 449 | static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req, | 
 | 450 | 				    struct xdr_stream *xdr, | 
 | 451 | 				    const struct nlm_args *args) | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 452 | { | 
 | 453 | 	const struct nlm_lock *lock = &args->lock; | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 454 |  | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 455 | 	encode_cookie(xdr, &args->cookie); | 
 | 456 | 	encode_nlm4_lock(xdr, lock); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 457 | } | 
 | 458 |  | 
 | 459 | /* | 
 | 460 |  *	struct nlm4_res { | 
 | 461 |  *		netobj cookie; | 
 | 462 |  *		nlm4_stat stat; | 
 | 463 |  *	}; | 
 | 464 |  */ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 465 | static void nlm4_xdr_enc_res(struct rpc_rqst *req, | 
 | 466 | 			     struct xdr_stream *xdr, | 
 | 467 | 			     const struct nlm_res *result) | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 468 | { | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 469 | 	encode_cookie(xdr, &result->cookie); | 
 | 470 | 	encode_nlm4_stat(xdr, result->status); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 471 | } | 
 | 472 |  | 
 | 473 | /* | 
 | 474 |  *	union nlm4_testrply switch (nlm4_stats stat) { | 
 | 475 |  *	case NLM4_DENIED: | 
 | 476 |  *		struct nlm4_holder holder; | 
 | 477 |  *	default: | 
 | 478 |  *		void; | 
 | 479 |  *	}; | 
 | 480 |  * | 
 | 481 |  *	struct nlm4_testres { | 
 | 482 |  *		netobj cookie; | 
 | 483 |  *		nlm4_testrply test_stat; | 
 | 484 |  *	}; | 
 | 485 |  */ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 486 | static void nlm4_xdr_enc_testres(struct rpc_rqst *req, | 
 | 487 | 				 struct xdr_stream *xdr, | 
 | 488 | 				 const struct nlm_res *result) | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 489 | { | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 490 | 	encode_cookie(xdr, &result->cookie); | 
 | 491 | 	encode_nlm4_stat(xdr, result->status); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 492 | 	if (result->status == nlm_lck_denied) | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 493 | 		encode_nlm4_holder(xdr, result); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 494 | } | 
 | 495 |  | 
 | 496 |  | 
 | 497 | /* | 
 | 498 |  * NLMv4 XDR decode functions | 
 | 499 |  * | 
 | 500 |  * NLMv4 argument types are defined in Appendix II of RFC 1813: | 
 | 501 |  * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's | 
 | 502 |  * "Protocols for Interworking: XNFS, Version 3W". | 
 | 503 |  */ | 
 | 504 |  | 
 | 505 | /* | 
 | 506 |  *	union nlm4_testrply switch (nlm4_stats stat) { | 
 | 507 |  *	case NLM4_DENIED: | 
 | 508 |  *		struct nlm4_holder holder; | 
 | 509 |  *	default: | 
 | 510 |  *		void; | 
 | 511 |  *	}; | 
 | 512 |  * | 
 | 513 |  *	struct nlm4_testres { | 
 | 514 |  *		netobj cookie; | 
 | 515 |  *		nlm4_testrply test_stat; | 
 | 516 |  *	}; | 
 | 517 |  */ | 
 | 518 | static int decode_nlm4_testrply(struct xdr_stream *xdr, | 
 | 519 | 				struct nlm_res *result) | 
 | 520 | { | 
 | 521 | 	int error; | 
 | 522 |  | 
 | 523 | 	error = decode_nlm4_stat(xdr, &result->status); | 
 | 524 | 	if (unlikely(error)) | 
 | 525 | 		goto out; | 
 | 526 | 	if (result->status == nlm_lck_denied) | 
 | 527 | 		error = decode_nlm4_holder(xdr, result); | 
 | 528 | out: | 
 | 529 | 	return error; | 
 | 530 | } | 
 | 531 |  | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 532 | static int nlm4_xdr_dec_testres(struct rpc_rqst *req, | 
 | 533 | 				struct xdr_stream *xdr, | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 534 | 				struct nlm_res *result) | 
 | 535 | { | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 536 | 	int error; | 
 | 537 |  | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 538 | 	error = decode_cookie(xdr, &result->cookie); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 539 | 	if (unlikely(error)) | 
 | 540 | 		goto out; | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 541 | 	error = decode_nlm4_testrply(xdr, result); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 542 | out: | 
 | 543 | 	return error; | 
 | 544 | } | 
 | 545 |  | 
 | 546 | /* | 
 | 547 |  *	struct nlm4_res { | 
 | 548 |  *		netobj cookie; | 
 | 549 |  *		nlm4_stat stat; | 
 | 550 |  *	}; | 
 | 551 |  */ | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 552 | static int nlm4_xdr_dec_res(struct rpc_rqst *req, | 
 | 553 | 			    struct xdr_stream *xdr, | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 554 | 			    struct nlm_res *result) | 
 | 555 | { | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 556 | 	int error; | 
 | 557 |  | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 558 | 	error = decode_cookie(xdr, &result->cookie); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 559 | 	if (unlikely(error)) | 
 | 560 | 		goto out; | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 561 | 	error = decode_nlm4_stat(xdr, &result->status); | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 562 | out: | 
 | 563 | 	return error; | 
 | 564 | } | 
 | 565 |  | 
 | 566 |  | 
 | 567 | /* | 
 | 568 |  * For NLM, a void procedure really returns nothing | 
 | 569 |  */ | 
 | 570 | #define nlm4_xdr_dec_norep	NULL | 
 | 571 |  | 
 | 572 | #define PROC(proc, argtype, restype)					\ | 
 | 573 | [NLMPROC_##proc] = {							\ | 
 | 574 | 	.p_proc      = NLMPROC_##proc,					\ | 
| Chuck Lever | 9f06c71 | 2010-12-14 14:59:18 +0000 | [diff] [blame] | 575 | 	.p_encode    = (kxdreproc_t)nlm4_xdr_enc_##argtype,		\ | 
| Chuck Lever | bf26955 | 2010-12-14 14:59:29 +0000 | [diff] [blame] | 576 | 	.p_decode    = (kxdrdproc_t)nlm4_xdr_dec_##restype,		\ | 
| Chuck Lever | 3460f29 | 2010-12-14 14:57:12 +0000 | [diff] [blame] | 577 | 	.p_arglen    = NLM4_##argtype##_sz,				\ | 
 | 578 | 	.p_replen    = NLM4_##restype##_sz,				\ | 
 | 579 | 	.p_statidx   = NLMPROC_##proc,					\ | 
 | 580 | 	.p_name      = #proc,						\ | 
 | 581 | 	} | 
 | 582 |  | 
 | 583 | static struct rpc_procinfo	nlm4_procedures[] = { | 
 | 584 | 	PROC(TEST,		testargs,	testres), | 
 | 585 | 	PROC(LOCK,		lockargs,	res), | 
 | 586 | 	PROC(CANCEL,		cancargs,	res), | 
 | 587 | 	PROC(UNLOCK,		unlockargs,	res), | 
 | 588 | 	PROC(GRANTED,		testargs,	res), | 
 | 589 | 	PROC(TEST_MSG,		testargs,	norep), | 
 | 590 | 	PROC(LOCK_MSG,		lockargs,	norep), | 
 | 591 | 	PROC(CANCEL_MSG,	cancargs,	norep), | 
 | 592 | 	PROC(UNLOCK_MSG,	unlockargs,	norep), | 
 | 593 | 	PROC(GRANTED_MSG,	testargs,	norep), | 
 | 594 | 	PROC(TEST_RES,		testres,	norep), | 
 | 595 | 	PROC(LOCK_RES,		res,		norep), | 
 | 596 | 	PROC(CANCEL_RES,	res,		norep), | 
 | 597 | 	PROC(UNLOCK_RES,	res,		norep), | 
 | 598 | 	PROC(GRANTED_RES,	res,		norep), | 
 | 599 | }; | 
 | 600 |  | 
 | 601 | struct rpc_version	nlm_version4 = { | 
 | 602 | 	.number		= 4, | 
 | 603 | 	.nrprocs	= ARRAY_SIZE(nlm4_procedures), | 
 | 604 | 	.procs		= nlm4_procedures, | 
 | 605 | }; |