2012-03-11 03:01:51 +04:00
/*
2007-01-31 15:24:59 +03:00
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 2006
2012-04-04 16:51:43 +04:00
Copyright ( C ) Volker Lendecke 2012
2009-04-09 17:51:35 +04:00
2007-01-31 15:24:59 +03: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 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-01-31 15:24:59 +03:00
( at your option ) any later version .
2009-04-09 17:51:35 +04:00
2007-01-31 15:24:59 +03: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 .
2009-04-09 17:51:35 +04:00
2007-01-31 15:24:59 +03:00
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/>.
2007-01-31 15:24:59 +03:00
*/
/*
this is the change notify database . It implements mechanisms for
storing current change notify waiters in a tdb , and checking if a
given event matches any of the stored notify waiiters .
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2007-01-31 15:24:59 +03:00
# include "librpc/gen_ndr/ndr_notify.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-07-06 18:40:21 +04:00
# include "dbwrap/dbwrap_open.h"
2012-04-04 16:51:43 +04:00
# include "dbwrap/dbwrap_tdb.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2012-03-11 00:33:11 +04:00
# include "lib/tdb_wrap/tdb_wrap.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2011-10-12 16:01:08 +04:00
# include "lib/param/param.h"
2012-04-04 16:51:43 +04:00
# include "lib/dbwrap/dbwrap_cache.h"
# include "ctdb_srvids.h"
# include "ctdbd_conn.h"
# include "ctdb_conn.h"
# include "lib/util/tevent_unix.h"
2007-01-31 15:24:59 +03:00
struct notify_list {
struct notify_list * next , * prev ;
2012-04-04 16:51:43 +04:00
const char * path ;
2007-01-31 15:24:59 +03:00
void ( * callback ) ( void * , const struct notify_event * ) ;
2012-04-04 16:51:43 +04:00
void * private_data ;
2007-01-31 15:24:59 +03:00
} ;
2012-04-04 16:51:43 +04:00
struct notify_context {
struct messaging_context * msg ;
struct notify_list * list ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
/*
* The notify database is split up into two databases : One
* relatively static index db and the real notify db with the
* volatile entries .
*/
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
/*
* " db_notify " is indexed by pathname . Per record it stores an
* array of notify_db_entry structs . These represent the
* notify records as requested by the smb client . This
* database is always held locally , it is never clustered .
*/
struct db_context * db_notify ;
2007-02-02 14:34:16 +03:00
2012-04-04 16:51:43 +04:00
/*
* " db_index " is indexed by pathname . The records are an array
* of VNNs which have any interest in notifies for this path
* name .
*
* In the non - clustered case this database is cached in RAM by
* means of db_cache_open , which maintains a cache per
* process . Cache consistency is maintained by the tdb
* sequence number .
*
* In the clustered case right now we can not use the tdb
* sequence number , but by means of read only records we
* should be able to avoid a lot of full migrations .
*
* In both cases , it is important to keep the update
* operations to db_index to a minimum . This is achieved by
* delayed deletion . When a db_notify is initially created ,
* the db_index record is also created . When more notifies are
* add for a path , then only the db_notify record needs to be
* modified , the db_index record is not touched . When the last
* entry from the db_notify record is deleted , the db_index
* record is not immediately deleted . Instead , the db_notify
* record is replaced with a current timestamp . A regular
* cleanup process will delete all db_index records that are
* older than a minute .
*/
struct db_context * db_index ;
} ;
2007-02-02 14:34:16 +03:00
2012-04-04 16:51:43 +04:00
static void notify_trigger_local ( struct notify_context * notify ,
uint32_t action , uint32_t filter ,
const char * path , size_t path_len ,
bool recursive ) ;
static NTSTATUS notify_send ( struct notify_context * notify ,
struct server_id * pid ,
const char * path , uint32_t action ,
void * private_data ) ;
static NTSTATUS notify_add_entry ( struct db_record * rec ,
const struct notify_db_entry * e ,
bool * p_add_idx ) ;
static NTSTATUS notify_add_idx ( struct db_record * rec , uint32_t vnn ) ;
static NTSTATUS notify_del_entry ( struct db_record * rec ,
const struct server_id * pid ,
void * private_data ) ;
static NTSTATUS notify_del_idx ( struct db_record * rec , uint32_t vnn ) ;
static int notify_context_destructor ( struct notify_context * notify ) ;
static void notify_handler ( struct messaging_context * msg_ctx ,
void * private_data , uint32_t msg_type ,
struct server_id server_id , DATA_BLOB * data ) ;
2007-01-31 15:24:59 +03:00
2012-03-14 13:31:13 +04:00
struct notify_context * notify_init ( TALLOC_CTX * mem_ctx ,
2012-04-04 16:51:43 +04:00
struct messaging_context * msg ,
2012-03-21 14:59:27 +04:00
struct event_context * ev )
2007-01-31 15:24:59 +03:00
{
2012-04-16 07:37:39 +04:00
struct loadparm_context * lp_ctx ;
2007-01-31 15:24:59 +03:00
struct notify_context * notify ;
notify = talloc ( mem_ctx , struct notify_context ) ;
if ( notify = = NULL ) {
2012-04-04 16:51:43 +04:00
goto fail ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
notify - > msg = msg ;
notify - > list = NULL ;
2007-01-31 15:24:59 +03:00
2012-04-16 07:37:39 +04:00
lp_ctx = loadparm_init_s3 ( notify , loadparm_s3_context ( ) ) ;
2012-04-04 16:51:43 +04:00
notify - > db_notify = db_open_tdb (
2012-04-16 07:37:39 +04:00
notify , lp_ctx , lock_path ( " notify.tdb " ) ,
2012-04-04 16:51:43 +04:00
0 , TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ,
O_RDWR | O_CREAT , 0644 , DBWRAP_LOCK_ORDER_2 ) ;
2012-04-16 07:37:39 +04:00
talloc_unlink ( notify , lp_ctx ) ;
2012-04-04 16:51:43 +04:00
if ( notify - > db_notify = = NULL ) {
goto fail ;
}
notify - > db_index = db_open (
notify , lock_path ( " notify_index.tdb " ) ,
0 , TDB_SEQNUM | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ,
O_RDWR | O_CREAT , 0644 , DBWRAP_LOCK_ORDER_3 ) ;
if ( notify - > db_index = = NULL ) {
goto fail ;
}
if ( ! lp_clustering ( ) ) {
notify - > db_index = db_open_cache ( notify , notify - > db_index ) ;
if ( notify - > db_index = = NULL ) {
goto fail ;
}
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
if ( notify - > msg ! = NULL ) {
NTSTATUS status ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
status = messaging_register ( notify - > msg , notify ,
MSG_PVFS_NOTIFY , notify_handler ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " messaging_register returned %s \n " ,
nt_errstr ( status ) ) ) ;
goto fail ;
}
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
talloc_set_destructor ( notify , notify_context_destructor ) ;
2007-01-31 15:24:59 +03:00
return notify ;
2012-04-04 16:51:43 +04:00
fail :
TALLOC_FREE ( notify ) ;
return NULL ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
static int notify_context_destructor ( struct notify_context * notify )
2010-03-25 18:01:54 +03:00
{
2012-04-04 16:51:43 +04:00
DEBUG ( 10 , ( " notify_context_destructor called \n " ) ) ;
2010-03-25 18:01:54 +03:00
2012-04-04 16:51:43 +04:00
if ( notify - > msg ! = NULL ) {
messaging_deregister ( notify - > msg , MSG_PVFS_NOTIFY , notify ) ;
2010-03-25 18:01:54 +03:00
}
2012-04-04 16:51:43 +04:00
while ( notify - > list ! = NULL ) {
DEBUG ( 10 , ( " Removing private_data=%p \n " ,
notify - > list - > private_data ) ) ;
notify_remove ( notify , notify - > list - > private_data ) ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
return 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
NTSTATUS notify_add ( struct notify_context * notify ,
const char * path , uint32_t filter , uint32_t subdir_filter ,
void ( * callback ) ( void * , const struct notify_event * ) ,
void * private_data )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
struct notify_db_entry e ;
struct notify_list * listel ;
struct db_record * notify_rec , * idx_rec ;
bool add_idx ;
2007-01-31 15:24:59 +03:00
NTSTATUS status ;
2012-04-04 16:51:43 +04:00
TDB_DATA key , notify_copy ;
if ( notify = = NULL ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
DEBUG ( 10 , ( " notify_add: path=[%s], private_data=%p \n " , path ,
private_data ) ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
listel = talloc ( notify , struct notify_list ) ;
if ( listel = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
listel - > callback = callback ;
listel - > private_data = private_data ;
listel - > path = talloc_strdup ( listel , path ) ;
if ( listel - > path = = NULL ) {
TALLOC_FREE ( listel ) ;
return NT_STATUS_NO_MEMORY ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
DLIST_ADD ( notify - > list , listel ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
ZERO_STRUCT ( e ) ;
e . filter = filter ;
e . subdir_filter = subdir_filter ;
e . server = messaging_server_id ( notify - > msg ) ;
e . private_data = private_data ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
key = string_tdb_data ( path ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
notify_rec = dbwrap_fetch_locked ( notify - > db_notify ,
talloc_tos ( ) , key ) ;
if ( notify_rec = = NULL ) {
status = NT_STATUS_INTERNAL_DB_CORRUPTION ;
goto fail ;
}
2010-04-05 16:12:52 +04:00
2012-04-04 16:51:43 +04:00
/*
* Make a copy of the notify_rec for easy restore in case
* updating the index_rec fails ;
*/
notify_copy = dbwrap_record_get_value ( notify_rec ) ;
if ( notify_copy . dsize ! = 0 ) {
notify_copy . dptr = ( uint8_t * ) talloc_memdup (
notify_rec , notify_copy . dptr ,
notify_copy . dsize ) ;
if ( notify_copy . dptr = = NULL ) {
TALLOC_FREE ( notify_rec ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
2007-11-09 16:39:45 +03:00
}
2007-05-29 14:50:25 +04:00
}
2007-02-02 14:34:16 +03:00
2012-04-04 16:51:43 +04:00
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( notify_db_entry , & e ) ;
}
2007-02-02 14:34:16 +03:00
2012-04-04 16:51:43 +04:00
status = notify_add_entry ( notify_rec , & e , & add_idx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
if ( ! add_idx ) {
/*
* Someone else has added the idx entry already
*/
TALLOC_FREE ( notify_rec ) ;
return NT_STATUS_OK ;
2007-05-29 14:50:25 +04:00
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
idx_rec = dbwrap_fetch_locked ( notify - > db_index ,
talloc_tos ( ) , key ) ;
if ( idx_rec = = NULL ) {
status = NT_STATUS_INTERNAL_DB_CORRUPTION ;
goto restore_notify ;
}
status = notify_add_idx ( idx_rec , get_my_vnn ( ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto restore_notify ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
TALLOC_FREE ( idx_rec ) ;
TALLOC_FREE ( notify_rec ) ;
return NT_STATUS_OK ;
restore_notify :
if ( notify_copy . dsize ! = 0 ) {
dbwrap_record_store ( notify_rec , notify_copy , 0 ) ;
} else {
dbwrap_record_delete ( notify_rec ) ;
}
TALLOC_FREE ( notify_rec ) ;
fail :
DLIST_REMOVE ( notify - > list , listel ) ;
TALLOC_FREE ( listel ) ;
return status ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
static NTSTATUS notify_add_entry ( struct db_record * rec ,
const struct notify_db_entry * e ,
bool * p_add_idx )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
TDB_DATA value = dbwrap_record_get_value ( rec ) ;
struct notify_db_entry * entries ;
size_t num_entries ;
bool add_idx = true ;
2007-01-31 15:24:59 +03:00
NTSTATUS status ;
2012-04-04 16:51:43 +04:00
if ( value . dsize = = sizeof ( time_t ) ) {
DEBUG ( 10 , ( " Re-using deleted entry \n " ) ) ;
value . dsize = 0 ;
add_idx = false ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
if ( ( value . dsize % sizeof ( struct notify_db_entry ) ) ! = 0 ) {
DEBUG ( 1 , ( " Invalid value.dsize = %u \n " ,
( unsigned ) value . dsize ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
num_entries = value . dsize / sizeof ( struct notify_db_entry ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( num_entries ! = 0 ) {
add_idx = false ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
entries = talloc_array ( rec , struct notify_db_entry , num_entries + 1 ) ;
if ( entries = = NULL ) {
return NT_STATUS_NO_MEMORY ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
memcpy ( entries , value . dptr , value . dsize ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
entries [ num_entries ] = * e ;
value = make_tdb_data ( ( uint8_t * ) entries , talloc_get_size ( entries ) ) ;
status = dbwrap_record_store ( rec , value , 0 ) ;
TALLOC_FREE ( entries ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2007-02-06 20:28:03 +03:00
}
2012-04-04 16:51:43 +04:00
* p_add_idx = add_idx ;
return NT_STATUS_OK ;
}
2007-02-06 20:28:03 +03:00
2012-04-04 16:51:43 +04:00
static NTSTATUS notify_add_idx ( struct db_record * rec , uint32_t vnn )
{
TDB_DATA value = dbwrap_record_get_value ( rec ) ;
uint32_t * vnns ;
size_t i , num_vnns ;
NTSTATUS status ;
2007-05-29 14:50:25 +04:00
2012-04-04 16:51:43 +04:00
if ( ( value . dsize % sizeof ( uint32_t ) ) ! = 0 ) {
DEBUG ( 1 , ( " Invalid value.dsize = %u \n " ,
( unsigned ) value . dsize ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
num_vnns = value . dsize / sizeof ( uint32_t ) ;
vnns = ( uint32_t * ) value . dptr ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
for ( i = 0 ; i < num_vnns ; i + + ) {
if ( vnns [ i ] = = vnn ) {
return NT_STATUS_OK ;
}
if ( vnns [ i ] > vnn ) {
break ;
}
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
value . dptr = ( uint8_t * ) talloc_realloc (
rec , value . dptr , uint32_t , num_vnns + 1 ) ;
if ( value . dptr = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
value . dsize = talloc_get_size ( value . dptr ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
vnns = ( uint32_t * ) value . dptr ;
memmove ( & vnns [ i + 1 ] , & vnns [ i ] , sizeof ( uint32_t ) * ( num_vnns - i ) ) ;
vnns [ i ] = vnn ;
status = dbwrap_record_store ( rec , value , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
NTSTATUS notify_remove ( struct notify_context * notify , void * private_data )
2007-01-31 15:24:59 +03:00
{
2012-04-19 11:51:11 +04:00
struct server_id pid ;
2007-01-31 15:24:59 +03:00
struct notify_list * listel ;
2012-04-04 16:51:43 +04:00
struct db_record * notify_rec ;
NTSTATUS status ;
2007-01-31 15:24:59 +03:00
2012-04-19 12:20:27 +04:00
if ( ( notify = = NULL ) | | ( notify - > msg = = NULL ) ) {
2012-04-04 16:51:43 +04:00
return NT_STATUS_NOT_IMPLEMENTED ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
DEBUG ( 10 , ( " notify_remove: private_data=%p \n " , private_data ) ) ;
2007-01-31 15:24:59 +03:00
2012-04-19 11:51:11 +04:00
pid = messaging_server_id ( notify - > msg ) ;
2007-01-31 15:24:59 +03:00
for ( listel = notify - > list ; listel ; listel = listel - > next ) {
2012-04-04 16:51:43 +04:00
if ( listel - > private_data = = private_data ) {
DLIST_REMOVE ( notify - > list , listel ) ;
2007-01-31 15:24:59 +03:00
break ;
}
}
2012-04-04 16:51:43 +04:00
if ( listel = = NULL ) {
DEBUG ( 10 , ( " %p not found \n " , private_data ) ) ;
return NT_STATUS_NOT_FOUND ;
}
notify_rec = dbwrap_fetch_locked ( notify - > db_notify , talloc_tos ( ) ,
string_tdb_data ( listel - > path ) ) ;
TALLOC_FREE ( listel ) ;
if ( notify_rec = = NULL ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
status = notify_del_entry ( notify_rec , & pid , private_data ) ;
DEBUG ( 10 , ( " del_entry returned %s \n " , nt_errstr ( status ) ) ) ;
TALLOC_FREE ( notify_rec ) ;
return status ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
static NTSTATUS notify_del_entry ( struct db_record * rec ,
const struct server_id * pid ,
void * private_data )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
TDB_DATA value = dbwrap_record_get_value ( rec ) ;
struct notify_db_entry * entries ;
size_t i , num_entries ;
time_t now ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
DEBUG ( 10 , ( " del_entry called for %s %p \n " , procid_str_static ( pid ) ,
private_data ) ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( ( value . dsize % sizeof ( struct notify_db_entry ) ) ! = 0 ) {
DEBUG ( 1 , ( " Invalid value.dsize = %u \n " ,
( unsigned ) value . dsize ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
num_entries = value . dsize / sizeof ( struct notify_db_entry ) ;
entries = ( struct notify_db_entry * ) value . dptr ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
for ( i = 0 ; i < num_entries ; i + + ) {
struct notify_db_entry * e = & entries [ i ] ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( notify_db_entry , e ) ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( e - > private_data ! = private_data ) {
continue ;
}
2012-06-16 02:26:26 +04:00
if ( serverid_equal ( & e - > server , pid ) ) {
2012-04-04 16:51:43 +04:00
break ;
}
}
if ( i = = num_entries ) {
return NT_STATUS_NOT_FOUND ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
entries [ i ] = entries [ num_entries - 1 ] ;
value . dsize - = sizeof ( struct notify_db_entry ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( value . dsize = = 0 ) {
now = time ( NULL ) ;
value . dptr = ( uint8_t * ) & now ;
value . dsize = sizeof ( now ) ;
}
return dbwrap_record_store ( rec , value , 0 ) ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
struct notify_trigger_index_state {
TALLOC_CTX * mem_ctx ;
uint32_t * vnns ;
uint32_t my_vnn ;
bool found_my_vnn ;
} ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
static void notify_trigger_index_parser ( TDB_DATA key , TDB_DATA data ,
void * private_data )
2009-04-14 22:39:14 +04:00
{
2012-04-04 16:51:43 +04:00
struct notify_trigger_index_state * state =
( struct notify_trigger_index_state * ) private_data ;
uint32_t * new_vnns ;
size_t i , num_vnns , num_new_vnns ;
if ( ( data . dsize % sizeof ( uint32_t ) ) ! = 0 ) {
DEBUG ( 1 , ( " Invalid record size in notify index db: %u \n " ,
( unsigned ) data . dsize ) ) ;
2009-04-14 22:39:14 +04:00
return ;
}
2012-04-04 16:51:43 +04:00
new_vnns = ( uint32_t * ) data . dptr ;
num_new_vnns = data . dsize / sizeof ( uint32_t ) ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
num_vnns = talloc_array_length ( state - > vnns ) ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
for ( i = 0 ; i < num_new_vnns ; i + + ) {
if ( new_vnns [ i ] = = state - > my_vnn ) {
state - > found_my_vnn = true ;
2009-04-14 22:39:14 +04:00
}
}
2012-04-04 16:51:43 +04:00
state - > vnns = talloc_realloc ( state - > mem_ctx , state - > vnns , uint32_t ,
num_vnns + num_new_vnns ) ;
if ( ( num_vnns + num_new_vnns ! = 0 ) & & ( state - > vnns = = NULL ) ) {
DEBUG ( 1 , ( " talloc_realloc failed \n " ) ) ;
2009-04-14 22:39:14 +04:00
return ;
}
2012-04-04 16:51:43 +04:00
memcpy ( & state - > vnns [ num_vnns ] , data . dptr , data . dsize ) ;
}
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
static int vnn_cmp ( const void * p1 , const void * p2 )
{
2012-05-08 18:03:13 +04:00
const uint32_t * vnn1 = ( const uint32_t * ) p1 ;
const uint32_t * vnn2 = ( const uint32_t * ) p2 ;
2012-04-04 16:51:43 +04:00
if ( * vnn1 < * vnn2 ) {
return - 1 ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
if ( * vnn1 = = * vnn2 ) {
return 0 ;
}
return 1 ;
}
static bool notify_push_remote_blob ( TALLOC_CTX * mem_ctx , uint32_t action ,
uint32_t filter , const char * path ,
uint8_t * * pblob , size_t * pblob_len )
{
struct notify_remote_event ev ;
DATA_BLOB data ;
enum ndr_err_code ndr_err ;
ev . action = action ;
ev . filter = filter ;
ev . path = path ;
2009-04-14 22:39:14 +04:00
if ( DEBUGLEVEL > = 10 ) {
2012-04-04 16:51:43 +04:00
NDR_PRINT_DEBUG ( notify_remote_event , & ev ) ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
ndr_err = ndr_push_struct_blob (
& data , mem_ctx , & ev ,
( ndr_push_flags_fn_t ) ndr_push_notify_remote_event ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return false ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
* pblob = data . data ;
* pblob_len = data . length ;
return true ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
static bool notify_pull_remote_blob ( TALLOC_CTX * mem_ctx ,
const uint8_t * blob , size_t blob_len ,
uint32_t * paction , uint32_t * pfilter ,
char * * path )
{
struct notify_remote_event * ev ;
enum ndr_err_code ndr_err ;
DATA_BLOB data ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
data . data = discard_const_p ( uint8_t , blob ) ;
data . length = blob_len ;
ev = talloc ( mem_ctx , struct notify_remote_event ) ;
if ( ev = = NULL ) {
return false ;
}
ndr_err = ndr_pull_struct_blob (
& data , ev , ev ,
( ndr_pull_flags_fn_t ) ndr_pull_notify_remote_event ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
TALLOC_FREE ( ev ) ;
return false ;
}
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( notify_remote_event , ev ) ;
}
* paction = ev - > action ;
* pfilter = ev - > filter ;
* path = talloc_move ( mem_ctx , ( char * * ) & ev - > path ) ;
TALLOC_FREE ( ev ) ;
return true ;
}
void notify_trigger ( struct notify_context * notify ,
uint32_t action , uint32_t filter , const char * path )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
struct ctdbd_connection * ctdbd_conn ;
struct notify_trigger_index_state idx_state ;
const char * p , * next_p ;
size_t i , num_vnns ;
uint32_t last_vnn ;
uint8_t * remote_blob = NULL ;
size_t remote_blob_len = 0 ;
DEBUG ( 10 , ( " notify_trigger called action=0x%x, filter=0x%x, "
" path=%s \n " , ( unsigned ) action , ( unsigned ) filter , path ) ) ;
2007-01-31 15:24:59 +03:00
/* see if change notify is enabled at all */
if ( notify = = NULL ) {
2012-04-04 16:51:43 +04:00
return ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
idx_state . mem_ctx = talloc_tos ( ) ;
idx_state . vnns = NULL ;
idx_state . my_vnn = get_my_vnn ( ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
for ( p = path ; p ! = NULL ; p = next_p ) {
ptrdiff_t path_len = p - path ;
bool recursive ;
next_p = strchr ( p + 1 , ' / ' ) ;
recursive = ( next_p ! = NULL ) ;
idx_state . found_my_vnn = false ;
dbwrap_parse_record (
notify - > db_index ,
make_tdb_data ( ( uint8_t * ) path , path_len ) ,
notify_trigger_index_parser , & idx_state ) ;
if ( ! idx_state . found_my_vnn ) {
continue ;
}
notify_trigger_local ( notify , action , filter ,
path , path_len , recursive ) ;
}
ctdbd_conn = messaging_ctdbd_connection ( ) ;
if ( ctdbd_conn = = NULL ) {
2007-01-31 15:24:59 +03:00
goto done ;
}
2012-04-04 16:51:43 +04:00
num_vnns = talloc_array_length ( idx_state . vnns ) ;
qsort ( idx_state . vnns , num_vnns , sizeof ( uint32_t ) , vnn_cmp ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
last_vnn = 0xffffffff ;
remote_blob = NULL ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
for ( i = 0 ; i < num_vnns ; i + + ) {
uint32_t vnn = idx_state . vnns [ i ] ;
NTSTATUS status ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( vnn = = last_vnn ) {
continue ;
}
if ( vnn = = idx_state . my_vnn ) {
continue ;
}
if ( ( remote_blob = = NULL ) & &
! notify_push_remote_blob (
talloc_tos ( ) , action , filter ,
path , & remote_blob , & remote_blob_len ) ) {
break ;
2012-03-14 13:52:03 +04:00
}
2012-04-04 16:51:43 +04:00
status = ctdbd_messaging_send_blob (
ctdbd_conn , vnn , CTDB_SRVID_SAMBA_NOTIFY_PROXY ,
remote_blob , remote_blob_len ) ;
2012-03-14 13:52:03 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-04-04 16:51:43 +04:00
DEBUG ( 10 , ( " ctdbd_messaging_send_blob to vnn %d "
" returned %s, ignoring \n " , ( int ) vnn ,
nt_errstr ( status ) ) ) ;
2012-03-14 13:52:03 +04:00
}
2012-04-04 16:51:43 +04:00
last_vnn = vnn ;
2012-03-14 13:52:03 +04:00
}
2012-04-04 16:51:43 +04:00
2007-01-31 15:24:59 +03:00
done :
2012-04-04 16:51:43 +04:00
TALLOC_FREE ( remote_blob ) ;
TALLOC_FREE ( idx_state . vnns ) ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
static void notify_trigger_local ( struct notify_context * notify ,
uint32_t action , uint32_t filter ,
const char * path , size_t path_len ,
bool recursive )
2009-04-14 22:39:14 +04:00
{
2012-04-04 16:51:43 +04:00
TDB_DATA data ;
struct notify_db_entry * entries ;
size_t i , num_entries ;
2009-04-14 22:39:14 +04:00
NTSTATUS status ;
2012-04-04 16:51:43 +04:00
DEBUG ( 10 , ( " notify_trigger_local called for %*s, path_len=%d, "
" filter=%d \n " , ( int ) path_len , path , ( int ) path_len ,
( int ) filter ) ) ;
2009-11-05 17:06:21 +03:00
2012-04-04 16:51:43 +04:00
status = dbwrap_fetch (
notify - > db_notify , talloc_tos ( ) ,
make_tdb_data ( ( uint8_t * ) path , path_len ) , & data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " dbwrap_fetch returned %s \n " ,
nt_errstr ( status ) ) ) ;
return ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
if ( data . dsize = = sizeof ( time_t ) ) {
DEBUG ( 10 , ( " Got deleted record \n " ) ) ;
goto done ;
}
if ( ( data . dsize % sizeof ( struct notify_db_entry ) ) ! = 0 ) {
DEBUG ( 1 , ( " Invalid data.dsize = %u \n " ,
( unsigned ) data . dsize ) ) ;
goto done ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
entries = ( struct notify_db_entry * ) data . dptr ;
num_entries = data . dsize / sizeof ( struct notify_db_entry ) ;
DEBUG ( 10 , ( " recursive = %s pathlen=%d (%c) \n " ,
recursive ? " true " : " false " , ( int ) path_len ,
path [ path_len ] ) ) ;
for ( i = 0 ; i < num_entries ; i + + ) {
struct notify_db_entry * e = & entries [ i ] ;
uint32_t e_filter ;
2009-04-14 22:39:14 +04:00
if ( DEBUGLEVEL > = 10 ) {
2012-04-04 16:51:43 +04:00
NDR_PRINT_DEBUG ( notify_db_entry , e ) ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
e_filter = recursive ? e - > subdir_filter : e - > filter ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
if ( ( filter & e_filter ) = = 0 ) {
continue ;
}
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
if ( ! procid_is_local ( & e - > server ) ) {
DEBUG ( 1 , ( " internal error: Non-local pid %s in "
" notify.tdb \n " ,
procid_str_static ( & e - > server ) ) ) ;
continue ;
}
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
status = notify_send ( notify , & e - > server , path + path_len + 1 ,
action , e - > private_data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " notify_send returned %s \n " ,
nt_errstr ( status ) ) ) ;
}
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
done :
TALLOC_FREE ( data . dptr ) ;
}
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
static NTSTATUS notify_send ( struct notify_context * notify ,
struct server_id * pid ,
const char * path , uint32_t action ,
void * private_data )
{
struct notify_event ev ;
DATA_BLOB data ;
NTSTATUS status ;
enum ndr_err_code ndr_err ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
ev . action = action ;
ev . path = path ;
ev . private_data = private_data ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
ndr_err = ndr_push_struct_blob (
& data , talloc_tos ( ) , & ev ,
( ndr_push_flags_fn_t ) ndr_push_notify_event ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
status = messaging_send ( notify - > msg , * pid , MSG_PVFS_NOTIFY ,
& data ) ;
TALLOC_FREE ( data . data ) ;
return status ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
static void notify_handler ( struct messaging_context * msg_ctx ,
void * private_data , uint32_t msg_type ,
struct server_id server_id , DATA_BLOB * data )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
struct notify_context * notify = talloc_get_type_abort (
private_data , struct notify_context ) ;
enum ndr_err_code ndr_err ;
struct notify_event * n ;
2007-01-31 15:24:59 +03:00
struct notify_list * listel ;
2012-04-04 16:51:43 +04:00
n = talloc ( talloc_tos ( ) , struct notify_event ) ;
if ( n = = NULL ) {
DEBUG ( 1 , ( " talloc failed \n " ) ) ;
return ;
}
ndr_err = ndr_pull_struct_blob (
data , n , n , ( ndr_pull_flags_fn_t ) ndr_pull_notify_event ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
TALLOC_FREE ( n ) ;
return ;
}
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( notify_event , n ) ;
2007-01-31 15:24:59 +03:00
}
for ( listel = notify - > list ; listel ; listel = listel - > next ) {
2012-04-04 16:51:43 +04:00
if ( listel - > private_data = = n - > private_data ) {
listel - > callback ( listel - > private_data , n ) ;
2007-01-31 15:24:59 +03:00
break ;
}
}
2012-04-04 16:51:43 +04:00
TALLOC_FREE ( n ) ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
struct notify_walk_idx_state {
void ( * fn ) ( const char * path ,
uint32_t * vnns , size_t num_vnns ,
void * private_data ) ;
void * private_data ;
} ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
static int notify_walk_idx_fn ( struct db_record * rec , void * private_data )
{
struct notify_walk_idx_state * state =
( struct notify_walk_idx_state * ) private_data ;
TDB_DATA key , value ;
char * path ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
key = dbwrap_record_get_key ( rec ) ;
value = dbwrap_record_get_value ( rec ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( ( value . dsize % sizeof ( uint32_t ) ) ! = 0 ) {
DEBUG ( 1 , ( " invalid value size in notify index db: %u \n " ,
( unsigned ) ( value . dsize ) ) ) ;
return 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
path = talloc_strndup ( talloc_tos ( ) , ( char * ) key . dptr , key . dsize ) ;
if ( path = = NULL ) {
DEBUG ( 1 , ( " talloc_strndup failed \n " ) ) ;
return 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
state - > fn ( path , ( uint32_t * ) value . dptr , value . dsize / sizeof ( uint32_t ) ,
state - > private_data ) ;
TALLOC_FREE ( path ) ;
return 0 ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
void notify_walk_idx ( struct notify_context * notify ,
void ( * fn ) ( const char * path ,
uint32_t * vnns , size_t num_vnns ,
void * private_data ) ,
void * private_data )
{
struct notify_walk_idx_state state ;
state . fn = fn ;
state . private_data = private_data ;
dbwrap_traverse_read ( notify - > db_index , notify_walk_idx_fn , & state ,
NULL ) ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
struct notify_walk_state {
void ( * fn ) ( const char * path ,
struct notify_db_entry * entries , size_t num_entries ,
time_t deleted_time , void * private_data ) ;
void * private_data ;
} ;
static int notify_walk_fn ( struct db_record * rec , void * private_data )
{
struct notify_walk_state * state =
( struct notify_walk_state * ) private_data ;
TDB_DATA key , value ;
struct notify_db_entry * entries ;
size_t num_entries ;
time_t deleted_time ;
char * path ;
key = dbwrap_record_get_key ( rec ) ;
value = dbwrap_record_get_value ( rec ) ;
if ( value . dsize = = sizeof ( deleted_time ) ) {
memcpy ( & deleted_time , value . dptr , sizeof ( deleted_time ) ) ;
entries = NULL ;
num_entries = 0 ;
} else {
if ( ( value . dsize % sizeof ( struct notify_db_entry ) ) ! = 0 ) {
DEBUG ( 1 , ( " invalid value size in notify db: %u \n " ,
( unsigned ) ( value . dsize ) ) ) ;
return 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
entries = ( struct notify_db_entry * ) value . dptr ;
num_entries = value . dsize / sizeof ( struct notify_db_entry ) ;
deleted_time = 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
path = talloc_strndup ( talloc_tos ( ) , ( char * ) key . dptr , key . dsize ) ;
if ( path = = NULL ) {
DEBUG ( 1 , ( " talloc_strndup failed \n " ) ) ;
return 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
state - > fn ( path , entries , num_entries , deleted_time ,
state - > private_data ) ;
TALLOC_FREE ( path ) ;
return 0 ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
void notify_walk ( struct notify_context * notify ,
void ( * fn ) ( const char * path ,
struct notify_db_entry * entries ,
size_t num_entries ,
time_t deleted_time , void * private_data ) ,
void * private_data )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
struct notify_walk_state state ;
state . fn = fn ;
state . private_data = private_data ;
dbwrap_traverse_read ( notify - > db_notify , notify_walk_fn , & state ,
NULL ) ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
struct notify_cleanup_state {
TALLOC_CTX * mem_ctx ;
time_t delete_before ;
ssize_t array_size ;
uint32_t num_paths ;
char * * paths ;
} ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
static void notify_cleanup_collect (
const char * path , struct notify_db_entry * entries , size_t num_entries ,
time_t deleted_time , void * private_data )
{
struct notify_cleanup_state * state =
( struct notify_cleanup_state * ) private_data ;
char * p ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
if ( num_entries ! = 0 ) {
return ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
if ( deleted_time > = state - > delete_before ) {
return ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
p = talloc_strdup ( state - > mem_ctx , path ) ;
if ( p = = NULL ) {
DEBUG ( 1 , ( " talloc_strdup failed \n " ) ) ;
return ;
}
add_to_large_array ( state - > mem_ctx , sizeof ( p ) , ( void * ) & p ,
& state - > paths , & state - > num_paths ,
& state - > array_size ) ;
if ( state - > array_size = = - 1 ) {
TALLOC_FREE ( p ) ;
}
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
static bool notify_cleanup_path ( struct notify_context * notify ,
const char * path , time_t delete_before ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
void notify_cleanup ( struct notify_context * notify )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
struct notify_cleanup_state state ;
uint32_t failure_pool ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
ZERO_STRUCT ( state ) ;
state . mem_ctx = talloc_stackframe ( ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
state . delete_before = time ( NULL )
- lp_parm_int ( - 1 , " smbd " , " notify cleanup interval " , 60 ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
notify_walk ( notify , notify_cleanup_collect , & state ) ;
failure_pool = state . num_paths ;
while ( state . num_paths ! = 0 ) {
size_t idx ;
/*
* This loop is designed to be as kind as possible to
* ctdb . ctdb does not like it if many smbds hammer on a
* single record . If on many nodes the cleanup process starts
* running , it can happen that all of them need to clean up
* records in the same order . This would generate a ctdb
* migrate storm on these records . Randomizing the load across
* multiple records reduces the load on the individual record .
*/
generate_random_buffer ( ( uint8_t * ) & idx , sizeof ( idx ) ) ;
idx = idx % state . num_paths ;
if ( ! notify_cleanup_path ( notify , state . paths [ idx ] ,
state . delete_before ) ) {
/*
* notify_cleanup_path failed , the most likely reason
* is that dbwrap_try_fetch_locked failed due to
* contention . We allow one failed attempt per deleted
* path on average before we give up .
*/
failure_pool - = 1 ;
if ( failure_pool = = 0 ) {
/*
* Too many failures . We will come back here ,
* maybe next time there is less contention .
*/
break ;
}
}
TALLOC_FREE ( state . paths [ idx ] ) ;
state . paths [ idx ] = state . paths [ state . num_paths - 1 ] ;
state . num_paths - = 1 ;
}
TALLOC_FREE ( state . mem_ctx ) ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
static bool notify_cleanup_path ( struct notify_context * notify ,
const char * path , time_t delete_before )
2009-04-14 22:39:14 +04:00
{
2012-04-04 16:51:43 +04:00
struct db_record * notify_rec = NULL ;
struct db_record * idx_rec = NULL ;
TDB_DATA key = string_tdb_data ( path ) ;
TDB_DATA value ;
time_t deleted ;
2011-08-25 03:35:16 +04:00
NTSTATUS status ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
notify_rec = dbwrap_fetch_locked ( notify - > db_notify , talloc_tos ( ) , key ) ;
if ( notify_rec = = NULL ) {
DEBUG ( 10 , ( " Could not fetch notify_rec \n " ) ) ;
return false ;
2009-04-30 14:24:51 +04:00
}
2012-04-04 16:51:43 +04:00
value = dbwrap_record_get_value ( notify_rec ) ;
2009-04-30 14:24:51 +04:00
2012-04-04 16:51:43 +04:00
if ( value . dsize ! = sizeof ( deleted ) ) {
DEBUG ( 10 , ( " record %s has been re-used \n " , path ) ) ;
goto done ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
memcpy ( & deleted , value . dptr , sizeof ( deleted ) ) ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
if ( deleted > = delete_before ) {
DEBUG ( 10 , ( " record %s too young \n " , path ) ) ;
goto done ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
/*
* Be kind to ctdb and only try one dmaster migration at most .
*/
idx_rec = dbwrap_try_fetch_locked ( notify - > db_index , talloc_tos ( ) , key ) ;
if ( idx_rec = = NULL ) {
DEBUG ( 10 , ( " Could not fetch idx_rec \n " ) ) ;
goto done ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
status = dbwrap_record_delete ( notify_rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Could not delete notify_rec: %s \n " ,
nt_errstr ( status ) ) ) ;
}
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
status = notify_del_idx ( idx_rec , get_my_vnn ( ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Could not delete idx_rec: %s \n " ,
nt_errstr ( status ) ) ) ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
done :
TALLOC_FREE ( idx_rec ) ;
TALLOC_FREE ( notify_rec ) ;
return true ;
}
static NTSTATUS notify_del_idx ( struct db_record * rec , uint32_t vnn )
{
TDB_DATA value = dbwrap_record_get_value ( rec ) ;
uint32_t * vnns ;
size_t i , num_vnns ;
if ( ( value . dsize % sizeof ( uint32_t ) ) ! = 0 ) {
DEBUG ( 1 , ( " Invalid value.dsize = %u \n " ,
( unsigned ) value . dsize ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
num_vnns = value . dsize / sizeof ( uint32_t ) ;
vnns = ( uint32_t * ) value . dptr ;
2009-04-14 22:39:14 +04:00
2012-04-04 16:51:43 +04:00
for ( i = 0 ; i < num_vnns ; i + + ) {
if ( vnns [ i ] = = vnn ) {
break ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
}
if ( i = = num_vnns ) {
2009-04-14 22:39:14 +04:00
/*
2012-04-04 16:51:43 +04:00
* Not found . Should not happen , but okay . . .
2009-04-14 22:39:14 +04:00
*/
2012-04-04 16:51:43 +04:00
return NT_STATUS_OK ;
2009-04-14 22:39:14 +04:00
}
2012-04-04 16:51:43 +04:00
memmove ( & vnns [ i ] , & vnns [ i + 1 ] , sizeof ( uint32_t ) * ( num_vnns - i - 1 ) ) ;
value . dsize - = sizeof ( uint32_t ) ;
if ( value . dsize = = 0 ) {
return dbwrap_record_delete ( rec ) ;
}
return dbwrap_record_store ( rec , value , 0 ) ;
2009-04-14 22:39:14 +04:00
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
struct notify_cluster_proxy_state {
struct tevent_context * ev ;
struct notify_context * notify ;
struct ctdb_msg_channel * chan ;
} ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
static void notify_cluster_proxy_got_chan ( struct tevent_req * subreq ) ;
static void notify_cluster_proxy_got_msg ( struct tevent_req * subreq ) ;
static void notify_cluster_proxy_trigger ( struct notify_context * notify ,
uint32_t action , uint32_t filter ,
char * path ) ;
struct tevent_req * notify_cluster_proxy_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct notify_context * notify )
2007-01-31 15:24:59 +03:00
{
2012-04-04 16:51:43 +04:00
struct tevent_req * req , * subreq ;
struct notify_cluster_proxy_state * state ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct notify_cluster_proxy_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > notify = notify ;
2007-01-31 16:47:37 +03:00
2012-04-04 16:51:43 +04:00
subreq = ctdb_msg_channel_init_send (
state , state - > ev , lp_ctdbd_socket ( ) ,
CTDB_SRVID_SAMBA_NOTIFY_PROXY ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
tevent_req_set_callback ( subreq , notify_cluster_proxy_got_chan , req ) ;
return req ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
static void notify_cluster_proxy_got_chan ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct notify_cluster_proxy_state * state = tevent_req_data (
req , struct notify_cluster_proxy_state ) ;
int ret ;
ret = ctdb_msg_channel_init_recv ( subreq , state , & state - > chan ) ;
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
tevent_req_error ( req , ret ) ;
2007-01-31 15:24:59 +03:00
return ;
}
2012-04-04 16:51:43 +04:00
subreq = ctdb_msg_read_send ( state , state - > ev , state - > chan ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , notify_cluster_proxy_got_msg , req ) ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
static void notify_cluster_proxy_got_msg ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct notify_cluster_proxy_state * state = tevent_req_data (
req , struct notify_cluster_proxy_state ) ;
uint8_t * msg ;
size_t msg_len ;
uint32_t action , filter ;
char * path ;
int ret ;
bool res ;
ret = ctdb_msg_read_recv ( subreq , talloc_tos ( ) , & msg , & msg_len ) ;
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
tevent_req_error ( req , ret ) ;
return ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
res = notify_pull_remote_blob ( talloc_tos ( ) , msg , msg_len ,
& action , & filter , & path ) ;
TALLOC_FREE ( msg ) ;
if ( ! res ) {
tevent_req_error ( req , EIO ) ;
return ;
}
notify_cluster_proxy_trigger ( state - > notify , action , filter , path ) ;
TALLOC_FREE ( path ) ;
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
subreq = ctdb_msg_read_send ( state , state - > ev , state - > chan ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , notify_cluster_proxy_got_msg , req ) ;
}
2007-01-31 15:24:59 +03:00
2012-04-04 16:51:43 +04:00
static void notify_cluster_proxy_trigger ( struct notify_context * notify ,
uint32_t action , uint32_t filter ,
char * path )
{
const char * p , * next_p ;
2012-03-15 15:22:50 +04:00
2012-04-04 16:51:43 +04:00
for ( p = path ; p ! = NULL ; p = next_p ) {
ptrdiff_t path_len = p - path ;
bool recursive ;
2012-03-15 15:22:50 +04:00
2012-04-04 16:51:43 +04:00
next_p = strchr ( p + 1 , ' / ' ) ;
recursive = ( next_p ! = NULL ) ;
2012-03-15 15:22:50 +04:00
2012-04-04 16:51:43 +04:00
notify_trigger_local ( notify , action , filter ,
path , path_len , recursive ) ;
}
}
2007-02-02 14:34:16 +03:00
2012-04-04 16:51:43 +04:00
int notify_cluster_proxy_recv ( struct tevent_req * req )
{
int err ;
2007-02-02 14:34:16 +03:00
2012-04-04 16:51:43 +04:00
if ( tevent_req_is_unix_error ( req , & err ) ) {
return err ;
2007-01-31 15:24:59 +03:00
}
2012-04-04 16:51:43 +04:00
return 0 ;
2007-01-31 15:24:59 +03:00
}