Skip to contentSkip to conversation

procfs fdinfo extension v2

RFC In review Cyrill Gorcunov 3 participants 14 messages May 23, 2012 – May 24, 2012

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

v2 cover procfs fdinfo extension v2

Hi guys,

here is an updated version of "get more detailed fdinfo" on eventfd/epoll/fsnotify files. The main change from previous version is that now almost everything is under CONFIG_CHECKPOINT_RESTORE config symbol (except of conversion of fdinfo proc handling routines to seq files which I think increase readability for mainline as well). I've tried hard to minimaze impact on source code.

The comments and espec. complains are highly appreciated (even proposal of some different design is welcome).

Andrew, as to questions what else needed for c/r in mainline -- that's what I counted (at least at moment)

- fdinfo to restore eventfd/epoll/fsnotify (this series)

- restore of file-owner UIDs (there were a series from Eric for mapping kernel-uids to user-uids, so I'm waiting for their final merge before I adopt my patch and send it out (maybe I've missed something and the whole Eric's series already in linux-next, need to check)

- IPC c/r (there were a series from Stas not sure what status of them at moment, as far as I remember they should be rewored)

- finally it would be great to have ability to attach tasks to frozen tasks cgroup to thaw them at one moment (the preliminary patch I've proposed pretty long ago, but Tejun was modifying cgroups code and asked to wait until 3.4 is release, so I didn't check the current status of task cgroups at moment, I've it in my todo list)

that's all I know.

Cyrill

#1 lore raw

RFC v2 1/7 procfs: Move /proc/pid/fd[info] handling code to fd.[ch]

This prepares the ground for further extension of /proc/pid/fd[info] handling code, also makes both fs/proc/base.c and fs/proc/fd.c easier to read.

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/proc/Makefile   |    2 
 fs/proc/base.c     |  401 -----------------------------------------------------
 fs/proc/fd.c       |  370 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/proc/fd.h       |   14 +
 fs/proc/internal.h |   49 ++++++
 5 files changed, 436 insertions(+), 400 deletions(-)
fs/proc/Makefile +1 -1
Index: linux-2.6.git/fs/proc/Makefile
===================================================================
@@ -8,7 +8,7 @@ proc-y			:= nommu.o task_nommu.o
 proc-$(CONFIG_MMU)	:= mmu.o task_mmu.o
 
 proc-y       += inode.o root.o base.o generic.o array.o \
-		proc_tty.o
+		proc_tty.o fd.o
 proc-y	+= cmdline.o
 proc-y	+= consoles.o
 proc-y	+= cpuinfo.o
fs/proc/base.c +3 -398

445 lines not on this page · raw message

fs/proc/fd.c new file +370 -0

370 lines not on this page · raw message

fs/proc/fd.h new file +14 -0
Index: linux-2.6.git/fs/proc/fd.h
===================================================================
@@ -0,0 +1,14 @@
+#ifndef __PROCFS_FD_H__
+#define __PROCFS_FD_H__
+
+#include <linux/fs.h>
+
+extern const struct file_operations proc_fd_operations;
+extern const struct inode_operations proc_fd_inode_operations;
+
+extern const struct file_operations proc_fdinfo_operations;
+extern const struct inode_operations proc_fdinfo_inode_operations;
+
+extern int proc_fd_permission(struct inode *inode, int mask);
+
+#endif /* __PROCFS_FD_H__ */
fs/proc/internal.h +48 -1

67 lines not on this page · raw message

#2 lore raw

RFC v2 2/7 procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file

In reply to Cyrill Gorcunov

This patch converts /proc/pid/fdinfo/ handling routines to seq-file which is needed to extend seq operations to plug in auxiliary fdinfo provides from subsystems like eventfd/eventpoll/fsnotify.

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/proc/fd.c |  136 ++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 84 insertions(+), 52 deletions(-)
fs/proc/fd.c +84 -52
Index: linux-2.6.git/fs/proc/fd.c
===================================================================
@@ -6,66 +6,90 @@
 #include <linux/namei.h>
 #include <linux/pid.h>
 #include <linux/security.h>
+#include <linux/file.h>
+#include <linux/seq_file.h>
 
 #include <linux/proc_fs.h>
 
 #include "internal.h"
+#include "fd.h"
 
-#define PROC_FDINFO_MAX 64
+struct proc_fdinfo {
+	loff_t	f_pos;
+	int	f_flags;
+};
 
-static int proc_fd_info(struct inode *inode, struct path *path, char *info)
+static int seq_show(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo *fdinfo = m->private;
+	seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
+		   (long long)fdinfo->f_pos,
+		   fdinfo->f_flags);
+	return 0;
+}
+
+static int seq_fdinfo_open(struct inode *inode, struct file *file)
 {
-	struct task_struct *task = get_proc_task(inode);
 	struct files_struct *files = NULL;
-	int fd = proc_fd(inode);
-	struct file *file;
+	struct proc_fdinfo *fdinfo = NULL;
+	struct task_struct *task;
+	int ret = -ENOENT;
+
+	fdinfo = kzalloc(sizeof(*fdinfo), GFP_KERNEL);
+	if (!fdinfo)
+		return -ENOMEM;
 
+	task = get_proc_task(inode);
 	if (task) {
 		files = get_files_struct(task);
 		put_task_struct(task);
 	}
 
 	if (files) {
-		/*
-		 * We are not taking a ref to the file structure,
-		 * so we must hold ->file_lock.
-		 */
-		spin_lock(&files->file_lock);
-		file = fcheck_files(files, fd);
+		int fd = proc_fd(inode);
+		struct file *fd_file;
 
-		if (file) {
-			unsigned int f_flags;
-			struct fdtable *fdt;
+		spin_lock(&files->file_lock);
+		fd_file = fcheck_files(files, fd);
+		if (fd_file) {
+			struct fdtable *fdt = files_fdtable(files);
 
-			fdt = files_fdtable(files);
-			f_flags = file->f_flags & ~O_CLOEXEC;
+			fdinfo->f_flags = fd_file->f_flags & ~O_CLOEXEC;
 			if (close_on_exec(fd, fdt))
-				f_flags |= O_CLOEXEC;
-
-			if (path) {
-				*path = file->f_path;
-				path_get(&file->f_path);
-			}
-
-			if (info)
-				snprintf(info, PROC_FDINFO_MAX,
-					 "pos:\t%lli\n"
-					 "flags:\t0%o\n",
-					 (long long)file->f_pos,
-					 f_flags);
-
-			spin_unlock(&files->file_lock);
-			put_files_struct(files);
-			return 0;
+				fdinfo->f_flags |= O_CLOEXEC;
+			ret = 0;
 		}
-
 		spin_unlock(&files->file_lock);
 		put_files_struct(files);
 	}
 
-	return -ENOENT;
+	if (!ret) {
+		ret = single_open(file, seq_show, fdinfo);
+		if (!ret)
+			fdinfo = NULL;
+	}
+
+	kfree(fdinfo);
+	return ret;
 }
 
+static int seq_fdinfo_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *m = file->private_data;
+	struct proc_fdinfo *fdinfo = m->private;
+
+	kfree(fdinfo);
+
+	return single_release(inode, file);
+}
+
+static const struct file_operations proc_fdinfo_file_operations = {
+	.open		= seq_fdinfo_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_fdinfo_release,
+};
+
 static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
 	struct files_struct *files;
@@ -120,7 +144,31 @@ static const struct dentry_operations ti
 
 static int proc_fd_link(struct dentry *dentry, struct path *path)
 {
-	return proc_fd_info(dentry->d_inode, path, NULL);
+	struct inode *inode = dentry->d_inode;
+	struct task_struct *task = get_proc_task(inode);
+	struct files_struct *files = NULL;
+	int fd = proc_fd(inode);
+	struct file *file;
+	int err = -ENOENT;
+
+	if (task) {
+		files = get_files_struct(task);
+		put_task_struct(task);
+	}
+
+	if (files) {
+		spin_lock(&files->file_lock);
+		file = fcheck_files(files, fd);
+		if (file) {
+			*path = file->f_path;
+			path_get(&file->f_path);
+		}
+		spin_unlock(&files->file_lock);
+		put_files_struct(files);
+		err = 0;
+	}
+
+	return err;
 }
 
 static struct dentry *
@@ -263,22 +311,6 @@ out_no_task:
 	return retval;
 }
 
