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"
2009-02-28 01:47:47 +03:00
# include "onefs_config.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
static int onefs_connect ( struct vfs_handle_struct * handle , const char * service ,
const char * user )
{
2009-02-24 01:51:17 +03:00
int ret ;
2009-01-29 19:08:35 +03:00
2009-02-24 01:51:17 +03:00
ret = onefs_load_config ( handle - > conn ) ;
if ( ret ) {
DEBUG ( 3 , ( " Load config failed: %s \n " , strerror ( errno ) ) ) ;
2009-01-29 19:08:35 +03:00
return ret ;
2009-02-24 01:51:17 +03:00
}
2009-01-29 19:08:35 +03:00
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-21 00:27:39 +03:00
static ssize_t onefs_sendfile ( vfs_handle_struct * handle , int tofd ,
files_struct * fromfsp , const DATA_BLOB * header ,
SMB_OFF_T offset , size_t count )
{
ssize_t result ;
START_PROFILE_BYTES ( syscall_sendfile , count ) ;
result = onefs_sys_sendfile ( handle - > conn , tofd , fromfsp - > fh - > fd ,
header , offset , count ) ;
END_PROFILE ( syscall_sendfile ) ;
return result ;
}
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 ;
}
2009-02-18 05:38:58 +03:00
static struct file_id onefs_file_id_create ( struct vfs_handle_struct * handle ,
SMB_STRUCT_STAT * sbuf )
{
struct file_id key ;
/* the ZERO_STRUCT ensures padding doesn't break using the key as a
* blob */
ZERO_STRUCT ( key ) ;
key . devid = sbuf - > st_dev ;
key . inode = sbuf - > st_ino ;
key . extid = sbuf - > st_snapid ;
return key ;
}
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 ;
2009-04-07 04:56:50 +04:00
struct connection_struct * conn = handle - > conn ;
2009-02-13 22:07:46 +03:00
struct stat_extra se ;
int result ;
2009-04-07 04:56:50 +04:00
char * unmangled_name = NULL ;
2009-02-13 22:07:46 +03:00
char * full_name = NULL ;
2009-04-07 04:56:50 +04:00
/* First demangle the name if necessary. */
if ( ! conn - > case_sensitive & & mangle_is_mangled ( name , conn - > params ) & &
mangle_lookup_name_from_8_3 ( mem_ctx , name , & unmangled_name ,
conn - > params ) ) {
/* Name is now unmangled. */
name = unmangled_name ;
}
/* Do the case insensitive stat. */
2009-02-13 22:07:46 +03:00
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 ) ;
2009-04-07 04:56:50 +04:00
TALLOC_FREE ( unmangled_name ) ;
2009-02-13 22:07:46 +03:00
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 )
{
2009-02-28 03:25:31 +03:00
uint32_t result = 0 ;
if ( ! lp_parm_bool ( SNUM ( handle - > conn ) , PARM_ONEFS_TYPE ,
PARM_IGNORE_STREAMS , PARM_IGNORE_STREAMS_DEFAULT ) ) {
result | = FILE_NAMED_STREAMS ;
}
return result | SMB_VFS_NEXT_FS_CAPABILITIES ( handle ) ;
2008-12-13 01:32:48 +03:00
}
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-21 00:27:39 +03:00
{ SMB_VFS_OP ( onefs_sendfile ) , SMB_VFS_OP_SENDFILE ,
SMB_VFS_LAYER_OPAQUE } ,
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 } ,
2009-02-18 05:38:58 +03:00
{ SMB_VFS_OP ( onefs_file_id_create ) , SMB_VFS_OP_FILE_ID_CREATE ,
SMB_VFS_LAYER_OPAQUE } ,
2008-12-13 01:32:48 +03:00
{ 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 } ,
2009-03-14 00:21:40 +03:00
{ SMB_VFS_OP ( onefs_strict_lock ) , SMB_VFS_OP_STRICT_LOCK ,
SMB_VFS_LAYER_OPAQUE } ,
{ SMB_VFS_OP ( onefs_strict_unlock ) , SMB_VFS_OP_STRICT_UNLOCK ,
SMB_VFS_LAYER_OPAQUE } ,
2009-02-21 00:25:17 +03:00
{ SMB_VFS_OP ( onefs_notify_watch ) , SMB_VFS_OP_NOTIFY_WATCH ,
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 ) ;
}