Browse Source

[block] Add generic block device translator

Add a generic mechanism for providing block devices on top of a data
transfer interface (such as HTTP).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
09236e6030
3 changed files with 300 additions and 0 deletions
  1. 261
    0
      src/core/blocktrans.c
  2. 38
    0
      src/include/ipxe/blocktrans.h
  3. 1
    0
      src/include/ipxe/errfile.h

+ 261
- 0
src/core/blocktrans.c View File

@@ -0,0 +1,261 @@
1
+/*
2
+ * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * Block device translator
30
+ *
31
+ */
32
+
33
+#include <stdlib.h>
34
+#include <errno.h>
35
+#include <assert.h>
36
+#include <ipxe/iobuf.h>
37
+#include <ipxe/xfer.h>
38
+#include <ipxe/blockdev.h>
39
+#include <ipxe/blocktrans.h>
40
+
41
+/**
42
+ * Reallocate block device translator data buffer
43
+ *
44
+ * @v xferbuf		Data transfer buffer
45
+ * @v len		New length (or zero to free buffer)
46
+ * @ret rc		Return status code
47
+ */
48
+static int blktrans_xferbuf_realloc ( struct xfer_buffer *xferbuf,
49
+				      size_t len ) {
50
+	struct block_translator *blktrans =
51
+		container_of ( xferbuf, struct block_translator, xferbuf );
52
+
53
+	/* Record length, if applicable */
54
+	if ( blktrans->buffer ) {
55
+
56
+		/* We have a (non-reallocatable) data buffer */
57
+		return -ENOTSUP;
58
+
59
+	} else {
60
+
61
+		/* Record length (for block device capacity) */
62
+		xferbuf->len = len;
63
+		return 0;
64
+	}
65
+}
66
+
67
+/**
68
+ * Write data to block device translator data buffer
69
+ *
70
+ * @v xferbuf		Data transfer buffer
71
+ * @v offset		Starting offset
72
+ * @v data		Data to copy
73
+ * @v len		Length of data
74
+ */
75
+static void blktrans_xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
76
+				     const void *data, size_t len ) {
77
+	struct block_translator *blktrans =
78
+		container_of ( xferbuf, struct block_translator, xferbuf );
79
+
80
+	/* Write data to buffer, if applicable */
81
+	if ( blktrans->buffer ) {
82
+
83
+		/* Write data to buffer */
84
+		copy_to_user ( blktrans->buffer, offset, data, len );
85
+
86
+	} else {
87
+
88
+		/* Sanity check */
89
+		assert ( len == 0 );
90
+	}
91
+}
92
+
93
+/**
94
+ * Read data from block device translator data buffer
95
+ *
96
+ * @v xferbuf		Data transfer buffer
97
+ * @v offset		Starting offset
98
+ * @v data		Data to read
99
+ * @v len		Length of data
100
+ */
101
+static void blktrans_xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
102
+				    void *data, size_t len ) {
103
+	struct block_translator *blktrans =
104
+		container_of ( xferbuf, struct block_translator, xferbuf );
105
+
106
+	/* Read data from buffer, if applicable */
107
+	if ( blktrans->buffer ) {
108
+
109
+		/* Read data from buffer */
110
+		copy_from_user ( data, blktrans->buffer, offset, len );
111
+
112
+	} else {
113
+
114
+		/* Sanity check */
115
+		assert ( len == 0 );
116
+	}
117
+}
118
+
119
+/** Block device translator data transfer buffer operations */
120
+static struct xfer_buffer_operations blktrans_xferbuf_operations = {
121
+	.realloc = blktrans_xferbuf_realloc,
122
+	.write = blktrans_xferbuf_write,
123
+	.read = blktrans_xferbuf_read,
124
+};
125
+
126
+/**
127
+ * Close block device translator
128
+ *
129
+ * @v blktrans		Block device translator
130
+ * @v rc		Reason for close
131
+ */
132
+static void blktrans_close ( struct block_translator *blktrans, int rc ) {
133
+	struct block_device_capacity capacity;
134
+
135
+	/* Report block device capacity, if applicable */
136
+	if ( ( rc == 0 ) && ( blktrans->blksize ) ) {
137
+
138
+		/* Construct block device capacity */
139
+		capacity.blocks =
140
+			( blktrans->xferbuf.len / blktrans->blksize );
141
+		capacity.blksize = blktrans->blksize;
142
+		capacity.max_count = -1U;
143
+
144
+		/* Report block device capacity */
145
+		block_capacity ( &blktrans->block, &capacity );
146
+	}
147
+
148
+	/* Shut down interfaces */
149
+	intf_shutdown ( &blktrans->xfer, rc );
150
+	intf_shutdown ( &blktrans->block, rc );
151
+}
152
+
153
+/**
154
+ * Deliver data
155
+ *
156
+ * @v blktrans		Block device translator
157
+ * @v iobuf		I/O buffer
158
+ * @v meta		Data transfer metadata
159
+ * @ret rc		Return status code
160
+ */
161
+static int blktrans_deliver ( struct block_translator *blktrans,
162
+			      struct io_buffer *iobuf,
163
+			      struct xfer_metadata *meta ) {
164
+	int rc;
165
+
166
+	/* Deliver to buffer */
167
+	if ( ( rc = xferbuf_deliver ( &blktrans->xferbuf, iob_disown ( iobuf ),
168
+				      meta ) ) != 0 ) {
169
+		DBGC ( blktrans, "BLKTRANS %p could not deliver: %s\n",
170
+		       blktrans, strerror ( rc ) );
171
+		goto err;
172
+	}
173
+
174
+	return 0;
175
+
176
+ err:
177
+	blktrans_close ( blktrans, rc );
178
+	return rc;
179
+}
180
+
181
+/**
182
+ * Get underlying data transfer buffer
183
+ *
184
+ * @v blktrans		Block device translator
185
+ * @ret xferbuf		Data transfer buffer
186
+ */
187
+static struct xfer_buffer *
188
+blktrans_buffer ( struct block_translator *blktrans ) {
189
+
190
+	return &blktrans->xferbuf;
191
+}
192
+
193
+/** Block device translator block device interface operations */
194
+static struct interface_operation blktrans_block_operations[] = {
195
+	INTF_OP ( intf_close, struct block_translator *, blktrans_close ),
196
+};
197
+
198
+/** Block device translator block device interface descriptor */
199
+static struct interface_descriptor blktrans_block_desc =
200
+	INTF_DESC_PASSTHRU ( struct block_translator, block,
201
+			     blktrans_block_operations, xfer );
202
+
203
+/** Block device translator data transfer interface operations */
204
+static struct interface_operation blktrans_xfer_operations[] = {
205
+	INTF_OP ( xfer_deliver, struct block_translator *, blktrans_deliver ),
206
+	INTF_OP ( xfer_buffer, struct block_translator *, blktrans_buffer ),
207
+	INTF_OP ( intf_close, struct block_translator *, blktrans_close ),
208
+};
209
+
210
+/** Block device translator data transfer interface descriptor */
211
+static struct interface_descriptor blktrans_xfer_desc =
212
+	INTF_DESC_PASSTHRU ( struct block_translator, xfer,
213
+			     blktrans_xfer_operations, block );
214
+
215
+/**
216
+ * Insert block device translator
217
+ *
218
+ * @v block		Block device interface
219
+ * @v buffer		Data buffer (or UNULL)
220
+ * @v size		Length of data buffer, or block size
221
+ * @ret rc		Return status code
222
+ */
223
+int block_translate ( struct interface *block, userptr_t buffer, size_t size ) {
224
+	struct block_translator *blktrans;
225
+	int rc;
226
+
227
+	/* Allocate and initialise structure */
228
+	blktrans = zalloc ( sizeof ( *blktrans ) );
229
+	if ( ! blktrans ) {
230
+		rc = -ENOMEM;
231
+		goto err_alloc;
232
+	}
233
+	ref_init ( &blktrans->refcnt, NULL );
234
+	intf_init ( &blktrans->block, &blktrans_block_desc, &blktrans->refcnt );
235
+	intf_init ( &blktrans->xfer, &blktrans_xfer_desc, &blktrans->refcnt );
236
+	blktrans->xferbuf.op = &blktrans_xferbuf_operations;
237
+	blktrans->buffer = buffer;
238
+	if ( buffer ) {
239
+		blktrans->xferbuf.len = size;
240
+	} else {
241
+		blktrans->blksize = size;
242
+	}
243
+
244
+	/* Attach to interfaces, mortalise self, and return */
245
+	assert ( block->dest != &null_intf );
246
+	intf_plug_plug ( &blktrans->xfer, block->dest );
247
+	intf_plug_plug ( &blktrans->block, block );
248
+	ref_put ( &blktrans->refcnt );
249
+
250
+	DBGC2 ( blktrans, "BLKTRANS %p created", blktrans );
251
+	if ( buffer ) {
252
+		DBGC2 ( blktrans, " for %#lx+%#zx",
253
+			user_to_phys ( buffer, 0 ), size );
254
+	}
255
+	DBGC2 ( blktrans, "\n" );
256
+	return 0;
257
+
258
+	ref_put ( &blktrans->refcnt );
259
+ err_alloc:
260
+	return rc;
261
+}

