Linuxとかカーネル方面のYoutubeチャンネル

Linuxとかカーネル方面のYoutubeチャンネルをめも

hupstream

Kernel Recipesというタイトルのシリーズがカーネルの濃い発表動画。

www.youtube.com

KVM Forum

KVMQEMUなど。

www.youtube.com

The Linux Foundation

色んなカンファレンス動画がある。

www.youtube.com

USENIX

色んなカンファレンス動画がある。

www.youtube.com

Fedora Project

Flockが開発者・ユーザーがあつまるイベントでディストリビューションの開発に関するネタが多い。

www.youtube.com

DebConf Videos

Debianのカンファレンス。

www.youtube.com

FOSDEM

FOSDEM(Free and Open Source Development European Meeting)。ヨーロッパで行われてるOSS系のイベント。

www.youtube.com

BSDCan

BSD!

www.youtube.com

bsdconferences

BSD系のカンファレンスはこちらが多いか。

www.youtube.com

netdevconf

Linuxのネットワーク系カンファレンス。  NetDev: The Technical Conference On Linux Networking

www.youtube.com

linux: カーネルからioctl(2)可能なfdをユーザ空間に返す

KVMはioctl(2)でVMを作ったりvcpuを作ったりします。この時に使うfdは/dev/kvmファイルに対してioctl(2)を実行した時の戻り値です。ioctl(2)の戻り値がioctl(2)可能なfdとなってます。ユーザーランドに返すfdはどうやって作るのかというのが今回のめもです。

早速ですが、出来たコードはこうなります。

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/anon_inodes.h>
#include <linux/string.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/file.h>

MODULE_DESCRIPTION("ioctl test");
MODULE_AUTHOR("masami256");
MODULE_LICENSE("GPL");

struct fd_test_data {
    unsigned long id;
};

static long fd_test_anon_fd_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
{
    int r = -1;
    struct fd_test_data *p = filp->private_data;

    pr_info("%s: ioctl is %d\n", __func__, ioctl);

    switch (ioctl) {
    case 0:
        r = p->id;
        break;
    default:
        pr_warn("unkown ioctl %ud\n", ioctl);
    }

    return r;
}

static struct file_operations fd_test_anon_fd_fops = {
    .unlocked_ioctl     = fd_test_anon_fd_ioctl,
    .compat_ioctl       = fd_test_anon_fd_ioctl,
    .llseek     = noop_llseek,
};

static int create_file(unsigned long id)
{
    struct fd_test_data *p = kmalloc(sizeof(*p), GFP_KERNEL);
    int fd;
    char name[256] = { 0x0 };
    struct file *filp;

    if (!p)
        return -ENOMEM;

    p->id = id;

    snprintf(name, sizeof(name), "fd_test-%ld\n", id);


    filp =  anon_inode_getfile(name, &fd_test_anon_fd_fops, p, O_RDWR);
    if (IS_ERR(filp))
        return -1;

    fd = get_unused_fd_flags(O_CLOEXEC);
    if (fd < 0)
        return -1;

    fd_install(fd, filp);

    return fd;
}

static long fd_test_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
{
    long r = -EINVAL;

    pr_info("%s: ioctl is %d\n", __func__, ioctl);

    switch (ioctl) {
    case 0:
        r = create_file(arg);
        break;
    default:
        pr_warn("unkown ioctl %ud\n", ioctl);
    }

    return r;
}


static struct file_operations fd_test_chardev_fops = {
    .unlocked_ioctl     = fd_test_ioctl,
    .compat_ioctl       = fd_test_ioctl,
    .llseek         = noop_llseek,
};

static struct miscdevice fd_test_chardev = {
    .minor      = 243,
    .name       = "fd_test",
    .fops       = &fd_test_chardev_fops,
};

