clnt4xdr.c 13 KB

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