Re: proc_tty_init called too late, crash possible

Theodore Y. Ts'o (tytso@MIT.EDU)
Fri, 7 Mar 1997 15:39:03 -0500


From: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
Date: Fri, 7 Mar 97 10:43:39 +0100

The proc file system is only initialized the first time it is mounted,
which is too late for proc_tty_register_driver to be able to register the
builtin drivers. Also it is possible that a tty driver module is unloaded
before /proc is ever mounted, in which case proc_tty_unregister_driver
would crash in proc_unregister.

Here's a set of patches which fix this problem, as well as doing further
cleanup on the 2.1.28 /proc file cleanups. Linus, could you apply these
patches into 2.1.29? Thanks!!

These patches migrate the /proc/net/* and /proc/sys/* to use the generic
fs/proc/generic.c functions. (After you apply this patch, you can
remove fs/proc/net.c). It also cleans up a bit more dead code in the
proc filesystem, and migrates us to the point where the easist way to
get a new file registered into the proc filesystem is using the
interface:

struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent)

This function takes three arguments: the name of the proc entry, the
permissions of the file (the correct inode operations structure is
automatically used based on whether the mode indicates that the entry is
a directory or not), and the parent proc_dir_entry where the /proc file
should be linked.

If parent is NULL, then the name can contain a pathname such as
"/tty/driver/serial". This will eventually allow us to phase out
exporting variables such as proc_net and proc_scsi. Modules can simply
specify where in the /proc tree their /proc file should be linked, and
they will be able to do so without needing access to a magically
exported kernel symbol such as proc_net or proc_scsi.

After calling create_proc_entry, all the caller has to do is patch in
the appropriate get_info, read_proc, write_proc, or data fields, as
necessary. All of the hard work of allocating the proc_dir_entry
structure and linking it into the /proc filesystem is dealt with,
automatically. Furthermore, there's no need to have a pre-assigned
inode number; create_proc_entry will dynamically assign an inode number
as well.

- Ted

Patch generated: on Fri Mar 7 15:35:13 EST 1997 by tytso@rsts-11.mit.edu
against Linux version 2.1.28

===================================================================
RCS file: fs/proc/RCS/Makefile,v
retrieving revision 1.1
diff -u -r1.1 fs/proc/Makefile
--- fs/proc/Makefile 1997/03/05 06:11:41 1.1
+++ fs/proc/Makefile 1997/03/05 06:12:00
@@ -9,7 +9,7 @@

O_TARGET := proc.o
O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
- kmsg.o net.o scsi.o proc_tty.o
+ kmsg.o scsi.o proc_tty.o
OX_OBJS := procfs_syms.o
M_OBJS :=

===================================================================
RCS file: fs/proc/RCS/generic.c,v
retrieving revision 1.1
diff -u -r1.1 fs/proc/generic.c
--- fs/proc/generic.c 1997/03/04 18:53:53 1.1
+++ fs/proc/generic.c 1997/03/06 16:34:04
@@ -41,7 +41,7 @@
* proc files can do almost nothing..
*/
struct inode_operations proc_file_inode_operations = {
- &proc_file_operations, /* default scsi directory file-ops */
+ &proc_file_operations, /* default proc file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
@@ -60,6 +60,30 @@
NULL /* permission */
};

+/*
+ * compatibility to replace fs/proc/net.c
+ */
+struct inode_operations proc_net_inode_operations = {
+ &proc_file_operations, /* default net file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
@@ -72,7 +96,8 @@
{
char *page;
int retval=0;
- int n;
+ int eof=0;
+ int n, count;
char *start;
struct proc_dir_entry * dp;

@@ -82,10 +107,11 @@
if (!(page = (char*) __get_free_page(GFP_KERNEL)))
return -ENOMEM;

- while (nbytes > 0)
+ while ((nbytes > 0) && !eof)
{
- n = MIN(PROC_BLOCK_SIZE, nbytes);
+ count = MIN(PROC_BLOCK_SIZE, nbytes);

+ start = NULL;
if (dp->get_info) {
/*
* Handle backwards compatibility with the old net
@@ -94,14 +120,27 @@
* XXX What gives with the file->f_flags & O_ACCMODE
* test? Seems stupid to me....
*/
- n = dp->get_info(page, &start, file->f_pos, n,
+ n = dp->get_info(page, &start, file->f_pos, count,
(file->f_flags & O_ACCMODE) == O_RDWR);
+ if (n < count)
+ eof = 1;
} else if (dp->read_proc) {
n = dp->read_proc(page, &start, file->f_pos,
- n, dp->data);
+ count, &eof, dp->data);
} else
break;

