summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorTim Prouty <tprouty@samba.org>2009-02-03 11:56:35 -0800
committerTim Prouty <tprouty@samba.org>2009-02-09 23:47:45 -0800
commitc6f1f055fdeee29ad7c5b2ae9909e8f1b1a7daec (patch)
tree1fc919526e3c6988ede50457ad72b098d42c1be9 /source3/smbd
parent9c1310fa6ae1a67dc0fea3bf549d805ff167e78f (diff)
downloadsamba-c6f1f055fdeee29ad7c5b2ae9909e8f1b1a7daec.tar.gz
samba-c6f1f055fdeee29ad7c5b2ae9909e8f1b1a7daec.tar.bz2
samba-c6f1f055fdeee29ad7c5b2ae9909e8f1b1a7daec.zip
s3 oplocks: Make the level2 oplock contention API more granular
This replaces release_level2_oplocks_on_change with contend_level2_oplock_begin/end in order to contend level2 oplocks throughout an operation rather than just at the begining. This is necessary for some kernel oplock implementations, and also lays the groundwork for better correctness in Samba's standard level2 oplock handling. The next step for non-kernel oplocks is to add additional state to the share mode lock struct that prevents any new opens from granting oplocks while a contending operation is in progress. All operations that contend level 2 oplocks are now correctly spanned except for aio and synchronous writes. The two write paths both have non-trivial error paths that need extra care to get right. RAW-OPLOCK and the rest of 'make test' are still passing with this change.
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/aio.c4
-rw-r--r--source3/smbd/fileio.c4
-rw-r--r--source3/smbd/oplock.c25
-rw-r--r--source3/smbd/oplock_irix.c6
-rw-r--r--source3/smbd/oplock_linux.c6
-rw-r--r--source3/smbd/reply.c11
-rw-r--r--source3/smbd/vfs.c33
7 files changed, 62 insertions, 27 deletions
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 75ce07d41a..6b19e098e5 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -291,7 +291,9 @@ bool schedule_aio_write_and_X(connection_struct *conn,
aio_ex->req = talloc_move(aio_ex, &req);
- release_level_2_oplocks_on_change(fsp);
+ /* This should actually be improved to span the write. */
+ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
+ contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
if (!write_through && !lp_syncalways(SNUM(fsp->conn))
&& fsp->aio_write_behind) {
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 3e3f0943b3..a9a97a2d14 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -318,7 +318,9 @@ ssize_t write_file(struct smb_request *req,
* the shared memory area whilst doing this.
*/
- release_level_2_oplocks_on_change(fsp);
+ /* This should actually be improved to span the write. */
+ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
+ contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
#ifdef WITH_PROFILE
if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 0945ac6677..4c84fd41ed 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -329,7 +329,7 @@ static void add_oplock_timeout_handler(files_struct *fsp)
the client for LEVEL2.
*******************************************************************/
-static void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx,
+void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx,
void *private_data,
uint32_t msg_type,
struct server_id src,
@@ -699,7 +699,8 @@ static void process_open_retry_message(struct messaging_context *msg_ctx,
none.
****************************************************************************/
-void release_level_2_oplocks_on_change(files_struct *fsp)
+static void contend_level2_oplocks_begin_default(files_struct *fsp,
+ enum level2_contention_type type)
{
int i;
struct share_mode_lock *lck;
@@ -799,6 +800,26 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
TALLOC_FREE(lck);
}
+void contend_level2_oplocks_begin(files_struct *fsp,
+ enum level2_contention_type type)
+{
+ if (koplocks && koplocks->ops->contend_level2_oplocks_begin) {
+ koplocks->ops->contend_level2_oplocks_begin(fsp, type);
+ return;
+ }
+
+ contend_level2_oplocks_begin_default(fsp, type);
+}
+
+void contend_level2_oplocks_end(files_struct *fsp,
+ enum level2_contention_type type)
+{
+ /* Only kernel oplocks implement this so far */
+ if (koplocks && koplocks->ops->contend_level2_oplocks_end) {
+ koplocks->ops->contend_level2_oplocks_end(fsp, type);
+ }
+}
+
/****************************************************************************
Linearize a share mode entry struct to an internal oplock break message.
****************************************************************************/
diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c
index 23b2fa9081..bbc9132a08 100644
--- a/source3/smbd/oplock_irix.c
+++ b/source3/smbd/oplock_irix.c
@@ -270,8 +270,10 @@ static void irix_oplocks_read_fde_handler(struct event_context *ev,
****************************************************************************/
static const struct kernel_oplocks_ops irix_koplocks = {
- .set_oplock = irix_set_kernel_oplock,
- .release_oplock = irix_release_kernel_oplock,
+ .set_oplock = irix_set_kernel_oplock,
+ .release_oplock = irix_release_kernel_oplock,
+ .contend_level2_oplocks_begin = NULL,
+ .contend_level2_oplocks_end = NULL,
};
struct kernel_oplocks *irix_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index 5840ff0851..273fbfdc01 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -179,8 +179,10 @@ static bool linux_oplocks_available(void)
****************************************************************************/
static const struct kernel_oplocks_ops linux_koplocks = {
- .set_oplock = linux_set_kernel_oplock,
- .release_oplock = linux_release_kernel_oplock,
+ .set_oplock = linux_set_kernel_oplock,
+ .release_oplock = linux_release_kernel_oplock,
+ .contend_level2_oplocks_begin = NULL,
+ .contend_level2_oplocks_end = NULL,
};
struct kernel_oplocks *linux_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 60e2e5dc7a..151f9d0827 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3010,8 +3010,6 @@ void reply_lockread(struct smb_request *req)
return;
}
- release_level_2_oplocks_on_change(fsp);
-
numtoread = SVAL(req->vwv+1, 0);
startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
@@ -4497,8 +4495,6 @@ void reply_lock(struct smb_request *req)
return;
}
- release_level_2_oplocks_on_change(fsp);
-
count = (uint64_t)IVAL(req->vwv+1, 0);
offset = (uint64_t)IVAL(req->vwv+3, 0);
@@ -6870,13 +6866,6 @@ void reply_lockingX(struct smb_request *req)
}
}
- /*
- * We do this check *after* we have checked this is not a oplock break
- * response message. JRA.
- */
-
- release_level_2_oplocks_on_change(fsp);
-
if (req->buflen <
(num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 515e557f67..8d82ca550c 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -514,8 +514,6 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
uint64_t space_avail;
uint64_t bsize,dfree,dsize;
- release_level_2_oplocks_on_change(fsp);
-
/*
* Actually try and commit the space on disk....
*/
@@ -541,15 +539,23 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
fsp->fsp_name, (double)st.st_size ));
+ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
+
flush_write_cache(fsp, SIZECHANGE_FLUSH);
if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
set_filelen_write_cache(fsp, len);
}
+
+ contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
+
return ret;
}
/* Grow - we need to test if we have enough space. */
+ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+ contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+
if (!lp_strict_allocate(SNUM(fsp->conn)))
return 0;
@@ -581,7 +587,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
{
int ret;
- release_level_2_oplocks_on_change(fsp);
+ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
+
DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
flush_write_cache(fsp, SIZECHANGE_FLUSH);
if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
@@ -592,6 +599,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
fsp->fsp_name);
}
+ contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
+
return ret;
}
@@ -613,7 +622,6 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
size_t num_to_write;
ssize_t pwrite_ret;
- release_level_2_oplocks_on_change(fsp);
ret = SMB_VFS_FSTAT(fsp, &st);
if (ret == -1) {
return ret;
@@ -626,13 +634,16 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
+ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
+
flush_write_cache(fsp, SIZECHANGE_FLUSH);
if (!sparse_buf) {
sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
if (!sparse_buf) {
errno = ENOMEM;
- return -1;
+ ret = -1;
+ goto out;
}
}
@@ -647,17 +658,23 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
if (pwrite_ret == -1) {
DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
fsp->fsp_name, strerror(errno) ));
- return -1;
+ ret = -1;
+ goto out;
}
if (pwrite_ret == 0) {
- return 0;
+ ret = 0;
+ goto out;
}
total += pwrite_ret;
}
set_filelen_write_cache(fsp, len);
- return 0;
+
+ ret = 0;
+ out:
+ contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
+ return ret;
}
/****************************************************************************