vfs_prealloc: implement SMB_VFS_OPENAT()
authorRalph Boehme <slow@samba.org>
Wed, 20 May 2020 19:46:41 +0000 (21:46 +0200)
committerJeremy Allison <jra@samba.org>
Thu, 21 May 2020 20:38:33 +0000 (20:38 +0000)
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/vfs_prealloc.c

index 04e77a3412babb06911a3176577e62cc9d3f9dd5..cf3019c588a9a3dfe1d6b2e03dbe2a9936381b26 100644 (file)
@@ -192,6 +192,92 @@ normal_open:
        return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
 }
 
+static int prealloc_openat(struct vfs_handle_struct* handle,
+                          const struct files_struct *dirfsp,
+                          const struct smb_filename *smb_fname,
+                          files_struct *fsp,
+                          int flags,
+                          mode_t mode)
+{
+       int fd;
+       off_t size = 0;
+       const char * dot;
+       char fext[10];
+
+       if (!(flags & (O_CREAT|O_TRUNC))) {
+               /* Caller is not intending to rewrite the file. Let's not mess
+                * with the allocation in this case.
+                */
+               goto normal_open;
+       }
+
+       *fext = '\0';
+       dot = strrchr(smb_fname->base_name, '.');
+       if (dot && *++dot) {
+               if (strlen(dot) < sizeof(fext)) {
+                       strncpy(fext, dot, sizeof(fext));
+                       if (!strnorm(fext, CASE_LOWER)) {
+                               goto normal_open;
+                       }
+               }
+       }
+
+       if (*fext == '\0') {
+               goto normal_open;
+       }
+
+       /* Syntax for specifying preallocation size is:
+        *      MODULE: <extension> = <size>
+        * where
+        *      <extension> is the file extension in lower case
+        *      <size> is a size like 10, 10K, 10M
+        */
+       size = conv_str_size(lp_parm_const_string(SNUM(handle->conn), MODULE,
+                                                   fext, NULL));
+       if (size <= 0) {
+               /* No need to preallocate this file. */
+               goto normal_open;
+       }
+
+       fd = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
+       if (fd < 0) {
+               return fd;
+       }
+
+       /* Prellocate only if the file is being created or replaced. Note that
+        * Samba won't ever pass down O_TRUNC, which is why we have to handle
+        * truncate calls specially.
+        */
+       if ((flags & O_CREAT) || (flags & O_TRUNC)) {
+               off_t * psize;
+
+               psize = VFS_ADD_FSP_EXTENSION(handle, fsp, off_t, NULL);
+               if (psize == NULL || *psize == -1) {
+                       return fd;
+               }
+
+               DEBUG(module_debug,
+                       ("%s: preallocating %s (fd=%d) to %lld bytes\n",
+                           MODULE, smb_fname_str_dbg(smb_fname), fd,
+                           (long long)size));
+
+               *psize = size;
+               if (preallocate_space(fd, *psize) < 0) {
+                       VFS_REMOVE_FSP_EXTENSION(handle, fsp);
+               }
+       }
+
+       return fd;
+
+normal_open:
+       /* We are not creating or replacing a file. Skip the
+        * preallocation.
+        */
+       DEBUG(module_debug, ("%s: skipping preallocation for %s\n",
+               MODULE, smb_fname_str_dbg(smb_fname)));
+       return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
+}
+
 static int prealloc_ftruncate(vfs_handle_struct * handle,
                        files_struct *  fsp,
                        off_t   offset)
@@ -209,6 +295,7 @@ static int prealloc_ftruncate(vfs_handle_struct * handle,
 
 static struct vfs_fn_pointers prealloc_fns = {
        .open_fn = prealloc_open,
+       .openat_fn = prealloc_openat,
        .ftruncate_fn = prealloc_ftruncate,
        .connect_fn = prealloc_connect,
 };