Fix bug #7835 - vfs_fill_sparse() doesn't use posix_fallocate when strict allocate...
authorJeremy Allison <jra@samba.org>
Thu, 2 Dec 2010 23:38:36 +0000 (15:38 -0800)
committerJeremy Allison <jra@samba.org>
Thu, 2 Dec 2010 23:38:36 +0000 (15:38 -0800)
Tries posix_fallocate() and then falls back to old code.

Jeremy.

source3/smbd/vfs.c

index 7042518ce203c49e6825dbbe322856724453c322..8757682242ca0b3f14b6bf4a9551b9b319f33cc8 100644 (file)
@@ -584,6 +584,12 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
                return 0;
        }
 
+#ifdef S_ISFIFO
+       if (S_ISFIFO(st.st_ex_mode)) {
+               return 0;
+       }
+#endif
+
        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,
@@ -593,6 +599,30 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
 
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
+       offset = st.st_ex_size;
+       num_to_write = len - st.st_ex_size;
+
+       /* Only do this on non-stream file handles. */
+       if (fsp->base_fsp == NULL) {
+               /* for allocation try posix_fallocate first. This can fail on some
+                * platforms e.g. when the filesystem doesn't support it and no
+                * emulation is being done by the libc (like on AIX with JFS1). In that
+                * case we do our own emulation. posix_fallocate implementations can
+                * return ENOTSUP or EINVAL in cases like that. */
+               ret = sys_posix_fallocate(fsp->fh->fd, offset, num_to_write);
+               if (ret == ENOSPC) {
+                       errno = ENOSPC;
+                       ret = -1;
+                       goto out;
+               }
+               if (ret == 0) {
+                       set_filelen_write_cache(fsp, len);
+                       goto out;
+               }
+               DEBUG(10,("vfs_fill_sparse: sys_posix_fallocate failed with "
+                       "error %d. Falling back to slow manual allocation\n", ret));
+       }
+
        if (!sparse_buf) {
                sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
                if (!sparse_buf) {
@@ -602,8 +632,6 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
                }
        }
 
-       offset = st.st_ex_size;
-       num_to_write = len - st.st_ex_size;
        total = 0;
 
        while (total < num_to_write) {