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)
* 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) {
if (buflen < 0)
goto Elong;
retval -= namelen-1; /* hit the slash */
memcpy(retval, dentry->d_name.name, namelen);
} else
retval = ERR_PTR(-ENAMETOOLONG);
return retval;
Elong:
return ERR_PTR(-ENAMETOOLONG);
}
/* write full pathname into buffer and return start of pathname */
......
......@@ -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");
......
......@@ -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);
}
}
......
......@@ -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;
......
#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);
}
}
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, ...)
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);
......
......@@ -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 *);
......
......@@ -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),
......
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