Skip to content

Commit

Permalink
[PATCH] Simplify proc/devices and fix early termination regression
Browse files Browse the repository at this point in the history
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.

[[email protected]: cleanups, simplifications]
Signed-off-by: Joe Korty <[email protected]>
Cc: Neil Horman <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Joe Korty authored and Linus Torvalds committed Mar 31, 2006
1 parent a2c348f commit 68eef3b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 306 deletions.
103 changes: 11 additions & 92 deletions block/genhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
#include <linux/buffer_head.h>
#include <linux/mutex.h>

#define MAX_PROBE_HASH 255 /* random */

static struct subsystem block_subsys;

static DEFINE_MUTEX(block_subsys_lock);
Expand All @@ -31,108 +29,29 @@ static struct blk_major_name {
struct blk_major_name *next;
int major;
char name[16];
} *major_names[MAX_PROBE_HASH];
} *major_names[BLKDEV_MAJOR_HASH_SIZE];

/* index in the above - for now: assume no multimajor ranges */
static inline int major_to_index(int major)
{
return major % MAX_PROBE_HASH;
}

struct blkdev_info {
int index;
struct blk_major_name *bd;
};

/*
* iterate over a list of blkdev_info structures. allows
* the major_names array to be iterated over from outside this file
* must be called with the block_subsys_lock held
*/
void *get_next_blkdev(void *dev)
{
struct blkdev_info *info;

if (dev == NULL) {
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
goto out;
info->index=0;
info->bd = major_names[info->index];
if (info->bd)
goto out;
} else {
info = dev;
}

while (info->index < ARRAY_SIZE(major_names)) {
if (info->bd)
info->bd = info->bd->next;
if (info->bd)
goto out;
/*
* No devices on this chain, move to the next
*/
info->index++;
info->bd = (info->index < ARRAY_SIZE(major_names)) ?
major_names[info->index] : NULL;
if (info->bd)
goto out;
}

out:
return info;
}

void *acquire_blkdev_list(void)
{
mutex_lock(&block_subsys_lock);
return get_next_blkdev(NULL);
}

void release_blkdev_list(void *dev)
{
mutex_unlock(&block_subsys_lock);
kfree(dev);
return major % BLKDEV_MAJOR_HASH_SIZE;
}

#ifdef CONFIG_PROC_FS

/*
* Count the number of records in the blkdev_list.
* must be called with the block_subsys_lock held
*/
int count_blkdev_list(void)
void blkdev_show(struct seq_file *f, off_t offset)
{
struct blk_major_name *n;
int i, count;
struct blk_major_name *dp;

count = 0;

for (i = 0; i < ARRAY_SIZE(major_names); i++) {
for (n = major_names[i]; n; n = n->next)
count++;
if (offset < BLKDEV_MAJOR_HASH_SIZE) {
mutex_lock(&block_subsys_lock);
for (dp = major_names[offset]; dp; dp = dp->next)
seq_printf(f, "%3d %s\n", dp->major, dp->name);
mutex_unlock(&block_subsys_lock);
}

return count;
}

/*
* extract the major and name values from a blkdev_info struct
* passed in as a void to *dev. Must be called with
* block_subsys_lock held
*/
int get_blkdev_info(void *dev, int *major, char **name)
{
struct blkdev_info *info = dev;

if (info->bd == NULL)
return 1;

*major = info->bd->major;
*name = info->bd->name;
return 0;
}

#endif /* CONFIG_PROC_FS */

int register_blkdev(unsigned int major, const char *name)
{
Expand Down
87 changes: 11 additions & 76 deletions fs/char_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/seq_file.h>

#include <linux/kobject.h>
#include <linux/kobj_map.h>
Expand All @@ -27,8 +28,6 @@

static struct kobj_map *cdev_map;

#define MAX_PROBE_HASH 255 /* random */

static DEFINE_MUTEX(chrdevs_lock);

static struct char_device_struct {
Expand All @@ -39,93 +38,29 @@ static struct char_device_struct {
char name[64];
struct file_operations *fops;
struct cdev *cdev; /* will die */
} *chrdevs[MAX_PROBE_HASH];
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

/* index in the above */
static inline int major_to_index(int major)
{
return major % MAX_PROBE_HASH;
}

struct chrdev_info {
int index;
struct char_device_struct *cd;
};

void *get_next_chrdev(void *dev)
{
struct chrdev_info *info;

if (dev == NULL) {
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
goto out;
info->index=0;
info->cd = chrdevs[info->index];
if (info->cd)
goto out;
} else {
info = dev;
}

while (info->index < ARRAY_SIZE(chrdevs)) {
if (info->cd)
info->cd = info->cd->next;
if (info->cd)
goto out;
/*
* No devices on this chain, move to the next
*/
info->index++;
info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
chrdevs[info->index] : NULL;
if (info->cd)
goto out;
}

out:
return info;
}

void *acquire_chrdev_list(void)
{
mutex_lock(&chrdevs_lock);
return get_next_chrdev(NULL);
}

void release_chrdev_list(void *dev)
{
mutex_unlock(&chrdevs_lock);
kfree(dev);
return major % CHRDEV_MAJOR_HASH_SIZE;
}

#ifdef CONFIG_PROC_FS

int count_chrdev_list(void)
void chrdev_show(struct seq_file *f, off_t offset)
{
struct char_device_struct *cd;
int i, count;

count = 0;

for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
for (cd = chrdevs[i]; cd; cd = cd->next)
count++;
if (offset < CHRDEV_MAJOR_HASH_SIZE) {
mutex_lock(&chrdevs_lock);
for (cd = chrdevs[offset]; cd; cd = cd->next)
seq_printf(f, "%3d %s\n", cd->major, cd->name);
mutex_unlock(&chrdevs_lock);
}

return count;
}

int get_chrdev_info(void *dev, int *major, char **name)
{
struct chrdev_info *info = dev;

if (info->cd == NULL)
return 1;

*major = info->cd->major;
*name = info->cd->name;
return 0;
}
#endif /* CONFIG_PROC_FS */

/*
* Register a single major with a specified minor range.
Expand Down
Loading

0 comments on commit 68eef3b

Please sign in to comment.