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