lkml.org 
[lkml]   [1999]   [Mar]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From

I submit the following for your approval:

(I would like to apologize ahead of time if this has already been done or
rejected)

Purpose:
To dynamically create device inodes when the modules load without
needing a special script.

Background:
I have been writing a device driver for a specialty board we use here at my
workplace. I am writing it as a module. Because of the possibility of a
conflict with a MAJOR number, I want have the module ask for the next
available MAJOR number. This causes problems because I have to provide a
script which creates the device inode files in /dev.

Solution:
I have modified the /proc file system to support block and character device
inode entries. The module now has two routines to instantiate a driver inode
into the /proc/dev/ directory structure:

int create_proc_dev_entry(const char *name,mode_t mode,kdev_t dev);

given the device name, ie "myboard0X", the mode of operation, S_IFCHR|0666,
and the device info, MKDEV(my_major_number,my_minor_number), the routine
will add the device to /proc/dev and return 1.

int remove_proc_dev_entry(const char *name);

this routine will remove the device inode from the /proc/dev directory.

Comments:
The owner of the device file is root. Once installed, there is no way to
change the permissions on the file.

There is a current limitition that the file must not belong to a subdirectory
of the /proc/dev/ directory. The routine does not allow you to add a
device "device/part".

How It Works:

The "/proc/dev" directory is created when the proc filesystem is initialized.
The proc_dev variable holds the entry for the subdirectory "dev".

The user calls the create_proc_dev_entry from the init_module routine.
This routine adds the device name to the directory and stores the major and
minor numbers in the size element of the proc_dir_entry (as device inodes
don't need the size). The inode operation is set to blkdev_inode_operations,
or chrdev_inode_operations, depending on the device type.

When the inode entry is looked up, a check is done on the mode to see if it
is a block or char device, if so, sets the inode dev and rdev entry to the
size, and sets the size to 0.


My Questions:
I tried compiling the kernel with version information included, but it would
not calculate the checksum on the two new routines I wrote. A cat of
/proc/ksyms gave a create_proc_dev_entry_R__ver_create_proc_dev_entry, and
the module would not load. What am I missing?


The Modifications (7 minor changes total):

The following modifications were done to the Linux 2.2.3 kernel tree,
specifically in the linux/fs/proc subdirectory:

Change 1: (to root.c)
changed line:

struct proc_dir_entry *proc_net, *proc_scsi, *proc_bus;

to read:

struct proc_dir_entry *proc_dev, *proc_net, *proc_scsi, *proc_bus;

Change 2: (to root.c)
added line:

proc_dev = create_proc_entry("dev",S_IFDIR,0);

Change 3: (to procfs_syms.c)
added lines:

EXPORT_SYMBOL(create_proc_dev_entry);
EXPORT_SYMBOL(remove_proc_dev_entry);

Change 4: (to /usr/include/linux/proc_fs.h)
added lines:

int create_proc_dev_entry(const char *name, mode_t mode, kdev_t dev);
void remove_proc_dev_entry(const char *name);

( and their corresponding NULL functions if !CONFIG_PROC_FS )

Change 5: (to inode.c)
replaced, in function proc_get_inode, the line:

inode->i_size = de->size;

with:

if(S_ISCHR(de->mode) || S_ISBLK(de->mode)) {
inode->i_rdev=de->size;
inode->i_dev=de->size;
inode->i_size=0;
} else if(de->size)
inode->i_size=de->size

Change 6: (to Makefile)
added proc_dev.o to list of object files

Change 7: (added a file proc_dev.c)

==============START of FILE=========================================
/*
* proc/fs/proc_dev.c --- special routines for the proc/dev
*
* This file contains proc/dev routines for handling
* insertion and removal of device inodes in /proc/dev/
*
* This file is modified from generic.c
*
* changes Copyright (C) 1999 Kevin Johnson
*/

#include <asm/uaccess.h>

#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <asm/bitops.h>

extern struct proc_dir_entry *proc_dev;
extern struct inode_operations chrdev_inode_operations;
extern struct inode_operations blkdev_inode_operations;

int create_proc_dev_entry(const char *name, mode_t mode,dev_t dev)
{
struct proc_dir_entry *ent = NULL;
const char *fn = name;
int len;

/*
* No subdirectories allowed (yet)
*/

if(strchr(fn,'/')) return 0;

/*
* make sure its a block or character device
*/

if (!S_ISCHR(mode) && !S_ISBLK(mode)) return;

len = strlen(fn);

ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
if (!ent) return 0;

memset(ent, 0, sizeof(struct proc_dir_entry));
memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);

ent->name = ((char *) ent) + sizeof(*ent);
ent->namelen = len;
ent->size=dev;
ent->mode=mode;
ent->nlink = 1;
if(S_ISCHR(mode)) {
ent->ops=&chrdev_inode_operations;
} else {
ent->ops=&blkdev_inode_operations;
}
proc_register(proc_dev, ent);

return 1;
}

extern void free_proc_entry(struct proc_dir_entry *);

/*
* Remove a /proc/dev entry and free it if it's not currently in use.
* If it is in use, we set the 'deleted' flag.
*/

void remove_proc_dev_entry(const char *name)
{
struct proc_dir_entry *de;
const char *fn = name;
int len;

/*
* No subdirectories allowed (yet)
*/

if(strchr(fn,'/'))
goto out;

len = strlen(fn);

for (de = proc_dev->subdir; de ; de = de->next) {
if (proc_match(len, fn, de))
break;
}

if (de) {
proc_unregister(proc_dev, de->low_ino);
de->nlink = 0;
de->deleted = 1;
if (!de->count)
free_proc_entry(de);
else {
printk("remove_proc_dev_entry: %s/%s busy, count=%d\n",
proc_dev->name, de->name, de->count);
}
}
out:
return;
}

==================================END of FILE================================

Kevin Johnson,
kevin@www.dsabl.sill.army.mil
- or -
kevin@rli.net


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:51    [W:0.033 / U:0.116 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site