linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/8] procfs fdinfo providers updated
@ 2012-08-14 14:03 Cyrill Gorcunov
  2012-08-14 14:03 ` [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch] Cyrill Gorcunov
                   ` (7 more replies)
  0 siblings, 8 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley

Hi guys,

in this series I tried to address concerns on code duplication
at seq_fdinfo_open and proc_fd_link, thus fdinfo_open_helper()
is used in both routines. Also series updated to be appliable
on top of v3.6-rc1.

Please review, comments are highly appreciated.

	Cyrill

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch]
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:21   ` Pavel Emelyanov
  2012-08-14 14:03 ` [patch 2/8] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file Cyrill Gorcunov
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-base-proc-5 --]
[-- Type: text/plain, Size: 23060 bytes --]

This patch prepares the ground for further extension of
/proc/pid/fd[info] handling code by moving fdinfo handling
code into fs/proc/fd.c.

I think such move makes both fs/proc/base.c and fs/proc/fd.c
easier to read.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/proc/Makefile   |    2 
 fs/proc/base.c     |  388 -----------------------------------------------------
 fs/proc/fd.c       |  351 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/proc/fd.h       |   14 +
 fs/proc/internal.h |   48 ++++++
 5 files changed, 416 insertions(+), 387 deletions(-)

Index: linux-2.6.git/fs/proc/Makefile
===================================================================
--- linux-2.6.git.orig/fs/proc/Makefile
+++ 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
Index: linux-2.6.git/fs/proc/base.c
===================================================================
--- linux-2.6.git.orig/fs/proc/base.c
+++ linux-2.6.git/fs/proc/base.c
@@ -90,6 +90,7 @@
 #endif
 #include <trace/events/oom.h>
 #include "internal.h"
+#include "fd.h"
 
 /* NOTE:
  *	Implementing inode permission operations in /proc is almost
@@ -136,8 +137,6 @@ struct pid_entry {
 		NULL, &proc_single_file_operations,	\
 		{ .proc_show = show } )
 
-static int proc_fd_permission(struct inode *inode, int mask);
-
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
  * and .. links.
@@ -1492,7 +1491,7 @@ out:
 	return error;
 }
 
-static const struct inode_operations proc_pid_link_inode_operations = {
+const struct inode_operations proc_pid_link_inode_operations = {
 	.readlink	= proc_pid_readlink,
 	.follow_link	= proc_pid_follow_link,
 	.setattr	= proc_setattr,
@@ -1501,21 +1500,6 @@ static const struct inode_operations pro
 
 /* building an inode */
 
