summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-05-20 08:16:17 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-05-20 08:16:17 -0700
commit07ca08b17cd52e7797ace521e94716677abb1db5 (patch)
tree48501f23f99217125713a5087ca71c9c78b5f7bc
parentdf13121f96f31bb5dda755ad6f0fbefb97d7f7fb (diff)
parenta45a6dde99e92061a3aa088fb534aa53b4c4d573 (diff)
Merge bk://kernel.bkbits.net/davem/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--fs/dcache.c19
-rw-r--r--fs/namespace.c11
-rw-r--r--fs/open.c4
-rw-r--r--fs/proc/base.c22
-rw-r--r--fs/proc/task_mmu.c215
-rw-r--r--fs/seq_file.c31
-rw-r--r--include/linux/seq_file.h4
-rw-r--r--mm/swapfile.c16
8 files changed, 133 insertions, 189 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 33e861853287..4bbd819d97cf 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1275,7 +1275,7 @@ void d_move(struct dentry * dentry, struct dentry * target)
* the string " (deleted)" is appended. Note that this is ambiguous. Returns
* the buffer.
*
- * "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock.
+ * "buflen" should be positive. Caller holds the dcache_lock.
*/
static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt,
@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
buflen -= 10;
end -= 10;
+ if (buflen < 0)
+ goto Elong;
memcpy(end, " (deleted)", 10);
}
+ if (buflen < 1)
+ goto Elong;
/* Get '/' right */
retval = end-1;
*retval = '/';
@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
namelen = dentry->d_name.len;
buflen -= namelen + 1;
if (buflen < 0)
- return ERR_PTR(-ENAMETOOLONG);
+ goto Elong;
end -= namelen;
memcpy(end, dentry->d_name.name, namelen);
*--end = '/';
@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
global_root:
namelen = dentry->d_name.len;
buflen -= namelen;
- if (buflen >= 0) {
- retval -= namelen-1; /* hit the slash */
- memcpy(retval, dentry->d_name.name, namelen);
- } else
- retval = ERR_PTR(-ENAMETOOLONG);
+ if (buflen < 0)
+ goto Elong;
+ retval -= namelen-1; /* hit the slash */
+ memcpy(retval, dentry->d_name.name, namelen);
return retval;
+Elong:
+ return ERR_PTR(-ENAMETOOLONG);
}
/* write full pathname into buffer and return start of pathname */
diff --git a/fs/namespace.c b/fs/namespace.c
index 6c46fbda724d..09238867b43b 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v)
{ 0, NULL }
};
struct proc_fs_info *fs_infop;
- char *path_buf, *path;
-
- path_buf = (char *) __get_free_page(GFP_KERNEL);
- if (!path_buf)
- return -ENOMEM;
- path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE);
- if (IS_ERR(path))
- path = " (too long)";
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
seq_putc(m, ' ');
- mangle(m, path);
- free_page((unsigned long) path_buf);
+ seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name);
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
diff --git a/fs/open.c b/fs/open.c
index b8ea4700af59..fac3d44702d6 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -671,8 +671,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
if (f->f_flags & O_DIRECT) {
if (!inode->i_mapping || !inode->i_mapping->a_ops ||
!inode->i_mapping->a_ops->direct_IO) {
- error = -EINVAL;
- goto cleanup_all;
+ fput(f);
+ f = ERR_PTR(-EINVAL);
}
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 06e363b4efc8..cad41397fd3f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -322,21 +322,23 @@ static int proc_permission(struct inode *inode, int mask)
return proc_check_root(inode);
}
-extern ssize_t proc_pid_read_maps(struct task_struct *, struct file *,
- char *, size_t, loff_t *);
-static ssize_t pid_maps_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
+extern struct seq_operations proc_pid_maps_op;
+static int maps_open(struct inode *inode, struct file *file)
{
- struct inode * inode = file->f_dentry->d_inode;
struct task_struct *task = proc_task(inode);
- ssize_t res;
-
- res = proc_pid_read_maps(task, file, buf, count, ppos);
- return res;
+ int ret = seq_open(file, &proc_pid_maps_op);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = task;
+ }
+ return ret;
}
static struct file_operations proc_maps_operations = {
- .read = pid_maps_read,
+ .open = maps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
};
extern struct seq_operations mounts_op;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 60ff443d4866..a9d6f99c1869 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1,6 +1,6 @@
-
#include <linux/mm.h>
#include <linux/hugetlb.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
char *task_mem(struct mm_struct *mm, char *buffer)
@@ -75,167 +75,86 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
return size;
}
-/*
- * The way we support synthetic files > 4K
- * - without storing their contents in some buffer and
- * - without walking through the entire synthetic file until we reach the
- * position of the requested data
- * is to cleverly encode the current position in the file's f_pos field.
- * There is no requirement that a read() call which returns `count' bytes
- * of data increases f_pos by exactly `count'.
- *
- * This idea is Linus' one. Bruno implemented it.
- */
-
-/*
- * For the /proc/<pid>/maps file, we use fixed length records, each containing
- * a single line.
- *
- * f_pos = (number of the vma in the task->mm->mmap list) * PAGE_SIZE
- * + (index into the line)
- */
-/* for systems with sizeof(void*) == 4: */
-#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %02x:%02x %lu"
-#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
-
-/* for systems with sizeof(void*) == 8: */
-#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %02x:%02x %lu"
-#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
-
-#define MAPS_LINE_FORMAT (sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8)
-#define MAPS_LINE_MAX (sizeof(void*) == 4 ? MAPS_LINE_MAX4 : MAPS_LINE_MAX8)
-
-static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map)
+static int show_map(struct seq_file *m, void *v)
{
- /* produce the next line */
- char *line;
- char str[5];
- int flags;
- dev_t dev;
- unsigned long ino;
+ struct vm_area_struct *map = v;
+ struct file *file = map->vm_file;
+ int flags = map->vm_flags;
+ unsigned long ino = 0;
+ dev_t dev = 0;
int len;
- flags = map->vm_flags;
-
- str[0] = flags & VM_READ ? 'r' : '-';
- str[1] = flags & VM_WRITE ? 'w' : '-';
- str[2] = flags & VM_EXEC ? 'x' : '-';
- str[3] = flags & VM_MAYSHARE ? 's' : 'p';
- str[4] = 0;
-
- dev = 0;
- ino = 0;
- if (map->vm_file != NULL) {
+ if (file) {
struct inode *inode = map->vm_file->f_dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
- line = d_path(map->vm_file->f_dentry,
- map->vm_file->f_vfsmnt,
- buf, PAGE_SIZE);
- buf[PAGE_SIZE-1] = '\n';
- line -= MAPS_LINE_MAX;
- if(line < buf)
- line = buf;
- } else
- line = buf;
-
- len = sprintf(line,
- MAPS_LINE_FORMAT,
- map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
- MAJOR(dev), MINOR(dev), ino);
-
- if(map->vm_file) {
- int i;
- for(i = len; i < MAPS_LINE_MAX; i++)
- line[i] = ' ';
- len = buf + PAGE_SIZE - line;
- memmove(buf, line, len);
- } else
- line[len++] = '\n';
- return len;
+ }
+
+ seq_printf(m, "%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %lu %n",
+ 2*sizeof(void*), map->vm_start,
+ 2*sizeof(void*), map->vm_end,
+ flags & VM_READ ? 'r' : '-',
+ flags & VM_WRITE ? 'w' : '-',
+ flags & VM_EXEC ? 'x' : '-',
+ flags & VM_MAYSHARE ? 's' : 'p',
+ 2*sizeof(void*), map->vm_pgoff << PAGE_SHIFT,
+ MAJOR(dev), MINOR(dev), ino, &len);
+
+ if (map->vm_file) {
+ len = 25 + sizeof(void*) * 6 - len;
+ if (len < 1)
+ len = 1;
+ seq_printf(m, "%*c", len, ' ');
+ seq_path(m, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+ }
+ seq_putc(m, '\n');
+ return 0;
}
-ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file,
- char *buf, size_t count, loff_t *ppos)
+static void *m_start(struct seq_file *m, loff_t *pos)
{
- struct mm_struct *mm;
+ struct task_struct *task = m->private;
+ struct mm_struct *mm = get_task_mm(task);
struct vm_area_struct * map;
- char *tmp, *kbuf;
- long retval;
- int off, lineno, loff;
-
- /* reject calls with out of range parameters immediately */
- retval = 0;
- if (*ppos > LONG_MAX)
- goto out;
- if (count == 0)
- goto out;
- off = (long)*ppos;
- /*
- * We might sleep getting the page, so get it first.
- */
- retval = -ENOMEM;
- kbuf = (char*)__get_free_page(GFP_KERNEL);
- if (!kbuf)
- goto out;
-
- tmp = (char*)__get_free_page(GFP_KERNEL);
- if (!tmp)
- goto out_free1;
-
- mm = get_task_mm(task);
-
- retval = 0;
+ loff_t l = *pos;
+
if (!mm)
- goto out_free2;
+ return NULL;
down_read(&mm->mmap_sem);
map = mm->mmap;
- lineno = 0;
- loff = 0;
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
- while (map) {
- int len;
- if (off > PAGE_SIZE) {
- off -= PAGE_SIZE;
- goto next;
- }
- len = proc_pid_maps_get_line(tmp, map);
- len -= off;
- if (len > 0) {
- if (retval+len > count) {
- /* only partial line transfer possible */
- len = count - retval;
- /* save the offset where the next read
- * must start */
- loff = len+off;
- }
- memcpy(kbuf+retval, tmp+off, len);
- retval += len;
- }
- off = 0;
-next:
- if (!loff)
- lineno++;
- if (retval >= count)
- break;
- if (loff) BUG();
+ while (l-- && map)
map = map->vm_next;
+ if (!map) {
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ }
+ return map;
+}
+
+static void m_stop(struct seq_file *m, void *v)
+{
+ struct vm_area_struct *map = v;
+ if (map) {
+ struct mm_struct *mm = map->vm_mm;
+ up_read(&mm->mmap_sem);
+ mmput(mm);
}
- up_read(&mm->mmap_sem);
- mmput(mm);
-
- if (retval > count) BUG();
- if (copy_to_user(buf, kbuf, retval))
- retval = -EFAULT;
- else
- *ppos = (lineno << PAGE_SHIFT) + loff;
-
-out_free2:
- free_page((unsigned long)tmp);
-out_free1:
- free_page((unsigned long)kbuf);
-out:
- return retval;
}
+
+static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct vm_area_struct *map = v;
+ (*pos)++;
+ if (map->vm_next)
+ return map->vm_next;
+ m_stop(m, v);
+ return NULL;
+}
+
+struct seq_operations proc_pid_maps_op = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+ .show = show_map
+};
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 98d7a01c14a4..7a9bcab37d49 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...)
return -1;
}
+int seq_path(struct seq_file *m,
+ struct vfsmount *mnt, struct dentry *dentry,
+ char *esc)
+{
+ if (m->count < m->size) {
+ char *s = m->buf + m->count;
+ char *p = d_path(dentry, mnt, s, m->size - m->count);
+ if (!IS_ERR(p)) {
+ while (s <= p) {
+ char c = *p++;
+ if (!c) {
+ p = m->buf + m->count;
+ m->count = s - m->buf;
+ return s - p;
+ } else if (!strchr(esc, c)) {
+ *s++ = c;
+ } else if (s + 4 > p) {
+ break;
+ } else {
+ *s++ = '\\';
+ *s++ = '0' + ((c & 0300) >> 6);
+ *s++ = '0' + ((c & 070) >> 3);
+ *s++ = '0' + (c & 07);
+ }
+ }
+ }
+ }
+ m->count = m->size;
+ return -1;
+}
+
static void *single_start(struct seq_file *p, loff_t *pos)
{
return NULL + (*pos == 0);
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index a704ab14e499..13df4750a271 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -8,6 +8,8 @@
struct seq_operations;
struct file;
+struct vfsmount;
+struct dentry;
struct inode;
struct seq_file {
@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s)
int seq_printf(struct seq_file *, const char *, ...)
__attribute__ ((format (printf,2,3)));
+int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);
+
int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct file *);
int seq_release_private(struct inode *, struct file *);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 55b2de7bca97..bdfd09be8d4c 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1118,14 +1118,9 @@ static void *swap_start(struct seq_file *swap, loff_t *pos)
struct swap_info_struct *ptr = swap_info;
int i;
loff_t l = *pos;
- char * page = (char *) __get_free_page(GFP_KERNEL);
- swap->private = page; /* save for swap_show */
swap_list_lock();
- if (!page)
- return ERR_PTR(-ENOMEM);
-
for (i = 0; i < nr_swapfiles; i++, ptr++) {
if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
continue;
@@ -1154,24 +1149,21 @@ static void *swap_next(struct seq_file *swap, void *v, loff_t *pos)
static void swap_stop(struct seq_file *swap, void *v)
{
swap_list_unlock();
- free_page((unsigned long) swap->private);
- swap->private = NULL;
}
static int swap_show(struct seq_file *swap, void *v)
{
struct swap_info_struct *ptr = v;
struct file *file;
- char *path;
+ int len;
if (v == swap_info)
seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
file = ptr->swap_file;
- path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE);
-
- seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n",
- path,
+ len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+ seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
+ len < 40 ? 40 - len : 1, " ",
S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10),