+ if (!start) {
+ /*
+ * For proc files that are less than 4k
+ */
+ start = page + file->f_pos;
+ n -= file->f_pos;
+ if (n <= 0)
+ break;
+ if (n > count)
+ n = count;
+ }
if (n == 0)
break; /* End of file */
if (n < 0) {
@@ -131,13 +170,10 @@
const char * buffer, unsigned long count)
{
struct proc_dir_entry * dp;
- char *page;

if (count < 0)
return -EINVAL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;

if (!dp->write_proc)
return -EIO;
@@ -146,7 +182,6 @@
}


-
static long long proc_file_lseek(struct inode * inode, struct file * file,
long long offset, int orig)
{
@@ -164,10 +199,50 @@
}
}

+/*
+ * This function parses a name such as "tty/driver/serial", and
+ * returns the struct proc_dir_entry for "/proc/tty/driver", and
+ * returns "serial" in residual.
+ */
+static int xlate_proc_name(const char *name,
+ struct proc_dir_entry **ret, const char **residual)
+{
+ const char *cp = name, *next;
+ struct proc_dir_entry *de;
+ int len;
+
+ de = &proc_root;
+ while (1) {
+ next = strchr(cp, '/');
+ if (!next)
+ break;
+
+ len = next - cp;
+ for (de = de->subdir; de ; de = de->next) {
+ if (proc_match(len, cp, de))
+ break;
+ }
+ if (!de)
+ return -ENOENT;
+ cp += len + 1;
+ }
+ *residual = cp;
+ *ret = de;
+ return 0;
+}
+
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent)
{
struct proc_dir_entry *ent;
+ const char *fn;
+
+ if (parent)
+ fn = name;
+ else {
+ if (xlate_proc_name(name, &parent, &fn))
+ return NULL;
+ }

ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
if (!ent)
@@ -179,17 +254,37 @@
else if (mode == 0)
mode = S_IFREG | S_IRUGO;

- ent->name = name;
- ent->namelen = strlen(ent->name);
+ ent->name = fn;
+ ent->namelen = strlen(fn);
ent->mode = mode;
if (S_ISDIR(mode))
ent->nlink = 2;
else
ent->nlink = 1;

- if (parent)
- proc_register(parent, ent);
+ proc_register(parent, ent);

return ent;
}

+void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
+{
+ struct proc_dir_entry *de;
+ const char *fn;
+ int len;
+
+ if (parent)
+ fn = name;
+ else
+ if (xlate_proc_name(name, &parent, &fn))
+ return;
+ len = strlen(fn);
+
+ for (de = parent->subdir; de ; de = de->next) {
+ if (proc_match(len, fn, de))
+ break;
+ }
+ if (de)
+ proc_unregister(parent, de->low_ino);
+ kfree(de);
+}
===================================================================
RCS file: fs/proc/RCS/proc_tty.c,v
retrieving revision 1.1
diff -u -r1.1 fs/proc/proc_tty.c
--- fs/proc/proc_tty.c 1997/03/04 21:32:26 1.1
+++ fs/proc/proc_tty.c 1997/03/06 13:50:04
@@ -19,20 +19,20 @@


static int tty_drivers_read_proc(char *page, char **start, off_t off,
- int count, void *data);
+ int count, int *eof, void *data);
static int tty_ldiscs_read_proc(char *page, char **start, off_t off,
- int count, void *data);
+ int count, int *eof, void *data);

/*
* The /proc/tty directory inodes...
*/
-static struct proc_dir_entry *proc_tty, *proc_tty_ldisc, *proc_tty_driver;
+static struct proc_dir_entry *proc_tty_ldisc, *proc_tty_driver;