-static int task_dumpable(struct task_struct *task)
-{
-	int dumpable = 0;
-	struct mm_struct *mm;
-
-	task_lock(task);
-	mm = task->mm;
-	if (mm)
-		dumpable = get_dumpable(mm);
-	task_unlock(task);
-	if(dumpable == 1)
-		return 1;
-	return 0;
-}
-
 struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
 {
 	struct inode * inode;
@@ -1641,15 +1625,6 @@ int pid_revalidate(struct dentry *dentry
 	return 0;
 }
 
-static int pid_delete_dentry(const struct dentry * dentry)
-{
-	/* Is the task we represent dead?
-	 * If so, then don't put the dentry on the lru list,
-	 * kill it immediately.
-	 */
-	return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
-}
-
 const struct dentry_operations pid_dentry_operations =
 {
 	.d_revalidate	= pid_revalidate,
@@ -1712,289 +1687,6 @@ end_instantiate:
 	return filldir(dirent, name, len, filp->f_pos, ino, type);
 }
 
-static unsigned name_to_int(struct dentry *dentry)
-{
-	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
-	unsigned n = 0;
-
-	if (len > 1 && *name == '0')
-		goto out;
-	while (len-- > 0) {
-		unsigned c = *name++ - '0';
-		if (c > 9)
-			goto out;
-		if (n >= (~0U-9)/10)
-			goto out;
-		n *= 10;
-		n += c;
-	}
-	return n;
-out:
-	return ~0U;
-}
-
-#define PROC_FDINFO_MAX 64
-
-static int proc_fd_info(struct inode *inode, struct path *path, char *info)
-{
-	struct task_struct *task = get_proc_task(inode);
-	struct files_struct *files = NULL;
-	struct file *file;
-	int fd = proc_fd(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);
-		if (file) {
-			unsigned int f_flags;
-			struct fdtable *fdt;
-
-			fdt = files_fdtable(files);
-			f_flags = 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;
-		}
-		spin_unlock(&files->file_lock);
-		put_files_struct(files);
-	}
-	return -ENOENT;
-}
-
-static int proc_fd_link(struct dentry *dentry, struct path *path)
-{
-	return proc_fd_info(dentry->d_inode, path, NULL);
-}
-
-static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
-{
-	struct inode *inode;
-	struct task_struct *task;
-	int fd;
-	struct files_struct *files;
-	const struct cred *cred;
-
-	if (flags & LOOKUP_RCU)
-		return -ECHILD;
-
-	inode = dentry->d_inode;
-	task = get_proc_task(inode);
-	fd = proc_fd(inode);
-
-	if (task) {
-		files = get_files_struct(task);
-		if (files) {
-			struct file *file;
-			rcu_read_lock();
-			file = fcheck_files(files, fd);
-			if (file) {
-				unsigned f_mode = file->f_mode;
-
-				rcu_read_unlock();
-				put_files_struct(files);
-
-				if (task_dumpable(task)) {
-					rcu_read_lock();
-					cred = __task_cred(task);
-					inode->i_uid = cred->euid;
-					inode->i_gid = cred->egid;
-					rcu_read_unlock();
-				} else {
-					inode->i_uid = GLOBAL_ROOT_UID;
-					inode->i_gid = GLOBAL_ROOT_GID;
-				}
-
-				if (S_ISLNK(inode->i_mode)) {
-					unsigned i_mode = S_IFLNK;
-					if (f_mode & FMODE_READ)
-						i_mode |= S_IRUSR | S_IXUSR;
-					if (f_mode & FMODE_WRITE)
-						i_mode |= S_IWUSR | S_IXUSR;
-					inode->i_mode = i_mode;
-				}
-
-				security_task_to_inode(task, inode);
-				put_task_struct(task);
-				return 1;
-			}
-			rcu_read_unlock();
-			put_files_struct(files);
-		}
-		put_task_struct(task);
-	}
-	d_drop(dentry);
-	return 0;
-}
-
-static const struct dentry_operations tid_fd_dentry_operations =
-{
-	.d_revalidate	= tid_fd_revalidate,
-	.d_delete	= pid_delete_dentry,
-};
-
-static struct dentry *proc_fd_instantiate(struct inode *dir,
-	struct dentry *dentry, struct task_struct *task, const void *ptr)
-{
-	unsigned fd = (unsigned long)ptr;
- 	struct inode *inode;
- 	struct proc_inode *ei;
-	struct dentry *error = ERR_PTR(-ENOENT);
-
-	inode = proc_pid_make_inode(dir->i_sb, task);
-	if (!inode)
-		goto out;
-	ei = PROC_I(inode);
-	ei->fd = fd;
-
-	inode->i_mode = S_IFLNK;
-	inode->i_op = &proc_pid_link_inode_operations;
-	inode->i_size = 64;
-	ei->op.proc_get_link = proc_fd_link;
-	d_set_d_op(dentry, &tid_fd_dentry_operations);
-	d_add(dentry, inode);
-	/* Close the race of the process dying before we return the dentry */
-	if (tid_fd_revalidate(dentry, 0))
-		error = NULL;
-
- out:
-	return error;
-}
-
-static struct dentry *proc_lookupfd_common(struct inode *dir,
-					   struct dentry *dentry,
-					   instantiate_t instantiate)
-{
-	struct task_struct *task = get_proc_task(dir);
-	unsigned fd = name_to_int(dentry);
-	struct dentry *result = ERR_PTR(-ENOENT);
-
-	if (!task)
-		goto out_no_task;
-	if (fd == ~0U)
-		goto out;
-
-	result = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
-out:
-	put_task_struct(task);
-out_no_task:
-	return result;
-}
-
-static int proc_readfd_common(struct file * filp, void * dirent,
-			      filldir_t filldir, instantiate_t instantiate)
-{
-	struct dentry *dentry = filp->f_path.dentry;
-	struct inode *inode = dentry->d_inode;
-	struct task_struct *p = get_proc_task(inode);
-	unsigned int fd, ino;
-	int retval;
-	struct files_struct * files;
-
-	retval = -ENOENT;
-	if (!p)
-		goto out_no_task;
-	retval = 0;
-
-	fd = filp->f_pos;
-	switch (fd) {
-		case 0:
-			if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
-				goto out;
-			filp->f_pos++;
-		case 1:
-			ino = parent_ino(dentry);
-			if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
-				goto out;
-			filp->f_pos++;
-		default:
-			files = get_files_struct(p);
-			if (!files)
-				goto out;
-			rcu_read_lock();
-			for (fd = filp->f_pos-2;
-			     fd < files_fdtable(files)->max_fds;
-			     fd++, filp->f_pos++) {
-				char name[PROC_NUMBUF];
-				int len;
-				int rv;
-
-				if (!fcheck_files(files, fd))
-					continue;
-				rcu_read_unlock();
-
-				len = snprintf(name, sizeof(name), "%d", fd);
-				rv = proc_fill_cache(filp, dirent, filldir,
-						     name, len, instantiate, p,
-						     (void *)(unsigned long)fd);
-				if (rv < 0)
-					goto out_fd_loop;
-				rcu_read_lock();
-			}
-			rcu_read_unlock();
-out_fd_loop:
-			put_files_struct(files);
-	}
-out:
-	put_task_struct(p);
-out_no_task:
-	return retval;
-}
-
-static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
-				    unsigned int flags)
-{
-	return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
-}
-
-static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
-{
-	return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
-}
-
-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 const struct file_operations proc_fd_operations = {
-	.read		= generic_read_dir,
-	.readdir	= proc_readfd,
-	.llseek		= default_llseek,
-};
-
 #ifdef CONFIG_CHECKPOINT_RESTORE
 
 /*
@@ -2337,82 +2029,6 @@ static const struct file_operations proc
 
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 
-/*
- * /proc/pid/fd needs a special permission handler so that a process can still
- * access /proc/self/fd after it has executed a setuid().
- */
-static int proc_fd_permission(struct inode *inode, int mask)
-{
-	int rv = generic_permission(inode, mask);
-	if (rv == 0)
-		return 0;
-	if (task_pid(current) == proc_pid(inode))
-		rv = 0;
-	return rv;
-}
-
-/*
- * proc directories can do almost nothing..
- */
-static const struct inode_operations proc_fd_inode_operations = {
-	.lookup		= proc_lookupfd,
-	.permission	= proc_fd_permission,
-	.setattr	= proc_setattr,
-};
-
-static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
-	struct dentry *dentry, struct task_struct *task, const void *ptr)
-{
-	unsigned fd = (unsigned long)ptr;
- 	struct inode *inode;
- 	struct proc_inode *ei;
-	struct dentry *error = ERR_PTR(-ENOENT);
-
-	inode = proc_pid_make_inode(dir->i_sb, task);
-	if (!inode)
-		goto out;
-	ei = PROC_I(inode);
-	ei->fd = fd;
-	inode->i_mode = S_IFREG | S_IRUSR;
-	inode->i_fop = &proc_fdinfo_file_operations;
-	d_set_d_op(dentry, &tid_fd_dentry_operations);
-	d_add(dentry, inode);
-	/* Close the race of the process dying before we return the dentry */
-	if (tid_fd_revalidate(dentry, 0))
-		error = NULL;
-
- out:
-	return error;
-}
-
-static struct dentry *proc_lookupfdinfo(struct inode *dir,
-					struct dentry *dentry,
-					unsigned int flags)
-{
-	return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
-}
-
-static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
-{
-	return proc_readfd_common(filp, dirent, filldir,
-				  proc_fdinfo_instantiate);
-}
-
-static const struct file_operations proc_fdinfo_operations = {
-	.read		= generic_read_dir,
-	.readdir	= proc_readfdinfo,
-	.llseek		= default_llseek,
-};
-
-/*
- * proc directories can do almost nothing..
- */
-static const struct inode_operations proc_fdinfo_inode_operations = {
-	.lookup		= proc_lookupfdinfo,
-	.setattr	= proc_setattr,
-};
-
-
 static struct dentry *proc_pident_instantiate(struct inode *dir,
 	struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- /dev/null
+++ linux-2.6.git/fs/proc/fd.c
@@ -0,0 +1,351 @@
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/dcache.h>
+#include <linux/path.h>
+#include <linux/fdtable.h>
+#include <linux/namei.h>
+#include <linux/pid.h>
+#include <linux/security.h>
+
+#include <linux/proc_fs.h>
+
+#include "internal.h"
+#include "fd.h"
+
+#define PROC_FDINFO_MAX 64
+
+static int proc_fd_info(struct inode *inode, struct path *path, char *info)
+{
+	struct task_struct *task = get_proc_task(inode);
+	struct files_struct *files = NULL;
+	int fd = proc_fd(inode);
+	struct file *file;
+
+	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);
+		if (file) {
+			unsigned int f_flags;
+			struct fdtable *fdt;
+
+			fdt = files_fdtable(files);
+			f_flags = 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;
+		}
+		spin_unlock(&files->file_lock);
+		put_files_struct(files);
+	}
+	return -ENOENT;
+}
+
+static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
+{
+	struct files_struct *files;
+	struct task_struct *task;
+	const struct cred *cred;
+	struct inode *inode;
+	int fd;
+
+	if (flags & LOOKUP_RCU)
+		return -ECHILD;
+
+	inode = dentry->d_inode;
+	task = get_proc_task(inode);
+	fd = proc_fd(inode);
+
+	if (task) {
+		files = get_files_struct(task);
+		if (files) {
+			struct file *file;
+
+			rcu_read_lock();
+			file = fcheck_files(files, fd);
+			if (file) {
+				unsigned f_mode = file->f_mode;
+
+				rcu_read_unlock();
+				put_files_struct(files);
+
+				if (task_dumpable(task)) {
+					rcu_read_lock();
+					cred = __task_cred(task);
+					inode->i_uid = cred->euid;
+					inode->i_gid = cred->egid;
+					rcu_read_unlock();
+				} else {
+					inode->i_uid = GLOBAL_ROOT_UID;
+					inode->i_gid = GLOBAL_ROOT_GID;
+				}
+
+				if (S_ISLNK(inode->i_mode)) {
+					unsigned i_mode = S_IFLNK;
+					if (f_mode & FMODE_READ)
+						i_mode |= S_IRUSR | S_IXUSR;
+					if (f_mode & FMODE_WRITE)
+						i_mode |= S_IWUSR | S_IXUSR;
+					inode->i_mode = i_mode;
+				}
+
+				security_task_to_inode(task, inode);
+				put_task_struct(task);
+				return 1;
+			}
+			rcu_read_unlock();
+			put_files_struct(files);
+		}
+		put_task_struct(task);
+	}
+
+	d_drop(dentry);
+	return 0;
+}
+
+static const struct dentry_operations tid_fd_dentry_operations = {
+	.d_revalidate	= tid_fd_revalidate,
+	.d_delete	= pid_delete_dentry,
+};
+
+static int proc_fd_link(struct dentry *dentry, struct path *path)
+{
+	return proc_fd_info(dentry->d_inode, path, NULL);
+}
+
+static struct dentry *
+proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
+		    struct task_struct *task, const void *ptr)
+{
+	struct dentry *error = ERR_PTR(-ENOENT);
+	unsigned fd = (unsigned long)ptr;
+	struct proc_inode *ei;
+	struct inode *inode;
+
+	inode = proc_pid_make_inode(dir->i_sb, task);
+	if (!inode)
+		goto out;
+
+	ei = PROC_I(inode);
+	ei->fd = fd;
+
+	inode->i_mode = S_IFLNK;
+	inode->i_op = &proc_pid_link_inode_operations;
+	inode->i_size = 64;
+
+	ei->op.proc_get_link = proc_fd_link;
+
+	d_set_d_op(dentry, &tid_fd_dentry_operations);
+	d_add(dentry, inode);
+
+	/* Close the race of the process dying before we return the dentry */
+	if (tid_fd_revalidate(dentry, 0))
+		error = NULL;
+ out:
+	return error;
+}
+
+static struct dentry *proc_lookupfd_common(struct inode *dir,
+					   struct dentry *dentry,
+					   instantiate_t instantiate)
+{
+	struct task_struct *task = get_proc_task(dir);
+	struct dentry *result = ERR_PTR(-ENOENT);
+	unsigned fd = name_to_int(dentry);
+
+	if (!task)
+		goto out_no_task;
+	if (fd == ~0U)
+		goto out;
+
+	result = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
+out:
+	put_task_struct(task);
+out_no_task:
+	return result;
+}
+
+static int proc_readfd_common(struct file * filp, void * dirent,
+			      filldir_t filldir, instantiate_t instantiate)
+{
+	struct dentry *dentry = filp->f_path.dentry;
+	struct inode *inode = dentry->d_inode;
+	struct task_struct *p = get_proc_task(inode);
+	struct files_struct *files;
+	unsigned int fd, ino;
+	int retval;
+
+	retval = -ENOENT;
+	if (!p)
+		goto out_no_task;
+	retval = 0;
+
+	fd = filp->f_pos;
+	switch (fd) {
+		case 0:
+			if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
+				goto out;
+			filp->f_pos++;
+		case 1:
+			ino = parent_ino(dentry);
+			if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
+				goto out;
+			filp->f_pos++;
+		default:
+			files = get_files_struct(p);
+			if (!files)
+				goto out;
+			rcu_read_lock();
+			for (fd = filp->f_pos - 2;
+			     fd < files_fdtable(files)->max_fds;
+			     fd++, filp->f_pos++) {
+				char name[PROC_NUMBUF];
+				int len;
+				int rv;
+
+				if (!fcheck_files(files, fd))
+					continue;
+				rcu_read_unlock();
+
+				len = snprintf(name, sizeof(name), "%d", fd);
+				rv = proc_fill_cache(filp, dirent, filldir,
+						     name, len, instantiate, p,
+						     (void *)(unsigned long)fd);
+				if (rv < 0)
+					goto out_fd_loop;
+				rcu_read_lock();
+			}
+			rcu_read_unlock();
+out_fd_loop:
+			put_files_struct(files);
+	}
+out:
+	put_task_struct(p);
+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);
+}
+
+const struct file_operations proc_fd_operations = {
+	.read		= generic_read_dir,
+	.readdir	= proc_readfd,
+	.llseek		= default_llseek,
+};
+
+static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
+				    unsigned int flags)
+{
+	return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
+}
+
+/*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+int proc_fd_permission(struct inode *inode, int mask)
+{
+	int rv = generic_permission(inode, mask);
+	if (rv == 0)
+		return 0;
+	if (task_pid(current) == proc_pid(inode))
+		rv = 0;
+	return rv;
+}
+
+const struct inode_operations proc_fd_inode_operations = {
+	.lookup		= proc_lookupfd,
+	.permission	= proc_fd_permission,
+	.setattr	= proc_setattr,
+};
+
+static struct dentry *
+proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
+			struct task_struct *task, const void *ptr)
+{
+	struct dentry *error = ERR_PTR(-ENOENT);
+	unsigned fd = (unsigned long)ptr;
+	struct proc_inode *ei;
+	struct inode *inode;
+
+	inode = proc_pid_make_inode(dir->i_sb, task);
+	if (!inode)
+		goto out;
+
+	ei = PROC_I(inode);
+	ei->fd = fd;
+
+	inode->i_mode = S_IFREG | S_IRUSR;
+	inode->i_fop = &proc_fdinfo_file_operations;
+
+	d_set_d_op(dentry, &tid_fd_dentry_operations);
+	d_add(dentry, inode);
+
+	/* Close the race of the process dying before we return the dentry */
+	if (tid_fd_revalidate(dentry, 0))
+		error = NULL;
+ out:
+	return error;
+}
+
+static struct dentry *
+proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+	return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
+}
+
+static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
+{
+	return proc_readfd_common(filp, dirent, filldir,
+				  proc_fdinfo_instantiate);
+}
+
+const struct inode_operations proc_fdinfo_inode_operations = {
+	.lookup		= proc_lookupfdinfo,
+	.setattr	= proc_setattr,
+};
+
+const struct file_operations proc_fdinfo_operations = {
+	.read		= generic_read_dir,
+	.readdir	= proc_readfdinfo,
+	.llseek		= default_llseek,
+};
Index: linux-2.6.git/fs/proc/fd.h
===================================================================
--- /dev/null
+++ 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__ */
Index: linux-2.6.git/fs/proc/internal.h
===================================================================
--- linux-2.6.git.orig/fs/proc/internal.h
+++ linux-2.6.git/fs/proc/internal.h
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/sched.h>
 #include <linux/proc_fs.h>
 struct  ctl_table_header;
 
@@ -65,6 +66,7 @@ extern const struct file_operations proc
 extern const struct file_operations proc_pagemap_operations;
 extern const struct file_operations proc_net_operations;
 extern const struct inode_operations proc_net_inode_operations;
+extern const struct inode_operations proc_pid_link_inode_operations;
 
 struct proc_maps_private {
 	struct pid *pid;
@@ -91,6 +93,52 @@ static inline int proc_fd(struct inode *
 	return PROC_I(inode)->fd;
 }
 
+static inline int task_dumpable(struct task_struct *task)
+{
+	int dumpable = 0;
+	struct mm_struct *mm;
+
+	task_lock(task);
+	mm = task->mm;
+	if (mm)
+		dumpable = get_dumpable(mm);
+	task_unlock(task);
+	if(dumpable == 1)
+		return 1;
+	return 0;
+}
+
+static inline int pid_delete_dentry(const struct dentry * dentry)
+{
+	/* Is the task we represent dead?
+	 * If so, then don't put the dentry on the lru list,
+	 * kill it immediately.
+	 */
+	return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
+}
+
+static inline unsigned name_to_int(struct dentry *dentry)
+{
+	const char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	unsigned n = 0;
+
+	if (len > 1 && *name == '0')
+		goto out;
+	while (len-- > 0) {
+		unsigned c = *name++ - '0';
+		if (c > 9)
+			goto out;
+		if (n >= (~0U-9)/10)
+			goto out;
+		n *= 10;
+		n += c;
+	}
+	return n;
+out:
+	return ~0U;
+}
+
 struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *ino,
 		struct dentry *dentry);
 int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 2/8] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
  2012-08-14 14:03 ` [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch] Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:21   ` Pavel Emelyanov
  2012-08-14 14:03 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-seq-ops-6 --]
