디버그 메모리 -5- (Fault Injection)

<kernel v5.0>

디버그 메모리 -5- (Fault Injection)

 

디버깅용 페이지 할당 실패 Injection

FAIL_PAGE_ALLOC

alloc_pages()에 대한 디버그 기능으로 fault-injection 처리를 위한 코드가 추가된다.

  • “fail_page_alloc=<interval>,<probability>,<space>,<times>” 커널 옵션을 사용하여 FAULT-INJECTION에 대한 4가지 속성을 변경할 수 있다.

 

should_fail_alloc_page()

mm/page_alloc.c

static noinline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
{
        return __should_fail_alloc_page(gfp_mask, order);
}
ALLOW_ERROR_INJECTION(should_fail_alloc_page, TRUE);

 

__should_fail_alloc_page()

mm/page_alloc.c

static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
{
        if (order < fail_page_alloc.min_order)
                return false;
        if (gfp_mask & __GFP_NOFAIL)
                return false;
        if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
                return false;
        if (fail_page_alloc.ignore_gfp_reclaim && 
                        (gfp_mask & __GFP_DIRECT_RECLAIM))
                return false;

        return should_fail(&fail_page_alloc.attr, 1 << order);
}

CONFIG_FAIL_PAGE_ALLOC 커널 옵션을 사용하는 경우 디버깅 목적으로 사용되며 fail_page_alloc 전역 객체의 조건을 벗어나는 gfp_mask를 가진 경우 false를 반환한다. 또한 __GFP_NOFAIL 옵션을 사용하는 경우에도 false를 반환한다.

 

should_fail()

lib/fault-inject.c

/*
 * This code is stolen from failmalloc-1.0
 * http://www.nongnu.org/failmalloc/
 */
bool should_fail(struct fault_attr *attr, ssize_t size)
{
        if (in_task()) {
                unsigned int fail_nth = READ_ONCE(current->fail_nth);

                if (fail_nth) {
                        if (!WRITE_ONCE(current->fail_nth, fail_nth - 1))
                                goto fail;

                        return false;
                }
        }

        /* No need to check any other properties if the probability is 0 */
        if (attr->probability == 0)
                return false;

        if (attr->task_filter && !fail_task(attr, current))
                return false;

        if (atomic_read(&attr->times) == 0)
                return false;

        if (atomic_read(&attr->space) > size) {
                atomic_sub(size, &attr->space);
                return false;
        }

        if (attr->interval > 1) {
                attr->count++;
                if (attr->count % attr->interval)
                        return false;
        }

        if (attr->probability <= prandom_u32() % 100)
                return false;

        if (!fail_stacktrace(attr))
                return false;

fail:
        fail_dump(attr);

        if (atomic_read(&attr->times) != -1)
                atomic_dec_not_zero(&attr->times);

        return true;
}
EXPORT_SYMBOL_GPL(should_fail);

 

참고

 

댓글 남기기