/*
* This is the handler for /proc/tty/drivers
*/
static int tty_drivers_read_proc(char *page, char **start, off_t off,
- int count, void *data)
+ int count, int *eof, void *data)
{
int len = 0;
off_t begin = 0;
@@ -87,6 +87,8 @@
len = 0;
}
}
+ if (!p)
+ *eof = 1;
if (off >= len+begin)
return 0;
*start = page + (begin-off);
@@ -97,7 +99,7 @@
* This is the handler for /proc/tty/ldiscs
*/
static int tty_ldiscs_read_proc(char *page, char **start, off_t off,
- int count, void *data)
+ int count, int *eof, void *data)
{
int i;
int len = 0;
@@ -115,6 +117,8 @@
len = 0;
}
}
+ if (i >= NR_LDISCS)
+ *eof = 1;
if (off >= len+begin)
return 0;
*start = page + (begin-off);
@@ -168,16 +172,16 @@
{
struct proc_dir_entry *ent;

- proc_tty = create_proc_entry("tty", S_IFDIR, &proc_root);
- if (!proc_tty)
+ ent = create_proc_entry("tty", S_IFDIR, 0);
+ if (!ent)
return;
- proc_tty_ldisc = create_proc_entry("ldisc", S_IFDIR, proc_tty);
- proc_tty_driver = create_proc_entry("driver", S_IFDIR, proc_tty);
+ proc_tty_ldisc = create_proc_entry("tty/ldisc", S_IFDIR, 0);
+ proc_tty_driver = create_proc_entry("tty/driver", S_IFDIR, 0);

- ent = create_proc_entry("ldiscs", 0, proc_tty);
+ ent = create_proc_entry("tty/ldiscs", 0, 0);
ent->read_proc = tty_ldiscs_read_proc;

- ent = create_proc_entry("drivers", 0, proc_tty);
+ ent = create_proc_entry("tty/drivers", 0, 0);
ent->read_proc = tty_drivers_read_proc;
}

===================================================================
RCS file: fs/proc/RCS/root.c,v
retrieving revision 1.1
diff -u -r1.1 fs/proc/root.c
--- fs/proc/root.c 1997/03/05 06:12:40 1.1
+++ fs/proc/root.c 1997/03/06 16:03:07
@@ -125,22 +125,7 @@
&proc_root, NULL
};