static int fd_test_init(void)
{
    int fd;

    fd = misc_register(&fd_test_chardev);
    if (fd < 0) {
        pr_warn("failed to create miscdevice\n");
        return fd;
    }

    pr_info("device file created\n");
    return fd;
}

static void fd_test_exit(void)
{
    misc_deregister(&fd_test_chardev);
    pr_info("finish %s\n", __func__);

}

module_init(fd_test_init);
module_exit(fd_test_exit);

まずはmiscデバイスを作っていて、最初にこのファイルを開いてioctl(2)を実行します。そうするとioctl(2)を実行できるfdが返るという感じです。 このfdの作り方は以下の3ステップでできます。

  1. fdを新たに割り当て
  2. file構造体を作成
  3. fdとファイル構造体を関連付ける

あ、上記のコードだと1と2は逆ですが。

1のfdの割り当てはget_unused_fd_flags()で行います。 2はanon_inode_getfile()です。この関数の3番目の引数はfile構造体のprivate_data変数に設定するデータです。上記のコードだとfd_test_data構造体を設定してます。 最後の3はfd_install()で、見ての通りfdとfile構造体を渡してます。 そして、fdをユーザーランドに返せば完了です。

テストコードはこんな感じです。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

int main(int argc, char **argv)
{
    int fd;
    int anon_fd;
    int r;

    unsigned long id = argc == 2 ? strtoul(argv[1], NULL, 10) : 1234UL;

    fd = open("/dev/fd_test", O_RDWR);
    if (fd < 0) {
        perror("open");
        exit(-1);
    }

    anon_fd = ioctl(fd, 0, id);
    if (anon_fd < 0) {
        perror("ioctl");
        exit(-1);
    }


    r = ioctl(anon_fd, 0, 0UL);

    printf("id is %d\n", r);
    close(fd);
}

これをコンパイルして動かすとこんなふうになります。

masami@kerntest:~/fd_test$ sudo ./a.out 1234
id is 1234
masami@kerntest:~/fd_test$ sudo ./a.out 12345678
id is 12345678
masami@kerntest:~/fd_test$ 

