Browse Source

[nvo] Allow resizing of non-volatile stored option blocks

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
17d28f4877

+ 103
- 49
src/core/nvo.c View File

49
 	return sum;
49
 	return sum;
50
 }
50
 }
51
 
51
 
52
+/**
53
+ * Reallocate non-volatile stored options block
54
+ *
55
+ * @v nvo		Non-volatile options block
56
+ * @v len		New length
57
+ * @ret rc		Return status code
58
+ */
59
+static int nvo_realloc ( struct nvo_block *nvo, size_t len ) {
60
+	void *new_data;
61
+
62
+	/* Reallocate data */
63
+	new_data = realloc ( nvo->data, len );
64
+	if ( ! new_data ) {
65
+		DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
66
+		       nvo, len );
67
+		return -ENOMEM;
68
+	}
69
+	nvo->data = new_data;
70
+	nvo->len = len;
71
+
72
+	/* Update DHCP option block */
73
+	if ( len ) {
74
+		nvo->dhcpopts.data = ( nvo->data + 1 /* checksum */ );
75
+		nvo->dhcpopts.alloc_len = ( len - 1 /* checksum */ );
76
+	} else {
77
+		nvo->dhcpopts.data = NULL;
78
+		nvo->dhcpopts.used_len = 0;
79
+		nvo->dhcpopts.alloc_len = 0;
80
+	}
81
+
82
+	return 0;
83
+}
84
+
85
+/**
86
+ * Reallocate non-volatile stored options DHCP option block
87
+ *
88
+ * @v options		DHCP option block
89
+ * @v len		New length
90
+ * @ret rc		Return status code
91
+ */
92
+static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
93
+	struct nvo_block *nvo =
94
+		container_of ( options, struct nvo_block, dhcpopts );
95
+	int rc;
96
+
97
+	/* Refuse to reallocate if we have no way to resize the block */
98
+	if ( ! nvo->resize )
99
+		return dhcpopt_no_realloc ( options, len );
100
+
101
+	/* Allow one byte for the checksum (if any data is present) */
102
+	if ( len )
103
+		len += 1;
104
+
105
+	/* Resize underlying non-volatile options block */
106
+	if ( ( rc = nvo->resize ( nvo, len ) ) != 0 ) {
107
+		DBGC ( nvo, "NVO %p could not resize to %zd bytes: %s\n",
108
+		       nvo, len, strerror ( rc ) );
109
+		return rc;
110
+	}
111
+
112
+	/* Reallocate in-memory options block */
113
+	if ( ( rc = nvo_realloc ( nvo, len ) ) != 0 )
114
+		return rc;
115
+
116
+	return 0;
117
+}
118
+
52
 /**
119
 /**
53
  * Load non-volatile stored options from non-volatile storage device
120
  * Load non-volatile stored options from non-volatile storage device
54
  *
121
  *
56
  * @ret rc		Return status code
123
  * @ret rc		Return status code
57
  */
124
  */
58
 static int nvo_load ( struct nvo_block *nvo ) {
125
 static int nvo_load ( struct nvo_block *nvo ) {
126
+	uint8_t *options_data = nvo->dhcpopts.data;
59
 	int rc;
127
 	int rc;
60
 
128
 
129
+	/* Skip reading zero-length NVO fields */
130
+	if ( nvo->len == 0 ) {
131
+		DBGC ( nvo, "NVO %p is empty; skipping load\n", nvo );
132
+		return 0;
133
+	}
134
+
61
 	/* Read data */
135
 	/* Read data */
62
 	if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
136
 	if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
63
 			       nvo->len ) ) != 0 ) {
137
 			       nvo->len ) ) != 0 ) {
66
 		return rc;
140
 		return rc;
67
 	}
141
 	}
68
 
142
 
143
+	/* If checksum fails, or options data starts with a zero,
144
+	 * assume the whole block is invalid.  This should capture the
145
+	 * case of random initial contents.
146
+	 */
147
+	if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
148
+		DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
149
+		       "assuming empty\n", nvo, nvo_checksum ( nvo ),
150
+		       options_data[0] );
151
+		memset ( nvo->data, 0, nvo->len );
152
+	}
153
+
154
+	/* Rescan DHCP option block */
155
+	dhcpopt_update_used_len ( &nvo->dhcpopts );
156
+
69
 	DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
157
 	DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
70
 	return 0;
158
 	return 0;
71
 }
159
 }
80
 	uint8_t *checksum = nvo->data;
168
 	uint8_t *checksum = nvo->data;
81
 	int rc;
169
 	int rc;
82
 
170
 
83
-	/* Recalculate checksum */
84
-	*checksum -= nvo_checksum ( nvo );
171
+	/* Recalculate checksum, if applicable */
172
+	if ( nvo->len > 0 )
173
+		*checksum -= nvo_checksum ( nvo );
85
 
174
 
86
 	/* Write data */
175
 	/* Write data */
