~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/modules/vfs_aio_fork.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Simulate the Posix AIO using mmap/fork
 
3
 *
 
4
 * Copyright (C) Volker Lendecke 2008
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#include "includes.h"
 
22
 
 
23
struct mmap_area {
 
24
        size_t size;
 
25
        volatile void *ptr;
 
26
};
 
27
 
 
28
static int mmap_area_destructor(struct mmap_area *area)
 
29
{
 
30
        munmap((void *)area->ptr, area->size);
 
31
        return 0;
 
32
}
 
33
 
 
34
static struct mmap_area *mmap_area_init(TALLOC_CTX *mem_ctx, size_t size)
 
35
{
 
36
        struct mmap_area *result;
 
37
        int fd;
 
38
 
 
39
        result = talloc(mem_ctx, struct mmap_area);
 
40
        if (result == NULL) {
 
41
                DEBUG(0, ("talloc failed\n"));
 
42
                goto fail;
 
43
        }
 
44
 
 
45
        fd = open("/dev/zero", O_RDWR);
 
46
        if (fd == -1) {
 
47
                DEBUG(3, ("open(\"/dev/zero\") failed: %s\n",
 
48
                          strerror(errno)));
 
49
                goto fail;
 
50
        }
 
51
 
 
52
        result->ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
 
53
                           MAP_SHARED|MAP_FILE, fd, 0);
 
54
        if (result->ptr == MAP_FAILED) {
 
55
                DEBUG(1, ("mmap failed: %s\n", strerror(errno)));
 
56
                goto fail;
 
57
        }
 
58
 
 
59
        close(fd);
 
60
 
 
61
        result->size = size;
 
62
        talloc_set_destructor(result, mmap_area_destructor);
 
63
 
 
64
        return result;
 
65
 
 
66
fail:
 
67
        TALLOC_FREE(result);
 
68
        return NULL;
 
69
}
 
70
 
 
71
struct rw_cmd {
 
72
        size_t n;
 
73
        SMB_OFF_T offset;
 
74
        bool read_cmd;
 
75
};
 
76
 
 
77
struct rw_ret {
 
78
        ssize_t size;
 
79
        int ret_errno;
 
80
};
 
81
 
 
82
struct aio_child_list;
 
83
 
 
84
struct aio_child {
 
85
        struct aio_child *prev, *next;
 
86
        struct aio_child_list *list;
 
87
        SMB_STRUCT_AIOCB *aiocb;
 
88
        pid_t pid;
 
89
        int sockfd;
 
90
        struct fd_event *sock_event;
 
91
        struct rw_ret retval;
 
92
        struct mmap_area *map;  /* ==NULL means write request */
 
93
        bool dont_delete;       /* Marked as in use since last cleanup */
 
94
        bool cancelled;
 
95
        bool read_cmd;
 
96
};
 
97
 
 
98
struct aio_child_list {
 
99
        struct aio_child *children;
 
100
        struct timed_event *cleanup_event;
 
101
};
 
102
 
 
103
static void free_aio_children(void **p)
 
104
{
 
105
        TALLOC_FREE(*p);
 
106
}
 
107
 
 
108
static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
 
109
{
 
110
        struct msghdr msg;
 
111
        struct iovec iov[1];
 
112
        ssize_t n;
 
113
#ifndef HAVE_MSGHDR_MSG_CONTROL
 
114
        int newfd;
 
115
#endif
 
116
 
 
117
#ifdef  HAVE_MSGHDR_MSG_CONTROL
 
118
        union {
 
119
          struct cmsghdr        cm;
 
120
          char                          control[CMSG_SPACE(sizeof(int))];
 
121
        } control_un;
 
122
        struct cmsghdr  *cmptr;
 
123
 
 
124
        msg.msg_control = control_un.control;
 
125
        msg.msg_controllen = sizeof(control_un.control);
 
126
#else
 
127
#if HAVE_MSGHDR_MSG_ACCTRIGHTS
 
128
        msg.msg_accrights = (caddr_t) &newfd;
 
129
        msg.msg_accrightslen = sizeof(int);
 
130
#else
 
131
#error Can not pass file descriptors
 
132
#endif
 
133
#endif
 
134
 
 
135
        msg.msg_name = NULL;
 
136
        msg.msg_namelen = 0;
 
137
 
 
138
        iov[0].iov_base = ptr;
 
139
        iov[0].iov_len = nbytes;
 
140
        msg.msg_iov = iov;
 
141
        msg.msg_iovlen = 1;
 
142
 
 
143
        if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
 
144
                return(n);
 
145
        }
 
