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