( ´ー`)フゥー...

dockerでNignxのリバースプロキシとwebアプリをlinkしたローカル開発環境を作る

前に仕事で作ったdockerを使ったwebアプリの開発環境の覚書です。

実環境はAWSで動いていて、ALBがhttpsでリクエストを受けてALBとwebアプリはhttpで通信します。このような構成をdockerで作りたかったわけです。 簡単な概要はこんな図になります。

f:id:masami256:20180724230335p:plain

ALBのところをNginxのリバースプロキシに置き換えて作りました。

Nginxのリバースプロキシはこんな設定です。

server {
       listen         443;
       server_name    www.webapp-test.local;
       ssl on;
       ssl_certificate      /etc/nginx/server.crt;
       ssl_certificate_key  /etc/nginx/server.key;

       location / {
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-Proto https;
             proxy_set_header X-Forwarded-Host $host;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

             # name is docker's link alias.
             proxy_pass http://local.webapp-test.local:3000/;
             proxy_redirect http:// https://;
       }
}

アプリの方でX-Forwarded-*を参照するのでセットしたり、hostヘッダはそのまま流したりしてます。 server_nameは実際にはちゃんとしたサーバ名ですがここではこんな名前にしてます。この名前はdocker-compose.ymlファイルのlinkで使う名前と合わせています。 www.webapp-test.localがブラウザでアクセスするURLになって、proxy_passで記述しているのがアプリのURLですね。どっちもlinkする時に使います。

Dockerfileはこの程度です。ベースのイメージは軽めなやつがよかったのでalpineを使ってます。

FROM alpine:latest

RUN apk update && \
apk add nginx && \
mkdir -p /run/nginx && \
rm -rf /var/cache/apk/*

COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/server.conf /etc/nginx/conf.d/server.conf

COPY nginx/server.crt /etc/nginx/server.crt
COPY nginx/server.key /etc/nginx/server.key

CMD ["/usr/sbin/nginx", "-g", "daemon off;"]

webアプリの方はDockerfileとかは特に変わったことはしてません。webaアプリのほうにあるdocker-compose.ymlでlinkしてあげるだけです。

version: '2'

services:
  webapp:
    build: .
    image: webapp
    hostname: local
    domainname: local.webapp-test.local
  proxy:
    image: local_dev_proxy
    ports:
      - 443:443
    links:
      - webapp:local.webapp-test.local
    hostname: www
    domainname: www.webapp-test.local

webappがwebアプリ、proxyがリバースプロキシです。hostとdomainnameはNginxの設定と合わせています。proxyのほうは443ポートを公開してます。ホストからアクセスする時は普通にhttpsの443番ポートを使います。で、proxyからwebappにアクセスを流したいのでlinkを使ってます。 あ、リバースプロキシもdocker-compose.yml使ってビルドしていて、名前はlocal_dev_proxyとしてます。

docker-compose upでwebアプリとリバースプロキシを起動しておいてcurlでアクセスを確認するとこうなります。

f:id:masami256:20180724232128p:plain

とまあ、ローカルの開発環境でALBの代わりにNginxでリバースプロキシを作ったというめもでした。

Docker実践ガイド impress top gearシリーズ

Docker実践ガイド impress top gearシリーズ

Linux:パフォーマンスに影響あるデバッグオプションがどれだけ影響あるか試してみた

なんとなくやってみた系ですね。

今回はCONFIG_DEBUG_OBJECTSのところです。

f:id:masami256:20180706233206p:plain

CONFIG_DEBUG_OBJECTS_FREEがkmalloc/kfreeをヘヴィにつかうような場合にパフォーマンス劣化するよーなんていってます。

f:id:masami256:20180706233254p:plain

まずはCONFIG_DEBUG_OBJECTSの項目を全部無効にした場合。

この時点でもロック周りに時間取ってますね。

f:id:masami256:20180706233504p:plain

hackbenchを引数 10 process 20000 で実行してる時の様子がこんな感じです。

f:id:masami256:20180706233612p:plain

次にCONFIG_DEBUG_OBJECTSの項目を全部無効にした場合。

起動した時点でかなりの時間をロックで使ってます。

f:id:masami256:20180706233435p:plain

そして、hackbenchを同じく実行するとこうこうなります/(^o^)\

f:id:masami256:20180706233745p:plain

このときはこんな感じになっていてもうどうにもならない感がありますね。

f:id:masami256:20180706233833p:plain

説明に書いてあるとおり、ほんと遅くなりますね。

( ´ー`)フゥー...

日経Linux 2018年 7 月号

日経Linux 2018年 7 月号

qemu: pyhtonでゲストとシリアル通信

ゲスト側のLinuxカーネルでシリアルコンソールを有効にしているときに、ホストからpythonでシリアルコンソールにアクセスするときメモです。

ゲスト側はカーネルコマンドラインでシリアルの設定をするのと、qemuのオプションで-serial ptyとしてptyを使うようにする。

$ qemu-kvm -initrd ./initramfs-4.17.2-200.fc28.x86_64.img -kernel ./vmlinuz-4.17.2-200.fc28.x86_64 -m 512 -append "console=ttyS0,115200" -serial pty -nographic
QEMU 2.11.1 monitor - type 'help' for more information
(qemu) qemu-system-x86_64: -serial pty: char device redirected to /dev/pts/2 (label serial0)

pythonのコードは特にパッケージとかはインストールしていなくて、qemu起動時に表示された /dev/pts/Xをオープンしてデータの読み書きを行います。

#!/usr/bin/env python3
#  qemu-system-x86_64 -initrd ./initramfs-4.17.2-200.fc28.x86_64.img  -kernel ./vmlinuz-4.17.2-200.fc28.x86_64 -m 512 -append "console=ttyS0,115200" -serial pty -nographic

