aboutsummaryrefslogtreecommitdiff
path: root/fs/proc
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/generic.c63
-rw-r--r--fs/proc/inode-alloc.txt14
-rw-r--r--fs/proc/inode.c21
-rw-r--r--fs/proc/internal.h1
-rw-r--r--fs/proc/proc_tty.c1
-rw-r--r--fs/proc/task_mmu.c8
-rw-r--r--fs/proc/uptime.c38
7 files changed, 80 insertions, 66 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 5d2989e9dcc..fa678abc9db 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -37,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de)
#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
static ssize_t
-proc_file_read(struct file *file, char __user *buf, size_t nbytes,
+__proc_file_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
struct inode * inode = file->f_path.dentry->d_inode;
@@ -183,19 +183,47 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes,
}
static ssize_t
+proc_file_read(struct file *file, char __user *buf, size_t nbytes,
+ loff_t *ppos)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ ssize_t rv = -EIO;
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ spin_unlock(&pde->pde_unload_lock);
+
+ rv = __proc_file_read(file, buf, nbytes, ppos);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static ssize_t
proc_file_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- struct proc_dir_entry * dp;
-
- dp = PDE(inode);
-
- if (!dp->write_proc)
- return -EIO;
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ ssize_t rv = -EIO;
+
+ if (pde->write_proc) {
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ spin_unlock(&pde->pde_unload_lock);
- /* FIXME: does this routine need ppos? probably... */
- return dp->write_proc(file, buffer, count, dp->data);
+ /* FIXME: does this routine need ppos? probably... */
+ rv = pde->write_proc(file, buffer, count, pde->data);
+ pde_users_dec(pde);
+ }
+ return rv;
}
@@ -307,6 +335,21 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
/*
* Return an inode number between PROC_DYNAMIC_FIRST and
* 0xffffffff, or zero on failure.
+ *
+ * Current inode allocations in the proc-fs (hex-numbers):
+ *
+ * 00000000 reserved
+ * 00000001-00000fff static entries (goners)
+ * 001 root-ino
+ *
+ * 00001000-00001fff unused
+ * 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
+ * 80000000-efffffff unused
+ * f0000000-ffffffff dynamic entries
+ *
+ * Goal:
+ * Once we split the thing into several virtual filesystems,
+ * we will get rid of magical ranges (and this comment, BTW).
*/
static unsigned int get_inode_number(void)
{
diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt
deleted file mode 100644
index 77212f938c2..00000000000
--- a/fs/proc/inode-alloc.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Current inode allocations in the proc-fs (hex-numbers):
-
- 00000000 reserved
- 00000001-00000fff static entries (goners)
- 001 root-ino
-
- 00001000-00001fff unused
- 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 80000000-efffffff unused
- f0000000-ffffffff dynamic entries
-
-Goal:
- a) once we'll split the thing into several virtual filesystems we
- will get rid of magical ranges (and this file, BTW).
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index d8bb5c671f4..d78ade30554 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -58,11 +58,8 @@ static void proc_delete_inode(struct inode *inode)
/* Let go of any associated proc directory entry */
de = PROC_I(inode)->pde;
- if (de) {
- if (de->owner)
- module_put(de->owner);
+ if (de)
de_put(de);
- }
if (PROC_I(inode)->sysctl)
sysctl_head_put(PROC_I(inode)->sysctl);
clear_inode(inode);
@@ -127,7 +124,7 @@ static void __pde_users_dec(struct proc_dir_entry *pde)
complete(pde->pde_unload_completion);
}
-static void pde_users_dec(struct proc_dir_entry *pde)
+void pde_users_dec(struct proc_dir_entry *pde)
{
spin_lock(&pde->pde_unload_lock);
__pde_users_dec(pde);
@@ -449,12 +446,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
{
struct inode * inode;
- if (!try_module_get(de->owner))
- goto out_mod;
-
inode = iget_locked(sb, ino);
if (!inode)
- goto out_ino;
+ return NULL;
if (inode->i_state & I_NEW) {
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
PROC_I(inode)->fd = 0;
@@ -485,16 +479,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
}
}
unlock_new_inode(inode);
- } else {
- module_put(de->owner);
+ } else
de_put(de);
- }
return inode;
-
-out_ino:
- module_put(de->owner);
-out_mod:
- return NULL;
}
int proc_fill_super(struct super_block *s)
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index cd53ff83849..f6db9618a88 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -91,3 +91,4 @@ struct pde_opener {
int (*release)(struct inode *, struct file *);
struct list_head lh;
};
+void pde_users_dec(struct proc_dir_entry *pde);
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index d153946d6d1..4a9e0f65ae6 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -152,7 +152,6 @@ void proc_tty_register_driver(struct tty_driver *driver)
if (!ent)
return;
ent->read_proc = driver->ops->read_proc;
- ent->owner = driver->owner;
ent->data = driver;
driver->proc_entry = ent;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 94063840832..b0ae0be4801 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -693,8 +693,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
goto out_pages;
}
- pm.out = (u64 *)buf;
- pm.end = (u64 *)(buf + count);
+ pm.out = (u64 __user *)buf;
+ pm.end = (u64 __user *)(buf + count);
pagemap_walk.pmd_entry = pagemap_pte_range;
pagemap_walk.pte_hole = pagemap_pte_hole;
@@ -720,9 +720,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
if (ret == PM_END_OF_BUFFER)
ret = 0;
/* don't need mmap_sem for these, but this looks cleaner */
- *ppos += (char *)pm.out - buf;
+ *ppos += (char __user *)pm.out - buf;
if (!ret)
- ret = (char *)pm.out - buf;
+ ret = (char __user *)pm.out - buf;
out_pages:
for (; pagecount; pagecount--) {
diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c
index df26aa88fa4..0c10a0b3f14 100644
--- a/fs/proc/uptime.c
+++ b/fs/proc/uptime.c
@@ -1,45 +1,43 @@
+#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
+#include <linux/seq_file.h>
#include <linux/time.h>
#include <asm/cputime.h>
-static int proc_calc_metrics(char *page, char **start, off_t off,
- int count, int *eof, int len)
-{
- if (len <= off + count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-}
-
-static int uptime_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int uptime_proc_show(struct seq_file *m, void *v)
{
struct timespec uptime;
struct timespec idle;
- int len;
cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
do_posix_clock_monotonic_gettime(&uptime);
monotonic_to_bootbased(&uptime);
cputime_to_timespec(idletime, &idle);
- len = sprintf(page, "%lu.%02lu %lu.%02lu\n",
+ seq_printf(m, "%lu.%02lu %lu.%02lu\n",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
(unsigned long) idle.tv_sec,
(idle.tv_nsec / (NSEC_PER_SEC / 100)));
- return proc_calc_metrics(page, start, off, count, eof, len);
+ return 0;
}
+static int uptime_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, uptime_proc_show, NULL);
+}
+
+static const struct file_operations uptime_proc_fops = {
+ .open = uptime_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int __init proc_uptime_init(void)
{
- create_proc_read_entry("uptime", 0, NULL, uptime_read_proc, NULL);
+ proc_create("uptime", 0, NULL, &uptime_proc_fops);
return 0;
}
module_init(proc_uptime_init);