diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
commit | 230e5ab6a084ed50470f101934782dbf54b0d06b (patch) | |
tree | 5dd821c8d33f450470588e7a543f74bf74306e9e /fs/proc/generic.c | |
parent | c9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff) |
Merge with Linux 2.1.67.
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 139 |
1 files changed, 79 insertions, 60 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 83139f492..89da7544b 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -16,11 +16,13 @@ #include <linux/stat.h> #include <asm/bitops.h> -static long proc_file_read(struct inode * inode, struct file * file, - char * buf, unsigned long nbytes); -static long proc_file_write(struct inode * inode, struct file * file, - const char * buffer, unsigned long count); -static long long proc_file_lseek(struct file * file, long long offset, int orig); +extern struct inode_operations proc_dyna_dir_inode_operations; + +static ssize_t proc_file_read(struct file * file, char * buf, + size_t nbytes, loff_t *ppos); +static ssize_t proc_file_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos); +static long long proc_file_lseek(struct file *, long long, int); int proc_match(int len, const char *name,struct proc_dir_entry * de) { @@ -44,17 +46,14 @@ static struct file_operations proc_file_operations = { NULL /* can't fsync */ }; -/* - * proc files can do almost nothing.. - */ struct inode_operations proc_file_inode_operations = { - &proc_file_operations, /* default proc file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ + &proc_file_operations, /* default proc file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ @@ -98,18 +97,17 @@ struct inode_operations proc_net_inode_operations = { /* 4K page size but our output routines use some slack for overruns */ #define PROC_BLOCK_SIZE (3*1024) -static long proc_file_read(struct inode * inode, struct file * file, - char * buf, unsigned long nbytes) +static ssize_t +proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { + struct inode * inode = file->f_dentry->d_inode; char *page; - int retval=0; + ssize_t retval=0; int eof=0; - int n, count; + ssize_t n, count; char *start; struct proc_dir_entry * dp; - if (nbytes < 0) - return -EINVAL; dp = (struct proc_dir_entry *) inode->u.generic_ip; if (!(page = (char*) __get_free_page(GFP_KERNEL))) return -ENOMEM; @@ -127,12 +125,12 @@ static long proc_file_read(struct inode * inode, struct file * file, * XXX What gives with the file->f_flags & O_ACCMODE * test? Seems stupid to me.... */ - n = dp->get_info(page, &start, file->f_pos, count, + n = dp->get_info(page, &start, *ppos, 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->read_proc(page, &start, *ppos, count, &eof, dp->data); } else break; @@ -141,8 +139,8 @@ static long proc_file_read(struct inode * inode, struct file * file, /* * For proc files that are less than 4k */ - start = page + file->f_pos; - n -= file->f_pos; + start = page + *ppos; + n -= *ppos; if (n <= 0) break; if (n > count) @@ -163,7 +161,7 @@ static long proc_file_read(struct inode * inode, struct file * file, break; } - file->f_pos += n; /* Move down the file */ + *ppos += n; /* Move down the file */ nbytes -= n; buf += n; retval += n; @@ -172,24 +170,25 @@ static long proc_file_read(struct inode * inode, struct file * file, return retval; } -static long -proc_file_write(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) +static ssize_t +proc_file_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry * dp; - if (count < 0) - return -EINVAL; dp = (struct proc_dir_entry *) inode->u.generic_ip; if (!dp->write_proc) return -EIO; + /* FIXME: does this routine need ppos? probably... */ return dp->write_proc(file, buffer, count, dp->data); } -static long long proc_file_lseek(struct file * file, long long offset, int orig) +static long long +proc_file_lseek(struct file * file, long long offset, int orig) { switch (orig) { case 0: @@ -240,57 +239,77 @@ static int xlate_proc_name(const char *name, 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; - } + struct proc_dir_entry *ent = NULL; + const char *fn = name; + int len; + + if (!parent && xlate_proc_name(name, &parent, &fn) != 0) + goto out; + len = strlen(fn); - ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); + ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); if (!ent) - return NULL; + goto out; 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; - if (mode == S_IFDIR) + if (mode == S_IFDIR) { mode |= S_IRUGO | S_IXUGO; - else if (mode == 0) - mode = S_IFREG | S_IRUGO; - - ent->name = fn; - ent->namelen = strlen(fn); - ent->mode = mode; - if (S_ISDIR(mode)) + ent->ops = &proc_dyna_dir_inode_operations; ent->nlink = 2; - else + } + else if (mode == 0) { + mode = S_IFREG | S_IRUGO; ent->nlink = 1; + } + ent->mode = mode; proc_register(parent, ent); +out: return ent; } +extern void free_proc_entry(struct proc_dir_entry *); +void free_proc_entry(struct proc_dir_entry *de) +{ + kfree(de); +} + +/* + * Remove a /proc entry and free it if it's not currently in use. + * If it is in use, we set the 'deleted' flag. + */ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) { struct proc_dir_entry *de; - const char *fn; + const char *fn = name; int len; - if (parent) - fn = name; - else - if (xlate_proc_name(name, &parent, &fn)) - return; + if (!parent && xlate_proc_name(name, &parent, &fn) != 0) + goto out; len = strlen(fn); for (de = parent->subdir; de ; de = de->next) { if (proc_match(len, fn, de)) break; } - if (de) + + if (de) { +printk("remove_proc_entry: parent nlink=%d, file nlink=%d\n", +parent->nlink, de->nlink); proc_unregister(parent, de->low_ino); - kfree(de); + de->nlink = 0; + de->deleted = 1; + if (!de->count) + free_proc_entry(de); + else { + printk("remove_proc_entry: %s/%s busy, count=%d\n", + parent->name, de->name, de->count); + } + } +out: + return; } |