From 8cf14c21b3bc55454728bf48b23f696e15c92aea Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 16 May 2011 12:20:14 -0700 Subject: Fix the SMB2 showstopper, found by an extended torture test from Volker. In the oplock refactoring, the algorithm underwent an unnoticed change. In 3.5.x stat_opens were silently (i.e. no explicit code had comments explaining this) ignored when looking for oplock breaks and share mode violations. After the refactoring, the function find_oplock_types() no longer ignored stat_open entries in the share mode table when looking for batch and exclusive oplocks. This patch adds two changes to find_oplock_types() to ignore the case where the incoming open request is a stat open being tested against existing opens, and also when the incoming open request is a non-stat open being tested against existing stat opens. Neither of these cause an oplock break or share mode violation. Thanks a *lot* to Volker, who persevered in reproducing this problem. Autobuild-User: Jeremy Allison Autobuild-Date: Mon May 16 22:38:20 CEST 2011 on sn-devel-104 --- source3/smbd/open.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'source3/smbd') diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 5d9621748f..bb7e6c29df 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -949,7 +949,9 @@ static NTSTATUS send_break_message(files_struct *fsp, * Do internal consistency checks on the share mode for a file. */ -static void find_oplock_types(struct share_mode_lock *lck, +static void find_oplock_types(files_struct *fsp, + int oplock_request, + struct share_mode_lock *lck, struct share_mode_entry **pp_batch, struct share_mode_entry **pp_ex_or_batch, bool *got_level2, @@ -962,11 +964,27 @@ static void find_oplock_types(struct share_mode_lock *lck, *got_level2 = false; *got_no_oplock = false; + /* Ignore stat or internal opens, as is done in + delay_for_batch_oplocks() and + delay_for_exclusive_oplocks(). + */ + if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) { + return; + } + for (i=0; inum_share_modes; i++) { if (!is_valid_share_mode_entry(&lck->share_modes[i])) { continue; } + if (lck->share_modes[i].op_type == NO_OPLOCK && + is_stat_open(lck->share_modes[i].access_mask)) { + /* We ignore stat opens in the table - they + always have NO_OPLOCK and never get or + cause breaks. JRA. */ + continue; + } + if (BATCH_OPLOCK_TYPE(lck->share_modes[i].op_type)) { /* batch - can only be one. */ if (*pp_ex_or_batch || *pp_batch || *got_level2 || *got_no_oplock) { @@ -1906,7 +1924,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } /* Get the types we need to examine. */ - find_oplock_types(lck, + find_oplock_types(fsp, + oplock_request, + lck, &batch_entry, &exclusive_entry, &got_level2_oplock, @@ -2151,7 +2171,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } /* Get the types we need to examine. */ - find_oplock_types(lck, + find_oplock_types(fsp, + oplock_request, + lck, &batch_entry, &exclusive_entry, &got_level2_oplock, -- cgit