svn commit: samba r13804 - in trunk/source/locking: .
jra at samba.org
jra at samba.org
Fri Mar 3 03:00:52 GMT 2006
Author: jra
Date: 2006-03-03 03:00:52 +0000 (Fri, 03 Mar 2006)
New Revision: 13804
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=13804
Log:
Add in support for lock splits/merges on POSIX
flavour setlock. Now to add support for unlock.
Jeremy.
Modified:
trunk/source/locking/brlock.c
trunk/source/locking/locking.c
Changeset:
Modified: trunk/source/locking/brlock.c
===================================================================
--- trunk/source/locking/brlock.c 2006-03-03 02:29:48 UTC (rev 13803)
+++ trunk/source/locking/brlock.c 2006-03-03 03:00:52 UTC (rev 13804)
@@ -124,9 +124,11 @@
static BOOL brl_conflict(struct lock_struct *lck1,
struct lock_struct *lck2)
{
+ /* Ignore PENDING locks. */
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
return False;
+ /* Read locks never conflict. */
if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
return False;
}
@@ -139,6 +141,39 @@
return brl_overlap(lck1, lck2);
}
+/****************************************************************************
+ See if lock2 can be added when lock1 is in place - when both locks are POSIX
+ flavour.
+****************************************************************************/
+
+static BOOL brl_conflict_posix(struct lock_struct *lck1,
+ struct lock_struct *lck2)
+{
+#if defined(DEVELOPER)
+ SMB_ASSERT(lck1->lock_flav == POSIX_LOCK);
+ SMB_ASSERT(lck2->lock_flav == POSIX_LOCK);
+#endif
+
+ /* Ignore PENDING locks. */
+ if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+ return False;
+
+ /* Read locks never conflict. */
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ /* Locks on the same context on the same fnum con't conflict. */
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ (lck1->fnum == lck2->fnum)) {
+ return False;
+ }
+
+ /* One is read, the other write, context or fnum are different,
+ do the overlap ? */
+ return brl_overlap(lck1, lck2);
+}
+
#if ZERO_ZERO
static BOOL brl_conflict1(struct lock_struct *lck1,
struct lock_struct *lck2)
@@ -287,9 +322,10 @@
{
unsigned int i;
struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
- char *tp;
+ struct lock_struct *tp;
for (i=0; i < br_lck->num_locks; i++) {
+ /* Do any Windows or POSIX locks conflict ? */
if (brl_conflict(&locks[i], plock)) {
NTSTATUS status = brl_lock_failed(plock);;
/* Did we block ourselves ? */
@@ -307,34 +343,292 @@
}
/* no conflicts - add it to the list of locks */
- tp = SMB_REALLOC(locks, (br_lck->num_locks + 1) * sizeof(*locks));
+ tp = (struct lock_struct *)SMB_REALLOC(locks, (br_lck->num_locks + 1) * sizeof(*locks));
if (!tp) {
return NT_STATUS_NO_MEMORY;
} else {
- locks = (struct lock_struct *)tp;
+ locks = tp;
memcpy(&locks[br_lck->num_locks], plock, sizeof(struct lock_struct));
br_lck->num_locks += 1;
br_lck->lock_data = (void *)locks;
br_lck->modified = True;
}
-#if ZERO_ZERO
- /* sort the lock list */
- qsort(br_lck->lock_data, (size_t)br_lck->num_locks, sizeof(lock), lock_compare);
-#endif
-
return NT_STATUS_OK;
}
/****************************************************************************
+ Cope with POSIX range splits and merges.
+****************************************************************************/
+
+static unsigned int brlock_posix_split_merge(struct lock_struct *lck_arr,
+ struct lock_struct *ex,
+ struct lock_struct *plock,
+ BOOL *lock_was_added)
+{
+ BOOL lock_types_differ = (ex->lock_type != plock->lock_type);
+
+ /* We can't merge non-conplicting locks on different context
+ or not on the same fnum */
+
+ if (!brl_same_context(&ex->context, &plock->context) || (ex->fnum != plock->fnum)) {
+ /* Just copy. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+
+ /* We now know we have the same context and fnum. */
+
+ /* Did we overlap ? */
+
+/*********************************************
+ +---------+
+ | ex |
+ +---------+
+ +-------+
+ | plock |
+ +-------+
+OR....
+ +---------+
+ | ex |
+ +---------+
+**********************************************/
+
+ if ( (ex->start >= (plock->start + plock->size)) ||
+ (plock->start >= (ex->start + ex->size))) {
+ /* No overlap with this lock - copy existing. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+
+/*********************************************
+ +---------+
+ | ex |
+ +---------+
+ +---------------------------+
+ | plock | -> replace with plock.
+ +---------------------------+
+**********************************************/
+
+ if ( (ex->start >= plock->start) &&
+ (ex->start + ex->size <= plock->start + plock->size) ) {
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ *lock_was_added = True;
+ return 1;
+ }
+
+/*********************************************
+ +---------------+
+ | ex |
+ +---------------+
+ +---------------+
+ | plock |
+ +---------------+
+BECOMES....
+ +---------------+-------+
+ | plock | ex | - different lock types.
+ +---------------+-------+
+OR....
+ +---------------+-------+
+ | ex | - same lock type.
+ +---------------+-------+
+**********************************************/
+
+ if ( (ex->start >= plock->start) &&
+ (ex->start < plock->start + plock->size) &&
+ (ex->start + ex->size > plock->start + plock->size) ) {
+
+ *lock_was_added = True;
+
+ /* If the lock types are the same, we merge, if different, we
+ add the new lock before the old. */
+
+ if (lock_types_differ) {
+ /* Add new. */
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], ex, sizeof(struct lock_struct));
+ /* Adjust existing start and size. */
+ lck_arr[1].start = plock->start + plock->size;
+ lck_arr[1].size = (ex->start + ex->size) - (plock->start + plock->size);
+ return 2;
+ } else {
+ /* Merge. */
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ /* Set new start and size. */
+ lck_arr[0].start = plock->start;
+ lck_arr[0].size = (ex->start + ex->size) - plock->start;
+ return 1;
+ }
+ }
+
+/*********************************************
+ +---------------+
+ | ex |
+ +---------------+
+ +---------------+
+ | plock |
+ +---------------+
+BECOMES....
+ +-------+---------------+
+ | ex | plock | - different lock types
+ +-------+---------------+
+
+OR
+ +-------+---------------+
+ | ex | - same lock type.
+ +-------+---------------+
+
+**********************************************/
+
+ if ( (ex->start < plock->start) &&
+ (ex->start + ex->size > plock->start) &&
+ (ex->start + ex->size <= plock->start + plock->size) ) {
+
+ *lock_was_added = True;
+
+ /* If the lock types are the same, we merge, if different, we
+ add the new lock after the old. */
+
+ if (lock_types_differ) {
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+ /* Adjust existing size. */
+ lck_arr[0].size = plock->start - ex->start;
+ return 2;
+ } else {
+ /* Merge. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ /* Adjust existing size. */
+ lck_arr[0].size = (plock->start + plock->size) - ex->start;
+ return 1;
+ }
+ }
+
+/*********************************************
+ +---------------------------+
+ | ex |
+ +---------------------------+
+ +---------+
+ | plock |
+ +---------+
+BECOMES.....
+ +-------+---------+---------+
+ | ex | plock | ex | - different lock types.
+ +-------+---------+---------+
+OR
+ +---------------------------+
+ | ex | - same lock type.
+ +---------------------------+
+**********************************************/
+
+ if ( (ex->start < plock->start) && (ex->start + ex->size > plock->start + plock->size) ) {
+ *lock_was_added = True;
+
+ if (lock_types_differ) {
+
+ /* We have to split ex into two locks here. */
+
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+ memcpy(&lck_arr[2], ex, sizeof(struct lock_struct));
+
+ /* Adjust first existing size. */
+ lck_arr[0].size = plock->start - ex->start;
+
+ /* Adjust second existing start and size. */
+ lck_arr[2].start = plock->start + plock->size;
+ lck_arr[2].size = (ex->start + ex->size) - (plock->start + plock->size);
+ return 3;
+ } else {
+ /* Just eat plock. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+ }
+
+ /* Never get here. */
+ smb_panic("brlock_posix_split_merge\n");
+ return 0;
+}
+
+/****************************************************************************
Lock a range of bytes - POSIX lock semantics.
+ We must cope with range splits and merges.
****************************************************************************/
static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
- struct lock_struct *plock)
+ struct lock_struct *plock,
+ BOOL *my_lock_ctx)
{
- /* Placeholder until I fix this. */
- return NT_STATUS_LOCK_NOT_GRANTED;
+ unsigned int i, count;
+ struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+ struct lock_struct *tp, *tp1;
+ BOOL lock_was_added = False;
+
+ /* No zero-zero locks for POSIX. */
+ if (plock->start == 0 && plock->size == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Don't allow 64-bit lock wrap. */
+ if (plock->start + plock->size < plock->start ||
+ plock->start + plock->size < plock->size) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* The worst case scenario here is we have to split an
+ existing POSIX lock range into two, and add our lock,
+ so we need at most 2 more entries. */
+
+ tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 2));
+ if (!tp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ count = 0;
+ for (i=0; i < br_lck->num_locks; i++) {
+ if (locks[i].lock_flav == WINDOWS_LOCK) {
+ /* Do any Windows flavour locks conflict ? */
+ if (brl_conflict(&locks[i], plock)) {
+ /* Did we block ourselves ? */
+ if (brl_same_context(&locks[i].context, &plock->context)) {
+ *my_lock_ctx = True;
+ }
+ /* No games with error messages. */
+ SAFE_FREE(tp);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+ /* Just copy the Windows lock into the new array. */
+ memcpy(&tp[count], &locks[i], sizeof(struct lock_struct));
+ count++;
+ } else {
+ /* POSIX conflict semantics are different. */
+ if (brl_conflict_posix(&locks[i], plock)) {
+ /* Can't block ourselves with POSIX locks. */
+ /* No games with error messages. */
+ SAFE_FREE(tp);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /* Work out overlaps. */
+ count += brlock_posix_split_merge(&tp[count], &locks[i], plock, &lock_was_added);
+ }
+ }
+
+ if (!lock_was_added) {
+ memcpy(&tp[count], plock, sizeof(struct lock_struct));
+ count++;
+ }
+
+ /* Realloc so we don't leak entries per lock call. */
+ tp1 = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+ if (!tp1) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ br_lck->num_locks = count;
+ br_lck->lock_data = (void *)tp1;
+ br_lck->modified = True;
+ return NT_STATUS_OK;
}
/****************************************************************************
@@ -350,6 +644,7 @@
enum brl_flavour lock_flav,
BOOL *my_lock_ctx)
{
+ NTSTATUS ret;
struct lock_struct lock;
*my_lock_ctx = False;
@@ -370,10 +665,17 @@
lock.lock_flav = lock_flav;
if (lock_flav == WINDOWS_LOCK) {
- return brl_lock_windows(br_lck, &lock, my_lock_ctx);
+ ret = brl_lock_windows(br_lck, &lock, my_lock_ctx);
} else {
- return brl_lock_posix(br_lck, &lock);
+ ret = brl_lock_posix(br_lck, &lock, my_lock_ctx);
}
+
+#if ZERO_ZERO
+ /* sort the lock list */
+ qsort(br_lck->lock_data, (size_t)br_lck->num_locks, sizeof(lock), lock_compare);
+#endif
+
+ return ret;
}
/****************************************************************************
Modified: trunk/source/locking/locking.c
===================================================================
--- trunk/source/locking/locking.c 2006-03-03 02:29:48 UTC (rev 13803)
+++ trunk/source/locking/locking.c 2006-03-03 03:00:52 UTC (rev 13804)
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
Locking functions
Copyright (C) Andrew Tridgell 1992-2000
- Copyright (C) Jeremy Allison 1992-2000
+ Copyright (C) Jeremy Allison 1992-2006
Copyright (C) Volker Lendecke 2005
This program is free software; you can redistribute it and/or modify
@@ -33,6 +33,7 @@
rewrtten completely to use new tdb code. Tridge, Dec '99
Added POSIX locking support. Jeremy Allison (jeremy at valinux.com), Apr. 2000.
+ Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006.
*/
#include "includes.h"
More information about the samba-cvs
mailing list