This commit was manufactured by cvs2svn to create branch 'vserver'.
[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/config.h>
16 #include <linux/module.h>
17 #include <linux/moduleparam.h>
18 #include <linux/file.h>
19 #include <linux/major.h>
20 #include <linux/blkdev.h>
21 #include <linux/devfs_fs_kernel.h>
22
23 #include <linux/vroot.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         printk(KERN_INFO "vroot[%d]_set_dev: dev=%p[%d,%d]\n",
64                 vr->vr_number, real_bdev,
65                 imajor(real_bdev->bd_inode), iminor(real_bdev->bd_inode));
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         printk(KERN_INFO "vroot[%d]_clr_dev: dev=%p[%d,%d]\n",
91                 vr->vr_number, real_bdev,
92                 imajor(real_bdev->bd_inode), iminor(real_bdev->bd_inode));
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         printk(KERN_INFO "vroot[%d]_get_real_bdev: dev=%p[%p,%d,%d]\n",
161                 vr->vr_number, real_bdev, real_bdev->bd_inode,
162                 imajor(real_bdev->bd_inode), iminor(real_bdev->bd_inode));
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     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         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         devfs_mk_dir("vroot");
215
216         for (i = 0; i < max_vroot; i++) {
217                 struct vroot_device *vr = &vroot_dev[i];
218                 struct gendisk *disk = disks[i];
219
220                 memset(vr, 0, sizeof(*vr));
221                 init_MUTEX(&vr->vr_ctl_mutex);
222                 vr->vr_number = i;
223                 disk->major = VROOT_MAJOR;
224                 disk->first_minor = i;
225                 disk->fops = &vr_fops;
226                 sprintf(disk->disk_name, "vroot%d", i);
227                 sprintf(disk->devfs_name, "vroot/%d", i);
228                 disk->private_data = vr;
229         }
230
231         for (i = 0; i < max_vroot; i++)
232                 add_disk(disks[i]);
233         printk(KERN_INFO "vroot: loaded (max %d devices)\n", max_vroot);
234         return 0;
235
236 out_mem3:
237         while (i--)
238                 put_disk(disks[i]);
239         kfree(disks);
240 out_mem2:
241         kfree(vroot_dev);
242 out_mem1:
243         unregister_blkdev(VROOT_MAJOR, "vroot");
244         printk(KERN_ERR "vroot: ran out of memory\n");
245         return -ENOMEM;
246 }
247
248 void vroot_exit(void)
249 {
250         int i;
251
252         for (i = 0; i < max_vroot; i++) {
253                 del_gendisk(disks[i]);
254                 put_disk(disks[i]);
255         }
256         devfs_remove("vroot");
257         if (unregister_blkdev(VROOT_MAJOR, "vroot"))
258                 printk(KERN_WARNING "vroot: cannot unregister blkdev\n");
259
260         kfree(disks);
261         kfree(vroot_dev);
262 }
263
264 module_init(vroot_init);
265 module_exit(vroot_exit);
266