Commit 07ca08b1 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents df13121f a45a6dde
...@@ -1275,7 +1275,7 @@ void d_move(struct dentry * dentry, struct dentry * target) ...@@ -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 string " (deleted)" is appended. Note that this is ambiguous. Returns
* the buffer. * 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, static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt, struct dentry *root, struct vfsmount *rootmnt,
...@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ...@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
if (!IS_ROOT(dentry) && d_unhashed(dentry)) { if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
buflen -= 10; buflen -= 10;
end -= 10; end -= 10;
if (buflen < 0)
goto Elong;
memcpy(end, " (deleted)", 10); memcpy(end, " (deleted)", 10);
} }
if (buflen < 1)
goto Elong;
/* Get '/' right */ /* Get '/' right */
retval = end-1; retval = end-1;
*retval = '/'; *retval = '/';
...@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ...@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
buflen -= namelen + 1; buflen -= namelen + 1;
if (buflen < 0) if (buflen < 0)
return ERR_PTR(-ENAMETOOLONG); goto Elong;
end -= namelen; end -= namelen;
memcpy(end, dentry->d_name.name, namelen); memcpy(end, dentry->d_name.name, namelen);
*--end = '/'; *--end = '/';
...@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ...@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
global_root: global_root:
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
buflen -= namelen; buflen -= namelen;
if (buflen >= 0) { if (buflen < 0)
retval -= namelen-1; /* hit the slash */ goto Elong;
memcpy(retval, dentry->d_name.name, namelen); retval -= namelen-1; /* hit the slash */
} else memcpy(retval, dentry->d_name.name, namelen);
retval = ERR_PTR(-ENAMETOOLONG);
return retval; return retval;
Elong:
return ERR_PTR(-ENAMETOOLONG);
} }
/* write full pathname into buffer and return start of pathname */ /* write full pathname into buffer and return start of pathname */
......
...@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v) ...@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v)
{ 0, NULL } { 0, NULL }
}; };
struct proc_fs_info *fs_infop; 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"); mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
seq_putc(m, ' '); seq_putc(m, ' ');
mangle(m, path); seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
free_page((unsigned long) path_buf);
seq_putc(m, ' '); seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name); mangle(m, mnt->mnt_sb->s_type->name);
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
......
...@@ -671,8 +671,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) ...@@ -671,8 +671,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
if (f->f_flags & O_DIRECT) { if (f->f_flags & O_DIRECT) {
if (!inode->i_mapping || !inode->i_mapping->a_ops || if (!inode->i_mapping || !inode->i_mapping->a_ops ||
!inode->i_mapping->a_ops->direct_IO) { !inode->i_mapping->a_ops->direct_IO) {
error = -EINVAL; fput(f);
goto cleanup_all; f = ERR_PTR(-EINVAL);
} }
} }
......
...@@ -322,21 +322,23 @@ static int proc_permission(struct inode *inode, int mask) ...@@ -322,21 +322,23 @@ static int proc_permission(struct inode *inode, int mask)
return proc_check_root(inode); return proc_check_root(inode);
} }
extern ssize_t proc_pid_read_maps(struct task_struct *, struct file *, extern struct seq_operations proc_pid_maps_op;
char *, size_t, loff_t *); static int maps_open(struct inode *inode, struct file *file)
static ssize_t pid_maps_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{ {
struct inode * inode = file->f_dentry->d_inode;
struct task_struct *task = proc_task(inode); struct task_struct *task = proc_task(inode);
ssize_t res; int ret = seq_open(file, &proc_pid_maps_op);
if (!ret) {
res = proc_pid_read_maps(task, file, buf, count, ppos); struct seq_file *m = file->private_data;
return res; m->private = task;
}
return ret;
} }
static struct file_operations proc_maps_operations = { 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; extern struct seq_operations mounts_op;
......
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
char *task_mem(struct mm_struct *mm, char *buffer) char *task_mem(struct mm_struct *mm, char *buffer)
...@@ -75,167 +75,86 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, ...@@ -75,167 +75,86 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
return size; return size;
} }
/* static int show_map(struct seq_file *m, void *v)
* 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)
{ {
/* produce the next line */ struct vm_area_struct *map = v;
char *line; struct file *file = map->vm_file;
char str[5]; int flags = map->vm_flags;
int flags; unsigned long ino = 0;
dev_t dev; dev_t dev = 0;
unsigned long ino;
int len; int len;
flags = map->vm_flags; if (file) {
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) {
struct inode *inode = map->vm_file->f_dentry->d_inode; struct inode *inode = map->vm_file->f_dentry->d_inode;
dev = inode->i_sb->s_dev; dev = inode->i_sb->s_dev;
ino = inode->i_ino; ino = inode->i_ino;
line = d_path(map->vm_file->f_dentry, }
map->vm_file->f_vfsmnt,
buf, PAGE_SIZE); seq_printf(m, "%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %lu %n",
buf[PAGE_SIZE-1] = '\n'; 2*sizeof(void*), map->vm_start,
line -= MAPS_LINE_MAX; 2*sizeof(void*), map->vm_end,
if(line < buf) flags & VM_READ ? 'r' : '-',
line = buf; flags & VM_WRITE ? 'w' : '-',
} else flags & VM_EXEC ? 'x' : '-',
line = buf; flags & VM_MAYSHARE ? 's' : 'p',
2*sizeof(void*), map->vm_pgoff << PAGE_SHIFT,
len = sprintf(line, MAJOR(dev), MINOR(dev), ino, &len);
MAPS_LINE_FORMAT,
map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, if (map->vm_file) {
MAJOR(dev), MINOR(dev), ino); len = 25 + sizeof(void*) * 6 - len;
if (len < 1)
if(map->vm_file) { len = 1;
int i; seq_printf(m, "%*c", len, ' ');
for(i = len; i < MAPS_LINE_MAX; i++) seq_path(m, file->f_vfsmnt, file->f_dentry, " \t\n\\");
line[i] = ' '; }
len = buf + PAGE_SIZE - line; seq_putc(m, '\n');
memmove(buf, line, len); return 0;
} else
line[len++] = '\n';
return len;
} }
ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file, static void *m_start(struct seq_file *m, loff_t *pos)
char *buf, size_t count, loff_t *ppos)
{ {
struct mm_struct *mm; struct task_struct *task = m->private;
struct mm_struct *mm = get_task_mm(task);
struct vm_area_struct * map; struct vm_area_struct * map;
char *tmp, *kbuf; loff_t l = *pos;
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;
if (!mm) if (!mm)
goto out_free2; return NULL;
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
map = mm->mmap; map = mm->mmap;
lineno = 0; while (l-- && map)
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();
map = map->vm_next; 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
};
...@@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...) ...@@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...)
return -1; 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) static void *single_start(struct seq_file *p, loff_t *pos)
{ {
return NULL + (*pos == 0); return NULL + (*pos == 0);
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
struct seq_operations; struct seq_operations;
struct file; struct file;
struct vfsmount;
struct dentry;
struct inode; struct inode;
struct seq_file { struct seq_file {
...@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s) ...@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s)
int seq_printf(struct seq_file *, const char *, ...) int seq_printf(struct seq_file *, const char *, ...)
__attribute__ ((format (printf,2,3))); __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_open(struct file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct file *); int single_release(struct inode *, struct file *);
int seq_release_private(struct inode *, struct file *); int seq_release_private(struct inode *, struct file *);
......
...@@ -1118,14 +1118,9 @@ static void *swap_start(struct seq_file *swap, loff_t *pos) ...@@ -1118,14 +1118,9 @@ static void *swap_start(struct seq_file *swap, loff_t *pos)
struct swap_info_struct *ptr = swap_info; struct swap_info_struct *ptr = swap_info;
int i; int i;
loff_t l = *pos; loff_t l = *pos;
char * page = (char *) __get_free_page(GFP_KERNEL);
swap->private = page; /* save for swap_show */
swap_list_lock(); swap_list_lock();
if (!page)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_swapfiles; i++, ptr++) { for (i = 0; i < nr_swapfiles; i++, ptr++) {
if (!(ptr->flags & SWP_USED) || !ptr->swap_map) if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
continue; continue;
...@@ -1154,24 +1149,21 @@ static void *swap_next(struct seq_file *swap, void *v, loff_t *pos) ...@@ -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) static void swap_stop(struct seq_file *swap, void *v)
{ {
swap_list_unlock(); swap_list_unlock();
free_page((unsigned long) swap->private);
swap->private = NULL;
} }
static int swap_show(struct seq_file *swap, void *v) static int swap_show(struct seq_file *swap, void *v)
{ {
struct swap_info_struct *ptr = v; struct swap_info_struct *ptr = v;
struct file *file; struct file *file;
char *path; int len;
if (v == swap_info) if (v == swap_info)
seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
file = ptr->swap_file; file = ptr->swap_file;
path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE); len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n", len < 40 ? 40 - len : 1, " ",
path,
S_ISBLK(file->f_dentry->d_inode->i_mode) ? S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t", "partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10), ptr->pages << (PAGE_SHIFT - 10),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment