1998-08-17 13:11:34 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
1998-08-17 13:11:34 +00:00
oplock processing
Copyright ( C ) Andrew Tridgell 1992 - 1998
2001-10-20 21:59:34 +00:00
Copyright ( C ) Jeremy Allison 1998 - 2001
2005-09-30 17:13:37 +00:00
Copyright ( C ) Volker Lendecke 2005
2011-08-02 16:44:53 +02:00
1998-08-17 13:11:34 +00:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
1998-08-17 13:11:34 +00:00
( at your option ) any later version .
2011-08-02 16:44:53 +02:00
1998-08-17 13:11:34 +00:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2011-08-02 16:44:53 +02:00
1998-08-17 13:11:34 +00:00
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 13:11:34 +00:00
*/
2006-05-05 02:06:37 +00:00
# define DBGC_CLASS DBGC_LOCKING
1998-08-17 13:11:34 +00:00
# include "includes.h"
2011-03-22 16:57:01 +01:00
# include "smbd/smbd.h"
2009-01-08 12:03:45 +01:00
# include "smbd/globals.h"
2011-03-24 15:31:06 +01:00
# include "messages.h"
2011-11-24 14:11:28 +01:00
# include "../librpc/gen_ndr/open_files.h"
2000-06-10 13:38:07 +00:00
1999-12-13 13:27:58 +00:00
/****************************************************************************
Get the number of current exclusive oplocks .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 get_number_of_exclusive_open_oplocks ( void )
{
return exclusive_oplocks_open ;
}
1998-09-05 05:07:05 +00:00
2009-01-23 10:08:44 +01:00
/*
* helper function used by the kernel oplock backends to post the break message
*/
void break_kernel_oplock ( struct messaging_context * msg_ctx , files_struct * fsp )
2001-09-05 22:45:48 +00:00
{
2009-01-23 10:08:44 +01:00
uint8_t msg [ MSG_SMB_KERNEL_BREAK_SIZE ] ;
2001-09-05 22:45:48 +00:00
2009-01-23 10:08:44 +01:00
/* Put the kernel break info into the message. */
2009-02-15 23:45:28 -08:00
push_file_id_24 ( ( char * ) msg , & fsp - > file_id ) ;
SIVAL ( msg , 24 , fsp - > fh - > gen_id ) ;
2000-06-09 06:58:06 +00:00
2009-01-23 10:08:44 +01:00
/* Don't need to be root here as we're only ever
sending to ourselves . */
2002-07-15 10:35:28 +00:00
2010-07-04 18:07:29 +02:00
messaging_send_buf ( msg_ctx , messaging_server_id ( msg_ctx ) ,
2009-01-23 10:08:44 +01:00
MSG_SMB_KERNEL_BREAK ,
msg , MSG_SMB_KERNEL_BREAK_SIZE ) ;
1998-09-23 01:48:45 +00:00
}
1999-12-13 13:27:58 +00:00
/****************************************************************************
2011-01-31 12:00:15 -08:00
Attempt to set an oplock on a file . Succeeds if kernel oplocks are
disabled ( just sets flags ) and no byte - range locks in the file . Returns True
if oplock set .
1999-12-13 13:27:58 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-20 21:59:34 +00:00
2007-10-18 17:40:25 -07:00
bool set_file_oplock ( files_struct * fsp , int oplock_type )
1999-12-13 13:27:58 +00:00
{
2012-03-30 16:11:08 +02:00
bool use_kernel = lp_kernel_oplocks ( SNUM ( fsp - > conn ) ) & & koplocks ;
2011-01-31 12:00:15 -08:00
if ( fsp - > oplock_type = = LEVEL_II_OPLOCK ) {
2012-03-30 16:11:08 +02:00
if ( use_kernel & &
2011-01-31 12:00:15 -08:00
! ( koplocks - > flags & KOPLOCKS_LEVEL2_SUPPORTED ) ) {
DEBUG ( 10 , ( " Refusing level2 oplock, kernel oplocks "
" don't support them \n " ) ) ;
return false ;
}
2009-04-08 08:29:23 +02:00
}
2011-01-31 12:00:15 -08:00
2008-12-17 17:23:13 -08:00
if ( ( fsp - > oplock_type ! = NO_OPLOCK ) & &
( fsp - > oplock_type ! = FAKE_LEVEL_II_OPLOCK ) & &
2012-03-30 16:11:08 +02:00
use_kernel & &
2009-01-09 14:02:18 +01:00
! koplocks - > ops - > set_oplock ( koplocks , fsp , oplock_type ) ) {
2000-06-09 06:58:06 +00:00
return False ;
2006-01-12 22:17:54 +00:00
}
1999-12-13 13:27:58 +00:00
2000-06-09 06:58:06 +00:00
fsp - > oplock_type = oplock_type ;
fsp - > sent_oplock_break = NO_BREAK_SENT ;
2006-01-12 22:17:54 +00:00
if ( oplock_type = = LEVEL_II_OPLOCK ) {
2000-06-09 06:58:06 +00:00
level_II_oplocks_open + + ;
2008-12-17 17:23:13 -08:00
} else if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) ) {
2000-06-09 06:58:06 +00:00
exclusive_oplocks_open + + ;
2006-01-12 22:17:54 +00:00
}
1999-12-13 13:27:58 +00:00
2007-05-29 09:30:34 +00:00
DEBUG ( 5 , ( " set_file_oplock: granted oplock on file %s, %s/%lu, "
2006-05-05 02:06:37 +00:00
" tv_sec = %x, tv_usec = %x \n " ,
2009-07-10 14:50:37 -07:00
fsp_str_dbg ( fsp ) , file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 09:30:34 +00:00
fsp - > fh - > gen_id , ( int ) fsp - > open_time . tv_sec ,
2006-05-05 02:06:37 +00:00
( int ) fsp - > open_time . tv_usec ) ) ;
1998-08-17 13:11:34 +00:00
2000-06-09 06:58:06 +00:00
return True ;
1998-08-17 13:11:34 +00:00
}
1999-12-13 13:27:58 +00:00
/****************************************************************************
Attempt to release an oplock on a file . Decrements oplock count .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void release_file_oplock ( files_struct * fsp )
{
2005-09-30 17:13:37 +00:00
if ( ( fsp - > oplock_type ! = NO_OPLOCK ) & &
( fsp - > oplock_type ! = FAKE_LEVEL_II_OPLOCK ) & &
koplocks ) {
2009-01-09 13:07:58 -08:00
koplocks - > ops - > release_oplock ( koplocks , fsp , NO_OPLOCK ) ;
2005-09-30 17:13:37 +00:00
}
2000-06-09 06:58:06 +00:00
2006-01-12 22:17:54 +00:00
if ( fsp - > oplock_type = = LEVEL_II_OPLOCK ) {
2000-06-09 06:58:06 +00:00
level_II_oplocks_open - - ;
2006-01-12 22:17:54 +00:00
} else if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) ) {
2000-06-09 06:58:06 +00:00
exclusive_oplocks_open - - ;
2006-01-12 22:17:54 +00:00
}
2005-09-30 17:13:37 +00:00
SMB_ASSERT ( exclusive_oplocks_open > = 0 ) ;
SMB_ASSERT ( level_II_oplocks_open > = 0 ) ;
2008-12-17 17:23:13 -08:00
if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) ) {
/* This doesn't matter for close. */
fsp - > oplock_type = FAKE_LEVEL_II_OPLOCK ;
} else {
fsp - > oplock_type = NO_OPLOCK ;
}
2000-06-09 06:58:06 +00:00
fsp - > sent_oplock_break = NO_BREAK_SENT ;
2008-12-17 17:23:13 -08:00
2000-06-09 06:58:06 +00:00
flush_write_cache ( fsp , OPLOCK_RELEASE_FLUSH ) ;
2010-10-02 17:07:00 +02:00
delete_write_cache ( fsp ) ;
2007-06-22 17:19:08 +00:00
TALLOC_FREE ( fsp - > oplock_timeout ) ;
1999-12-13 13:27:58 +00:00
}
/****************************************************************************
Attempt to downgrade an oplock on a file . Doesn ' t decrement oplock count .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void downgrade_file_oplock ( files_struct * fsp )
{
2009-01-27 16:13:35 -08:00
if ( ! EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) ) {
DEBUG ( 0 , ( " trying to downgrade an already-downgraded oplock! \n " ) ) ;
return ;
}
2006-01-12 22:17:54 +00:00
if ( koplocks ) {
2009-01-09 13:07:58 -08:00
koplocks - > ops - > release_oplock ( koplocks , fsp , LEVEL_II_OPLOCK ) ;
2006-01-12 22:17:54 +00:00
}
2000-06-10 13:38:07 +00:00
fsp - > oplock_type = LEVEL_II_OPLOCK ;
exclusive_oplocks_open - - ;
level_II_oplocks_open + + ;
fsp - > sent_oplock_break = NO_BREAK_SENT ;
1999-12-13 13:27:58 +00:00
}
/****************************************************************************
Remove a file oplock . Copes with level II and exclusive .
2000-11-16 00:59:18 +00:00
Locks then unlocks the share mode lock . Client can decide to go directly
to none even if a " break-to-level II " was sent .
1999-12-13 13:27:58 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-18 17:40:25 -07:00
bool remove_oplock ( files_struct * fsp )
1999-12-13 13:27:58 +00:00
{
2007-10-18 17:40:25 -07:00
bool ret ;
2005-09-30 17:13:37 +00:00
struct share_mode_lock * lck ;
2000-06-10 13:38:07 +00:00
/* Remove the oplock flag from the sharemode. */
2012-02-19 14:23:56 +01:00
lck = get_existing_share_mode_lock ( talloc_tos ( ) , fsp - > file_id ) ;
2005-09-30 17:13:37 +00:00
if ( lck = = NULL ) {
DEBUG ( 0 , ( " remove_oplock: failed to lock share entry for "
2009-07-10 14:50:37 -07:00
" file %s \n " , fsp_str_dbg ( fsp ) ) ) ;
2003-04-22 01:12:52 +00:00
return False ;
2000-06-10 13:38:07 +00:00
}
2005-09-30 17:13:37 +00:00
ret = remove_share_oplock ( lck , fsp ) ;
if ( ! ret ) {
DEBUG ( 0 , ( " remove_oplock: failed to remove share oplock for "
2007-05-29 09:30:34 +00:00
" file %s fnum %d, %s \n " ,
2009-07-10 14:50:37 -07:00
fsp_str_dbg ( fsp ) , fsp - > fnum ,
file_id_string_tos ( & fsp - > file_id ) ) ) ;
2005-09-30 17:13:37 +00:00
}
release_file_oplock ( fsp ) ;
2006-02-20 17:59:58 +00:00
TALLOC_FREE ( lck ) ;
2005-09-30 17:13:37 +00:00
return ret ;
}
1999-12-13 13:27:58 +00:00
2005-09-30 17:13:37 +00:00
/*
* Deal with a reply when a break - to - level II was sent .
*/
2007-10-18 17:40:25 -07:00
bool downgrade_oplock ( files_struct * fsp )
2005-09-30 17:13:37 +00:00
{
2007-10-18 17:40:25 -07:00
bool ret ;
2005-09-30 17:13:37 +00:00
struct share_mode_lock * lck ;
1999-12-13 13:27:58 +00:00
2012-02-19 14:23:56 +01:00
lck = get_existing_share_mode_lock ( talloc_tos ( ) , fsp - > file_id ) ;
2005-09-30 17:13:37 +00:00
if ( lck = = NULL ) {
DEBUG ( 0 , ( " downgrade_oplock: failed to lock share entry for "
2009-07-10 14:50:37 -07:00
" file %s \n " , fsp_str_dbg ( fsp ) ) ) ;
2005-09-30 17:13:37 +00:00
return False ;
2000-06-10 13:38:07 +00:00
}
2005-09-30 17:13:37 +00:00
ret = downgrade_share_oplock ( lck , fsp ) ;
if ( ! ret ) {
DEBUG ( 0 , ( " downgrade_oplock: failed to downgrade share oplock "
2007-05-29 09:30:34 +00:00
" for file %s fnum %d, file_id %s \n " ,
2009-07-10 14:50:37 -07:00
fsp_str_dbg ( fsp ) , fsp - > fnum ,
file_id_string_tos ( & fsp - > file_id ) ) ) ;
2005-09-30 17:13:37 +00:00
}
2006-01-12 22:17:54 +00:00
2005-09-30 17:13:37 +00:00
downgrade_file_oplock ( fsp ) ;
2006-02-20 17:59:58 +00:00
TALLOC_FREE ( lck ) ;
2000-06-10 13:38:07 +00:00
return ret ;
1998-09-23 01:48:45 +00:00
}
2009-02-03 15:40:23 -08:00
/*
* Some kernel oplock implementations handle the notification themselves .
*/
bool should_notify_deferred_opens ( )
{
return ! ( koplocks & &
( koplocks - > flags & KOPLOCKS_DEFERRED_OPEN_NOTIFICATION ) ) ;
}
1998-09-23 01:48:45 +00:00
/****************************************************************************
2005-09-30 17:13:37 +00:00
Set up an oplock break message .
1998-08-17 13:11:34 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-20 21:59:34 +00:00
2010-04-09 19:26:34 -07:00
static char * new_break_message_smb1 ( TALLOC_CTX * mem_ctx ,
2010-04-24 00:29:41 -07:00
files_struct * fsp , int cmd )
1998-08-17 13:11:34 +00:00
{
2011-06-07 11:30:12 +10:00
char * result = talloc_array ( mem_ctx , char , smb_size + 8 * 2 + 0 ) ;
2001-10-20 21:59:34 +00:00
2005-09-30 17:13:37 +00:00
if ( result = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NULL ;
2001-10-20 21:59:34 +00:00
}
2005-09-30 17:13:37 +00:00
memset ( result , ' \0 ' , smb_size ) ;
2008-01-04 12:56:23 -08:00
srv_set_message ( result , 8 , 0 , true ) ;
2005-09-30 17:13:37 +00:00
SCVAL ( result , smb_com , SMBlockingX ) ;
SSVAL ( result , smb_tid , fsp - > conn - > cnum ) ;
SSVAL ( result , smb_pid , 0xFFFF ) ;
SSVAL ( result , smb_uid , 0 ) ;
SSVAL ( result , smb_mid , 0xFFFF ) ;
SCVAL ( result , smb_vwv0 , 0xFF ) ;
SSVAL ( result , smb_vwv2 , fsp - > fnum ) ;
SCVAL ( result , smb_vwv3 , LOCKING_ANDX_OPLOCK_RELEASE ) ;
SCVAL ( result , smb_vwv3 + 1 , cmd ) ;
return result ;
1999-12-13 13:27:58 +00:00
}
/****************************************************************************
Function to do the waiting before sending a local break .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-07-17 09:56:25 +00:00
static void wait_before_sending_break ( void )
1999-12-13 13:27:58 +00:00
{
2006-04-15 04:07:10 +00:00
long wait_time = ( long ) lp_oplock_break_wait_time ( ) ;
1999-12-13 13:27:58 +00:00
2006-04-15 04:07:10 +00:00
if ( wait_time ) {
smb_msleep ( wait_time ) ;
2001-10-20 21:59:34 +00:00
}
1999-12-13 13:27:58 +00:00
}
/****************************************************************************
Ensure that we have a valid oplock .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-20 21:59:34 +00:00
2010-10-03 17:18:26 +02:00
static files_struct * initial_break_processing (
struct smbd_server_connection * sconn , struct file_id id ,
unsigned long file_id )
1998-08-17 13:11:34 +00:00
{
2001-10-20 21:59:34 +00:00
files_struct * fsp = NULL ;
if ( DEBUGLVL ( 3 ) ) {
2007-05-29 09:30:34 +00:00
dbgtext ( " initial_break_processing: called for %s/%u \n " ,
2007-09-10 10:56:07 +00:00
file_id_string_tos ( & id ) , ( int ) file_id ) ;
2001-10-20 21:59:34 +00:00
dbgtext ( " Current oplocks_open (exclusive = %d, levelII = %d) \n " ,
exclusive_oplocks_open , level_II_oplocks_open ) ;
}
/*
* We need to search the file open table for the
* entry containing this dev and inode , and ensure
* we have an oplock on it .
*/
2010-10-03 17:18:26 +02:00
fsp = file_find_dif ( sconn , id , file_id ) ;
2001-10-20 21:59:34 +00:00
if ( fsp = = NULL ) {
/* The file could have been closed in the meantime - return success. */
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " initial_break_processing: cannot find open file with " ) ;
2007-09-10 10:56:07 +00:00
dbgtext ( " file_id %s gen_id = %lu " , file_id_string_tos ( & id ) , file_id ) ;
2001-10-20 21:59:34 +00:00
dbgtext ( " allowing break to succeed. \n " ) ;
}
return NULL ;
}
/* Ensure we have an oplock on the file */
/*
* There is a potential race condition in that an oplock could
* have been broken due to another udp request , and yet there are
* still oplock break messages being sent in the udp message
* queue for this file . So return true if we don ' t have an oplock ,
* as we may have just freed it .
*/
if ( fsp - > oplock_type = = NO_OPLOCK ) {
if ( DEBUGLVL ( 3 ) ) {
2009-07-10 14:50:37 -07:00
dbgtext ( " initial_break_processing: file %s " ,
fsp_str_dbg ( fsp ) ) ;
2007-05-29 09:30:34 +00:00
dbgtext ( " (file_id = %s gen_id = %lu) has no oplock. \n " ,
2007-09-10 10:56:07 +00:00
file_id_string_tos ( & id ) , fsp - > fh - > gen_id ) ;
2001-10-20 21:59:34 +00:00
dbgtext ( " Allowing break to succeed regardless. \n " ) ;
}
return NULL ;
}
return fsp ;
1999-12-13 13:27:58 +00:00
}
2007-01-17 12:59:14 +00:00
static void oplock_timeout_handler ( struct event_context * ctx ,
struct timed_event * te ,
2009-01-05 10:22:50 +01:00
struct timeval now ,
2005-09-30 17:13:37 +00:00
void * private_data )
1999-12-13 13:27:58 +00:00
{
2006-08-08 09:56:38 +00:00
files_struct * fsp = ( files_struct * ) private_data ;
2004-06-11 23:54:52 +00:00
2007-06-22 17:19:08 +00:00
/* Remove the timed event handler. */
TALLOC_FREE ( fsp - > oplock_timeout ) ;
2009-07-10 14:50:37 -07:00
DEBUG ( 0 , ( " Oplock break failed for file %s -- replying anyway \n " ,
fsp_str_dbg ( fsp ) ) ) ;
2005-09-30 17:13:37 +00:00
remove_oplock ( fsp ) ;
reply_to_oplock_break_requests ( fsp ) ;
1999-12-13 13:27:58 +00:00
}
2006-01-27 23:30:30 +00:00
/*******************************************************************
Add a timeout handler waiting for the client reply .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_oplock_timeout_handler ( files_struct * fsp )
{
2009-02-03 15:40:23 -08:00
/*
* If kernel oplocks already notifies smbds when an oplock break times
* out , just return .
*/
if ( koplocks & &
( koplocks - > flags & KOPLOCKS_TIMEOUT_NOTIFICATION ) ) {
return ;
}
2006-01-27 23:30:30 +00:00
if ( fsp - > oplock_timeout ! = NULL ) {
DEBUG ( 0 , ( " Logic problem -- have an oplock event hanging "
" around \n " ) ) ;
}
fsp - > oplock_timeout =
2011-12-12 13:51:27 +01:00
tevent_add_timer ( fsp - > conn - > sconn - > ev_ctx , fsp ,
timeval_current_ofs ( OPLOCK_BREAK_TIMEOUT , 0 ) ,
oplock_timeout_handler , fsp ) ;
2006-01-27 23:30:30 +00:00
if ( fsp - > oplock_timeout = = NULL ) {
DEBUG ( 0 , ( " Could not add oplock timeout handler \n " ) ) ;
}
}
2010-04-24 00:29:41 -07:00
static void send_break_message_smb1 ( files_struct * fsp , int level )
2010-04-07 19:00:44 -07:00
{
2010-04-09 19:26:34 -07:00
char * break_msg = new_break_message_smb1 ( talloc_tos ( ) ,
2010-04-07 19:00:44 -07:00
fsp ,
level ) ;
if ( break_msg = = NULL ) {
exit_server ( " Could not talloc break_msg \n " ) ;
}
show_msg ( break_msg ) ;
2010-08-24 20:10:20 +02:00
if ( ! srv_send_smb ( fsp - > conn - > sconn ,
2010-04-07 19:00:44 -07:00
break_msg , false , 0 ,
IS_CONN_ENCRYPTED ( fsp - > conn ) ,
NULL ) ) {
2010-04-09 19:26:34 -07:00
exit_server_cleanly ( " send_break_message_smb1: "
2010-04-07 19:00:44 -07:00
" srv_send_smb failed. " ) ;
}
TALLOC_FREE ( break_msg ) ;
}
2009-04-02 18:33:30 -07:00
void break_level2_to_none_async ( files_struct * fsp )
{
2010-06-12 13:21:46 +02:00
struct smbd_server_connection * sconn = fsp - > conn - > sconn ;
2009-04-02 18:33:30 -07:00
if ( fsp - > oplock_type = = NO_OPLOCK ) {
/* We already got a "break to none" message and we've handled
* it . just ignore . */
DEBUG ( 3 , ( " process_oplock_async_level2_break_message: already "
" broken to none, ignoring. \n " ) ) ;
return ;
}
if ( fsp - > oplock_type = = FAKE_LEVEL_II_OPLOCK ) {
/* Don't tell the client, just downgrade. */
DEBUG ( 3 , ( " process_oplock_async_level2_break_message: "
" downgrading fake level 2 oplock. \n " ) ) ;
remove_oplock ( fsp ) ;
return ;
}
/* Ensure we're really at level2 state. */
SMB_ASSERT ( fsp - > oplock_type = = LEVEL_II_OPLOCK ) ;
DEBUG ( 10 , ( " process_oplock_async_level2_break_message: sending break "
" to none message for fid %d, file %s \n " , fsp - > fnum ,
2009-07-10 14:50:37 -07:00
fsp_str_dbg ( fsp ) ) ) ;
2009-04-02 18:33:30 -07:00
/* Now send a break to none message to our client. */
2010-06-09 19:12:02 -07:00
if ( sconn - > using_smb2 ) {
2010-04-09 19:26:34 -07:00
send_break_message_smb2 ( fsp , OPLOCKLEVEL_NONE ) ;
2010-04-07 19:00:44 -07:00
} else {
2010-04-09 19:26:34 -07:00
send_break_message_smb1 ( fsp , OPLOCKLEVEL_NONE ) ;
2009-04-02 18:33:30 -07:00
}
/* Async level2 request, don't send a reply, just remove the oplock. */
remove_oplock ( fsp ) ;
}
2006-01-27 23:30:30 +00:00
/*******************************************************************
This handles the case of a write triggering a break to none
message on a level2 oplock .
When we get this message we may be in any of three states :
NO_OPLOCK , LEVEL_II , FAKE_LEVEL2 . We only send a message to
the client for LEVEL2 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-12-14 09:54:42 +01:00
static void process_oplock_async_level2_break_message ( struct messaging_context * msg_ctx ,
2007-05-14 20:31:28 +00:00
void * private_data ,
uint32_t msg_type ,
struct server_id src ,
DATA_BLOB * data )
2006-01-27 23:30:30 +00:00
{
struct share_mode_entry msg ;
files_struct * fsp ;
2011-12-13 13:18:47 +01:00
struct smbd_server_connection * sconn =
2011-12-14 09:50:24 +01:00
talloc_get_type_abort ( private_data ,
2011-12-13 13:18:47 +01:00
struct smbd_server_connection ) ;
2006-01-27 23:30:30 +00:00
2011-12-13 13:18:47 +01:00
if ( data - > data = = NULL ) {
DEBUG ( 0 , ( " Got NULL buffer \n " ) ) ;
2010-10-03 17:20:43 +02:00
return ;
}
2007-05-14 20:31:28 +00:00
if ( data - > length ! = MSG_SMB_SHARE_MODE_ENTRY_SIZE ) {
DEBUG ( 0 , ( " Got invalid msg len %d \n " , ( int ) data - > length ) ) ;
2006-01-27 23:30:30 +00:00
return ;
}
/* De-linearize incoming message. */
2007-05-14 20:31:28 +00:00
message_to_share_mode_entry ( & msg , ( char * ) data - > data ) ;
2006-01-27 23:30:30 +00:00
2009-04-07 09:49:55 -07:00
DEBUG ( 10 , ( " Got oplock async level 2 break message from pid %s: "
2011-12-02 15:03:05 +01:00
" %s/%llu \n " , server_id_str ( talloc_tos ( ) , & src ) ,
file_id_string_tos ( & msg . id ) ,
( unsigned long long ) msg . share_file_id ) ) ;
2006-01-27 23:30:30 +00:00
2010-10-03 17:20:43 +02:00
fsp = initial_break_processing ( sconn , msg . id , msg . share_file_id ) ;
2006-01-27 23:30:30 +00:00
if ( fsp = = NULL ) {
/* We hit a race here. Break messages are sent, and before we
* get to process this message , we have closed the file .
* No need to reply as this is an async message . */
DEBUG ( 3 , ( " process_oplock_async_level2_break_message: Did not find fsp, ignoring \n " ) ) ;
return ;
}
2009-04-02 18:33:30 -07:00
break_level2_to_none_async ( fsp ) ;
2006-01-27 23:30:30 +00:00
}
/*******************************************************************
This handles the generic oplock break message from another smbd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-14 20:31:28 +00:00
static void process_oplock_break_message ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id src ,
DATA_BLOB * data )
1999-12-13 13:27:58 +00:00
{
2006-01-12 22:17:54 +00:00
struct share_mode_entry msg ;
2005-09-30 17:13:37 +00:00
files_struct * fsp ;
2007-10-18 17:40:25 -07:00
bool break_to_level2 = False ;
2012-03-30 16:11:08 +02:00
bool use_kernel ;
2011-12-13 13:18:47 +01:00
struct smbd_server_connection * sconn =
2011-12-14 09:50:24 +01:00
talloc_get_type_abort ( private_data ,
2011-12-13 13:18:47 +01:00
struct smbd_server_connection ) ;
2001-10-20 21:59:34 +00:00
2011-12-13 13:18:47 +01:00
if ( data - > data = = NULL ) {
DEBUG ( 0 , ( " Got NULL buffer \n " ) ) ;
2010-10-03 17:22:09 +02:00
return ;
}
2007-05-14 20:31:28 +00:00
if ( data - > length ! = MSG_SMB_SHARE_MODE_ENTRY_SIZE ) {
DEBUG ( 0 , ( " Got invalid msg len %d \n " , ( int ) data - > length ) ) ;
2005-09-30 17:13:37 +00:00
return ;
2001-10-20 21:59:34 +00:00
}
2006-01-12 22:17:54 +00:00
/* De-linearize incoming message. */
2007-05-14 20:31:28 +00:00
message_to_share_mode_entry ( & msg , ( char * ) data - > data ) ;
2006-01-12 22:17:54 +00:00
2011-12-02 15:03:05 +01:00
DEBUG ( 10 , ( " Got oplock break message from pid %s: %s/%llu \n " ,
server_id_str ( talloc_tos ( ) , & src ) ,
file_id_string_tos ( & msg . id ) ,
( unsigned long long ) msg . share_file_id ) ) ;
2001-10-20 21:59:34 +00:00
2010-10-03 17:22:09 +02:00
fsp = initial_break_processing ( sconn , msg . id , msg . share_file_id ) ;
2001-10-20 21:59:34 +00:00
2005-09-30 17:13:37 +00:00
if ( fsp = = NULL ) {
2010-01-19 16:51:33 +01:00
/* We hit a race here. Break messages are sent, and before we
2005-09-30 17:13:37 +00:00
* get to process this message , we have closed the file . Reply
* with ' ok , oplock broken ' */
DEBUG ( 3 , ( " Did not find fsp \n " ) ) ;
2006-01-12 22:17:54 +00:00
/* We just send the same message back. */
2007-05-14 20:31:28 +00:00
messaging_send_buf ( msg_ctx , src , MSG_SMB_BREAK_RESPONSE ,
( uint8 * ) data - > data ,
MSG_SMB_SHARE_MODE_ENTRY_SIZE ) ;
2005-09-30 17:13:37 +00:00
return ;
2001-10-20 21:59:34 +00:00
}
2005-09-30 17:13:37 +00:00
if ( fsp - > sent_oplock_break ! = NO_BREAK_SENT ) {
/* Remember we have to inform the requesting PID when the
* client replies */
2006-01-12 22:17:54 +00:00
msg . pid = src ;
ADD_TO_ARRAY ( NULL , struct share_mode_entry , msg ,
2005-09-30 17:13:37 +00:00
& fsp - > pending_break_messages ,
& fsp - > num_pending_break_messages ) ;
return ;
2001-10-20 21:59:34 +00:00
}
2006-01-12 22:17:54 +00:00
if ( EXCLUSIVE_OPLOCK_TYPE ( msg . op_type ) & &
2005-09-30 17:13:37 +00:00
! EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) ) {
2007-05-29 09:30:34 +00:00
DEBUG ( 3 , ( " Already downgraded oplock on %s: %s \n " ,
2007-09-10 10:56:07 +00:00
file_id_string_tos ( & fsp - > file_id ) ,
2009-07-10 14:50:37 -07:00
fsp_str_dbg ( fsp ) ) ) ;
2006-01-12 22:17:54 +00:00
/* We just send the same message back. */
2007-05-14 20:31:28 +00:00
messaging_send_buf ( msg_ctx , src , MSG_SMB_BREAK_RESPONSE ,
( uint8 * ) data - > data ,
MSG_SMB_SHARE_MODE_ENTRY_SIZE ) ;
2005-09-30 17:13:37 +00:00
return ;
2005-07-17 09:56:25 +00:00
}
2001-10-20 21:59:34 +00:00
2012-03-30 16:11:08 +02:00
use_kernel = lp_kernel_oplocks ( SNUM ( fsp - > conn ) ) & & koplocks ;
if ( ( global_client_caps & CAP_LEVEL_II_OPLOCKS ) & &
2006-05-30 18:17:37 +00:00
! ( msg . op_type & FORCE_OPLOCK_BREAK_TO_NONE ) & &
2012-03-30 16:11:08 +02:00
! ( use_kernel & & ! ( koplocks - > flags & KOPLOCKS_LEVEL2_SUPPORTED ) ) & &
2005-09-30 17:13:37 +00:00
lp_level2_oplocks ( SNUM ( fsp - > conn ) ) ) {
break_to_level2 = True ;
}
2001-10-20 21:59:34 +00:00
2010-04-07 19:00:44 -07:00
/* Need to wait before sending a break
message if we sent ourselves this message . */
2009-04-03 10:43:13 +02:00
if ( procid_is_me ( & src ) ) {
2005-09-30 17:13:37 +00:00
wait_before_sending_break ( ) ;
}
2001-10-20 21:59:34 +00:00
2010-06-09 19:12:02 -07:00
if ( sconn - > using_smb2 ) {
2010-04-09 19:26:34 -07:00
send_break_message_smb2 ( fsp , break_to_level2 ?
2010-04-07 19:00:44 -07:00
OPLOCKLEVEL_II : OPLOCKLEVEL_NONE ) ;
} else {
2010-04-09 19:26:34 -07:00
send_break_message_smb1 ( fsp , break_to_level2 ?
2010-04-07 19:00:44 -07:00
OPLOCKLEVEL_II : OPLOCKLEVEL_NONE ) ;
2003-07-16 21:06:21 +00:00
}
2003-07-17 00:58:14 +00:00
2006-01-27 23:30:30 +00:00
fsp - > sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT : BREAK_TO_NONE_SENT ;
2006-01-12 22:17:54 +00:00
msg . pid = src ;
ADD_TO_ARRAY ( NULL , struct share_mode_entry , msg ,
2005-09-30 17:13:37 +00:00
& fsp - > pending_break_messages ,
& fsp - > num_pending_break_messages ) ;
2001-10-20 21:59:34 +00:00
2006-01-27 23:30:30 +00:00
add_oplock_timeout_handler ( fsp ) ;
2005-09-30 17:13:37 +00:00
}
2001-10-20 21:59:34 +00:00
2006-01-27 23:30:30 +00:00
/*******************************************************************
This handles the kernel oplock break message .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-14 20:31:28 +00:00
static void process_kernel_oplock_break ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id src ,
DATA_BLOB * data )
2005-09-30 17:13:37 +00:00
{
2007-05-29 09:30:34 +00:00
struct file_id id ;
2006-01-12 22:17:54 +00:00
unsigned long file_id ;
2005-09-30 17:13:37 +00:00
files_struct * fsp ;
2011-12-13 13:18:47 +01:00
struct smbd_server_connection * sconn =
2011-12-14 09:50:24 +01:00
talloc_get_type_abort ( private_data ,
2011-12-13 13:18:47 +01:00
struct smbd_server_connection ) ;
2007-05-14 20:31:28 +00:00
if ( data - > data = = NULL ) {
2005-09-30 17:13:37 +00:00
DEBUG ( 0 , ( " Got NULL buffer \n " ) ) ;
return ;
2001-10-20 21:59:34 +00:00
}
2007-05-14 20:31:28 +00:00
if ( data - > length ! = MSG_SMB_KERNEL_BREAK_SIZE ) {
DEBUG ( 0 , ( " Got invalid msg len %d \n " , ( int ) data - > length ) ) ;
2005-09-30 17:13:37 +00:00
return ;
2001-10-20 21:59:34 +00:00
}
2006-01-12 22:17:54 +00:00
/* Pull the data from the message. */
2009-02-15 23:45:28 -08:00
pull_file_id_24 ( ( char * ) data - > data , & id ) ;
file_id = ( unsigned long ) IVAL ( data - > data , 24 ) ;
2001-10-20 21:59:34 +00:00
2009-04-03 10:42:43 +02:00
DEBUG ( 10 , ( " Got kernel oplock break message from pid %s: %s/%u \n " ,
2011-06-08 14:05:55 +10:00
server_id_str ( talloc_tos ( ) , & src ) , file_id_string_tos ( & id ) ,
2006-01-12 22:17:54 +00:00
( unsigned int ) file_id ) ) ;
2010-10-03 17:24:33 +02:00
fsp = initial_break_processing ( sconn , id , file_id ) ;
2001-10-20 21:59:34 +00:00
2005-09-30 17:13:37 +00:00
if ( fsp = = NULL ) {
DEBUG ( 3 , ( " Got a kernel oplock break message for a file "
" I don't know about \n " ) ) ;
return ;
2001-10-20 21:59:34 +00:00
}
2005-09-30 17:13:37 +00:00
if ( fsp - > sent_oplock_break ! = NO_BREAK_SENT ) {
/* This is ok, kernel oplocks come in completely async */
DEBUG ( 3 , ( " Got a kernel oplock request while waiting for a "
" break reply \n " ) ) ;
return ;
2001-10-20 21:59:34 +00:00
}
2010-06-09 19:12:02 -07:00
if ( sconn - > using_smb2 ) {
2010-04-09 19:26:34 -07:00
send_break_message_smb2 ( fsp , OPLOCKLEVEL_NONE ) ;
2010-04-07 19:00:44 -07:00
} else {
2010-04-09 19:26:34 -07:00
send_break_message_smb1 ( fsp , OPLOCKLEVEL_NONE ) ;
2001-10-20 21:59:34 +00:00
}
2005-09-30 17:13:37 +00:00
fsp - > sent_oplock_break = BREAK_TO_NONE_SENT ;
2006-01-27 23:30:30 +00:00
add_oplock_timeout_handler ( fsp ) ;
2005-09-30 17:13:37 +00:00
}
1998-08-17 13:11:34 +00:00
2005-09-30 17:13:37 +00:00
void reply_to_oplock_break_requests ( files_struct * fsp )
{
int i ;
2001-08-21 01:25:45 +00:00
2009-02-03 15:40:23 -08:00
/*
* If kernel oplocks already notifies smbds when oplocks are
* broken / removed , just return .
*/
if ( koplocks & &
( koplocks - > flags & KOPLOCKS_OPLOCK_BROKEN_NOTIFICATION ) ) {
return ;
}
2005-09-30 17:13:37 +00:00
for ( i = 0 ; i < fsp - > num_pending_break_messages ; i + + ) {
2006-01-12 22:17:54 +00:00
struct share_mode_entry * e = & fsp - > pending_break_messages [ i ] ;
char msg [ MSG_SMB_SHARE_MODE_ENTRY_SIZE ] ;
share_mode_entry_to_message ( msg , e ) ;
2010-07-04 18:34:31 +02:00
messaging_send_buf ( fsp - > conn - > sconn - > msg_ctx , e - > pid ,
2007-05-14 20:31:28 +00:00
MSG_SMB_BREAK_RESPONSE ,
( uint8 * ) msg ,
MSG_SMB_SHARE_MODE_ENTRY_SIZE ) ;
2001-10-20 21:59:34 +00:00
}
2005-09-30 17:13:37 +00:00
SAFE_FREE ( fsp - > pending_break_messages ) ;
fsp - > num_pending_break_messages = 0 ;
if ( fsp - > oplock_timeout ! = NULL ) {
2006-01-27 23:30:30 +00:00
/* Remove the timed event handler. */
2006-02-20 17:59:58 +00:00
TALLOC_FREE ( fsp - > oplock_timeout ) ;
2005-09-30 17:13:37 +00:00
fsp - > oplock_timeout = NULL ;
2001-10-20 21:59:34 +00:00
}
2005-09-30 17:13:37 +00:00
return ;
}
2001-10-20 21:59:34 +00:00
2007-05-14 20:31:28 +00:00
static void process_oplock_break_response ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id src ,
DATA_BLOB * data )
2005-09-30 17:13:37 +00:00
{
2006-01-12 22:17:54 +00:00
struct share_mode_entry msg ;
2011-12-13 13:18:47 +01:00
struct smbd_server_connection * sconn =
2011-12-14 09:50:24 +01:00
talloc_get_type_abort ( private_data ,
2011-12-13 13:18:47 +01:00
struct smbd_server_connection ) ;
2007-05-14 20:31:28 +00:00
if ( data - > data = = NULL ) {
2005-09-30 17:13:37 +00:00
DEBUG ( 0 , ( " Got NULL buffer \n " ) ) ;
return ;
2001-10-20 21:59:34 +00:00
}
2007-05-14 20:31:28 +00:00
if ( data - > length ! = MSG_SMB_SHARE_MODE_ENTRY_SIZE ) {
DEBUG ( 0 , ( " Got invalid msg len %u \n " ,
( unsigned int ) data - > length ) ) ;
2005-09-30 17:13:37 +00:00
return ;
2001-10-20 21:59:34 +00:00
}
2006-01-12 22:17:54 +00:00
/* De-linearize incoming message. */
2007-05-14 20:31:28 +00:00
message_to_share_mode_entry ( & msg , ( char * ) data - > data ) ;
2006-01-12 22:17:54 +00:00
2011-12-02 15:03:05 +01:00
DEBUG ( 10 , ( " Got oplock break response from pid %s: %s/%llu mid %llu \n " ,
server_id_str ( talloc_tos ( ) , & src ) ,
file_id_string_tos ( & msg . id ) ,
( unsigned long long ) msg . share_file_id ,
( unsigned long long ) msg . op_mid ) ) ;
2001-10-20 21:59:34 +00:00
2011-12-13 13:18:47 +01:00
schedule_deferred_open_message_smb ( sconn , msg . op_mid ) ;
1998-08-17 13:11:34 +00:00
}
2007-05-14 20:31:28 +00:00
static void process_open_retry_message ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id src ,
DATA_BLOB * data )
1998-08-17 13:11:34 +00:00
{
2006-01-12 22:17:54 +00:00
struct share_mode_entry msg ;
2011-12-13 13:18:47 +01:00
struct smbd_server_connection * sconn =
2011-12-14 09:50:24 +01:00
talloc_get_type_abort ( private_data ,
2011-12-13 13:18:47 +01:00
struct smbd_server_connection ) ;
2007-05-14 20:31:28 +00:00
if ( data - > data = = NULL ) {
2005-09-30 17:13:37 +00:00
DEBUG ( 0 , ( " Got NULL buffer \n " ) ) ;
return ;
2001-10-20 21:59:34 +00:00
}
1998-08-17 13:11:34 +00:00
2007-05-14 20:31:28 +00:00
if ( data - > length ! = MSG_SMB_SHARE_MODE_ENTRY_SIZE ) {
DEBUG ( 0 , ( " Got invalid msg len %d \n " , ( int ) data - > length ) ) ;
2005-09-30 17:13:37 +00:00
return ;
2005-01-26 20:01:21 +00:00
}
2006-01-12 22:17:54 +00:00
/* De-linearize incoming message. */
2007-05-14 20:31:28 +00:00
message_to_share_mode_entry ( & msg , ( char * ) data - > data ) ;
2005-01-26 20:01:21 +00:00
2010-04-12 21:40:28 -07:00
DEBUG ( 10 , ( " Got open retry msg from pid %s: %s mid %llu \n " ,
2011-06-08 14:05:55 +10:00
server_id_str ( talloc_tos ( ) , & src ) , file_id_string_tos ( & msg . id ) ,
2010-04-12 21:40:28 -07:00
( unsigned long long ) msg . op_mid ) ) ;
2006-01-12 22:17:54 +00:00
2011-12-13 13:18:47 +01:00
schedule_deferred_open_message_smb ( sconn , msg . op_mid ) ;
2005-01-26 20:01:21 +00:00
}
2012-01-13 13:26:41 +01:00
struct break_to_none_state {
struct smbd_server_connection * sconn ;
struct file_id id ;
} ;
static void do_break_to_none ( struct tevent_req * req ) ;
2000-11-16 00:59:18 +00:00
/****************************************************************************
This function is called on any file modification or lock request . If a file
2005-09-30 17:13:37 +00:00
is level 2 oplocked then it must tell all other level 2 holders to break to
none .
2000-11-16 00:59:18 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-03 11:56:35 -08:00
static void contend_level2_oplocks_begin_default ( files_struct * fsp ,
enum level2_contention_type type )
2000-11-16 00:59:18 +00:00
{
2012-01-13 13:26:41 +01:00
struct smbd_server_connection * sconn = fsp - > conn - > sconn ;
struct tevent_req * req ;
struct break_to_none_state * state ;
2000-11-16 00:59:18 +00:00
/*
* If this file is level II oplocked then we need
* to grab the shared memory lock and inform all
* other files with a level II lock that they need
* to flush their read caches . We keep the lock over
* the shared memory area whilst doing this .
*/
if ( ! LEVEL_II_OPLOCK_TYPE ( fsp - > oplock_type ) )
return ;
2012-01-13 13:26:41 +01:00
/*
* When we get here we might have a brlock entry locked . Also
* locking the share mode entry would violate the locking
* order . Breaking level2 oplocks to none is asynchronous
* anyway , so we postpone this into an immediate timed event .
*/
state = talloc ( sconn , struct break_to_none_state ) ;
if ( state = = NULL ) {
DEBUG ( 1 , ( " talloc failed \n " ) ) ;
return ;
}
state - > sconn = sconn ;
state - > id = fsp - > file_id ;
req = tevent_wakeup_send ( state , sconn - > ev_ctx , timeval_set ( 0 , 0 ) ) ;
if ( req = = NULL ) {
DEBUG ( 1 , ( " tevent_wakeup_send failed \n " ) ) ;
TALLOC_FREE ( state ) ;
2006-03-07 09:09:13 +00:00
return ;
2000-11-16 00:59:18 +00:00
}
2012-01-13 13:26:41 +01:00
tevent_req_set_callback ( req , do_break_to_none , state ) ;
return ;
}
static void do_break_to_none ( struct tevent_req * req )
{
struct break_to_none_state * state = tevent_req_callback_data (
req , struct break_to_none_state ) ;
bool ret ;
int i ;
struct share_mode_lock * lck ;
ret = tevent_wakeup_recv ( req ) ;
TALLOC_FREE ( req ) ;
if ( ! ret ) {
DEBUG ( 1 , ( " tevent_wakeup_recv failed \n " ) ) ;
goto done ;
}
2012-02-19 14:23:56 +01:00
lck = get_existing_share_mode_lock ( talloc_tos ( ) , state - > id ) ;
2012-01-13 13:26:41 +01:00
if ( lck = = NULL ) {
DEBUG ( 1 , ( " release_level_2_oplocks_on_change: failed to lock "
" share mode entry for file %s. \n " ,
file_id_string_tos ( & state - > id ) ) ) ;
goto done ;
}
2000-11-16 00:59:18 +00:00
2001-08-22 00:29:40 +00:00
DEBUG ( 10 , ( " release_level_2_oplocks_on_change: num_share_modes = %d \n " ,
2012-01-10 13:56:37 +01:00
lck - > data - > num_share_modes ) ) ;
2005-09-30 17:13:37 +00:00
2012-01-10 13:56:37 +01:00
for ( i = 0 ; i < lck - > data - > num_share_modes ; i + + ) {
struct share_mode_entry * share_entry = & lck - > data - > share_modes [ i ] ;
2006-01-12 22:17:54 +00:00
char msg [ MSG_SMB_SHARE_MODE_ENTRY_SIZE ] ;
2000-11-16 00:59:18 +00:00
2006-01-27 19:54:39 +00:00
if ( ! is_valid_share_mode_entry ( share_entry ) ) {
continue ;
}
2000-11-16 00:59:18 +00:00
/*
2005-09-30 17:13:37 +00:00
* As there could have been multiple writes waiting at the
* lock_share_entry gate we may not be the first to
* enter . Hence the state of the op_types in the share mode
2006-01-27 23:30:30 +00:00
* entries may be partly NO_OPLOCK and partly LEVEL_II or FAKE_LEVEL_II
2005-09-30 17:13:37 +00:00
* oplock . It will do no harm to re - send break messages to
* those smbd ' s that are still waiting their turn to remove
* their LEVEL_II state , and also no harm to ignore existing
* NO_OPLOCK states . JRA .
2000-11-16 00:59:18 +00:00
*/
2005-09-30 17:13:37 +00:00
DEBUG ( 10 , ( " release_level_2_oplocks_on_change: "
" share_entry[%i]->op_type == %d \n " ,
i , share_entry - > op_type ) ) ;
2001-08-22 00:29:40 +00:00
2006-01-27 23:30:30 +00:00
if ( share_entry - > op_type = = NO_OPLOCK ) {
2000-11-16 00:59:18 +00:00
continue ;
2005-09-30 17:13:37 +00:00
}
2000-11-16 00:59:18 +00:00
/* Paranoia .... */
if ( EXCLUSIVE_OPLOCK_TYPE ( share_entry - > op_type ) ) {
2005-09-30 17:13:37 +00:00
DEBUG ( 0 , ( " release_level_2_oplocks_on_change: PANIC. "
" share mode entry %d is an exlusive "
" oplock ! \n " , i ) ) ;
2006-02-20 17:59:58 +00:00
TALLOC_FREE ( lck ) ;
2000-11-16 00:59:18 +00:00
abort ( ) ;
}
2006-01-12 22:17:54 +00:00
share_mode_entry_to_message ( msg , share_entry ) ;
2008-12-18 13:27:42 -08:00
/*
* Deal with a race condition when breaking level2
* oplocks . Don ' t send all the messages and release
* the lock , this allows someone else to come in and
* get a level2 lock before any of the messages are
* processed , and thus miss getting a break message .
* Ensure at least one entry ( the one we ' re breaking )
* is processed immediately under the lock and becomes
* set as NO_OPLOCK to stop any waiter getting a level2 .
* Bugid # 5980.
*/
if ( procid_is_me ( & share_entry - > pid ) ) {
2011-01-31 14:52:11 -08:00
struct files_struct * cur_fsp =
2012-01-13 13:26:41 +01:00
initial_break_processing ( state - > sconn ,
2011-01-31 14:52:11 -08:00
share_entry - > id ,
share_entry - > share_file_id ) ;
2009-04-02 18:33:30 -07:00
wait_before_sending_break ( ) ;
2011-01-31 14:52:11 -08:00
if ( cur_fsp ! = NULL ) {
break_level2_to_none_async ( cur_fsp ) ;
} else {
DEBUG ( 3 , ( " release_level_2_oplocks_on_change: "
" Did not find fsp, ignoring \n " ) ) ;
}
2008-12-18 13:27:42 -08:00
} else {
2012-01-13 13:26:41 +01:00
messaging_send_buf ( state - > sconn - > msg_ctx ,
2008-12-18 13:27:42 -08:00
share_entry - > pid ,
MSG_SMB_ASYNC_LEVEL2_BREAK ,
( uint8 * ) msg ,
MSG_SMB_SHARE_MODE_ENTRY_SIZE ) ;
}
2004-06-08 16:14:31 +00:00
}
2006-01-27 23:30:30 +00:00
/* We let the message receivers handle removing the oplock state
in the share mode lock db . */
2006-02-20 17:59:58 +00:00
TALLOC_FREE ( lck ) ;
2012-01-13 13:26:41 +01:00
done :
TALLOC_FREE ( state ) ;
return ;
2004-06-08 16:14:31 +00:00
}
2011-05-31 13:18:37 +10:00
void smbd_contend_level2_oplocks_begin ( files_struct * fsp ,
2009-02-03 11:56:35 -08:00
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 ) ;
}
2011-05-31 13:18:37 +10:00
void smbd_contend_level2_oplocks_end ( files_struct * fsp ,
2009-02-03 11:56:35 -08:00
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 ) ;
}
}
2006-01-12 22:17:54 +00:00
/****************************************************************************
Linearize a share mode entry struct to an internal oplock break message .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-27 11:23:59 -07:00
void share_mode_entry_to_message ( char * msg , const struct share_mode_entry * e )
2006-01-12 22:17:54 +00:00
{
2010-04-12 21:40:28 -07:00
SIVAL ( msg , OP_BREAK_MSG_PID_OFFSET , ( uint32 ) e - > pid . pid ) ;
SBVAL ( msg , OP_BREAK_MSG_MID_OFFSET , e - > op_mid ) ;
SSVAL ( msg , OP_BREAK_MSG_OP_TYPE_OFFSET , e - > op_type ) ;
SIVAL ( msg , OP_BREAK_MSG_ACCESS_MASK_OFFSET , e - > access_mask ) ;
SIVAL ( msg , OP_BREAK_MSG_SHARE_ACCESS_OFFSET , e - > share_access ) ;
SIVAL ( msg , OP_BREAK_MSG_PRIV_OFFSET , e - > private_options ) ;
SIVAL ( msg , OP_BREAK_MSG_TIME_SEC_OFFSET , ( uint32_t ) e - > time . tv_sec ) ;
SIVAL ( msg , OP_BREAK_MSG_TIME_USEC_OFFSET , ( uint32_t ) e - > time . tv_usec ) ;
push_file_id_24 ( msg + OP_BREAK_MSG_DEV_OFFSET , & e - > id ) ;
SIVAL ( msg , OP_BREAK_MSG_FILE_ID_OFFSET , e - > share_file_id ) ;
SIVAL ( msg , OP_BREAK_MSG_UID_OFFSET , e - > uid ) ;
SSVAL ( msg , OP_BREAK_MSG_FLAGS_OFFSET , e - > flags ) ;
2011-01-25 14:01:52 -08:00
SIVAL ( msg , OP_BREAK_MSG_NAME_HASH_OFFSET , e - > name_hash ) ;
2010-04-12 21:40:28 -07:00
SIVAL ( msg , OP_BREAK_MSG_VNN_OFFSET , e - > pid . vnn ) ;
2006-01-12 22:17:54 +00:00
}
/****************************************************************************
De - linearize an internal oplock break message to a share mode entry struct .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void message_to_share_mode_entry ( struct share_mode_entry * e , char * msg )
{
2010-04-12 21:40:28 -07:00
e - > pid . pid = ( pid_t ) IVAL ( msg , OP_BREAK_MSG_PID_OFFSET ) ;
e - > op_mid = BVAL ( msg , OP_BREAK_MSG_MID_OFFSET ) ;
e - > op_type = SVAL ( msg , OP_BREAK_MSG_OP_TYPE_OFFSET ) ;
e - > access_mask = IVAL ( msg , OP_BREAK_MSG_ACCESS_MASK_OFFSET ) ;
e - > share_access = IVAL ( msg , OP_BREAK_MSG_SHARE_ACCESS_OFFSET ) ;
e - > private_options = IVAL ( msg , OP_BREAK_MSG_PRIV_OFFSET ) ;
e - > time . tv_sec = ( time_t ) IVAL ( msg , OP_BREAK_MSG_TIME_SEC_OFFSET ) ;
e - > time . tv_usec = ( int ) IVAL ( msg , OP_BREAK_MSG_TIME_USEC_OFFSET ) ;
pull_file_id_24 ( msg + OP_BREAK_MSG_DEV_OFFSET , & e - > id ) ;
e - > share_file_id = ( unsigned long ) IVAL ( msg , OP_BREAK_MSG_FILE_ID_OFFSET ) ;
e - > uid = ( uint32 ) IVAL ( msg , OP_BREAK_MSG_UID_OFFSET ) ;
e - > flags = ( uint16 ) SVAL ( msg , OP_BREAK_MSG_FLAGS_OFFSET ) ;
2011-01-25 14:01:52 -08:00
e - > name_hash = IVAL ( msg , OP_BREAK_MSG_NAME_HASH_OFFSET ) ;
2010-04-12 21:40:28 -07:00
e - > pid . vnn = IVAL ( msg , OP_BREAK_MSG_VNN_OFFSET ) ;
2006-01-12 22:17:54 +00:00
}
2004-06-08 16:14:31 +00:00
/****************************************************************************
Setup oplocks for this process .
1998-09-23 01:48:45 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-20 21:59:34 +00:00
2011-12-13 13:13:53 +01:00
bool init_oplocks ( struct smbd_server_connection * sconn )
1998-09-18 17:50:18 +00:00
{
2006-07-19 10:42:50 +00:00
DEBUG ( 3 , ( " init_oplocks: initializing messages. \n " ) ) ;
2000-06-10 13:38:07 +00:00
2011-12-13 13:18:47 +01:00
messaging_register ( sconn - > msg_ctx , sconn , MSG_SMB_BREAK_REQUEST ,
2007-05-14 20:31:28 +00:00
process_oplock_break_message ) ;
2011-12-13 13:18:47 +01:00
messaging_register ( sconn - > msg_ctx , sconn , MSG_SMB_ASYNC_LEVEL2_BREAK ,
2007-05-14 20:31:28 +00:00
process_oplock_async_level2_break_message ) ;
2011-12-13 13:18:47 +01:00
messaging_register ( sconn - > msg_ctx , sconn , MSG_SMB_BREAK_RESPONSE ,
2007-05-14 20:31:28 +00:00
process_oplock_break_response ) ;
2011-12-13 13:18:47 +01:00
messaging_register ( sconn - > msg_ctx , sconn , MSG_SMB_KERNEL_BREAK ,
2007-05-14 20:31:28 +00:00
process_kernel_oplock_break ) ;
2011-12-13 13:18:47 +01:00
messaging_register ( sconn - > msg_ctx , sconn , MSG_SMB_OPEN_RETRY ,
2007-05-14 20:31:28 +00:00
process_open_retry_message ) ;
2000-06-10 13:38:07 +00:00
2012-03-30 15:51:25 +02:00
return true ;
}
void init_kernel_oplocks ( struct smbd_server_connection * sconn )
{
/* only initialize once */
if ( koplocks = = NULL ) {
2000-06-10 13:38:07 +00:00
# if HAVE_KERNEL_OPLOCKS_IRIX
2011-12-13 13:38:41 +01:00
koplocks = irix_init_kernel_oplocks ( sconn ) ;
2000-06-11 05:57:58 +00:00
# elif HAVE_KERNEL_OPLOCKS_LINUX
2011-12-13 13:38:41 +01:00
koplocks = linux_init_kernel_oplocks ( sconn ) ;
2009-01-27 16:13:35 -08:00
# elif HAVE_ONEFS
2010-10-07 22:01:28 +02:00
# error Isilon, please check if the NULL context is okay here. Thanks!
2011-12-13 13:38:41 +01:00
koplocks = onefs_init_kernel_oplocks ( sconn ) ;
2000-06-10 13:38:07 +00:00
# endif
}
1998-09-18 17:50:18 +00:00
}