87
 	if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
176
 	if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
95
 	return 0;
184
 	return 0;
96
 }
185
 }
97
 
186
 
98
-/**
99
- * Parse stored options
100
- *
101
- * @v nvo		Non-volatile options block
102
- *
103
- * Verifies that the options data is valid, and configures the DHCP
104
- * options block.  If the data is not valid, it is replaced with an
105
- * empty options block.
106
- */
107
-static void nvo_init_dhcpopts ( struct nvo_block *nvo ) {
108
-	uint8_t *options_data;
109
-	size_t options_len;
110
-
111
-	/* Steal one byte for the checksum */
112
-	options_data = ( nvo->data + 1 );
113
-	options_len = ( nvo->len - 1 );
114
-
115
-	/* If checksum fails, or options data starts with a zero,
116
-	 * assume the whole block is invalid.  This should capture the
117
-	 * case of random initial contents.
118
-	 */
119
-	if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
120
-		DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
121
-		       "assuming empty\n", nvo, nvo_checksum ( nvo ),
122
-		       options_data[0] );
123
-		memset ( nvo->data, 0, nvo->len );
124
-	}
125
-
126
-	dhcpopt_init ( &nvo->dhcpopts, options_data, options_len,
127
-		       dhcpopt_no_realloc );
128
-}
129
-
130
 /**
187
 /**
131
  * Store value of NVO setting
188
  * Store value of NVO setting
132
  *
189
  *
190
  * @v nvs		Underlying non-volatile storage device
247
  * @v nvs		Underlying non-volatile storage device
191
  * @v address		Address within NVS device
248
  * @v address		Address within NVS device
192
  * @v len		Length of non-volatile options data
249
  * @v len		Length of non-volatile options data
250
+ * @v resize		Resize method
193
  * @v refcnt		Containing object reference counter, or NULL
251
  * @v refcnt		Containing object reference counter, or NULL
194
  */
252
  */
195
 void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
253
 void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
196
-		size_t address, size_t len, struct refcnt *refcnt ) {
254
+		size_t address, size_t len,
255
+		int ( * resize ) ( struct nvo_block *nvo, size_t len ),
256
+		struct refcnt *refcnt ) {
197
 	nvo->nvs = nvs;
257
 	nvo->nvs = nvs;
198
 	nvo->address = address;
258
 	nvo->address = address;
199
 	nvo->len = len;
259
 	nvo->len = len;
260
+	nvo->resize = resize;
261
+	dhcpopt_init ( &nvo->dhcpopts, NULL, 0, nvo_realloc_dhcpopt );
200
 	settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, 0 );
262
 	settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, 0 );
201
 }
263
 }
202
 
264
 
211
 	int rc;
273
 	int rc;
212
 
274
 
213
 	/* Allocate memory for options */
275
 	/* Allocate memory for options */
214
-	nvo->data = zalloc ( nvo->len );
215
-	if ( ! nvo->data ) {
216
-		DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
217
-		       nvo, nvo->len );
218
-		rc = -ENOMEM;
219
-		goto err_malloc;
220
-	}
276
+	if ( ( rc = nvo_realloc ( nvo, nvo->len ) ) != 0 )
277
+		goto err_realloc;
221
 
278
 
222
 	/* Read data from NVS */
279
 	/* Read data from NVS */
223
 	if ( ( rc = nvo_load ( nvo ) ) != 0 )
280
 	if ( ( rc = nvo_load ( nvo ) ) != 0 )
224
 		goto err_load;
281
 		goto err_load;
225
 
282
 
226
-	/* Verify and register options */
227
-	nvo_init_dhcpopts ( nvo );
283
+	/* Register settings */
228
 	if ( ( rc = register_settings ( &nvo->settings, parent, "nvo" ) ) != 0 )
284
 	if ( ( rc = register_settings ( &nvo->settings, parent, "nvo" ) ) != 0 )
229
 		goto err_register;
285
 		goto err_register;
230
 
286
 
233
 	
289
 	
234
  err_register:
290
  err_register:
235
  err_load:
291
  err_load:
236
-	free ( nvo->data );
237
-	nvo->data = NULL;
238
- err_malloc:
292
+	nvo_realloc ( nvo, 0 );
293
+ err_realloc:
239
 	return rc;
294
 	return rc;
240
 }
295
 }
241
 
296
 
246
  */
301
  */
247
 void unregister_nvo ( struct nvo_block *nvo ) {
302
 void unregister_nvo ( struct nvo_block *nvo ) {
248
 	unregister_settings ( &nvo->settings );
303
 	unregister_settings ( &nvo->settings );
249
-	free ( nvo->data );
250
-	nvo->data = NULL;
304
+	nvo_realloc ( nvo, 0 );
251
 	DBGC ( nvo, "NVO %p unregistered\n", nvo );
305
 	DBGC ( nvo, "NVO %p unregistered\n", nvo );
252
 }
306
 }

