123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- /*
- * This tries to keep block devices away from devfs as much as possible.
- */
- #include <linux/fs.h>
- #include <linux/devfs_fs_kernel.h>
- #include <linux/vmalloc.h>
- #include <linux/genhd.h>
- #include <linux/bitops.h>
- #include <linux/mutex.h>
- struct unique_numspace {
- u32 num_free; /* Num free in bits */
- u32 length; /* Array length in bytes */
- unsigned long *bits;
- struct semaphore mutex;
- };
- static DEFINE_MUTEX(numspace_mutex);
- static int expand_numspace(struct unique_numspace *s)
- {
- u32 length;
- void *bits;
- if (s->length < 16)
- length = 16;
- else
- length = s->length << 1;
- bits = vmalloc(length);
- if (!bits)
- return -ENOMEM;
- if (s->bits) {
- memcpy(bits, s->bits, s->length);
- vfree(s->bits);
- }
-
- s->num_free = (length - s->length) << 3;
- s->bits = bits;
- memset(bits + s->length, 0, length - s->length);
- s->length = length;
- return 0;
- }
- static int alloc_unique_number(struct unique_numspace *s)
- {
- int rval = 0;
- mutex_lock(&numspace_mutex);
- if (s->num_free < 1)
- rval = expand_numspace(s);
- if (!rval) {
- rval = find_first_zero_bit(s->bits, s->length << 3);
- --s->num_free;
- __set_bit(rval, s->bits);
- }
- mutex_unlock(&numspace_mutex);
- return rval;
- }
- static void dealloc_unique_number(struct unique_numspace *s, int number)
- {
- int old_val;
- if (number >= 0) {
- mutex_lock(&numspace_mutex);
- old_val = __test_and_clear_bit(number, s->bits);
- if (old_val)
- ++s->num_free;
- mutex_unlock(&numspace_mutex);
- }
- }
- static struct unique_numspace disc_numspace;
- static struct unique_numspace cdrom_numspace;
- void devfs_add_partitioned(struct gendisk *disk)
- {
- char dirname[64], symlink[16];
- devfs_mk_dir(disk->devfs_name);
- devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
- S_IFBLK|S_IRUSR|S_IWUSR,
- "%s/disc", disk->devfs_name);
- disk->number = alloc_unique_number(&disc_numspace);
- sprintf(symlink, "discs/disc%d", disk->number);
- sprintf(dirname, "../%s", disk->devfs_name);
- devfs_mk_symlink(symlink, dirname);
- }
- void devfs_add_disk(struct gendisk *disk)
- {
- devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
- (disk->flags & GENHD_FL_CD) ?
- S_IFBLK|S_IRUGO|S_IWUGO :
- S_IFBLK|S_IRUSR|S_IWUSR,
- "%s", disk->devfs_name);
- if (disk->flags & GENHD_FL_CD) {
- char dirname[64], symlink[16];
- disk->number = alloc_unique_number(&cdrom_numspace);
- sprintf(symlink, "cdroms/cdrom%d", disk->number);
- sprintf(dirname, "../%s", disk->devfs_name);
- devfs_mk_symlink(symlink, dirname);
- }
- }
- void devfs_remove_disk(struct gendisk *disk)
- {
- if (disk->minors != 1) {
- devfs_remove("discs/disc%d", disk->number);
- dealloc_unique_number(&disc_numspace, disk->number);
- devfs_remove("%s/disc", disk->devfs_name);
- }
- if (disk->flags & GENHD_FL_CD) {
- devfs_remove("cdroms/cdrom%d", disk->number);
- dealloc_unique_number(&cdrom_numspace, disk->number);
- }
- devfs_remove(disk->devfs_name);
- }
|