P6.X: add SMB_VFS_[NEXT_]IO_READ_SEND/RECV
authorStefan Metzmacher <metze@samba.org>
Thu, 1 Oct 2020 13:51:37 +0000 (15:51 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 16 Oct 2023 11:03:51 +0000 (13:03 +0200)
examples/VFS/skel_opaque.c
examples/VFS/skel_transparent.c
source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_default.c
source3/modules/vfs_full_audit.c
source3/modules/vfs_not_implemented.c
source3/modules/vfs_time_audit.c
source3/smbd/vfs.c

index 255fa830402e5e854ec8771bfc74609a36eab1d2..1e5c73212902764aa26f9c95df7fc61fbbbd43fe 100644 (file)
@@ -294,6 +294,23 @@ static ssize_t skel_recvfile(vfs_handle_struct *handle, int fromfd,
        return -1;
 }
 
+static struct tevent_req *skel_io_read_send(struct vfs_handle_struct *handle,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct files_struct *fsp,
+                                           struct smb_vfs_io *io,
+                                           size_t n, off_t offset)
+{
+       return NULL;
+}
+
+static ssize_t skel_io_read_recv(struct tevent_req *req,
+                                struct vfs_aio_state *vfs_aio_state)
+{
+       vfs_aio_state->error = ENOSYS;
+       return -1;
+}
+
 static int skel_renameat(vfs_handle_struct *handle,
                       files_struct *srcfsp,
                       const struct smb_filename *smb_fname_src,
@@ -1000,6 +1017,8 @@ static struct vfs_fn_pointers skel_opaque_fns = {
        .lseek_fn = skel_lseek,
        .sendfile_fn = skel_sendfile,
        .recvfile_fn = skel_recvfile,
+       .io_read_send_fn = skel_io_read_send,
+       .io_read_recv_fn = skel_io_read_recv,
        .renameat_fn = skel_renameat,
        .fsync_send_fn = skel_fsync_send,
        .fsync_recv_fn = skel_fsync_recv,
index 461228f09afd617cfce94da8ae2d687da0b58bfd..d6252abe9f69e1ae2b20658066683fa44fc840fe 100644 (file)
@@ -380,6 +380,61 @@ static ssize_t skel_recvfile(vfs_handle_struct *handle, int fromfd,
        return SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, n);
 }
 
+struct skel_io_read_state {
+       ssize_t ret;
+       struct vfs_aio_state vfs_aio_state;
+};
+
+static void skel_io_read_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_io_read_send(struct vfs_handle_struct *handle,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct files_struct *fsp,
+                                           struct smb_vfs_io *io,
+                                           size_t n, off_t offset)
+{
+       struct tevent_req *req, *subreq;
+       struct skel_io_read_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct skel_io_read_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       subreq = SMB_VFS_NEXT_IO_READ_SEND(state, ev, handle, fsp,
+                                          io, n, offset);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, skel_io_read_done, req);
+       return req;
+}
+
+static void skel_io_read_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+           tevent_req_callback_data(subreq, struct tevent_req);
+       struct skel_io_read_state *state =
+           tevent_req_data(req, struct skel_io_read_state);
+
+       state->ret = SMB_VFS_IO_READ_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static ssize_t skel_io_read_recv(struct tevent_req *req,
+                              struct vfs_aio_state *vfs_aio_state)
+{
+       struct skel_io_read_state *state =
+           tevent_req_data(req, struct skel_io_read_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
+}
+
 static int skel_renameat(vfs_handle_struct *handle,
                       files_struct *srcfsp,
                       const struct smb_filename *smb_fname_src,
@@ -1310,6 +1365,8 @@ static struct vfs_fn_pointers skel_transparent_fns = {
        .lseek_fn = skel_lseek,
        .sendfile_fn = skel_sendfile,
        .recvfile_fn = skel_recvfile,
+       .io_read_send_fn = skel_io_read_send,
+       .io_read_recv_fn = skel_io_read_recv,
        .renameat_fn = skel_renameat,
        .fsync_send_fn = skel_fsync_send,
        .fsync_recv_fn = skel_fsync_recv,
index 1e2e88d65cefa03807abbd7871a99305ed1c5516..84eec2421a7a14bd3c972f14451dcc407a88ed88 100644 (file)
@@ -404,6 +404,9 @@ struct smb_file_time;
 struct smb_filename;
 struct dfs_GetDFSReferral;
 
+struct smb_vfs_io_pool;
+struct smb_vfs_io;
+
 typedef union unid_t {
        uid_t uid;
        gid_t gid;
@@ -1023,6 +1026,13 @@ struct vfs_fn_pointers {
        off_t (*lseek_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t offset, int whence);
        ssize_t (*sendfile_fn)(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *header, off_t offset, size_t count);
        ssize_t (*recvfile_fn)(struct vfs_handle_struct *handle, int fromfd, files_struct *tofsp, off_t offset, size_t count);
+       struct tevent_req *(*io_read_send_fn)(struct vfs_handle_struct *handle,
+                                             TALLOC_CTX *mem_ctx,
+                                             struct tevent_context *ev,
+                                             struct files_struct *fsp,
+                                             struct smb_vfs_io *io,
+                                             size_t n, off_t offset);
+       ssize_t (*io_read_recv_fn)(struct tevent_req *req, struct vfs_aio_state *state);
        int (*renameat_fn)(struct vfs_handle_struct *handle,
                         struct files_struct *srcdir_fsp,
                         const struct smb_filename *smb_fname_src,
@@ -1529,6 +1539,24 @@ ssize_t smb_vfs_call_sendfile(struct vfs_handle_struct *handle, int tofd,
 ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd,
                              files_struct *tofsp, off_t offset,
                              size_t count);
+
+struct smb_vfs_io_pool *smb_vfs_io_pool_create(TALLOC_CTX *mem_ctx,
+                                              size_t io_size,
+                                              size_t min_count,
+                                              size_t max_count);
+struct smb_vfs_io *smb_vfs_io_get(TALLOC_CTX *mem_ctx,
+                                 struct smb_vfs_io_pool *pool);
+int smb_vfs_io_input_fd(const struct smb_vfs_io *io);
+int smb_vfs_io_output_fd(const struct smb_vfs_io *io);
+
+struct tevent_req *smb_vfs_call_io_read_send(struct vfs_handle_struct *handle,
+                                            TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct files_struct *fsp,
+                                            struct smb_vfs_io *io,
+                                            size_t n, off_t offset);
+ssize_t SMB_VFS_IO_READ_RECV(struct tevent_req *req, struct vfs_aio_state *state);
+
 int smb_vfs_call_renameat(struct vfs_handle_struct *handle,
                        struct files_struct *srcfsp,
                        const struct smb_filename *smb_fname_src,
@@ -1964,6 +1992,14 @@ ssize_t vfs_not_implemented_sendfile(vfs_handle_struct *handle, int tofd,
                                     off_t offset, size_t n);
 ssize_t vfs_not_implemented_recvfile(vfs_handle_struct *handle, int fromfd,
                                     files_struct *tofsp, off_t offset, size_t n);
+struct tevent_req *vfs_not_implemented_io_read_send(struct vfs_handle_struct *handle,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   struct tevent_context *ev,
+                                                   struct files_struct *fsp,
+                                                   struct smb_vfs_io *io,
+                                                   size_t n, off_t offset);
+ssize_t vfs_not_implemented_io_read_recv(struct tevent_req *req,
+                                        struct vfs_aio_state *vfs_aio_state);
 int vfs_not_implemented_renameat(vfs_handle_struct *handle,
                               files_struct *srcfsp,
                               const struct smb_filename *smb_fname_src,
index 9196f6e5e405f26cd8fbed8af77cf841b70fbb38..580693b705987a35eaee53534803d20bc2b04ee9 100644 (file)
        smb_vfs_call_pread_send((handle)->next, (mem_ctx), (ev), (fsp), \
                                (data), (n), (off))
 
+#define SMB_VFS_IO_READ_SEND(mem_ctx, ev, fsp, io, n, off) \
+       smb_vfs_call_io_read_send((fsp)->conn->vfs_handles, (mem_ctx), (ev), \
+                                 (fsp), (io), (n), (off))
+#define SMB_VFS_NEXT_IO_READ_SEND(mem_ctx, ev, handle, fsp, io, n, off)        \
+       smb_vfs_call_io_read_send((handle)->next, (mem_ctx), (ev), (fsp), \
+                                 (io), (n), (off))
+
 #define SMB_VFS_PWRITE(fsp, data, n, off) \
        smb_vfs_call_pwrite((fsp)->conn->vfs_handles, (fsp), (data), (n), (off))
 #define SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, off) \
index 7fa6872d1716c8c35a4dbf97e8413174b62e41f8..1c6bce7e8ac0dfa134d0a97482f6ff066ff1a7b6 100644 (file)
@@ -4028,6 +4028,8 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .lseek_fn = vfswrap_lseek,
        .sendfile_fn = vfswrap_sendfile,
        .recvfile_fn = vfswrap_recvfile,
+       .io_read_send_fn = vfs_not_implemented_io_read_send,
+       .io_read_recv_fn = vfs_not_implemented_io_read_recv,
        .renameat_fn = vfswrap_renameat,
        .fsync_send_fn = vfswrap_fsync_send,
        .fsync_recv_fn = vfswrap_fsync_recv,
index 9fd8a7515720eec4a3ad229d180991190ec93f42..e56c89f92b986045df4071d5ac96b291483756b1 100644 (file)
@@ -2936,6 +2936,8 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
        .lseek_fn = smb_full_audit_lseek,
        .sendfile_fn = smb_full_audit_sendfile,
        .recvfile_fn = smb_full_audit_recvfile,
+       .io_read_send_fn = vfs_not_implemented_io_read_send,
+       .io_read_recv_fn = vfs_not_implemented_io_read_recv,
        .renameat_fn = smb_full_audit_renameat,
        .fsync_send_fn = smb_full_audit_fsync_send,
        .fsync_recv_fn = smb_full_audit_fsync_recv,
index b00a4993bc5ff5d906d2833b576bac2f973a7b36..93bf3ed8552f17968f066df47389aa56c137cd87 100644 (file)
@@ -316,6 +316,52 @@ ssize_t vfs_not_implemented_recvfile(vfs_handle_struct *handle, int fromfd,
        return -1;
 }
 
+struct vfs_not_implemented_io_read_state {
+       struct vfs_aio_state aio_state;
+       size_t nread;
+};
+
+_PUBLIC_
+struct tevent_req *vfs_not_implemented_io_read_send(struct vfs_handle_struct *handle,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   struct tevent_context *ev,
+                                                   struct files_struct *fsp,
+                                                   struct smb_vfs_io *io,
+                                                   size_t n, off_t offset)
+{
+       struct tevent_req *req = NULL;
+       struct vfs_not_implemented_io_read_state *state = NULL;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct vfs_not_implemented_io_read_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       tevent_req_error(req, ENOSYS);
+       return tevent_req_post(req, ev);
+}
+
+_PUBLIC_
+ssize_t vfs_not_implemented_io_read_recv(struct tevent_req *req,
+                                        struct vfs_aio_state *aio_state)
+{
+       struct vfs_not_implemented_io_read_state *state =
+               tevent_req_data(req,
+               struct vfs_not_implemented_io_read_state);
+       size_t nread;
+
+       if (tevent_req_is_unix_error(req, &aio_state->error)) {
+               tevent_req_received(req);
+               return -1;
+       }
+
+       *aio_state = state->aio_state;
+       nread = state->nread;
+       tevent_req_received(req);
+       return nread;
+}
+
 _PUBLIC_
 int vfs_not_implemented_renameat(vfs_handle_struct *handle,
                               files_struct *srcfsp,
@@ -1096,6 +1142,8 @@ static struct vfs_fn_pointers vfs_not_implemented_fns = {
        .lseek_fn = vfs_not_implemented_lseek,
        .sendfile_fn = vfs_not_implemented_sendfile,
        .recvfile_fn = vfs_not_implemented_recvfile,
+       .io_read_send_fn = vfs_not_implemented_io_read_send,
+       .io_read_recv_fn = vfs_not_implemented_io_read_recv,
        .renameat_fn = vfs_not_implemented_renameat,
        .fsync_send_fn = vfs_not_implemented_fsync_send,
        .fsync_recv_fn = vfs_not_implemented_fsync_recv,
index 59bc68861b46645cc173d06a10970670c6193456..0c6ea73641885a1f4288a157df038701d03a6890 100644 (file)
@@ -2727,6 +2727,8 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .lseek_fn = smb_time_audit_lseek,
        .sendfile_fn = smb_time_audit_sendfile,
        .recvfile_fn = smb_time_audit_recvfile,
+       .io_read_send_fn = vfs_not_implemented_io_read_send,
+       .io_read_recv_fn = vfs_not_implemented_io_read_recv,
        .renameat_fn = smb_time_audit_renameat,
        .fsync_send_fn = smb_time_audit_fsync_send,
        .fsync_recv_fn = smb_time_audit_fsync_recv,
index a34b908335284ecc3feeea79523715a3e3c94373..6965d0ae2467b96f512b1cc30e57e1a1fb21be75 100644 (file)
@@ -1753,6 +1753,255 @@ ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd,
        return handle->fns->recvfile_fn(handle, fromfd, tofsp, offset, count);
 }
 
+struct smb_vfs_io_pool {
+       size_t io_size;
+       size_t min_count;
+       size_t max_count;
+       size_t cur_count;
+       struct smb_vfs_io *free_list;
+       struct smb_vfs_io *busy_list;
+};
+
+struct smb_vfs_io {
+       struct smb_vfs_io *prev, *next;
+       struct smb_vfs_io_pool *pool;
+       int pipefds[2];
+       size_t pipesz;
+};
+
+static int smb_vfs_io_destructor(struct smb_vfs_io *io)
+{
+       if (io->pool == NULL) {
+               close(io->pipefds[0]);
+               io->pipefds[0] = -1;
+               close(io->pipefds[1]);
+               io->pipefds[1] = -1;
+               return 0;
+       }
+
+       DLIST_REMOVE(io->pool->busy_list, io);
+       DLIST_ADD_END(io->pool->free_list, io);
+       talloc_steal(io->pool, io);
+       return -1;
+}
+
+static int smb_vfs_io_allocate_root(struct smb_vfs_io_pool *pool)
+{
+       TALLOC_CTX *mem_ctx = pool;
+       struct smb_vfs_io *io = NULL;
+       bool ok;
+       int ret;
+
+       if (pool->cur_count >= pool->max_count) {
+               return -ENOBUFS;
+       }
+
+       // TODO:
+       // mem_ctx = 2nd talloc_pool for pool->cur_count >= pool->min_count
+       // prefer to keep entries from the primary pool.
+
+       io = talloc_zero(mem_ctx, struct smb_vfs_io);
+       if (io == NULL) {
+               return -ENOMEM;
+       }
+
+       ret = pipe(io->pipefds);
+       if (ret == -1) {
+               ret = errno;
+               TALLOC_FREE(io);
+               return -ret;
+       }
+
+       talloc_set_destructor(io, smb_vfs_io_destructor);
+
+       ok = smb_set_close_on_exec(io->pipefds[0]);
+       if (!ok) {
+               ret = errno;
+               TALLOC_FREE(io);
+               return -EINVAL;
+       }
+       ok = smb_set_close_on_exec(io->pipefds[1]);
+       if (!ok) {
+               ret = errno;
+               TALLOC_FREE(io);
+               return -EINVAL;
+       }
+
+       ret = fcntl(io->pipefds[0], F_GETPIPE_SZ);
+       if (ret >= pool->io_size) {
+               io->pipesz = ret;
+               io->pool = pool;
+               DLIST_ADD_END(pool->free_list, io);
+               pool->cur_count++;
+               return 0;
+       }
+       ret = fcntl(io->pipefds[0], F_SETPIPE_SZ, pool->io_size);
+       if (ret >= pool->io_size) {
+               io->pipesz = ret;
+               io->pool = pool;
+               DLIST_ADD_END(pool->free_list, io);
+               pool->cur_count++;
+               return 0;
+       }
+
+       if (ret == 0) {
+               errno = EMSGSIZE;
+       }
+       ret = errno;
+       TALLOC_FREE(io);
+       return -ret;
+}
+
+static int smb_vfs_io_allocate(struct smb_vfs_io_pool *pool)
+{
+       int ret;
+
+       /*
+        * We need to create the pipes as root
+        * in order to choose the size
+        */
+       become_root();
+       ret = smb_vfs_io_allocate_root(pool);
+       unbecome_root();
+
+       return ret;
+}
+
+struct smb_vfs_io_pool *smb_vfs_io_pool_create(TALLOC_CTX *mem_ctx,
+                                              size_t io_size,
+                                              size_t min_count,
+                                              size_t max_count)
+{
+       struct smb_vfs_io_pool *pool = NULL;
+
+       pool = talloc_pooled_object(mem_ctx, struct smb_vfs_io_pool,
+                                   min_count,
+                                   min_count * sizeof(struct smb_vfs_io));
+       if (pool == NULL) {
+               return NULL;
+       }
+       *pool = (struct smb_vfs_io_pool) {
+               .io_size = io_size,
+               .min_count = min_count,
+               .max_count = min_count,
+       };
+
+       while (pool->cur_count < pool->min_count) {
+               int ret;
+
+               ret = smb_vfs_io_allocate(pool);
+               if (ret < 0) {
+                       TALLOC_FREE(pool);
+                       errno = -ret;
+                       return NULL;
+               }
+       }
+
+       return pool;
+}
+
+struct smb_vfs_io *smb_vfs_io_get(TALLOC_CTX *mem_ctx,
+                                 struct smb_vfs_io_pool *pool)
+{
+       struct smb_vfs_io *io = NULL;
+
+       if (pool->free_list == NULL) {
+               int ret;
+
+               ret = smb_vfs_io_allocate(pool);
+               if (ret < 0) {
+                       errno = -ret;
+                       return NULL;
+               }
+       }
+
+       SMB_ASSERT(pool->free_list != NULL);
+
+       io = pool->free_list;
+       DLIST_REMOVE(io->pool->free_list, io);
+       DLIST_ADD_END(io->pool->busy_list, io);
+       talloc_steal(mem_ctx, io);
+       return io;
+}
+
+int smb_vfs_io_input_fd(const struct smb_vfs_io *io)
+{
+       return io->pipefds[1];
+}
+
+int smb_vfs_io_output_fd(const struct smb_vfs_io *io)
+{
+       return io->pipefds[0];
+}
+
+struct smb_vfs_call_io_read_state {
+       ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
+       ssize_t retval;
+       struct vfs_aio_state vfs_aio_state;
+};
+
+static void smb_vfs_call_io_read_done(struct tevent_req *subreq);
+
+struct tevent_req *smb_vfs_call_io_read_send(struct vfs_handle_struct *handle,
+                                            TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct files_struct *fsp,
+                                            struct smb_vfs_io *io,
+                                            size_t n, off_t offset)
+{
+       struct tevent_req *req, *subreq;
+       struct smb_vfs_call_io_read_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb_vfs_call_io_read_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       VFS_FIND(io_read_send);
+       state->recv_fn = handle->fns->io_read_recv_fn;
+
+       subreq = handle->fns->io_read_send_fn(handle, state, ev, fsp,
+                                             io, n, offset);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb_vfs_call_io_read_done, req);
+       return req;
+}
+
+static void smb_vfs_call_io_read_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smb_vfs_call_io_read_state *state = tevent_req_data(
+               req, struct smb_vfs_call_io_read_state);
+
+       state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+       if (state->retval == -1) {
+               tevent_req_error(req, state->vfs_aio_state.error);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+ssize_t SMB_VFS_IO_READ_RECV(struct tevent_req *req,
+                            struct vfs_aio_state *vfs_aio_state)
+{
+       struct smb_vfs_call_io_read_state *state = tevent_req_data(
+               req, struct smb_vfs_call_io_read_state);
+       ssize_t retval;
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               tevent_req_received(req);
+               return -1;
+       }
+       *vfs_aio_state = state->vfs_aio_state;
+       retval = state->retval;
+       tevent_req_received(req);
+       return retval;
+}
+
 int smb_vfs_call_renameat(struct vfs_handle_struct *handle,
                        files_struct *srcfsp,
                        const struct smb_filename *smb_fname_src,