+ 38
- 0
src/include/ipxe/blocktrans.h View File

@@ -0,0 +1,38 @@
1
+#ifndef _IPXE_BLOCKTRANS_H
2
+#define _IPXE_BLOCKTRANS_H
3
+
4
+/** @file
5
+ *
6
+ * Block device translator
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <stdint.h>
13
+#include <ipxe/refcnt.h>
14
+#include <ipxe/interface.h>
15
+#include <ipxe/xferbuf.h>
16
+#include <ipxe/uaccess.h>
17
+
18
+/** A block device translator */
19
+struct block_translator {
20
+	/** Reference count */
21
+	struct refcnt refcnt;
22
+	/** Block device interface */
23
+	struct interface block;
24
+	/** Data transfer interface */
25
+	struct interface xfer;
26
+
27
+	/** Data transfer buffer */
28
+	struct xfer_buffer xferbuf;
29
+	/** Data buffer */
30
+	userptr_t buffer;
31
+	/** Block size */
32
+	size_t blksize;
33
+};
34
+
35
+extern int block_translate ( struct interface *block,
36
+			     userptr_t buffer, size_t size );
37
+
38
+#endif /* _IPXE_BLOCKTRANS_H */

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -69,6 +69,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
69 69
 #define ERRFILE_ansicol		       ( ERRFILE_CORE | 0x001d0000 )
70 70
 #define ERRFILE_ansicoldef	       ( ERRFILE_CORE | 0x001e0000 )
71 71
 #define ERRFILE_fault		       ( ERRFILE_CORE | 0x001f0000 )
72
+#define ERRFILE_blocktrans	       ( ERRFILE_CORE | 0x00200000 )
72 73
 
73 74
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
74 75
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

Loading…
Cancel
Save