import io, os
pty = io.TextIOWrapper(
    io.FileIO(
        os.open(
            "/dev/pts/2", os.O_NOCTTY | os.O_RDWR
        ),
        "w+"
    )
)
pty.write("uname -a\n");
for line in iter(pty.readline, None):
    print(line.strip())

こんな感じで使えます。

f:id:masami256:20180701003342p:plain

TwitterのPC版のUIからだと連携解除できないappの連携解除方法メモ

iPhoneとかで連携したappの一部はPCのWeb版からだとrevokeできなかったのでやり方のメモです。

PCのWeb版だと連携しているアプリを見るとLearn how to revoke an iOS appとリンクがあるだけでRevoke Accessボタンがないappがあります。Twitter for iPhoneとかを使ってるアプリがこうなってるようです。

revokeしたい場合はスマホのアプリもしくは、モバイル版のtwitterにアクセスしてrevokeします。 ただ、それでも個別にrevokeということは出来ないのでiPhoneを使っているならTwittre for iPhoneをrevokeします。そうするとこのrevokeに連動してTwitter for iPhoneと連携しているappが一気にrevokeされます。 もし、許可したいappがある場合は再度許可してあげる必要があります。

週刊? Linux Kernel Patch Watch 20180520

前書き

細かいpatchも見ているとなるほどーなとか勉強になりますね

今週のpatch

2038年問題対応

[PATCH 0/6] Transition vfs to 64-bit timestampsです。VFSがstruct timespecを使っているところで、この構造体は2038年問題があるのでstruct timespec64に置き換え。

typo修正

[PATCH] cramfs: Fix IS_ENABLED typoです。 fs/cramfs/inode.cで4.15からtypoってたようです。利用者数とかもあるんでしょうけど、意外と気付かれないものですね。

boot初期のhashed pointer表示

[PATCH] vsprintf: Add command line option debug_boot_weak_hashです。早い段階だと十分なエントロピーがないため、ポインタのアドレスをhash値で表現できずに固定の文字列表示になってしまうのですが、これだとデバッグが難しいということで、bootの初期段階でもhash値を作れるようにするpatchです。

空の/proc//cmdlineは許可しない

[PATCH] proc: Don't allow empty /proc/PID/cmdline for user tasksです。カーネルスレッドがの場合、/proc//cmdlineが空になっていて、ps(1)等はこれでプロセスがカーネルスレッドか判定してるそうです。ただ、この挙動は普通のユーザーランドのプログラムでエミュレートできるので止めようとのことです。

secompのフィルターに引っかかったらユーザ空間に通知

[PATCH v2 0/4] seccomp trap to userspaceです。secompでフィルターに引っかかったらそれをユーザーランド側に通知する仕組みの追加です。カーネル側に色々と処理を持たすよりもユーザーランド側で処理するようにしたほうが柔軟にもなりますね。

その他

UPのシステムでfor_each_cpu()がバグってる?

for_each_cpu() is buggy for UP kernel?です。

以下のイテレータで、システムがUni Processorな場合でmaskに0が設定されていてもmaskの値が無視されているからループが一回走ってしまって良くないということです。

#define for_each_cpu(cpu, mask)                 \
        for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)

4.16.10だとUPでない場合はfor_each_cpu()はこのようになっていて、maskの値が使われます。

/**
 * for_each_cpu - iterate over every cpu in a mask
 * @cpu: the (optionally unsigned) integer iterator
 * @mask: the cpumask pointer
 *
 * After the loop, cpu is >= nr_cpu_ids.
 */
#define for_each_cpu(cpu, mask)                \
   for ((cpu) = -1;             \
       (cpu) = cpumask_next((cpu), (mask)),    \
       (cpu) < nr_cpu_ids;)

これについては過去に議論されたけど、結論はでてないとのことでした。

あとがき

(´-`).。oO(遅れましたがなんとか