Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / block / vroot.c
1 /*
2  *  linux/drivers/block/vroot.c
3  *
4  *  written by Herbert Pötzl, 9/11/2002
5  *  ported to 2.6.10 by Herbert Pötzl, 30/12/2004
6  *
7  *  based on the loop.c code by Theodore Ts'o.
8  *
9  * Copyright (C) 2002-2005 by Herbert Pötzl.
10  * Redistribution of this file is permitted under the
11  * GNU General Public License.
12  *
13  */
14
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/file.h>
18 #include <linux/major.h>
19 #include <linux/blkdev.h>
20 #include <linux/devfs_fs_kernel.h>
21
22 #include <linux/vroot.h>
23 #include <linux/vserver/debug.h>
24
25
26 static int max_vroot = 8;
27
28 static struct vroot_device *vroot_dev;
29 static struct gendisk **disks;
30
31
32 static int vroot_set_dev(
33         struct vroot_device *vr,
34         struct file *vr_file,
35         struct block_device *bdev,
36         unsigned int arg)
37 {
38         struct block_device *real_bdev;
39         struct file *file;
40         struct inode *inode;
41         int error;
42
43         error = -EBUSY;
44         if (vr->vr_state != Vr_unbound)
45                 goto out;
46
47         error = -EBADF;
48         file = fget(arg);
49         if (!file)
50                 goto out;
51
52         error = -EINVAL;
53         inode = file->f_dentry->d_inode;
54
55
56         if (S_ISBLK(inode->i_mode)) {
57                 real_bdev = inode->i_bdev;
58                 vr->vr_device = real_bdev;
59                 __iget(real_bdev->bd_inode);
60         } else
61                 goto out_fput;
62
63         vxdprintk(VXD_CBIT(misc, 0),
64                 "vroot[%d]_set_dev: dev=" VXF_DEV,
65                 vr->vr_number, VXD_DEV(real_bdev));
66
67         vr->vr_state = Vr_bound;
68         error = 0;
69
70  out_fput:
71         fput(file);
72  out:
73         return error;
74 }
75
76 static int vroot_clr_dev(
77         struct vroot_device *vr,
78         struct file *vr_file,
79         struct block_device *bdev)
80 {
81         struct block_device *real_bdev;
82
83         if (vr->vr_state != Vr_bound)
84                 return -ENXIO;
85         if (vr->vr_refcnt > 1)  /* we needed one fd for the ioctl */
86                 return -EBUSY;
87
88         real_bdev = vr->vr_device;
89
90         vxdprintk(VXD_CBIT(misc, 0),
91                 "vroot[%d]_clr_dev: dev=" VXF_DEV,
92                 vr->vr_number, VXD_DEV(real_bdev));
93
94         bdput(real_bdev);
95         vr->vr_state = Vr_unbound;
96         vr->vr_device = NULL;
97         return 0;
98 }
99
100
101 static int vr_ioctl(struct inode * inode, struct file * file,
102         unsigned int cmd, unsigned long arg)
103 {
104         struct vroot_device *vr = inode->i_bdev->bd_disk->private_data;
105         int err;
106
107         down(&vr->vr_ctl_mutex);
108         switch (cmd) {
109         case VROOT_SET_DEV:
110                 err = vroot_set_dev(vr, file, inode->i_bdev, arg);
111                 break;
112         case VROOT_CLR_DEV:
113                 err = vroot_clr_dev(vr, file, inode->i_bdev);
114                 break;
115         default:
116                 err = -EINVAL;
117                 break;
118         }
119         up(&vr->vr_ctl_mutex);
120         return err;
121 }
122
123 static int vr_open(struct inode *inode, struct file *file)
124 {
125         struct vroot_device *vr = inode->i_bdev->bd_disk->private_data;
126
127         down(&vr->vr_ctl_mutex);
128         vr->vr_refcnt++;
129         up(&vr->vr_ctl_mutex);
130         return 0;
131 }
132
133 static int vr_release(struct inode *inode, struct file *file)
134 {
135         struct vroot_device *vr = inode->i_bdev->bd_disk->private_data;
136
137         down(&vr->vr_ctl_mutex);
138         --vr->vr_refcnt;
139         up(&vr->vr_ctl_mutex);
140         return 0;
141 }
142
143 static struct block_device_operations vr_fops = {
144         .owner =        THIS_MODULE,
145         .open =         vr_open,
146         .release =      vr_release,
147         .ioctl =        vr_ioctl,
148 };
149
150 struct block_device *__vroot_get_real_bdev(struct block_device *bdev)
151 {
152         struct inode *inode = bdev->bd_inode;
153         struct vroot_device *vr;
154         struct block_device *real_bdev;
155         int minor = iminor(inode);
156
157         vr = &vroot_dev[minor];
158         real_bdev = vr->vr_device;
159
160         vxdprintk(VXD_CBIT(misc, 0),
161                 "vroot[%d]_get_real_bdev: dev=" VXF_DEV,
162                 vr->vr_number, VXD_DEV(real_bdev));
163
164         if (vr->vr_state != Vr_bound)
165                 return ERR_PTR(-ENXIO);
166
167         __iget(real_bdev->bd_inode);
168         return real_bdev;
169 }
170
171 /*
172  * And now the modules code and kernel interface.
173  */
174
175 module_param(max_vroot, int, 0);
176
177 MODULE_PARM_DESC(max_vroot, "Maximum number of vroot devices (1-256)");
178 MODULE_LICENSE("GPL");
179 MODULE_ALIAS_BLOCKDEV_MAJOR(VROOT_MAJOR);
180
181 MODULE_AUTHOR ("Herbert Pötzl");
182 MODULE_DESCRIPTION ("Virtual Root Device Mapper");
183
184
185 int __init vroot_init(void)
186 {
187         int err, i;
188
189         if (max_vroot < 1 || max_vroot > 256) {
190                 max_vroot = MAX_VROOT_DEFAULT;
191                 printk(KERN_WARNING "vroot: invalid max_vroot "
192                         "(must be between 1 and 256), "
193                         "using default (%d)\n", max_vroot);
194         }
195
196         if (register_blkdev(VROOT_MAJOR, "vroot"))
197                 return -EIO;
198
199         err = -ENOMEM;
200         vroot_dev = kmalloc(max_vroot * sizeof(struct vroot_device), GFP_KERNEL);
201         if (!vroot_dev)
202                 goto out_mem1;
203         memset(vroot_dev, 0, max_vroot * sizeof(struct vroot_device));
204
205         disks = kmalloc(max_vroot * sizeof(struct gendisk *), GFP_KERNEL);
206         if (!disks)
207                 goto out_mem2;
208
209         for (i = 0; i < max_vroot; i++) {
210                 disks[i] = alloc_disk(1);
211                 if (!disks[i])
212                         goto out_mem3;
213         }
214
215         devfs_mk_dir("vroot");
216
217         for (i = 0; i < max_vroot; i++) {
218                 struct vroot_device *vr = &vroot_dev[i];
219                 struct gendisk *disk = disks[i];
220
221                 memset(vr, 0, sizeof(*vr));
222                 init_MUTEX(&vr->vr_ctl_mutex);
223                 vr->vr_number = i;
224                 disk->major = VROOT_MAJOR;
225                 disk->first_minor = i;
226                 disk->fops = &vr_fops;
227                 sprintf(disk->disk_name, "vroot%d", i);
228                 sprintf(disk->devfs_name, "vroot/%d", i);
229                 disk->private_data = vr;
230         }
231
232         err = register_vroot_grb(&__vroot_get_real_bdev);
233         if (err)
234                 goto out_reg;
235
236         for (i = 0; i < max_vroot; i++)
237                 add_disk(disks[i]);
238         printk(KERN_INFO "vroot: loaded (max %d devices)\n", max_vroot);
239         return 0;
240
241 out_reg:
242         devfs_remove("vroot");
243 out_mem3:
244         while (i--)
245                 put_disk(disks[i]);
246         kfree(disks);
247 out_mem2:
248         kfree(vroot_dev);
249 out_mem1:
250         unregister_blkdev(VROOT_MAJOR, "vroot");
251         printk(KERN_ERR "vroot: ran out of memory\n");
252         return err;
253 }
254
255 void vroot_exit(void)
256 {
257         int i;
258
259         if (unregister_vroot_grb(&__vroot_get_real_bdev))
260                 printk(KERN_WARNING "vroot: cannot unregister grb\n");
261
262         for (i = 0; i < max_vroot; i++) {
263                 del_gendisk(disks[i]);
264                 put_disk(disks[i]);
265         }
266         devfs_remove("vroot");
267         if (unregister_blkdev(VROOT_MAJOR, "vroot"))
268                 printk(KERN_WARNING "vroot: cannot unregister blkdev\n");
269
270         kfree(disks);
271         kfree(vroot_dev);
272 }
273
274 module_init(vroot_init);
275 module_exit(vroot_exit);
276
277 #ifndef MODULE
278
279 static int __init max_vroot_setup(char *str)
280 {
281         max_vroot = simple_strtol(str, NULL, 0);
282         return 1;
283 }
284
285 __setup("max_vroot=", max_vroot_setup);
286
287 #endif
288