[-- Type: text/plain, Size: 5334 bytes --]

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

Note the proc_fd_link no longer call for proc_fd_info, simply because
proc_fd_info is converted to seq_fdinfo_open (which is seq-file open()
prototype), moreover in further patches I need to provide two seq_fdinfo_open
variants -- one with CONFIG_CHECKPOINT_RESTORE and one without this
symbol. All in one -- this will look more messy then.

Also, to eliminate code duplication (and Pavel's concerns) the fdinfo_open_helper
function introduced which is used in both seq_fdinfo_open and proc_fd_link.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/proc/fd.c |  123 +++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 75 insertions(+), 48 deletions(-)

Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -6,61 +6,104 @@
 #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 fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
 {
-	struct task_struct *task = get_proc_task(inode);
 	struct files_struct *files = NULL;
-	int fd = proc_fd(inode);
-	struct file *file;
+	struct task_struct *task;
+	int ret = -ENOENT;
 
+	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);
-		if (file) {
-			unsigned int f_flags;
-			struct fdtable *fdt;
-
-			fdt = files_fdtable(files);
-			f_flags = file->f_flags & ~O_CLOEXEC;
-			if (close_on_exec(fd, fdt))
-				f_flags |= O_CLOEXEC;
+		int fd = proc_fd(inode);
+		struct file *fd_file;
 
+		spin_lock(&files->file_lock);
+		fd_file = fcheck_files(files, fd);
+		if (fd_file) {
+			if (f_flags) {
+				struct fdtable *fdt = files_fdtable(files);
+
+				*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);
+				*path = fd_file->f_path;
+				path_get(&fd_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;
+			ret = 0;
 		}
 		spin_unlock(&files->file_lock);
 		put_files_struct(files);
 	}
-	return -ENOENT;
+
+	return ret;
 }
 
+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 proc_fdinfo *fdinfo = NULL;
+	int ret = -ENOENT;
+
+	fdinfo = kzalloc(sizeof(*fdinfo), GFP_KERNEL);
+	if (!fdinfo)
+		return -ENOMEM;
+
+	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, NULL);
+	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, unsigned int flags)
 {
 	struct files_struct *files;
@@ -130,7 +173,7 @@ 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);
+	return fdinfo_open_helper(dentry->d_inode, NULL, path);
 }
 
 static struct dentry *
@@ -245,22 +288,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);


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
  2012-08-14 14:03 ` [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch] Cyrill Gorcunov
  2012-08-14 14:03 ` [patch 2/8] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:22   ` Pavel Emelyanov
  2012-08-14 18:31   ` Al Viro
  2012-08-14 14:03 ` [patch 4/8] fs, eventfd: Add procfs fdinfo helper Cyrill Gorcunov
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-seq-ops-helpers-8 --]
[-- Type: text/plain, Size: 8862 bytes --]

This patch brings ability to plug in 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).

The basic usage rule is the following

 - fdinfo provider should register own "show" method
   via proc_register_fdinfo_driver call, where "show"
   methods are rather well known seq-file operations

 - once the kernel opens /proc/$pid/fdinfo/$fd file
   it calls for ->probe() method in registered fdinfo
   drivers, and if probe success, then seq-file "show"
   operations will be called to provide out additional
   infomation

Initially we considered to inject some "show" metod to
file_operations but since there really a number of
file_operations declared inside kernel (and in real the
further patches cover onle eventfd/epoll/inotify) the
waste of memory space will be inacceptable I think.

Pavel, I've left seq_next memthod as it was simply because
we can't leave seq_next() after calling extra->driver->ops->start
without increasing "pos", thus we need to call for "show" manually
once.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/proc/fd.c            |  198 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/proc_fs.h |   26 ++++++
 2 files changed, 216 insertions(+), 8 deletions(-)

Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -8,18 +8,14 @@
 #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"
 
-struct proc_fdinfo {
-	loff_t	f_pos;
-	int	f_flags;
-};
-
-static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
+static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct file **f_file, struct path *path)
 {
 	struct files_struct *files = NULL;
 	struct task_struct *task;
@@ -49,6 +45,10 @@ static int fdinfo_open_helper(struct ino
 				*path = fd_file->f_path;
 				path_get(&fd_file->f_path);
 			}
+			if (f_file) {
+				*f_file = fd_file;
+				get_file(fd_file);
+			}
 			ret = 0;
 		}
 		spin_unlock(&files->file_lock);
@@ -58,6 +58,186 @@ static int fdinfo_open_helper(struct ino
 	return ret;
 }
 
+#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, *tmp;
+
+	down_write(&fdinfo_drivers_sem);
+	list_for_each_entry_safe(i, tmp, &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;
+
+	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);
+
+	return 0;
+}
+
+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 proc_fdinfo_extra *extra;
+	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;
+
+		ret = fdinfo_open_helper(inode, &extra->f_flags,
+					 &extra->f_file, NULL);
+		if (!ret)
+			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(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;
+};
+
 static int seq_show(struct seq_file *m, void *v)
 {
 	struct proc_fdinfo *fdinfo = m->private;
@@ -76,7 +256,7 @@ static int seq_fdinfo_open(struct inode
 	if (!fdinfo)
 		return -ENOMEM;
 
-	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, NULL);
+	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, NULL, NULL);
 	if (!ret) {
 		ret = single_open(file, seq_show, fdinfo);
 		if (!ret)
@@ -104,6 +284,8 @@ static const struct file_operations proc
 	.release	= seq_fdinfo_release,
 };
 
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
 static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct files_struct *files;
@@ -173,7 +355,7 @@ static const struct dentry_operations ti
 
 static int proc_fd_link(struct dentry *dentry, struct path *path)
 {
-	return fdinfo_open_helper(dentry->d_inode, NULL, path);
+	return fdinfo_open_helper(dentry->d_inode, NULL, NULL, path);
 }
 
 static struct dentry *
Index: linux-2.6.git/include/linux/proc_fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/proc_fs.h
+++ linux-2.6.git/include/linux/proc_fs.h
@@ -100,6 +100,24 @@ 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);
+};
+
+/* auxiliary data allocated per fdinfo reader */
+struct proc_fdinfo_extra {
+	struct proc_fdinfo_driver	*driver;
+	loff_t				pos;
+	struct file			*f_file;
+	unsigned int			f_flags;
+};
+
 #ifdef CONFIG_PROC_FS
 
 extern void proc_root_init(void);
@@ -175,6 +193,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 +252,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)


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 4/8] fs, eventfd: Add procfs fdinfo helper
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
                   ` (2 preceding siblings ...)
  2012-08-14 14:03 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:22   ` Pavel Emelyanov
  2012-08-14 14:03 ` [patch 5/8] fs, epoll: Add procfs fdinfo helper v2 Cyrill Gorcunov
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-eventfd-6 --]
[-- Type: text/plain, Size: 2276 bytes --]

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.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/eventfd.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

Index: linux-2.6.git/fs/eventfd.c
===================================================================
--- linux-2.6.git.orig/fs/eventfd.c
+++ 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;
@@ -433,3 +435,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 */


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 5/8] fs, epoll: Add procfs fdinfo helper v2
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
                   ` (3 preceding siblings ...)
  2012-08-14 14:03 ` [patch 4/8] fs, eventfd: Add procfs fdinfo helper Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:22   ` Pavel Emelyanov
  2012-08-14 14:03 ` [patch 6/8] fs, exportfs: Add export_encode_inode_fh helper Cyrill Gorcunov
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-eventpoll-5 --]
[-- Type: text/plain, Size: 3034 bytes --]

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.

v2:
 - don't walk over all rb nodes on seq-next,
   try to continue from pervious position

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
CC: Matthew Helsley <matt.helsley@gmail.com>
---
 fs/eventpoll.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

Index: linux-2.6.git/fs/eventpoll.c
===================================================================
--- linux-2.6.git.orig/fs/eventpoll.c
+++ linux-2.6.git/fs/eventpoll.c
@@ -38,6 +38,8 @@
 #include <asm/io.h>
 #include <asm/mman.h>
 #include <linux/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 /*
  * LOCKING:
@@ -1897,6 +1899,69 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd,
 	return error;
 }
 
