Skip to contentSkip to conversation

Probleam reading fdinfo symlinks after 30a08bf2d31d275c6fc71dd1811342777e95c831

DISCUSSION Cyrill Gorcunov 2 participants 3 messages Jun 4, 2012

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

Hi Linus,

just tried 3.5-rc1 out and found that with commit 30a08bf2d31d275c6fc71dd1811342777e95c831 the reading of fdinfo files returns "Too many levels of symbolic links" error.

| [root@neptune~]# cat /proc/pidof crond/fdinfo/0 | cat: /proc/1417/fdinfo/0: Too many levels of symbolic links

so I reverted it manually and now it works as expected

 | [root@neptune ~]# cat /proc/`pidof crond`/fdinfo/0
 | pos:	0
 | flags:	0100002

I suspect this is unintentional behaviour of the commit.

#1 lore raw
Quoted 5 lines · Cyrill Gorcunov

just tried 3.5-rc1 out and found that with commit 30a08bf2d31d275c6fc71dd1811342777e95c831 the reading of fdinfo files returns "Too many levels of symbolic links" error.

Ugh. The fdinfo files aren't symlinks at all, and share the revalidate function.

My bad. The fix isn't pretty, but still better than reverting things. This should fix it.

Linus

 fs/proc/base.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
fs/proc/base.c +10 -7
index 616f41a7cde6..437195f204e1 100644
@@ -1803,7 +1803,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 			rcu_read_lock();
 			file = fcheck_files(files, fd);
 			if (file) {
-				unsigned i_mode, f_mode = file->f_mode;
+				unsigned f_mode = file->f_mode;
 
 				rcu_read_unlock();
 				put_files_struct(files);
@@ -1819,12 +1819,14 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 					inode->i_gid = GLOBAL_ROOT_GID;
 				}
 
-				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;
+				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);
@@ -1859,6 +1861,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
 	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;
author Tested-by
#2 lore raw
Quoted 11 lines · Linus Torvalds
Quoted 5 lines · Cyrill Gorcunov

just tried 3.5-rc1 out and found that with commit 30a08bf2d31d275c6fc71dd1811342777e95c831 the reading of fdinfo files returns "Too many levels of symbolic links" error.

Ugh. The fdinfo files aren't symlinks at all, and share the revalidate function.

My bad. The fix isn't pretty, but still better than reverting things. This should fix it.

Thanks Linus! This patch fixed it.