Added call out to a Linux-compatible fallocate() when we need to extend a file
authorJeremy Allison <jra@samba.org>
Tue, 21 Dec 2010 00:53:16 +0000 (16:53 -0800)
committerJeremy Allison <jra@samba.org>
Tue, 21 Dec 2010 01:41:23 +0000 (02:41 +0100)
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

source3/configure.in
source3/include/proto.h
source3/lib/system.c
source3/modules/vfs_default.c
source3/smbd/vfs.c

index b43d0b34de846545035b5df922c7e992a6257494..ed99b171918887b0695b4c327405642ffe5e13c5 100644 (file)
@@ -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,
index dabb3158753d302cce905c7046cdbcc8545d91b0..566b3f31dfa096c39af8b876aa7ed60bae3bdbbd 100644 (file)
@@ -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);
index 02322b72b51b56b7d0c9ca1c6f1c7be198ae1a22..4cf6a299daa11b96670ed3ed7e83b15af5ed2ce3 100644 (file)
@@ -694,6 +694,41 @@ int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
 #endif
 }
 
+/*******************************************************************
+ 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.
 ********************************************************************/
index e08d48ff5f0a7529cc5937d05d656e2628120d68..54f38c3714b5ee99567be7a23510a70bc687b949 100644 (file)
@@ -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);
index 2ebe2a10623c43f4291ff47374e75d8043d7afd5..802639f2fb352bcddf573798311b6f3a3d046e5a 100644 (file)
@@ -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. */