-static ssize_t proc_fdinfo_read(struct file *file, char __user *buf,
-				      size_t len, loff_t *ppos)
-{
-	char tmp[PROC_FDINFO_MAX];
-	int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp);
-	if (!err)
-		err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
-	return err;
-}
-
-static const struct file_operations proc_fdinfo_file_operations = {
-	.open           = nonseekable_open,
-	.read		= proc_fdinfo_read,
-	.llseek		= no_llseek,
-};
-
 static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
 {
 	return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
#3 lore raw

RFC v2 3/7 procfs: Add ability to plugin auxiliary fdinfo providers

In reply to Cyrill Gorcunov

This patch brings ability to plugin auxiliary fdinfo providers. For example in further patches eventfd, evenpoll and fsnotify will print out information associated with files.

This feature is CONFIG_CHECKPOINT_RESTORE guarded to eliminate overhead for those who don't need it at all (this unfortunately makes patch bigger than I wanted).

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/proc/fd.c            |  208 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/proc_fs.h |   28 ++++++
 2 files changed, 236 insertions(+)
fs/proc/fd.c +208 -0
Index: linux-2.6.git/fs/proc/fd.c
===================================================================
@@ -8,12 +8,218 @@
 #include <linux/security.h>
 #include <linux/file.h>
 #include <linux/seq_file.h>
+#include <linux/spinlock.h>
 
 #include <linux/proc_fs.h>
 
 #include "internal.h"
 #include "fd.h"
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+
+static LIST_HEAD(fdinfo_drivers);
+static DECLARE_RWSEM(fdinfo_drivers_sem);
+
+int proc_register_fdinfo_driver(struct proc_fdinfo_driver *s)
+{
+	struct proc_fdinfo_driver *i;
+	int ret = 0;
+
+	if (!s->ops || !s->probe)
+		return -EINVAL;
+
+	down_write(&fdinfo_drivers_sem);
+	list_for_each_entry(i, &fdinfo_drivers, list) {
+		if (i == s) {
+			WARN_ONCE("Trying reassign fdinfo driver `%s'\n",
+				  i->name);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	if (!ret)
+		list_add(&s->list, &fdinfo_drivers);
+	up_write(&fdinfo_drivers_sem);
+
+	return ret;
+}
+
+void proc_unregister_fdinfo_driver(struct proc_fdinfo_driver *s)
+{
+	struct proc_fdinfo_driver *i;
+
+	down_write(&fdinfo_drivers_sem);
+	list_for_each_entry(i, &fdinfo_drivers, list) {
+		if (i == s) {
+			list_del(&i->list);
+			break;
+		}
+	}
+	up_write(&fdinfo_drivers_sem);
+}
+
+static int prep_fdinfo_driver(struct proc_fdinfo_extra *extra)
+{
+	struct proc_fdinfo_driver *s;
+	int ret = 0;
+
+	down_read(&fdinfo_drivers_sem);
+	list_for_each_entry(s, &fdinfo_drivers, list) {
+		if (s->probe(extra->f_file)) {
+			extra->driver = s;
+			break;
+		}
+	}
+	up_read(&fdinfo_drivers_sem);
+
+	if (extra->driver && extra->driver->priv_size) {
+		extra->priv = kmalloc(extra->driver->priv_size, GFP_KERNEL);
+		if (!extra->priv)
+			ret = -ENOMEM;
+	}
+
+	return ret;
+}
+
+static void *seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+
+	down_read(&fdinfo_drivers_sem);
+	extra->pos = *pos;
+
+	return *pos == 0 ? extra :
+		(extra->driver ? extra->driver->ops->start(m, pos) : NULL);
+}
+
+static void seq_stop(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+
+	if (extra->driver && extra->pos > 0)
+		extra->driver->ops->stop(m, v);
+	up_read(&fdinfo_drivers_sem);
+}
+
+static void *seq_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	void *v = NULL;
+
+	if (extra->driver) {
+		int ret = 0;
+
+		if (*pos == 0) {
+			v = extra->driver->ops->start(m, pos);
+			if (v) {
+				ret = extra->driver->ops->show(m, v);
+				p = v;
+			} else
+				ret = -1;
+		}
+
+		if (!ret)
+			v = extra->driver->ops->next(m, p, pos);
+	} else
+		++*pos;
+
+	extra->pos = *pos;
+	return v;
+}
+
+static int seq_show(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+
+	if (extra->driver && extra->pos > 0)
+		return extra->driver->ops->show(m, v);
+
+	seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
+		   (long long)extra->f_file->f_pos,
+		   extra->f_flags);
+	return 0;
+}
+
+static const struct seq_operations fdinfo_seq_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show,
+};
+
+static int seq_fdinfo_open(struct inode *inode, struct file *file)
+{
+	struct files_struct *files = NULL;
+	struct proc_fdinfo_extra *extra;
+	struct task_struct *task;
+	struct seq_file *m;
+	int ret;
+
+	extra = kzalloc(sizeof(*extra), GFP_KERNEL);
+	if (!extra)
+		return -ENOMEM;
+
+	ret = seq_open(file, &fdinfo_seq_ops);
+	if (!ret) {
+		ret = -ENOENT;
+		m = file->private_data;
+		m->private = extra;
+
+		task = get_proc_task(inode);
+		if (task) {
+			files = get_files_struct(task);
+			put_task_struct(task);
+		}
+
+		if (files) {
+			int fd = proc_fd(inode);
+
+			spin_lock(&files->file_lock);
+			extra->f_file = fcheck_files(files, fd);
+			if (extra->f_file) {
+				struct fdtable *fdt = files_fdtable(files);
+
+				extra->f_flags = extra->f_file->f_flags & ~O_CLOEXEC;
+				if (close_on_exec(fd, fdt))
+					extra->f_flags |= O_CLOEXEC;
+				get_file(extra->f_file);
+			}
+			spin_unlock(&files->file_lock);
+			put_files_struct(files);
+
+			ret = prep_fdinfo_driver(extra);
+		}
+	}
+
+	if (ret) {
+		if (extra->f_file)
+			put_filp(extra->f_file);
+		kfree(extra);
+	}
+	return ret;
+}
+
+static int seq_fdinfo_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *m = file->private_data;
+	struct proc_fdinfo_extra *extra = m->private;
+
+	put_filp(extra->f_file);
+	kfree(extra->priv);
+	kfree(m->private);
+
+	return seq_release(inode, file);
+}
+
+static const struct file_operations proc_fdinfo_file_operations = {
+	.open		= seq_fdinfo_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_fdinfo_release,
+};
+
+#else /* CONFIG_CHECKPOINT_RESTORE */
+
 struct proc_fdinfo {
 	loff_t	f_pos;
 	int	f_flags;
@@ -90,6 +296,8 @@ static const struct file_operations proc
 	.release	= seq_fdinfo_release,
 };
 
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
 static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
 	struct files_struct *files;
