Bläddra i källkod

[xferbuf] Generalise to handle umalloc()-based buffers

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 år sedan
förälder
incheckning
cbbd6b761e
3 ändrade filer med 268 tillägg och 25 borttagningar
  1. 195
    22
      src/core/xferbuf.c
  2. 70
    1
      src/include/ipxe/xferbuf.h
  3. 3
    2
      src/net/validator.c

+ 195
- 22
src/core/xferbuf.c Visa fil

@@ -28,6 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 28
 #include <errno.h>
29 29
 #include <ipxe/xfer.h>
30 30
 #include <ipxe/iobuf.h>
31
+#include <ipxe/umalloc.h>
32
+#include <ipxe/profile.h>
31 33
 #include <ipxe/xferbuf.h>
32 34
 
33 35
 /** @file
@@ -36,14 +38,26 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
36 38
  *
37 39
  */
38 40
 
41
+/** Data delivery profiler */
42
+static struct profiler xferbuf_deliver_profiler __profiler =
43
+	{ .name = "xferbuf.deliver" };
44
+
45
+/** Data write profiler */
46
+static struct profiler xferbuf_write_profiler __profiler =
47
+	{ .name = "xferbuf.write" };
48
+
49
+/** Data read profiler */
50
+static struct profiler xferbuf_read_profiler __profiler =
51
+	{ .name = "xferbuf.read" };
52
+
39 53
 /**
40
- * Finish using data transfer buffer
54
+ * Free data transfer buffer
41 55
  *
42 56
  * @v xferbuf		Data transfer buffer
43 57
  */
44
-void xferbuf_done ( struct xfer_buffer *xferbuf ) {
45
-	free ( xferbuf->data );
46
-	xferbuf->data = NULL;
58
+void xferbuf_free ( struct xfer_buffer *xferbuf ) {
59
+
60
+	xferbuf->op->realloc ( xferbuf, 0 );
47 61
 	xferbuf->len = 0;
48 62
 	xferbuf->pos = 0;
49 63
 }
@@ -56,25 +70,77 @@ void xferbuf_done ( struct xfer_buffer *xferbuf ) {
56 70
  * @ret rc		Return status code
57 71
  */
58 72
 static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
59
-	void *new_data;
73
+	int rc;
60 74
 
61 75
 	/* If buffer is already large enough, do nothing */
62 76
 	if ( len <= xferbuf->len )
63 77
 		return 0;
64 78
 
65 79
 	/* Extend buffer */
66
-	new_data = realloc ( xferbuf->data, len );
67
-	if ( ! new_data ) {
80
+	if ( ( rc = xferbuf->op->realloc ( xferbuf, len ) ) != 0 ) {
68 81
 		DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
69
-		       "%zd bytes\n", xferbuf, len );
70
-		return -ENOSPC;
82
+		       "%zd bytes: %s\n", xferbuf, len, strerror ( rc ) );
83
+		return rc;
71 84
 	}
72
-	xferbuf->data = new_data;
73 85
 	xferbuf->len = len;
74 86
 
75 87
 	return 0;
76 88
 }
77 89
 
