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 00:58:14 +0000 (16:58 -0800)
allocation extent without changing end-of-file size.
(cherry picked from commit 00d2d16262909fde2c144a504d7d554767b7fd45)

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

index 5f81a193ca8ed5e0fb9f48bc5ce11d010ee3308f..c772f58b0dc2ccc3c6b559ba06bda55b8d12c692 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 e26f43e7471c5d385161c6e04cd4c8f0a8af8234..8b2ba95b7de84deb1c73fa430e4e28ba075017f5 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 1c00ad87e4de092268dafde831c82150de51b645..d5b833c2c8b277701f0c5109e20ac0fe38d15ba9 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 ee70a3d583f3f3da64ed076dd77c3bdd834f6a07..9f9b067ca22f87e32c5eb43c2e6c38112ec935ac 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. */