diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/Makefile | 2 | ||||
-rw-r--r-- | fs/proc/base.c | 40 | ||||
-rw-r--r-- | fs/proc/generic.c | 18 | ||||
-rw-r--r-- | fs/proc/inode.c | 23 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 15 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 8 |
6 files changed, 64 insertions, 42 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 11a7b5c..2758e2a 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -2,7 +2,7 @@ # Makefile for the Linux proc filesystem routines. # -obj-$(CONFIG_PROC_FS) += proc.o +obj-y += proc.o proc-y := nommu.o task_nommu.o proc-$(CONFIG_MMU) := mmu.o task_mmu.o diff --git a/fs/proc/base.c b/fs/proc/base.c index 69254a3..a1c43e7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -149,18 +149,13 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, return count; } -static int get_fs_path(struct task_struct *task, struct path *path, bool root) +static int get_task_root(struct task_struct *task, struct path *root) { - struct fs_struct *fs; int result = -ENOENT; task_lock(task); - fs = task->fs; - if (fs) { - read_lock(&fs->lock); - *path = root ? fs->root : fs->pwd; - path_get(path); - read_unlock(&fs->lock); + if (task->fs) { + get_fs_root(task->fs, root); result = 0; } task_unlock(task); @@ -173,7 +168,12 @@ static int proc_cwd_link(struct inode *inode, struct path *path) int result = -ENOENT; if (task) { - result = get_fs_path(task, path, 0); + task_lock(task); + if (task->fs) { + get_fs_pwd(task->fs, path); + result = 0; + } + task_unlock(task); put_task_struct(task); } return result; @@ -185,7 +185,7 @@ static int proc_root_link(struct inode *inode, struct path *path) int result = -ENOENT; if (task) { - result = get_fs_path(task, path, 1); + result = get_task_root(task, path); put_task_struct(task); } return result; @@ -559,9 +559,19 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr) return -EPERM; error = inode_change_ok(inode, attr); - if (!error) - error = inode_setattr(inode, attr); - return error; + if (error) + return error; + + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size != i_size_read(inode)) { + error = vmtruncate(inode, attr->ia_size); + if (error) + return error; + } + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + return 0; } static const struct inode_operations proc_def_inode_operations = { @@ -587,7 +597,7 @@ static int mounts_open_common(struct inode *inode, struct file *file, get_mnt_ns(ns); } rcu_read_unlock(); - if (ns && get_fs_path(task, &root, 1) == 0) + if (ns && get_task_root(task, &root) == 0) ret = 0; put_task_struct(task); } @@ -1516,7 +1526,7 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) if (!tmp) return -ENOMEM; - pathname = d_path(path, tmp, PAGE_SIZE); + pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE); len = PTR_ERR(pathname); if (IS_ERR(pathname)) goto out; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 2791907..dd29f03 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -12,6 +12,7 @@ #include <linux/time.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/mount.h> @@ -258,17 +259,22 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) error = inode_change_ok(inode, iattr); if (error) - goto out; + return error; - error = inode_setattr(inode, iattr); - if (error) - goto out; + if ((iattr->ia_valid & ATTR_SIZE) && + iattr->ia_size != i_size_read(inode)) { + error = vmtruncate(inode, iattr->ia_size); + if (error) + return error; + } + + setattr_copy(inode, iattr); + mark_inode_dirty(inode); de->uid = inode->i_uid; de->gid = inode->i_gid; de->mode = inode->i_mode; -out: - return error; + return 0; } static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index aea8502..9c2b5f4 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -25,11 +25,12 @@ #include "internal.h" -static void proc_delete_inode(struct inode *inode) +static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; truncate_inode_pages(&inode->i_data, 0); + end_writeback(inode); /* Stop tracking associated processes */ put_pid(PROC_I(inode)->pid); @@ -40,7 +41,6 @@ static void proc_delete_inode(struct inode *inode) pde_put(de); if (PROC_I(inode)->sysctl) sysctl_head_put(PROC_I(inode)->sysctl); - clear_inode(inode); } struct vfsmount *proc_mnt; @@ -91,7 +91,7 @@ static const struct super_operations proc_sops = { .alloc_inode = proc_alloc_inode, .destroy_inode = proc_destroy_inode, .drop_inode = generic_delete_inode, - .delete_inode = proc_delete_inode, + .evict_inode = proc_evict_inode, .statfs = simple_statfs, }; @@ -214,8 +214,7 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); long rv = -ENOTTY; - long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); - int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); + long (*ioctl)(struct file *, unsigned int, unsigned long); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { @@ -223,19 +222,11 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne return rv; } pde->pde_users++; - unlocked_ioctl = pde->proc_fops->unlocked_ioctl; - ioctl = pde->proc_fops->ioctl; + ioctl = pde->proc_fops->unlocked_ioctl; spin_unlock(&pde->pde_unload_lock); - if (unlocked_ioctl) { - rv = unlocked_ioctl(file, cmd, arg); - if (rv == -ENOIOCTLCMD) - rv = -EINVAL; - } else if (ioctl) { - WARN_ONCE(1, "Procfs ioctl handlers must use unlocked_ioctl, " - "%pf will be called without the Bkl held\n", ioctl); - rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg); - } + if (ioctl) + rv = ioctl(file, cmd, arg); pde_users_dec(pde); return rv; diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 6ff9981..5be436e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -329,10 +329,19 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) return -EPERM; error = inode_change_ok(inode, attr); - if (!error) - error = inode_setattr(inode, attr); + if (error) + return error; + + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size != i_size_read(inode)) { + error = vmtruncate(inode, attr->ia_size); + if (error) + return error; + } - return error; + setattr_copy(inode, attr); + mark_inode_dirty(inode); + return 0; } static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index aea1d3f..439fc1f 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -210,6 +210,7 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) int flags = vma->vm_flags; unsigned long ino = 0; unsigned long long pgoff = 0; + unsigned long start; dev_t dev = 0; int len; @@ -220,8 +221,13 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; } + /* We don't show the stack guard page in /proc/maps */ + start = vma->vm_start; + if (vma->vm_flags & VM_GROWSDOWN) + start += PAGE_SIZE; + seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", - vma->vm_start, + start, vma->vm_end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', |