include/linux/proc_fs.h +28 -0
Index: linux-2.6.git/include/linux/proc_fs.h
===================================================================
@@ -100,6 +100,26 @@ struct vmcore {
 	loff_t offset;
 };
 
+struct seq_operations;
+
+/* fdinfo auxiliary information drivers */
+struct proc_fdinfo_driver {
+	struct list_head		list;
+	const char			*name;
+	const struct seq_operations	*ops;
+	int				(*probe)(struct file *file);
+	size_t				priv_size;
+};
+
+/* auxiliary data allocated per fdinfo reader */
+struct proc_fdinfo_extra {
+	struct proc_fdinfo_driver	*driver;
+	void				*priv;
+	loff_t				pos;
+	struct file			*f_file;
+	unsigned int			f_flags;
+};
+
 #ifdef CONFIG_PROC_FS
 
 extern void proc_root_init(void);
@@ -175,6 +195,11 @@ extern struct proc_dir_entry *proc_net_m
 
 extern struct file *proc_ns_fget(int fd);
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+extern int proc_register_fdinfo_driver(struct proc_fdinfo_driver *s);
+extern void proc_unregister_fdinfo_driver(struct proc_fdinfo_driver *s);
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
 #else
 
 #define proc_net_fops_create(net, name, mode, fops)  ({ (void)(mode), NULL; })