90
+/**
91
+ * Write to data transfer buffer
92
+ *
93
+ * @v xferbuf		Data transfer buffer
94
+ * @v offset		Starting offset
95
+ * @v data		Data to write
96
+ * @v len		Length of data
97
+ */
98
+int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
99
+		    const void *data, size_t len ) {
100
+	size_t max_len;
101
+	int rc;
102
+
103
+	/* Check for overflow */
104
+	max_len = ( offset + len );
105
+	if ( max_len < offset )
106
+		return -EOVERFLOW;
107
+
108
+	/* Ensure buffer is large enough to contain this write */
109
+	if ( ( rc = xferbuf_ensure_size ( xferbuf, max_len ) ) != 0 )
110
+		return rc;
111
+
112
+	/* Copy data to buffer */
113
+	profile_start ( &xferbuf_write_profiler );
114
+	xferbuf->op->write ( xferbuf, offset, data, len );
115
+	profile_stop ( &xferbuf_write_profiler );
116
+
117
+	return 0;
118
+}
119
+
120
+/**
121
+ * Read from data transfer buffer
122
+ *
123
+ * @v xferbuf		Data transfer buffer
124
+ * @v offset		Starting offset
125
+ * @v data		Data to write
126
+ * @v len		Length of data
127
+ */
128
+int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
129
+		   void *data, size_t len ) {
130
+
131
+	/* Check that read is within buffer range */
132
+	if ( ( offset > xferbuf->len ) ||
133
+	     ( len > ( xferbuf->len - offset ) ) )
134
+		return -ENOENT;
135
+
136
+	/* Copy data from buffer */
137
+	profile_start ( &xferbuf_read_profiler );
138
+	xferbuf->op->read ( xferbuf, offset, data, len );
139
+	profile_stop ( &xferbuf_read_profiler );
140
+
141
+	return 0;
142
+}
143
+
78 144
 /**
79 145
  * Add received data to data transfer buffer
80 146
  *
@@ -85,28 +151,135 @@ static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
85 151
  */
86 152
 int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
87 153
 		      struct xfer_metadata *meta ) {
88
-	size_t len;
89
-	size_t max;
154
+	size_t len = iob_len ( iobuf );
155
+	size_t pos;
90 156
 	int rc;
91 157
 
158
+	/* Start profiling */
159
+	profile_start ( &xferbuf_deliver_profiler );
160
+
92 161
 	/* Calculate new buffer position */
162
+	pos = xferbuf->pos;
93 163
 	if ( meta->flags & XFER_FL_ABS_OFFSET )
94
-		xferbuf->pos = 0;
95
-	xferbuf->pos += meta->offset;
164
+		pos = 0;
165
+	pos += meta->offset;
96 166
 
97
-	/* Ensure that we have enough buffer space for this data */
98
-	len = iob_len ( iobuf );
99
-	max = ( xferbuf->pos + len );
100
-	if ( ( rc = xferbuf_ensure_size ( xferbuf, max ) ) != 0 )
167
+	/* Write data to buffer */
168
+	if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 )
101 169
 		goto done;
102 170
 
103
-	/* Copy data to buffer */
104
-	memcpy ( ( xferbuf->data + xferbuf->pos ), iobuf->data, len );
105
-
106 171
 	/* Update current buffer position */
107
-	xferbuf->pos += len;
172
+	xferbuf->pos = ( pos + len );
108 173
 
109 174
  done:
110 175
 	free_iob ( iobuf );
176
+	profile_stop ( &xferbuf_deliver_profiler );
111 177
 	return rc;
112 178
 }
