sb_getblk.. 몇일째 헤매고 있네요.

shad0wse의 이미지

안녕하세요. 너무 길을 몰라서.. 여기에 남깁니다.
제가 하드디스크의 특정 블록을 얻어오려고..

struct buffer_head *bh = sb_getblk( struct super_block *sb, unsigned long block );

이런식으로 bh을 얻어 옵니다. 이 것을 가지고 bh->b_data에 접근해서
실제 블록에 접근을 하게 됩니다.
헌데 문제는요. 이게 가끔 크래쉬를 발생시킨다는 것입니다.
매번 그런 것은 아니고요. 몇 번 호출하다 보면 그대로 뻗어버립니다.

아무래도 이유인즉, 동기화 문제인 거 같아서
여러가지 해결책을 생각해봤는데요.

sb_getblk() 호출 후 brelse() 를 통해서 bh를 해제시켜도 마찬가지였습니다.
또한 lock_buffer()/unlock_buffer()를 써도 의미가 없었구요.

이게 실제로 sb_getblk()에서 얻어온 데이터를 수정한다면 lock/unlock을
사용하면 유용할 거 같은데 현재는 sb_getblk()해서 참조만 할 거라서 무의미한 거 같습니다.

get_bh/put_bh 같은 경우에도 bh를 수정할 때 쓰이는 거 같더라구요.
결과적으로는 아직까지 어떠한 해결책도 못 찾아서 헤매는 중입니다. ㅠㅠ

현재, 제 시스템은 Ubuntu 8.10, linux-2.6.27-14-gen 버전입니다.
파일 시스템은 ext3 이고요.

혹시나 도움이 될까 해당 소스를 올려보았습니다.
물론 이 함수 호출 전에 open_bdev_excl()로 블록 디바이스 장치를 오픈해서
get_super() 함수로 sb를 얻었는 상태에서 호출한 것입니다.

169 struct ext3_super_block *ext3_get_superblock( struct super_block *sb, struct fs_info *fs_i )
170 {
171     unsigned long offset = 0;
172     ext3_fsblk_t logic_sb_block;
173     struct buffer_head *bh = NULL;
176
177     // 슈퍼블록 블록 번호를 구함
178     logic_sb_block = get_logic_sb_block( sb, LOGIC_SB_BLOCK );
179     offset = get_logic_sb_block( sb, OFFSET );
182
183     brelse( bh );
184     // 슈퍼 블록을 읽어 버퍼헤드 형태로 저장
185     if( !(bh = sb_getblk( sb, logic_sb_block )) )
186     {
189         goto OUT_FAIL;
190     }
192     brelse( bh );
196     return NULL;

혹시, 작은 조언이라도 좋으니 부탁드리겠습니다...

shad0wse의 이미지

블록 디바이스 장치는 usb입니다. 2GB 이며, 현재 ext3로 파티션이 생성 돼 있는 상태입니다..

Always as first

Always as first

headbang의 이미지

글을 읽어보니 32bit 커널이군요.
해당 페이지(즉, bh->b_page)가 high memory에 있는 경우와 low memory에 있는 경우에 따라 bh->b_data가 다르게 해석됩니다.

Understanding the Linux Kernel 책을 뒤져보니 아래처럼 나오는 군요.

Quote:

The b_data field specifies the position of the block buffer inside the buffer page. Actually, the encoding of this position depends on whether the page is in high memory or not. If the page is in high memory, the b_data field contains the offset of the block buffer with respect to the beginning of the page; otherwise, b_data contains the linear address of the block buffer.

아래 예제 코드를 수정해서 쓰시면 됩니다.

         char *buff = my_buff;
         char *addr;
         addr = kmap(bh->p_page) + offset_in_page(bh->b_data);
         memcpy(addr, buff, bh->b_size);                  
         kunmap(bh->p_page);