@@ -229,6 +254,9 @@ static inline struct file *proc_ns_fget(
 	return ERR_PTR(-EINVAL);
 }
 
+static inline int proc_register_fdinfo_driver(struct proc_fdinfo_driver *s) { return -EINVAL; }
+static inline void proc_unregister_fdinfo_driver(struct proc_fdinfo_driver *s) { }
+
 #endif /* CONFIG_PROC_FS */
 
 #if !defined(CONFIG_PROC_KCORE)
#4 lore raw

RFC v2 4/7 fs, eventfd: Add procfs fdinfo helper

In reply to Cyrill Gorcunov

This allow us to print out raw counter value. The /proc/pid/fdinfo/fd output is

 | pos:	0
 | flags:	04002
 | eventfd-count:               5a

This feature is CONFIG_CHECKPOINT_RESTORE only.

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/eventfd.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)
fs/eventfd.c +55 -0
Index: linux-2.6.git/fs/eventfd.c
===================================================================
@@ -19,6 +19,8 @@
 #include <linux/export.h>
 #include <linux/kref.h>
 #include <linux/eventfd.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 struct eventfd_ctx {
 	struct kref kref;
@@ -437,3 +439,56 @@ SYSCALL_DEFINE1(eventfd, unsigned int, c
 	return sys_eventfd2(count, 0);
 }
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_CHECKPOINT_RESTORE)
+
+static void *seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	return *pos == 0 ? extra->f_file : NULL;
+}
+
+static void *seq_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+static int seq_show(struct seq_file *m, void *v)
+{
+	struct eventfd_ctx *ctx = ((struct file *)v)->private_data;
+
+	spin_lock_irq(&ctx->wqh.lock);
+	seq_printf(m, "eventfd-count: %16llx\n",
+		   (unsigned long long)ctx->count);
+	spin_unlock_irq(&ctx->wqh.lock);
+
+	return 0;
+}
+
+static void seq_stop(struct seq_file *p, void *v) { }
+
+static const struct seq_operations eventfd_fdinfo_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show,
+};
+
+static int is_eventfd_file(struct file *file)
+{
+	return file->f_op == &eventfd_fops;
+}
+
+static struct proc_fdinfo_driver eventfd_fdinfo = {
+	.name	= "eventfd",
+	.ops	= &eventfd_fdinfo_ops,
+	.probe	= is_eventfd_file,
+};
+
+static int __init eventfd_init(void)
+{
+	return proc_register_fdinfo_driver(&eventfd_fdinfo);
+}
+fs_initcall(eventfd_init);
+
+#endif /* CONFIG_PROC_FS && CONFIG_CHECKPOINT_RESTORE */
#5 lore raw

