0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/types.h>
0013 #include <linux/sunrpc/xdr.h>
0014 #include <linux/sunrpc/clnt.h>
0015 #include <linux/sunrpc/stats.h>
0016 #include <linux/lockd/lockd.h>
0017
0018 #include <uapi/linux/nfs3.h>
0019
0020 #define NLMDBG_FACILITY NLMDBG_XDR
0021
0022 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
0023 # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
0024 #endif
0025
0026 #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
0027 # error "NLM host name cannot be larger than NLM's maximum string length!"
0028 #endif
0029
0030
0031
0032
0033
0034 #define NLM4_void_sz (0)
0035 #define NLM4_cookie_sz (1+(NLM_MAXCOOKIELEN>>2))
0036 #define NLM4_caller_sz (1+(NLMCLNT_OHSIZE>>2))
0037 #define NLM4_owner_sz (1+(NLMCLNT_OHSIZE>>2))
0038 #define NLM4_fhandle_sz (1+(NFS3_FHSIZE>>2))
0039 #define NLM4_lock_sz (5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz)
0040 #define NLM4_holder_sz (6+NLM4_owner_sz)
0041
0042 #define NLM4_testargs_sz (NLM4_cookie_sz+1+NLM4_lock_sz)
0043 #define NLM4_lockargs_sz (NLM4_cookie_sz+4+NLM4_lock_sz)
0044 #define NLM4_cancargs_sz (NLM4_cookie_sz+2+NLM4_lock_sz)
0045 #define NLM4_unlockargs_sz (NLM4_cookie_sz+NLM4_lock_sz)
0046
0047 #define NLM4_testres_sz (NLM4_cookie_sz+1+NLM4_holder_sz)
0048 #define NLM4_res_sz (NLM4_cookie_sz+1)
0049 #define NLM4_norep_sz (0)
0050
0051
0052 static s64 loff_t_to_s64(loff_t offset)
0053 {
0054 s64 res;
0055
0056 if (offset >= NLM4_OFFSET_MAX)
0057 res = NLM4_OFFSET_MAX;
0058 else if (offset <= -NLM4_OFFSET_MAX)
0059 res = -NLM4_OFFSET_MAX;
0060 else
0061 res = offset;
0062 return res;
0063 }
0064
0065 static void nlm4_compute_offsets(const struct nlm_lock *lock,
0066 u64 *l_offset, u64 *l_len)
0067 {
0068 const struct file_lock *fl = &lock->fl;
0069
0070 *l_offset = loff_t_to_s64(fl->fl_start);
0071 if (fl->fl_end == OFFSET_MAX)
0072 *l_len = 0;
0073 else
0074 *l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
0075 }
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 static void encode_bool(struct xdr_stream *xdr, const int value)
0090 {
0091 __be32 *p;
0092
0093 p = xdr_reserve_space(xdr, 4);
0094 *p = value ? xdr_one : xdr_zero;
0095 }
0096
0097 static void encode_int32(struct xdr_stream *xdr, const s32 value)
0098 {
0099 __be32 *p;
0100
0101 p = xdr_reserve_space(xdr, 4);
0102 *p = cpu_to_be32(value);
0103 }
0104
0105
0106
0107
0108 static void encode_netobj(struct xdr_stream *xdr,
0109 const u8 *data, const unsigned int length)
0110 {
0111 __be32 *p;
0112
0113 p = xdr_reserve_space(xdr, 4 + length);
0114 xdr_encode_opaque(p, data, length);
0115 }
0116
0117 static int decode_netobj(struct xdr_stream *xdr,
0118 struct xdr_netobj *obj)
0119 {
0120 ssize_t ret;
0121
0122 ret = xdr_stream_decode_opaque_inline(xdr, (void *)&obj->data,
0123 XDR_MAX_NETOBJ);
0124 if (unlikely(ret < 0))
0125 return -EIO;
0126 obj->len = ret;
0127 return 0;
0128 }
0129
0130
0131
0132
0133 static void encode_cookie(struct xdr_stream *xdr,
0134 const struct nlm_cookie *cookie)
0135 {
0136 encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
0137 }
0138
0139 static int decode_cookie(struct xdr_stream *xdr,
0140 struct nlm_cookie *cookie)
0141 {
0142 u32 length;
0143 __be32 *p;
0144
0145 p = xdr_inline_decode(xdr, 4);
0146 if (unlikely(p == NULL))
0147 goto out_overflow;
0148 length = be32_to_cpup(p++);
0149
0150 if (length == 0)
0151 goto out_hpux;
0152 if (length > NLM_MAXCOOKIELEN)
0153 goto out_size;
0154 p = xdr_inline_decode(xdr, length);
0155 if (unlikely(p == NULL))
0156 goto out_overflow;
0157 cookie->len = length;
0158 memcpy(cookie->data, p, length);
0159 return 0;
0160 out_hpux:
0161 cookie->len = 4;
0162 memset(cookie->data, 0, 4);
0163 return 0;
0164 out_size:
0165 dprintk("NFS: returned cookie was too long: %u\n", length);
0166 return -EIO;
0167 out_overflow:
0168 return -EIO;
0169 }
0170
0171
0172
0173
0174 static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
0175 {
0176 encode_netobj(xdr, (u8 *)&fh->data, fh->size);
0177 }
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 static void encode_nlm4_stat(struct xdr_stream *xdr,
0202 const __be32 stat)
0203 {
0204 __be32 *p;
0205
0206 BUG_ON(be32_to_cpu(stat) > NLM_FAILED);
0207 p = xdr_reserve_space(xdr, 4);
0208 *p = stat;
0209 }
0210
0211 static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat)
0212 {
0213 __be32 *p;
0214
0215 p = xdr_inline_decode(xdr, 4);
0216 if (unlikely(p == NULL))
0217 goto out_overflow;
0218 if (unlikely(ntohl(*p) > ntohl(nlm4_failed)))
0219 goto out_bad_xdr;
0220 *stat = *p;
0221 return 0;
0222 out_bad_xdr:
0223 dprintk("%s: server returned invalid nlm4_stats value: %u\n",
0224 __func__, be32_to_cpup(p));
0225 return -EIO;
0226 out_overflow:
0227 return -EIO;
0228 }
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239 static void encode_nlm4_holder(struct xdr_stream *xdr,
0240 const struct nlm_res *result)
0241 {
0242 const struct nlm_lock *lock = &result->lock;
0243 u64 l_offset, l_len;
0244 __be32 *p;
0245
0246 encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
0247 encode_int32(xdr, lock->svid);
0248 encode_netobj(xdr, lock->oh.data, lock->oh.len);
0249
0250 p = xdr_reserve_space(xdr, 4 + 4);
0251 nlm4_compute_offsets(lock, &l_offset, &l_len);
0252 p = xdr_encode_hyper(p, l_offset);
0253 xdr_encode_hyper(p, l_len);
0254 }
0255
0256 static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
0257 {
0258 struct nlm_lock *lock = &result->lock;
0259 struct file_lock *fl = &lock->fl;
0260 u64 l_offset, l_len;
0261 u32 exclusive;
0262 int error;
0263 __be32 *p;
0264 s32 end;
0265
0266 memset(lock, 0, sizeof(*lock));
0267 locks_init_lock(fl);
0268
0269 p = xdr_inline_decode(xdr, 4 + 4);
0270 if (unlikely(p == NULL))
0271 goto out_overflow;
0272 exclusive = be32_to_cpup(p++);
0273 lock->svid = be32_to_cpup(p);
0274 fl->fl_pid = (pid_t)lock->svid;
0275
0276 error = decode_netobj(xdr, &lock->oh);
0277 if (unlikely(error))
0278 goto out;
0279
0280 p = xdr_inline_decode(xdr, 8 + 8);
0281 if (unlikely(p == NULL))
0282 goto out_overflow;
0283
0284 fl->fl_flags = FL_POSIX;
0285 fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK;
0286 p = xdr_decode_hyper(p, &l_offset);
0287 xdr_decode_hyper(p, &l_len);
0288 end = l_offset + l_len - 1;
0289
0290 fl->fl_start = (loff_t)l_offset;
0291 if (l_len == 0 || end < 0)
0292 fl->fl_end = OFFSET_MAX;
0293 else
0294 fl->fl_end = (loff_t)end;
0295 error = 0;
0296 out:
0297 return error;
0298 out_overflow:
0299 return -EIO;
0300 }
0301
0302
0303
0304
0305 static void encode_caller_name(struct xdr_stream *xdr, const char *name)
0306 {
0307
0308 u32 length = strlen(name);
0309 __be32 *p;
0310
0311 p = xdr_reserve_space(xdr, 4 + length);
0312 xdr_encode_opaque(p, name, length);
0313 }
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325 static void encode_nlm4_lock(struct xdr_stream *xdr,
0326 const struct nlm_lock *lock)
0327 {
0328 u64 l_offset, l_len;
0329 __be32 *p;
0330
0331 encode_caller_name(xdr, lock->caller);
0332 encode_fh(xdr, &lock->fh);
0333 encode_netobj(xdr, lock->oh.data, lock->oh.len);
0334
0335 p = xdr_reserve_space(xdr, 4 + 8 + 8);
0336 *p++ = cpu_to_be32(lock->svid);
0337
0338 nlm4_compute_offsets(lock, &l_offset, &l_len);
0339 p = xdr_encode_hyper(p, l_offset);
0340 xdr_encode_hyper(p, l_len);
0341 }
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359 static void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
0360 struct xdr_stream *xdr,
0361 const void *data)
0362 {
0363 const struct nlm_args *args = data;
0364 const struct nlm_lock *lock = &args->lock;
0365
0366 encode_cookie(xdr, &args->cookie);
0367 encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
0368 encode_nlm4_lock(xdr, lock);
0369 }
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
0382 struct xdr_stream *xdr,
0383 const void *data)
0384 {
0385 const struct nlm_args *args = data;
0386 const struct nlm_lock *lock = &args->lock;
0387
0388 encode_cookie(xdr, &args->cookie);
0389 encode_bool(xdr, args->block);
0390 encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
0391 encode_nlm4_lock(xdr, lock);
0392 encode_bool(xdr, args->reclaim);
0393 encode_int32(xdr, args->state);
0394 }
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
0405 struct xdr_stream *xdr,
0406 const void *data)
0407 {
0408 const struct nlm_args *args = data;
0409 const struct nlm_lock *lock = &args->lock;
0410
0411 encode_cookie(xdr, &args->cookie);
0412 encode_bool(xdr, args->block);
0413 encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
0414 encode_nlm4_lock(xdr, lock);
0415 }
0416
0417
0418
0419
0420
0421
0422
0423 static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req,
0424 struct xdr_stream *xdr,
0425 const void *data)
0426 {
0427 const struct nlm_args *args = data;
0428 const struct nlm_lock *lock = &args->lock;
0429
0430 encode_cookie(xdr, &args->cookie);
0431 encode_nlm4_lock(xdr, lock);
0432 }
0433
0434
0435
0436
0437
0438
0439
0440 static void nlm4_xdr_enc_res(struct rpc_rqst *req,
0441 struct xdr_stream *xdr,
0442 const void *data)
0443 {
0444 const struct nlm_res *result = data;
0445
0446 encode_cookie(xdr, &result->cookie);
0447 encode_nlm4_stat(xdr, result->status);
0448 }
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463 static void nlm4_xdr_enc_testres(struct rpc_rqst *req,
0464 struct xdr_stream *xdr,
0465 const void *data)
0466 {
0467 const struct nlm_res *result = data;
0468
0469 encode_cookie(xdr, &result->cookie);
0470 encode_nlm4_stat(xdr, result->status);
0471 if (result->status == nlm_lck_denied)
0472 encode_nlm4_holder(xdr, result);
0473 }
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 static int decode_nlm4_testrply(struct xdr_stream *xdr,
0498 struct nlm_res *result)
0499 {
0500 int error;
0501
0502 error = decode_nlm4_stat(xdr, &result->status);
0503 if (unlikely(error))
0504 goto out;
0505 if (result->status == nlm_lck_denied)
0506 error = decode_nlm4_holder(xdr, result);
0507 out:
0508 return error;
0509 }
0510
0511 static int nlm4_xdr_dec_testres(struct rpc_rqst *req,
0512 struct xdr_stream *xdr,
0513 void *data)
0514 {
0515 struct nlm_res *result = data;
0516 int error;
0517
0518 error = decode_cookie(xdr, &result->cookie);
0519 if (unlikely(error))
0520 goto out;
0521 error = decode_nlm4_testrply(xdr, result);
0522 out:
0523 return error;
0524 }
0525
0526
0527
0528
0529
0530
0531
0532 static int nlm4_xdr_dec_res(struct rpc_rqst *req,
0533 struct xdr_stream *xdr,
0534 void *data)
0535 {
0536 struct nlm_res *result = data;
0537 int error;
0538
0539 error = decode_cookie(xdr, &result->cookie);
0540 if (unlikely(error))
0541 goto out;
0542 error = decode_nlm4_stat(xdr, &result->status);
0543 out:
0544 return error;
0545 }
0546
0547
0548
0549
0550
0551 #define nlm4_xdr_dec_norep NULL
0552
0553 #define PROC(proc, argtype, restype) \
0554 [NLMPROC_##proc] = { \
0555 .p_proc = NLMPROC_##proc, \
0556 .p_encode = nlm4_xdr_enc_##argtype, \
0557 .p_decode = nlm4_xdr_dec_##restype, \
0558 .p_arglen = NLM4_##argtype##_sz, \
0559 .p_replen = NLM4_##restype##_sz, \
0560 .p_statidx = NLMPROC_##proc, \
0561 .p_name = #proc, \
0562 }
0563
0564 static const struct rpc_procinfo nlm4_procedures[] = {
0565 PROC(TEST, testargs, testres),
0566 PROC(LOCK, lockargs, res),
0567 PROC(CANCEL, cancargs, res),
0568 PROC(UNLOCK, unlockargs, res),
0569 PROC(GRANTED, testargs, res),
0570 PROC(TEST_MSG, testargs, norep),
0571 PROC(LOCK_MSG, lockargs, norep),
0572 PROC(CANCEL_MSG, cancargs, norep),
0573 PROC(UNLOCK_MSG, unlockargs, norep),
0574 PROC(GRANTED_MSG, testargs, norep),
0575 PROC(TEST_RES, testres, norep),
0576 PROC(LOCK_RES, res, norep),
0577 PROC(CANCEL_RES, res, norep),
0578 PROC(UNLOCK_RES, res, norep),
0579 PROC(GRANTED_RES, res, norep),
0580 };
0581
0582 static unsigned int nlm_version4_counts[ARRAY_SIZE(nlm4_procedures)];
0583 const struct rpc_version nlm_version4 = {
0584 .number = 4,
0585 .nrprocs = ARRAY_SIZE(nlm4_procedures),
0586 .procs = nlm4_procedures,
0587 .counts = nlm_version4_counts,
0588 };