aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorJoe Korty <joe.korty@ccur.com>2006-03-31 05:30:32 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-31 15:18:53 -0500
commit68eef3b4791572ecb70249c7fb145bb3742dd899 (patch)
tree1f61fce839cec8d672ae06a423d46f0a6fcd924d /block
parenta2c348fe0117adced11e374329a5ea3f7c43cb41 (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.c103
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
22static struct subsystem block_subsys; 20static struct subsystem block_subsys;
23 21
24static DEFINE_MUTEX(block_subsys_lock); 22static 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 */
37static inline int major_to_index(int major) 35static inline int major_to_index(int major)
38{ 36{
39 return major % MAX_PROBE_HASH; 37 return major % BLKDEV_MAJOR_HASH_SIZE;
40}
41
42struct 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 */
52void *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
83out:
84 return info;
85}
86
87void *acquire_blkdev_list(void)
88{
89 mutex_lock(&block_subsys_lock);
90 return get_next_blkdev(NULL);
91}
92
93void 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/* 42void 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 */
104int 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 */
124int 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
137int register_blkdev(unsigned int major, const char *name) 56int register_blkdev(unsigned int major, const char *name)
138{ 57{