RFC v2 5/7 fs, epoll: Add procfs fdinfo helper

In reply to Cyrill Gorcunov

This allow us to print out eventpoll target file descriptor, events and data, the /proc/pid/fdinfo/fd consists of

 | pos:	0
 | flags:	02
 | tfd:        5 events:       1d data: ffffffffffffffff

This feature is CONFIG_CHECKPOINT_RESTORE only.

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/eventpoll.c |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
fs/eventpoll.c +81 -0
Index: linux-2.6.git/fs/eventpoll.c
===================================================================
@@ -37,6 +37,8 @@
 #include <asm/io.h>
 #include <asm/mman.h>
 #include <linux/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 /*
  * LOCKING:
@@ -1815,6 +1817,83 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd,
 
 #endif /* HAVE_SET_RESTORE_SIGMASK */
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_CHECKPOINT_RESTORE)
+
+struct epitem_fdinfo {
+	struct epoll_event	ev;
+	int			fd;
+};
+
+static struct epitem_fdinfo *
+seq_lookup_fdinfo(struct proc_fdinfo_extra *extra, struct eventpoll *ep, loff_t num)
+{
+	struct epitem_fdinfo *fdinfo = extra->priv;
+	struct epitem *epi = NULL;
+	struct rb_node *rbp;
+
+	mutex_lock(&ep->mtx);
+	for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+		if (num-- == 0) {
+			epi = rb_entry(rbp, struct epitem, rbn);
+			fdinfo->fd = epi->ffd.fd;
+			fdinfo->ev = epi->event;
+			break;
+		}
+	}
+	mutex_unlock(&ep->mtx);
+
+	return epi ? fdinfo : NULL;
+}
+
+static void *seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	struct eventpoll *ep = extra->f_file->private_data;
+
+	return seq_lookup_fdinfo(extra, ep, *pos);
+}
+
+static void seq_stop(struct seq_file *m, void *v) { }
+
+static void *seq_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	struct eventpoll *ep = extra->f_file->private_data;
+	++*pos;
+	return (void *)seq_lookup_fdinfo(extra, ep, *pos);
+}
+
+static int seq_show(struct seq_file *m, void *v)
+{
+	struct epitem_fdinfo *fdinfo = v;
+	seq_printf(m, "tfd: %8d events: %8x data: %16llx\n",
+		   fdinfo->fd, fdinfo->ev.events,
+		   (long long)fdinfo->ev.data);
+	return 0;
+}
+
+static const struct seq_operations ep_fdinfo_ops = {
+	.start		= seq_start,
+	.next		= seq_next,
+	.stop		= seq_stop,
+	.show		= seq_show,
+};
+
+static struct proc_fdinfo_driver ep_fdinfo = {
+	.name		= "eventpoll",
+	.ops		= &ep_fdinfo_ops,
+	.probe		= is_file_epoll,
+	.priv_size	= sizeof(struct epitem_fdinfo),
+};
+
+static int __init ep_register_fdinfo_driver(void)
+{
+	return proc_register_fdinfo_driver(&ep_fdinfo);
+}
+#else
+static void ep_register_fdinfo_driver(void) { }
+#endif /* CONFIG_PROC_FS && CONFIG_CHECKPOINT_RESTORE */
+
 static int __init eventpoll_init(void)
 {
 	struct sysinfo si;
@@ -1847,6 +1926,8 @@ static int __init eventpoll_init(void)
 	pwq_cache = kmem_cache_create("eventpoll_pwq",
 			sizeof(struct eppoll_entry), 0, SLAB_PANIC, NULL);
 
+	ep_register_fdinfo_driver();
+
 	return 0;
 }
 fs_initcall(eventpoll_init);