-struct proc_dir_entry proc_net = {
- PROC_NET, 3, "net",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-
-struct proc_dir_entry proc_scsi = {
- PROC_SCSI, 4, "scsi",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL, &proc_root, NULL
-};
+struct proc_dir_entry *proc_net, *proc_scsi;

#ifdef CONFIG_MCA
struct proc_dir_entry proc_mca = {
@@ -358,18 +343,6 @@
return -EINVAL;
}

-int proc_register_dynamic(struct proc_dir_entry * dir,
- struct proc_dir_entry * dp)
-{
- /*
- * Make sure we use a dynamically allocated inode.
- * In the future, all procedures should just call
- * proc_register....
- */
- dp->low_ino = 0;
- return proc_register(dir, dp);
-}
-
/*
* /proc/self:
*/
@@ -567,11 +540,6 @@

void proc_root_init(void)
{
- static int done = 0;
-
- if (done)
- return;
- done = 1;
proc_base_init();
proc_register(&proc_root, &proc_root_loadavg);
proc_register(&proc_root, &proc_root_uptime);
@@ -586,8 +554,8 @@
#endif
proc_register(&proc_root, &proc_root_cpuinfo);
proc_register(&proc_root, &proc_root_self);
- proc_register(&proc_root, &proc_net);
- proc_register(&proc_root, &proc_scsi);
+ proc_net = create_proc_entry("net", S_IFDIR, 0);
+ proc_scsi = create_proc_entry("scsi", S_IFDIR, 0);
proc_register(&proc_root, &proc_sys_root);
#ifdef CONFIG_MCA
proc_register(&proc_root, &proc_mca);
===================================================================
RCS file: fs/proc/RCS/inode.c,v
retrieving revision 1.1
diff -u -r1.1 fs/proc/inode.c
--- fs/proc/inode.c 1997/03/06 16:00:56 1.1
+++ fs/proc/inode.c 1997/03/06 16:01:19
@@ -121,7 +121,6 @@
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
- proc_root_init();
lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
===================================================================
RCS file: fs/proc/RCS/procfs_syms.c,v
retrieving revision 1.1
diff -u -r1.1 fs/proc/procfs_syms.c
--- fs/proc/procfs_syms.c 1997/03/05 07:39:38 1.1
+++ fs/proc/procfs_syms.c 1997/03/05 07:40:17
@@ -13,7 +13,6 @@
extern struct inode_operations proc_scsi_inode_operations;

EXPORT_SYMBOL(proc_register);
-EXPORT_SYMBOL(proc_register_dynamic);
EXPORT_SYMBOL(proc_unregister);
EXPORT_SYMBOL(proc_root);
EXPORT_SYMBOL(proc_get_inode);
===================================================================
RCS file: net/unix/RCS/af_unix.c,v
retrieving revision 1.1
diff -u -r1.1 net/unix/af_unix.c
--- net/unix/af_unix.c 1997/03/04 21:04:07 1.1
+++ net/unix/af_unix.c 1997/03/06 13:49:48
@@ -1366,7 +1366,8 @@
}

#ifdef CONFIG_PROC_FS
-static int unix_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+static int unix_read_proc(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
{
off_t pos=0;
off_t begin=0;
@@ -1410,6 +1411,7 @@
if(pos>offset+length)
goto done;
}
+ *eof = 1;
done:
*start=buffer+(offset-begin);
len-=(offset-begin);
@@ -1466,19 +1468,11 @@
unix_create
};

-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_unix = {
- PROC_NET_UNIX, 4, "unix",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- unix_get_info
-};
-#endif
-
-
void unix_proto_init(struct net_proto *pro)
{
struct sk_buff *dummy_skb;
+ struct proc_dir_entry *ent;
+
printk(KERN_INFO "NET3: Unix domain sockets 0.15 for Linux NET3.038.\n");
if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb))
{
@@ -1487,7 +1481,8 @@
}
sock_register(&unix_family_ops);
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_unix);
+ ent = create_proc_entry("net/unix", 0, 0);
+ ent->read_proc = unix_read_proc;
#endif
}
/*
===================================================================
RCS file: include/linux/RCS/proc_fs.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/proc_fs.h
--- include/linux/proc_fs.h 1997/03/04 21:30:52 1.1
+++ include/linux/proc_fs.h 1997/03/06 16:10:25
@@ -224,7 +224,7 @@
struct proc_dir_entry *next, *parent, *subdir;
void *data;
int (*read_proc)(char *page, char **start, off_t off,
- int count, void *data);
+ int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);
};
@@ -233,8 +233,8 @@
off_t offset, int length, int inout);

extern struct proc_dir_entry proc_root;
-extern struct proc_dir_entry proc_net;
-extern struct proc_dir_entry proc_scsi;
+extern struct proc_dir_entry *proc_net;
+extern struct proc_dir_entry *proc_scsi;
extern struct proc_dir_entry proc_sys;
extern struct proc_dir_entry proc_openprom;
extern struct proc_dir_entry proc_pid;
@@ -248,18 +248,16 @@
extern void proc_net_init(void);

extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *);
-extern int proc_register_dynamic(struct proc_dir_entry *,
- struct proc_dir_entry *);
extern int proc_unregister(struct proc_dir_entry *, int);

static inline int proc_net_register(struct proc_dir_entry * x)
{
- return proc_register(&proc_net, x);
+ return proc_register(proc_net, x);
}

static inline int proc_net_unregister(int x)
{
- return proc_unregister(&proc_net, x);
+ return proc_unregister(proc_net, x);
}

static inline int proc_scsi_register(struct proc_dir_entry *driver,
@@ -267,7 +265,7 @@
{
x->ops = &proc_scsi_inode_operations;
if(x->low_ino < PROC_SCSI_FILE){
- return(proc_register(&proc_scsi, x));
+ return(proc_register(proc_scsi, x));
}else{
return(proc_register(driver, x));
}
@@ -278,7 +276,7 @@
extern void scsi_init_free(char *ptr, unsigned int size);

if(x <= PROC_SCSI_FILE)
- return(proc_unregister(&proc_scsi, x));
+ return(proc_unregister(proc_scsi, x));
else {
struct proc_dir_entry **p = &driver->subdir, *dp;
int ret;
@@ -355,6 +353,7 @@
*/
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);
+void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

