Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / blktap2-new / control.c
1 #include <linux/module.h>
2 #include <linux/sched.h>
3 #include <linux/miscdevice.h>
4 #include <linux/device.h>
5 #include <asm/uaccess.h>
6
7 #include "blktap.h"
8
9 DEFINE_MUTEX(blktap_lock);
10
11 struct blktap **blktaps;
12 int blktap_max_minor;
13 static struct blktap_page_pool *default_pool;
14
15 static struct blktap *
16 blktap_control_get_minor(void)
17 {
18         int minor;
19         struct blktap *tap;
20
21         tap = kzalloc(sizeof(*tap), GFP_KERNEL);
22         if (unlikely(!tap))
23                 return NULL;
24
25         mutex_lock(&blktap_lock);
26
27         for (minor = 0; minor < blktap_max_minor; minor++)
28                 if (!blktaps[minor])
29                         break;
30
31         if (minor == CONFIG_XEN_NR_TAP2_DEVICES)
32                 goto fail;
33
34         if (minor == blktap_max_minor) {
35                 void *p;
36                 int n;
37
38                 n = min(2 * blktap_max_minor, CONFIG_XEN_NR_TAP2_DEVICES);
39                 p = krealloc(blktaps, n * sizeof(blktaps[0]), GFP_KERNEL);
40                 if (!p)
41                         goto fail;
42
43                 blktaps          = p;
44                 minor            = blktap_max_minor;
45                 blktap_max_minor = n;
46
47                 memset(&blktaps[minor], 0, (n - minor) * sizeof(blktaps[0]));
48         }
49
50         tap->minor = minor;
51         blktaps[minor] = tap;
52
53         __module_get(THIS_MODULE);
54 out:
55         mutex_unlock(&blktap_lock);
56         return tap;
57
58 fail:
59         mutex_unlock(&blktap_lock);
60         kfree(tap);
61         tap = NULL;
62         goto out;
63 }
64
65 static void
66 blktap_control_put_minor(struct blktap* tap)
67 {
68         blktaps[tap->minor] = NULL;
69         kfree(tap);
70
71         module_put(THIS_MODULE);
72 }
73
74 static struct blktap*
75 blktap_control_create_tap(void)
76 {
77         struct blktap *tap;
78         int err;
79
80         tap = blktap_control_get_minor();
81         if (!tap)
82                 return NULL;
83
84         kobject_get(&default_pool->kobj);
85         tap->pool = default_pool;
86
87         err = blktap_ring_create(tap);
88         if (err)
89                 goto fail_tap;
90
91         err = blktap_sysfs_create(tap);
92         if (err)
93                 goto fail_ring;
94
95         return tap;
96
97 fail_ring:
98         blktap_ring_destroy(tap);
99 fail_tap:
100         blktap_control_put_minor(tap);
101
102         return NULL;
103 }
104
105 int
106 blktap_control_destroy_tap(struct blktap *tap)
107 {
108         int err;
109
110         err = blktap_ring_destroy(tap);
111         if (err)
112                 return err;
113
114         kobject_put(&tap->pool->kobj);
115
116         blktap_sysfs_destroy(tap);
117
118         blktap_control_put_minor(tap);
119
120         return 0;
121 }
122
123 static long
124 blktap_control_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
125 {
126         struct blktap *tap;
127
128         switch (cmd) {
129         case BLKTAP2_IOCTL_ALLOC_TAP: {
130                 struct blktap_handle h;
131                 void __user *ptr = (void __user*)arg;
132
133                 tap = blktap_control_create_tap();
134                 if (!tap)
135                         return -ENOMEM;
136
137                 h.ring   = blktap_ring_major;
138                 h.device = blktap_device_major;
139                 h.minor  = tap->minor;
140
141                 if (copy_to_user(ptr, &h, sizeof(h))) {
142                         blktap_control_destroy_tap(tap);
143                         return -EFAULT;
144                 }
145
146                 return 0;
147         }
148
149         case BLKTAP2_IOCTL_FREE_TAP: {
150                 int minor = arg;
151
152                 if (minor > CONFIG_XEN_NR_TAP2_DEVICES)
153                         return -EINVAL;
154
155                 tap = blktaps[minor];
156                 if (!tap)
157                         return -ENODEV;
158
159                 return blktap_control_destroy_tap(tap);
160         }
161         }
162
163         return -ENOIOCTLCMD;
164 }
165
166 static const struct file_operations blktap_control_file_operations = {
167         .owner    = THIS_MODULE,
168         .unlocked_ioctl = blktap_control_ioctl,
169 };
170
171 static struct miscdevice blktap_control = {
172         .minor    = MISC_DYNAMIC_MINOR,
173         .name     = "blktap-control",
174         .nodename = BLKTAP2_DEV_DIR "control",
175         .fops     = &blktap_control_file_operations,
176 };
177
178 static struct device *control_device;
179
180 static ssize_t
181 blktap_control_show_default_pool(struct device *device,
182                                  struct device_attribute *attr,
183                                  char *buf)
184 {
185         return sprintf(buf, "%s", kobject_name(&default_pool->kobj));
186 }
187
188 static ssize_t
189 blktap_control_store_default_pool(struct device *device,
190                                   struct device_attribute *attr,
191                                   const char *buf, size_t size)
192 {
193         struct blktap_page_pool *pool, *tmp = default_pool;
194
195         pool = blktap_page_pool_get(buf);
196         if (IS_ERR(pool))
197                 return PTR_ERR(pool);
198
199         default_pool = pool;
200         kobject_put(&tmp->kobj);
201
202         return size;
203 }
204
205 static DEVICE_ATTR(default_pool, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
206                    blktap_control_show_default_pool,
207                    blktap_control_store_default_pool);
208
209 size_t
210 blktap_control_debug(struct blktap *tap, char *buf, size_t size)
211 {
212         char *s = buf, *end = buf + size;
213
214         s += snprintf(s, end - s,
215                       "tap %u:%u name:'%s' flags:%#08lx\n",
216                       MAJOR(tap->ring.devno), MINOR(tap->ring.devno),
217                       tap->name, tap->dev_inuse);
218
219         return s - buf;
220 }
221
222 static int __init
223 blktap_control_init(void)
224 {
225         int err;
226
227         err = misc_register(&blktap_control);
228         if (err)
229                 return err;
230
231         control_device = blktap_control.this_device;
232
233         blktap_max_minor = min(64, CONFIG_XEN_NR_TAP2_DEVICES);
234         blktaps = kzalloc(blktap_max_minor * sizeof(blktaps[0]), GFP_KERNEL);
235         if (!blktaps) {
236                 BTERR("failed to allocate blktap minor map");
237                 return -ENOMEM;
238         }
239
240         err = blktap_page_pool_init(&control_device->kobj);
241         if (err)
242                 return err;
243
244         default_pool = blktap_page_pool_get("default");
245         if (!default_pool)
246                 return -ENOMEM;
247
248         err = device_create_file(control_device, &dev_attr_default_pool);
249         if (err)
250                 return err;
251
252         return 0;
253 }
254
255 static void
256 blktap_control_exit(void)
257 {
258         if (default_pool) {
259                 kobject_put(&default_pool->kobj);
260                 default_pool = NULL;
261         }
262
263         blktap_page_pool_exit();
264
265         if (blktaps) {
266                 kfree(blktaps);
267                 blktaps = NULL;
268         }
269
270         if (control_device) {
271                 misc_deregister(&blktap_control);
272                 control_device = NULL;
273         }
274 }
275
276 static void
277 blktap_exit(void)
278 {
279         blktap_control_exit();
280         blktap_ring_exit();
281         blktap_sysfs_exit();
282         blktap_device_exit();
283 }
284
285 static int __init
286 blktap_init(void)
287 {
288         int err;
289
290         err = blktap_device_init();
291         if (err)
292                 goto fail;
293
294         err = blktap_ring_init();
295         if (err)
296                 goto fail;
297
298         err = blktap_sysfs_init();
299         if (err)
300                 goto fail;
301
302         err = blktap_control_init();
303         if (err)
304                 goto fail;
305
306         return 0;
307
308 fail:
309         blktap_exit();
310         return err;
311 }
312
313 module_init(blktap_init);
314 module_exit(blktap_exit);
315 MODULE_LICENSE("Dual BSD/GPL");
316 MODULE_ALIAS("devname:" BLKTAP2_DEV_DIR "control");