+#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;
+	struct eventpoll *ep = extra->f_file->private_data;
+	struct rb_node *rbp;
+	loff_t num = *pos;
+
+	mutex_lock(&ep->mtx);
+	for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+		if (num-- == 0)
+			return rbp;
+	}
+
+	return NULL;
+}
+
+static void seq_stop(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	struct eventpoll *ep = extra->f_file->private_data;
+	mutex_unlock(&ep->mtx);
+}
+
+static void *seq_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	struct rb_node *rbp = p;
+	++*pos;
+	return (void *)rb_next(rbp);
+}
+
+static int seq_show(struct seq_file *m, void *v)
+{
+	struct rb_node *rbp = v;
+	struct epitem *epi = rb_entry(rbp, struct epitem, rbn);
+
+	return seq_printf(m, "tfd: %8d events: %8x data: %16llx\n",
+			  epi->ffd.fd, epi->event.events,
+			  (long long)epi->event.data);
+}
+
+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,
+};
+
+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;
@@ -1929,6 +1994,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);


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 6/8] fs, exportfs: Add export_encode_inode_fh helper
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
                   ` (4 preceding siblings ...)
  2012-08-14 14:03 ` [patch 5/8] fs, epoll: Add procfs fdinfo helper v2 Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:23   ` Pavel Emelyanov
  2012-08-14 14:03 ` [patch 7/8] fs, notify: Add procfs fdinfo helper v3 Cyrill Gorcunov
  2012-08-14 14:03 ` [patch 8/8] fdinfo: Show sigmask for signalfd fd Cyrill Gorcunov
  7 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fs-exportfs-ino-2 --]
[-- Type: text/plain, Size: 2017 bytes --]

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.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/exportfs/expfs.c      |   21 +++++++++++++++++++++
 include/linux/exportfs.h |    4 ++++
 2 files changed, 25 insertions(+)

Index: linux-2.6.git/fs/exportfs/expfs.c
===================================================================
--- linux-2.6.git.orig/fs/exportfs/expfs.c
+++ 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
  * @inode:   the object to encode
Index: linux-2.6.git/include/linux/exportfs.h
===================================================================
--- linux-2.6.git.orig/include/linux/exportfs.h
+++ 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,


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 7/8] fs, notify: Add procfs fdinfo helper v3
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
                   ` (5 preceding siblings ...)
  2012-08-14 14:03 ` [patch 6/8] fs, exportfs: Add export_encode_inode_fh helper Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  2012-08-14 14:23   ` Pavel Emelyanov
  2012-08-14 14:03 ` [patch 8/8] fdinfo: Show sigmask for signalfd fd Cyrill Gorcunov
  7 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-fsnotify-4 --]
[-- Type: text/plain, Size: 11382 bytes --]

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.

v2:
 - append missing colons to terms
v3:
 - continue from pervious position in list on ->next

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/notify/Makefile                 |    2 
 fs/notify/fanotify/fanotify_user.c |   17 ++
 fs/notify/fdinfo.c                 |  216 +++++++++++++++++++++++++++++++++++++
 fs/notify/fdinfo.h                 |   19 +++
 fs/notify/inotify/inotify_user.c   |   32 +++++
 5 files changed, 284 insertions(+), 2 deletions(-)

Index: linux-2.6.git/fs/notify/Makefile
===================================================================
--- linux-2.6.git.orig/fs/notify/Makefile
+++ 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/
Index: linux-2.6.git/fs/notify/fanotify/fanotify_user.c
===================================================================
--- linux-2.6.git.orig/fs/notify/fanotify/fanotify_user.c
+++ 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
@@ -873,6 +874,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
@@ -883,7 +898,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);
Index: linux-2.6.git/fs/notify/fdinfo.c
===================================================================
--- /dev/null
+++ linux-2.6.git/fs/notify/fdinfo.c
@@ -0,0 +1,216 @@
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fsnotify_backend.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/inotify.h>
+#include <linux/kernel.h>
+#include <linux/namei.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/seq_file.h>
+#include <linux/exportfs.h>
+#include <linux/proc_fs.h>
+
+#include "inotify/inotify.h"
+#include "../fs/mount.h"
+
+struct inode_file_handle {
+	struct file_handle		h;
+	struct fid			fid;
+} __packed;
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_CHECKPOINT_RESTORE)
+
+#if defined(CONFIG_INOTIFY_USER) || defined(CONFIG_FANOTIFY)
+
+#ifdef CONFIG_EXPORTFS
+static int inotify_encode_target(struct inode *inode, struct inode_file_handle *fhandle)
+{
+	int ret, size;
+
+	size = sizeof(fhandle->fid) >> 2;
+	ret = export_encode_inode_fh(inode, &fhandle->fid, &size);
+	BUG_ON(ret != FILEID_INO32_GEN);
+
+	fhandle->h.handle_type = FILEID_INO32_GEN;
+	fhandle->h.handle_bytes = size * sizeof(u32);
+
+	return 0;
+}
+#else
+static int inotify_encode_target(struct inode *inode, struct inode_file_handle *fhandle)
+{
+	fhandle->h.handle_type = FILEID_ROOT;
+	fhandle->h.handle_bytes = 0;
+	return 0;
+}
+#endif /* CONFIG_EXPORTFS */
+
+static inline bool mark_match(struct fsnotify_mark *mark)
+{
+	return (mark->flags & FSNOTIFY_MARK_FLAG_ALIVE) &&
+		(mark->flags & (FSNOTIFY_MARK_FLAG_INODE | FSNOTIFY_MARK_FLAG_VFSMOUNT));
+}
+
+static void *seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	struct fsnotify_group *group = extra->f_file->private_data;
+	struct fsnotify_mark *mark;
+	loff_t num = *pos;
+
+	spin_lock(&group->mark_lock);
+
+	list_for_each_entry(mark, &group->marks_list, g_list) {
+		if (!mark_match(mark))
+			continue;
+		if (num-- == 0)
+			return (void *)mark;
+	}
+
+	return NULL;
+}
+
+static void seq_stop(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	struct fsnotify_group *group = extra->f_file->private_data;
+
+	spin_unlock(&group->mark_lock);
+}
+
+static void *seq_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+	struct fsnotify_group *group = extra->f_file->private_data;
+	struct fsnotify_mark *mark = p;
+
+	++*pos;
+
+	list_for_each_entry_continue(mark, &group->marks_list, g_list) {
+		if (mark_match(mark))
+			return mark;
+	}
+
+	return NULL;
+}
+
+#ifdef CONFIG_INOTIFY_USER
+
+extern int is_file_inotify(struct file *file);
+
+static int seq_show_inotify(struct seq_file *m, void *v)
+{
+	struct inotify_inode_mark *inode_mark;
+	struct fsnotify_mark *mark = v;
+	struct inode *inode;
+
+	if (unlikely(!(mark->flags & FSNOTIFY_MARK_FLAG_INODE)))
+		goto out;
+
+	inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
+	inode = igrab(mark->i.inode);
+	if (inode) {
+		struct inode_file_handle fhandle;
+		int i;
+
+		inotify_encode_target(inode, &fhandle);
+
+		seq_printf(m, "inotify wd: %8d ino: %16lx sdev: %8x "
+			   "mask: %8x ignored_mask: %8x "
+			   "fhandle-bytes: %8x fhandle-type: %8x f_handle: ",
+			   inode_mark->wd, inode->i_ino,
+			   inode->i_sb->s_dev,
+			   mark->mask,
+			   mark->ignored_mask,
+			   fhandle.h.handle_bytes,
+			   fhandle.h.handle_type);
+
+		for (i = 0; i < fhandle.h.handle_bytes; i++) {
+			seq_printf(m, "%02x",
+				   (int)(unsigned char)fhandle.h.f_handle[i]);
+		}
+		seq_putc(m, '\n');
+		iput(inode);
+	}
+out:
+	return 0;
+}
+
+static const struct seq_operations inotify_fdinfo_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show_inotify,
+};
+
+struct proc_fdinfo_driver inotify_fdinfo = {
+	.name	= "inotify",
+	.ops	= &inotify_fdinfo_ops,
+	.probe	= is_file_inotify,
+};
+
+#endif /* CONFIG_INOTIFY_USER */
+
+#ifdef CONFIG_FANOTIFY
+
+extern int is_file_fanotify(struct file *file);
+
+static int seq_show_fanotify(struct seq_file *m, void *v)
+{
+	struct fsnotify_mark *mark = v;
+	struct inode *inode;
+
+	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
+		struct inode_file_handle fhandle;
+		int i;
+
+		inode = igrab(mark->i.inode);
+		if (!inode)
+			goto out;
+		inotify_encode_target(inode, &fhandle);
+
+		seq_printf(m, "fanotify ino: %16lx sdev: %8x "
+			   "mask: %8x ignored_mask: %8x "
+			   "fhandle-bytes: %8x fhandle-type: %8x f_handle: ",
+			   inode->i_ino,
+			   inode->i_sb->s_dev,
+			   mark->mask,
+			   mark->ignored_mask,
+			   fhandle.h.handle_bytes,
+			   fhandle.h.handle_type);
+
+		for (i = 0; i < fhandle.h.handle_bytes; i++)
+			seq_printf(m, "%02x",
+				   (int)(unsigned char)fhandle.h.f_handle[i]);
+		seq_putc(m, '\n');
+		iput(inode);
+	} else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) {
+		struct mount *mnt = real_mount(mark->m.mnt);
+
+		seq_printf(m, "fanotify mnt_id: %8x mask: %8x ignored_mask: %8x\n",
+			   mnt->mnt_id, mark->mask, mark->ignored_mask);
+	}
+out:
+	return 0;
+}
+
+static const struct seq_operations fanotify_fdinfo_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show_fanotify,
+};
+
+struct proc_fdinfo_driver fanotify_fdinfo = {
+	.name		= "fanotify",
+	.ops		= &fanotify_fdinfo_ops,
+	.probe		= is_file_fanotify,
+};
+
+#endif /* CONFIG_FANOTIFY */
+
+#endif /* CONFIG_INOTIFY_USER || CONFIG_FANOTIFY */
+
+#endif /* CONFIG_PROC_FS && CONFIG_CHECKPOINT_RESTORE */
Index: linux-2.6.git/fs/notify/fdinfo.h
===================================================================
--- /dev/null
+++ 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__ */
Index: linux-2.6.git/fs/notify/inotify/inotify_user.c
===================================================================
--- linux-2.6.git.orig/fs/notify/inotify/inotify_user.c
+++ 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);


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 8/8] fdinfo: Show sigmask for signalfd fd
  2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
                   ` (6 preceding siblings ...)
  2012-08-14 14:03 ` [patch 7/8] fs, notify: Add procfs fdinfo helper v3 Cyrill Gorcunov
@ 2012-08-14 14:03 ` Cyrill Gorcunov
  7 siblings, 0 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 14:03 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov

