Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

lockd: Move nlm4svc_set_file_lock_range()

Both client-side and server-side NLMv4 code convert lock byte ranges
from the wire format (start, length) to the kernel's file_lock format
(start, end). The current nlm4svc_set_file_lock_range() performs this
conversion, but the "svc" prefix incorrectly suggests server-only use,
and client code must include server-internal headers to access it.

Rename to lockd_set_file_lock_range4() and relocate to the shared
lockd.h header, making it accessible to both client and server code.
This eliminates the need for client code to include xdr4.h, reducing
coupling between the XDR implementation files.

While relocating the function, add input validation: clamp the
starting offset to OFFSET_MAX before use. Without this, a malformed
lock request with off > OFFSET_MAX results in fl_start > fl_end,
violating file_lock invariants and potentially causing incorrect
lock conflict detection.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

+27 -14
+1 -1
fs/lockd/clnt4xdr.c
··· 287 287 fl->c.flc_type = exclusive != 0 ? F_WRLCK : F_RDLCK; 288 288 p = xdr_decode_hyper(p, &l_offset); 289 289 xdr_decode_hyper(p, &l_len); 290 - nlm4svc_set_file_lock_range(fl, l_offset, l_len); 290 + lockd_set_file_lock_range4(fl, l_offset, l_len); 291 291 error = 0; 292 292 out: 293 293 return error;
+25
fs/lockd/lockd.h
··· 413 413 &&(fl1->c.flc_type == fl2->c.flc_type || fl2->c.flc_type == F_UNLCK); 414 414 } 415 415 416 + /** 417 + * lockd_set_file_lock_range4 - set the byte range of a file_lock 418 + * @fl: file_lock whose length fields are to be initialized 419 + * @off: starting offset of the lock, in bytes 420 + * @len: length of the byte range, in bytes, or zero 421 + * 422 + * The NLMv4 protocol represents lock byte ranges as (start, length), 423 + * where length zero means "lock to end of file." The kernel's file_lock 424 + * structure uses (start, end) representation. Convert from NLMv4 format 425 + * to file_lock format, clamping the starting offset and treating 426 + * arithmetic overflow as "lock to EOF." 427 + */ 428 + static inline void 429 + lockd_set_file_lock_range4(struct file_lock *fl, u64 off, u64 len) 430 + { 431 + u64 clamped_off = (off > OFFSET_MAX) ? OFFSET_MAX : off; 432 + s64 end = clamped_off + len - 1; 433 + 434 + fl->fl_start = clamped_off; 435 + if (len == 0 || end < 0) 436 + fl->fl_end = OFFSET_MAX; 437 + else 438 + fl->fl_end = end; 439 + } 440 + 416 441 extern const struct lock_manager_operations nlmsvc_lock_operations; 417 442 418 443 #endif /* _LOCKD_LOCKD_H */
+1 -12
fs/lockd/xdr4.c
··· 34 34 return res; 35 35 } 36 36 37 - void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len) 38 - { 39 - s64 end = off + len - 1; 40 - 41 - fl->fl_start = off; 42 - if (len == 0 || end < 0) 43 - fl->fl_end = OFFSET_MAX; 44 - else 45 - fl->fl_end = end; 46 - } 47 - 48 37 /* 49 38 * NLM file handles are defined by specification to be a variable-length 50 39 * XDR opaque no longer than 1024 bytes. However, this implementation ··· 80 91 81 92 locks_init_lock(fl); 82 93 fl->c.flc_type = F_RDLCK; 83 - nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len); 94 + lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len); 84 95 return true; 85 96 } 86 97
-1
fs/lockd/xdr4.h
··· 15 15 #define nlm4_fbig cpu_to_be32(NLM_FBIG) 16 16 #define nlm4_failed cpu_to_be32(NLM_FAILED) 17 17 18 - void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len); 19 18 bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 20 19 bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 21 20 bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);