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,
.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,
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,
.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,
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;
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,
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,
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,
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) \
.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,
.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,
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,
.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,
.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,
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,