[-- Attachment #1: seq-fdinfo-signalfd --]
[-- Type: text/plain, Size: 3654 bytes --]

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
 fs/proc/array.c         |    2 -
 fs/signalfd.c           |   63 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/proc_fs.h |    3 ++
 3 files changed, 67 insertions(+), 1 deletion(-)

Index: linux-2.6.git/fs/proc/array.c
===================================================================
--- linux-2.6.git.orig/fs/proc/array.c
+++ linux-2.6.git/fs/proc/array.c
@@ -220,7 +220,7 @@ static inline void task_state(struct seq
 	seq_putc(m, '\n');
 }
 
-static void render_sigset_t(struct seq_file *m, const char *header,
+void render_sigset_t(struct seq_file *m, const char *header,
 				sigset_t *set)
 {
 	int i;
Index: linux-2.6.git/fs/signalfd.c
===================================================================
--- linux-2.6.git.orig/fs/signalfd.c
+++ linux-2.6.git/fs/signalfd.c
@@ -29,6 +29,7 @@
 #include <linux/anon_inodes.h>
 #include <linux/signalfd.h>
 #include <linux/syscalls.h>
+#include <linux/proc_fs.h>
 
 void signalfd_cleanup(struct sighand_struct *sighand)
 {
@@ -46,6 +47,7 @@ void signalfd_cleanup(struct sighand_str
 }
 
 struct signalfd_ctx {
+	seqcount_t cnt;
 	sigset_t sigmask;
 };
 
@@ -259,6 +261,7 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sig
 			return -ENOMEM;
 
 		ctx->sigmask = sigmask;
+		seqcount_init(&ctx->cnt);
 
 		/*
 		 * When we call this, the initialization must be complete, since
@@ -279,7 +282,9 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sig
 			return -EINVAL;
 		}
 		spin_lock_irq(&current->sighand->siglock);
+		write_seqcount_begin(&ctx->cnt);
 		ctx->sigmask = sigmask;
+		write_seqcount_end(&ctx->cnt);
 		spin_unlock_irq(&current->sighand->siglock);
 
 		wake_up(&current->sighand->signalfd_wqh);
@@ -294,3 +299,61 @@ SYSCALL_DEFINE3(signalfd, int, ufd, sigs
 {
 	return sys_signalfd4(ufd, user_mask, sizemask, 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 signalfd_ctx *ctx = ((struct file *)v)->private_data;
+	sigset_t sigmask;
+	unsigned seq;
+
+	do {
+		seq = read_seqcount_begin(&ctx->cnt);
+		sigmask = ctx->sigmask;
+	} while (read_seqcount_retry(&ctx->cnt, seq));
+
+	signotset(&sigmask);
+	render_sigset_t(m, "sigmask:\t", &sigmask);
+	return 0;
+}
+
+static void seq_stop(struct seq_file *p, void *v) { }
+
+static const struct seq_operations signalfd_fdinfo_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show,
+};
+
+static int is_signalfd_file(struct file *file)
+{
+	return file->f_op == &signalfd_fops;
+}
+
+static struct proc_fdinfo_driver signalfd_fdinfo = {
+	.name	= "signalfd",
+	.ops	= &signalfd_fdinfo_ops,
+	.probe	= is_signalfd_file,
+};
+
+static int __init signalfd_init(void)
+{
+	return proc_register_fdinfo_driver(&signalfd_fdinfo);
+}
+fs_initcall(signalfd_init);
+
+#endif /* CONFIG_PROC_FS && CONFIG_CHECKPOINT_RESTORE */
Index: linux-2.6.git/include/linux/proc_fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/proc_fs.h
+++ linux-2.6.git/include/linux/proc_fs.h
@@ -316,4 +316,7 @@ static inline struct net *PDE_NET(struct
 	return pde->parent->data;
 }
 
+#include <asm/signal.h>
+
+void render_sigset_t(struct seq_file *m, const char *header, sigset_t *set);
 #endif /* _LINUX_PROC_FS_H */


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch]
  2012-08-14 14:03 ` [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch] Cyrill Gorcunov
@ 2012-08-14 14:21   ` Pavel Emelyanov
  0 siblings, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:21 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> This patch prepares the ground for further extension of
> /proc/pid/fd[info] handling code by moving fdinfo handling
> code into fs/proc/fd.c.
> 
> I think such move makes both fs/proc/base.c and fs/proc/fd.c
> easier to read.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 2/8] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file
  2012-08-14 14:03 ` [patch 2/8] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file Cyrill Gorcunov
@ 2012-08-14 14:21   ` Pavel Emelyanov
  0 siblings, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:21 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> This patch converts /proc/pid/fdinfo/ handling routines to seq-file which
> is needed to extend seq operations and plug in auxiliary fdinfo provides
> from subsystems like eventfd/eventpoll/fsnotify.
> 
> Note the proc_fd_link no longer call for proc_fd_info, simply because
> proc_fd_info is converted to seq_fdinfo_open (which is seq-file open()
> prototype), moreover in further patches I need to provide two seq_fdinfo_open
> variants -- one with CONFIG_CHECKPOINT_RESTORE and one without this
> symbol. All in one -- this will look more messy then.
> 
> Also, to eliminate code duplication (and Pavel's concerns) the fdinfo_open_helper
> function introduced which is used in both seq_fdinfo_open and proc_fd_link.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 14:03 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
@ 2012-08-14 14:22   ` Pavel Emelyanov
  2012-08-14 18:31   ` Al Viro
  1 sibling, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:22 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> This patch brings ability to plug in 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).
> 
> The basic usage rule is the following
> 
>  - fdinfo provider should register own "show" method
>    via proc_register_fdinfo_driver call, where "show"
>    methods are rather well known seq-file operations
> 
>  - once the kernel opens /proc/$pid/fdinfo/$fd file
>    it calls for ->probe() method in registered fdinfo
>    drivers, and if probe success, then seq-file "show"
>    operations will be called to provide out additional
>    infomation
> 
> Initially we considered to inject some "show" metod to
> file_operations but since there really a number of
> file_operations declared inside kernel (and in real the
> further patches cover onle eventfd/epoll/inotify) the
> waste of memory space will be inacceptable I think.
> 
> Pavel, I've left seq_next memthod as it was simply because
> we can't leave seq_next() after calling extra->driver->ops->start
> without increasing "pos", thus we need to call for "show" manually
> once.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 4/8] fs, eventfd: Add procfs fdinfo helper
  2012-08-14 14:03 ` [patch 4/8] fs, eventfd: Add procfs fdinfo helper Cyrill Gorcunov
@ 2012-08-14 14:22   ` Pavel Emelyanov
  0 siblings, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:22 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> 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.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 5/8] fs, epoll: Add procfs fdinfo helper v2
  2012-08-14 14:03 ` [patch 5/8] fs, epoll: Add procfs fdinfo helper v2 Cyrill Gorcunov
@ 2012-08-14 14:22   ` Pavel Emelyanov
  0 siblings, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:22 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> 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.
> 
> v2:
>  - don't walk over all rb nodes on seq-next,
>    try to continue from pervious position
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>
> CC: Matthew Helsley <matt.helsley@gmail.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 6/8] fs, exportfs: Add export_encode_inode_fh helper
  2012-08-14 14:03 ` [patch 6/8] fs, exportfs: Add export_encode_inode_fh helper Cyrill Gorcunov
@ 2012-08-14 14:23   ` Pavel Emelyanov
  0 siblings, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:23 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> 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.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 7/8] fs, notify: Add procfs fdinfo helper v3
  2012-08-14 14:03 ` [patch 7/8] fs, notify: Add procfs fdinfo helper v3 Cyrill Gorcunov
@ 2012-08-14 14:23   ` Pavel Emelyanov
  0 siblings, 0 replies; 30+ messages in thread
From: Pavel Emelyanov @ 2012-08-14 14:23 UTC (permalink / raw)
  To: Cyrill Gorcunov, Al Viro, Andrew Morton
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, James Bottomley,
	Matthew Helsley

On 08/14/2012 06:03 PM, Cyrill Gorcunov wrote:
> 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.
> 
> v2:
>  - append missing colons to terms
> v3:
>  - continue from pervious position in list on ->next
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
> CC: Al Viro <viro@ZenIV.linux.org.uk>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: Pavel Emelyanov <xemul@parallels.com>
> CC: James Bottomley <jbottomley@parallels.com>

Acked-by: Pavel Emelyanov <xemul@parallels.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 14:03 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
  2012-08-14 14:22   ` Pavel Emelyanov
@ 2012-08-14 18:31   ` Al Viro
  2012-08-14 18:35     ` Cyrill Gorcunov
  1 sibling, 1 reply; 30+ messages in thread
From: Al Viro @ 2012-08-14 18:31 UTC (permalink / raw)
  To: Cyrill Gorcunov
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Tue, Aug 14, 2012 at 06:03:45PM +0400, Cyrill Gorcunov wrote:
> This patch brings ability to plug in 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).
> 
> The basic usage rule is the following
> 
>  - fdinfo provider should register own "show" method
>    via proc_register_fdinfo_driver call, where "show"
>    methods are rather well known seq-file operations
> 
>  - once the kernel opens /proc/$pid/fdinfo/$fd file
>    it calls for ->probe() method in registered fdinfo
>    drivers, and if probe success, then seq-file "show"
>    operations will be called to provide out additional
>    infomation
> 
> Initially we considered to inject some "show" metod to
> file_operations but since there really a number of
> file_operations declared inside kernel (and in real the
> further patches cover onle eventfd/epoll/inotify) the
> waste of memory space will be inacceptable I think.

NAK.  This is too ugly to live.  Put it into file_operations,
with NULL meaning default output, or don't do it at all.

And no, "it's only if you enable CONFIG_SOME_SHIT" gambit won't
fly - we have all seen it played too many times.  All it takes
is one politically-inclined induhvidual adding a dependency to
some "vertically integrated" turd (*cough* systemd *spit* udev
*cough*) and we are stuck with the damn thing.  CGROUP shite
is already there, DEVTMPFS is well on its way, etc.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 18:31   ` Al Viro
@ 2012-08-14 18:35     ` Cyrill Gorcunov
  2012-08-14 19:56       ` Cyrill Gorcunov
  0 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 18:35 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Tue, Aug 14, 2012 at 07:31:42PM +0100, Al Viro wrote:
> > Initially we considered to inject some "show" metod to
> > file_operations but since there really a number of
> > file_operations declared inside kernel (and in real the
> > further patches cover onle eventfd/epoll/inotify) the
> > waste of memory space will be inacceptable I think.
> 
> NAK.  This is too ugly to live.  Put it into file_operations,
> with NULL meaning default output, or don't do it at all.
> 
> And no, "it's only if you enable CONFIG_SOME_SHIT" gambit won't
> fly - we have all seen it played too many times.  All it takes
> is one politically-inclined induhvidual adding a dependency to
> some "vertically integrated" turd (*cough* systemd *spit* udev
> *cough*) and we are stuck with the damn thing.  CGROUP shite
> is already there, DEVTMPFS is well on its way, etc.