146
 
 
147
#ifdef  HAVE_MSGHDR_MSG_CONTROL
 
148
        if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
 
149
            && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
 
150
                if (cmptr->cmsg_level != SOL_SOCKET) {
 
151
                        DEBUG(10, ("control level != SOL_SOCKET"));
 
152
                        errno = EINVAL;
 
153
                        return -1;
 
154
                }
 
155
                if (cmptr->cmsg_type != SCM_RIGHTS) {
 
156
                        DEBUG(10, ("control type != SCM_RIGHTS"));
 
157
                        errno = EINVAL;
 
158
                        return -1;
 
159
                }
 
160
                *recvfd = *((int *) CMSG_DATA(cmptr));
 
161
        } else {
 
162
                *recvfd = -1;           /* descriptor was not passed */
 
163
        }
 
164
#else
 
165
        if (msg.msg_accrightslen == sizeof(int)) {
 
166
                *recvfd = newfd;
 
167
        }
 
168
        else {
 
169
                *recvfd = -1;           /* descriptor was not passed */
 
170
        }
 
171
#endif
 
172
 
 
173
        return(n);
 
174
}
 
175
 
 
176
static ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
 
177
{
 
178
        struct msghdr   msg;
 
179
        struct iovec    iov[1];
 
180
 
 
181
#ifdef  HAVE_MSGHDR_MSG_CONTROL
 
182
        union {
 
183
                struct cmsghdr  cm;
 
184
                char control[CMSG_SPACE(sizeof(int))];
 
185
        } control_un;
 
186
        struct cmsghdr  *cmptr;
 
187
 
 
188
        ZERO_STRUCT(msg);
 
189
        ZERO_STRUCT(control_un);
 
190
 
 
191
        msg.msg_control = control_un.control;
 
192
        msg.msg_controllen = sizeof(control_un.control);
 
193
 
 
194
        cmptr = CMSG_FIRSTHDR(&msg);
 
195
        cmptr->cmsg_len = CMSG_LEN(sizeof(int));
 
196
        cmptr->cmsg_level = SOL_SOCKET;
 
197
        cmptr->cmsg_type = SCM_RIGHTS;
 
198
        *((int *) CMSG_DATA(cmptr)) = sendfd;
 
199
#else
 
200
        ZERO_STRUCT(msg);
 
201
        msg.msg_accrights = (caddr_t) &sendfd;
 
202
        msg.msg_accrightslen = sizeof(int);
 
203
#endif
 
204
 
 
205
        msg.msg_name = NULL;
 
206
        msg.msg_namelen = 0;
 
207
 
 
208
        ZERO_STRUCT(iov);
 
209
        iov[0].iov_base = ptr;
 
210
        iov[0].iov_len = nbytes;
 
211
        msg.msg_iov = iov;
 
212
        msg.msg_iovlen = 1;
 
213
 
 
214
        return (sendmsg(fd, &msg, 0));
 
215
}
 
216
 
 
217
static void aio_child_cleanup(struct event_context *event_ctx,
 
218
                              struct timed_event *te,
 
219
                              struct timeval now,
 
220
                              void *private_data)
 
