s3:locking: add share_mode_do_locked_vfs_{denied,allowed}()
authorStefan Metzmacher <metze@samba.org>
Thu, 18 Aug 2022 11:26:47 +0000 (13:26 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 20 Sep 2022 00:34:35 +0000 (00:34 +0000)
These function will add an abstraction to protect
a function that is not allowed to call vfs functions
or allow vfs functions to be called.

Currently these are implemented similar,
but we'll optimize them in the next commits.

The idea is that share_mode_do_locked_vfs_denied()
will be able to run fast enough in order to run
under a tdb chainlock (just a pthread mutex).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15125

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/locking/share_mode_lock.c
source3/locking/share_mode_lock.h

index 58ce1d0442ef14bc10a2723257deeadaba479164..89b9d1dd2d2d5d879dd011b757c263d8b8f48c42 100644 (file)
@@ -2602,3 +2602,80 @@ done:
        TALLOC_FREE(ltdb);
        return ret;
 }
+
+/**
+ * @brief Run @fn protected with G_LOCK_WRITE in the given file_id
+ *
+ * @fn is NOT allowed to call SMB_VFS_* or similar functions,
+ * which may block for some time in the kernel.
+ *
+ * There must be at least one share_mode_entry, otherwise
+ * NT_STATUS_NOT_FOUND is returned.
+ *
+ * @param[in]  id           The key for the share_mode record.
+ * @param[in]  fn           The function to run under the g_lock.
+ * @param[in]  private_date A private pointer passed to @fn.
+ */
+NTSTATUS _share_mode_do_locked_vfs_denied(
+       struct file_id id,
+       share_mode_do_locked_vfs_fn_t fn,
+       void *private_data,
+       const char *location)
+{
+       struct smb_vfs_deny_state vfs_deny = {};
+       struct share_mode_lock *lck = NULL;
+
+       lck = get_existing_share_mode_lock(talloc_tos(), id);
+       if (lck == NULL) {
+               NTSTATUS status = NT_STATUS_NOT_FOUND;
+               DBG_DEBUG("get_existing_share_mode_lock failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       _smb_vfs_deny_push(&vfs_deny, location);
+       fn(lck, private_data);
+       _smb_vfs_deny_pop(&vfs_deny, location);
+
+       TALLOC_FREE(lck);
+
+       return NT_STATUS_OK;
+}
+
+/**
+ * @brief Run @fn protected with G_LOCK_WRITE in the given file_id
+ *
+ * @fn is allowed to call SMB_VFS_* or similar functions,
+ * which may block for some time in the kernel.
+ *
+ * There must be at least one share_mode_entry, otherwise
+ * NT_STATUS_NOT_FOUND is returned.
+ *
+ * @param[in]  id           The key for the share_mode record.
+ * @param[in]  fn           The function to run under the g_lock.
+ * @param[in]  private_date A private pointer passed to @fn.
+ */
+NTSTATUS _share_mode_do_locked_vfs_allowed(
+       struct file_id id,
+       share_mode_do_locked_vfs_fn_t fn,
+       void *private_data,
+       const char *location)
+{
+       struct share_mode_lock *lck = NULL;
+
+       smb_vfs_assert_allowed();
+
+       lck = get_existing_share_mode_lock(talloc_tos(), id);
+       if (lck == NULL) {
+               NTSTATUS status = NT_STATUS_NOT_FOUND;
+               DBG_DEBUG("get_existing_share_mode_lock failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       fn(lck, private_data);
+
+       TALLOC_FREE(lck);
+
+       return NT_STATUS_OK;
+}
index 4f47b6fbcbe5203cd719eda3d6e710f889a6120b..c02058634ac83409aec278f192abdea37f32cdff 100644 (file)
@@ -137,4 +137,22 @@ NTSTATUS share_mode_watch_recv(
        struct tevent_req *req, bool *blockerdead, struct server_id *blocker);
 NTSTATUS share_mode_wakeup_waiters(struct file_id id);
 
+typedef void (*share_mode_do_locked_vfs_fn_t)(
+               struct share_mode_lock *lck,
+               void *private_data);
+NTSTATUS _share_mode_do_locked_vfs_denied(
+       struct file_id id,
+       share_mode_do_locked_vfs_fn_t fn,
+       void *private_data,
+       const char *location);
+#define share_mode_do_locked_vfs_denied(__id, __fn, __private_data) \
+       _share_mode_do_locked_vfs_denied(__id, __fn, __private_data, __location__)
+NTSTATUS _share_mode_do_locked_vfs_allowed(
+       struct file_id id,
+       share_mode_do_locked_vfs_fn_t fn,
+       void *private_data,
+       const char *location);
+#define share_mode_do_locked_vfs_allowed(__id, __fn, __private_data) \
+       _share_mode_do_locked_vfs_allowed(__id, __fn, __private_data, __location__)
+
 #endif