OK, I'll put it into file_operations then (actually Pavel was
proposing the same but I've been scared by amount of file_operations
declared). Thanks!

	Cyrill

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 18:35     ` Cyrill Gorcunov
@ 2012-08-14 19:56       ` Cyrill Gorcunov
  2012-08-14 21:27         ` Al Viro
  0 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 19:56 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Tue, Aug 14, 2012 at 10:35:58PM +0400, Cyrill Gorcunov wrote:
> On Tue, Aug 14, 2012 at 07:31:42PM +0100, Al Viro wrote:
> > > Initially we considered to inject some "show" metod to
> > > file_operations but since there really a number of
> > > file_operations declared inside kernel (and in real the
> > > further patches cover onle eventfd/epoll/inotify) the
> > > waste of memory space will be inacceptable I think.
> > 
> > NAK.  This is too ugly to live.  Put it into file_operations,
> > with NULL meaning default output, or don't do it at all.
> > 
> > And no, "it's only if you enable CONFIG_SOME_SHIT" gambit won't
> > fly - we have all seen it played too many times.  All it takes
> > is one politically-inclined induhvidual adding a dependency to
> > some "vertically integrated" turd (*cough* systemd *spit* udev
> > *cough*) and we are stuck with the damn thing.  CGROUP shite
> > is already there, DEVTMPFS is well on its way, etc.
> 
> OK, I'll put it into file_operations then (actually Pavel was
> proposing the same but I've been scared by amount of file_operations
> declared). Thanks!

Al, does the patch below looks better? If so I'll fix up the rest.
---
 fs/proc/fd.c            |  109 ++++++++++++++++++++++++++++++++++++++----------
 include/linux/fs.h      |    3 +
 include/linux/proc_fs.h |    8 +++
 3 files changed, 99 insertions(+), 21 deletions(-)

Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -8,18 +8,14 @@
 #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"
 
-struct proc_fdinfo {
-	loff_t	f_pos;
-	int	f_flags;
-};
-
-static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
+static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct file **f_file, struct path *path)
 {
 	struct files_struct *files = NULL;
 	struct task_struct *task;
@@ -49,6 +45,10 @@ static int fdinfo_open_helper(struct ino
 				*path = fd_file->f_path;
 				path_get(&fd_file->f_path);
 			}
+			if (f_file) {
+				*f_file = fd_file;
+				get_file(fd_file);
+			}
 			ret = 0;
 		}
 		spin_unlock(&files->file_lock);
@@ -58,43 +58,110 @@ static int fdinfo_open_helper(struct ino
 	return ret;
 }
 
+static void *seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+
+	extra->pos = *pos;
+
+	return *pos == 0 ? extra :
+		(extra->fdinfo_ops ?
+		 extra->fdinfo_ops->start(m, pos) : NULL);
+}
+
+static void seq_stop(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo_extra *extra = m->private;
+
+	if (extra->fdinfo_ops && extra->pos > 0)
+		extra->fdinfo_ops->stop(m, v);
+}
+
+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->fdinfo_ops) {
+		int ret = 0;
+
+		if (*pos == 0) {
+			v = extra->fdinfo_ops->start(m, pos);
+			if (v) {
+				ret = extra->fdinfo_ops->show(m, v);
+				p = v;
+			} else
+				ret = -1;
+		}
+
+		if (!ret)
+			v = extra->fdinfo_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 *fdinfo = m->private;
+	struct proc_fdinfo_extra *extra = m->private;
+
+	if (extra->fdinfo_ops && extra->pos > 0)
+		return extra->fdinfo_ops->show(m, v);
+
 	seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
-		   (long long)fdinfo->f_pos,
-		   fdinfo->f_flags);
+		   (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 proc_fdinfo *fdinfo = NULL;
-	int ret = -ENOENT;
+	struct proc_fdinfo_extra *extra;
+	struct seq_file *m;
+	int ret;
 
-	fdinfo = kzalloc(sizeof(*fdinfo), GFP_KERNEL);
-	if (!fdinfo)
+	extra = kzalloc(sizeof(*extra), GFP_KERNEL);
+	if (!extra)
 		return -ENOMEM;
 
-	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, NULL);
+	ret = seq_open(file, &fdinfo_seq_ops);
 	if (!ret) {
-		ret = single_open(file, seq_show, fdinfo);
+		ret = -ENOENT;
+		m = file->private_data;
+		m->private = extra;
+
+		ret = fdinfo_open_helper(inode, &extra->f_flags,
+					 &extra->f_file, NULL);
 		if (!ret)
-			fdinfo = NULL;
+			extra->fdinfo_ops = extra->f_file->f_op->fdinfo_ops;
 	}
 
-	kfree(fdinfo);
+	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 *fdinfo = m->private;
+	struct proc_fdinfo_extra *extra = m->private;
 
-	kfree(fdinfo);
+	put_filp(extra->f_file);
+	kfree(m->private);
 
-	return single_release(inode, file);
+	return seq_release(inode, file);
 }
 
 static const struct file_operations proc_fdinfo_file_operations = {
@@ -173,7 +240,7 @@ static const struct dentry_operations ti
 
 static int proc_fd_link(struct dentry *dentry, struct path *path)
 {
-	return fdinfo_open_helper(dentry->d_inode, NULL, path);
+	return fdinfo_open_helper(dentry->d_inode, NULL, NULL, path);
 }
 
 static struct dentry *
Index: linux-2.6.git/include/linux/fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/fs.h
+++ linux-2.6.git/include/linux/fs.h
@@ -1775,8 +1775,11 @@ struct block_device_operations;
 #define HAVE_COMPAT_IOCTL 1
 #define HAVE_UNLOCKED_IOCTL 1
 
+struct seq_operations;
+
 struct file_operations {
 	struct module *owner;
+	struct seq_operations *fdinfo_ops;
 	loff_t (*llseek) (struct file *, loff_t, int);
 	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
Index: linux-2.6.git/include/linux/proc_fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/proc_fs.h
+++ linux-2.6.git/include/linux/proc_fs.h
@@ -100,6 +100,14 @@ struct vmcore {
 	loff_t offset;
 };
 
+/* auxiliary data allocated per fdinfo reader */
+struct proc_fdinfo_extra {
+	loff_t			pos;
+	struct file		*f_file;
+	struct seq_operations	*fdinfo_ops;
+	unsigned int		f_flags;
+};
+
 #ifdef CONFIG_PROC_FS
 
 extern void proc_root_init(void);

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 19:56       ` Cyrill Gorcunov
@ 2012-08-14 21:27         ` Al Viro
  2012-08-14 21:56           ` Cyrill Gorcunov
  0 siblings, 1 reply; 30+ messages in thread
From: Al Viro @ 2012-08-14 21:27 UTC (permalink / raw)
  To: Cyrill Gorcunov
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Tue, Aug 14, 2012 at 11:56:49PM +0400, Cyrill Gorcunov wrote:
> Al, does the patch below looks better? If so I'll fix up the rest.

>  struct file_operations {
>  	struct module *owner;
> +	struct seq_operations *fdinfo_ops;

IDGI.  Why on the earth do you need the whole iterator?  All it takes
is show_fdinfo(struct seq_file *m, struct file *f); have ->show() in
your iterator (one going through the files) call that sucker for the
file we are trying to show.

I think you are severely overdesigning that thing...

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 21:27         ` Al Viro
@ 2012-08-14 21:56           ` Cyrill Gorcunov
  2012-08-14 22:21             ` Cyrill Gorcunov
  0 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 21:56 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Tue, Aug 14, 2012 at 10:27:21PM +0100, Al Viro wrote:
> On Tue, Aug 14, 2012 at 11:56:49PM +0400, Cyrill Gorcunov wrote:
> > Al, does the patch below looks better? If so I'll fix up the rest.
> 
> >  struct file_operations {
> >  	struct module *owner;
> > +	struct seq_operations *fdinfo_ops;
> 
> IDGI.  Why on the earth do you need the whole iterator?  All it takes
> is show_fdinfo(struct seq_file *m, struct file *f); have ->show() in
> your iterator (one going through the files) call that sucker for the
> file we are trying to show.
> 
> I think you are severely overdesigning that thing...

Hmm, in very first versions I've been using one ->show method, but
then I thought that this is not very correlate with seq-files idea
where for each record show/next sequence is called. I'll update (this
for sure will make code simplier, and I'll have to check for seq-file
overflow after seq_printf call to not continue printing data for too
long if buffer already out of space).

	Cyrill

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 21:56           ` Cyrill Gorcunov
@ 2012-08-14 22:21             ` Cyrill Gorcunov
  2012-08-15  0:07               ` Al Viro
  0 siblings, 1 reply; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-14 22:21 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 01:56:16AM +0400, Cyrill Gorcunov wrote:
> > >  struct file_operations {
> > >  	struct module *owner;
> > > +	struct seq_operations *fdinfo_ops;
> > 
> > IDGI.  Why on the earth do you need the whole iterator?  All it takes
> > is show_fdinfo(struct seq_file *m, struct file *f); have ->show() in
> > your iterator (one going through the files) call that sucker for the
> > file we are trying to show.
> > 
> > I think you are severely overdesigning that thing...
> 
> Hmm, in very first versions I've been using one ->show method, but
> then I thought that this is not very correlate with seq-files idea
> where for each record show/next sequence is called. I'll update (this
> for sure will make code simplier, and I'll have to check for seq-file
> overflow after seq_printf call to not continue printing data for too
> long if buffer already out of space).

Al, I'll cook the whole series tomorrow and resend it for review,
also I guess the new show_fdinfo() member in file-operations should
be guarded with CONFIG_PROC_FS, right?

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-14 22:21             ` Cyrill Gorcunov
@ 2012-08-15  0:07               ` Al Viro
  2012-08-15  7:40                 ` Cyrill Gorcunov
  0 siblings, 1 reply; 30+ messages in thread
From: Al Viro @ 2012-08-15  0:07 UTC (permalink / raw)
  To: Cyrill Gorcunov
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 02:21:47AM +0400, Cyrill Gorcunov wrote:
> > Hmm, in very first versions I've been using one ->show method, but
> > then I thought that this is not very correlate with seq-files idea
> > where for each record show/next sequence is called. I'll update (this
> > for sure will make code simplier, and I'll have to check for seq-file
> > overflow after seq_printf call to not continue printing data for too
> > long if buffer already out of space).
> 
> Al, I'll cook the whole series tomorrow and resend it for review,
> also I guess the new show_fdinfo() member in file-operations should
> be guarded with CONFIG_PROC_FS, right?

I seriously doubt that it's worth bothering.  If somebody cares, they
can add making it conditional later.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15  0:07               ` Al Viro
@ 2012-08-15  7:40                 ` Cyrill Gorcunov
  0 siblings, 0 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-15  7:40 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 01:07:03AM +0100, Al Viro wrote:
> On Wed, Aug 15, 2012 at 02:21:47AM +0400, Cyrill Gorcunov wrote:
> > > Hmm, in very first versions I've been using one ->show method, but
> > > then I thought that this is not very correlate with seq-files idea
> > > where for each record show/next sequence is called. I'll update (this
> > > for sure will make code simplier, and I'll have to check for seq-file
> > > overflow after seq_printf call to not continue printing data for too
> > > long if buffer already out of space).
> > 
> > Al, I'll cook the whole series tomorrow and resend it for review,
> > also I guess the new show_fdinfo() member in file-operations should
> > be guarded with CONFIG_PROC_FS, right?
> 
> I seriously doubt that it's worth bothering.  If somebody cares, they
> can add making it conditional later.

That's what I've beed testing, does it looks good for you?
---
From: Cyrill Gorcunov <gorcunov@openvz.org>
Subject: procfs: Add ability to plug in auxiliary fdinfo providers

This patch brings ability to print out auxiliary data associated
with file in procfs interface /proc/pid/fdinfo/fd.

Inparticular further patches make eventfd, evenpoll, signalfd
and fsnotify to print additional information complete enough
to restore these objects after checkpoint.

To simplify the code we add show_fdinfo callback into
struct file_operations (as Al proposed).

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/proc/fd.c       |   51 ++++++++++++++++++++++++++++++++++++---------------
 include/linux/fs.h |    3 +++
 2 files changed, 39 insertions(+), 15 deletions(-)

Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -15,11 +15,11 @@
 #include "fd.h"
 
 struct proc_fdinfo {
-	loff_t	f_pos;
-	int	f_flags;
+	struct file	*f_file;
+	int		f_flags;
 };
 
-static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
+static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct file **f_file, struct path *path)
 {
 	struct files_struct *files = NULL;
 	struct task_struct *task;
@@ -49,6 +49,10 @@ static int fdinfo_open_helper(struct ino
 				*path = fd_file->f_path;
 				path_get(&fd_file->f_path);
 			}
+			if (f_file) {
+				*f_file = fd_file;
+				get_file(fd_file);
+			}
 			ret = 0;
 		}
 		spin_unlock(&files->file_lock);
@@ -61,28 +65,44 @@ static int fdinfo_open_helper(struct ino
 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;
+	int ret;
+
+	ret = seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
+			 (long long)fdinfo->f_file->f_pos,
+			 fdinfo->f_flags);
+
+	if (!ret && fdinfo->f_file->f_op->show_fdinfo)
+		ret = fdinfo->f_file->f_op->show_fdinfo(m, fdinfo->f_file);
+
+	return ret;
 }
 
 static int seq_fdinfo_open(struct inode *inode, struct file *file)
 {
-	struct proc_fdinfo *fdinfo = NULL;
-	int ret = -ENOENT;
+	struct proc_fdinfo *fdinfo;
+	struct seq_file *m;
+	int ret;
 
 	fdinfo = kzalloc(sizeof(*fdinfo), GFP_KERNEL);
 	if (!fdinfo)
 		return -ENOMEM;
 
-	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, NULL);
-	if (!ret) {
-		ret = single_open(file, seq_show, fdinfo);
-		if (!ret)
-			fdinfo = NULL;
+	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, &fdinfo->f_file, NULL);
+	if (ret)
+		goto err_free;
+
+	ret = single_open(file, seq_show, fdinfo);
+	if (ret) {
+		put_filp(fdinfo->f_file);
+		goto err_free;
 	}
 
+	m = file->private_data;
+	m->private = fdinfo;
+
+	return ret;
+
+err_free:
 	kfree(fdinfo);
 	return ret;
 }
@@ -92,6 +112,7 @@ static int seq_fdinfo_release(struct ino
 	struct seq_file *m = file->private_data;
 	struct proc_fdinfo *fdinfo = m->private;
 
+	put_filp(fdinfo->f_file);
 	kfree(fdinfo);
 
 	return single_release(inode, file);
@@ -173,7 +194,7 @@ static const struct dentry_operations ti
 
 static int proc_fd_link(struct dentry *dentry, struct path *path)
 {
-	return fdinfo_open_helper(dentry->d_inode, NULL, path);
+	return fdinfo_open_helper(dentry->d_inode, NULL, NULL, path);
 }
 
 static struct dentry *
Index: linux-2.6.git/include/linux/fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/fs.h
+++ linux-2.6.git/include/linux/fs.h
@@ -1775,6 +1775,8 @@ struct block_device_operations;
 #define HAVE_COMPAT_IOCTL 1
 #define HAVE_UNLOCKED_IOCTL 1
 
+struct seq_file;
+
 struct file_operations {
 	struct module *owner;
 	loff_t (*llseek) (struct file *, loff_t, int);
@@ -1803,6 +1805,7 @@ struct file_operations {
 	int (*setlease)(struct file *, long, struct file_lock **);
 	long (*fallocate)(struct file *file, int mode, loff_t offset,
 			  loff_t len);
+	int (*show_fdinfo)(struct seq_file *m, struct file *f);
 };
 
 struct inode_operations {

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15 21:29   ` Al Viro
  2012-08-15 21:34     ` Cyrill Gorcunov
@ 2012-08-16 10:58     ` Cyrill Gorcunov
  1 sibling, 0 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-16 10:58 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 10:29:27PM +0100, Al Viro wrote:
> This, BTW, is too convoluted for its own good.  What you need is
> something like
> struct whatever {
> 	struct seq_file *m;
> 	struct file *f;
> 	int flags;
> };
> with single allocation of that sucker in your ->open().  Set
> file->private_data to address of seq_file field in your object *before*
> calling seq_open() and don't bother with m->private at all - just use
> container_of(m, struct whatever, m) in your ->show() to get to that
> structure...

Al, does the version below looks better? (Since it's harder to review diff,
here is the code after the patch applied).
---
struct proc_fdinfo {
	struct seq_file		m;
	struct file		*fd_file;
	int			f_flags;
};

static int seq_show(struct seq_file *m, void *v)
{
	struct proc_fdinfo *fdinfo = container_of(m, struct proc_fdinfo, m);
	seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
		   (long long)fdinfo->fd_file->f_pos, fdinfo->f_flags);
	return 0;
}