#6 lore raw

RFC v2 6/7 fs, exportfs: Add export_encode_inode_fh helper

In reply to Cyrill Gorcunov

To provide fsnotify object inodes being watched without binding to alphabetical path we need to encode them with exportfs help. This patch adds a helper which operates with plain inodes directly.

This feature is CONFIG_CHECKPOINT_RESTORE only.

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/exportfs/expfs.c      |   21 +++++++++++++++++++++
 include/linux/exportfs.h |    4 ++++
 2 files changed, 25 insertions(+)
fs/exportfs/expfs.c +21 -0
Index: linux-2.6.git/fs/exportfs/expfs.c
===================================================================
@@ -302,6 +302,27 @@ out:
 	return error;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+int export_encode_inode_fh(struct inode *inode, struct fid *fid, int *max_len)
+{
+	int len = *max_len;
+	int type = FILEID_INO32_GEN;
+
+	if (len < 2) {
+		*max_len = 2;
+		return 255;
+	}
+
+	len = 2;
+	fid->i32.ino = inode->i_ino;
+	fid->i32.gen = inode->i_generation;
+	*max_len = len;
+
+	return type;
+}
+EXPORT_SYMBOL_GPL(export_encode_inode_fh);
+#endif
+
 /**
  * export_encode_fh - default export_operations->encode_fh function
  * @dentry:  the dentry to encode
include/linux/exportfs.h +4 -0
Index: linux-2.6.git/include/linux/exportfs.h
===================================================================
@@ -177,6 +177,10 @@ struct export_operations {
 	int (*commit_metadata)(struct inode *inode);
 };
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+extern int export_encode_inode_fh(struct inode *inode, struct fid *fid, int *max_len);
+#endif
+
 extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
 	int *max_len, int connectable);
 extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
#7 lore raw

RFC v2 7/7 fs, notify: Add procfs fdinfo helper

In reply to Cyrill Gorcunov

This allow us to print out fsnotify details such as watchee inode, device, mask and file handle.

For example for inotify objects the output is

 | pos:	0
 | flags:	02000000
 | inotify wd:        3 ino:             9e7e sdev:   800013 mask  800afce ignored_mask        0 fhandle-bytes:        8 fhandle-type:        1 f_handle: 7e9e0000640d1b6d
 | inotify wd:        2 ino:             a111 sdev:   800013 mask  800afce ignored_mask        0 fhandle-bytes:        8 fhandle-type:        1 f_handle: 11a1000020542153
 | inotify wd:        1 ino:            6b149 sdev:   800013 mask  800afce ignored_mask        0 fhandle-bytes:        8 fhandle-type:        1 f_handle: 49b1060023552153

For fanotify it is like

 | pos:	0
 | flags:	02
 | fanotify ino:            68f71 sdev:   800013 mask        1 ignored_mask 40000000 fhandle-bytes:        8 fhandle-type:        1 f_handle: 718f0600b9f42053
 | fanotify mnt_id:       13 mask        1 ignored_mask 40000000

This feature is CONFIG_CHECKPOINT_RESTORE only. To minimize impact on general fsnotify code the new functionality is gathered in fs/notify/fdinfo.c file mostly.

CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC James Bottomley <[email protected]>
---
 fs/notify/Makefile                 |    2 
 fs/notify/fanotify/fanotify_user.c |   17 ++
 fs/notify/fdinfo.c                 |  218 +++++++++++++++++++++++++++++++++++++
 fs/notify/fdinfo.h                 |   19 +++
 fs/notify/inotify/inotify_user.c   |   32 +++++
 5 files changed, 286 insertions(+), 2 deletions(-)
fs/notify/Makefile +1 -1
Index: linux-2.6.git/fs/notify/Makefile
===================================================================
@@ -1,5 +1,5 @@
 obj-$(CONFIG_FSNOTIFY)		+= fsnotify.o notification.o group.o inode_mark.o \
-				   mark.o vfsmount_mark.o
+				   mark.o vfsmount_mark.o fdinfo.o
 
 obj-y			+= dnotify/
 obj-y			+= inotify/
fs/notify/fanotify/fanotify_user.c +16 -1
Index: linux-2.6.git/fs/notify/fanotify/fanotify_user.c
===================================================================
@@ -17,6 +17,7 @@
 #include <asm/ioctls.h>
 
 #include "../../mount.h"
+#include "../fdinfo.h"
 
 #define FANOTIFY_DEFAULT_MAX_EVENTS	16384
 #define FANOTIFY_DEFAULT_MAX_MARKS	8192
@@ -877,6 +878,20 @@ asmlinkage long SyS_fanotify_mark(long f
 SYSCALL_ALIAS(sys_fanotify_mark, SyS_fanotify_mark);
 #endif
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_CHECKPOINT_RESTORE)
+int is_file_fanotify(struct file *file)
+{
+	return file->f_op == &fanotify_fops;
+}
+
+static int __init fanotify_register_fdinfo_driver(void)
+{
+	return proc_register_fdinfo_driver(&fanotify_fdinfo);
+}
+#else
+void fanotify_register_fdinfo_driver(void) { }
+#endif /* CONFIG_PROC_FS && CONFIG_CHECKPOINT_RESTORE */
+
 /*
  * fanotify_user_setup - Our initialization function.  Note that we cannot return
  * error because we have compiled-in VFS hooks.  So an (unlikely) failure here
@@ -887,7 +902,7 @@ static int __init fanotify_user_setup(vo
 	fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
 	fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event,
 						   SLAB_PANIC);
-
+	fanotify_register_fdinfo_driver();
 	return 0;
 }
 device_initcall(fanotify_user_setup);
fs/notify/fdinfo.c new file +218 -0

218 lines not on this page · raw message

fs/notify/fdinfo.h new file +19 -0
Index: linux-2.6.git/fs/notify/fdinfo.h
===================================================================
@@ -0,0 +1,19 @@
+#ifndef __FSNOTIFY_FDINFO_H__
+#define __FSNOTIFY_FDINFO_H__
+
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_CHECKPOINT_RESTORE)
+
+#ifdef CONFIG_INOTIFY_USER
+extern struct proc_fdinfo_driver inotify_fdinfo;
+#endif
+
+#ifdef CONFIG_FANOTIFY
+extern struct proc_fdinfo_driver fanotify_fdinfo;
+#endif
+
+#endif
+
+#endif /* __FSNOTIFY_FDINFO_H__ */
fs/notify/inotify/inotify_user.c +32 -0
Index: linux-2.6.git/fs/notify/inotify/inotify_user.c
===================================================================
@@ -38,8 +38,12 @@
 #include <linux/uaccess.h>
 #include <linux/poll.h>
 #include <linux/wait.h>
