Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / partitions / devfs.c
blob87f50444fd3932bcfe93550e51ac3f8ba265d52a
1 /*
2 * This tries to keep block devices away from devfs as much as possible.
3 */
4 #include <linux/fs.h>
5 #include <linux/devfs_fs_kernel.h>
6 #include <linux/vmalloc.h>
7 #include <linux/genhd.h>
8 #include <linux/bitops.h>
9 #include <asm/semaphore.h>
12 struct unique_numspace {
13 u32 num_free; /* Num free in bits */
14 u32 length; /* Array length in bytes */
15 unsigned long *bits;
16 struct semaphore mutex;
19 static DECLARE_MUTEX(numspace_mutex);
21 static int expand_numspace(struct unique_numspace *s)
23 u32 length;
24 void *bits;
26 if (s->length < 16)
27 length = 16;
28 else
29 length = s->length << 1;
31 bits = vmalloc(length);
32 if (!bits)
33 return -ENOMEM;
34 if (s->bits) {
35 memcpy(bits, s->bits, s->length);
36 vfree(s->bits);
39 s->num_free = (length - s->length) << 3;
40 s->bits = bits;
41 memset(bits + s->length, 0, length - s->length);
42 s->length = length;
44 return 0;
47 static int alloc_unique_number(struct unique_numspace *s)
49 int rval = 0;
51 down(&numspace_mutex);
52 if (s->num_free < 1)
53 rval = expand_numspace(s);
54 if (!rval) {
55 rval = find_first_zero_bit(s->bits, s->length << 3);
56 --s->num_free;
57 __set_bit(rval, s->bits);
59 up(&numspace_mutex);
61 return rval;
64 static void dealloc_unique_number(struct unique_numspace *s, int number)
66 int old_val;
68 if (number >= 0) {
69 down(&numspace_mutex);
70 old_val = __test_and_clear_bit(number, s->bits);
71 if (old_val)
72 ++s->num_free;
73 up(&numspace_mutex);
77 static struct unique_numspace disc_numspace;
78 static struct unique_numspace cdrom_numspace;
80 void devfs_add_partitioned(struct gendisk *disk)
82 char dirname[64], symlink[16];
84 devfs_mk_dir(disk->devfs_name);
85 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
86 S_IFBLK|S_IRUSR|S_IWUSR,
87 "%s/disc", disk->devfs_name);
89 disk->number = alloc_unique_number(&disc_numspace);
91 sprintf(symlink, "discs/disc%d", disk->number);
92 sprintf(dirname, "../%s", disk->devfs_name);
93 devfs_mk_symlink(symlink, dirname);
97 void devfs_add_disk(struct gendisk *disk)
99 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
100 (disk->flags & GENHD_FL_CD) ?
101 S_IFBLK|S_IRUGO|S_IWUGO :
102 S_IFBLK|S_IRUSR|S_IWUSR,
103 "%s", disk->devfs_name);
105 if (disk->flags & GENHD_FL_CD) {
106 char dirname[64], symlink[16];
108 disk->number = alloc_unique_number(&cdrom_numspace);
110 sprintf(symlink, "cdroms/cdrom%d", disk->number);
111 sprintf(dirname, "../%s", disk->devfs_name);
112 devfs_mk_symlink(symlink, dirname);
116 void devfs_remove_disk(struct gendisk *disk)
118 if (disk->minors != 1) {
119 devfs_remove("discs/disc%d", disk->number);
120 dealloc_unique_number(&disc_numspace, disk->number);
121 devfs_remove("%s/disc", disk->devfs_name);
123 if (disk->flags & GENHD_FL_CD) {
124 devfs_remove("cdroms/cdrom%d", disk->number);
125 dealloc_unique_number(&cdrom_numspace, disk->number);
127 devfs_remove(disk->devfs_name);