221
{
 
222
        struct aio_child_list *list = talloc_get_type_abort(
 
223
                private_data, struct aio_child_list);
 
224
        struct aio_child *child, *next;
 
225
 
 
226
        TALLOC_FREE(list->cleanup_event);
 
227
 
 
228
        for (child = list->children; child != NULL; child = next) {
 
229
                next = child->next;
 
230
 
 
231
                if (child->aiocb != NULL) {
 
232
                        DEBUG(10, ("child %d currently active\n",
 
233
                                   (int)child->pid));
 
234
                        continue;
 
235
                }
 
236
 
 
237
                if (child->dont_delete) {
 
238
                        DEBUG(10, ("Child %d was active since last cleanup\n",
 
239
                                   (int)child->pid));
 
240
                        child->dont_delete = false;
 
241
                        continue;
 
242
                }
 
243
 
 
244
                DEBUG(10, ("Child %d idle for more than 30 seconds, "
 
245
                           "deleting\n", (int)child->pid));
 
246
 
 
247
                TALLOC_FREE(child);
 
248
        }
 
249
 
 
250
        if (list->children != NULL) {
 
251
                /*
 
252
                 * Re-schedule the next cleanup round
 
253
                 */
 
254
                list->cleanup_event = event_add_timed(smbd_event_context(), list,
 
255
                                                      timeval_add(&now, 30, 0),
 
256
                                                      aio_child_cleanup, list);
 
257
 
 
258
        }
 
259
}
 
260
 
 
261
static struct aio_child_list *init_aio_children(struct vfs_handle_struct *handle)
 
262
{
 
263
        struct aio_child_list *data = NULL;
 
264
 
 
265
        if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
 
266
                SMB_VFS_HANDLE_GET_DATA(handle, data, struct aio_child_list,
 
267
                                        return NULL);
 
268
        }
 
269
 
 
270
        if (data == NULL) {
 
271
                data = TALLOC_ZERO_P(NULL, struct aio_child_list);
 
272
                if (data == NULL) {
 
273
                        return NULL;
 
274
                }
 
275
        }
 
276
 
 
277
        /*
 
278
         * Regardless of whether the child_list had been around or not, make
 
279
         * sure that we have a cleanup timed event. This timed event will
 
280
         * delete itself when it finds that no children are around anymore.
 
281
         */
 
282
 
 
283
        if (data->cleanup_event == NULL) {
 
284
                data->cleanup_event = event_add_timed(smbd_event_context(), data,
 
285
                                                      timeval_current_ofs(30, 0),
 
286
                                                      aio_child_cleanup, data);
 
287
                if (data->cleanup_event == NULL) {
 
288
                        TALLOC_FREE(data);
 
289
                        return NULL;
 
290
                }
 
291
        }
 
292
 
 
293
        if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
 
294
                SMB_VFS_HANDLE_SET_DATA(handle, data, free_aio_children,
 
295
                                        struct aio_child_list, return False);
 
296
        }
 
297
 
 
298
        return data;
 
299
}
 
300
 
 
301
static void aio_child_loop(int sockfd, struct mmap_area *map)
 
