- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / blktap2-new / sysfs.c
1 #include <linux/types.h>
2 #include <linux/device.h>
3 #include <linux/module.h>
4 #include <linux/sched.h>
5 #include <linux/genhd.h>
6 #include <linux/blkdev.h>
7
8 #include "blktap.h"
9
10 int blktap_debug_level = 1;
11
12 static struct class *class;
13
14 static ssize_t
15 blktap_sysfs_set_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
16 {
17         struct blktap *tap;
18
19         tap = dev_get_drvdata(dev);
20         if (!tap)
21                 return 0;
22
23         if (size > BLKTAP2_MAX_MESSAGE_LEN)
24                 return -ENAMETOOLONG;
25
26         if (strnlen(buf, size) >= size)
27                 return -EINVAL;
28
29         strlcpy(tap->name, buf, size);
30
31         return size;
32 }
33
34 static ssize_t
35 blktap_sysfs_get_name(struct device *dev, struct device_attribute *attr, char *buf)
36 {
37         struct blktap *tap;
38         ssize_t size;
39
40         tap = dev_get_drvdata(dev);
41         if (!tap)
42                 return 0;
43
44         if (tap->name[0])
45                 size = sprintf(buf, "%s\n", tap->name);
46         else
47                 size = sprintf(buf, "%d\n", tap->minor);
48
49         return size;
50 }
51 static DEVICE_ATTR(name, S_IRUGO|S_IWUSR,
52                    blktap_sysfs_get_name, blktap_sysfs_set_name);
53
54 static void
55 blktap_sysfs_remove_work(struct work_struct *work)
56 {
57         struct blktap *tap
58                 = container_of(work, struct blktap, remove_work);
59         blktap_control_destroy_tap(tap);
60 }
61
62 static ssize_t
63 blktap_sysfs_remove_device(struct device *dev,
64                            struct device_attribute *attr,
65                            const char *buf, size_t size)
66 {
67         struct blktap *tap;
68         int err;
69
70         tap = dev_get_drvdata(dev);
71         if (!tap)
72                 return size;
73
74         if (test_and_set_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse))
75                 goto wait;
76
77         if (tap->ring.vma) {
78                 struct blkif_sring *sring = tap->ring.ring.sring;
79                 sring->private.tapif_user.msg = BLKTAP2_RING_MESSAGE_CLOSE;
80                 blktap_ring_kick_user(tap);
81         } else {
82                 INIT_WORK(&tap->remove_work, blktap_sysfs_remove_work);
83                 schedule_work(&tap->remove_work);
84         }
85 wait:
86         err = wait_event_interruptible(tap->remove_wait,
87                                        !dev_get_drvdata(dev));
88         if (err)
89                 return err;
90
91         return size;
92 }
93 static DEVICE_ATTR(remove, S_IWUSR, NULL, blktap_sysfs_remove_device);
94
95 static ssize_t
96 blktap_sysfs_debug_device(struct device *dev, struct device_attribute *attr, char *buf)
97 {
98         struct blktap *tap;
99         char *s = buf, *end = buf + PAGE_SIZE;
100
101         tap = dev_get_drvdata(dev);
102         if (!tap)
103                 return 0;
104
105         s += blktap_control_debug(tap, s, end - s);
106
107         s += blktap_request_debug(tap, s, end - s);
108
109         s += blktap_device_debug(tap, s, end - s);
110
111         s += blktap_ring_debug(tap, s, end - s);
112
113         return s - buf;
114 }
115 static DEVICE_ATTR(debug, S_IRUGO, blktap_sysfs_debug_device, NULL);
116
117 static ssize_t
118 blktap_sysfs_show_task(struct device *dev, struct device_attribute *attr, char *buf)
119 {
120         struct blktap *tap;
121         ssize_t rv = 0;
122
123         tap = dev_get_drvdata(dev);
124         if (!tap)
125                 return 0;
126
127         if (tap->ring.task)
128                 rv = sprintf(buf, "%d\n", tap->ring.task->pid);
129
130         return rv;
131 }
132 static DEVICE_ATTR(task, S_IRUGO, blktap_sysfs_show_task, NULL);
133
134 static ssize_t
135 blktap_sysfs_show_pool(struct device *dev,
136                        struct device_attribute *attr,
137                        char *buf)
138 {
139         struct blktap *tap = dev_get_drvdata(dev);
140         return sprintf(buf, "%s", kobject_name(&tap->pool->kobj));
141 }
142
143 static ssize_t
144 blktap_sysfs_store_pool(struct device *dev,
145                         struct device_attribute *attr,
146                         const char *buf, size_t size)
147 {
148         struct blktap *tap = dev_get_drvdata(dev);
149         struct blktap_page_pool *pool, *tmp = tap->pool;
150
151         if (tap->device.gd)
152                 return -EBUSY;
153
154         pool = blktap_page_pool_get(buf);
155         if (IS_ERR(pool))
156                 return PTR_ERR(pool);
157
158         tap->pool = pool;
159         kobject_put(&tmp->kobj);
160
161         return size;
162 }
163 static DEVICE_ATTR(pool, S_IRUSR|S_IWUSR,
164                    blktap_sysfs_show_pool, blktap_sysfs_store_pool);
165
166 int
167 blktap_sysfs_create(struct blktap *tap)
168 {
169         struct blktap_ring *ring = &tap->ring;
170         struct device *dev;
171         int err = 0;
172
173         init_waitqueue_head(&tap->remove_wait);
174
175         dev = device_create(class, NULL, ring->devno,
176                             tap, "blktap%d", tap->minor);
177         if (IS_ERR(dev))
178                 err = PTR_ERR(dev);
179         if (!err)
180                 err = device_create_file(dev, &dev_attr_name);
181         if (!err)
182                 err = device_create_file(dev, &dev_attr_remove);
183         if (!err)
184                 err = device_create_file(dev, &dev_attr_debug);
185         if (!err)
186                 err = device_create_file(dev, &dev_attr_task);
187         if (!err)
188                 err = device_create_file(dev, &dev_attr_pool);
189         if (!err)
190                 ring->dev = dev;
191         else
192                 device_unregister(dev);
193
194         return err;
195 }
196
197 void
198 blktap_sysfs_destroy(struct blktap *tap)
199 {
200         struct blktap_ring *ring = &tap->ring;
201         struct device *dev;
202
203         dev = ring->dev;
204
205         if (!dev)
206                 return;
207
208         dev_set_drvdata(dev, NULL);
209         wake_up(&tap->remove_wait);
210
211         device_unregister(dev);
212         ring->dev = NULL;
213 }
214
215 static ssize_t
216 blktap_sysfs_show_verbosity(struct class *class, struct class_attribute *attr,
217                             char *buf)
218 {
219         return sprintf(buf, "%d\n", blktap_debug_level);
220 }
221
222 static ssize_t
223 blktap_sysfs_set_verbosity(struct class *class, struct class_attribute *attr,
224                            const char *buf, size_t size)
225 {
226         int level;
227
228         if (sscanf(buf, "%d", &level) == 1) {
229                 blktap_debug_level = level;
230                 return size;
231         }
232
233         return -EINVAL;
234 }
235 static CLASS_ATTR(verbosity, S_IRUGO|S_IWUSR,
236                   blktap_sysfs_show_verbosity, blktap_sysfs_set_verbosity);
237
238 static ssize_t
239 blktap_sysfs_show_devices(struct class *class, struct class_attribute *attr,
240                           char *buf)
241 {
242         int i, ret;
243         struct blktap *tap;
244
245         mutex_lock(&blktap_lock);
246
247         ret = 0;
248         for (i = 0; i < blktap_max_minor; i++) {
249                 tap = blktaps[i];
250                 if (!tap)
251                         continue;
252
253                 if (!test_bit(BLKTAP_DEVICE, &tap->dev_inuse))
254                         continue;
255
256                 ret += sprintf(buf + ret, "%d %s\n", tap->minor, tap->name);
257         }
258
259         mutex_unlock(&blktap_lock);
260
261         return ret;
262 }
263 static CLASS_ATTR(devices, S_IRUGO, blktap_sysfs_show_devices, NULL);
264
265 static char *blktap_devnode(struct device *dev, umode_t *mode)
266 {
267         return kasprintf(GFP_KERNEL, BLKTAP2_DEV_DIR "blktap%u",
268                          MINOR(dev->devt));
269 }
270
271 void
272 blktap_sysfs_exit(void)
273 {
274         if (class)
275                 class_destroy(class);
276 }
277
278 int __init
279 blktap_sysfs_init(void)
280 {
281         struct class *cls;
282         int err = 0;
283
284         cls = class_create(THIS_MODULE, "blktap2");
285         if (IS_ERR(cls))
286                 err = PTR_ERR(cls);
287         else
288                 cls->devnode = blktap_devnode;
289         if (!err)
290                 err = class_create_file(cls, &class_attr_verbosity);
291         if (!err)
292                 err = class_create_file(cls, &class_attr_devices);
293         if (!err)
294                 class = cls;
295         else
296                 class_destroy(cls);
297
298         return err;
299 }