2001-03-11 03:32:10 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-06-10 18:29:31 +04:00
IRIX kernel oplock processing
2000-06-10 17:38:07 +04:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
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 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-06-10 17:38:07 +04:00
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-06-10 17:38:07 +04:00
*/
2006-05-05 06:06:37 +04:00
# define DBGC_CLASS DBGC_LOCKING
2000-06-10 17:38:07 +04:00
# include "includes.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2000-06-10 17:38:07 +04:00
2000-06-11 09:57:58 +04:00
# if HAVE_KERNEL_OPLOCKS_IRIX
2000-06-10 17:38:07 +04:00
2009-01-09 16:02:18 +03:00
struct irix_oplocks_context {
struct kernel_oplocks * ctx ;
int write_fd ;
int read_fd ;
struct fd_event * read_fde ;
bool pending ;
} ;
2000-06-10 17:38:07 +04:00
/****************************************************************************
2001-10-21 01:59:34 +04:00
Test to see if IRIX kernel oplocks work .
2000-06-10 17:38:07 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-21 01:59:34 +04:00
2007-10-19 04:40:25 +04:00
static bool irix_oplocks_available ( void )
2000-06-10 17:38:07 +04:00
{
int fd ;
int pfd [ 2 ] ;
2007-09-14 05:07:57 +04:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
char * tmpname = NULL ;
2000-06-10 17:38:07 +04:00
2006-03-21 05:56:49 +03:00
set_effective_capability ( KERNEL_OPLOCK_CAPABILITY ) ;
2000-06-10 17:38:07 +04:00
2007-09-14 05:07:57 +04:00
tmpname = talloc_asprintf ( ctx ,
" %s/koplock.%d " ,
lp_lockdir ( ) ,
( int ) sys_getpid ( ) ) ;
if ( ! tmpname ) {
TALLOC_FREE ( ctx ) ;
return False ;
}
2000-06-10 17:38:07 +04:00
if ( pipe ( pfd ) ! = 0 ) {
2007-01-16 18:50:25 +03:00
DEBUG ( 0 , ( " check_kernel_oplocks: Unable to create pipe. Error "
" was %s \n " ,
2000-06-10 17:38:07 +04:00
strerror ( errno ) ) ) ;
2007-09-14 05:07:57 +04:00
TALLOC_FREE ( ctx ) ;
2000-06-10 17:38:07 +04:00
return False ;
}
if ( ( fd = sys_open ( tmpname , O_RDWR | O_CREAT | O_EXCL | O_TRUNC , 0600 ) ) < 0 ) {
2007-01-16 18:50:25 +03:00
DEBUG ( 0 , ( " check_kernel_oplocks: Unable to open temp test file "
" %s. Error was %s \n " ,
2000-06-10 17:38:07 +04:00
tmpname , strerror ( errno ) ) ) ;
unlink ( tmpname ) ;
close ( pfd [ 0 ] ) ;
close ( pfd [ 1 ] ) ;
2007-09-14 05:07:57 +04:00
TALLOC_FREE ( ctx ) ;
2000-06-10 17:38:07 +04:00
return False ;
}
unlink ( tmpname ) ;
2007-09-14 05:07:57 +04:00
TALLOC_FREE ( ctx ) ;
2002-07-15 14:35:28 +04:00
if ( sys_fcntl_long ( fd , F_OPLKREG , pfd [ 1 ] ) = = - 1 ) {
2007-01-16 18:50:25 +03:00
DEBUG ( 0 , ( " check_kernel_oplocks: Kernel oplocks are not "
" available on this machine. Disabling kernel oplock "
" support. \n " ) ) ;
2000-06-10 17:38:07 +04:00
close ( pfd [ 0 ] ) ;
close ( pfd [ 1 ] ) ;
close ( fd ) ;
return False ;
}
2002-07-15 14:35:28 +04:00
if ( sys_fcntl_long ( fd , F_OPLKACK , OP_REVOKE ) < 0 ) {
2007-01-16 18:50:25 +03:00
DEBUG ( 0 , ( " check_kernel_oplocks: Error when removing kernel "
" oplock. Error was %s. Disabling kernel oplock "
" support. \n " , strerror ( errno ) ) ) ;
2000-06-10 17:38:07 +04:00
close ( pfd [ 0 ] ) ;
close ( pfd [ 1 ] ) ;
close ( fd ) ;
return False ;
}
close ( pfd [ 0 ] ) ;
close ( pfd [ 1 ] ) ;
close ( fd ) ;
return True ;
}
2009-02-16 10:38:53 +03:00
/*
* This is bad because the file_id should always be created through the vfs
* layer ! Unfortunately , a conn struct isn ' t available here .
*/
static struct file_id file_id_create_dev ( SMB_DEV_T dev , SMB_INO_T inode )
{
struct file_id key ;
/* the ZERO_STRUCT ensures padding doesn't break using the key as a
* blob */
ZERO_STRUCT ( key ) ;
key . devid = dev ;
key . inode = inode ;
return key ;
}
2000-06-10 17:38:07 +04:00
/****************************************************************************
* Deal with the IRIX kernel < - - > smbd
* oplock break protocol .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-21 01:59:34 +04:00
2009-01-09 16:02:18 +03:00
static files_struct * irix_oplock_receive_message ( struct kernel_oplocks * _ctx )
2000-06-10 17:38:07 +04:00
{
2009-01-09 16:02:18 +03:00
struct irix_oplocks_context * ctx = talloc_get_type ( _ctx - > private_data ,
struct irix_oplocks_context ) ;
2001-10-21 01:59:34 +04:00
oplock_stat_t os ;
char dummy ;
2007-08-07 18:06:27 +04:00
struct file_id fileid ;
2001-10-21 01:59:34 +04:00
files_struct * fsp ;
2009-01-09 16:02:18 +03:00
/*
* TODO : is it correct to assume we only get one
* oplock break , for each byte we read from the pipe ?
*/
ctx - > pending = false ;
2006-02-15 02:00:39 +03:00
2001-10-21 01:59:34 +04:00
/*
* Read one byte of zero to clear the
* kernel break notify message .
*/
2009-01-09 16:02:18 +03:00
if ( read ( ctx - > read_fd , & dummy , 1 ) ! = 1 ) {
2005-10-01 14:00:07 +04:00
DEBUG ( 0 , ( " irix_oplock_receive_message: read of kernel "
" notification failed. Error was %s. \n " ,
strerror ( errno ) ) ) ;
2005-09-30 21:13:37 +04:00
return NULL ;
2001-10-21 01:59:34 +04:00
}
/*
* Do a query to get the
* device and inode of the file that has the break
* request outstanding .
*/
2009-01-09 16:02:18 +03:00
if ( sys_fcntl_ptr ( ctx - > read_fd , F_OPLKSTAT , & os ) < 0 ) {
2005-10-01 14:00:07 +04:00
DEBUG ( 0 , ( " irix_oplock_receive_message: fcntl of kernel "
" notification failed. Error was %s. \n " ,
strerror ( errno ) ) ) ;
2001-10-21 01:59:34 +04:00
if ( errno = = EAGAIN ) {
/*
* Duplicate kernel break message - ignore .
*/
2005-10-01 14:00:07 +04:00
return NULL ;
2001-10-21 01:59:34 +04:00
}
2005-09-30 21:13:37 +04:00
return NULL ;
2001-10-21 01:59:34 +04:00
}
/*
* We only have device and inode info here - we have to guess that this
* is the first fsp open with this dev , ino pair .
2007-08-07 18:06:27 +04:00
*
* NOTE : this doesn ' t work if any VFS modules overloads
* the file_id_create ( ) hook !
2001-10-21 01:59:34 +04:00
*/
2007-08-07 18:06:27 +04:00
fileid = file_id_create_dev ( ( SMB_DEV_T ) os . os_dev ,
( SMB_INO_T ) os . os_ino ) ;
if ( ( fsp = file_find_di_first ( fileid ) ) = = NULL ) {
2005-10-01 14:00:07 +04:00
DEBUG ( 0 , ( " irix_oplock_receive_message: unable to find open "
" file with dev = %x, inode = %.0f \n " ,
( unsigned int ) os . os_dev , ( double ) os . os_ino ) ) ;
return NULL ;
2001-10-21 01:59:34 +04:00
}
2000-06-10 17:38:07 +04:00
2005-10-01 14:00:07 +04:00
DEBUG ( 5 , ( " irix_oplock_receive_message: kernel oplock break request "
2007-05-29 13:30:34 +04:00
" received for file_id %s gen_id = %ul " ,
2007-09-10 14:56:07 +04:00
file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 13:30:34 +04:00
fsp - > fh - > gen_id ) ) ;
2005-09-30 21:13:37 +04:00
return fsp ;
2000-06-10 17:38:07 +04:00
}
/****************************************************************************
Attempt to set an kernel oplock on a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-21 01:59:34 +04:00
2009-01-09 16:02:18 +03:00
static bool irix_set_kernel_oplock ( struct kernel_oplocks * _ctx ,
files_struct * fsp , int oplock_type )
2000-06-10 17:38:07 +04:00
{
2009-01-09 16:02:18 +03:00
struct irix_oplocks_context * ctx = talloc_get_type ( _ctx - > private_data ,
struct irix_oplocks_context ) ;
if ( sys_fcntl_long ( fsp - > fh - > fd , F_OPLKREG , ctx - > write_fd ) = = - 1 ) {
2000-06-10 17:38:07 +04:00
if ( errno ! = EAGAIN ) {
2007-01-16 18:50:25 +03:00
DEBUG ( 0 , ( " irix_set_kernel_oplock: Unable to get "
2007-05-29 13:30:34 +04:00
" kernel oplock on file %s, file_id %s "
" gen_id = %ul. Error was %s \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) ,
file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 13:30:34 +04:00
fsp - > fh - > gen_id ,
2000-06-10 17:38:07 +04:00
strerror ( errno ) ) ) ;
} else {
2007-01-16 18:50:25 +03:00
DEBUG ( 5 , ( " irix_set_kernel_oplock: Refused oplock on "
2008-07-02 02:39:41 +04:00
" file %s, fd = %d, file_id = %s, "
2007-05-29 13:30:34 +04:00
" gen_id = %ul. Another process had the file "
2007-01-16 18:50:25 +03:00
" open. \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , fsp - > fh - > fd ,
2007-09-10 14:56:07 +04:00
file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 13:30:34 +04:00
fsp - > fh - > gen_id ) ) ;
2000-06-10 17:38:07 +04:00
}
return False ;
}
2007-05-29 13:30:34 +04:00
DEBUG ( 10 , ( " irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
" gen_id = %ul \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 13:30:34 +04:00
fsp - > fh - > gen_id ) ) ;
2000-06-10 17:38:07 +04:00
return True ;
}
/****************************************************************************
Release a kernel oplock on a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-21 01:59:34 +04:00
2009-01-09 16:02:18 +03:00
static void irix_release_kernel_oplock ( struct kernel_oplocks * _ctx ,
2009-01-10 00:07:58 +03:00
files_struct * fsp , int oplock_type )
2000-06-10 17:38:07 +04:00
{
if ( DEBUGLVL ( 10 ) ) {
/*
* Check and print out the current kernel
* oplock state of this file .
*/
2005-07-08 11:54:28 +04:00
int state = sys_fcntl_long ( fsp - > fh - > fd , F_OPLKACK , - 1 ) ;
2007-05-29 13:30:34 +04:00
dbgtext ( " irix_release_kernel_oplock: file %s, file_id = %s "
" gen_id = %ul, has kernel oplock state "
2009-07-11 01:50:37 +04:00
" of %x. \n " , fsp_str_dbg ( fsp ) ,
file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 13:30:34 +04:00
fsp - > fh - > gen_id , state ) ;
2000-06-10 17:38:07 +04:00
}
/*
* Remove the kernel oplock on this file .
*/
2005-07-08 11:54:28 +04:00
if ( sys_fcntl_long ( fsp - > fh - > fd , F_OPLKACK , OP_REVOKE ) < 0 ) {
2000-06-10 17:38:07 +04:00
if ( DEBUGLVL ( 0 ) ) {
2007-01-16 18:50:25 +03:00
dbgtext ( " irix_release_kernel_oplock: Error when "
" removing kernel oplock on file " ) ;
2007-05-29 13:30:34 +04:00
dbgtext ( " %s, file_id = %s gen_id = %ul. "
2007-01-16 18:50:25 +03:00
" Error was %s \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) ,
file_id_string_tos ( & fsp - > file_id ) ,
2007-05-29 13:30:34 +04:00
fsp - > fh - > gen_id ,
2007-01-16 18:50:25 +03:00
strerror ( errno ) ) ;
2000-06-10 17:38:07 +04:00
}
}
}
2009-01-09 16:02:18 +03:00
static void irix_oplocks_read_fde_handler ( struct event_context * ev ,
struct fd_event * fde ,
uint16_t flags ,
void * private_data )
{
struct irix_oplocks_context * ctx = talloc_get_type ( private_data ,
struct irix_oplocks_context ) ;
2009-01-23 12:08:44 +03:00
files_struct * fsp ;
2006-02-15 04:05:06 +03:00
2009-01-23 12:08:44 +03:00
fsp = irix_oplock_receive_message ( ctx - > ctx ) ;
break_kernel_oplock ( smbd_messaging_context ( ) , fsp ) ;
2000-06-10 17:38:07 +04:00
}
/****************************************************************************
2001-10-21 01:59:34 +04:00
Setup kernel oplocks .
2000-06-10 17:38:07 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-21 01:59:34 +04:00
2009-01-09 16:02:18 +03:00
static const struct kernel_oplocks_ops irix_koplocks = {
2009-02-03 22:56:35 +03:00
. set_oplock = irix_set_kernel_oplock ,
. release_oplock = irix_release_kernel_oplock ,
. contend_level2_oplocks_begin = NULL ,
. contend_level2_oplocks_end = NULL ,
2009-01-09 16:02:18 +03:00
} ;
struct kernel_oplocks * irix_init_kernel_oplocks ( TALLOC_CTX * mem_ctx )
2000-06-10 17:38:07 +04:00
{
2009-01-09 16:02:18 +03:00
struct kernel_oplocks * _ctx ;
struct irix_oplocks_context * ctx ;
2000-06-10 17:38:07 +04:00
int pfd [ 2 ] ;
2001-10-21 01:59:34 +04:00
if ( ! irix_oplocks_available ( ) )
return NULL ;
2000-06-10 17:38:07 +04:00
2009-01-09 16:02:18 +03:00
_ctx = talloc_zero ( mem_ctx , struct kernel_oplocks ) ;
if ( ! _ctx ) {
return NULL ;
}
ctx = talloc_zero ( _ctx , struct irix_oplocks_context ) ;
if ( ! ctx ) {
talloc_free ( _ctx ) ;
return NULL ;
}
_ctx - > ops = & irix_koplocks ;
_ctx - > private_data = ctx ;
ctx - > ctx = _ctx ;
2000-06-10 17:38:07 +04:00
if ( pipe ( pfd ) ! = 0 ) {
2009-01-09 16:02:18 +03:00
talloc_free ( _ctx ) ;
2007-01-16 18:50:25 +03:00
DEBUG ( 0 , ( " setup_kernel_oplock_pipe: Unable to create pipe. "
" Error was %s \n " , strerror ( errno ) ) ) ;
2000-06-10 17:38:07 +04:00
return False ;
}
2009-01-09 16:02:18 +03:00
ctx - > read_fd = pfd [ 0 ] ;
ctx - > write_fd = pfd [ 1 ] ;
2000-06-10 17:38:07 +04:00
2009-01-09 16:02:18 +03:00
ctx - > read_fde = event_add_fd ( smbd_event_context ( ) ,
ctx ,
ctx - > read_fd ,
EVENT_FD_READ ,
irix_oplocks_read_fde_handler ,
ctx ) ;
return _ctx ;
2000-06-10 17:38:07 +04:00
}
# else
2006-12-12 23:15:47 +03:00
void oplock_irix_dummy ( void ) ;
2000-06-10 17:38:07 +04:00
void oplock_irix_dummy ( void ) { }
# endif /* HAVE_KERNEL_OPLOCKS_IRIX */