302
{
 
303
        while (true) {
 
304
                int fd = -1;
 
305
                ssize_t ret;
 
306
                struct rw_cmd cmd_struct;
 
307
                struct rw_ret ret_struct;
 
308
 
 
309
                ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
 
310
                if (ret != sizeof(cmd_struct)) {
 
311
                        DEBUG(10, ("read_fd returned %d: %s\n", (int)ret,
 
312
                                   strerror(errno)));
 
313
                        exit(1);
 
314
                }
 
315
 
 
316
                DEBUG(10, ("aio_child_loop: %s %d bytes at %d from fd %d\n",
 
317
                           cmd_struct.read_cmd ? "read" : "write",
 
318
                           (int)cmd_struct.n, (int)cmd_struct.offset, fd));
 
319
 
 
320
#ifdef ENABLE_BUILD_FARM_HACKS
 
321
                {
 
322
                        /*
 
323
                         * In the build farm, we want erratic behaviour for
 
324
                         * async I/O times
 
325
                         */
 
326
                        uint8_t randval;
 
327
                        unsigned msecs;
 
328
                        /*
 
329
                         * use generate_random_buffer, we just forked from a
 
330
                         * common parent state
 
331
                         */
 
332
                        generate_random_buffer(&randval, sizeof(randval));
 
333
                        msecs = randval + 20;
 
334
                        DEBUG(10, ("delaying for %u msecs\n", msecs));
 
335
                        smb_msleep(msecs);
 
336
                }
 
337
#endif
 
338
 
 
339
 
 
340
                ZERO_STRUCT(ret_struct);
 
341
 
 
342
                if (cmd_struct.read_cmd) {
 
343
                        ret_struct.size = sys_pread(
 
344
                                fd, (void *)map->ptr, cmd_struct.n,
 
345
                                cmd_struct.offset);
 
346
                }
 
347
                else {
 
348
                        ret_struct.size = sys_pwrite(
 
349
                                fd, (void *)map->ptr, cmd_struct.n,
 
350
                                cmd_struct.offset);
 
351
                }
 
352
 
 
353
                DEBUG(10, ("aio_child_loop: syscall returned %d\n",
 
354
                           (int)ret_struct.size));
 
355
 
 
356
                if (ret_struct.size == -1) {
 
357
                        ret_struct.ret_errno = errno;
 
358
                }
 
359
 
 
360
                /*
 
361
                 * Close the fd before telling our parent we're done. The
 
362
                 * parent might close and re-open the file very quickly, and
 
363
                 * with system-level share modes (GPFS) we would get an
 
364
                 * unjustified SHARING_VIOLATION.
 
365
                 */
 
366
                close(fd);
 
367
 
 
368
                ret = write_data(sockfd, (char *)&ret_struct,
 
369
                                 sizeof(ret_struct));
 
370
                if (ret != sizeof(ret_struct)) {
 
371
                        DEBUG(10, ("could not write ret_struct: %s\n",
 
372
                                   strerror(errno)));
 
373
                        exit(2);
 
374
                }
 
375
        }
 
376
}
 
377
 
 
378
static void handle_aio_completion(struct event_context *event_ctx,
 
379
                                  struct fd_event *event, uint16 flags,
 
380
                                  void *p)
 
381
{
 
382
        struct aio_child *child = (struct aio_child *)p;
 
383
        uint16 mid;
 
384
 
 
385
        DEBUG(10, ("handle_aio_completion called with flags=%d\n", flags));
 
386
 
 
387
        if ((flags & EVENT_FD_READ) == 0) {
 
388
                return;
 
389
        }
 
390
 
 
391
        if (!NT_STATUS_IS_OK(read_data(child->sockfd,
 
392
                                       (char *)&child->retval,
 
393
                                       sizeof(child->retval)))) {
 
394
                DEBUG(0, ("aio child %d died\n", (int)child->pid));
 
395
                child->retval.size = -1;
 
396
                child->retval.ret_errno = EIO;
 
397
        }
 
398
 
 
399
        if (child->cancelled) {
 
400
                child->aiocb = NULL;
 
401
                child->cancelled = false;
 
402
                return;
 
403
        }
 
404
 
 
405
        if (child->read_cmd && (child->retval.size > 0)) {
 
406
                SMB_ASSERT(child->retval.size <= child->aiocb->aio_nbytes);
 
407
                memcpy((void *)child->aiocb->aio_buf, (void *)child->map->ptr,
 
408
                       child->retval.size);
 
409
        }
 
410
 
 
411
        mid = child->aiocb->aio_sigevent.sigev_value.sival_int;
 
412
 
 
413
        DEBUG(10, ("mid %d finished\n", (int)mid));
 
414
 
 
415
        smbd_aio_complete_mid(mid);
 
416
}
 
417
 
 
418
static int aio_child_destructor(struct aio_child *child)
 
419
{
 
420
        SMB_ASSERT((child->aiocb == NULL) || child->cancelled);
 
421
        close(child->sockfd);
 
422
        DLIST_REMOVE(child->list->children, child);
 
423
        return 0;
 
424
}
 
425
 
 
426
/*
 
427
 * We have to close all fd's in open files, we might incorrectly hold a system
 
428
 * level share mode on a file.
 
429
 */
 
430
 
 
431
static struct files_struct *close_fsp_fd(struct files_struct *fsp,
 
432
                                         void *private_data)
 
433
{
 
434
        if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
 
435
                close(fsp->fh->fd);
 
436
                fsp->fh->fd = -1;
 
437
        }
 
438
        return NULL;
 
439
}
 
