4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 * This module provides range lock functionality for CIFS/SMB clients.
28 * Lock range service functions process SMB lock and and unlock
29 * requests for a file by applying lock rules and marks file range
30 * as locked if the lock is successful otherwise return proper
34 #include <smbsrv/smb_kproto.h>
35 #include <smbsrv/smb_fsops.h>
36 #include <sys/nbmlock.h>
37 #include <sys/param.h>
39 extern caller_context_t smb_ct
;
41 static void smb_lock_posix_unlock(smb_node_t
*, smb_lock_t
*, cred_t
*);
42 static boolean_t
smb_is_range_unlocked(uint64_t, uint64_t, uint32_t,
43 smb_llist_t
*, uint64_t *);
44 static int smb_lock_range_overlap(smb_lock_t
*, uint64_t, uint64_t);
45 static uint32_t smb_lock_range_lckrules(smb_request_t
*, smb_ofile_t
*,
46 smb_node_t
*, smb_lock_t
*, smb_lock_t
**);
47 static clock_t smb_lock_wait(smb_request_t
*, smb_lock_t
*, smb_lock_t
*);
48 static uint32_t smb_lock_range_ulckrules(smb_request_t
*, smb_node_t
*,
49 uint64_t, uint64_t, smb_lock_t
**nodelock
);
50 static smb_lock_t
*smb_lock_create(smb_request_t
*, uint64_t, uint64_t,
52 static void smb_lock_destroy(smb_lock_t
*);
53 static void smb_lock_free(smb_lock_t
*);
56 * Return the number of range locks on the specified ofile.
59 smb_lock_get_lock_count(smb_node_t
*node
, smb_ofile_t
*of
)
68 llist
= &node
->n_lock_list
;
70 smb_llist_enter(llist
, RW_READER
);
71 for (lock
= smb_llist_head(llist
);
73 lock
= smb_llist_next(llist
, lock
)) {
74 if (lock
->l_file
== of
)
77 smb_llist_exit(llist
);
85 * locates lock range performed for corresponding to unlock request.
87 * NT_STATUS_SUCCESS - Lock range performed successfully.
88 * !NT_STATUS_SUCCESS - Error in unlock range operation.
97 smb_lock_t
*lock
= NULL
;
100 /* Apply unlocking rules */
101 smb_llist_enter(&node
->n_lock_list
, RW_WRITER
);
102 status
= smb_lock_range_ulckrules(sr
, node
, start
, length
, &lock
);
103 if (status
!= NT_STATUS_SUCCESS
) {
105 * If lock range is not matching in the list
108 ASSERT(lock
== NULL
);
109 smb_llist_exit(&node
->n_lock_list
);
113 smb_llist_remove(&node
->n_lock_list
, lock
);
114 smb_lock_posix_unlock(node
, lock
, sr
->user_cr
);
115 smb_llist_exit(&node
->n_lock_list
);
116 smb_lock_destroy(lock
);
124 * Checks for integrity of file lock operation for the given range of file data.
125 * This is performed by applying lock rules with all the elements of the node
128 * Break shared (levelII) oplocks. If there is an exclusive oplock, it is
129 * owned by this ofile and therefore should not be broken.
131 * The function returns with new lock added if lock request is non-conflicting
132 * with existing range lock for the file. Otherwise smb request is filed
135 * NT_STATUS_SUCCESS - Lock range performed successfully.
136 * !NT_STATUS_SUCCESS - Error in lock range operation.
146 smb_ofile_t
*file
= sr
->fid_ofile
;
147 smb_node_t
*node
= file
->f_node
;
149 smb_lock_t
*clock
= NULL
;
150 uint32_t result
= NT_STATUS_SUCCESS
;
151 boolean_t lock_has_timeout
= (timeout
!= 0);
153 lock
= smb_lock_create(sr
, start
, length
, locktype
, timeout
);
155 smb_llist_enter(&node
->n_lock_list
, RW_WRITER
);
159 /* Apply locking rules */
160 result
= smb_lock_range_lckrules(sr
, file
, node
, lock
, &clock
);
162 if ((result
== NT_STATUS_CANCELLED
) ||
163 (result
== NT_STATUS_SUCCESS
) ||
164 (result
== NT_STATUS_RANGE_NOT_LOCKED
)) {
165 ASSERT(clock
== NULL
);
167 } else if (timeout
== 0) {
171 ASSERT(result
== NT_STATUS_LOCK_NOT_GRANTED
);
174 * Call smb_lock_wait holding write lock for
175 * node lock list. smb_lock_wait will release
176 * this lock if it blocks.
178 ASSERT(node
== clock
->l_file
->f_node
);
180 rc
= smb_lock_wait(sr
, lock
, clock
);
182 result
= NT_STATUS_CANCELLED
;
191 lock
->l_blocked_by
= NULL
;
193 if (result
!= NT_STATUS_SUCCESS
) {
195 * Under certain conditions NT_STATUS_FILE_LOCK_CONFLICT
196 * should be returned instead of NT_STATUS_LOCK_NOT_GRANTED.
198 if (result
== NT_STATUS_LOCK_NOT_GRANTED
) {
200 * Locks with timeouts always return
201 * NT_STATUS_FILE_LOCK_CONFLICT
203 if (lock_has_timeout
)
204 result
= NT_STATUS_FILE_LOCK_CONFLICT
;
207 * Locks starting higher than 0xef000000 that do not
208 * have the MSB set always return
209 * NT_STATUS_FILE_LOCK_CONFLICT
211 if ((lock
->l_start
>= 0xef000000) &&
212 !(lock
->l_start
& (1ULL << 63))) {
213 result
= NT_STATUS_FILE_LOCK_CONFLICT
;
217 * If the last lock attempt to fail on this file handle
218 * started at the same offset as this one then return
219 * NT_STATUS_FILE_LOCK_CONFLICT
221 mutex_enter(&file
->f_mutex
);
222 if ((file
->f_flags
& SMB_OFLAGS_LLF_POS_VALID
) &&
223 (lock
->l_start
== file
->f_llf_pos
)) {
224 result
= NT_STATUS_FILE_LOCK_CONFLICT
;
226 mutex_exit(&file
->f_mutex
);
229 /* Update last lock failed offset */
230 mutex_enter(&file
->f_mutex
);
231 file
->f_llf_pos
= lock
->l_start
;
232 file
->f_flags
|= SMB_OFLAGS_LLF_POS_VALID
;
233 mutex_exit(&file
->f_mutex
);
238 * don't insert into the CIFS lock list unless the
241 if (smb_fsop_frlock(node
, lock
, B_FALSE
, sr
->user_cr
))
242 result
= NT_STATUS_FILE_LOCK_CONFLICT
;
244 smb_llist_insert_tail(&node
->n_lock_list
, lock
);
246 smb_llist_exit(&node
->n_lock_list
);
248 if (result
== NT_STATUS_SUCCESS
)
249 smb_oplock_break_levelII(node
);
256 * smb_lock_range_access
258 * scans node lock list
259 * to check if there is any overlapping lock. Overlapping
260 * lock is allowed only under same session and client pid.
263 * NT_STATUS_SUCCESS lock access granted.
264 * NT_STATUS_FILE_LOCK_CONFLICT access denied due to lock conflict.
267 smb_lock_range_access(
271 uint64_t length
, /* zero means to EoF */
272 boolean_t will_write
)
276 int status
= NT_STATUS_SUCCESS
;
278 llist
= &node
->n_lock_list
;
279 smb_llist_enter(llist
, RW_READER
);
280 /* Search for any applicable lock */
281 for (lock
= smb_llist_head(llist
);
283 lock
= smb_llist_next(llist
, lock
)) {
285 if (!smb_lock_range_overlap(lock
, start
, length
))
286 /* Lock does not overlap */
289 if (lock
->l_type
== SMB_LOCK_TYPE_READONLY
&& !will_write
)
292 if (lock
->l_type
== SMB_LOCK_TYPE_READWRITE
&&
293 lock
->l_session_kid
== sr
->session
->s_kid
&&
294 lock
->l_pid
== sr
->smb_pid
)
297 status
= NT_STATUS_FILE_LOCK_CONFLICT
;
300 smb_llist_exit(llist
);
305 smb_node_destroy_lock_by_ofile(smb_node_t
*node
, smb_ofile_t
*file
)
311 SMB_NODE_VALID(node
);
312 ASSERT(node
->n_refcnt
);
315 * Move locks matching the specified file from the node->n_lock_list
316 * to a temporary list (holding the lock the entire time) then
317 * destroy all the matching locks. We can't call smb_lock_destroy
318 * while we are holding the lock for node->n_lock_list because we will
319 * deadlock and we can't drop the lock because the list contents might
320 * change (for example nxtl might get removed on another thread).
322 list_create(&destroy_list
, sizeof (smb_lock_t
),
323 offsetof(smb_lock_t
, l_lnd
));
325 smb_llist_enter(&node
->n_lock_list
, RW_WRITER
);
326 lock
= smb_llist_head(&node
->n_lock_list
);
328 nxtl
= smb_llist_next(&node
->n_lock_list
, lock
);
329 if (lock
->l_file
== file
) {
330 smb_llist_remove(&node
->n_lock_list
, lock
);
331 smb_lock_posix_unlock(node
, lock
, file
->f_user
->u_cred
);
332 list_insert_tail(&destroy_list
, lock
);
336 smb_llist_exit(&node
->n_lock_list
);
338 lock
= list_head(&destroy_list
);
340 nxtl
= list_next(&destroy_list
, lock
);
341 list_remove(&destroy_list
, lock
);
342 smb_lock_destroy(lock
);
346 list_destroy(&destroy_list
);
350 smb_lock_range_error(smb_request_t
*sr
, uint32_t status32
)
354 if (status32
== NT_STATUS_CANCELLED
)
355 errcode
= ERROR_OPERATION_ABORTED
;
359 smbsr_error(sr
, status32
, ERRDOS
, errcode
);
363 * An SMB variant of nbl_conflict().
365 * SMB prevents remove or rename when conflicting locks exist
366 * (unlike NFS, which is why we can't just use nbl_conflict).
369 * NT_STATUS_SHARING_VIOLATION - nbl_share_conflict
370 * NT_STATUS_FILE_LOCK_CONFLICT - nbl_lock_conflict
371 * NT_STATUS_SUCCESS - operation can proceed
373 * NB: This function used to also check the list of ofiles,
374 * via: smb_lock_range_access() but we _can't_ do that here
375 * due to lock order constraints between node->n_lock_list
376 * and node->vp->vnbllock (taken via nvl_start_crit).
377 * They must be taken in that order, and in here, we
378 * already hold vp->vnbllock.
381 smb_nbl_conflict(smb_node_t
*node
, uint64_t off
, uint64_t len
, nbl_op_t op
)
385 SMB_NODE_VALID(node
);
386 ASSERT(smb_node_in_crit(node
));
387 ASSERT(op
== NBL_READ
|| op
== NBL_WRITE
|| op
== NBL_READWRITE
||
388 op
== NBL_REMOVE
|| op
== NBL_RENAME
);
390 if (smb_node_is_dir(node
))
391 return (NT_STATUS_SUCCESS
);
393 if (nbl_share_conflict(node
->vp
, op
, &smb_ct
))
394 return (NT_STATUS_SHARING_VIOLATION
);
397 * When checking for lock conflicts, rename and remove
398 * are not allowed, so treat those as read/write.
400 if (op
== NBL_RENAME
|| op
== NBL_REMOVE
)
403 if (nbl_svmand(node
->vp
, zone_kcred(), &svmand
))
406 if (nbl_lock_conflict(node
->vp
, op
, off
, len
, svmand
, &smb_ct
))
407 return (NT_STATUS_FILE_LOCK_CONFLICT
);
409 return (NT_STATUS_SUCCESS
);
413 * smb_lock_posix_unlock
415 * checks if the current unlock request is in another lock and repeatedly calls
416 * smb_is_range_unlocked on a sliding basis to unlock all bits of the lock
417 * that are not in other locks
421 smb_lock_posix_unlock(smb_node_t
*node
, smb_lock_t
*lock
, cred_t
*cr
)
424 uint64_t unlock_start
;
426 smb_lock_t new_unlock
;
428 boolean_t can_unlock
;
431 unlock_start
= lock
->l_start
;
432 unlock_end
= unlock_start
+ lock
->l_length
;
433 llist
= &node
->n_lock_list
;
436 can_unlock
= smb_is_range_unlocked(unlock_start
, unlock_end
,
437 lock
->l_file
->f_uniqid
, llist
, &new_mark
);
441 new_unlock
.l_start
= unlock_start
;
442 new_unlock
.l_length
= new_mark
- unlock_start
;
443 (void) smb_fsop_frlock(node
, &new_unlock
,
445 unlock_start
= new_mark
;
448 new_unlock
.l_start
= unlock_start
;
449 new_unlock
.l_length
= unlock_end
- unlock_start
;
450 (void) smb_fsop_frlock(node
, &new_unlock
,
454 } else if (new_mark
) {
455 unlock_start
= new_mark
;
463 * smb_lock_range_overlap
465 * Checks if lock range(start, length) overlaps range in lock structure.
467 * Zero-length byte range locks actually affect no single byte of the stream,
468 * meaning they can still be accessed even with such locks in place. However,
469 * they do conflict with other ranges in the following manner:
470 * conflict will only exist if the positive-length range contains the
471 * zero-length range's offset but doesn't start at it
474 * 0 - Lock range doesn't overlap
475 * 1 - Lock range overlaps.
478 #define RANGE_NO_OVERLAP 0
479 #define RANGE_OVERLAP 1
482 smb_lock_range_overlap(struct smb_lock
*lock
, uint64_t start
, uint64_t length
)
485 if ((lock
->l_start
< start
) &&
486 ((lock
->l_start
+ lock
->l_length
) > start
))
487 return (RANGE_OVERLAP
);
489 return (RANGE_NO_OVERLAP
);
492 /* The following test is intended to catch roll over locks. */
493 if ((start
== lock
->l_start
) && (length
== lock
->l_length
))
494 return (RANGE_OVERLAP
);
496 if (start
< lock
->l_start
) {
497 if (start
+ length
> lock
->l_start
)
498 return (RANGE_OVERLAP
);
499 } else if (start
< lock
->l_start
+ lock
->l_length
)
500 return (RANGE_OVERLAP
);
502 return (RANGE_NO_OVERLAP
);
506 * smb_lock_range_lckrules
509 * 1. Overlapping read locks are allowed if the
510 * current locks in the region are only read locks
511 * irrespective of pid of smb client issuing lock request.
513 * 2. Read lock in the overlapped region of write lock
514 * are allowed if the pervious lock is performed by the
515 * same pid and connection.
518 * NT_STATUS_SUCCESS - Input lock range adapts to lock rules.
519 * NT_STATUS_LOCK_NOT_GRANTED - Input lock conflicts lock rules.
520 * NT_STATUS_CANCELLED - Error in processing lock rules
523 smb_lock_range_lckrules(
531 uint32_t status
= NT_STATUS_SUCCESS
;
533 /* Check if file is closed */
534 if (!smb_ofile_is_open(file
)) {
535 return (NT_STATUS_RANGE_NOT_LOCKED
);
538 /* Caller must hold lock for node->n_lock_list */
539 for (lock
= smb_llist_head(&node
->n_lock_list
);
541 lock
= smb_llist_next(&node
->n_lock_list
, lock
)) {
543 if (!smb_lock_range_overlap(lock
, dlock
->l_start
,
548 * Check to see if lock in the overlapping record
549 * is only read lock. Current finding is read
550 * locks can overlapped irrespective of pids.
552 if ((lock
->l_type
== SMB_LOCK_TYPE_READONLY
) &&
553 (dlock
->l_type
== SMB_LOCK_TYPE_READONLY
)) {
558 * When the read lock overlaps write lock, check if
561 if ((dlock
->l_type
== SMB_LOCK_TYPE_READONLY
) &&
562 !(lock
->l_type
== SMB_LOCK_TYPE_READONLY
)) {
563 if (lock
->l_file
== sr
->fid_ofile
&&
564 lock
->l_session_kid
== sr
->session
->s_kid
&&
565 lock
->l_pid
== sr
->smb_pid
&&
566 lock
->l_uid
== sr
->smb_uid
) {
571 /* Conflict in overlapping lock element */
573 status
= NT_STATUS_LOCK_NOT_GRANTED
;
583 * Wait operation for smb overlapping lock to be released. Caller must hold
584 * write lock for node->n_lock_list so that the set of active locks can't
585 * change unexpectedly. The lock for node->n_lock_list will be released
586 * within this function during the sleep after the lock dependency has
591 * 0 The request was canceled.
592 * -1 The timeout was reached.
596 smb_lock_wait(smb_request_t
*sr
, smb_lock_t
*b_lock
, smb_lock_t
*c_lock
)
600 ASSERT(sr
->sr_awaiting
== NULL
);
602 mutex_enter(&sr
->sr_mutex
);
604 switch (sr
->sr_state
) {
605 case SMB_REQ_STATE_ACTIVE
:
607 * Wait up till the timeout time keeping track of actual
608 * time waited for possible retry failure.
610 sr
->sr_state
= SMB_REQ_STATE_WAITING_LOCK
;
611 sr
->sr_awaiting
= c_lock
;
612 mutex_exit(&sr
->sr_mutex
);
614 mutex_enter(&c_lock
->l_mutex
);
616 * The conflict list (l_conflict_list) for a lock contains
617 * all the locks that are blocked by and in conflict with
618 * that lock. Add the new lock to the conflict list for the
621 * l_conflict_list is currently a fancy way of representing
622 * the references/dependencies on a lock. It could be
623 * replaced with a reference count but this approach
624 * has the advantage that MDB can display the lock
625 * dependencies at any point in time. In the future
626 * we should be able to leverage the list to implement
627 * an asynchronous locking model.
629 * l_blocked_by is the reverse of the conflict list. It
630 * points to the lock that the new lock conflicts with.
631 * As currently implemented this value is purely for
632 * debug purposes -- there are windows of time when
633 * l_blocked_by may be non-NULL even though there is no
636 b_lock
->l_blocked_by
= c_lock
;
637 smb_slist_insert_tail(&c_lock
->l_conflict_list
, b_lock
);
638 smb_llist_exit(&c_lock
->l_file
->f_node
->n_lock_list
);
640 if (SMB_LOCK_INDEFINITE_WAIT(b_lock
)) {
641 cv_wait(&c_lock
->l_cv
, &c_lock
->l_mutex
);
643 rc
= cv_timedwait(&c_lock
->l_cv
,
644 &c_lock
->l_mutex
, b_lock
->l_end_time
);
647 mutex_exit(&c_lock
->l_mutex
);
649 smb_llist_enter(&c_lock
->l_file
->f_node
->n_lock_list
,
651 smb_slist_remove(&c_lock
->l_conflict_list
, b_lock
);
653 mutex_enter(&sr
->sr_mutex
);
654 sr
->sr_awaiting
= NULL
;
655 if (sr
->sr_state
== SMB_REQ_STATE_CANCELED
) {
658 sr
->sr_state
= SMB_REQ_STATE_ACTIVE
;
663 ASSERT(sr
->sr_state
== SMB_REQ_STATE_CANCELED
);
667 mutex_exit(&sr
->sr_mutex
);
673 * smb_lock_range_ulckrules
675 * 1. Unlock should be performed at exactly matching ends.
676 * This has been changed because overlapping ends is
677 * allowed and there is no other precise way of locating
678 * lock entity in node lock list.
680 * 2. Unlock is failed if there is no corresponding lock exists.
684 * NT_STATUS_SUCCESS Unlock request matches lock record
685 * pointed by 'nodelock' lock structure.
687 * NT_STATUS_RANGE_NOT_LOCKED Unlock request doen't match any
688 * of lock record in node lock request or
689 * error in unlock range processing.
692 smb_lock_range_ulckrules(
697 smb_lock_t
**nodelock
)
700 uint32_t status
= NT_STATUS_RANGE_NOT_LOCKED
;
702 /* Caller must hold lock for node->n_lock_list */
703 for (lock
= smb_llist_head(&node
->n_lock_list
);
705 lock
= smb_llist_next(&node
->n_lock_list
, lock
)) {
707 if ((start
== lock
->l_start
) &&
708 (length
== lock
->l_length
) &&
709 lock
->l_file
== sr
->fid_ofile
&&
710 lock
->l_session_kid
== sr
->session
->s_kid
&&
711 lock
->l_pid
== sr
->smb_pid
&&
712 lock
->l_uid
== sr
->smb_uid
) {
714 status
= NT_STATUS_SUCCESS
;
732 ASSERT(locktype
== SMB_LOCK_TYPE_READWRITE
||
733 locktype
== SMB_LOCK_TYPE_READONLY
);
735 lock
= kmem_zalloc(sizeof (smb_lock_t
), KM_SLEEP
);
736 lock
->l_magic
= SMB_LOCK_MAGIC
;
737 lock
->l_sr
= sr
; /* Invalid after lock is active */
738 lock
->l_session_kid
= sr
->session
->s_kid
;
739 lock
->l_session
= sr
->session
;
740 lock
->l_file
= sr
->fid_ofile
;
741 lock
->l_uid
= sr
->smb_uid
;
742 lock
->l_pid
= sr
->smb_pid
;
743 lock
->l_type
= locktype
;
744 lock
->l_start
= start
;
745 lock
->l_length
= length
;
747 * Calculate the absolute end time so that we can use it
750 lock
->l_end_time
= ddi_get_lbolt() + MSEC_TO_TICK(timeout
);
751 if (timeout
== UINT_MAX
)
752 lock
->l_flags
|= SMB_LOCK_FLAG_INDEFINITE
;
754 mutex_init(&lock
->l_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
755 cv_init(&lock
->l_cv
, NULL
, CV_DEFAULT
, NULL
);
756 smb_slist_constructor(&lock
->l_conflict_list
, sizeof (smb_lock_t
),
757 offsetof(smb_lock_t
, l_conflict_lnd
));
763 smb_lock_free(smb_lock_t
*lock
)
765 smb_slist_destructor(&lock
->l_conflict_list
);
766 cv_destroy(&lock
->l_cv
);
767 mutex_destroy(&lock
->l_mutex
);
769 kmem_free(lock
, sizeof (smb_lock_t
));
775 * Caller must hold node->n_lock_list
778 smb_lock_destroy(smb_lock_t
*lock
)
781 * Caller must hold node->n_lock_list lock.
783 mutex_enter(&lock
->l_mutex
);
784 cv_broadcast(&lock
->l_cv
);
785 mutex_exit(&lock
->l_mutex
);
788 * The cv_broadcast above should wake up any locks that previous
789 * had conflicts with this lock. Wait for the locking threads
790 * to remove their references to this lock.
792 smb_slist_wait_for_empty(&lock
->l_conflict_list
);
798 * smb_is_range_unlocked
800 * Checks if the current unlock byte range request overlaps another lock
801 * This function is used to determine where POSIX unlocks should be
804 * The return code and the value of new_mark must be interpreted as
807 * B_TRUE and (new_mark == 0):
808 * This is the last or only lock left to be unlocked
810 * B_TRUE and (new_mark > 0):
811 * The range from start to new_mark can be unlocked
813 * B_FALSE and (new_mark == 0):
814 * The unlock can't be performed and we are done
816 * B_FALSE and (new_mark > 0),
817 * The range from start to new_mark can't be unlocked
818 * Start should be reset to new_mark for the next pass
822 smb_is_range_unlocked(uint64_t start
, uint64_t end
, uint32_t uniqid
,
823 smb_llist_t
*llist_head
, uint64_t *new_mark
)
825 struct smb_lock
*lk
= NULL
;
826 uint64_t low_water_mark
= MAXOFFSET_T
;
831 lk
= smb_llist_head(llist_head
);
833 if (lk
->l_length
== 0) {
834 lk
= smb_llist_next(llist_head
, lk
);
838 if (lk
->l_file
->f_uniqid
!= uniqid
) {
839 lk
= smb_llist_next(llist_head
, lk
);
843 lk_end
= lk
->l_start
+ lk
->l_length
- 1;
844 lk_start
= lk
->l_start
;
847 * there is no overlap for the first 2 cases
850 if (lk_end
< start
) {
851 lk
= smb_llist_next(llist_head
, lk
);
854 if (lk_start
> end
) {
855 lk
= smb_llist_next(llist_head
, lk
);
859 /* this range is completely locked */
860 if ((lk_start
<= start
) && (lk_end
>= end
)) {
864 /* the first part of this range is locked */
865 if ((start
>= lk_start
) && (start
<= lk_end
)) {
867 *new_mark
= lk_end
+ 1;
871 /* this piece is unlocked */
872 if ((lk_start
>= start
) && (lk_start
<= end
)) {
873 if (low_water_mark
> lk_start
)
874 low_water_mark
= lk_start
;
877 lk
= smb_llist_next(llist_head
, lk
);
880 if (low_water_mark
!= MAXOFFSET_T
) {
881 *new_mark
= low_water_mark
;
884 /* the range is completely unlocked */