diff options
author | Joe Korty <joe.korty@ccur.com> | 2006-03-31 05:30:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-31 15:18:53 -0500 |
commit | 68eef3b4791572ecb70249c7fb145bb3742dd899 (patch) | |
tree | 1f61fce839cec8d672ae06a423d46f0a6fcd924d /block | |
parent | a2c348fe0117adced11e374329a5ea3f7c43cb41 (diff) |
[PATCH] Simplify proc/devices and fix early termination regression
Make baby-simple the code for /proc/devices. Based on the proven design
for /proc/interrupts.
This also fixes the early-termination regression 2.6.16 introduced, as
demonstrated by:
# dd if=/proc/devices bs=1
Character devices:
1 mem
27+0 records in
27+0 records out
This should also work (but is untested) when /proc/devices >4096 bytes,
which I believe is what the original 2.6.16 rewrite fixed.
[akpm@osdl.org: cleanups, simplifications]
Signed-off-by: Joe Korty <joe.korty@ccur.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'block')
-rw-r--r-- | block/genhd.c | 103 |
1 files changed, 11 insertions, 92 deletions
diff --git a/block/genhd.c b/block/genhd.c index db4c60c802d6..5a8d3bf02f17 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | 19 | ||
20 | #define MAX_PROBE_HASH 255 /* random */ | ||
21 | |||
22 | static struct subsystem block_subsys; | 20 | static struct subsystem block_subsys; |
23 | 21 | ||
24 | static DEFINE_MUTEX(block_subsys_lock); | 22 | static DEFINE_MUTEX(block_subsys_lock); |
@@ -31,108 +29,29 @@ static struct blk_major_name { | |||
31 | struct blk_major_name *next; | 29 | struct blk_major_name *next; |
32 | int major; | 30 | int major; |
33 | char name[16]; | 31 | char name[16]; |
34 | } *major_names[MAX_PROBE_HASH]; | 32 | } *major_names[BLKDEV_MAJOR_HASH_SIZE]; |
35 | 33 | ||
36 | /* index in the above - for now: assume no multimajor ranges */ | 34 | /* index in the above - for now: assume no multimajor ranges */ |
37 | static inline int major_to_index(int major) | 35 | static inline int major_to_index(int major) |
38 | { | 36 | { |
39 | return major % MAX_PROBE_HASH; | 37 | return major % BLKDEV_MAJOR_HASH_SIZE; |
40 | } | ||
41 | |||
42 | struct blkdev_info { | ||
43 | int index; | ||
44 | struct blk_major_name *bd; | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * iterate over a list of blkdev_info structures. allows | ||
49 | * the major_names array to be iterated over from outside this file | ||
50 | * must be called with the block_subsys_lock held | ||
51 | */ | ||
52 | void *get_next_blkdev(void *dev) | ||
53 | { | ||
54 | struct blkdev_info *info; | ||
55 | |||
56 | if (dev == NULL) { | ||
57 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
58 | if (!info) | ||
59 | goto out; | ||
60 | info->index=0; | ||
61 | info->bd = major_names[info->index]; | ||
62 | if (info->bd) | ||
63 | goto out; | ||
64 | } else { | ||
65 | info = dev; | ||
66 | } | ||
67 | |||
68 | while (info->index < ARRAY_SIZE(major_names)) { | ||
69 | if (info->bd) | ||
70 | info->bd = info->bd->next; | ||
71 | if (info->bd) | ||
72 | goto out; | ||
73 | /* | ||
74 | * No devices on this chain, move to the next | ||
75 | */ | ||
76 | info->index++; | ||
77 | info->bd = (info->index < ARRAY_SIZE(major_names)) ? | ||
78 | major_names[info->index] : NULL; | ||
79 | if (info->bd) | ||
80 | goto out; | ||
81 | } | ||
82 | |||
83 | out: | ||
84 | return info; | ||
85 | } | ||
86 | |||
87 | void *acquire_blkdev_list(void) | ||
88 | { | ||
89 | mutex_lock(&block_subsys_lock); | ||
90 | return get_next_blkdev(NULL); | ||
91 | } | ||
92 | |||
93 | void release_blkdev_list(void *dev) | ||
94 | { | ||
95 | mutex_unlock(&block_subsys_lock); | ||
96 | kfree(dev); | ||
97 | } | 38 | } |
98 | 39 | ||
40 | #ifdef CONFIG_PROC_FS | ||
99 | 41 | ||
100 | /* | 42 | void blkdev_show(struct seq_file *f, off_t offset) |
101 | * Count the number of records in the blkdev_list. | ||
102 | * must be called with the block_subsys_lock held | ||
103 | */ | ||
104 | int count_blkdev_list(void) | ||
105 | { | 43 | { |
106 | struct blk_major_name *n; | 44 | struct blk_major_name *dp; |
107 | int i, count; | ||
108 | 45 | ||
109 | count = 0; | 46 | if (offset < BLKDEV_MAJOR_HASH_SIZE) { |
110 | 47 | mutex_lock(&block_subsys_lock); | |
111 | for (i = 0; i < ARRAY_SIZE(major_names); i++) { | 48 | for (dp = major_names[offset]; dp; dp = dp->next) |
112 | for (n = major_names[i]; n; n = n->next) | 49 | seq_printf(f, "%3d %s\n", dp->major, dp->name); |
113 | count++; | 50 | mutex_unlock(&block_subsys_lock); |
114 | } | 51 | } |
115 | |||
116 | return count; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * extract the major and name values from a blkdev_info struct | ||
121 | * passed in as a void to *dev. Must be called with | ||
122 | * block_subsys_lock held | ||
123 | */ | ||
124 | int get_blkdev_info(void *dev, int *major, char **name) | ||
125 | { | ||
126 | struct blkdev_info *info = dev; | ||
127 | |||
128 | if (info->bd == NULL) | ||
129 | return 1; | ||
130 | |||
131 | *major = info->bd->major; | ||
132 | *name = info->bd->name; | ||
133 | return 0; | ||
134 | } | 52 | } |
135 | 53 | ||
54 | #endif /* CONFIG_PROC_FS */ | ||
136 | 55 | ||
137 | int register_blkdev(unsigned int major, const char *name) | 56 | int register_blkdev(unsigned int major, const char *name) |
138 | { | 57 | { |