diff options
| author | Yann Droneaud <ydroneaud@opteya.com> | 2015-06-30 17:57:30 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-30 22:44:56 -0400 |
| commit | ede1bf0dcff2b07001c760992b1ca18fd0f419bc (patch) | |
| tree | 924a682aa9fa0d076840edc178521d15abacfcf5 | |
| parent | 0e1cc95b4cc7293bb7b39175035e7f7e45c90977 (diff) | |
fs: use seq_open_private() for proc_mounts
A patchset to remove support for passing pre-allocated struct seq_file to
seq_open(). Such feature is undocumented and prone to error.
In particular, if seq_release() is used in release handler, it will
kfree() a pointer which was not allocated by seq_open().
So this patchset drops support for pre-allocated struct seq_file: it's
only of use in proc_namespace.c and can be easily replaced by using
seq_open_private()/seq_release_private().
Additionally, it documents the use of file->private_data to hold pointer
to struct seq_file by seq_open().
This patch (of 3):
Since patch described below, from v2.6.15-rc1, seq_open() could use a
struct seq_file already allocated by the caller if the pointer to the
structure is stored in file->private_data before calling the function.
Commit 1abe77b0fc4b485927f1f798ae81a752677e1d05
Author: Al Viro <viro@zeniv.linux.org.uk>
Date: Mon Nov 7 17:15:34 2005 -0500
[PATCH] allow callers of seq_open do allocation themselves
Allow caller of seq_open() to kmalloc() seq_file + whatever else they
want and set ->private_data to it. seq_open() will then abstain from
doing allocation itself.
Such behavior is only used by mounts_open_common().
In order to drop support for such uncommon feature, proc_mounts is
converted to use seq_open_private(), which take care of allocating the
proc_mounts structure, making it available through ->private in struct
seq_file.
Conversely, proc_mounts is converted to use seq_release_private(), in
order to release the private structure allocated by seq_open_private().
Then, ->private is used directly instead of proc_mounts() macro to access
to the proc_mounts structure.
Link: http://lkml.kernel.org/r/cover.1433193673.git.ydroneaud@opteya.com
Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | fs/mount.h | 3 | ||||
| -rw-r--r-- | fs/namespace.c | 6 | ||||
| -rw-r--r-- | fs/proc_namespace.c | 34 |
3 files changed, 19 insertions, 24 deletions
diff --git a/fs/mount.h b/fs/mount.h index b5b8082bfa42..14db05d424f7 100644 --- a/fs/mount.h +++ b/fs/mount.h | |||
| @@ -118,7 +118,6 @@ static inline void unlock_mount_hash(void) | |||
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | struct proc_mounts { | 120 | struct proc_mounts { |
| 121 | struct seq_file m; | ||
| 122 | struct mnt_namespace *ns; | 121 | struct mnt_namespace *ns; |
| 123 | struct path root; | 122 | struct path root; |
| 124 | int (*show)(struct seq_file *, struct vfsmount *); | 123 | int (*show)(struct seq_file *, struct vfsmount *); |
| @@ -127,8 +126,6 @@ struct proc_mounts { | |||
| 127 | loff_t cached_index; | 126 | loff_t cached_index; |
| 128 | }; | 127 | }; |
| 129 | 128 | ||
| 130 | #define proc_mounts(p) (container_of((p), struct proc_mounts, m)) | ||
| 131 | |||
| 132 | extern const struct seq_operations mounts_op; | 129 | extern const struct seq_operations mounts_op; |
| 133 | 130 | ||
| 134 | extern bool __is_local_mountpoint(struct dentry *dentry); | 131 | extern bool __is_local_mountpoint(struct dentry *dentry); |
diff --git a/fs/namespace.c b/fs/namespace.c index 9c1c43d0d4f1..e99f1f4e00cd 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -1226,7 +1226,7 @@ EXPORT_SYMBOL(replace_mount_options); | |||
| 1226 | /* iterator; we want it to have access to namespace_sem, thus here... */ | 1226 | /* iterator; we want it to have access to namespace_sem, thus here... */ |
| 1227 | static void *m_start(struct seq_file *m, loff_t *pos) | 1227 | static void *m_start(struct seq_file *m, loff_t *pos) |
| 1228 | { | 1228 | { |
| 1229 | struct proc_mounts *p = proc_mounts(m); | 1229 | struct proc_mounts *p = m->private; |
| 1230 | 1230 | ||
| 1231 | down_read(&namespace_sem); | 1231 | down_read(&namespace_sem); |
| 1232 | if (p->cached_event == p->ns->event) { | 1232 | if (p->cached_event == p->ns->event) { |
| @@ -1247,7 +1247,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
| 1247 | 1247 | ||
| 1248 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) | 1248 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) |
| 1249 | { | 1249 | { |
| 1250 | struct proc_mounts *p = proc_mounts(m); | 1250 | struct proc_mounts *p = m->private; |
| 1251 | 1251 | ||
| 1252 | p->cached_mount = seq_list_next(v, &p->ns->list, pos); | 1252 | p->cached_mount = seq_list_next(v, &p->ns->list, pos); |
| 1253 | p->cached_index = *pos; | 1253 | p->cached_index = *pos; |
| @@ -1261,7 +1261,7 @@ static void m_stop(struct seq_file *m, void *v) | |||
| 1261 | 1261 | ||
| 1262 | static int m_show(struct seq_file *m, void *v) | 1262 | static int m_show(struct seq_file *m, void *v) |
| 1263 | { | 1263 | { |
| 1264 | struct proc_mounts *p = proc_mounts(m); | 1264 | struct proc_mounts *p = m->private; |
| 1265 | struct mount *r = list_entry(v, struct mount, mnt_list); | 1265 | struct mount *r = list_entry(v, struct mount, mnt_list); |
| 1266 | return p->show(m, &r->mnt); | 1266 | return p->show(m, &r->mnt); |
| 1267 | } | 1267 | } |
diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 8db932da4009..8ebd9a334085 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c | |||
| @@ -17,7 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | static unsigned mounts_poll(struct file *file, poll_table *wait) | 18 | static unsigned mounts_poll(struct file *file, poll_table *wait) |
| 19 | { | 19 | { |
| 20 | struct proc_mounts *p = proc_mounts(file->private_data); | 20 | struct seq_file *m = file->private_data; |
| 21 | struct proc_mounts *p = m->private; | ||
| 21 | struct mnt_namespace *ns = p->ns; | 22 | struct mnt_namespace *ns = p->ns; |
| 22 | unsigned res = POLLIN | POLLRDNORM; | 23 | unsigned res = POLLIN | POLLRDNORM; |
| 23 | int event; | 24 | int event; |
| @@ -25,8 +26,8 @@ static unsigned mounts_poll(struct file *file, poll_table *wait) | |||
| 25 | poll_wait(file, &p->ns->poll, wait); | 26 | poll_wait(file, &p->ns->poll, wait); |
| 26 | 27 | ||
| 27 | event = ACCESS_ONCE(ns->event); | 28 | event = ACCESS_ONCE(ns->event); |
| 28 | if (p->m.poll_event != event) { | 29 | if (m->poll_event != event) { |
| 29 | p->m.poll_event = event; | 30 | m->poll_event = event; |
| 30 | res |= POLLERR | POLLPRI; | 31 | res |= POLLERR | POLLPRI; |
| 31 | } | 32 | } |
| 32 | 33 | ||
| @@ -92,7 +93,7 @@ static void show_type(struct seq_file *m, struct super_block *sb) | |||
| 92 | 93 | ||
| 93 | static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) | 94 | static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) |
| 94 | { | 95 | { |
| 95 | struct proc_mounts *p = proc_mounts(m); | 96 | struct proc_mounts *p = m->private; |
| 96 | struct mount *r = real_mount(mnt); | 97 | struct mount *r = real_mount(mnt); |
| 97 | int err = 0; | 98 | int err = 0; |
| 98 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | 99 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; |
| @@ -126,7 +127,7 @@ out: | |||
| 126 | 127 | ||
| 127 | static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) | 128 | static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) |
| 128 | { | 129 | { |
| 129 | struct proc_mounts *p = proc_mounts(m); | 130 | struct proc_mounts *p = m->private; |
| 130 | struct mount *r = real_mount(mnt); | 131 | struct mount *r = real_mount(mnt); |
| 131 | struct super_block *sb = mnt->mnt_sb; | 132 | struct super_block *sb = mnt->mnt_sb; |
| 132 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | 133 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; |
| @@ -186,7 +187,7 @@ out: | |||
| 186 | 187 | ||
| 187 | static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) | 188 | static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) |
| 188 | { | 189 | { |
| 189 | struct proc_mounts *p = proc_mounts(m); | 190 | struct proc_mounts *p = m->private; |
| 190 | struct mount *r = real_mount(mnt); | 191 | struct mount *r = real_mount(mnt); |
| 191 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | 192 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; |
| 192 | struct super_block *sb = mnt_path.dentry->d_sb; | 193 | struct super_block *sb = mnt_path.dentry->d_sb; |
| @@ -236,6 +237,7 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 236 | struct mnt_namespace *ns = NULL; | 237 | struct mnt_namespace *ns = NULL; |
| 237 | struct path root; | 238 | struct path root; |
| 238 | struct proc_mounts *p; | 239 | struct proc_mounts *p; |
| 240 | struct seq_file *m; | ||
| 239 | int ret = -EINVAL; | 241 | int ret = -EINVAL; |
| 240 | 242 | ||
| 241 | if (!task) | 243 | if (!task) |
| @@ -260,26 +262,21 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 260 | task_unlock(task); | 262 | task_unlock(task); |
| 261 | put_task_struct(task); | 263 | put_task_struct(task); |
| 262 | 264 | ||
| 263 | ret = -ENOMEM; | 265 | ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts)); |
| 264 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); | 266 | if (ret) |
| 265 | if (!p) | ||
| 266 | goto err_put_path; | 267 | goto err_put_path; |
| 267 | 268 | ||
| 268 | file->private_data = &p->m; | 269 | m = file->private_data; |
| 269 | ret = seq_open(file, &mounts_op); | 270 | m->poll_event = ns->event; |
| 270 | if (ret) | ||
| 271 | goto err_free; | ||
| 272 | 271 | ||
| 272 | p = m->private; | ||
| 273 | p->ns = ns; | 273 | p->ns = ns; |
| 274 | p->root = root; | 274 | p->root = root; |
| 275 | p->m.poll_event = ns->event; | ||
| 276 | p->show = show; | 275 | p->show = show; |
| 277 | p->cached_event = ~0ULL; | 276 | p->cached_event = ~0ULL; |
| 278 | 277 | ||
| 279 | return 0; | 278 | return 0; |
| 280 | 279 | ||
| 281 | err_free: | ||
| 282 | kfree(p); | ||
| 283 | err_put_path: | 280 | err_put_path: |
| 284 | path_put(&root); | 281 | path_put(&root); |
| 285 | err_put_ns: | 282 | err_put_ns: |
| @@ -290,10 +287,11 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 290 | 287 | ||
| 291 | static int mounts_release(struct inode *inode, struct file *file) | 288 | static int mounts_release(struct inode *inode, struct file *file) |
| 292 | { | 289 | { |
| 293 | struct proc_mounts *p = proc_mounts(file->private_data); | 290 | struct seq_file *m = file->private_data; |
| 291 | struct proc_mounts *p = m->private; | ||
| 294 | path_put(&p->root); | 292 | path_put(&p->root); |
| 295 | put_mnt_ns(p->ns); | 293 | put_mnt_ns(p->ns); |
| 296 | return seq_release(inode, file); | 294 | return seq_release_private(inode, file); |
| 297 | } | 295 | } |
| 298 | 296 | ||
| 299 | static int mounts_open(struct inode *inode, struct file *file) | 297 | static int mounts_open(struct inode *inode, struct file *file) |