static int seq_fdinfo_open(struct inode *inode, struct file *file)
{
	struct proc_fdinfo *fdinfo = NULL;
	struct files_struct *files = NULL;
	struct task_struct *task;
	struct file *fd_file;
	int f_flags, ret;

	ret = -ENOENT;

	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);
		fd_file = fcheck_files(files, fd);
		if (fd_file) {
			struct fdtable *fdt = files_fdtable(files);

			f_flags = fd_file->f_flags & ~O_CLOEXEC;
			if (close_on_exec(fd, fdt))
				f_flags |= O_CLOEXEC;

			get_file(fd_file);
			ret = 0;
		}
		spin_unlock(&files->file_lock);

		put_files_struct(files);
	}

	if (ret)
		return ret;

	ret = -ENOMEM;
	fdinfo = kmalloc(sizeof(*fdinfo), GFP_KERNEL);
	if (!fdinfo)
		goto err_put;

	fdinfo->fd_file = fd_file;
	fdinfo->f_flags = f_flags;
	file->private_data = &fdinfo->m;

	ret = single_open(file, seq_show, NULL);
	if (ret)
		goto err_free;

	return 0;

err_free:
	kfree(fdinfo);
err_put:
	fput(fd_file);
	return ret;
}

static int seq_fdinfo_release(struct inode *inode, struct file *file)
{
	struct proc_fdinfo *fdinfo =
		container_of((struct seq_file *)file->private_data,
			     struct proc_fdinfo, m);
	fput(fdinfo->fd_file);
	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,
};
---
From: Cyrill Gorcunov <gorcunov@openvz.org>
Subject: procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file v2

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

Note the proc_fd_link no longer call for proc_fd_info, simply because
proc_fd_info is converted to seq_fdinfo_open (which is seq-file open()
prototype).

v2 (by Al Viro):
 - Don't use helper function with optional arguments, thus proc_fd_info get deprecated
 - Use proc_fdinfo structure with seq_file embedded, thus we can use container_of helper
 - Use fput to free reference to the file we've grabbed

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/proc/fd.c |  145 ++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 99 insertions(+), 46 deletions(-)

Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -6,61 +6,105 @@
 #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 {
+	struct seq_file		m;
+	struct file		*fd_file;
+	int			f_flags;
+};
+
+static int seq_show(struct seq_file *m, void *v)
+{
+	struct proc_fdinfo *fdinfo = container_of(m, struct proc_fdinfo, m);
+	seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
+		   (long long)fdinfo->fd_file->f_pos, fdinfo->f_flags);
+	return 0;
+}
 
-static int proc_fd_info(struct inode *inode, struct path *path, char *info)
+static int seq_fdinfo_open(struct inode *inode, struct file *file)
 {
-	struct task_struct *task = get_proc_task(inode);
+	struct proc_fdinfo *fdinfo = NULL;
 	struct files_struct *files = NULL;
-	int fd = proc_fd(inode);
-	struct file *file;
+	struct task_struct *task;
+	struct file *fd_file;
+	int f_flags, ret;
 
+	ret = -ENOENT;
+
+	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.
-		 */
+		int fd = proc_fd(inode);
+
 		spin_lock(&files->file_lock);
-		file = fcheck_files(files, fd);
-		if (file) {
-			unsigned int f_flags;
-			struct fdtable *fdt;
+		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;
+			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;
+			get_file(fd_file);
+			ret = 0;
 		}
 		spin_unlock(&files->file_lock);
+
 		put_files_struct(files);
 	}
-	return -ENOENT;
+
+	if (ret)
+		return ret;
+
+	ret = -ENOMEM;
+	fdinfo = kmalloc(sizeof(*fdinfo), GFP_KERNEL);
+	if (!fdinfo)
+		goto err_put;
+
+	fdinfo->fd_file = fd_file;
+	fdinfo->f_flags = f_flags;
+	file->private_data = &fdinfo->m;
+
+	ret = single_open(file, seq_show, NULL);
+	if (ret)
+		goto err_free;
+
+	return 0;
+
+err_free:
+	kfree(fdinfo);
+err_put:
+	fput(fd_file);
+	return ret;
 }
 
+static int seq_fdinfo_release(struct inode *inode, struct file *file)
+{
+	struct proc_fdinfo *fdinfo =
+		container_of((struct seq_file *)file->private_data,
+			     struct proc_fdinfo, m);
+	fput(fdinfo->fd_file);
+	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, unsigned int flags)
 {
 	struct files_struct *files;
@@ -130,7 +174,32 @@ 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 files_struct *files = NULL;
+	struct task_struct *task;
+	int ret = -ENOENT;
+
+	task = get_proc_task(dentry->d_inode);
+	if (task) {
+		files = get_files_struct(task);
+		put_task_struct(task);
+	}
+
+	if (files) {
+		int fd = proc_fd(dentry->d_inode);
+		struct file *fd_file;
+
+		spin_lock(&files->file_lock);
+		fd_file = fcheck_files(files, fd);
+		if (fd_file) {
+			*path = fd_file->f_path;
+			path_get(&fd_file->f_path);
+			ret = 0;
+		}
+		spin_unlock(&files->file_lock);
+		put_files_struct(files);
+	}
+
+	return ret;
 }
 
 static struct dentry *
@@ -245,22 +314,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);

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15 21:29   ` Al Viro
@ 2012-08-15 21:34     ` Cyrill Gorcunov
  2012-08-16 10:58     ` Cyrill Gorcunov
  1 sibling, 0 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-15 21:34 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 10:29:27PM +0100, Al Viro wrote:
> 
> This, BTW, is too convoluted for its own good.  What you need is
> something like
> struct whatever {
> 	struct seq_file *m;
> 	struct file *f;
> 	int flags;
> };
> with single allocation of that sucker in your ->open().  Set
> file->private_data to address of seq_file field in your object *before*
> calling seq_open() and don't bother with m->private at all - just use
> container_of(m, struct whatever, m) in your ->show() to get to that
> structure...

I will try and post results, thanks!

	Cyrill

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15 21:16   ` Al Viro
@ 2012-08-15 21:31     ` Cyrill Gorcunov
  0 siblings, 0 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-15 21:31 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 10:16:28PM +0100, Al Viro wrote:
> On Wed, Aug 15, 2012 at 01:21:19PM +0400, Cyrill Gorcunov wrote:
> > -static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
> > +static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct file **f_file, struct path *path)
> 
> Bloody bad taste, that...  This kind of optional arguments is almost always
> a bad sign - tends to happen when you have two barely related functions
> crammed into one.  And yes, proc_fd_info() suffers the same braindamage.
> Trying to avoid code duplication is generally a good thing, but it's not
> always worth doing - less obfuscated code wins.

Sure I'll update. Thanks.

> >  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;
> > +	int ret;
> > +
> > +	ret = seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
> > +			 (long long)fdinfo->f_file->f_pos,
> > +			 fdinfo->f_flags);
> 
> Realistically, that one is not going to overflow; you are almost certainly
> wasting more cycles on that check of !ret just below than you'll save on
> not going into ->show_fdinfo() in case of full buffer.

Yes, this is redundant, thanks. Will fix.

> 
> > +	if (!ret && fdinfo->f_file->f_op->show_fdinfo)
> > +		ret = fdinfo->f_file->f_op->show_fdinfo(m, fdinfo->f_file);
> > +
> > +	return ret;
> >  }
>   
> > +	ret = single_open(file, seq_show, fdinfo);
> > +	if (ret) {
> > +		put_filp(fdinfo->f_file);
> 
> Excuse me?  We should *never* do put_filp() on anything that has already
> been opened.  Think what happens if you race with close(); close() would
> rip the reference from descriptor table and do fput(), leaving you with
> the last reference to that struct file.  You really don't want to just
> go and free it.  IOW, that one should be fput().
> 
> > +	put_filp(fdinfo->f_file);
> Ditto. 

It seems I indeed missed this scenario, thanks Al, will update!

	Cyrill

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15  9:21 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
  2012-08-15 21:16   ` Al Viro
