devfs.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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 <linux/mutex.h>
  10. struct unique_numspace {
  11. u32 num_free; /* Num free in bits */
  12. u32 length; /* Array length in bytes */
  13. unsigned long *bits;
  14. struct semaphore mutex;
  15. };
  16. static DEFINE_MUTEX(numspace_mutex);
  17. static int expand_numspace(struct unique_numspace *s)
  18. {
  19. u32 length;
  20. void *bits;
  21. if (s->length < 16)
  22. length = 16;
  23. else
  24. length = s->length << 1;
  25. bits = vmalloc(length);
  26. if (!bits)
  27. return -ENOMEM;
  28. if (s->bits) {
  29. memcpy(bits, s->bits, s->length);
  30. vfree(s->bits);
  31. }
  32. s->num_free = (length - s->length) << 3;
  33. s->bits = bits;
  34. memset(bits + s->length, 0, length - s->length);
  35. s->length = length;
  36. return 0;
  37. }
  38. static int alloc_unique_number(struct unique_numspace *s)
  39. {
  40. int rval = 0;
  41. mutex_lock(&numspace_mutex);
  42. if (s->num_free < 1)
  43. rval = expand_numspace(s);
  44. if (!rval) {
  45. rval = find_first_zero_bit(s->bits, s->length << 3);
  46. --s->num_free;
  47. __set_bit(rval, s->bits);
  48. }
  49. mutex_unlock(&numspace_mutex);
  50. return rval;
  51. }
  52. static void dealloc_unique_number(struct unique_numspace *s, int number)
  53. {
  54. int old_val;
  55. if (number >= 0) {
  56. mutex_lock(&numspace_mutex);
  57. old_val = __test_and_clear_bit(number, s->bits);
  58. if (old_val)
  59. ++s->num_free;
  60. mutex_unlock(&numspace_mutex);
  61. }
  62. }
  63. static struct unique_numspace disc_numspace;
  64. static struct unique_numspace cdrom_numspace;
  65. void devfs_add_partitioned(struct gendisk *disk)
  66. {
  67. char dirname[64], symlink[16];
  68. devfs_mk_dir(disk->devfs_name);
  69. devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
  70. S_IFBLK|S_IRUSR|S_IWUSR,
  71. "%s/disc", disk->devfs_name);
  72. disk->number = alloc_unique_number(&disc_numspace);
  73. sprintf(symlink, "discs/disc%d", disk->number);
  74. sprintf(dirname, "../%s", disk->devfs_name);
  75. devfs_mk_symlink(symlink, dirname);
  76. }
  77. void devfs_add_disk(struct gendisk *disk)
  78. {
  79. devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
  80. (disk->flags & GENHD_FL_CD) ?
  81. S_IFBLK|S_IRUGO|S_IWUGO :
  82. S_IFBLK|S_IRUSR|S_IWUSR,
  83. "%s", disk->devfs_name);
  84. if (disk->flags & GENHD_FL_CD) {
  85. char dirname[64], symlink[16];
  86. disk->number = alloc_unique_number(&cdrom_numspace);
  87. sprintf(symlink, "cdroms/cdrom%d", disk->number);
  88. sprintf(dirname, "../%s", disk->devfs_name);
  89. devfs_mk_symlink(symlink, dirname);
  90. }
  91. }
  92. void devfs_remove_disk(struct gendisk *disk)
  93. {
  94. if (disk->minors != 1) {
  95. devfs_remove("discs/disc%d", disk->number);
  96. dealloc_unique_number(&disc_numspace, disk->number);
  97. devfs_remove("%s/disc", disk->devfs_name);
  98. }
  99. if (disk->flags & GENHD_FL_CD) {
  100. devfs_remove("cdroms/cdrom%d", disk->number);
  101. dealloc_unique_number(&cdrom_numspace, disk->number);
  102. }
  103. devfs_remove(disk->devfs_name);
  104. }