440
 
 
441
static NTSTATUS create_aio_child(struct aio_child_list *children,
 
442
                                 size_t map_size,
 
443
                                 struct aio_child **presult)
 
444
{
 
445
        struct aio_child *result;
 
446
        int fdpair[2];
 
447
        NTSTATUS status;
 
448
 
 
449
        fdpair[0] = fdpair[1] = -1;
 
450
 
 
451
        result = TALLOC_ZERO_P(children, struct aio_child);
 
452
        NT_STATUS_HAVE_NO_MEMORY(result);
 
453
 
 
454
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
 
455
                status = map_nt_error_from_unix(errno);
 
456
                DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
 
457
                goto fail;
 
458
        }
 
459
 
 
460
        DEBUG(10, ("fdpair = %d/%d\n", fdpair[0], fdpair[1]));
 
461
 
 
462
        result->map = mmap_area_init(result, map_size);
 
463
        if (result->map == NULL) {
 
464
                status = map_nt_error_from_unix(errno);
 
465
                DEBUG(0, ("Could not create mmap area\n"));
 
466
                goto fail;
 
467
        }
 
468
 
 
469
        result->pid = sys_fork();
 
470
        if (result->pid == -1) {
 
471
                status = map_nt_error_from_unix(errno);
 
472
                DEBUG(0, ("fork failed: %s\n", strerror(errno)));
 
473
                goto fail;
 
474
        }
 
475
 
 
476
        if (result->pid == 0) {
 
477
                close(fdpair[0]);
 
478
                result->sockfd = fdpair[1];
 
479
                file_walk_table(close_fsp_fd, NULL);
 
480
                aio_child_loop(result->sockfd, result->map);
 
481
        }
 
482
 
 
483
        DEBUG(10, ("Child %d created\n", result->pid));
 
484
 
 
485
        result->sockfd = fdpair[0];
 
486
        close(fdpair[1]);
 
487
 
 
488
        result->sock_event = event_add_fd(smbd_event_context(), result,
 
489
                                          result->sockfd, EVENT_FD_READ,
 
490
                                          handle_aio_completion,
 
491
                                          result);
 
492
        if (result->sock_event == NULL) {
 
493
                status = NT_STATUS_NO_MEMORY;
 
494
                DEBUG(0, ("event_add_fd failed\n"));
 
495
                goto fail;
 
496
        }
 
497
 
 
498
        result->list = children;
 
499
        DLIST_ADD(children->children, result);
 
500
 
 
501
        talloc_set_destructor(result, aio_child_destructor);
 
502
 
 
503
        *presult = result;
 
504
 
 
505
        return NT_STATUS_OK;
 
506
 
 
507
 fail:
 
508
        if (fdpair[0] != -1) close(fdpair[0]);
 
509
        if (fdpair[1] != -1) close(fdpair[1]);
 
510
        TALLOC_FREE(result);
 
511
 
 
512
        return status;
 
513
}
 
514
 
 
515
static NTSTATUS get_idle_child(struct vfs_handle_struct *handle,
 
516
                               struct aio_child **pchild)
 
517
{
 
518
        struct aio_child_list *children;
 
519
        struct aio_child *child;
 
520
        NTSTATUS status;
 
521
 
 
522
        children = init_aio_children(handle);
 
523
        if (children == NULL) {
 
524
                return NT_STATUS_NO_MEMORY;
 
525
        }
 
526
 
 
527
        for (child = children->children; child != NULL; child = child->next) {
 
528
                if (child->aiocb == NULL) {
 
529
                        /* idle */
 
530
                        break;
 
531
                }
 
532
        }
 
533
 
 
534
        if (child == NULL) {
 
535
                DEBUG(10, ("no idle child found, creating new one\n"));
 
536
 
 
537
                status = create_aio_child(children, 128*1024, &child);
 
538
                if (!NT_STATUS_IS_OK(status)) {
 
539
                        DEBUG(10, ("create_aio_child failed: %s\n",
 
540
                                   nt_errstr(status)));
 
541
                        return status;
 
542
                }
 
543
        }
 
544
 
 
545
        child->dont_delete = true;
 
546
 
 
547
        *pchild = child;
 
548
        return NT_STATUS_OK;
 
549
}
 