+ 1
- 1
src/drivers/net/etherfabric.c View File

3273
 	/* If the device has EEPROM attached, then advertise NVO space */
3273
 	/* If the device has EEPROM attached, then advertise NVO space */
3274
 	if ( has_eeprom ) {
3274
 	if ( has_eeprom ) {
3275
 		nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, 0x100, 0xf0,
3275
 		nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, 0x100, 0xf0,
3276
-			   &efab->netdev->refcnt );
3276
+			   NULL, &efab->netdev->refcnt );
3277
 	}
3277
 	}
3278
 
3278
 
3279
 	return 0;
3279
 	return 0;

+ 1
- 0
src/drivers/net/myri10ge.c View File

732
 	nvo_init ( &priv->nvo,
732
 	nvo_init ( &priv->nvo,
733
 		   &priv->nvs,
733
 		   &priv->nvs,
734
 		   nvo_fragment_pos, 0x200,
734
 		   nvo_fragment_pos, 0x200,
735
+		   NULL,
735
 		   & myri10ge_netdev (priv) -> refcnt );
736
 		   & myri10ge_netdev (priv) -> refcnt );
736
 	rc = register_nvo ( &priv->nvo,
737
 	rc = register_nvo ( &priv->nvo,
737
 			    netdev_settings ( myri10ge_netdev ( priv ) ) );
738
 			    netdev_settings ( myri10ge_netdev ( priv ) ) );

+ 1
- 1
src/drivers/net/natsemi.c View File

154
 	 * this region.  Currently it is not working. But with some
154
 	 * this region.  Currently it is not working. But with some
155
 	 * efforts it can.
155
 	 * efforts it can.
156
 	 */
156
 	 */
157
-	nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL );
157
+	nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL );
158
 }
158
 }
159
 
159
 
160
 /**
160
 /**

+ 1
- 1
src/drivers/net/rtl8139.c View File

288
 		DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use "
288
 		DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use "
289
 		       "for options\n", rtl );
289
 		       "for options\n", rtl );
290
 	} else {
290
 	} else {
291
-		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40,
291
+		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL,
292
 			   &netdev->refcnt );
292
 			   &netdev->refcnt );
293
 	}
293
 	}
294
 }
294
 }

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

36
 			   void *data, size_t alloc_len,
36
 			   void *data, size_t alloc_len,
37
 			   int ( * realloc ) ( struct dhcp_options *options,
37
 			   int ( * realloc ) ( struct dhcp_options *options,
38
 					       size_t len ) );
38
 					       size_t len ) );
39
+extern void dhcpopt_update_used_len ( struct dhcp_options *options );
39
 extern int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len );
40
 extern int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len );
40
 
41
 
41
 #endif /* _IPXE_DHCPOPTS_H */
42
 #endif /* _IPXE_DHCPOPTS_H */

+ 11
- 1
src/include/ipxe/nvo.h View File

30
 	size_t len;
30
 	size_t len;
31
 	/** Option-containing data */
31
 	/** Option-containing data */
32
 	void *data;
32
 	void *data;
33
+	/**
34
+	 * Resize non-volatile stored option block
35
+	 *
36
+	 * @v nvo		Non-volatile options block
37
+	 * @v len		New size
38
+	 * @ret rc		Return status code
39
+	 */
40
+	int ( * resize ) ( struct nvo_block *nvo, size_t len );
33
 	/** DHCP options block */
41
 	/** DHCP options block */
34
 	struct dhcp_options dhcpopts;
42
 	struct dhcp_options dhcpopts;
35
 };
43
 };
36
 
44
 
37
 extern void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
45
 extern void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
38
-		       size_t address, size_t len, struct refcnt *refcnt );
46
+		       size_t address, size_t len,
47
+		       int ( * resize ) ( struct nvo_block *nvo, size_t len ),
48
+		       struct refcnt *refcnt );
39
 extern int register_nvo ( struct nvo_block *nvo, struct settings *parent );
49
 extern int register_nvo ( struct nvo_block *nvo, struct settings *parent );
40
 extern void unregister_nvo ( struct nvo_block *nvo );
50
 extern void unregister_nvo ( struct nvo_block *nvo );
41
 
51
 

+ 1
- 1
src/net/dhcpopts.c View File

402
  * The "used length" field will be updated based on scanning through
402
  * The "used length" field will be updated based on scanning through
403
  * the block to find the end of the options.
403
  * the block to find the end of the options.
404
  */
404
  */
405
-static void dhcpopt_update_used_len ( struct dhcp_options *options ) {
405
+void dhcpopt_update_used_len ( struct dhcp_options *options ) {
406
 	struct dhcp_option *option;
406
 	struct dhcp_option *option;
407
 	int offset = 0;
407
 	int offset = 0;
408
 	ssize_t remaining = options->alloc_len;
408
 	ssize_t remaining = options->alloc_len;

Loading…
Cancel
Save