clnt4xdr.c 13 KB

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