Fix bug #7835 - vfs_fill_sparse() doesn't use posix_fallocate when strict allocate...
authorJeremy Allison <jra@samba.org>
Thu, 2 Dec 2010 23:27:17 +0000 (15:27 -0800)
committerKarolin Seeger <kseeger@samba.org>
Sun, 5 Dec 2010 18:25:05 +0000 (19:25 +0100)
Tries posix_fallocate() and then falls back to old code.

Jeremy.

source3/smbd/vfs.c

index 00cf1e5af47332693090cddbb07baadfbd5daddc..c939044eed54573c2b64d46f605cd413a11d40ca 100644 (file)
@@ -582,6 +582,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,
@@ -591,6 +597,32 @@ 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) {
@@ -600,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) {