debuggers.hg

view xen/drivers/block/xen_segment.c @ 628:3e071d151e22

bitkeeper revision 1.329 (3f0d30d74QKz0HxzOWPKez8__UdvjQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/rac61/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/sos22/xeno.bk
author sos22@labyrinth.cl.cam.ac.uk
date Thu Jul 10 09:24:39 2003 +0000 (2003-07-10)
parents 01725801761a 5ed7375f954a
children f33864f401d8 75e23848b238
line source
1 /*
2 * xen_segment.c
3 */
5 #include <xeno/config.h>
6 #include <xeno/types.h>
7 #include <xeno/lib.h>
8 #include <asm/io.h>
9 #include <xeno/slab.h>
10 #include <xeno/segment.h>
11 #include <xeno/sched.h>
12 #include <xeno/blkdev.h>
13 #include <xeno/keyhandler.h>
14 #include <asm/current.h>
15 #include <asm/domain_page.h>
16 #include <hypervisor-ifs/block.h>
18 segment_t xsegments[XEN_MAX_SEGMENTS];
20 #if 0
21 #define DPRINTK(_f, _a...) printk( _f , ## _a )
22 #else
23 #define DPRINTK(_f, _a...) ((void)0)
24 #endif
26 /*
27 * xen_segment_map_request
28 *
29 * xen_device must be a valid device.
30 *
31 * NB. All offsets and sizes here are in sector units.
32 * eg. 'size == 1' means an actual size of 512 bytes.
33 */
34 int xen_segment_map_request(
35 phys_seg_t *pseg, struct task_struct *p, int operation,
36 unsigned short segment_number,
37 unsigned long sect_nr, unsigned long buffer, unsigned short nr_sects)
38 {
39 segment_t *seg;
40 extent_t *ext;
41 int sum, i;
43 segment_number &= XENDEV_IDX_MASK;
44 if ( segment_number >= XEN_MAX_SEGMENTS )
45 {
46 DPRINTK("invalid segment number. %d %d\n",
47 segment_number, XEN_MAX_SEGMENTS);
48 goto fail;
49 }
51 seg = p->segment_list[segment_number];
52 if ( seg == NULL )
53 {
54 DPRINTK("segment is null. %d\n", segment_number);
55 goto fail;
56 }
58 /* check domain permissions */
59 if ( seg->domain != p->domain )
60 {
61 DPRINTK("seg is for another domain. %d %d\n", seg->domain, p->domain);
62 goto fail;
63 }
65 /* check rw access */
66 if ( ((operation == WRITE) && (seg->mode != XEN_SEGMENT_RW)) ||
67 ((operation == READ) && (seg->mode == XEN_SEGMENT_UNUSED)) )
68 {
69 DPRINTK("illegal operation: %d %d\n", operation, seg->mode);
70 goto fail;
71 }
73 if ( (nr_sects + sect_nr) <= sect_nr )
74 {
75 DPRINTK("sector + size wrap! %08lx %04x\n", sect_nr, nr_sects);
76 goto fail;
77 }
79 /* find extent, check size */
80 sum = 0;
81 i = 0;
82 ext = seg->extents;
83 while ( (i < seg->num_extents) && ((sum + ext->size) <= sect_nr) )
84 {
85 sum += ext->size;
86 ext++; i++;
87 }
89 if ( (sum + ext->size) <= sect_nr )
90 {
91 DPRINTK("extent size mismatch: %d %d : %d %ld %ld\n",
92 i, seg->num_extents, sum, ext->size, sect_nr);
93 goto fail;
94 }
96 pseg->sector_number = (sect_nr - sum) + ext->offset;
97 pseg->buffer = buffer;
98 pseg->nr_sects = nr_sects;
99 pseg->dev = xendev_to_physdev(ext->disk);
100 if ( pseg->dev == 0 )
101 {
102 DPRINTK ("invalid device 0x%x 0x%lx 0x%lx\n",
103 ext->disk, ext->offset, ext->size);
104 goto fail;
105 }
107 /* We're finished if the virtual extent didn't overrun the phys extent. */
108 if ( (sum + ext->size) >= (sect_nr + nr_sects) )
109 return 1; /* entire read fits in this extent */
111 /* Hmmm... make sure there's another extent to overrun onto! */
112 if ( (i+1) == seg->num_extents )
113 {
114 DPRINTK ("not enough extents %d %d\n",
115 i, seg->num_extents);
116 goto fail;
117 }
119 pseg[1].nr_sects = (sect_nr + nr_sects) - (sum + ext->size);
120 pseg[0].nr_sects = sum + ext->size - sect_nr;
121 pseg[1].buffer = buffer + (pseg->nr_sects << 9);
122 pseg[1].sector_number = ext[1].offset;
123 pseg[1].dev = xendev_to_physdev(ext[1].disk);
124 if ( pseg[1].dev == 0 )
125 {
126 DPRINTK ("bogus device for pseg[1] \n");
127 goto fail;
128 }
130 /* We don't allow overrun onto a third physical extent. */
131 if ( pseg[1].nr_sects > ext[1].size )
132 {
133 DPRINTK ("third extent\n");
134 DPRINTK (" sum:%d, e0:%ld, e1:%ld p1.sect:%ld p1.nr:%d\n",
135 sum, ext[0].size, ext[1].size,
136 pseg[1].sector_number, pseg[1].nr_sects);
137 goto fail;
138 }
140 return 2; /* We overran onto a second physical extent. */
142 fail:
143 DPRINTK ("xen_segment_map_request failure\n");
144 DPRINTK ("operation: %d\n", operation);
145 DPRINTK ("segment number: %d\n", segment_number);
146 DPRINTK ("sect_nr: %ld 0x%lx\n", sect_nr, sect_nr);
147 DPRINTK ("nr_sects: %d 0x%x\n", nr_sects, nr_sects);
148 return -1;
149 }
151 /*
152 * xen_segment_probe
153 *
154 * return a list of segments to the guestos
155 */
156 void xen_segment_probe(struct task_struct *p, xen_disk_info_t *raw_xdi)
157 {
158 int loop, i;
159 xen_disk_info_t *xdi = map_domain_mem(virt_to_phys(raw_xdi));
160 unsigned long capacity = 0, device;
162 for ( loop = 0; loop < XEN_MAX_SEGMENTS; loop++ )
163 {
164 if ( (xsegments[loop].mode == XEN_SEGMENT_UNUSED) ||
165 (xsegments[loop].domain != p->domain) )
166 continue;
168 device = MK_VIRTUAL_XENDEV(xsegments[loop].segment_number);
169 for ( i = 0; i < xsegments[loop].num_extents; i++ )
170 capacity += xsegments[loop].extents[i].size;
172 xdi->disks[xdi->count].device = device;
173 xdi->disks[xdi->count].capacity = capacity;
174 xdi->count++;
175 }
177 unmap_domain_mem(xdi);
178 }
180 /*
181 * xen_segment_probe_all
182 *
183 * return a list of all segments to domain 0
184 */
185 void xen_segment_probe_all(xen_segment_info_t *raw_xsi)
186 {
187 int loop;
188 xen_segment_info_t *xsi = map_domain_mem(virt_to_phys(raw_xsi));
189 unsigned long device;
191 xsi->count = 0;
192 for ( loop = 0; loop < XEN_MAX_SEGMENTS; loop++ )
193 {
194 if ( xsegments[loop].mode == XEN_SEGMENT_UNUSED )
195 continue;
197 xsi->segments[xsi->count].mode = xsegments[loop].mode;
198 xsi->segments[xsi->count].domain = xsegments[loop].domain;
199 memcpy(xsi->segments[xsi->count].key,
200 xsegments[loop].key,
201 XEN_SEGMENT_KEYSIZE);
202 xsi->segments[xsi->count].seg_nr = xsegments[loop].segment_number;
203 xsi->count++;
204 }
206 unmap_domain_mem(xsi);
207 }
209 /*
210 * xen_refresh_segment_list
211 *
212 * find all segments associated with a domain and assign
213 * them to the domain
214 */
215 void xen_refresh_segment_list (struct task_struct *p)
216 {
217 int loop;
219 for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
220 {
221 if ( (xsegments[loop].mode == XEN_SEGMENT_UNUSED) ||
222 (xsegments[loop].domain != p->domain) )
223 continue;
225 p->segment_list[xsegments[loop].segment_number] = &xsegments[loop];
226 }
227 }
229 /*
230 * create a new segment for a domain
231 *
232 * return 0 on success, 1 on failure
233 *
234 * if we see the same DOM#/SEG# combination, we reuse the slot in
235 * the segment table (overwriting what was there before).
236 * an alternative would be to raise an error if the slot is reused.
237 * bug: we don't free the xtents array when we re-use a slot.
238 */
239 int xen_segment_create(xv_disk_t *xvd_in)
240 {
241 int idx;
242 int loop;
243 xv_disk_t *xvd = map_domain_mem(virt_to_phys(xvd_in));
244 struct task_struct *p;
246 for (idx = 0; idx < XEN_MAX_SEGMENTS; idx++)
247 {
248 if (xsegments[idx].mode == XEN_SEGMENT_UNUSED ||
249 (xsegments[idx].domain == xvd->domain &&
250 xsegments[idx].segment_number == xvd->segment)) break;
251 }
252 if (idx == XEN_MAX_SEGMENTS)
253 {
254 printk (KERN_ALERT "xen_segment_create: unable to find free slot\n");
255 unmap_domain_mem(xvd);
256 return 1;
257 }
259 xsegments[idx].mode = xvd->mode;
260 xsegments[idx].domain = xvd->domain;
261 xsegments[idx].segment_number = xvd->segment;
262 memcpy(xsegments[idx].key, xvd->key, XEN_SEGMENT_KEYSIZE);
263 xsegments[idx].num_extents = xvd->ext_count;
264 xsegments[idx].extents = (extent_t *)kmalloc(
265 sizeof(extent_t)*xvd->ext_count,
266 GFP_KERNEL);
268 /* could memcpy, but this is safer */
269 for (loop = 0; loop < xvd->ext_count; loop++)
270 {
271 xsegments[idx].extents[loop].disk = xvd->extents[loop].disk;
272 xsegments[idx].extents[loop].offset = xvd->extents[loop].offset;
273 xsegments[idx].extents[loop].size = xvd->extents[loop].size;
274 if (xsegments[idx].extents[loop].size == 0)
275 {
276 printk("xen_segment_create: extent %d is zero length\n", loop);
277 unmap_domain_mem(xvd);
278 return 1;
279 }
280 }
282 /* if the domain exists, assign the segment to the domain */
283 p = find_domain_by_id(xvd->domain);
284 if (p != NULL)
285 {
286 p->segment_list[xvd->segment] = &xsegments[idx];
287 put_task_struct(p);
288 }
290 unmap_domain_mem(xvd);
291 return 0;
292 }
294 /*
295 * delete a segment from a domain
296 *
297 * return 0 on success, 1 on failure
298 *
299 * TODO: caller must ensure that only domain 0 calls this function
300 */
301 int xen_segment_delete(struct task_struct *p, xv_disk_t *xvd)
302 {
303 return 0;
304 }
306 static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
307 {
308 int loop, i;
309 struct task_struct *p;
311 printk("segment list\n");
312 for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
313 {
314 if (xsegments[loop].mode != XEN_SEGMENT_UNUSED)
315 {
316 printk(" %2d: %s dom%d, seg# %d, num_exts: %d\n",
317 loop,
318 xsegments[loop].mode == XEN_SEGMENT_RO ? "RO" : "RW",
319 xsegments[loop].domain, xsegments[loop].segment_number,
320 xsegments[loop].num_extents);
321 for (i = 0; i < xsegments[loop].num_extents; i++)
322 {
323 printk(" extent %d: disk 0x%x, offset 0x%lx, size 0x%lx\n",
324 i, xsegments[loop].extents[i].disk,
325 xsegments[loop].extents[i].offset,
326 xsegments[loop].extents[i].size);
327 }
328 }
329 }
331 printk("segments by domain (index into segments list)\n");
332 p = current;
333 do
334 {
335 printk(" domain %d: ", p->domain);
336 for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
337 {
338 if (p->segment_list[loop])
339 {
340 printk (" %d", p->segment_list[loop] - xsegments);
341 }
342 }
343 printk("\n");
344 p = p->next_task;
345 } while (p != current);
346 }
348 /*
349 * initialize segments
350 */
352 void xen_segment_initialize(void)
353 {
354 memset (xsegments, 0, sizeof(xsegments));
356 add_key_handler('S', dump_segments, "dump segments");
357 }