From: Trond Myklebust Date: Wed, 14 May 2008 11:14:37 -0700 NLM/lockd: Fix NFSv2 locking on 64-bit systems Propagate an EINVAL error back to the user if they attempt to use 64-bit locking on NFSv2: currently we fail the Connectathon locking tests because the locking code propagates EIO instead. Signed-off-by: Trond Myklebust --- fs/lockd/xdr.c | 62 ++++++++++++++++++++++++++++++++----------------------- fs/lockd/xdr4.c | 62 ++++++++++++++++++++++++++++++++----------------------- 2 files changed, 72 insertions(+), 52 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 3e459e1..2673813 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -28,15 +28,16 @@ s32_to_loff_t(__s32 offset) } static inline __s32 -loff_t_to_s32(loff_t offset) +loff_t_to_s32(loff_t offset, int *error) { __s32 res; - if (offset >= NLM_OFFSET_MAX) - res = NLM_OFFSET_MAX; - else if (offset <= -NLM_OFFSET_MAX) - res = -NLM_OFFSET_MAX; - else - res = offset; + + res = offset; + if (error != NULL) { + *error = 0; + if ((loff_t)res != offset || res < 0) + *error = -EINVAL; + } return res; } @@ -157,22 +158,27 @@ static __be32 * nlm_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; - __s32 start, len; + __s32 start, end, len; + int error; if (!(p = xdr_encode_string(p, lock->caller)) || !(p = nlm_encode_fh(p, &lock->fh)) || !(p = nlm_encode_oh(p, &lock->oh))) - return NULL; - - if (fl->fl_start > NLM_OFFSET_MAX - || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) - return NULL; + return ERR_PTR(-EIO); - start = loff_t_to_s32(fl->fl_start); + start = loff_t_to_s32(fl->fl_start, &error); + if (error < 0) + return ERR_PTR(error); if (fl->fl_end == OFFSET_MAX) len = 0; - else - len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); + else { + end = loff_t_to_s32(fl->fl_end, &error); + if (error < 0) + return ERR_PTR(error); + if (end < start) + return ERR_PTR(-EINVAL); + len = end - start + 1; + } *p++ = htonl(lock->svid); *p++ = htonl(start); @@ -203,11 +209,11 @@ nlm_encode_testres(__be32 *p, struct nlm_res *resp) if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) return NULL; - start = loff_t_to_s32(fl->fl_start); + start = loff_t_to_s32(fl->fl_start, NULL); if (fl->fl_end == OFFSET_MAX) len = 0; else - len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); + len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1, NULL); *p++ = htonl(start); *p++ = htonl(len); @@ -396,8 +402,9 @@ nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) if (!(p = nlm_encode_cookie(p, &argp->cookie))) return -EIO; *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; - if (!(p = nlm_encode_lock(p, lock))) - return -EIO; + p = nlm_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } @@ -446,8 +453,9 @@ nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) return -EIO; *p++ = argp->block? xdr_one : xdr_zero; *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; - if (!(p = nlm_encode_lock(p, lock))) - return -EIO; + p = nlm_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); *p++ = argp->reclaim? xdr_one : xdr_zero; *p++ = htonl(argp->state); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -463,8 +471,9 @@ nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) return -EIO; *p++ = argp->block? xdr_one : xdr_zero; *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; - if (!(p = nlm_encode_lock(p, lock))) - return -EIO; + p = nlm_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } @@ -476,8 +485,9 @@ nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) if (!(p = nlm_encode_cookie(p, &argp->cookie))) return -EIO; - if (!(p = nlm_encode_lock(p, lock))) - return -EIO; + p = nlm_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 43ff939..a28c1db 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -29,15 +29,16 @@ s64_to_loff_t(__s64 offset) static inline s64 -loff_t_to_s64(loff_t offset) +loff_t_to_s64(loff_t offset, int *error) { s64 res; - if (offset > NLM4_OFFSET_MAX) - res = NLM4_OFFSET_MAX; - else if (offset < -NLM4_OFFSET_MAX) - res = -NLM4_OFFSET_MAX; - else - res = offset; + + res = offset; + if (error != NULL) { + *error = 0; + if ((loff_t)res != offset) + *error = -EINVAL; + } return res; } @@ -158,24 +159,29 @@ static __be32 * nlm4_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; - __s64 start, len; + __s64 start, end, len; + int error; if (!(p = xdr_encode_string(p, lock->caller)) || !(p = nlm4_encode_fh(p, &lock->fh)) || !(p = nlm4_encode_oh(p, &lock->oh))) - return NULL; - - if (fl->fl_start > NLM4_OFFSET_MAX - || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) - return NULL; + return ERR_PTR(-EIO); *p++ = htonl(lock->svid); - start = loff_t_to_s64(fl->fl_start); + start = loff_t_to_s64(fl->fl_start, &error); + if (error < 0) + return ERR_PTR(error); if (fl->fl_end == OFFSET_MAX) len = 0; - else - len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); + else { + end = loff_t_to_s64(fl->fl_end, &error); + if (error < 0) + return ERR_PTR(error); + if (end < start) + return ERR_PTR(-EINVAL); + len = end - start + 1; + } p = xdr_encode_hyper(p, start); p = xdr_encode_hyper(p, len); @@ -206,11 +212,11 @@ nlm4_encode_testres(__be32 *p, struct nlm_res *resp) if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) return NULL; - start = loff_t_to_s64(fl->fl_start); + start = loff_t_to_s64(fl->fl_start, NULL); if (fl->fl_end == OFFSET_MAX) len = 0; else - len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); + len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1, NULL); p = xdr_encode_hyper(p, start); p = xdr_encode_hyper(p, len); @@ -403,8 +409,9 @@ nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) if (!(p = nlm4_encode_cookie(p, &argp->cookie))) return -EIO; *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; - if (!(p = nlm4_encode_lock(p, lock))) - return -EIO; + p = nlm4_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } @@ -454,8 +461,9 @@ nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) return -EIO; *p++ = argp->block? xdr_one : xdr_zero; *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; - if (!(p = nlm4_encode_lock(p, lock))) - return -EIO; + p = nlm4_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); *p++ = argp->reclaim? xdr_one : xdr_zero; *p++ = htonl(argp->state); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -471,8 +479,9 @@ nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) return -EIO; *p++ = argp->block? xdr_one : xdr_zero; *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; - if (!(p = nlm4_encode_lock(p, lock))) - return -EIO; + p = nlm4_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } @@ -484,8 +493,9 @@ nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) if (!(p = nlm4_encode_cookie(p, &argp->cookie))) return -EIO; - if (!(p = nlm4_encode_lock(p, lock))) - return -EIO; + p = nlm4_encode_lock(p, lock); + if (IS_ERR(p)) + return PTR_ERR(p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; }