+#include <linux/seq_file.h>
+#include <linux/exportfs.h>
+#include <linux/proc_fs.h>
 
 #include "inotify.h"
+#include "../fdinfo.h"
 
 #include <asm/ioctls.h>
 
@@ -827,6 +831,26 @@ out:
 	return ret;
 }
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_CHECKPOINT_RESTORE)
+int is_file_inotify(struct file *file)
+{
+	return file->f_op == &inotify_fops;
+}
+
+static int __init inotify_register_fdinfo_driver(void)
+{
+	return proc_register_fdinfo_driver(&inotify_fdinfo);
+}
+
+static void __exit inotify_unregister_fdinfo_driver(void)
+{
+	proc_unregister_fdinfo_driver(&inotify_fdinfo);
+}
+#else
+static int __init inotify_register_fdinfo_driver(void) { return 0; }
+static void __exit inotify_unregister_fdinfo_driver(void) { }
+#endif /* CONFIG_PROC_FS && CONFIG_CHECKPOINT_RESTORE */
+
 /*
  * inotify_user_setup - Our initialization function.  Note that we cannot return
  * error because we have compiled-in VFS hooks.  So an (unlikely) failure here
@@ -862,6 +886,14 @@ static int __init inotify_user_setup(voi
 	inotify_max_user_instances = 128;
 	inotify_max_user_watches = 8192;
 
+	inotify_register_fdinfo_driver();
+
 	return 0;
 }
 module_init(inotify_user_setup);
+
+static void __exit inotify_user_exit(void)
+{
+	inotify_unregister_fdinfo_driver();
+}
+module_exit(inotify_user_exit);
#8 lore raw
In reply to Cyrill Gorcunov

On Wed, May 23, 2012 at 02:25:41PM +0400, Cyrill Gorcunov wrote:

<snip>

Quoted 5 lines

- finally it would be great to have ability to attach tasks to frozen tasks cgroup to thaw them at one moment (the preliminary patch I've proposed pretty long ago, but Tejun was modifying cgroups code and asked to wait until 3.4 is release, so I didn't check the current status of task cgroups at moment, I've it in my todo list)

This still strikes me as the wrong way to go about freezing for c/r. You never explained why you had to do it this way. Why can't you inject the parasite thread, move that thread out of the cgroup-to-be-frozen, then freeze?

As best I can tell your reply last time only fleshed out the details of *how* you would like it to work, not *why it needs to* work that way:

	http://lkml.org/lkml/2011/11/30/27

Cheers,
-Matt Helsley

#9 lore raw
Quoted 10 lines · Matt Helsley

On Wed, May 23, 2012 at 02:25:41PM +0400, Cyrill Gorcunov wrote:

<snip>

Quoted 5 lines

- finally it would be great to have ability to attach tasks to frozen tasks cgroup to thaw them at one moment (the preliminary patch I've proposed pretty long ago, but Tejun was modifying cgroups code and asked to wait until 3.4 is release, so I didn't check the current status of task cgroups at moment, I've it in my todo list)

Quoted 4 lines

This still strikes me as the wrong way to go about freezing for c/r. You never explained why you had to do it this way. Why can't you inject the parasite thread, move that thread out of the cgroup-to-be-frozen, then freeze?

Hi Matt,

last time I checked the code, the ptrace has been able to work with frozen groups (!), that's the main problem and moving thread out of frozen cgroup will not help. The same applies to restore time, we want to create frozen cgroup, restore everything up to original IP via ptrace (or parasite restorer) and thaw the cgroup. Or you asking something else?

Quoted 5 lines

As best I can tell your reply last time only fleshed out the details of *how* you would like it to work, not *why it needs to* work that way:

	http://lkml.org/lkml/2011/11/30/27

Cyrill

#10 lore raw
Quoted 5 lines · Cyrill Gorcunov
Quoted 5 lines

As best I can tell your reply last time only fleshed out the details of *how* you would like it to work, not *why it needs to* work that way:

	http://lkml.org/lkml/2011/11/30/27

Matt, as to "why it needs to work that way" -- this approach will simply work well without a need to patch mainline kernel much, since almost everything needed for transparent restore already in kernel except "ptrace with frozen cgroup", (we even restore without frozen cgroup but with a couple of nasty tricks in crtools utility now). But if there some other approach which we've missed, I would really appreciate if you share it.

Cyrill

#11 lore raw
In reply to Matt Helsley
Quoted 10 lines · Matt Helsley

On Wed, May 23, 2012 at 02:25:41PM +0400, Cyrill Gorcunov wrote:

<snip>

Quoted 5 lines

- finally it would be great to have ability to attach tasks to frozen tasks cgroup to thaw them at one moment (the preliminary patch I've proposed pretty long ago, but Tejun was modifying cgroups code and asked to wait until 3.4 is release, so I didn't check the current status of task cgroups at moment, I've it in my todo list)

Quoted 4 lines

This still strikes me as the wrong way to go about freezing for c/r. You never explained why you had to do it this way. Why can't you inject the parasite thread, move that thread out of the cgroup-to-be-frozen, then freeze?

Matt, I think that Cyrill copied this from some old wishlist and I didn't update him in time :(

The thing is that we seem to have resolved all the issues with freezing/unfreezing the processes we're checkpoiting/restoring, and currently we are OK with the existing ptrace functionality. No more modifications of freeze cgroup are required.

Cyrill?

Quoted 10 lines

As best I can tell your reply last time only fleshed out the details of *how* you would like it to work, not *why it needs to* work that way:

	http://lkml.org/lkml/2011/11/30/27

Cheers,
-Matt Helsley

.

#12 lore raw
Quoted 6 lines · Pavel Emelyanov

The thing is that we seem to have resolved all the issues with freezing/unfreezing the processes we're checkpoiting/restoring, and currently we are OK with the existing ptrace functionality. No more modifications of freeze cgroup are required.

Cyrill?

Oh, crap, sorry Matt, Pavel, indeed I somehow missed that this is not "must have" anymore, this bullet should be dropped from list. Sorry again guys for confusion.

Cyrill

#13 lore raw
Quoted 11 lines · Cyrill Gorcunov
Quoted 6 lines · Pavel Emelyanov

The thing is that we seem to have resolved all the issues with freezing/unfreezing the processes we're checkpoiting/restoring, and currently we are OK with the existing ptrace functionality. No more modifications of freeze cgroup are required.

Cyrill?

Oh, crap, sorry Matt, Pavel, indeed I somehow missed that this is not "must have" anymore, this bullet should be dropped from list. Sorry again guys for confusion.

OK, no problem -- if anything I'm glad to have verification that this change is not needed.

Cheers,
-Matt