179
+
180
+/**
181
+ * Reallocate malloc()-based data buffer
182
+ *
183
+ * @v xferbuf		Data transfer buffer
184
+ * @v len		New length (or zero to free buffer)
185
+ * @ret rc		Return status code
186
+ */
187
+static int xferbuf_malloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
188
+	void *new_data;
189
+
190
+	new_data = realloc ( xferbuf->data, len );
191
+	if ( ! new_data )
192
+		return -ENOSPC;
193
+	xferbuf->data = new_data;
194
+	return 0;
195
+}
196
+
197
+/**
198
+ * Write data to malloc()-based data buffer
199
+ *
200
+ * @v xferbuf		Data transfer buffer
201
+ * @v offset		Starting offset
202
+ * @v data		Data to copy
203
+ * @v len		Length of data
204
+ */
205
+static void xferbuf_malloc_write ( struct xfer_buffer *xferbuf, size_t offset,
206
+				   const void *data, size_t len ) {
207
+
208
+	memcpy ( ( xferbuf->data + offset ), data, len );
209
+}
210
+
211
+/**
212
+ * Read data from malloc()-based data buffer
213
+ *
214
+ * @v xferbuf		Data transfer buffer
215
+ * @v offset		Starting offset
216
+ * @v data		Data to read
217
+ * @v len		Length of data
218
+ */
219
+static void xferbuf_malloc_read ( struct xfer_buffer *xferbuf, size_t offset,
220
+				  void *data, size_t len ) {
221
+
222
+	memcpy ( data, ( xferbuf->data + offset ), len );
223
+}
224
+
225
+/** malloc()-based data buffer operations */
226
+struct xfer_buffer_operations xferbuf_malloc_operations = {
227
+	.realloc = xferbuf_malloc_realloc,
228
+	.write = xferbuf_malloc_write,
229
+	.read = xferbuf_malloc_read,
230
+};
231
+
232
+/**
233
+ * Reallocate umalloc()-based data buffer
234
+ *
235
+ * @v xferbuf		Data transfer buffer
236
+ * @v len		New length (or zero to free buffer)
237
+ * @ret rc		Return status code
238
+ */
239
+static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
240
+	userptr_t *udata = xferbuf->data;
241
+	userptr_t new_udata;
242
+
243
+	new_udata = urealloc ( *udata, len );
244
+	if ( ! new_udata )
245
+		return -ENOSPC;
246
+	*udata = new_udata;
247
+	return 0;
248
+}
249
+
250
+/**
251
+ * Write data to umalloc()-based data buffer
252
+ *
253
+ * @v xferbuf		Data transfer buffer
254
+ * @v offset		Starting offset
255
+ * @v data		Data to copy
256
+ * @v len		Length of data
257
+ */
258
+static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset,
259
+				    const void *data, size_t len ) {
260
+	userptr_t *udata = xferbuf->data;
261
+
262
+	copy_to_user ( *udata, offset, data, len );
263
+}
264
+
265
+/**
266
+ * Read data from umalloc()-based data buffer
267
+ *
268
+ * @v xferbuf		Data transfer buffer
269
+ * @v offset		Starting offset
270
+ * @v data		Data to read
271
+ * @v len		Length of data
272
+ */
273
+static void xferbuf_umalloc_read ( struct xfer_buffer *xferbuf, size_t offset,
274
+				   void *data, size_t len ) {
275
+	userptr_t *udata = xferbuf->data;
276
+
277
+	copy_from_user ( data, *udata, offset, len );
278
+}
279
+
280
+/** umalloc()-based data buffer operations */
281
+struct xfer_buffer_operations xferbuf_umalloc_operations = {
282
+	.realloc = xferbuf_umalloc_realloc,
283
+	.write = xferbuf_umalloc_write,
284
+	.read = xferbuf_umalloc_read,
285
+};

+ 70
- 1
src/include/ipxe/xferbuf.h Visa fil

@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11 11
 
12 12
 #include <stdint.h>
13 13
 #include <ipxe/iobuf.h>
14
+#include <ipxe/uaccess.h>
14 15
 #include <ipxe/xfer.h>
15 16
 
16 17
 /** A data transfer buffer */
@@ -21,9 +22,77 @@ struct xfer_buffer {
21 22
 	size_t len;
22 23
 	/** Current offset within data */
23 24
 	size_t pos;
25
+	/** Data transfer buffer operations */
26
+	struct xfer_buffer_operations *op;
24 27
 };
25 28
 
