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 /fs/proc/proc_misc.c | |
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 'fs/proc/proc_misc.c')
-rw-r--r-- | fs/proc/proc_misc.c | 163 |
1 files changed, 36 insertions, 127 deletions
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index ef5a3323f4b5..5c10ea157425 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -249,144 +249,60 @@ static int cpuinfo_open(struct inode *inode, struct file *file) | |||
249 | return seq_open(file, &cpuinfo_op); | 249 | return seq_open(file, &cpuinfo_op); |
250 | } | 250 | } |
251 | 251 | ||
252 | enum devinfo_states { | 252 | static struct file_operations proc_cpuinfo_operations = { |
253 | CHR_HDR, | 253 | .open = cpuinfo_open, |
254 | CHR_LIST, | 254 | .read = seq_read, |
255 | BLK_HDR, | 255 | .llseek = seq_lseek, |
256 | BLK_LIST, | 256 | .release = seq_release, |
257 | DEVINFO_DONE | ||
258 | }; | ||
259 | |||
260 | struct devinfo_state { | ||
261 | void *chrdev; | ||
262 | void *blkdev; | ||
263 | unsigned int num_records; | ||
264 | unsigned int cur_record; | ||
265 | enum devinfo_states state; | ||
266 | }; | 257 | }; |
267 | 258 | ||
268 | static void *devinfo_start(struct seq_file *f, loff_t *pos) | 259 | static int devinfo_show(struct seq_file *f, void *v) |
269 | { | 260 | { |
270 | struct devinfo_state *info = f->private; | 261 | int i = *(loff_t *) v; |
271 | 262 | ||
272 | if (*pos) { | 263 | if (i < CHRDEV_MAJOR_HASH_SIZE) { |
273 | if ((info) && (*pos <= info->num_records)) | 264 | if (i == 0) |
274 | return info; | 265 | seq_printf(f, "Character devices:\n"); |
275 | return NULL; | 266 | chrdev_show(f, i); |
267 | } else { | ||
268 | i -= CHRDEV_MAJOR_HASH_SIZE; | ||
269 | if (i == 0) | ||
270 | seq_printf(f, "\nBlock devices:\n"); | ||
271 | blkdev_show(f, i); | ||
276 | } | 272 | } |
277 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 273 | return 0; |
278 | f->private = info; | ||
279 | info->chrdev = acquire_chrdev_list(); | ||
280 | info->blkdev = acquire_blkdev_list(); | ||
281 | info->state = CHR_HDR; | ||
282 | info->num_records = count_chrdev_list(); | ||
283 | info->num_records += count_blkdev_list(); | ||
284 | info->num_records += 2; /* Character and Block headers */ | ||
285 | *pos = 1; | ||
286 | info->cur_record = *pos; | ||
287 | return info; | ||
288 | } | 274 | } |
289 | 275 | ||
290 | static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) | 276 | static void *devinfo_start(struct seq_file *f, loff_t *pos) |
291 | { | 277 | { |
292 | int idummy; | 278 | if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) |
293 | char *ndummy; | 279 | return pos; |
294 | struct devinfo_state *info = f->private; | 280 | return NULL; |
295 | |||
296 | switch (info->state) { | ||
297 | case CHR_HDR: | ||
298 | info->state = CHR_LIST; | ||
299 | (*pos)++; | ||
300 | /*fallthrough*/ | ||
301 | case CHR_LIST: | ||
302 | if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) { | ||
303 | /* | ||
304 | * The character dev list is complete | ||
305 | */ | ||
306 | info->state = BLK_HDR; | ||
307 | } else { | ||
308 | info->chrdev = get_next_chrdev(info->chrdev); | ||
309 | } | ||
310 | (*pos)++; | ||
311 | break; | ||
312 | case BLK_HDR: | ||
313 | info->state = BLK_LIST; | ||
314 | (*pos)++; | ||
315 | /*fallthrough*/ | ||
316 | case BLK_LIST: | ||
317 | if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) { | ||
318 | /* | ||
319 | * The block dev list is complete | ||
320 | */ | ||
321 | info->state = DEVINFO_DONE; | ||
322 | } else { | ||
323 | info->blkdev = get_next_blkdev(info->blkdev); | ||
324 | } | ||
325 | (*pos)++; | ||
326 | break; | ||
327 | case DEVINFO_DONE: | ||
328 | (*pos)++; | ||
329 | info->cur_record = *pos; | ||
330 | info = NULL; | ||
331 | break; | ||
332 | default: | ||
333 | break; | ||
334 | } | ||
335 | if (info) | ||
336 | info->cur_record = *pos; | ||
337 | return info; | ||
338 | } | 281 | } |
339 | 282 | ||
340 | static void devinfo_stop(struct seq_file *f, void *v) | 283 | static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) |
341 | { | 284 | { |
342 | struct devinfo_state *info = f->private; | 285 | (*pos)++; |
343 | 286 | if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) | |
344 | if (info) { | 287 | return NULL; |
345 | release_chrdev_list(info->chrdev); | 288 | return pos; |
346 | release_blkdev_list(info->blkdev); | ||
347 | f->private = NULL; | ||
348 | kfree(info); | ||
349 | } | ||
350 | } | 289 | } |
351 | 290 | ||
352 | static int devinfo_show(struct seq_file *f, void *arg) | 291 | static void devinfo_stop(struct seq_file *f, void *v) |
353 | { | 292 | { |
354 | int major; | 293 | /* Nothing to do */ |
355 | char *name; | ||
356 | struct devinfo_state *info = f->private; | ||
357 | |||
358 | switch(info->state) { | ||
359 | case CHR_HDR: | ||
360 | seq_printf(f,"Character devices:\n"); | ||
361 | /* fallthrough */ | ||
362 | case CHR_LIST: | ||
363 | if (!get_chrdev_info(info->chrdev,&major,&name)) | ||
364 | seq_printf(f,"%3d %s\n",major,name); | ||
365 | break; | ||
366 | case BLK_HDR: | ||
367 | seq_printf(f,"\nBlock devices:\n"); | ||
368 | /* fallthrough */ | ||
369 | case BLK_LIST: | ||
370 | if (!get_blkdev_info(info->blkdev,&major,&name)) | ||
371 | seq_printf(f,"%3d %s\n",major,name); | ||
372 | break; | ||
373 | default: | ||
374 | break; | ||
375 | } | ||
376 | |||
377 | return 0; | ||
378 | } | 294 | } |
379 | 295 | ||
380 | static struct seq_operations devinfo_op = { | 296 | static struct seq_operations devinfo_ops = { |
381 | .start = devinfo_start, | 297 | .start = devinfo_start, |
382 | .next = devinfo_next, | 298 | .next = devinfo_next, |
383 | .stop = devinfo_stop, | 299 | .stop = devinfo_stop, |
384 | .show = devinfo_show, | 300 | .show = devinfo_show |
385 | }; | 301 | }; |
386 | 302 | ||
387 | static int devinfo_open(struct inode *inode, struct file *file) | 303 | static int devinfo_open(struct inode *inode, struct file *filp) |
388 | { | 304 | { |
389 | return seq_open(file, &devinfo_op); | 305 | return seq_open(filp, &devinfo_ops); |
390 | } | 306 | } |
391 | 307 | ||
392 | static struct file_operations proc_devinfo_operations = { | 308 | static struct file_operations proc_devinfo_operations = { |
@@ -396,13 +312,6 @@ static struct file_operations proc_devinfo_operations = { | |||
396 | .release = seq_release, | 312 | .release = seq_release, |
397 | }; | 313 | }; |
398 | 314 | ||
399 | static struct file_operations proc_cpuinfo_operations = { | ||
400 | .open = cpuinfo_open, | ||
401 | .read = seq_read, | ||
402 | .llseek = seq_lseek, | ||
403 | .release = seq_release, | ||
404 | }; | ||
405 | |||
406 | extern struct seq_operations vmstat_op; | 315 | extern struct seq_operations vmstat_op; |
407 | static int vmstat_open(struct inode *inode, struct file *file) | 316 | static int vmstat_open(struct inode *inode, struct file *file) |
408 | { | 317 | { |