Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1162

kernel-2.6.18-238.el5.src.rpm

From: Jerome Marchand <jmarchan@redhat.com>
Date: Wed, 26 May 2010 14:59:53 -0400
Subject: [fs] proc: add file position and flags info in /proc
Message-id: <4BFD3769.9040102@redhat.com>
Patchwork-id: 25819
O-Subject: [RHEL5 PATCH] Add file position and flags infos in /proc
Bugzilla: 498081
RH-Acked-by: Amerigo Wang <amwang@redhat.com>

Bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=582672

Description:
Add entries /proc/<pid>/fdinfo/<fd> and /proc/<pid>/task/<tid>/fdinfo/<fd>
entries. They contains file position and flags information.

I also modified fake_ino() to ensure that pid-dir entries inode numbers
stay in their allocated range (0x0001xxxx-0x7fffxxxx) and avoid any
conflict with dynamic entries (range 0xf0000000-0xffffffff). There still
can be duplicate inodes among the pid-dir entries, but procfs does not
care about that.

Upstream status:
commit 2793274298c4423d79701e9a8190f2940bf3c785

Brew build:
https://brewweb.devel.redhat.com/taskinfo?taskID=2459711

Test status:
Built on all arch and tested by me on x86_64.

Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/fs/proc/base.c b/fs/proc/base.c
index bbc96b8..5581604 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -93,7 +93,16 @@
  * about magical ranges too.
  */
 