@ 2012-08-15 21:29   ` Al Viro
  2012-08-15 21:34     ` Cyrill Gorcunov
  2012-08-16 10:58     ` Cyrill Gorcunov
  1 sibling, 2 replies; 30+ messages in thread
From: Al Viro @ 2012-08-15 21:29 UTC (permalink / raw)
  To: Cyrill Gorcunov
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 01:21:19PM +0400, Cyrill Gorcunov wrote:
>  struct proc_fdinfo {
> -	loff_t	f_pos;
> -	int	f_flags;
> +	struct file	*f_file;
> +	int		f_flags;
>  };

> +	struct proc_fdinfo *fdinfo;
> +	struct seq_file *m;
> +	int ret;
>  
>  	fdinfo = kzalloc(sizeof(*fdinfo), GFP_KERNEL);
>  	if (!fdinfo)
>  		return -ENOMEM;

> +	ret = single_open(file, seq_show, fdinfo);
> +	if (ret) {
> +		put_filp(fdinfo->f_file);
> +		goto err_free;
>  	}
>  
> +	m = file->private_data;
> +	m->private = fdinfo;

This, BTW, is too convoluted for its own good.  What you need is
something like
struct whatever {
	struct seq_file *m;
	struct file *f;
	int flags;
};
with single allocation of that sucker in your ->open().  Set
file->private_data to address of seq_file field in your object *before*
calling seq_open() and don't bother with m->private at all - just use
container_of(m, struct whatever, m) in your ->show() to get to that
structure...

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15  9:21 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
@ 2012-08-15 21:16   ` Al Viro
  2012-08-15 21:31     ` Cyrill Gorcunov
  2012-08-15 21:29   ` Al Viro
  1 sibling, 1 reply; 30+ messages in thread
From: Al Viro @ 2012-08-15 21:16 UTC (permalink / raw)
  To: Cyrill Gorcunov
  Cc: linux-kernel, linux-fsdevel, Alexey Dobriyan, Andrew Morton,
	Pavel Emelyanov, James Bottomley, Matthew Helsley

On Wed, Aug 15, 2012 at 01:21:19PM +0400, Cyrill Gorcunov wrote:
> -static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
> +static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct file **f_file, struct path *path)

Bloody bad taste, that...  This kind of optional arguments is almost always
a bad sign - tends to happen when you have two barely related functions
crammed into one.  And yes, proc_fd_info() suffers the same braindamage.
Trying to avoid code duplication is generally a good thing, but it's not
always worth doing - less obfuscated code wins.

>  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;
> +	int ret;
> +
> +	ret = seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
> +			 (long long)fdinfo->f_file->f_pos,
> +			 fdinfo->f_flags);

Realistically, that one is not going to overflow; you are almost certainly
wasting more cycles on that check of !ret just below than you'll save on
not going into ->show_fdinfo() in case of full buffer.

> +	if (!ret && fdinfo->f_file->f_op->show_fdinfo)
> +		ret = fdinfo->f_file->f_op->show_fdinfo(m, fdinfo->f_file);
> +
> +	return ret;
>  }
  
> +	ret = single_open(file, seq_show, fdinfo);
> +	if (ret) {
> +		put_filp(fdinfo->f_file);

Excuse me?  We should *never* do put_filp() on anything that has already
been opened.  Think what happens if you race with close(); close() would
rip the reference from descriptor table and do fput(), leaving you with
the last reference to that struct file.  You really don't want to just
go and free it.  IOW, that one should be fput().

> +	put_filp(fdinfo->f_file);
Ditto.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers
  2012-08-15  9:21 [patch 0/8] procfs, fdinfo updated Cyrill Gorcunov
@ 2012-08-15  9:21 ` Cyrill Gorcunov
  2012-08-15 21:16   ` Al Viro
  2012-08-15 21:29   ` Al Viro
  0 siblings, 2 replies; 30+ messages in thread
From: Cyrill Gorcunov @ 2012-08-15  9:21 UTC (permalink / raw)
  To: linux-kernel, linux-fsdevel
  Cc: Al Viro, Alexey Dobriyan, Andrew Morton, Pavel Emelyanov,
	James Bottomley, Matthew Helsley, Cyrill Gorcunov, Al Viro

[-- Attachment #1: seq-fdinfo-seq-ops-helpers-10 --]
[-- Type: text/plain, Size: 4175 bytes --]

This patch brings ability to print out auxiliary data associated
with file in procfs interface /proc/pid/fdinfo/fd.

In particular further patches make eventfd, evenpoll, signalfd
and fsnotify to print additional information complete enough
to restore these objects after checkpoint.

To simplify the code we add show_fdinfo callback inside
struct file_operations (as Al proposed and Pavel are proposing).

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: James Bottomley <jbottomley@parallels.com>
---
 fs/proc/fd.c       |   51 ++++++++++++++++++++++++++++++++++++---------------
 include/linux/fs.h |    3 +++
 2 files changed, 39 insertions(+), 15 deletions(-)

Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -15,11 +15,11 @@
 #include "fd.h"
 
 struct proc_fdinfo {
-	loff_t	f_pos;
-	int	f_flags;
+	struct file	*f_file;
+	int		f_flags;
 };
 
-static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct path *path)
+static int fdinfo_open_helper(struct inode *inode, int *f_flags, struct file **f_file, struct path *path)
 {
 	struct files_struct *files = NULL;
 	struct task_struct *task;
@@ -49,6 +49,10 @@ static int fdinfo_open_helper(struct ino
 				*path = fd_file->f_path;
 				path_get(&fd_file->f_path);
 			}
+			if (f_file) {
+				*f_file = fd_file;
+				get_file(fd_file);
+			}
 			ret = 0;
 		}
 		spin_unlock(&files->file_lock);
@@ -61,28 +65,44 @@ static int fdinfo_open_helper(struct ino
 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;
+	int ret;
+
+	ret = seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
+			 (long long)fdinfo->f_file->f_pos,
+			 fdinfo->f_flags);
+
+	if (!ret && fdinfo->f_file->f_op->show_fdinfo)
+		ret = fdinfo->f_file->f_op->show_fdinfo(m, fdinfo->f_file);
+
+	return ret;
 }
 
 static int seq_fdinfo_open(struct inode *inode, struct file *file)
 {
-	struct proc_fdinfo *fdinfo = NULL;
-	int ret = -ENOENT;
+	struct proc_fdinfo *fdinfo;
+	struct seq_file *m;
+	int ret;
 
 	fdinfo = kzalloc(sizeof(*fdinfo), GFP_KERNEL);
 	if (!fdinfo)
 		return -ENOMEM;
 
-	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, NULL);
-	if (!ret) {
-		ret = single_open(file, seq_show, fdinfo);
-		if (!ret)
-			fdinfo = NULL;
+	ret = fdinfo_open_helper(inode, &fdinfo->f_flags, &fdinfo->f_file, NULL);
+	if (ret)
+		goto err_free;
+
+	ret = single_open(file, seq_show, fdinfo);
+	if (ret) {
+		put_filp(fdinfo->f_file);
+		goto err_free;
 	}
 
+	m = file->private_data;
+	m->private = fdinfo;
+
+	return ret;
+
+err_free:
 	kfree(fdinfo);
 	return ret;
 }
@@ -92,6 +112,7 @@ static int seq_fdinfo_release(struct ino
 	struct seq_file *m = file->private_data;
 	struct proc_fdinfo *fdinfo = m->private;
 
+	put_filp(fdinfo->f_file);
 	kfree(fdinfo);
 
 	return single_release(inode, file);
@@ -173,7 +194,7 @@ static const struct dentry_operations ti
 
 static int proc_fd_link(struct dentry *dentry, struct path *path)
 {
-	return fdinfo_open_helper(dentry->d_inode, NULL, path);
+	return fdinfo_open_helper(dentry->d_inode, NULL, NULL, path);
 }
 
 static struct dentry *
Index: linux-2.6.git/include/linux/fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/fs.h
+++ linux-2.6.git/include/linux/fs.h
@@ -1775,6 +1775,8 @@ struct block_device_operations;
 #define HAVE_COMPAT_IOCTL 1
 #define HAVE_UNLOCKED_IOCTL 1
 
+struct seq_file;
+
 struct file_operations {
 	struct module *owner;
 	loff_t (*llseek) (struct file *, loff_t, int);
@@ -1803,6 +1805,7 @@ struct file_operations {
 	int (*setlease)(struct file *, long, struct file_lock **);
 	long (*fallocate)(struct file *file, int mode, loff_t offset,
 			  loff_t len);
+	int (*show_fdinfo)(struct seq_file *m, struct file *f);
 };
 
 struct inode_operations {


^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2012-08-16 10:58 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-14 14:03 [patch 0/8] procfs fdinfo providers updated Cyrill Gorcunov
2012-08-14 14:03 ` [patch 1/8] procfs: Move /proc/pid/fd[info] handling code to fd.[ch] Cyrill Gorcunov
2012-08-14 14:21   ` Pavel Emelyanov
2012-08-14 14:03 ` [patch 2/8] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file Cyrill Gorcunov
2012-08-14 14:21   ` Pavel Emelyanov
2012-08-14 14:03 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
2012-08-14 14:22   ` Pavel Emelyanov
2012-08-14 18:31   ` Al Viro
2012-08-14 18:35     ` Cyrill Gorcunov
2012-08-14 19:56       ` Cyrill Gorcunov
2012-08-14 21:27         ` Al Viro
2012-08-14 21:56           ` Cyrill Gorcunov
2012-08-14 22:21             ` Cyrill Gorcunov
2012-08-15  0:07               ` Al Viro
2012-08-15  7:40                 ` Cyrill Gorcunov
2012-08-14 14:03 ` [patch 4/8] fs, eventfd: Add procfs fdinfo helper Cyrill Gorcunov
2012-08-14 14:22   ` Pavel Emelyanov
2012-08-14 14:03 ` [patch 5/8] fs, epoll: Add procfs fdinfo helper v2 Cyrill Gorcunov
2012-08-14 14:22   ` Pavel Emelyanov
2012-08-14 14:03 ` [patch 6/8] fs, exportfs: Add export_encode_inode_fh helper Cyrill Gorcunov
2012-08-14 14:23   ` Pavel Emelyanov
2012-08-14 14:03 ` [patch 7/8] fs, notify: Add procfs fdinfo helper v3 Cyrill Gorcunov
2012-08-14 14:23   ` Pavel Emelyanov
2012-08-14 14:03 ` [patch 8/8] fdinfo: Show sigmask for signalfd fd Cyrill Gorcunov
2012-08-15  9:21 [patch 0/8] procfs, fdinfo updated Cyrill Gorcunov
2012-08-15  9:21 ` [patch 3/8] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
2012-08-15 21:16   ` Al Viro
2012-08-15 21:31     ` Cyrill Gorcunov
2012-08-15 21:29   ` Al Viro
2012-08-15 21:34     ` Cyrill Gorcunov
2012-08-16 10:58     ` Cyrill Gorcunov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).