Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : POSIX NTVFS backend - async request wait routines
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/events/events.h"
24 : #include "../lib/util/dlinklist.h"
25 : #include "vfs_posix.h"
26 : #include "samba/service_stream.h"
27 : #include "lib/messaging/irpc.h"
28 :
29 : /* the context for a single wait instance */
30 : struct pvfs_wait {
31 : struct pvfs_wait *next, *prev;
32 : struct pvfs_state *pvfs;
33 : void (*handler)(void *, enum pvfs_wait_notice);
34 : void *private_data;
35 : int msg_type;
36 : struct imessaging_context *msg_ctx;
37 : struct tevent_context *ev;
38 : struct ntvfs_request *req;
39 : enum pvfs_wait_notice reason;
40 : };
41 :
42 : /*
43 : called from the ntvfs layer when we have requested setup of an async
44 : call. this ensures that async calls runs with the right state of
45 : previous ntvfs handlers in the chain (such as security context)
46 : */
47 3449 : NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs,
48 : struct ntvfs_request *req, void *private_data)
49 : {
50 3449 : struct pvfs_wait *pwait = talloc_get_type(private_data,
51 : struct pvfs_wait);
52 3449 : pwait->handler(pwait->private_data, pwait->reason);
53 3449 : return NT_STATUS_OK;
54 : }
55 :
56 : /*
57 : receive a completion message for a wait
58 : */
59 122 : static void pvfs_wait_dispatch(struct imessaging_context *msg,
60 : void *private_data,
61 : uint32_t msg_type,
62 : struct server_id src,
63 : size_t num_fds,
64 : int *fds,
65 : DATA_BLOB *data)
66 : {
67 122 : struct pvfs_wait *pwait = talloc_get_type(private_data,
68 : struct pvfs_wait);
69 0 : struct ntvfs_request *req;
70 122 : void *p = NULL;
71 :
72 122 : if (num_fds != 0) {
73 0 : DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
74 0 : return;
75 : }
76 :
77 : /* we need to check that this one is for us. See
78 : imessaging_send_ptr() for the other side of this.
79 : */
80 122 : if (data->length == sizeof(void *)) {
81 0 : void **pp;
82 122 : pp = (void **)data->data;
83 122 : p = *pp;
84 : }
85 122 : if (p == NULL || p != pwait->private_data) {
86 19 : return;
87 : }
88 :
89 103 : pwait->reason = PVFS_WAIT_EVENT;
90 :
91 : /* the extra reference here is to ensure that the req
92 : structure is not destroyed when the async request reply is
93 : sent, which would cause problems with the other ntvfs
94 : modules above us */
95 103 : req = talloc_reference(msg, pwait->req);
96 103 : ntvfs_async_setup(pwait->req, pwait);
97 103 : talloc_unlink(msg, req);
98 : }
99 :
100 :
101 : /*
102 : receive a timeout on a message wait
103 : */
104 2849 : static void pvfs_wait_timeout(struct tevent_context *ev,
105 : struct tevent_timer *te, struct timeval t,
106 : void *private_data)
107 : {
108 2849 : struct pvfs_wait *pwait = talloc_get_type(private_data,
109 : struct pvfs_wait);
110 2849 : struct ntvfs_request *req = pwait->req;
111 :
112 2849 : pwait->reason = PVFS_WAIT_TIMEOUT;
113 :
114 2849 : req = talloc_reference(ev, req);
115 2849 : if (req != NULL) {
116 2849 : ntvfs_async_setup(req, pwait);
117 2849 : talloc_unlink(ev, req);
118 : }
119 2849 : }
120 :
121 :
122 : /*
123 : destroy a pending wait
124 : */
125 3555 : static int pvfs_wait_destructor(struct pvfs_wait *pwait)
126 : {
127 3555 : if (pwait->msg_type != -1) {
128 3026 : imessaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait);
129 : }
130 3555 : DLIST_REMOVE(pwait->pvfs->wait_list, pwait);
131 3555 : return 0;
132 : }
133 :
134 : /*
135 : setup a request to wait on a message of type msg_type, with a
136 : timeout (given as an expiry time)
137 :
138 : the return value is a handle. To stop waiting talloc_free this
139 : handle.
140 :
141 : if msg_type == -1 then no message is registered, and it is assumed
142 : that the caller handles any messaging setup needed
143 : */
144 3555 : struct pvfs_wait *pvfs_wait_message(struct pvfs_state *pvfs,
145 : struct ntvfs_request *req,
146 : int msg_type,
147 : struct timeval end_time,
148 : void (*fn)(void *, enum pvfs_wait_notice),
149 : void *private_data)
150 : {
151 0 : struct pvfs_wait *pwait;
152 :
153 3555 : pwait = talloc(pvfs, struct pvfs_wait);
154 3555 : if (pwait == NULL) {
155 0 : return NULL;
156 : }
157 :
158 3555 : pwait->private_data = private_data;
159 3555 : pwait->handler = fn;
160 3555 : pwait->msg_ctx = pvfs->ntvfs->ctx->msg_ctx;
161 3555 : pwait->ev = pvfs->ntvfs->ctx->event_ctx;
162 3555 : pwait->msg_type = msg_type;
163 3555 : pwait->req = talloc_reference(pwait, req);
164 3555 : pwait->pvfs = pvfs;
165 :
166 3555 : if (!timeval_is_zero(&end_time)) {
167 : /* setup a timer */
168 3026 : tevent_add_timer(pwait->ev, pwait, end_time, pvfs_wait_timeout, pwait);
169 : }
170 :
171 : /* register with the messaging subsystem for this message
172 : type */
173 3555 : if (msg_type != -1) {
174 3026 : imessaging_register(pwait->msg_ctx,
175 : pwait,
176 : msg_type,
177 : pvfs_wait_dispatch);
178 : }
179 :
180 : /* tell the main smb server layer that we will be replying
181 : asynchronously */
182 3555 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
183 :
184 3555 : DLIST_ADD(pvfs->wait_list, pwait);
185 :
186 : /* make sure we cleanup the timer and message handler */
187 3555 : talloc_set_destructor(pwait, pvfs_wait_destructor);
188 :
189 3555 : return pwait;
190 : }
191 :
192 :
193 : /*
194 : cancel an outstanding async request
195 : */
196 497 : NTSTATUS pvfs_cancel(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req)
197 : {
198 497 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
199 : struct pvfs_state);
200 0 : struct pvfs_wait *pwait;
201 :
202 499 : for (pwait=pvfs->wait_list;pwait;pwait=pwait->next) {
203 499 : if (pwait->req == req) {
204 : /* trigger a cancel on the request */
205 497 : pwait->reason = PVFS_WAIT_CANCEL;
206 497 : ntvfs_async_setup(pwait->req, pwait);
207 497 : return NT_STATUS_OK;
208 : }
209 : }
210 :
211 0 : return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
212 : }
|