summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2010-12-20 16:53:16 -0800
committerJeremy Allison <jra@samba.org>2010-12-21 02:41:23 +0100
commit8998f4b01310e4b45e75d8d5f3260b5ba5c1cdf9 (patch)
tree21e648af9bd549f577ab8cbf59ebdeb89963cbd7
parent09aea038139f8717d38f0fdae6be9cf46bd86b15 (diff)
downloadsamba-8998f4b01310e4b45e75d8d5f3260b5ba5c1cdf9.tar.gz
samba-8998f4b01310e4b45e75d8d5f3260b5ba5c1cdf9.tar.bz2
samba-8998f4b01310e4b45e75d8d5f3260b5ba5c1cdf9.zip
Added call out to a Linux-compatible fallocate() when we need to extend a file
allocation extent without changing end-of-file size. Autobuild-User: Jeremy Allison <jra@samba.org> Autobuild-Date: Tue Dec 21 02:41:24 CET 2010 on sn-devel-104
-rw-r--r--source3/configure.in35
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/lib/system.c35
-rw-r--r--source3/modules/vfs_default.c5
-rw-r--r--source3/smbd/vfs.c13
5 files changed, 86 insertions, 3 deletions
diff --git a/source3/configure.in b/source3/configure.in
index b43d0b34de..ed99b17191 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -741,6 +741,7 @@ AC_CHECK_HEADERS(sys/syslog.h syslog.h)
AC_CHECK_HEADERS(langinfo.h locale.h)
AC_CHECK_HEADERS(xfs/libxfs.h)
AC_CHECK_HEADERS(netgroup.h)
+AC_CHECK_HEADERS(linux/falloc.h)
AC_CHECK_HEADERS(rpcsvc/yp_prot.h,,,[[
#if HAVE_RPC_RPC_H
@@ -1095,6 +1096,7 @@ AC_CHECK_FUNCS(sigprocmask sigblock sigaction sigset innetgr setnetgrent getnetg
AC_CHECK_FUNCS(initgroups select poll rdchk getgrnam getgrent pathconf)
AC_CHECK_FUNCS(setpriv setgidx setuidx setgroups sysconf stat64 fstat64)
AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt lseek64 ftruncate64 posix_fallocate posix_fallocate64)
+AC_CHECK_FUNCS(fallocate fallocate64)
AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid getpwanam)
AC_CHECK_FUNCS(opendir64 readdir64 seekdir64 telldir64 rewinddir64 closedir64)
AC_CHECK_FUNCS(getpwent_r)
@@ -2563,6 +2565,39 @@ fi
fi
# end utmp details
+AC_CACHE_CHECK([for linux fallocate],samba_cv_HAVE_LINUX_FALLOCATE,[
+AC_TRY_COMPILE([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#define _GNU_SOURCE
+#include <fcntl.h>
+#if defined(HAVE_LINUX_FALLOC_H)
+#include <linux/falloc.h>
+#endif],
+[int ret = fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 10);],
+samba_cv_HAVE_LINUX_FALLOCATE=yes,samba_cv_HAVE_LINUX_FALLOCATE=no)])
+if test x"$samba_cv_HAVE_LINUX_FALLOCATE" = x"yes" && test x"$ac_cv_func_fallocate" = x"yes"; then
+ AC_DEFINE(HAVE_LINUX_FALLOCATE,1,[Whether the Linux 'fallocate' function is available])
+fi
+
+AC_CACHE_CHECK([for linux fallocate64],samba_cv_HAVE_LINUX_FALLOCATE64,[
+AC_TRY_COMPILE([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#define _GNU_SOURCE
+#include <fcntl.h>
+#if defined(HAVE_LINUX_FALLOC_H)
+#include <linux/falloc.h>
+#endif],
+[int ret = fallocate64(0, FALLOC_FL_KEEP_SIZE, 0, 10);],
+samba_cv_HAVE_LINUX_FALLOCATE64=yes,samba_cv_HAVE_LINUX_FALLOCATE64=no)])
+if test x"$samba_cv_HAVE_LINUX_FALLOCATE64" = x"yes" && test x"$ac_cv_func_fallocate64" = x"yes"; then
+ AC_DEFINE(HAVE_LINUX_FALLOCATE64,1,[Whether the Linux 'fallocate64' function is available])
+fi
ICONV_LOOK_DIRS="/usr /usr/local /sw /opt"
AC_ARG_WITH(libiconv,
diff --git a/source3/include/proto.h b/source3/include/proto.h
index dabb315875..566b3f31df 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -888,6 +888,7 @@ int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
bool fake_dir_create_times);
int sys_ftruncate(int fd, SMB_OFF_T offset);
int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len);
+int sys_fallocate(int fd, enum vfs_fallocate_mode mode, SMB_OFF_T offset, SMB_OFF_T len);
SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence);
int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence);
SMB_OFF_T sys_ftell(FILE *fp);
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 02322b72b5..4cf6a299da 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -695,6 +695,41 @@ int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
}
/*******************************************************************
+ An fallocate() function that matches the semantics of the Linux one.
+********************************************************************/
+
+#ifdef HAVE_LINUX_FALLOC_H
+#include <linux/falloc.h>
+#endif
+
+int sys_fallocate(int fd, enum vfs_fallocate_mode mode, SMB_OFF_T offset, SMB_OFF_T len)
+{
+#if defined(HAVE_LINUX_FALLOCATE64) || defined(HAVE_LINUX_FALLOCATE)
+ int lmode;
+ switch (mode) {
+ case VFS_FALLOCATE_EXTEND_SIZE:
+ lmode = 0;
+ break;
+ case VFS_FALLOCATE_KEEP_SIZE:
+ lmode = FALLOC_FL_KEEP_SIZE;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LINUX_FALLOCATE64)
+ return fallocate64(fd, lmode, offset, len);
+#elif defined(HAVE_LINUX_FALLOCATE)
+ return fallocate(fd, lmode, offset, len);
+#endif
+#else
+ /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
+ 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 e08d48ff5f..54f38c3714 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -965,9 +965,10 @@ static int vfswrap_fallocate(vfs_handle_struct *handle,
START_PROFILE(syscall_fallocate);
if (mode == VFS_FALLOCATE_EXTEND_SIZE) {
result = sys_posix_fallocate(fsp->fh->fd, offset, len);
+ } else if (mode == VFS_FALLOCATE_KEEP_SIZE) {
+ result = sys_fallocate(fsp->fh->fd, mode, offset, len);
} else {
- /* TODO - implement call into Linux fallocate call. */
- errno = ENOSYS;
+ errno = EINVAL;
result = -1;
}
END_PROFILE(syscall_fallocate);
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 2ebe2a1062..802639f2fb 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -501,13 +501,24 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
return ret;
}
+ if (!lp_strict_allocate(SNUM(fsp->conn)))
+ return 0;
+
/* Grow - we need to test if we have enough space. */
contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+
+ /* See if we have a syscall that will allocate beyond end-of-file
+ without changing EOF. */
+ ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_KEEP_SIZE, 0, len);
+
contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
- if (!lp_strict_allocate(SNUM(fsp->conn)))
+ if (ret == 0) {
+ /* We changed the allocation size on disk, but not
+ EOF - exactly as required. We're done ! */
return 0;
+ }
len -= fsp->fsp_name->st.st_ex_size;
len /= 1024; /* Len is now number of 1k blocks needed. */