2 * This tries to keep block devices away from devfs as much as possible.
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 */
16 struct semaphore mutex
;
19 static DECLARE_MUTEX(numspace_mutex
);
21 static int expand_numspace(struct unique_numspace
*s
)
29 length
= s
->length
<< 1;
31 bits
= vmalloc(length
);
35 memcpy(bits
, s
->bits
, s
->length
);
39 s
->num_free
= (length
- s
->length
) << 3;
41 memset(bits
+ s
->length
, 0, length
- s
->length
);
47 static int alloc_unique_number(struct unique_numspace
*s
)
51 down(&numspace_mutex
);
53 rval
= expand_numspace(s
);
55 rval
= find_first_zero_bit(s
->bits
, s
->length
<< 3);
57 __set_bit(rval
, s
->bits
);
64 static void dealloc_unique_number(struct unique_numspace
*s
, int number
)
69 down(&numspace_mutex
);
70 old_val
= __test_and_clear_bit(number
, s
->bits
);
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
);