550
 
 
551
static int aio_fork_read(struct vfs_handle_struct *handle,
 
552
                         struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
 
553
{
 
554
        struct aio_child *child;
 
555
        struct rw_cmd cmd;
 
556
        ssize_t ret;
 
557
        NTSTATUS status;
 
558
 
 
559
        if (aiocb->aio_nbytes > 128*1024) {
 
560
                /* TODO: support variable buffers */
 
561
                errno = EINVAL;
 
562
                return -1;
 
563
        }
 
564
 
 
565
        status = get_idle_child(handle, &child);
 
566
        if (!NT_STATUS_IS_OK(status)) {
 
567
                DEBUG(10, ("Could not get an idle child\n"));
 
568
                return -1;
 
569
        }
 
570
 
 
571
        child->read_cmd = true;
 
572
        child->aiocb = aiocb;
 
573
        child->retval.ret_errno = EINPROGRESS;
 
574
 
 
575
        ZERO_STRUCT(cmd);
 
576
        cmd.n = aiocb->aio_nbytes;
 
577
        cmd.offset = aiocb->aio_offset;
 
578
        cmd.read_cmd = child->read_cmd;
 
579
 
 
580
        DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
 
581
                   (int)child->pid));
 
582
 
 
583
        ret = write_fd(child->sockfd, &cmd, sizeof(cmd), fsp->fh->fd);
 
584
        if (ret == -1) {
 
585
                DEBUG(10, ("write_fd failed: %s\n", strerror(errno)));
 
586
                return -1;
 
587
        }
 
588
 
 
589
        return 0;
 
590
}
 
591
 
 
592
static int aio_fork_write(struct vfs_handle_struct *handle,
 
593
                          struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
 
594
{
 
595
        struct aio_child *child;
 
596
        struct rw_cmd cmd;
 
597
        ssize_t ret;
 
598
        NTSTATUS status;
 
599
 
 
600
        if (aiocb->aio_nbytes > 128*1024) {
 
601
                /* TODO: support variable buffers */
 
602
                errno = EINVAL;
 
603
                return -1;
 
604
        }
 
605
 
 
606
        status = get_idle_child(handle, &child);
 
607
        if (!NT_STATUS_IS_OK(status)) {
 
608
                DEBUG(10, ("Could not get an idle child\n"));
 
609
                return -1;
 
610
        }
 
611
 
 
612
        child->read_cmd = false;
 
613
        child->aiocb = aiocb;
 
614
        child->retval.ret_errno = EINPROGRESS;
 
615
 
 
616
        memcpy((void *)child->map->ptr, (void *)aiocb->aio_buf,
 
617
               aiocb->aio_nbytes);
 
618
 
 
619
        ZERO_STRUCT(cmd);
 
620
        cmd.n = aiocb->aio_nbytes;
 
621
        cmd.offset = aiocb->aio_offset;
 
622
        cmd.read_cmd = child->read_cmd;
 
623
 
 
624
        DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
 
625
                   (int)child->pid));
 
626
 
 
627
        ret = write_fd(child->sockfd, &cmd, sizeof(cmd), fsp->fh->fd);
 
628
        if (ret == -1) {
 
629
                DEBUG(10, ("write_fd failed: %s\n", strerror(errno)));
 
630
                return -1;
 
631
        }
 
632
 
 
633
        return 0;
 
634
}
 
635
 
 
636
static struct aio_child *aio_fork_find_child(struct vfs_handle_struct *handle,
 
637
                                             SMB_STRUCT_AIOCB *aiocb)
 
638
{
 
639
        struct aio_child_list *children;
 
640
        struct aio_child *child;
 
641
 
 
642
        children = init_aio_children(handle);
 
643
        if (children == NULL) {
 
644
                return NULL;
 
645
        }
 
646
 
 
647
        for (child = children->children; child != NULL; child = child->next) {
 
648
                if (child->aiocb == aiocb) {
 
649
                        return child;
 
650
                }
 
651
        }
 
652
 
 
653
        return NULL;
 
654
}
 