-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
+#define PROC_TID_DIR_MIN 0x00010000
+#define PROC_TID_DIR_PID_MAX 0x7FFF
+#define PROC_TID_DIR_INO_MAX 0xFFFF
+inline unsigned long fake_ino(pid_t pid, unsigned long ino)
+{
+	unsigned long res;
+	/* we want inode numbers in 0x0001000-0x7FFFFFFF*/
+	res = pid > PROC_TID_DIR_PID_MAX ? PROC_TID_DIR_MIN : pid << 16;
+	return res | (ino & PROC_TID_DIR_INO_MAX);
+}
 
 enum pid_directory_inos {
 	PROC_TGID_INO = 2,
@@ -192,6 +201,9 @@ enum pid_directory_inos {
 	PROC_TGID_IO,
 	PROC_TID_IO,
 #endif
+	PROC_TGID_FDINFO,
+	PROC_TID_FDINFO,
+
 	/* Add new entries before this */
 	PROC_TID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
@@ -211,6 +223,7 @@ struct pid_entry {
 static struct pid_entry tgid_base_stuff[] = {
 	E(PROC_TGID_TASK,      "task",    S_IFDIR|S_IRUGO|S_IXUGO),
 	E(PROC_TGID_FD,        "fd",      S_IFDIR|S_IRUSR|S_IXUSR),
+	E(PROC_TGID_FDINFO,    "fdinfo",  S_IFDIR|S_IRUSR|S_IXUSR),
 	E(PROC_TGID_ENVIRON,   "environ", S_IFREG|S_IRUSR),
 	E(PROC_TGID_AUXV,      "auxv",	  S_IFREG|S_IRUSR),
 	E(PROC_TGID_STATUS,    "status",  S_IFREG|S_IRUGO),
@@ -263,6 +276,7 @@ static struct pid_entry tgid_base_stuff[] = {
 };
 static struct pid_entry tid_base_stuff[] = {
 	E(PROC_TID_FD,         "fd",      S_IFDIR|S_IRUSR|S_IXUSR),
+	E(PROC_TID_FDINFO,     "fdinfo",  S_IFDIR|S_IRUSR|S_IXUSR),
 	E(PROC_TID_ENVIRON,    "environ", S_IFREG|S_IRUSR),
 	E(PROC_TID_AUXV,       "auxv",	  S_IFREG|S_IRUSR),
 	E(PROC_TID_STATUS,     "status",  S_IFREG|S_IRUGO),
@@ -332,7 +346,10 @@ static struct pid_entry tid_attr_stuff[] = {
 
 #undef E
 
-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+#define PROC_FDINFO_MAX 64
+
+static int proc_fd_info(struct inode *inode, struct dentry **dentry,
+			struct vfsmount **mnt, char *info)
 {
 	struct task_struct *task = get_proc_task(inode);
 	struct files_struct *files = NULL;
@@ -351,8 +368,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
 		spin_lock(&files->file_lock);
 		file = fcheck_files(files, fd);
 		if (file) {
-			*mnt = mntget(file->f_vfsmnt);
-			*dentry = dget(file->f_dentry);
+			if (mnt)
+				*mnt = mntget(file->f_vfsmnt);
+			if (dentry)
+				*dentry = dget(file->f_dentry);
+			if (info)
+				snprintf(info, PROC_FDINFO_MAX,
+					 "pos:\t%lli\n"
+					 "flags:\t0%o\n",
+					 (long long) file->f_pos,
+					 file->f_flags);
 			spin_unlock(&files->file_lock);
 			put_files_struct(files);
 			return 0;
@@ -363,6 +388,27 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
 	return -ENOENT;
 }
 
+static int proc_fd_link(struct inode *inode, struct dentry **dentry,
+			struct vfsmount **mnt)
+{
+	return proc_fd_info(inode, dentry, mnt, NULL);
+}
+
+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_dentry->d_inode, NULL, 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,
+};
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
 	struct fs_struct *fs;
@@ -1422,7 +1468,8 @@ static struct inode_operations proc_pid_link_inode_operations = {
 	.setattr	= proc_setattr,
 };
 
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+static int proc_readfd_common(struct file *filp, void *dirent,
+			      filldir_t filldir, unsigned int d_type)
 {
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
@@ -1474,7 +1521,8 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 				} while (i);
 
 				ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
-				if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
+				if (filldir(dirent, buf+j, PROC_NUMBUF-j,
+					    fd+2, ino, d_type) < 0) {
 					rcu_read_lock();
 					break;
 				}
@@ -1489,6 +1537,16 @@ out_no_task:
 	return retval;
 }
 
+static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
+{
+	return proc_readfd_common(filp, dirent, filldir, DT_LNK);
+}
+
+static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
+{
+	return proc_readfd_common(filp, dirent, filldir, DT_REG);
+}
+
 static int proc_pident_readdir(struct file *filp,
 		void *dirent, filldir_t filldir,
 		struct pid_entry *ents, unsigned int nents)
@@ -1759,7 +1817,9 @@ out:
 }
 
 /* SMP-safe */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_lookupfd_common(struct inode *dir,
+					   struct dentry *dentry,
+					   struct nameidata *nd, int type)
 {
 	struct task_struct *task = get_proc_task(dir);
 	unsigned fd = name_to_int(dentry);
@@ -1779,33 +1839,46 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
 		goto out;
 	ei = PROC_I(inode);
 	ei->fd = fd;
-	files = get_files_struct(task);
-	if (!files)
-		goto out_unlock;
-	inode->i_mode = S_IFLNK;
+	switch (type) {
+	case PROC_TID_FDINFO:
+		inode->i_mode = S_IFREG | S_IRUSR;
+		inode->i_fop = &proc_fdinfo_file_operations;
+		dentry->d_op = &tid_fd_dentry_operations;
+		break;
+	case PROC_TID_FD:
+		files = get_files_struct(task);
+		if (!files)
+			goto out_unlock;
+		inode->i_mode = S_IFLNK;
+
+		/*
+		 * 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)
+			goto out_unlock2;
+		if (file->f_mode & 1)
+			inode->i_mode |= S_IRUSR | S_IXUSR;
+		if (file->f_mode & 2)
+			inode->i_mode |= S_IWUSR | S_IXUSR;
+		spin_unlock(&files->file_lock);
+		put_files_struct(files);
+		inode->i_op = &proc_pid_link_inode_operations;
+		inode->i_size = 64;
+		ei->op.proc_get_link = proc_fd_link;
+		dentry->d_op = &tid_fd_dentry_operations;
+		break;
+	default:
+		BUG();
+	}
 
-	/*
-	 * 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)
-		goto out_unlock2;
-	if (file->f_mode & 1)
-		inode->i_mode |= S_IRUSR | S_IXUSR;
-	if (file->f_mode & 2)
-		inode->i_mode |= S_IWUSR | S_IXUSR;
-	spin_unlock(&files->file_lock);
-	put_files_struct(files);
-	inode->i_op = &proc_pid_link_inode_operations;
-	inode->i_size = 64;
-	ei->op.proc_get_link = proc_fd_link;
-	dentry->d_op = &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, NULL))
 		result = NULL;
+
 out:
 	put_task_struct(task);
 out_no_task:
@@ -1819,10 +1892,36 @@ out_unlock:
 	goto out;
 }
 
+static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
+				    struct nameidata *nd)
+{
+	return proc_lookupfd_common(dir, dentry, nd, PROC_TID_FD);
+}
+
+static struct dentry *proc_lookupfdinfo(struct inode *dir,
+					struct dentry *dentry,
+					struct nameidata *nd)
+{
+	return proc_lookupfd_common(dir, dentry, nd, PROC_TID_FDINFO);
+}
+
 static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd);
 static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
 
+static const struct file_operations proc_fdinfo_operations = {
+	.read		= generic_read_dir,
+	.readdir	= proc_readfdinfo,
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+static struct inode_operations proc_fdinfo_inode_operations = {
+	.lookup		= proc_lookupfdinfo,
+	.setattr	= proc_setattr,
+};
+
 static struct file_operations proc_fd_operations = {
 	.read		= generic_read_dir,
 	.readdir	= proc_readfd,
@@ -1976,6 +2075,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
 			inode->i_op = &proc_fd_inode_operations;
 			inode->i_fop = &proc_fd_operations;
 			break;
+		case PROC_TID_FDINFO:
+		case PROC_TGID_FDINFO:
+			inode->i_nlink = 2;
+			inode->i_op = &proc_fdinfo_inode_operations;
+			inode->i_fop = &proc_fdinfo_operations;
+			break;
 		case PROC_TID_EXE:
 		case PROC_TGID_EXE:
 			inode->i_op = &proc_pid_link_inode_operations;
@@ -2370,9 +2475,9 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
 	inode->i_fop = &proc_tgid_base_operations;
 	inode->i_flags|=S_IMMUTABLE;
 #ifdef CONFIG_SECURITY
-	inode->i_nlink = 5;
+	inode->i_nlink = 6;
 #else
-	inode->i_nlink = 4;
+	inode->i_nlink = 5;
 #endif
 
 	dentry->d_op = &pid_dentry_operations;
@@ -2424,9 +2529,9 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
 	inode->i_fop = &proc_tid_base_operations;
 	inode->i_flags|=S_IMMUTABLE;
 #ifdef CONFIG_SECURITY
-	inode->i_nlink = 4;
+	inode->i_nlink = 5;
 #else
-	inode->i_nlink = 3;
+	inode->i_nlink = 4;
 #endif
 
 	dentry->d_op = &pid_dentry_operations;