diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2003-05-20 08:16:17 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-05-20 08:16:17 -0700 |
| commit | 07ca08b17cd52e7797ace521e94716677abb1db5 (patch) | |
| tree | 48501f23f99217125713a5087ca71c9c78b5f7bc | |
| parent | df13121f96f31bb5dda755ad6f0fbefb97d7f7fb (diff) | |
| parent | a45a6dde99e92061a3aa088fb534aa53b4c4d573 (diff) | |
Merge bk://kernel.bkbits.net/davem/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
| -rw-r--r-- | fs/dcache.c | 19 | ||||
| -rw-r--r-- | fs/namespace.c | 11 | ||||
| -rw-r--r-- | fs/open.c | 4 | ||||
| -rw-r--r-- | fs/proc/base.c | 22 | ||||
| -rw-r--r-- | fs/proc/task_mmu.c | 215 | ||||
| -rw-r--r-- | fs/seq_file.c | 31 | ||||
| -rw-r--r-- | include/linux/seq_file.h | 4 | ||||
| -rw-r--r-- | mm/swapfile.c | 16 |
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), |
