at v2.6.13 130 lines 2.9 kB view raw
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> 10 11 12struct 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; 17}; 18 19static DECLARE_MUTEX(numspace_mutex); 20 21static int expand_numspace(struct unique_numspace *s) 22{ 23 u32 length; 24 void *bits; 25 26 if (s->length < 16) 27 length = 16; 28 else 29 length = s->length << 1; 30 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); 37 } 38 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; 43 44 return 0; 45} 46 47static int alloc_unique_number(struct unique_numspace *s) 48{ 49 int rval = 0; 50 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); 58 } 59 up(&numspace_mutex); 60 61 return rval; 62} 63 64static void dealloc_unique_number(struct unique_numspace *s, int number) 65{ 66 int old_val; 67 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); 74 } 75} 76 77static struct unique_numspace disc_numspace; 78static struct unique_numspace cdrom_numspace; 79 80void devfs_add_partitioned(struct gendisk *disk) 81{ 82 char dirname[64], symlink[16]; 83 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); 88 89 disk->number = alloc_unique_number(&disc_numspace); 90 91 sprintf(symlink, "discs/disc%d", disk->number); 92 sprintf(dirname, "../%s", disk->devfs_name); 93 devfs_mk_symlink(symlink, dirname); 94 95} 96 97void devfs_add_disk(struct gendisk *disk) 98{ 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); 104 105 if (disk->flags & GENHD_FL_CD) { 106 char dirname[64], symlink[16]; 107 108 disk->number = alloc_unique_number(&cdrom_numspace); 109 110 sprintf(symlink, "cdroms/cdrom%d", disk->number); 111 sprintf(dirname, "../%s", disk->devfs_name); 112 devfs_mk_symlink(symlink, dirname); 113 } 114} 115 116void devfs_remove_disk(struct gendisk *disk) 117{ 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); 122 } 123 if (disk->flags & GENHD_FL_CD) { 124 devfs_remove("cdroms/cdrom%d", disk->number); 125 dealloc_unique_number(&cdrom_numspace, disk->number); 126 } 127 devfs_remove(disk->devfs_name); 128} 129 130