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に構造に基づいた物だと言う事です。