From 83df10a56f455dcf4efc5a2e38d504bd252063e3 Mon Sep 17 00:00:00 2001 From: Olaf Flebbe Date: Tue, 1 Dec 2009 15:44:38 +0100 Subject: [PATCH] Use fallocate to handle strict allocate = partial in order not to fragment files for CIFS write ahead mode --- source3/include/local.h | 4 ++ source3/include/proto.h | 4 +- source3/include/smb.h | 6 ++ source3/include/vfs.h | 6 ++- source3/include/vfs_macros.h | 5 ++ source3/lib/system.c | 8 ++- source3/modules/vfs_default.c | 103 +++++++++++++++++++++++++++++++++++++- source3/modules/vfs_full_audit.c | 16 ++++++ source3/param/loadparm.c | 27 ++++++++-- source3/smbd/aio.c | 48 +++++++++++++++++- source3/smbd/fileio.c | 5 +- source3/smbd/globals.c | 1 - source3/smbd/globals.h | 1 - source3/smbd/vfs.c | 54 +++++++------------ 14 files changed, 236 insertions(+), 52 deletions(-) diff --git a/source3/include/local.h b/source3/include/local.h index de54ea5..03c4c74 100644 --- a/source3/include/local.h +++ b/source3/include/local.h @@ -271,6 +271,10 @@ /* Windows minimum lock resolution timeout in ms */ #define WINDOWS_MINIMUM_LOCK_TIMEOUT_MS 200 +/* When strict allocate = partial, define the limit on how far + * ahead we will write. */ +#define STRICT_ALLOCATE_PARTIAL_LIMIT 0x200000 + /* Maximum size of RPC data we will accept for one call. */ #define MAX_RPC_DATA_SIZE (15*1024*1024) diff --git a/source3/include/proto.h b/source3/include/proto.h index 7b575ca..2617e46 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -4189,7 +4189,7 @@ bool lp_manglednames(const struct share_params *p ); bool lp_widelinks(int ); bool lp_symlinks(int ); bool lp_syncalways(int ); -bool lp_strict_allocate(int ); +int lp_strict_allocate(int ); bool lp_strict_sync(int ); bool lp_map_system(int ); bool lp_delete_readonly(int ); @@ -7118,7 +7118,7 @@ ssize_t vfs_pwrite_data(struct smb_request *req, SMB_OFF_T offset); int vfs_allocate_file_space(files_struct *fsp, uint64_t len); int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len); -int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len); +int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len, enum smb_strict_allocate_options sa_options); SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n); const char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf, char **talloced); diff --git a/source3/include/smb.h b/source3/include/smb.h index 4affd4a..3479397 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1938,6 +1938,12 @@ struct smb_extended_info { char samba_version_string[SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH]; }; +enum smb_strict_allocate_options { + STRICT_ALLOCATE_OFF=0, + STRICT_ALLOCATE_ON=1, + STRICT_ALLOCATE_PARTIAL=2 +}; + /* time info */ struct smb_file_time { struct timespec mtime; diff --git a/source3/include/vfs.h b/source3/include/vfs.h index aee84a7..0541754 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -125,7 +125,8 @@ * return to fs_capabilities call. JRA. */ /* Leave at 27 - not yet released. Add translate_name VFS call to convert UNIX names to Windows supported names -- asrinivasan. */ -#define SMB_VFS_INTERFACE_VERSION 27 +/* Changed to 28 - add fallocate: oflebbe */ +#define SMB_VFS_INTERFACE_VERSION 28 /* to bug old modules which are trying to compile with the old functions */ @@ -246,6 +247,7 @@ struct vfs_fn_pointers { const struct smb_filename *smb_fname, struct smb_file_time *ft); int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset); + int (*fallocate)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset, SMB_OFF_T len); bool (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type); int (*kernel_flock)(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 share_mode, uint32_t access_mask); @@ -597,6 +599,8 @@ int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, struct smb_file_time *ft); int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset); +int smb_vfs_call_fallocate(struct vfs_handle_struct *handle, + struct files_struct *fsp, SMB_OFF_T offset, SMB_OFF_T len); bool smb_vfs_call_lock(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index c6f83bd..53fe505 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -245,6 +245,11 @@ #define SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset) \ smb_vfs_call_ftruncate((handle)->next, (fsp), (offset)) +#define SMB_VFS_FALLOCATE(fsp, offset, len) \ + smb_vfs_call_fallocate((fsp)->conn->vfs_handles, (fsp), (offset), (len)) +#define SMB_VFS_NEXT_FALLOCATE(handle, fsp, offset, len) \ + smb_vfs_call_fallocate((handle)->next, (fsp), (offset), (len)) + #define SMB_VFS_LOCK(fsp, op, offset, count, type) \ smb_vfs_call_lock((fsp)->conn->vfs_handles, (fsp), (op), (offset), (count), (type)) #define SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type) \ diff --git a/source3/lib/system.c b/source3/lib/system.c index a2dd899..dbacb73 100644 --- a/source3/lib/system.c +++ b/source3/lib/system.c @@ -621,16 +621,20 @@ int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf, /******************************************************************* An posix_fallocate() wrapper that will deal with 64 bit filesizes. ********************************************************************/ -#if (defined(HAVE_POSIX_FALLOCATE64) || defined(HAVE_POSIX_FALLOCATE)) && !defined(HAVE_BROKEN_POSIX_FALLOCATE) int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len) { +#if (defined(HAVE_POSIX_FALLOCATE64) || defined(HAVE_POSIX_FALLOCATE)) && !defined(HAVE_BROKEN_POSIX_FALLOCATE) #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) return posix_fallocate64(fd, offset, len); #else return posix_fallocate(fd, offset, len); #endif -} +#else + /* No posix_fallocate System Call */ + errno = ENOSYS; + return -1; #endif +} /******************************************************************* An ftruncate() wrapper that will deal with 64 bit filesizes. diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 3691fb0..2826652 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -997,10 +997,14 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_O SMB_STRUCT_STAT st; char c = 0; SMB_OFF_T currpos; + enum smb_strict_allocate_options sa_options = lp_strict_allocate(SNUM(fsp->conn)); START_PROFILE(syscall_ftruncate); - if (lp_strict_allocate(SNUM(fsp->conn))) { + /* Only use allocation truncate if strict allocate + * is set "on", not off or partial. + */ + if (sa_options == STRICT_ALLOCATE_ON) { result = strict_allocate_ftruncate(handle, fsp, len); END_PROFILE(syscall_ftruncate); return result; @@ -1028,7 +1032,7 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_O size in which case the ftruncate above should have succeeded or shorter, in which case seek to len - 1 and write 1 byte of zero */ - if (SMB_VFS_FSTAT(fsp, &st) == -1) { + if (SMB_VFS_FSTAT(fsp, &st) == -1) { goto done; } @@ -1066,6 +1070,100 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_O return result; } +#define SPARSE_BUF_WRITE_SIZE (32*1024) +static char *sparse_buf = NULL; + +static int vfswrap_fallocate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T offset, SMB_OFF_T len) +{ + int result = -1; + SMB_STRUCT_STAT st; + char c = 0; + SMB_OFF_T currpos; + SMB_OFF_T total, pwrite_ret; + + START_PROFILE(syscall_fallocate); + + result = sys_posix_fallocate(fsp->fh->fd, offset, len); + if (result == 0) + goto done; + + /* double check for invalid parameters */ + if (len <= 0 || offset < 0) { + result = 0; + goto done; + } + + if (SMB_VFS_FSTAT(fsp, &st) == -1) { + goto done; + } + +#ifdef S_ISFIFO + if (S_ISFIFO(st.st_ex_mode)) { + result = 0; + goto done; + } +#endif + + /* be cautious! if file already larger: NOP */ + if (st.st_ex_size >= offset + len) { + result = 0; + goto done; + } + + if (!sparse_buf) { + sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE); + if (!sparse_buf) { + errno = ENOMEM; + result = -1; + goto done; + } + } + + /* check if offset is within the current file */ + if(st.st_ex_size > offset) { + /* already checked, len could not be negative */ + len -= (st.st_ex_size - offset) - 1; + /* position one byte behind eof */ + offset = st.st_ex_size + 1; + } + + currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); + if (currpos == -1) { + goto done; + } + + total = 0; + + while (total < len) { + size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (len - total)); + + pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total); + if (pwrite_ret == -1) { + DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file " + "%s failed with error %s\n", + fsp_str_dbg(fsp), strerror(errno))); + result = -1; + goto done; + } + if (pwrite_ret == 0) { + result = 0; + goto done; + } + + total += pwrite_ret; + } + + /* Seek to where we were */ + if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos) + goto done; + result = 0; + + done: + + END_PROFILE(syscall_ftruncate); + return result; +} + static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { bool result; @@ -1736,6 +1834,7 @@ static struct vfs_fn_pointers vfs_default_fns = { .getwd = vfswrap_getwd, .ntimes = vfswrap_ntimes, .ftruncate = vfswrap_ftruncate, + .fallocate = vfswrap_fallocate, .lock = vfswrap_lock, .kernel_flock = vfswrap_kernel_flock, .linux_setlease = vfswrap_linux_setlease, diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 19ac7ad..10f9713 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -123,6 +123,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_GETWD, SMB_VFS_OP_NTIMES, SMB_VFS_OP_FTRUNCATE, + SMB_VFS_OP_FALLOCATE, SMB_VFS_OP_LOCK, SMB_VFS_OP_KERNEL_FLOCK, SMB_VFS_OP_LINUX_SETLEASE, @@ -261,6 +262,7 @@ static struct { { SMB_VFS_OP_GETWD, "getwd" }, { SMB_VFS_OP_NTIMES, "ntimes" }, { SMB_VFS_OP_FTRUNCATE, "ftruncate" }, + { SMB_VFS_OP_FALLOCATE, "fallocate" }, { SMB_VFS_OP_LOCK, "lock" }, { SMB_VFS_OP_KERNEL_FLOCK, "kernel_flock" }, { SMB_VFS_OP_LINUX_SETLEASE, "linux_setlease" }, @@ -1231,6 +1233,19 @@ static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp return result; } +static int smb_full_audit_fallocate(vfs_handle_struct *handle, files_struct *fsp, + SMB_OFF_T offset, SMB_OFF_T len) +{ + int result; + + result = SMB_VFS_NEXT_FALLOCATE(handle, fsp, offset, len); + + do_log(SMB_VFS_OP_FTRUNCATE, (result >= 0), handle, + "%s", fsp_str_do_log(fsp)); + + return result; +} + static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { @@ -2227,6 +2242,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = { .getwd = smb_full_audit_getwd, .ntimes = smb_full_audit_ntimes, .ftruncate = smb_full_audit_ftruncate, + .fallocate = smb_full_audit_fallocate, .lock = smb_full_audit_lock, .kernel_flock = smb_full_audit_kernel_flock, .linux_setlease = smb_full_audit_linux_setlease, diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 0499d65..33b0afb 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -464,7 +464,7 @@ struct service { bool bWidelinks; bool bSymlinks; bool bSyncAlways; - bool bStrictAllocate; + int iStrictAllocate; bool bStrictSync; char magic_char; struct bitmap *copymap; @@ -608,7 +608,7 @@ static struct service sDefault = { True, /* bWidelinks */ True, /* bSymlinks */ False, /* bSyncAlways */ - False, /* bStrictAllocate */ + STRICT_ALLOCATE_OFF, /* iStrictAllocate */ False, /* bStrictSync */ '~', /* magic char */ NULL, /* copymap */ @@ -892,6 +892,21 @@ static const struct enum_list enum_kerberos_method[] = { {-1, NULL} }; +static const struct enum_list enum_strict_allocate[] = { + {STRICT_ALLOCATE_OFF, "No"}, + {STRICT_ALLOCATE_OFF, "False"}, + {STRICT_ALLOCATE_OFF, "0"}, + {STRICT_ALLOCATE_OFF, "Off"}, + {STRICT_ALLOCATE_OFF, "disabled"}, + {STRICT_ALLOCATE_ON, "Yes"}, + {STRICT_ALLOCATE_ON, "True"}, + {STRICT_ALLOCATE_ON, "1"}, + {STRICT_ALLOCATE_ON, "On"}, + {STRICT_ALLOCATE_ON, "enabled"}, + {STRICT_ALLOCATE_PARTIAL, "partial"}, + {-1, NULL} +}; + /* Note: We do not initialise the defaults union - it is not allowed in ANSI C * * The FLAG_HIDE is explicit. Parameters set this way do NOT appear in any edit @@ -2444,11 +2459,11 @@ static struct parm_struct parm_table[] = { }, { .label = "strict allocate", - .type = P_BOOL, + .type = P_ENUM, .p_class = P_LOCAL, - .ptr = &sDefault.bStrictAllocate, + .ptr = &sDefault.iStrictAllocate, .special = NULL, - .enum_list = NULL, + .enum_list = enum_strict_allocate, .flags = FLAG_ADVANCED | FLAG_SHARE, }, { @@ -5637,7 +5652,7 @@ FN_LOCAL_PARM_BOOL(lp_manglednames, bMangledNames) FN_LOCAL_BOOL(lp_widelinks, bWidelinks) FN_LOCAL_BOOL(lp_symlinks, bSymlinks) FN_LOCAL_BOOL(lp_syncalways, bSyncAlways) -FN_LOCAL_BOOL(lp_strict_allocate, bStrictAllocate) +FN_LOCAL_INTEGER(lp_strict_allocate, iStrictAllocate) FN_LOCAL_BOOL(lp_strict_sync, bStrictSync) FN_LOCAL_BOOL(lp_map_system, bMap_system) FN_LOCAL_BOOL(lp_delete_readonly, bDeleteReadonly) diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index 751fed1..b2a73b6 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -1,3 +1,4 @@ + /* Unix SMB/Netbios implementation. Version 3.0 @@ -207,8 +208,10 @@ bool schedule_aio_write_and_X(connection_struct *conn, { struct aio_extra *aio_ex; SMB_STRUCT_AIOCB *a; + SMB_STRUCT_STAT st; size_t bufsize; bool write_through = BITSETW(req->vwv+7,0); + bool other_aio_found; size_t min_aio_write_size = lp_aio_write_size(SNUM(conn)); int ret; @@ -229,7 +232,7 @@ bool schedule_aio_write_and_X(connection_struct *conn, } /* Only do this on non-chained and non-chaining reads not using the - * write cache. */ + write cache. */ if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) { return False; } @@ -247,6 +250,49 @@ bool schedule_aio_write_and_X(connection_struct *conn, return False; } + other_aio_found = false; + /* Make sure there are no outstanding aio writes on same fsp */ + for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) { + if (fsp == aio_ex->fsp) { + /* Don't do sparse file detection if other */ + /* aio statements are outstanding */ + /* this should not happen! */ + other_aio_found = true; + break; + } + } + + if (!other_aio_found) { + ret = SMB_VFS_FSTAT(fsp, &st); + if (ret == -1) { + /* This should not happen, fall back to synchronous */ + return False; + } + + if (startpos > st.st_ex_size) { + /* Writing beyond end of file + potentially creating a gap */ + + enum smb_strict_allocate_options sa_options = + lp_strict_allocate(SNUM(fsp->conn)); + + /* let a synchronous write handle filling + the sparse file */ + if (sa_options == STRICT_ALLOCATE_ON) + return False; + + /* If strict allocate is set to "partial", + ignore all allocate requests over the + STRICT_ALLOCATE_PARTIAL_LIMIT. */ + + if ((sa_options == STRICT_ALLOCATE_PARTIAL) && + (startpos - st.st_ex_size < + STRICT_ALLOCATE_PARTIAL_LIMIT)) { + return False; + } + } + } + bufsize = smb_size + 6*2; if (!(aio_ex = create_aio_extra(fsp, bufsize))) { diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 1c27fef..3f6dfbe 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -126,9 +126,10 @@ static ssize_t real_write_file(struct smb_request *req, if (pos == -1) { ret = vfs_write_data(req, fsp, data, n); } else { + enum smb_strict_allocate_options sa_options = lp_strict_allocate(SNUM(fsp->conn)); fsp->fh->pos = pos; - if (pos && lp_strict_allocate(SNUM(fsp->conn))) { - if (vfs_fill_sparse(fsp, pos) == -1) { + if (pos && (sa_options != STRICT_ALLOCATE_OFF)) { + if (vfs_fill_sparse(fsp, pos, sa_options) == -1) { return -1; } } diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c index 68fa795..bd792ad 100644 --- a/source3/smbd/globals.c +++ b/source3/smbd/globals.c @@ -121,7 +121,6 @@ struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH]; int conn_ctx_stack_ndx = 0; struct vfs_init_function_entry *backends = NULL; -char *sparse_buf = NULL; char *LastDir = NULL; /* Current number of oplocks we have outstanding. */ diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 0db61f8..5de1fcc 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -130,7 +130,6 @@ extern int conn_ctx_stack_ndx; struct vfs_init_function_entry; extern struct vfs_init_function_entry *backends; -extern char *sparse_buf; extern char *LastDir; /* Current number of oplocks we have outstanding. */ diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 2ce61ee..3c9454a 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -503,8 +503,9 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW); contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW); - if (!lp_strict_allocate(SNUM(fsp->conn))) + if (lp_strict_allocate(SNUM(fsp->conn)) == STRICT_ALLOCATE_OFF) { return 0; + } len -= st.st_ex_size; len /= 1024; /* Len is now number of 1k blocks needed. */ @@ -562,9 +563,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) Returns 0 on success, -1 on failure. ****************************************************************************/ -#define SPARSE_BUF_WRITE_SIZE (32*1024) -int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) +int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len, enum smb_strict_allocate_options sa_options) { int ret; SMB_STRUCT_STAT st; @@ -582,6 +582,14 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) return 0; } + /* If strict allocate is set to "partial", ignore all allocate + * requests over the STRICT_ALLOCATE_PARTIAL_LIMIT. */ + + if ((sa_options == STRICT_ALLOCATE_PARTIAL) && + (len - st.st_ex_size > STRICT_ALLOCATE_PARTIAL_LIMIT)) { + return 0; + } + DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to " "len %.0f (%.0f bytes)\n", fsp_str_dbg(fsp), (double)st.st_ex_size, (double)len, @@ -591,37 +599,7 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) flush_write_cache(fsp, SIZECHANGE_FLUSH); - if (!sparse_buf) { - sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE); - if (!sparse_buf) { - errno = ENOMEM; - ret = -1; - goto out; - } - } - - offset = st.st_ex_size; - num_to_write = len - st.st_ex_size; - total = 0; - - while (total < num_to_write) { - size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total)); - - pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total); - if (pwrite_ret == -1) { - DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file " - "%s failed with error %s\n", - fsp_str_dbg(fsp), strerror(errno))); - ret = -1; - goto out; - } - if (pwrite_ret == 0) { - ret = 0; - goto out; - } - - total += pwrite_ret; - } + SMB_VFS_FALLOCATE( fsp, st.st_ex_size, len); set_filelen_write_cache(fsp, len); @@ -1438,6 +1416,14 @@ int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle, return handle->fns->ftruncate(handle, fsp, offset); } +int smb_vfs_call_fallocate(struct vfs_handle_struct *handle, + struct files_struct *fsp, SMB_OFF_T offset, + SMB_OFF_T len) +{ + VFS_FIND(fallocate); + return handle->fns->fallocate(handle, fsp, offset, len); +} + int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 share_mode, uint32_t access_mask) -- 1.6.0.2