Skip to contentSkip to conversation

Polling on sockets in kernel space and struct file

DISCUSSION Martin Sustrik 3 participants 3 messages Dec 8, 2010

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

Hi all,

As part of implementing a new experimental protocol family, we are trying to create a socket in kernel. This seems to be easy, just use sock_create_kern(). However, the socket returned by this function does not have associated file structure; thus it cannot be polled on using poll_initwait() and friends.

We have tried to create the appropriate struct file using sock_map_fd(), but this has two problems:

1) We do not want our internal socket to be visible in the process context, i.e. it should not have a file descriptor.

2) During process exit, we get a kernel BUG from iput() in fs/inode.c:1260.

We then tried another approach using anon_inode_getfile() to get a struct file, but this still produces the problem 2) above.

Any help/advice on how to proceed would be appreciated; for reference our work in progress can be seen at

http://github.com/sustrik/linux-2.6/blob/sp-v2.6.36/net/sp/af_sp.c

Thanks,

Martin

#1 lore raw
Quoted 11 lines · Martin Sustrik

Hi all,

As part of implementing a new experimental protocol family, we are trying to create a socket in kernel. This seems to be easy, just use sock_create_kern(). However, the socket returned by this function does not have associated file structure; thus it cannot be polled on using poll_initwait() and friends.

We have tried to create the appropriate struct file using sock_map_fd(), but this has two problems:

Quoted 8 lines

1) We do not want our internal socket to be visible in the process context, i.e. it should not have a file descriptor.

2) During process exit, we get a kernel BUG from iput() in fs/inode.c:1260.

you could call sock_map_fd() then :

	int fd = sock_map_fd(sock, flags);
	struct file *file = NULL;

	if (fd != -1) {
		file = fget(fd);
		sys_close(fd);  /* still racy */
	}

	if (file) ...

Take a look at net/9p/trans_fd.c

Quoted 7 lines

We then tried another approach using anon_inode_getfile() to get a struct file, but this still produces the problem 2) above.

Any help/advice on how to proceed would be appreciated; for reference our work in progress can be seen at

http://github.com/sustrik/linux-2.6/blob/sp-v2.6.36/net/sp/af_sp.c

#2 lore raw

Hi Eric,

oddly enough our BUG at fs/inode.c seems to have gone away; may be a race of some sort...

Quoted 13 lines

you could call sock_map_fd() then :

	int fd = sock_map_fd(sock, flags);
	struct file *file = NULL;

	if (fd != -1) {
		file = fget(fd);
		sys_close(fd);  /* still racy */
	}

	if (file) ...
Quoted 1 line

Take a look at net/9p/trans_fd.c

Interesting approach.

We're currently doing the following -- we add this function to net/socket.c:

int sock_map_anon(struct socket *sock, const char *name, int flags)

{
	struct file *newfile;
	
	newfile = anon_inode_getfile(name, &socket_file_ops, sock, flags);
	sock->file = newfile;
	return 0;
}

and then call it instead of sock_map_fd() from our sock_create():

	/* Create peer socket and associated file structure */
	rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sp->peer);
	if (rc < 0)
		goto out;
	rc = sock_map_anon(sp->peer, "[sp]", 0);
	if (rc < 0)
		goto out_release;

Is this a valid approach to achieve the same thing?

It's not clear what, if anything special we need to do to correctly release the anonymous inode when we are releasing our socket... is sock_release(sp->peer) sufficient?

Also, I see in 9p/trans_fd.c that it's using get_file() to increment the file refcount; do we need to do this for all sockets/files we create in kernel space or is this only for the sys_close() hack?

Thanks,

-mato