26
-extern void xferbuf_done ( struct xfer_buffer *xferbuf );
29
+/** Data transfer buffer operations */
30
+struct xfer_buffer_operations {
31
+	/** Reallocate data buffer
32
+	 *
33
+	 * @v xferbuf		Data transfer buffer
34
+	 * @v len		New length (or zero to free buffer)
35
+	 * @ret rc		Return status code
36
+	 */
37
+	int ( * realloc ) ( struct xfer_buffer *xferbuf, size_t len );
38
+	/** Write data to buffer
39
+	 *
40
+	 * @v xferbuf		Data transfer buffer
41
+	 * @v offset		Starting offset
42
+	 * @v data		Data to write
43
+	 * @v len		Length of data
44
+	 *
45
+	 * This call is simply a wrapper for the appropriate
46
+	 * memcpy()-like operation: the caller is responsible for
47
+	 * ensuring that the write does not exceed the buffer length.
48
+	 */
49
+	void ( * write ) ( struct xfer_buffer *xferbuf, size_t offset,
50
+			   const void *data, size_t len );
51
+	/** Read data from buffer
52
+	 *
53
+	 * @v xferbuf		Data transfer buffer
54
+	 * @v offset		Starting offset
55
+	 * @v data		Data to read
56
+	 * @v len		Length of data
57
+	 *
58
+	 * This call is simply a wrapper for the appropriate
59
+	 * memcpy()-like operation: the caller is responsible for
60
+	 * ensuring that the read does not exceed the buffer length.
61
+	 */
62
+	void ( * read ) ( struct xfer_buffer *xferbuf, size_t offset,
63
+			  void *data, size_t len );
64
+};
65
+
66
+extern struct xfer_buffer_operations xferbuf_malloc_operations;
67
+extern struct xfer_buffer_operations xferbuf_umalloc_operations;
68
+
69
+/**
70
+ * Initialise malloc()-based data transfer buffer
71
+ *
72
+ * @v xferbuf		Data transfer buffer
73
+ */
74
+static inline __attribute__ (( always_inline )) void
75
+xferbuf_malloc_init ( struct xfer_buffer *xferbuf ) {
76
+	xferbuf->op = &xferbuf_malloc_operations;
77
+}
78
+
79
+/**
80
+ * Initialise umalloc()-based data transfer buffer
81
+ *
82
+ * @v xferbuf		Data transfer buffer
83
+ * @v data		User pointer
84
+ */
85
+static inline __attribute__ (( always_inline )) void
86
+xferbuf_umalloc_init ( struct xfer_buffer *xferbuf, userptr_t *data ) {
87
+	xferbuf->data = data;
88
+	xferbuf->op = &xferbuf_umalloc_operations;
89
+}
90
+
91
+extern void xferbuf_free ( struct xfer_buffer *xferbuf );
92
+extern int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
93
+			   const void *data, size_t len );
94
+extern int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
95
+			  void *data, size_t len );
27 96
 extern int xferbuf_deliver ( struct xfer_buffer *xferbuf,
28 97
 			     struct io_buffer *iobuf,
29 98
 			     struct xfer_metadata *meta );

+ 3
- 2
src/net/validator.c Visa fil

@@ -83,7 +83,7 @@ static void validator_free ( struct refcnt *refcnt ) {
83 83
 	DBGC2 ( validator, "VALIDATOR %p freed\n", validator );
84 84
 	x509_chain_put ( validator->chain );
85 85
 	ocsp_put ( validator->ocsp );
86
-	xferbuf_done ( &validator->buffer );
86
+	xferbuf_free ( &validator->buffer );
87 87
 	free ( validator );
88 88
 }
89 89
 
@@ -392,7 +392,7 @@ static void validator_xfer_close ( struct validator *validator, int rc ) {
392 392
 		goto err_append;
393 393
 
394 394
 	/* Free downloaded data */
395
-	xferbuf_done ( &validator->buffer );
395
+	xferbuf_free ( &validator->buffer );
396 396
 
397 397
 	/* Resume validation process */
398 398
 	process_add ( &validator->process );
@@ -557,6 +557,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain ) {
557 557
 	process_init ( &validator->process, &validator_process_desc,
558 558
 		       &validator->refcnt );
559 559
 	validator->chain = x509_chain_get ( chain );
560
+	xferbuf_malloc_init ( &validator->buffer );
560 561
 
561 562
 	/* Attach parent interface, mortalise self, and return */
562 563
 	intf_plug_plug ( &validator->job, job );

Laddar…
Avbryt
Spara