前の記事からの続き:Linux カーネルのアップストリーム送信の完了プロセスと例
Linux カーネルのアップストリーム提出の完了プロセスと例では、作成者は DRM のアップストリーム提出を行いました。当初は返信が来るまでに数日、1 週間、あるいはそれ以上かかるだろうと思っていましたが、24 時間以内に上流から返信が来るとは予想していませんでした。内容は次のとおりです。
ご覧のとおり、アップストリームのメンテナーである Ville Syrjälä からのフィードバックは次のとおりです。
すでに以前に確認したため、この場合はそうではありません。
しかし、実際にコードを見てみると、Linux Kernel ソースコードのルートディレクトリにある drivers/gpu/drm/drm_framebuffer.c にある Framebuffer_check 関数のコードは、もともと次のとおりです。
static int framebuffer_check(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *r)
{
const struct drm_format_info *info;
int i;
/* check if the format is supported at all */
if (!__drm_format_info(r->pixel_format)) {
drm_dbg_kms(dev, "bad framebuffer format %p4cc\n",
&r->pixel_format);
return -EINVAL;
}
if (r->width == 0) {
drm_dbg_kms(dev, "bad framebuffer width %u\n", r->width);
return -EINVAL;
}
if (r->height == 0) {
drm_dbg_kms(dev, "bad framebuffer height %u\n", r->height);
return -EINVAL;
}
/* now let the driver pick its own format info */
info = drm_get_format_info(dev, r);
for (i = 0; i < info->num_planes; i++) {
unsigned int width = fb_plane_width(r->width, info, i);
unsigned int height = fb_plane_height(r->height, info, i);
unsigned int block_size = info->char_per_block[i];
u64 min_pitch = drm_format_info_min_pitch(info, i, width);
if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
drm_dbg_kms(dev, "Format requires non-linear modifier for plane %d\n", i);
return -EINVAL;
}
if (!r->handles[i]) {
drm_dbg_kms(dev, "no buffer object handle for plane %d\n", i);
return -EINVAL;
}
if (min_pitch > UINT_MAX)
return -ERANGE;
if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
return -ERANGE;
if (block_size && r->pitches[i] < min_pitch) {
drm_dbg_kms(dev, "bad pitch %u for plane %d\n", r->pitches[i], i);
return -EINVAL;
}
if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
return -EINVAL;
}
if (r->flags & DRM_MODE_FB_MODIFIERS &&
r->modifier[i] != r->modifier[0]) {
drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
return -EINVAL;
}
/* modifier specific checks: */
switch (r->modifier[i]) {
case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
/* NOTE: the pitch restriction may be lifted later if it turns
* out that no hw has this restriction:
*/
if (r->pixel_format != DRM_FORMAT_NV12 ||
width % 128 || height % 32 ||
r->pitches[i] % 128) {
drm_dbg_kms(dev, "bad modifier data for plane %d\n", i);
return -EINVAL;
}
break;
default:
break;
}
}
for (i = info->num_planes; i < 4; i++) {
if (r->modifier[i]) {
drm_dbg_kms(dev, "non-zero modifier for unused plane %d\n", i);
return -EINVAL;
}
/* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */
if (!(r->flags & DRM_MODE_FB_MODIFIERS))
continue;
if (r->handles[i]) {
drm_dbg_kms(dev, "buffer object handle for unused plane %d\n", i);
return -EINVAL;
}
if (r->pitches[i]) {
drm_dbg_kms(dev, "non-zero pitch for unused plane %d\n", i);
return -EINVAL;
}
if (r->offsets[i]) {
drm_dbg_kms(dev, "non-zero offset for unused plane %d\n", i);
return -EINVAL;
}
}
return 0;
}
コードスニペットは次のとおりです。
/* now let the driver pick its own format info */
info = drm_get_format_info(dev, r);
for (i = 0; i < info->num_planes; i++) {
……
info はパラメータのチェックを行いません。上記のコードから判断すると、framebuffer_check 関数が情報の定義を開始した後 (コードは次のとおり)、
const struct drm_format_info *info;
info が再び使用されている場所は上記のコード スニペットであり、使用されていません。これは、上流のメンテナである Ville Syrjälä によって与えられたフィードバックです。
すでに以前に確認したため、この場合はそうではありません。
上記は当てはまりません。
以下のコードを見てみましょう。 drm_get_format_info 関数 (drivers/gpu/drm/drm_fourcc.c 内) コードは次のとおりです。
/**
* drm_get_format_info - query information for a given framebuffer configuration
* @dev: DRM device
* @mode_cmd: metadata from the userspace fb creation request
*
* Returns:
* The instance of struct drm_format_info that describes the pixel format, or
* NULL if the format is unsupported.
*/
const struct drm_format_info *
drm_get_format_info(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
const struct drm_format_info *info = NULL;
if (dev->mode_config.funcs->get_format_info)
info = dev->mode_config.funcs->get_format_info(mode_cmd);
if (!info)
info = drm_format_info(mode_cmd->pixel_format);
return info;
}
EXPORT_SYMBOL(drm_get_format_info);
著者によるさらなるフォローアップの後、それが正しいかどうかは
info = dev->mode_config.funcs->get_format_info(mode_cmd);
まだ
info = drm_format_info(mode_cmd->pixel_format);
呼び出された関数には、情報をチェックして空でないことを確認するコードはありません。したがって、作者は上流メンテナの返答に同意しません。そのため、著者は礼儀正しくなく、返信メールに直接返信しました。
今回はそれ以上の返答はありません。
その後、作成者は DRM コードに別の問題があることを発見しました。 drivers/gpu/drm/drm_framebuffer.c の Framebuffer_check 関数には、次のコード スニペットがまだ含まれています。
for (i = info->num_planes; i < 4; i++) {
if (r->modifier[i]) {
drm_dbg_kms(dev, "non-zero modifier for unused plane %d\n", i);
return -EINVAL;
}
/* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */
if (!(r->flags & DRM_MODE_FB_MODIFIERS))
continue;
if (r->handles[i]) {
drm_dbg_kms(dev, "buffer object handle for unused plane %d\n", i);
return -EINVAL;
}
if (r->pitches[i]) {
drm_dbg_kms(dev, "non-zero pitch for unused plane %d\n", i);
return -EINVAL;
}
if (r->offsets[i]) {
drm_dbg_kms(dev, "non-zero offset for unused plane %d\n", i);
return -EINVAL;
}
}
ここで次の行は
for (i = info->num_planes; i < 4; i++) {
数字の 4 が直接使用されるため、移植性の問題が発生します。そこで作者はそれを次のように変更しました
for (i = info->num_planes; i < DRM_FORMAT_MAX_PLANES; i++) {
DRM_FORMAT_MAX_PLANES マクロは include/drm/drm_fourcc.h で定義されています。
/**
* DRM_FORMAT_MAX_PLANES - maximum number of planes a DRM format can have
*/
#define DRM_FORMAT_MAX_PLANES 4u
もう一度手順に従ってLinux カーネルのアップストリーム送信の完了プロセスと例を実行し、アップストリームの送信を試してください。今回は24時間以内に返信が来ました。最初の応答は次のとおりです。
"審査"! DRM、つまりカーネルのアップストリーム提出まであと一歩です。著者は喜んでいた矢先、翌日に打撃を受けた。別のメンテナーがこのパッチに対して次のように回答しました。
こんにちは、午前 02.11.23 um 03:29 schrieb Peng Hao: >変更可能性を向上させるには、4 の代わりにマクロ DRM_FORMAT_MAX_PLANES を使用します。 > >署名者: Peng Hao
このメンテナの返答はもっと理にかなっています。
本当に上流申請を実現したいのであれば、優れた知識と技術が必要なようです。小さな部分だけを見て「何かを見逃した」と考えることはできません。