/*
* proc_tty.c
===================================================================
RCS file: include/linux/RCS/tty_driver.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/tty_driver.h
--- include/linux/tty_driver.h 1997/03/05 19:29:38 1.1
+++ include/linux/tty_driver.h 1997/03/05 19:29:44
@@ -153,7 +153,7 @@
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
void (*send_xchar)(struct tty_struct *tty, char ch);
int (*read_proc)(char *page, char **start, off_t off,
- int count, void *data);
+ int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);

===================================================================
RCS file: init/RCS/main.c,v
retrieving revision 1.1
diff -u -r1.1 init/main.c
--- init/main.c 1997/03/05 07:09:00 1.1
+++ init/main.c 1997/03/05 07:11:34
@@ -887,6 +887,7 @@
}
#endif
mem_init(memory_start,memory_end);
+ proc_root_init();
kmem_cache_sizes_init();
vma_init();
buffer_init();
===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c 1997/03/05 12:52:46 1.1
+++ drivers/char/serial.c 1997/03/05 19:32:02
@@ -52,7 +52,7 @@
#include <asm/bitops.h>

static char *serial_name = "Serial driver";
-static char *serial_version = "4.23";
+static char *serial_version = "4.24";

static DECLARE_TASK_QUEUE(tq_serial);

@@ -1053,7 +1053,7 @@
static int startup(struct async_struct * info)
{
unsigned long flags;
- int retval;
+ int retval=0;
void (*handler)(int, void *, struct pt_regs *);
struct serial_state *state= info->state;
unsigned long page;
@@ -1070,16 +1070,14 @@

if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
- restore_flags(flags);
- return 0;
+ goto errout;
}

if (!state->port || !state->type) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
- restore_flags(flags);
- return 0;
+ goto errout;
}
if (info->xmit_buf)
free_page(page);
@@ -1118,13 +1116,12 @@
* here.
*/
if (serial_inp(info, UART_LSR) == 0xff) {
- restore_flags(flags);
if (suser()) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- return 0;
} else
- return -ENODEV;
+ retval = -ENODEV;
+ goto errout;
}

/*
@@ -1142,7 +1139,8 @@
#endif
handler = rs_interrupt;
#else
- return -EBUSY;
+ retval = -EBUSY;
+ goto errout;
#endif /* CONFIG_SERIAL_SHARE_IRQ */
} else
handler = rs_interrupt_single;
@@ -1150,14 +1148,13 @@
retval = request_irq(state->irq, handler, IRQ_T(info),
"serial", NULL);
if (retval) {
- restore_flags(flags);
if (suser()) {
if (info->tty)
set_bit(TTY_IO_ERROR,
&info->tty->flags);
- return 0;
- } else
- return retval;
+ retval = 0;
+ }
+ goto errout;
}
}

@@ -1246,6 +1243,10 @@
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
return 0;
+
+errout:
+ restore_flags(flags);
+ return retval;
}

