2008-10-24 07:49:55 +04:00
/*
2008-12-09 03:57:58 +03:00
* Unix SMB / CIFS implementation .
2008-10-24 07:49:55 +04:00
* Support for OneFS
*
* Copyright ( C ) Tim Prouty , 2008
*
* 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
* the Free Software Foundation ; either version 3 of the License , or
* ( 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
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2008-12-09 03:57:58 +03:00
# include "onefs.h"
2008-10-24 07:49:55 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
2009-01-29 19:08:35 +03:00
# define ONEFS_DATA_FASTBUF 10
struct onefs_vfs_config share_config [ ONEFS_DATA_FASTBUF ] ;
struct onefs_vfs_config * pshare_config ;
static void onefs_load_faketimestamp_config ( struct vfs_handle_struct * handle ,
struct onefs_vfs_config * cfg )
{
const char * * parm ;
int snum = SNUM ( handle - > conn ) ;
parm = lp_parm_string_list ( snum , PARM_ONEFS_TYPE , PARM_ATIME_NOW ,
NULL ) ;
if ( parm ) {
cfg - > init_flags | = ONEFS_VFS_CONFIG_FAKETIMESTAMPS ;
set_namearray ( & cfg - > atime_now_list , * parm ) ;
}
parm = lp_parm_string_list ( snum , PARM_ONEFS_TYPE , PARM_CTIME_NOW ,
NULL ) ;
if ( parm ) {
cfg - > init_flags | = ONEFS_VFS_CONFIG_FAKETIMESTAMPS ;
set_namearray ( & cfg - > ctime_now_list , * parm ) ;
}
parm = lp_parm_string_list ( snum , PARM_ONEFS_TYPE , PARM_MTIME_NOW ,
NULL ) ;
if ( parm ) {
cfg - > init_flags | = ONEFS_VFS_CONFIG_FAKETIMESTAMPS ;
set_namearray ( & cfg - > mtime_now_list , * parm ) ;
}
parm = lp_parm_string_list ( snum , PARM_ONEFS_TYPE , PARM_ATIME_STATIC ,
NULL ) ;
if ( parm ) {
cfg - > init_flags | = ONEFS_VFS_CONFIG_FAKETIMESTAMPS ;
set_namearray ( & cfg - > atime_static_list , * parm ) ;
}
parm = lp_parm_string_list ( snum , PARM_ONEFS_TYPE , PARM_MTIME_STATIC ,
NULL ) ;
if ( parm ) {
cfg - > init_flags | = ONEFS_VFS_CONFIG_FAKETIMESTAMPS ;
set_namearray ( & cfg - > mtime_static_list , * parm ) ;
}
cfg - > atime_slop = lp_parm_int ( snum , PARM_ONEFS_TYPE , PARM_ATIME_SLOP , 0 ) ;
cfg - > ctime_slop = lp_parm_int ( snum , PARM_ONEFS_TYPE , PARM_CTIME_SLOP , 0 ) ;
cfg - > mtime_slop = lp_parm_int ( snum , PARM_ONEFS_TYPE , PARM_MTIME_SLOP , 0 ) ;
}
static int onefs_load_config ( struct vfs_handle_struct * handle )
{
int snum = SNUM ( handle - > conn ) ;
int share_count = lp_numservices ( ) ;
if ( ! pshare_config ) {
if ( share_count < = ONEFS_DATA_FASTBUF )
pshare_config = share_config ;
else {
2009-01-27 07:14:32 +03:00
pshare_config =
SMB_MALLOC_ARRAY ( struct onefs_vfs_config ,
share_count ) ;
2009-01-29 19:08:35 +03:00
if ( ! pshare_config ) {
errno = ENOMEM ;
return - 1 ;
}
memset ( pshare_config , 0 ,
( sizeof ( struct onefs_vfs_config ) * share_count ) ) ;
}
}
if ( ( pshare_config [ snum ] . init_flags &
ONEFS_VFS_CONFIG_INITIALIZED ) = = 0 ) {
pshare_config [ snum ] . init_flags =
ONEFS_VFS_CONFIG_INITIALIZED ;
onefs_load_faketimestamp_config ( handle ,
& pshare_config [ snum ] ) ;
}
return 0 ;
}
bool onefs_get_config ( int snum , int config_type ,
struct onefs_vfs_config * cfg )
{
if ( share_config [ snum ] . init_flags & config_type )
* cfg = share_config [ snum ] ;
else
return false ;
return true ;
}
static int onefs_connect ( struct vfs_handle_struct * handle , const char * service ,
const char * user )
{
int ret = onefs_load_config ( handle ) ;
if ( ret )
return ret ;
return SMB_VFS_NEXT_CONNECT ( handle , service , user ) ;
}
2008-12-09 03:57:58 +03:00
static int onefs_mkdir ( vfs_handle_struct * handle , const char * path ,
mode_t mode )
{
2008-12-31 04:17:24 +03:00
/* SMB_VFS_MKDIR should never be called in vfs_onefs */
SMB_ASSERT ( false ) ;
2008-12-09 03:57:58 +03:00
return SMB_VFS_NEXT_MKDIR ( handle , path , mode ) ;
}
2008-12-03 07:15:34 +03:00
2008-12-09 03:57:58 +03:00
static int onefs_open ( vfs_handle_struct * handle , const char * fname ,
files_struct * fsp , int flags , mode_t mode )
{
2008-12-31 04:17:24 +03:00
/* SMB_VFS_OPEN should never be called in vfs_onefs */
SMB_ASSERT ( false ) ;
2008-12-09 03:57:58 +03:00
return SMB_VFS_NEXT_OPEN ( handle , fname , fsp , flags , mode ) ;
}
2008-12-03 07:15:34 +03:00
2009-02-14 08:36:42 +03:00
static ssize_t onefs_recvfile ( vfs_handle_struct * handle , int fromfd ,
files_struct * tofsp , SMB_OFF_T offset ,
size_t count )
{
ssize_t result ;
START_PROFILE_BYTES ( syscall_recvfile , count ) ;
result = onefs_sys_recvfile ( fromfd , tofsp - > fh - > fd , offset , count ) ;
END_PROFILE ( syscall_recvfile ) ;
return result ;
}
2009-01-27 07:14:32 +03:00
static uint64_t onefs_get_alloc_size ( struct vfs_handle_struct * handle ,
files_struct * fsp ,
const SMB_STRUCT_STAT * sbuf )
2009-01-27 04:19:40 +03:00
{
uint64_t result ;
START_PROFILE ( syscall_get_alloc_size ) ;
if ( S_ISDIR ( sbuf - > st_mode ) ) {
result = 0 ;
goto out ;
}
/* Just use the file size since st_blocks is unreliable on OneFS. */
result = get_file_size_stat ( sbuf ) ;
if ( fsp & & fsp - > initial_allocation_size )
result = MAX ( result , fsp - > initial_allocation_size ) ;
result = smb_roundup ( handle - > conn , result ) ;
out :
END_PROFILE ( syscall_get_alloc_size ) ;
return result ;
}
2008-12-17 23:02:19 +03:00
static int onefs_statvfs ( vfs_handle_struct * handle , const char * path ,
vfs_statvfs_struct * statbuf )
{
struct statvfs statvfs_buf ;
int result ;
DEBUG ( 5 , ( " Calling SMB_STAT_VFS \n " ) ) ;
result = statvfs ( path , & statvfs_buf ) ;
ZERO_STRUCTP ( statbuf ) ;
if ( ! result ) {
statbuf - > OptimalTransferSize = statvfs_buf . f_iosize ;
statbuf - > BlockSize = statvfs_buf . f_bsize ;
statbuf - > TotalBlocks = statvfs_buf . f_blocks ;
statbuf - > BlocksAvail = statvfs_buf . f_bfree ;
statbuf - > UserBlocksAvail = statvfs_buf . f_bavail ;
statbuf - > TotalFileNodes = statvfs_buf . f_files ;
statbuf - > FreeFileNodes = statvfs_buf . f_ffree ;
statbuf - > FsIdentifier =
( ( ( uint64_t ) statvfs_buf . f_fsid . val [ 0 ] < < 32 ) &
0xffffffff00000000LL ) |
( uint64_t ) statvfs_buf . f_fsid . val [ 1 ] ;
}
return result ;
}
2009-02-13 22:07:46 +03:00
static int onefs_get_real_filename ( vfs_handle_struct * handle , const char * path ,
const char * name , TALLOC_CTX * mem_ctx ,
char * * found_name )
{
SMB_STRUCT_STAT sb ;
struct stat_extra se ;
int result ;
char * full_name = NULL ;
ZERO_STRUCT ( se ) ;
se . se_version = ESTAT_CURRENT_VERSION ;
se . se_flags = ESTAT_CASE_INSENSITIVE | ESTAT_SYMLINK_NOFOLLOW ;
if ( * path ! = ' \0 ' ) {
if ( ! ( full_name = talloc_asprintf ( mem_ctx , " %s/%s " , path , name ) ) ) {
errno = ENOMEM ;
DEBUG ( 2 , ( " talloc_asprintf failed \n " ) ) ;
result = - 1 ;
goto done ;
}
}
if ( ( result = estat ( full_name ? full_name : name , & sb , & se ) ) ! = 0 ) {
DEBUG ( 2 , ( " error calling estat: %s \n " , strerror ( errno ) ) ) ;
goto done ;
}
* found_name = talloc_strdup ( mem_ctx , se . se_realname ) ;
if ( * found_name = = NULL ) {
errno = ENOMEM ;
result = - 1 ;
goto done ;
}
done :
TALLOC_FREE ( full_name ) ;
return result ;
}
2009-01-24 03:55:18 +03:00
static int onefs_ntimes ( vfs_handle_struct * handle , const char * fname ,
struct smb_file_time * ft )
{
int flags = 0 ;
struct timespec times [ 3 ] ;
if ( ! null_timespec ( ft - > atime ) ) {
flags | = VT_ATIME ;
times [ 0 ] = ft - > atime ;
DEBUG ( 6 , ( " **** onefs_ntimes: actime: %s.%d \n " ,
time_to_asc ( convert_timespec_to_time_t ( ft - > atime ) ) ,
ft - > atime . tv_nsec ) ) ;
}
if ( ! null_timespec ( ft - > mtime ) ) {
flags | = VT_MTIME ;
times [ 1 ] = ft - > mtime ;
DEBUG ( 6 , ( " **** onefs_ntimes: modtime: %s.%d \n " ,
time_to_asc ( convert_timespec_to_time_t ( ft - > mtime ) ) ,
ft - > mtime . tv_nsec ) ) ;
}
if ( ! null_timespec ( ft - > create_time ) ) {
flags | = VT_BTIME ;
times [ 2 ] = ft - > create_time ;
DEBUG ( 6 , ( " **** onefs_ntimes: createtime: %s.%d \n " ,
time_to_asc ( convert_timespec_to_time_t ( ft - > create_time ) ) ,
ft - > create_time . tv_nsec ) ) ;
}
return onefs_vtimes_streams ( handle , fname , flags , times ) ;
}
2008-12-13 01:32:48 +03:00
static uint32_t onefs_fs_capabilities ( struct vfs_handle_struct * handle )
{
return SMB_VFS_NEXT_FS_CAPABILITIES ( handle ) | FILE_NAMED_STREAMS ;
}
2008-10-24 07:49:55 +04:00
static vfs_op_tuple onefs_ops [ ] = {
2009-01-29 19:08:35 +03:00
{ SMB_VFS_OP ( onefs_connect ) , SMB_VFS_OP_CONNECT ,
SMB_VFS_LAYER_TRANSPARENT } ,
2008-12-13 01:32:48 +03:00
{ SMB_VFS_OP ( onefs_fs_capabilities ) , SMB_VFS_OP_FS_CAPABILITIES ,
SMB_VFS_LAYER_TRANSPARENT } ,
2009-01-27 07:14:32 +03:00
{ SMB_VFS_OP ( onefs_opendir ) , SMB_VFS_OP_OPENDIR ,
SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( onefs_readdir ) , SMB_VFS_OP_READDIR ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_seekdir ) , SMB_VFS_OP_SEEKDIR ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_telldir ) , SMB_VFS_OP_TELLDIR ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_rewinddir ) , SMB_VFS_OP_REWINDDIR ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-09 03:57:58 +03:00
{ SMB_VFS_OP ( onefs_mkdir ) , SMB_VFS_OP_MKDIR ,
SMB_VFS_LAYER_OPAQUE } ,
2009-01-27 07:14:32 +03:00
{ SMB_VFS_OP ( onefs_closedir ) , SMB_VFS_OP_CLOSEDIR ,
SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( onefs_init_search_op ) , SMB_VFS_OP_INIT_SEARCH_OP ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-09 03:57:58 +03:00
{ SMB_VFS_OP ( onefs_open ) , SMB_VFS_OP_OPEN ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_create_file ) , SMB_VFS_OP_CREATE_FILE ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-13 01:32:48 +03:00
{ SMB_VFS_OP ( onefs_close ) , SMB_VFS_OP_CLOSE ,
SMB_VFS_LAYER_TRANSPARENT } ,
2009-02-14 08:36:42 +03:00
{ SMB_VFS_OP ( onefs_recvfile ) , SMB_VFS_OP_RECVFILE ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-13 01:32:48 +03:00
{ SMB_VFS_OP ( onefs_rename ) , SMB_VFS_OP_RENAME ,
SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( onefs_stat ) , SMB_VFS_OP_STAT ,
SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( onefs_fstat ) , SMB_VFS_OP_FSTAT ,
SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( onefs_lstat ) , SMB_VFS_OP_LSTAT ,
SMB_VFS_LAYER_TRANSPARENT } ,
2009-01-27 04:19:40 +03:00
{ SMB_VFS_OP ( onefs_get_alloc_size ) , SMB_VFS_OP_GET_ALLOC_SIZE ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-13 01:32:48 +03:00
{ SMB_VFS_OP ( onefs_unlink ) , SMB_VFS_OP_UNLINK ,
SMB_VFS_LAYER_TRANSPARENT } ,
2009-01-24 03:55:18 +03:00
{ SMB_VFS_OP ( onefs_ntimes ) , SMB_VFS_OP_NTIMES ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-13 01:32:48 +03:00
{ SMB_VFS_OP ( onefs_chflags ) , SMB_VFS_OP_CHFLAGS ,
SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( onefs_streaminfo ) , SMB_VFS_OP_STREAMINFO ,
SMB_VFS_LAYER_OPAQUE } ,
OneFS implementation of BRL VFS ops:
* Much of the beginning should look familiar, as I re-used the OneFS oplock
callback record concept. This was necessary to keep our own state around - it
really only consists of a lock state, per asynchronous lock that is currently
unsatisfied. The onefs_cbrl_callback_records map to BLRs by the id.
* There are 4 states an async lock can be in. NONE means there is no async
currently out for the lock, as opposed to ASYNC. DONE means we've locked
*every* lock (keep in mind a request can ask for multiple locks at a time.)
ERROR is an error.
* onefs_cbrl_async_success: The lock_num is incremented, and the state changed,
so that when process_blocking_lock_queue is run, we will try the *next* lock,
rather than the same one again.
* onefs_brl_lock_windows() has some complicated logic:
* We do a no-op if we're passed a BLR and the matching state is ASYNC --
this means Samba is trying to get the same lock twice, and we just need
to wait longer, so we return an error.
* PENDING lock calls happen when the lock is being queued on the BLQ -- we
do async in this case.
* We also do async in the case that we're passed a BLR, but the lock is not
pending. This is an async lock being probed by process_blocking_lock_queue.
* We do a sync lock for any normal first request of a lock.
* Failure is returned, but it doesn't go to the client unless the lock has
actually timed out.
2009-02-10 08:54:51 +03:00
{ SMB_VFS_OP ( onefs_brl_lock_windows ) , SMB_VFS_OP_BRL_LOCK_WINDOWS ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_brl_unlock_windows ) , SMB_VFS_OP_BRL_UNLOCK_WINDOWS ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_brl_cancel_windows ) , SMB_VFS_OP_BRL_CANCEL_WINDOWS ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-03 07:15:34 +03:00
{ SMB_VFS_OP ( onefs_fget_nt_acl ) , SMB_VFS_OP_FGET_NT_ACL ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_get_nt_acl ) , SMB_VFS_OP_GET_NT_ACL ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_fset_nt_acl ) , SMB_VFS_OP_FSET_NT_ACL ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-17 23:02:19 +03:00
{ SMB_VFS_OP ( onefs_statvfs ) , SMB_VFS_OP_STATVFS ,
SMB_VFS_LAYER_OPAQUE } ,
2009-02-13 22:07:46 +03:00
{ SMB_VFS_OP ( onefs_get_real_filename ) , SMB_VFS_OP_GET_REAL_FILENAME ,
SMB_VFS_LAYER_OPAQUE } ,
2008-10-24 07:49:55 +04:00
{ SMB_VFS_OP ( NULL ) , SMB_VFS_OP_NOOP , SMB_VFS_LAYER_NOOP }
} ;
NTSTATUS vfs_onefs_init ( void )
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " onefs " ,
onefs_ops ) ;
}