aboutsummaryrefslogtreecommitdiffstats
path: root/patches/linux-2.6.16.13/blktap-aio-16_03_06.patch
blob: 5f4fd6f7a981539d13a9f38aac68fccb77cdcd04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
diff -pruN ../pristine-linux-2.6.16-rc5/fs/aio.c ./fs/aio.c
--- ../pristine-linux-2.6.16-rc5/fs/aio.c	2006-03-14 14:10:10.827401387 +0000
+++ ./fs/aio.c	2006-03-16 09:57:53.898316582 +0000
@@ -34,6 +34,11 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_EPOLL
+#include <linux/poll.h>
+#include <linux/eventpoll.h>
+#endif
+
 #if DEBUG > 1
 #define dprintk		printk
 #else
@@ -1016,6 +1021,10 @@ put_rq:
 	if (waitqueue_active(&ctx->wait))
 		wake_up(&ctx->wait);
 
+#ifdef CONFIG_EPOLL
+	if (ctx->file && waitqueue_active(&ctx->poll_wait))
+		wake_up(&ctx->poll_wait);
+#endif
 	if (ret)
 		put_ioctx(ctx);
 
@@ -1025,6 +1034,8 @@ put_rq:
 /* aio_read_evt
  *	Pull an event off of the ioctx's event ring.  Returns the number of 
  *	events fetched (0 or 1 ;-)
+ *	If ent parameter is 0, just returns the number of events that would
+ *	be fetched.
  *	FIXME: make this use cmpxchg.
  *	TODO: make the ringbuffer user mmap()able (requires FIXME).
  */
@@ -1047,13 +1058,18 @@ static int aio_read_evt(struct kioctx *i
 
 	head = ring->head % info->nr;
 	if (head != ring->tail) {
-		struct io_event *evp = aio_ring_event(info, head, KM_USER1);
-		*ent = *evp;
-		head = (head + 1) % info->nr;
-		smp_mb(); /* finish reading the event before updatng the head */
-		ring->head = head;
-		ret = 1;
-		put_aio_ring_event(evp, KM_USER1);
+		if (ent) { /* event requested */
+			struct io_event *evp =
+				aio_ring_event(info, head, KM_USER1);
+			*ent = *evp;
+			head = (head + 1) % info->nr;
+			/* finish reading the event before updatng the head */
+			smp_mb();
+			ring->head = head;
+			ret = 1;
+			put_aio_ring_event(evp, KM_USER1);
+		} else /* only need to know availability */
+			ret = 1;
 	}
 	spin_unlock(&info->ring_lock);
 
@@ -1236,9 +1252,78 @@ static void io_destroy(struct kioctx *io
 
 	aio_cancel_all(ioctx);
 	wait_for_all_aios(ioctx);
+#ifdef CONFIG_EPOLL
+	/* forget the poll file, but it's up to the user to close it */
+	if (ioctx->file) {
+		ioctx->file->private_data = 0;
+		ioctx->file = 0;
+	}
+#endif
 	put_ioctx(ioctx);	/* once for the lookup */
 }
 
+#ifdef CONFIG_EPOLL
+
+static int aio_queue_fd_close(struct inode *inode, struct file *file)
+{
+	struct kioctx *ioctx = file->private_data;
+	if (ioctx) {
+		file->private_data = 0;
+		spin_lock_irq(&ioctx->ctx_lock);
+		ioctx->file = 0;
+		spin_unlock_irq(&ioctx->ctx_lock);
+	}
+	return 0;
+}
+
+static unsigned int aio_queue_fd_poll(struct file *file, poll_table *wait)
+{	unsigned int pollflags = 0;
+	struct kioctx *ioctx = file->private_data;
+
+	if (ioctx) {
+
+		spin_lock_irq(&ioctx->ctx_lock);
+		/* Insert inside our poll wait queue */
+		poll_wait(file, &ioctx->poll_wait, wait);
+
+		/* Check our condition */
+		if (aio_read_evt(ioctx, 0))
+			pollflags = POLLIN | POLLRDNORM;
+		spin_unlock_irq(&ioctx->ctx_lock);
+	}
+
+	return pollflags;
+}
+
+static struct file_operations aioq_fops = {
+	.release	= aio_queue_fd_close,
+	.poll		= aio_queue_fd_poll
+};
+
+/* make_aio_fd:
+ *  Create a file descriptor that can be used to poll the event queue.
+ *  Based and piggybacked on the excellent epoll code.
+ */
+
+static int make_aio_fd(struct kioctx *ioctx)
+{
+	int error, fd;
+	struct inode *inode;
+	struct file *file;
+
+	error = ep_getfd(&fd, &inode, &file, NULL, &aioq_fops);
+	if (error)
+		return error;
+
+	/* associate the file with the IO context */
+	file->private_data = ioctx;
+	ioctx->file = file;
+	init_waitqueue_head(&ioctx->poll_wait);
+	return fd;
+}
+#endif
+
+
 /* sys_io_setup:
  *	Create an aio_context capable of receiving at least nr_events.
  *	ctxp must not point to an aio_context that already exists, and
@@ -1251,18 +1336,30 @@ static void io_destroy(struct kioctx *io
  *	resources are available.  May fail with -EFAULT if an invalid
  *	pointer is passed for ctxp.  Will fail with -ENOSYS if not
  *	implemented.
+ *
+ *	To request a selectable fd, the user context has to be initialized
+ *	to 1, instead of 0, and the return value is the fd.
+ *	This keeps the system call compatible, since a non-zero value
+ *	was not allowed so far.
  */
 asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp)
 {
 	struct kioctx *ioctx = NULL;
 	unsigned long ctx;
 	long ret;
+	int make_fd = 0;
 
 	ret = get_user(ctx, ctxp);
 	if (unlikely(ret))
 		goto out;
 
 	ret = -EINVAL;
+#ifdef CONFIG_EPOLL
+	if (ctx == 1) {
+		make_fd = 1;
+		ctx = 0;
+	}
+#endif
 	if (unlikely(ctx || nr_events == 0)) {
 		pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n",
 		         ctx, nr_events);
@@ -1273,8 +1370,12 @@ asmlinkage long sys_io_setup(unsigned nr
 	ret = PTR_ERR(ioctx);
 	if (!IS_ERR(ioctx)) {
 		ret = put_user(ioctx->user_id, ctxp);
-		if (!ret)
-			return 0;
+#ifdef CONFIG_EPOLL
+		if (make_fd && ret >= 0)
+			ret = make_aio_fd(ioctx);
+#endif
+		if (ret >= 0)
+			return ret;
 
 		get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
 		io_destroy(ioctx);

diff -pruN ../pristine-linux-2.6.16-rc5/fs/eventpoll.c ./fs/eventpoll.c
--- ../pristine-linux-2.6.16-rc5/fs/eventpoll.c	2006-01-03 03:21:10.000000000 +0000
+++ ./fs/eventpoll.c	2006-03-16 10:04:35.469956167 +0000
@@ -235,8 +235,6 @@ struct ep_pqueue {
 
 static void ep_poll_safewake_init(struct poll_safewake *psw);
 static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq);
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
-		    struct eventpoll *ep);
 static int ep_alloc(struct eventpoll **pep);
 static void ep_free(struct eventpoll *ep);
 static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd);
@@ -266,7 +264,7 @@ static int ep_events_transfer(struct eve
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
 		   int maxevents, long timeout);
 static int eventpollfs_delete_dentry(struct dentry *dentry);
-static struct inode *ep_eventpoll_inode(void);
+static struct inode *ep_eventpoll_inode(struct file_operations *fops);
 static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
 					      int flags, const char *dev_name,
 					      void *data);