/*
@@ -2879,8 +2880,8 @@
return ret;
}

-int rs_read_proc(char *page, char **start, off_t off, int count, void
- *data)
+int rs_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
{
int i, len = 0;
off_t begin = 0;
@@ -2889,12 +2890,14 @@
for (i = 0; i < NR_PORTS && len < 4000; i++) {
len += line_info(page + len, &rs_table[i]);
if (len+begin > off+count)
- break;
+ goto done;
if (len+begin < off) {
begin += len;
len = 0;
}
}
+ *eof = 1;
+done:
if (off >= len+begin)
return 0;
*start = page + (begin-off);
@@ -2919,6 +2922,18 @@
printk(KERN_INFO "%s version %s with", serial_name, serial_version);
#ifdef CONFIG_HUB6
printk(" HUB-6");
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MANY_PORTS
+ printk(" MANY_PORTS");
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MULTIPORT
+ printk(" MULTIPORT");
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+ printk(" SHARE_IRQ");
#define SERIAL_OPT
#endif
#ifdef SERIAL_OPT
===================================================================
RCS file: kernel/RCS/sysctl.c,v
retrieving revision 1.1
diff -u -r1.1 kernel/sysctl.c
--- kernel/sysctl.c 1997/03/05 07:31:52 1.1
+++ kernel/sysctl.c 1997/03/06 14:10:10
@@ -424,11 +424,12 @@
/* Scan the sysctl entries in table and add them all into /proc */
static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
{
- struct proc_dir_entry *de, *tmp;
- int exists;
+ struct proc_dir_entry *de;
+ int len;
+ mode_t mode;

for (; table->ctl_name; table++) {
- exists = 0;
+ de = 0;
/* Can't do anything without a proc name. */
if (!table->procname)
continue;
@@ -436,46 +437,32 @@
if (!table->proc_handler &&
!table->child)
continue;
-
- de = kmalloc(sizeof(*de), GFP_KERNEL);
- if (!de) continue;
- de->namelen = strlen(table->procname);
- de->name = table->procname;
- de->mode = table->mode;
- de->nlink = 1;
- de->uid = 0;
- de->gid = 0;
- de->size = 0;
- de->get_info = 0; /* For internal use if we want it */
- de->fill_inode = 0; /* To override struct inode fields */
- de->next = de->subdir = 0;
- de->data = (void *) table;
- /* Is it a file? */
- if (table->proc_handler) {
- de->ops = &proc_sys_inode_operations;
- de->mode |= S_IFREG;
- }
- /* Otherwise it's a subdir */
- else {
- /* First check to see if it already exists */
- for (tmp = root->subdir; tmp; tmp = tmp->next) {
- if (tmp->namelen == de->namelen &&
- !memcmp(tmp->name,de->name,de->namelen)) {
- exists = 1;
- kfree (de);
- de = tmp;
- }
- }
- if (!exists) {
- de->ops = &proc_dir_inode_operations;
- de->nlink++;
- de->mode |= S_IFDIR;
+
+ len = strlen(table->procname);
+ mode = table->mode;
+
+ if (table->proc_handler)
+ mode |= S_IFREG;
+ else {
+ mode |= S_IFDIR;
+ for (de = root->subdir; de; de = de->next) {
+ if (proc_match(len, table->procname, de))
+ break;
}
+ /* If the subdir exists already, de is non-NULL */
+ }
+
+ if (!de) {
+ de = create_proc_entry(table->procname, mode, root);
+ if (!de)
+ continue;
+ de->data = (void *) table;
+ if (table->proc_handler)
+ de->ops = &proc_sys_inode_operations;
+
}
table->de = de;
- if (!exists)
- proc_register_dynamic(root, de);
- if (de->mode & S_IFDIR )
+ if (de->mode & S_IFDIR)
register_proc_table(table->child, de);
}
}
===================================================================
RCS file: net/ipv6/RCS/addrconf.c,v
retrieving revision 1.1
diff -u -r1.1 net/ipv6/addrconf.c
--- net/ipv6/addrconf.c 1997/03/05 07:32:02 1.1
+++ net/ipv6/addrconf.c 1997/03/05 07:33:51
@@ -1350,7 +1350,7 @@
if (dev && (dev->flags & IFF_UP))
addrconf_eth_config(dev);

- proc_register_dynamic(&proc_net, &iface_proc_entry);
+ proc_register(&proc_net, &iface_proc_entry);

addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
add_timer(&addr_chk_timer);
===================================================================
RCS file: net/ipv6/RCS/ndisc.c,v
retrieving revision 1.1
diff -u -r1.1 net/ipv6/ndisc.c
--- net/ipv6/ndisc.c 1997/03/05 07:32:02 1.1
+++ net/ipv6/ndisc.c 1997/03/05 07:37:05
@@ -1843,11 +1843,7 @@
add_timer(&ndisc_gc_timer);

#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_IPV6_MODULE
- proc_register_dynamic(&proc_net, &ndisc_proc_entry);
-#else
proc_net_register(&ndisc_proc_entry);
-#endif
#endif
#ifdef CONFIG_IPV6_MODULE
ndisc_eth_hook = ndisc_eth_resolv;
===================================================================
RCS file: net/wanrouter/RCS/wanproc.c,v
retrieving revision 1.1
diff -u -r1.1 net/wanrouter/wanproc.c
--- net/wanrouter/wanproc.c 1997/03/05 07:32:02 1.1
+++ net/wanrouter/wanproc.c 1997/03/05 07:41:51
@@ -273,13 +273,13 @@

int wanrouter_proc_init (void)
{
- int err = proc_register_dynamic(&proc_net, &proc_router);
+ int err = proc_register(&proc_net, &proc_router);

if (!err)
{
- proc_register_dynamic(&proc_router, &proc_router_info);
- proc_register_dynamic(&proc_router, &proc_router_conf);
- proc_register_dynamic(&proc_router, &proc_router_stat);
+ proc_register(&proc_router, &proc_router_info);
+ proc_register(&proc_router, &proc_router_conf);
+ proc_register(&proc_router, &proc_router_stat);
}
return err;
}
@@ -313,7 +313,7 @@
wandev->dent.ops = &wandev_inode;
wandev->dent.get_info = &wandev_get_info;
wandev->dent.data = wandev;
- return proc_register_dynamic(&proc_router, &wandev->dent);
+ return proc_register(&proc_router, &wandev->dent);
}

/*
===================================================================
RCS file: drivers/char/RCS/misc.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/misc.c
--- drivers/char/misc.c 1997/03/05 07:32:02 1.1
+++ drivers/char/misc.c 1997/03/06 14:34:58
@@ -74,7 +74,8 @@
extern int rtc_init(void);

#ifdef CONFIG_PROC_FS
-static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused)
+static int misc_read_proc(char *buf, char **start, off_t offset,
+ int len, int *eof, void *private)
{
struct miscdevice *p;

@@ -183,19 +184,16 @@
#endif

#if defined(CONFIG_PROC_FS) && !defined(MODULE)
-static struct proc_dir_entry proc_misc = {
- 0, 4, "misc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL /* ops -- default to array */,
- &proc_misc_read /* get_info */,
-};
+static struct proc_dir_entry *proc_misc;
#endif

