writeback 메커니즘 소스 코드 분석
writeback 과 관련 된 데이터 구 조 는 주로 다음 과 같다.
1,backing_dev_info, 이 데이터 구 조 는 backing 을 묘사 합 니 다.dev 의 모든 정보, 일반 블록 장치 의 request quue 에는 backing 이 포함 되 어 있 습 니 다.dev 대상.
2,bdi_writeback, 이 데이터 구 조 는 writeback 의 커 널 스 레 드 와 조작 해 야 할 inode 대기 열 을 패키지 합 니 다.
3,wb_writeback_work, 이 데이터 구 조 는 writeback 의 작업 임 무 를 패키지 합 니 다.
각 데이터 구조 간 의 관 계 는 다음 그림 과 같다.
다음은 각 데이터 구조 에 대해 간략하게 소개 한다.
bdi information
bdi 대상 은 블록 장치 가 추 가 될 때 시스템 의 bdi 대기 열 에 등록 해 야 합 니 다.ext 3 의 경우 mount 에 있 을 때 바 텀 블록 장치 의 bdi 대상 을 ext 3 root 에 연결 해 야 합 니 다.inode 중.bdi 대상 데이터 구조 정 의 는 다음 과 같 습 니 다.
struct backing_dev_info {
struct list_head bdi_list;
unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */
unsigned long state; /* Always use atomic bitops on this */
unsigned int capabilities; /* Device capabilities */
congested_fn *congested_fn; /* Function pointer if device is md/dm */
void *congested_data; /* Pointer to aux data for congested func */
char *name;
struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS];
unsigned long bw_time_stamp; /* last time write bw is updated */
unsigned long dirtied_stamp;
unsigned long written_stamp; /* pages written at bw_time_stamp */
unsigned long write_bandwidth; /* the estimated write bandwidth */
unsigned long avg_write_bandwidth; /* further smoothed write bw */
/*
* The base dirty throttle rate, re-calculated on every 200ms.
* All the bdi tasks' dirty rate will be curbed under it.
* @dirty_ratelimit tracks the estimated @balanced_dirty_ratelimit
* in small steps and is much more smooth/stable than the latter.
*/
unsigned long dirty_ratelimit;
unsigned long balanced_dirty_ratelimit;
struct prop_local_percpu completions;
int dirty_exceeded;
unsigned int min_ratio;
unsigned int max_ratio, max_prop_frac;
struct bdi_writeback wb; /* default writeback info for this bdi,writeback */
spinlock_t wb_lock; /* protects work_list */
/* */
struct list_head work_list;
struct device *dev;
/* laptop */
struct timer_list laptop_mode_wb_timer;
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_dir;
struct dentry *debug_stats;
#endif
};
bdi 데이터 구조 에서 writeback 대상 을 정 의 했 습 니 다. 이 대상 은 writeback 커 널 스 레 드 에 대한 설명 이 고 처리 해 야 할 inode 대기 열 을 밀봉 하 였 습 니 다.bdi 데이터 구조 에 work 가 있 습 니 다.list, 이 work 대기 열 은 writeback 커 널 스 레 드 가 처리 해 야 할 작업 을 유지 합 니 다.이 대기 열 에 work 가 처리 되 지 않 으 면 writeback 커 널 스 레 드 는 잠 을 자고 기다 릴 것 입 니 다.
writeback
writeback 대상 은 커 널 스 레 드 task 와 처리 해 야 할 inode 대기 열 을 패키지 합 니 다.page cache/buffer cache 가 radix tree 의 inode 를 새로 고 쳐 야 할 때 이 inode 를 writeback 대상 의 b 에 마 운 트 할 수 있 습 니 다.dirty 대기 열 에서 writeback 스 레 드 를 깨 웁 니 다.처리 과정 에서 inode 는 b 로 이동 합 니 다.io 대기 열 에서 처리 합 니 다.여러 개의 링크 방식 은 다 중 스 레 드 간 의 자원 공 유 를 낮 출 수 있다.writeback 데이터 구 조 는 다음 과 같이 구체 적 으로 정의 합 니 다.
struct bdi_writeback {
struct backing_dev_info *bdi; /* our parent bdi */
unsigned int nr;
unsigned long last_old_flush; /* last old data flush */
unsigned long last_active; /* last time bdi thread was active */
struct task_struct *task; /* writeback thread */
struct timer_list wakeup_timer; /* used for delayed bdi thread wakeup */
struct list_head b_dirty; /* dirty inodes */
struct list_head b_io; /* parked for writeback */
struct list_head b_more_io; /* parked for more writeback */
spinlock_t list_lock; /* protects the b_* lists */
};
writeback work
wb_writeback_work 데이터 구 조 는 writeback 작업 에 대한 패키지 로 서로 다른 작업 은 서로 다른 리 셋 전략 을 사용 할 수 있 습 니 다.writeback 스 레 드 의 처리 대상 은 writeback 입 니 다.work.하면, 만약, 만약...work 대기 열 이 비어 있 으 면 커 널 스 레 드 가 잠 을 잘 수 있 습 니 다.Writeback_work 의 데이터 구조 정 의 는 다음 과 같다.
struct wb_writeback_work {
long nr_pages;
struct super_block *sb; /* superblock */
unsigned long *older_than_this;
enum writeback_sync_modes sync_mode;
unsigned int tagged_writepages:1;
unsigned int for_kupdate:1;
unsigned int range_cyclic:1;
unsigned int for_background:1;
enum wb_reason reason; /* why was writeback initiated? */
struct list_head list; /* pending work list, bdi-> work_list */
struct completion *done; /* set if the caller waits,work */
};
writeback 주요 함수 분석
writeback 메커니즘 의 주요 함 수 는 다음 과 같은 두 가지 측면 을 포함한다.
1. bdi 대상 을 관리 하고 fork 에 해당 하 는 writeback 커 널 스 레 드 처리 cache 데이터 의 리 셋 작업.
2, writeback 커 널 스 레 드 처리 함수, dirty page 의 리 셋 작업 실현
writeback 스 레 드 관리
Linux 에 커 널 데 몬 스 레 드 가 있 습 니 다. 이 스 레 드 는 시스템 bdi 대기 열 을 관리 하고 block device 에 writeback thread 를 만 드 는 데 사 용 됩 니 다.bdi 에 dirty page 가 있 고 bdi 에 커 널 스 레 드 를 할당 하지 않 았 을 때 bdiforker_thread 프로그램 은 스 레 드 자원 을 분배 합 니 다.writeback 스 레 드 가 오랫동안 비어 있 을 때 bdiforker_thread 프로그램 은 이 스 레 드 자원 을 방출 합 니 다.
writeback 스 레 드 관리 프로그램 분석 은 다음 과 같 습 니 다.
static int bdi_forker_thread(void *ptr)
{
struct bdi_writeback *me = ptr;
current->flags |= PF_SWAPWRITE;
set_freezable();
/*
* Our parent may run at a different priority, just set us to normal
*/
set_user_nice(current, 0);
for (;;) {
struct task_struct *task = NULL;
struct backing_dev_info *bdi;
enum {
NO_ACTION, /* Nothing to do */
FORK_THREAD, /* Fork bdi thread */
KILL_THREAD, /* Kill inactive bdi thread */
} action = NO_ACTION;
/*
* Temporary measure, we want to make sure we don't see
* dirty data on the default backing_dev_info
*/
if (wb_has_dirty_io(me) || !list_empty(&me->bdi->work_list)) {
del_timer(&me->wakeup_timer);
wb_do_writeback(me, 0);
}
spin_lock_bh(&bdi_lock);
/*
* In the following loop we are going to check whether we have
* some work to do without any synchronization with tasks
* waking us up to do work for them. Set the task state here
* so that we don't miss wakeups after verifying conditions.
*/
set_current_state(TASK_INTERRUPTIBLE);
/* bdi , bdi , , fork , writeback */
list_for_each_entry(bdi, &bdi_list, bdi_list) {
bool have_dirty_io;
if (!bdi_cap_writeback_dirty(bdi) ||
bdi_cap_flush_forker(bdi))
continue;
WARN(!test_bit(BDI_registered, &bdi->state),
"bdi %p/%s is not registered!
", bdi, bdi->name);
/* */
have_dirty_io = !list_empty(&bdi->work_list) ||
wb_has_dirty_io(&bdi->wb);
/*
* If the bdi has work to do, but the thread does not
* exist - create it.
*/
if (!bdi->wb.task && have_dirty_io) {
/*
* Set the pending bit - if someone will try to
* unregister this bdi - it'll wait on this bit.
*/
/* , , FORK */
set_bit(BDI_pending, &bdi->state);
action = FORK_THREAD;
break;
}
spin_lock(&bdi->wb_lock);
/*
* If there is no work to do and the bdi thread was
* inactive long enough - kill it. The wb_lock is taken
* to make sure no-one adds more work to this bdi and
* wakes the bdi thread up.
*/
/* bdi , KILL , bdi writeback */
if (bdi->wb.task && !have_dirty_io &&
time_after(jiffies, bdi->wb.last_active +
bdi_longest_inactive())) {
task = bdi->wb.task;
bdi->wb.task = NULL;
spin_unlock(&bdi->wb_lock);
set_bit(BDI_pending, &bdi->state);
action = KILL_THREAD;
break;
}
spin_unlock(&bdi->wb_lock);
}
spin_unlock_bh(&bdi_lock);
/* Keep working if default bdi still has things to do */
if (!list_empty(&me->bdi->work_list))
__set_current_state(TASK_RUNNING);
/* FORK KILL */
switch (action) {
case FORK_THREAD:
/* FORK bdi_writeback_thread , flush-major:minor */
__set_current_state(TASK_RUNNING);
task = kthread_create(bdi_writeback_thread, &bdi->wb,
"flush-%s", dev_name(bdi->dev));
if (IS_ERR(task)) {
/*
* If thread creation fails, force writeout of
* the bdi from the thread. Hopefully 1024 is
* large enough for efficient IO.
*/
writeback_inodes_wb(&bdi->wb, 1024,
WB_REASON_FORKER_THREAD);
} else {
/*
* The spinlock makes sure we do not lose
* wake-ups when racing with 'bdi_queue_work()'.
* And as soon as the bdi thread is visible, we
* can start it.
*/
spin_lock_bh(&bdi->wb_lock);
bdi->wb.task = task;
spin_unlock_bh(&bdi->wb_lock);
wake_up_process(task);
}
bdi_clear_pending(bdi);
break;
case KILL_THREAD:
/* KILL */
__set_current_state(TASK_RUNNING);
kthread_stop(task);
bdi_clear_pending(bdi);
break;
case NO_ACTION:
/* , */
if (!wb_has_dirty_io(me) || !dirty_writeback_interval)
/*
* There are no dirty data. The only thing we
* should now care about is checking for
* inactive bdi threads and killing them. Thus,
* let's sleep for longer time, save energy and
* be friendly for battery-driven devices.
*/
schedule_timeout(bdi_longest_inactive());
else
schedule_timeout(msecs_to_jiffies(dirty_writeback_interval * 10));
try_to_freeze();
break;
}
}
return 0;
}
writeback 스 레 드
writeback 스 레 드 는 bdiforker_thread 가 만 든 이 스 레 드 의 작업 은 기다 리 는 데이터 리 턴 작업 을 처리 하 는 것 입 니 다.스 레 드 처리 함 수 는 bdiwriteback_thread, wb 호출do_writeback 함수 가 구체 적 인 조작 을 완 료 했 습 니 다. 이 함수 분석 은 다음 과 같 습 니 다.
long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
{
struct backing_dev_info *bdi = wb->bdi;
struct wb_writeback_work *work;
long wrote = 0;
set_bit(BDI_writeback_running, &wb->bdi->state);
/* work, work pengding bdi->work_list */
while ((work = get_next_work_item(bdi)) != NULL) {
/*
* Override sync mode, in case we must wait for completion
* because this thread is exiting now.
*/
if (force_wait)
work->sync_mode = WB_SYNC_ALL;
trace_writeback_exec(bdi, work);
/* wb_writeback inode */
wrote += wb_writeback(wb, work);
/*
* Notify the caller of completion if this is a synchronous
* work item, otherwise just free it.
*/
/* , work */
if (work->done)
complete(work->done);
else
kfree(work);
}
/*
* Check for periodic writeback, kupdated() style
*/
/* dirty page ,buffer cache , work, wb_writeback */
wrote += wb_check_old_data_flush(wb);
wrote += wb_check_background_flush(wb);
clear_bit(BDI_writeback_running, &wb->bdi->state);
return wrote;
}
작은 매듭
본 고 는 linux - 3.2 를 바탕 으로 writeback 코드 를 조회 했다.전체적으로 보면 writeback 체 제 는 비교적 간단 하 다. 그 핵심 은 상주 커 널 스 레 드 를 통 해 bdi 대상 에 writeback 스 레 드 를 분배 하여 cache 중의 dirty page 에 대한 데이터 리 턴 을 실현 하 는 것 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.