@@ -525,7 +523,7 @@ asmlinkage long sys_epoll_create(int siz
 	 * Creates all the items needed to setup an eventpoll file. That is,
 	 * a file structure, and inode and a free file descriptor.
 	 */
-	error = ep_getfd(&fd, &inode, &file, ep);
+	error = ep_getfd(&fd, &inode, &file, ep, &eventpoll_fops);
 	if (error)
 		goto eexit_2;
 
@@ -710,8 +708,8 @@ eexit_1:
 /*
  * Creates the file descriptor to be used by the epoll interface.
  */
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
-		    struct eventpoll *ep)
+int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+		    struct eventpoll *ep, struct file_operations *fops)
 {
 	struct qstr this;
 	char name[32];
@@ -727,7 +725,7 @@ static int ep_getfd(int *efd, struct ino
 		goto eexit_1;
 
 	/* Allocates an inode from the eventpoll file system */
-	inode = ep_eventpoll_inode();
+	inode = ep_eventpoll_inode(fops);
 	error = PTR_ERR(inode);
 	if (IS_ERR(inode))
 		goto eexit_2;
@@ -758,7 +756,7 @@ static int ep_getfd(int *efd, struct ino
 
 	file->f_pos = 0;
 	file->f_flags = O_RDONLY;
-	file->f_op = &eventpoll_fops;
+	file->f_op = fops;
 	file->f_mode = FMODE_READ;
 	file->f_version = 0;
 	file->private_data = ep;
@@ -1574,7 +1572,7 @@ static int eventpollfs_delete_dentry(str
 }
 
 
-static struct inode *ep_eventpoll_inode(void)
+static struct inode *ep_eventpoll_inode(struct file_operations *fops)
 {
 	int error = -ENOMEM;
 	struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
@@ -1582,7 +1580,7 @@ static struct inode *ep_eventpoll_inode(
 	if (!inode)
 		goto eexit_1;
 
-	inode->i_fop = &eventpoll_fops;
+	inode->i_fop = fops;
 
 	/*
 	 * Mark the inode dirty from the very beginning,

diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/aio.h ./include/linux/aio.h
--- ../pristine-linux-2.6.16-rc5/include/linux/aio.h	2006-03-14 14:10:21.597916731 +0000
+++ ./include/linux/aio.h	2006-03-16 10:05:39.848833028 +0000
@@ -191,6 +191,11 @@ struct kioctx {
 	struct aio_ring_info	ring_info;
 
 	struct work_struct	wq;
+#ifdef CONFIG_EPOLL
+	// poll integration
+	wait_queue_head_t       poll_wait;
+	struct file		*file;
+#endif
 };
 
 /* prototypes */

diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h ./include/linux/eventpoll.h
--- ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h	2006-01-03 03:21:10.000000000 +0000
+++ ./include/linux/eventpoll.h	2006-03-16 10:08:51.577809317 +0000
@@ -86,6 +86,12 @@ static inline void eventpoll_release(str
 }
 
 
+/*
+ * called by aio code to create fd that can poll the  aio event queueQ
+ */
+struct eventpoll;
+int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+             struct eventpoll *ep, struct file_operations *fops);
 #else
 
 static inline void eventpoll_init_file(struct file *file) {}