int misc_init(void)
{
#ifndef MODULE
#ifdef CONFIG_PROC_FS
- proc_register_dynamic(&proc_root, &proc_misc);
+ proc_misc = create_proc_entry("misc", 0, 0);
+ if (proc_misc)
+ proc_misc->read_proc = misc_read_proc;
#endif /* PROC_FS */
#ifdef CONFIG_BUSMOUSE
bus_mouse_init();
===================================================================
RCS file: drivers/char/RCS/apm_bios.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/apm_bios.c
--- drivers/char/apm_bios.c 1997/03/05 07:32:02 1.1
+++ drivers/char/apm_bios.c 1997/03/06 14:19:54
@@ -375,12 +375,6 @@
&apm_bios_fops
};

-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry apm_proc_entry = {
- 0, 3, "apm", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, apm_get_info
-};
-#endif
-
typedef struct callback_list_t {
int (* callback)(apm_event_t);
struct callback_list_t * next;
@@ -1072,6 +1066,7 @@
unsigned short error;
char * power_stat;
char * bat_stat;
+ static struct proc_dir_entry *ent;

if (apm_bios_info.version == 0) {
printk("APM BIOS not found.\n");
@@ -1196,7 +1191,8 @@
add_timer(&apm_timer);

#ifdef CONFIG_PROC_FS
- proc_register_dynamic(&proc_root, &apm_proc_entry);
+ ent = create_proc_entry("apm", 0, 0);
+ ent->get_info = apm_get_info;
#endif

misc_register(&apm_device);