655
 
 
656
static ssize_t aio_fork_return_fn(struct vfs_handle_struct *handle,
 
657
                                  struct files_struct *fsp,
 
658
                                  SMB_STRUCT_AIOCB *aiocb)
 
659
{
 
660
        struct aio_child *child = aio_fork_find_child(handle, aiocb);
 
661
 
 
662
        if (child == NULL) {
 
663
                errno = EINVAL;
 
664
                DEBUG(0, ("returning EINVAL\n"));
 
665
                return -1;
 
666
        }
 
667
 
 
668
        child->aiocb = NULL;
 
669
 
 
670
        if (child->retval.size == -1) {
 
671
                errno = child->retval.ret_errno;
 
672
        }
 
673
 
 
674
        return child->retval.size;
 
675
}
 
676
 
 
677
static int aio_fork_cancel(struct vfs_handle_struct *handle,
 
678
                           struct files_struct *fsp,
 
679
                           SMB_STRUCT_AIOCB *aiocb)
 
680
{
 
681
        struct aio_child_list *children;
 
682
        struct aio_child *child;
 
683
 
 
684
        children = init_aio_children(handle);
 
685
        if (children == NULL) {
 
686
                errno = EINVAL;
 
687
                return -1;
 
688
        }
 
689
 
 
690
        for (child = children->children; child != NULL; child = child->next) {
 
691
                if (child->aiocb == NULL) {
 
692
                        continue;
 
693
                }
 
694
                if (child->aiocb->aio_fildes != fsp->fh->fd) {
 
695
                        continue;
 
696
                }
 
697
                if ((aiocb != NULL) && (child->aiocb != aiocb)) {
 
698
                        continue;
 
699
                }
 
700
 
 
701
                /*
 
702
                 * We let the child do its job, but we discard the result when
 
703
                 * it's finished.
 
704
                 */
 
705
 
 
706
                child->cancelled = true;
 
707
        }
 
708
 
 
709
        return AIO_CANCELED;
 
710
}
 
711
 
 
712
static int aio_fork_error_fn(struct vfs_handle_struct *handle,
 
713
                             struct files_struct *fsp,
 
714
                             SMB_STRUCT_AIOCB *aiocb)
 
715
{
 
716
        struct aio_child *child = aio_fork_find_child(handle, aiocb);
 
717
 
 
718
        if (child == NULL) {
 
719
                errno = EINVAL;
 
720
                return -1;
 
721
        }
 
722
 
 
723
        return child->retval.ret_errno;
 
724
}
 
725
 
 
726
/* VFS operations structure */
 
727
 
 
728
static vfs_op_tuple aio_fork_ops[] = {
 
729
        {SMB_VFS_OP(aio_fork_read),     SMB_VFS_OP_AIO_READ,
 
730
         SMB_VFS_LAYER_TRANSPARENT},
 
731
        {SMB_VFS_OP(aio_fork_write),    SMB_VFS_OP_AIO_WRITE,
 
732
         SMB_VFS_LAYER_TRANSPARENT},
 
733
        {SMB_VFS_OP(aio_fork_return_fn), SMB_VFS_OP_AIO_RETURN,
 
734
         SMB_VFS_LAYER_TRANSPARENT},
 
735
        {SMB_VFS_OP(aio_fork_cancel),   SMB_VFS_OP_AIO_CANCEL,
 
736
         SMB_VFS_LAYER_TRANSPARENT},
 
737
        {SMB_VFS_OP(aio_fork_error_fn), SMB_VFS_OP_AIO_ERROR,
 
738
         SMB_VFS_LAYER_TRANSPARENT},
 
739
        {SMB_VFS_OP(NULL),              SMB_VFS_OP_NOOP,
 
740
         SMB_VFS_LAYER_NOOP}
 
741
};
 
742
 
 
743
NTSTATUS vfs_aio_fork_init(void);
 
744
NTSTATUS vfs_aio_fork_init(void)
 
745
{
 
746
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
 
747
                                "aio_fork", aio_fork_ops);
 
748
}