ia64/xen-unstable

view xen/drivers/block/xen_vbd.c @ 926:0a901de56d7c

bitkeeper revision 1.588 (3fafd2ccYgSbWe9z2kLiH-DeviUaIA)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/local/scratch/smh22/xeno.bk
author smh22@labyrinth.cl.cam.ac.uk
date Mon Nov 10 18:02:52 2003 +0000 (2003-11-10)
parents 38ad3cea577f 4aba3a48d64f
children cfd9961afd8b 7ae6b4359a0d
line source
1 /*
2 * xen_vbd.c : routines for managing virtual block devices
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/sched.h>
11 #include <xeno/vbd.h>
12 #include <xeno/blkdev.h>
13 #include <xeno/keyhandler.h>
14 #include <asm/current.h>
15 #include <asm/domain_page.h>
17 /*
18 ** XXX SMH: the below probe functions /append/ their info to the
19 ** xdi array; i.e. they assume that all earlier slots are correctly
20 ** filled, and that xdi->count points to the first free entry in
21 ** the array. All kinda gross but it'll do for now.
22 */
23 extern int ide_probe_devices(xen_disk_info_t *xdi);
24 extern int scsi_probe_devices(xen_disk_info_t *xdi);
27 #if 0
28 #define DPRINTK(_f, _a...) printk( _f , ## _a )
29 #else
30 #define DPRINTK(_f, _a...) ((void)0)
31 #endif
34 /* XXX SMH: crappy 'hash function' .. fix when care. */
35 #define HSH(_x) (((_x) >> 6) & (VBD_HTAB_SZ - 1))
37 /*
38 ** Create a new VBD; all this involves is adding an entry to the domain's
39 ** vbd hash table; caller must be privileged.
40 */
41 long vbd_create(vbd_create_t *create_params)
42 {
43 struct task_struct *p;
44 vbd_t *new_vbd, *v;
45 int h;
47 if(!IS_PRIV(current))
48 return -EPERM;
50 p = find_domain_by_id(create_params->domain);
52 if (!p) {
53 printk("vbd_create attempted for non-existent domain %d\n",
54 create_params->domain);
55 return -EINVAL;
56 }
58 new_vbd = kmalloc(sizeof(vbd_t), GFP_KERNEL);
59 new_vbd->vdevice = create_params->vdevice;
60 new_vbd->mode = create_params->mode;
61 new_vbd->extents = (xen_extent_le_t *)NULL;
62 new_vbd->next = (vbd_t *)NULL;
64 h = HSH(create_params->vdevice);
65 if(p->vbdtab[h]) {
66 for(v = p->vbdtab[h]; v->next; v = v->next)
67 ;
68 v->next = new_vbd;
69 } else p->vbdtab[h] = new_vbd;
71 put_task_struct(p);
73 return 0;
74 }
76 /*
77 ** Add an extent to an existing VBD; fails if the VBD doesn't exist.
78 ** Doesn't worry about overlapping extents (e.g. merging etc) for now.
79 */
80 long vbd_add(vbd_add_t *add_params)
81 {
82 struct task_struct *p;
83 xen_extent_le_t *x, *xele;
84 vbd_t *v;
85 int h;
87 if(!IS_PRIV(current))
88 return -EPERM;
90 p = find_domain_by_id(add_params->domain);
92 if (!p) {
93 printk("vbd_add attempted for non-existent domain %d\n",
94 add_params->domain);
95 return -EINVAL;
96 }
98 h = HSH(add_params->vdevice);
100 for(v = p->vbdtab[h]; v; v = v->next)
101 if(v->vdevice == add_params->vdevice)
102 break;
104 if(!v) {
105 printk("vbd_add; attempted to add extent to non-existent VBD.\n");
106 return -EINVAL;
107 }
109 xele = kmalloc(sizeof(xen_extent_le_t), GFP_KERNEL);
110 xele->extent.device = add_params->extent.device;
111 xele->extent.start_sector = add_params->extent.start_sector;
112 xele->extent.nr_sectors = add_params->extent.nr_sectors;
113 xele->next = (xen_extent_le_t *)NULL;
115 if(!v->extents) {
116 v->extents = xele;
117 } else {
118 for(x = v->extents; x->next; x = x->next)
119 ;
120 x->next = xele;
121 }
123 put_task_struct(p);
124 return 0;
125 }
127 long vbd_remove(vbd_remove_t *remove_params)
128 {
129 if(!IS_PRIV(current))
130 return -EPERM;
132 return -ENOSYS;
133 }
135 long vbd_delete(vbd_delete_t *delete_params)
136 {
137 if(!IS_PRIV(current))
138 return -EPERM;
140 return -ENOSYS;
141 }
144 /*
145 * vbd_probe_devices:
146 *
147 * add the virtual block devices for this domain to a xen_disk_info_t;
148 * we assume xdi->count points to the first unused place in the array.
149 */
150 static int vbd_probe_devices(xen_disk_info_t *xdi, struct task_struct *p)
151 {
152 xen_extent_le_t *x;
153 xen_disk_t cur_disk;
154 vbd_t *v;
155 int i, ret;
157 for(i = 0; i < VBD_HTAB_SZ; i++) {
159 for(v = p->vbdtab[i]; v; v = v->next) {
161 /* SMH: don't ever expect this to happen, hence verbose printk */
162 if ( xdi->count == xdi->max ) {
163 printk("vbd_probe_devices: out of space for probe.\n");
164 return -ENOMEM;
165 }
167 cur_disk.device = v->vdevice;
168 cur_disk.info = XD_FLAG_VIRT | XD_TYPE_DISK;
169 if(!VBD_CAN_WRITE(v))
170 cur_disk.info |= XD_FLAG_RO;
171 cur_disk.capacity = 0 ;
172 for(x = v->extents; x; x = x->next)
173 cur_disk.capacity += x->extent.nr_sectors;
174 cur_disk.domain = p->domain;
176 /* Now copy into relevant part of user-space buffer */
177 if((ret = copy_to_user(xdi->disks + xdi->count, &cur_disk,
178 sizeof(xen_disk_t))) < 0) {
179 printk("vbd_probe_devices: copy_to_user failed [rc=%d]\n",
180 ret);
181 return ret;
182 }
185 xdi->count++;
186 }
187 }
189 return 0;
190 }
193 /*
194 ** Return information about the VBDs available for a given domain,
195 ** or for all domains; in the general case the 'domain' argument
196 ** will be 0 which means "information about the caller"; otherwise
197 ** the 'domain' argument will specify either a given domain, or
198 ** all domains ("VBD_PROBE_ALL") -- both of these cases require the
199 ** caller to be privileged.
200 */
201 long vbd_probe(vbd_probe_t *probe_params)
202 {
203 struct task_struct *p = NULL;
204 int ret;
206 if(probe_params->domain) {
208 /* we can only probe for ourselves unless we're privileged */
209 if(probe_params->domain != current->domain && !IS_PRIV(current))
210 return -EPERM;
212 if(probe_params->domain != VBD_PROBE_ALL) {
214 p = find_domain_by_id(probe_params->domain);
216 if (!p) {
217 printk("vbd_probe attempted for non-existent domain %d\n",
218 probe_params->domain);
219 return -EINVAL;
220 }
222 }
224 } else
225 /* default is to probe for ourselves */
226 p = current;
229 if(!p || IS_PRIV(p)) {
231 /* privileged domains always get access to the 'real' devices */
232 if((ret = ide_probe_devices(&probe_params->xdi))) {
233 printk("vbd_probe: error %d in probing ide devices\n", ret);
234 return ret;
235 }
236 if((ret = scsi_probe_devices(&probe_params->xdi))) {
237 printk("vbd_probe: error %d in probing scsi devices\n", ret);
238 return ret;
239 }
240 }
243 if(!p) {
245 u_long flags;
247 read_lock_irqsave (&tasklist_lock, flags);
249 p = &idle0_task;
250 while ( (p = p->next_task) != &idle0_task ) {
251 if (!is_idle_task(p)) {
252 if((ret = vbd_probe_devices(&probe_params->xdi, p))) {
253 printk("vbd_probe: error %d in probing virtual devices\n",
254 ret);
255 read_unlock_irqrestore(&tasklist_lock, flags);
256 return ret;
257 }
258 }
259 }
261 read_unlock_irqrestore(&tasklist_lock, flags);
263 } else {
265 /* probe for disks and VBDs for just 'p' */
266 if((ret = vbd_probe_devices(&probe_params->xdi, p))) {
267 printk("vbd_probe: error %d in probing virtual devices\n", ret);
268 return ret;
269 }
271 }
274 return 0;
275 }
277 long vbd_info(vbd_info_t *info_params)
278 {
279 return -ENOSYS;
280 }
283 int vbd_translate(phys_seg_t * pseg, int *nr_segs,
284 struct task_struct *p, int operation)
285 {
286 xen_extent_le_t *x;
287 vbd_t *v;
288 int h;
289 long sec;
291 h = HSH(pseg->dev);
293 for(v = p->vbdtab[h]; v; v = v->next)
294 if(v->vdevice == pseg->dev)
295 break;
297 if(!v) {
298 if(!IS_PRIV(p))
299 printk("vbd_translate; domain %d attempted to access "
300 "non-existent VBD.\n", p->domain);
301 return -ENODEV;
302 }
304 if(operation == READ && !VBD_CAN_READ(v))
305 return -EACCES;
307 if(operation == WRITE && !VBD_CAN_WRITE(v))
308 return -EACCES;
311 /* Now iterate through the list of xen_extents, working out which
312 should be used to perform the translation. */
313 sec = pseg->sector_number;
314 for(x = v->extents; x; x = x->next) {
316 if(sec < x->extent.nr_sectors) {
318 /* we've got a match! XXX SMH: should deal with
319 situation where we span multiple xe's */
321 pseg->dev = x->extent.device;
322 pseg->sector_number += x->extent.start_sector;
324 return 0;
326 }
328 sec -= x->extent.nr_sectors;
329 }
331 /* No luck -- return no access */
332 return -EACCES;
333 }