[patch] fs: new inode i_state corruption fix Mar 6, 2009

역시 이런 core 쪽의 BUG는 언제나 Nick이 해결한다.

http://patchwork.kernel.org/patch/9984/

문제는 inode->i_state의 I_NEW state에 대한 race condition문제이다.

void unlock_new_inode(struct inode *inode)
{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
if (inode->i_mode & S_IFDIR) {
struct file_system_type *type = inode->i_sb->s_type;

/*
* ensure nobody is actually holding i_mutex
*/
mutex_destroy(&inode->i_mutex);
mutex_init(&inode->i_mutex);
lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key);
}
#endif
/*
* This is special! We do not need the spinlock
* when clearing I_LOCK, because we're guaranteed
* that nobody else tries to do anything about the
* state of the inode when it is locked, as we
* just created it (so there can be no old holders
* that haven't tested I_LOCK).
*/
inode->i_state &= ~(I_LOCK|I_NEW);
wake_up_inode(inode);
}
주석에서 보는 것과 같이 kernel은 의도적으로 inode의 state를 변경함에도 불구하고 spinlock을 잡지 않았다. 왜냐하면
1. 새로 생성되는 inode의 state에는 I_LOCK|I_NEW가 걸리게 되며, 새로 생성된 inode이기 때문에 이전에 이 inode에 대해서 I_LOCK을 test하지 않고 inode를 잡고 있는 녀석도 없을 테고,
2. inode가 lock되어 있을 때는 inode의 state를 바꾸기 위한 어떤 시도도 이루어질 수 없음으로

이 곳에서 spinlock이 굳이 필요 없다는 것이다.

하지만 패치에 명시된 문제가 발생한 것이다. CPU0과 CPU1이 unlock_new_inode와 __sync_single_inode를 패치에 명시된 순서대로 실행 되었을 경우, 해지된 I_NEW state가 다시 지정되어 결국 wake_up_inode가 프로세스를 깨우지 않게 되는 문제이다.

이 문제를 해결하기 위해서 Nick은 __sync_single_inode에서 I_NEW state를 기다리는 것 보다는 해당 inode를 queue에 다시 넣고 일단 skip하는 방법을 택했다. 합리적인 결정이다.

왜냐하면 동시에 막 생성되고 있는 inode들은 data integrity operation의 대상이 아니며 dirty memory에도 별로 영향을 미치지 않을 것이라는 이유에서이다.

역시 Nick, Good job!

0 개의 덧글: