vfs_default: Use openat2(RESOLVE_NO_SYMLINKS) if available
authorVolker Lendecke <vl@samba.org>
Fri, 17 Jun 2022 15:41:52 +0000 (17:41 +0200)
committerVolker Lendecke <vl@samba.org>
Mon, 15 Aug 2022 15:03:37 +0000 (15:03 +0000)
This improves the following test:

 time smbtorture //127.0.0.1/m -Uroot%test \
        smb2.create.bench-path-contention-shared \
        --option='torture:bench_path=Apps\1\2\3\4\5\6\7\8\9\10' \
        --option="torture:timelimit=600" \
        --option="torture:nprocs=1"

From:

   open[num/s=14186,avslat=0.000044,minlat=0.000042,maxlat=0.000079]
   close[num/s=14185,avslat=0.000027,minlat=0.000025,maxlat=0.000057]

to:

   open[num/s=16917,avslat=0.000038,minlat=0.000035,maxlat=0.000340]
   close[num/s=16916,avslat=0.000020,minlat=0.000019,maxlat=0.000104]

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
source3/modules/vfs_default.c

index 847eddd8991f7b7750df3aa116dde399c1dc9fc1..48ff174ebbe8dd67cd3998d4a7563af7e687f752 100644 (file)
 
 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
 {
+       bool bval;
+
        handle->conn->have_proc_fds = sys_have_proc_fds();
+
+       /*
+        * assume the kernel will support openat2(),
+        * it will be reset on the first ENOSYS.
+        *
+        * Note that libreplace will always provide openat2(),
+        * but return -1/errno = ENOSYS...
+        *
+        * The option is only there to test the fallback code.
+        */
+       bval = lp_parm_bool(SNUM(handle->conn),
+                           "vfs_default",
+                           "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
+                           true);
+       if (bval) {
+               handle->conn->open_how_resolve |=
+                       VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+       }
+
        return 0;    /* Return >= 0 for success */
 }
 
@@ -701,7 +722,7 @@ static int vfswrap_openat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_openat);
 
-       if (how->resolve != 0) {
+       if (how->resolve & ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
                errno = ENOSYS;
                result = -1;
                goto out;
@@ -734,6 +755,35 @@ static int vfswrap_openat(vfs_handle_struct *handle,
        }
 #endif
 
+       if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
+               struct open_how linux_how = {
+                       .flags = flags,
+                       .mode = mode,
+                       .resolve = RESOLVE_NO_SYMLINKS,
+               };
+
+               result = openat2(fsp_get_pathref_fd(dirfsp),
+                                smb_fname->base_name,
+                                &linux_how,
+                                sizeof(linux_how));
+               if (result == -1) {
+                       if (errno == ENOSYS) {
+                               /*
+                                * The kernel doesn't support
+                                * openat2(), so indicate to
+                                * the callers that
+                                * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
+                                * would just be a waste of time.
+                                */
+                               fsp->conn->open_how_resolve &=
+                                       ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+                       }
+                       goto out;
+               }
+
+               goto done;
+       }
+
        if (fsp->fsp_flags.is_pathref && !have_opath) {
                become_root();
                became_root = true;
@@ -748,6 +798,7 @@ static int vfswrap_openat(vfs_handle_struct *handle,
                unbecome_root();
        }
 
+done:
        fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
 
 out: