socket
Rev.1を表示中。最新版はこちら。
sock_create()で、ソケットファイルシステムのスーパブロックからinodeおよびをsocketを取得し、sock_map_fd()でFILEを取得し、FILE IDにセットします。file->private_dataにはsockが設定されています。
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
int retval;
struct socket *sock;
int flags;
flags = type & ~SOCK_TYPE_MASK;
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
return -EINVAL;
type &= SOCK_TYPE_MASK;
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
retval = sock_create(family, type, protocol, &sock);
if (retval < 0)
goto out;
retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
if (retval < 0)
goto out_release;
out:
return retval;
out_release:
sock_release(sock);
return retval;
}
sock_create()は引数チェックして、sock_alloc()がコールし、ソケットファイルシステムのスーパブロックからinode/sockを取得します。percpu_add()は、CPU変数(CPU毎に割り当てている変数で、ロックすることなく参照できます。)のsockets_in_useをインクリメントします。これは/proc/net/sockstatのsockets: usedで参照されます。
static struct socket *sock_alloc(void)
{
struct inode *inode;
struct socket *sock;
inode = new_inode_pseudo(sock_mnt->mnt_sb);
if (!inode)
return NULL;
sock = SOCKET_I(inode);
kmemcheck_annotate_bitfield(sock, type);
inode->i_ino = get_next_ino();
inode->i_mode = S_IFSOCK | S_IRWXUGO;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
percpu_add(sockets_in_use, 1);
return sock;
}
int sock_map_fd(struct socket *sock, int flags)
{
struct file *newfile;
int fd = sock_alloc_file(sock, &newfile, flags);
if (likely(fd >= 0))
fd_install(fd, newfile);
return fd;
}
current->filesから空きのfdを取得し、alloc_file()でFILEを取得します。file->f_op = socket_file_opsとなりますが、以降file->f_pos = 0としてますので、ソケットに関してはfileでのread/writeはできないようです。
static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
{
struct qstr name = { .name = "" };
struct path path;
struct file *file;
int fd;
fd = get_unused_fd_flags(flags);
if (unlikely(fd < 0))
return fd;
path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
if (unlikely(!path.dentry)) {
put_unused_fd(fd);
return -ENOMEM;
}
path.mnt = mntget(sock_mnt);
d_instantiate(path.dentry, SOCK_INODE(sock));
SOCK_INODE(sock)->i_fop = &socket_file_ops;
file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
&socket_file_ops);
if (unlikely(!file)) {
/* drop dentry, keep inode */
ihold(path.dentry->d_inode);
path_put(&path);
put_unused_fd(fd);
return -ENFILE;
}
sock->file = file;
file->f_flags = O_RDWR | (flags & O_NONBLOCK);
file->f_pos = 0;
file->private_data = sock;
*f = file;
return fd;
}
struct file *alloc_file(struct path *path, fmode_t mode,
const struct file_operations *fop)
{
struct file *file;
file = get_empty_filp();
if (!file)
return NULL;
file->f_path = *path;
file->f_mapping = path->dentry->d_inode->i_mapping;
file->f_mode = mode;
file->f_op = fop;
if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) {
file_take_write(file);
WARN_ON(mnt_clone_write(path->mnt));
}
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_inc(path->dentry->d_inode);
return file;
}
補足
ファイルオペレーションコールバックは、参照位置をブロック位置に変換し、アドレスマップのコールバックをコールして実デバイス(キャッシュも含めた)とのやり取りを行う介添え的な役割となります。socketはfile->f_pos = 0と言うことで、FILEをread/writeする様に読み書きできないようですが、実装としてはvfsに構造に基づいた物だと言う事です。




