softirqs, ksoftirqd kernel thread 에 관한 질문입니다.

swunk의 이미지

bottom half 처리방식의 한종류인 softirq 처리에 관해서 질문 드립니다.

do_softirq()가 수행되다가 계속해서(10번이상) softirq가 reactivated 되면 (계속해서 softirq를 등록을 하면, 예:NET_RX 가 check) 즉, raised_softirq() 함수가 계속해서 호출이 되면 이를 효율적으로 처리하기 위해서 priority 가 낮은( priority 값 = 19) ksoftirqd 커널 스레드를 깨워서 다시 do_softirq()함수를 수행시킵니다.

여기서 질문이 있습니다.
do_softirq()함수가 호출되는 것은 여러가지 경로가 있지만 interrupt 수행이 끝난후에 pending 되어 있는 softirq가 있는지 확인을 하고 있으면 do_softirq()함수를 호출하는게 일반적인 것으로 알고 있습니다.

그렇다면...예를 들어서 네트워크를 통해서 패킷이 하나 들어오면 interrupt가 발생할 것이고 top half를 수행 후에 pending 되어 있는 softirq를 확인하고 있으면 do_softirq() 를 호출한다는 얘기가 되는데....여기서 do_softirq를 수행하다가 계속해서 softirq가 발생하면, 즉, softirq가 reactivated되면 이를 효과적으로 처리하기 위해서 ksoftirqd 커널 스레드를 생성한다고 하는데요...

어차피 여기서 ksoftirq 커널 스레드를 깨워서 실행시키지 않아도 인터럽트가 발생할때마다 do_softirq()함수를 호출하기 때문에 계속해서 발생하는 NET_RX softirq를 모두 처리할 것 같은데요,... 왜 ksoftirqd 커널 스레드를 깨워서 실행시키는지 궁금합니다.

질문이 좀 난잡합니다만 고수님들은 이해하셨을것이라고 생각합니다.

답변 부탁드립니다.

sangwoo의 이미지

Interrupt Handler가 호출되는 경우에는 다른 interrupt들이 (더 낮거나 같은 priority를 갖는) block되기 때문에, 처리를 못하는 경우가 있습니다. 따라서 interrupt handler는 최대한 짧은 시간동안만 실행되어야 합니다. 그렇기 대문에 interrupt의 처리를 interrupt handler에서 모두 처리하는 것보다는 작업을 잘 나누어서, 뒤에 처리해도 되는 것은 천천히 처리하는 것이 더 효율적으로 자원을 이용하는 것이기 때문에 그렇습니다.

대답하고 나서 다시 읽어보니 왠지 이걸 물어보신 게 아닌 거 같다는 생각도 드는군요 -_ㅠ
----
Let's shut up and code.

----
Let's shut up and code.

swunk의 이미지

예 맞습니다 ...그걸 물어본건 아닌데...말씀하신 interrupt 처리(top half 처리) 를 수행후 처리되는 bottom half 처리 방식 중 softirq 방식에 대해서 질문 한것 입니다.

wariua의 이미지

Linux Kernel Development 2nd ed.(Robert Love, Sams Publishing) 7.3절을 보니까 설명이 약간 나오네요.

Quote:
Softirqs might be raised at very high rates (such as during intense network traffic). Further, softirq functions can reactivate themselves. That is, while running, a softirq can raise itself so that it runs again (indeed, the networking subsystem does this). The possibility of a high frequency of softirqs in conjunction with their capability to remark themselves active can result in user-space programs being starved of processor time. Not processing the reactivated softirqs in a timely manner, however, is unacceptable.
...
In designing softirqs, the developers realized that some sort of compromise was needed. The solution ultimately implemented in the kernel is to not immediately process reactivated softirqs. Instead, if the number of softirqs grows excessive, the kernel wakes up a family of kernel threads to handle the load. The kernel threads run with the lowest possible priority (nice value of 19), which ensures they do not run in lieu of anything important. This concession prevents heavy softirq activity from completely starving user-space of processor time. Conversely, it also ensures that "excess" softirqs do run eventually. Finally, this solution has the added property that on an idle system, the softirqs are handled rather quickly (because the kernel threads will schedule immediately).

인즉 bottom half 처리에 몰두하느라 다른 작업을 전혀 처리하지 못하는 걸 방지하기 위해서라는군요. ksoftirqd로 인해 softirq 처리 속도가 살짝 지연되면 위에서 언급한 'reactivate themselves' 하는 softirq 함수의 실행 속도도 좀 줄어들 것이고, 그러면 다른 작업을 실행할 수 있는 여력이 좀 생기겠지요.
----
$PWD `date`

$PWD `date`

swunk의 이미지

bottom half 처리에 몰두하느라 다른 작업을 전혀 처리하지 못하는걸 방지하기 위해서 iteration 횟수를 10으로 제한한 것으로 알고 있습니다.
10번 수행한 다음에도 pending 되어 있는 작업들이 있으면 그때 ksoftirqd를 깨워서 pending 되어 있는 작업들을 ksortirqd가 스케쥴러에 의해서 선택된 후에 수행 하는것으로 알고 있는데요...

위에서 언급한 내용에도 "such as during intense network traffic" 같은 환경에서 softirqd를 깨워서 수행한다고 하는데...intense network traffic 환경에서는 interrupt가 계속해서 발생할 것이고 발생한 interrput에서 top half만 처리하고는 다시 pending 되어 있는 softirq들을 처리할 것이기 때문에 ksoftirqd 커널 쓰레드가 필요가 없을듯 해서 드린 질문입니다.

제가 뭘 잘못 이해하고 있는것 같기도 하고...

좀더 자세한 답변을 부탁드려도 될까요 ?

wariua의 이미지

자세한 답변을 드릴 실력은 되지 않고... 소설이나 한번 써볼까 합니다.

어느 네트워크 관련 인터럽트에서 top half와 bottom half 실행에 각각 t1과 t2가 걸린다고 해보겠습니다. t2는 t1보다 훨씬 길겠죠. 그리고 평균적으로 (t1 + t2) 시간마다 인터럽트가 하나씩 발생한다고 해보겠습니다. top half 실행 후 pending 상태의 bottom half 실행을 하는 방식만을 사용한다고 하면 모든 인터럽트에 대해 top half와 bottom half 모두가 딱 맞게 실행됩니다. 그런데 문제는... 그 동안 다른 작업은 전혀 실행될 수가 없게 된다는 점입니다. 그렇게 실행되지 못하는 작업에는 그 네트워크 인터럽트를 거쳐 들어온 데이터를 처리해야 할 어느 userland 프로세스도 포함되어 있을 겁니다.

반면 ksoftirqd가 등장하게 되면 top half 실행 후 실행 가능한 다른 작업을 찾아보게 됩니다. 물론 실행 가능한 작업이 있어서 실행을 한다고 하더라도 도중에 빈번하게 인터럽트가 발생하겠지만, 그래도 (t1 + t2) 시간마다 t2 시간만큼의 여유가 있으니 그리 나쁘진 않습니다. 모두가 bottom half의 결과 데이터를 기다리고 있거나 해서 더 이상 실행 가능한 작업이 없게 되면 그 때서야 낮은 우선순위를 가진 ksoftirqd가 실행되어 pending 상태의 작업을 수행할 겁니다. 이 방식은 pending 상태의 작업 개수를 상당히 늘일 수 있고, 따라서 큐의 길이가 제한되어 있다면 상당수 인터럽트가 무시되는 결과를 낳을 수 있습니다. 하지만 그럼에도 불구하고, 인터럽트 핸들러만 실행되고 있는 상태와 비교하자면 분명 뭔가가 진행될 수 있도록 해줍니다.

... 이런 거 아닐까요? 인터럽트를 좀 무시하게 되더라도 실제로 필요한 작업을 실행할 수 있기 위한 기회를 만들어 준다, 라는-
----
$PWD `date`

$PWD `date`

swunk의 이미지

제가 좀 헷갈리는 부분이 아래 부분인데요...

"반면 ksoftirqd가 등장하게 되면 top half 실행 후 실행 가능한 다른 작업을 찾아보게 됩니다." 라고 하셨는데...
사실 top half 처리 후 즉, interrupt handler 수행 후 schedule()함수를 호출하기 전에(실행 가능한 다른 작업을 찾아보기 전에) 정확하게는 irq_exit()함수 호출 후에-먼저 pending 되어 있는 softirq가 있는지를 먼저 check를 해서 있으면 그것 먼저 처리한다고 (저는) 알고 있습니다. 그 후에 실행 가능한 다른 작업을 찾아 보겠지요...

그래서 어차피, ksoftirqd 커널 스레드가 스케쥴러에 의해서 선택되기 전에 다시 최소한 10번의 softirq가 수행되기 때문에 ksoftirqd 커널 스레드가 과연 얼마만큼의 의미가 있는가? 라는 의문이 드는 거구요...

일단 ...위에서 말햇듯이 ISR 처리 후에 pending 되어 있는 softirq를 먼저 확인하는 작업이 맞다면 (맞는지 틀린지 알려주세요...책에 보면은 그렇게 한다고 나와 있기는 한데...실제 코드는 어떻게 되남요 ?) 그래도 ksoftirq 커널 스레드가 의미가 있나요 ?

wariua의 이미지

아아... 든든한 자료조사 없는 소설은 역시 성공할 수 없군요. 앞서의 소설은 살짝 잊어주십시오. (아이, 부끄러워랏~)

이런 스토리는 어떨까요?

말씀하셨던 대로 ISR 실행 후 __do_softirq()에서 pending 상태의 softirq를 처리합니다. softirq handler 내에서 몇 번이고 계속해서 softirq를 재요청할 수 있는데, 그게 정도가 심하면 정작 그 softirq handler가 처리한 데이터를 처리할 다른 프로세스가 전혀 실행되지 못할 수 있습니다. 그리하여 pending 상태의 softirq 처리를 최대 10번(MAX_SOFTIRQ_RESTART)까지만 반복한 후에는 그냥 무시하고 진행을 하며, 그렇게 함으로써 계속해서 softirq를 재활성화 하는 softirq handler로 인해 다른 작업이 기아 상태가 되는 걸 피할 수 있습니다. 대기하고 있던 프로세스는 다음 번 인터럽트 발생 시점까지는 실행을 위한 시간을 확보하게 됩니다.

그런데 때에 따라선 10번 반복을 마친 시점에 실행 가능한 작업이 없을 수도 있습니다. 인즉 한가하게 놀고 있던 차에 인터럽트가 하나 날아와서 핸들러를 실행했는데 softirq handler가 계속 반복 실행되며 시간을 끌기에 도중에 적당한 시점에서 중단을 시켜뒀는데, 그러고 나서 살펴보니 실행할 작업도 없고 해서 '괜히 중단시켰네...' 싶은 상태가 되는 거지요. 그러면 다음 인터럽트 핸들러가 실행될 때까지 (최대 1 jiffy 동안) CPU가 딩가딩가 놀게 됩니다. 그럴 때 ksoftirqd 스레드가 있으면 그 스레드가 중단됐던 작업을 계속해서 진행해 줌으로써 그 짜투리 시간을 활용할 수 있게 됩니다.

인즉, 다른 프로세스의 기아를 막으면서도 그로 인해 CPU 시간을 낭비하는 경우가 없도록 하기 위한 절충안 정도가 아닌가 싶습니다.

& 이번 작품은 어떤가요? (퍼벅-)
----
$PWD `date`

$PWD `date`

swunk의 이미지

덕분에 상당 부분 정리가 많이 되었습니다.

한가지 더 의문을 가지자면 "그러면 다음 인터럽트 핸들러가 실행될 때까지 (최대 1 jiffy 동안) CPU가 딩가딩가 놀게 됩니다" 라는 의미는 그 동안에 인터럽트는 발생하지 않았다는 말이고, 다시 말하면 raise_cpu_softirq()함수가 호출되지 않았으므로 pending 되어 있는 softirq 도 없을것 같은데요...

예를 들어서 말씀 드리면, 딩가딩가 논다는 말은 그 동안에 packet 이 하나도 receive 되지 않았다는 말이고, 만약 receive 되었다면 위에서 말했듯이 top_half처리하고 pending 되어 있는 놈이 있으니 softirq 처리를 할것 같은데요...

이런 경우는 있을 수 있겠네요... softirq가 10번 수행 되었는데도 아직 pending된 놈이 존재하고, 스케쥴링이 되어 다른 프로세스들을 처리하는 동안 다른 interrupt가 하나도 발생하지 않는다면 ksoftirq 커널 쓰레드가 없다면 다음번 interrupt가 발생하기 전까지는 cpu가 놀고 있는데도 불구하고 pending 놈을 처리해 줄 수 없다.
글을 적다보니 님께서 하신 말씀이 이런 상황을 설명하신것 같습니다. 맞나요 ? 제가 이해력이 좀 딸려서리... 결국에는 (네트워크 관점에서만 본다면) 이전에 들어온 패킷 하나의 receive event에 대해서 bottom half 처리를 위해 ksoftirqd kernel thread가 존재한다는 의미로 해석이 되는군요... 그 뒤로 들어온 패킷에 대해서는 interrupt가 다시 발생 할 것이고 다시 do_softirq 가 수행될것이니까요..(제가 맞게 이해 했는지 모르겠습니다...--;)

여튼 커널 맹드는 사람들 이렇게 아주 작은것들 까지 신경써서 만든것 보면 대단하다라는 생각이 듭니다.

혼자 이해를 하려고 했으면 고생을 많이 했을것 같은데 님께서 관심있게 답변해 주셔서 나름대로 쉽게 이해를 한 것 같습니다. 고맙습니다.

그런데 wariua 님은 내공이 대단하신것 같은데 어떤일을 하시는 분인지 궁금합니다. 리눅스 커널개발 관련 일을 하시는 분인가요 ? 만일 그렇다면 한가지 더 여쭙고 싶은게 있는데...
커널 관련 개발자 들을 필요로 하는 곳이 얼마나 되는지, 수요가 있는지 궁금합니다. 커널 쪽에 관심을 가지고 일을 하려고 하니 주위 사람들이 하는 말이 "괜히 엄한짓 하지 말고, 응용프로그램쪽으로 파는게 좋을것 같다고" 하도 그러길래 여쭙는 겁니다. 막상 이직/취업 사이트 같은데를 뒤져 봐도 커널 관련해서 사람을 필요로 하는 업체는 별로 없는것 같더라구요 (디바이스 드라이버 관련자들은 많이 찾는거 같기는 하던데)... 특히나 프로토콜 스택쪽으로는 더더욱 없더라구요...제가 네트워크 프로토콜 스택(IPv6, Mobility, QoS 등등..)쪽에 관심을 가지고 있거든요....

그럼 좋은 주말 되시고 가능하다면 답변 부탁드립니다.

wariua의 이미지

오해를 이용한 띄워주기 신공을 시연하시니 기쁜 마음으로 답글을 달아야겠군요 :)

말씀하신 내용 대로라고 생각합니다. 아직 덜 처리한, 하지만 혹시라도 다른 프로세스가 굶게 될까봐 일단 중단시켜 둔 softirq를 조금이라도 여유가 생겼을 때 즉시 처리할 수 있도록 하기 위한 메커니즘이 아닌가 합니다.

하는 일은... 지금은 잠시 쉬고 있습니다만, 네트워크 장비 만드는 데서 잠시 일을 했습니다. 주로 userland에서 놀기는 했지만 일의 특성상 아주 가끔씩은 커널 속을 방황해야 할 때도 있었구요.

커널 개발자에 대한 수요는 느끼고 계신 대로가 아닌가 싶습니다. 어차피 새로운 OS를 만드려는 회사가 아닌 이상 커널 자체에 대한 지식을 필요로 하는 경우는 드물 수밖에 없습니다. 그리고 새로 개발한 장치를 사용해야 해서 디바이스 드라이버를 작성하는 경우가 아니라면 커널을 직접 건드리는 것보다는 기존의 소스 및 패키지를 잘 이용하는 쪽으로 방향을 잡는 경우가 많은 듯합니다. 웬만한 기능들은 이미 리눅스 커널 및 여러 패키지에 갖춰져 있기에 그걸 잘 이용하기만 해도 최고까지는 아니더라도 '쓸만한' 제품을 만드는 데에는 아무 지장이 없으니까요. 거기서 더 나아가 정말로 흐뭇한 네트워크 제품을 만들려고 할 때는 하드웨어에서 커널, 응용까지를 아우르는 기술이 필요하게 될 텐데, 그만한 기술을 필요로 하는 수준의 회사들로는... 글쎄요, 당장은 다산네트워크, 퓨처시스템, 파이오링크 정도가 떠오르는데, 다른 회사들은 저도 잘...;;

기본적인 개발 능력과 해당 분야에 대한 충분한 지식을 갖춘 다음이라면 커널 개발 능력은 당연히 강점이 될 거라 생각합니다. 다만 그걸 강점으로 만들어 주는 수요가 그리 많지 않은 것 또한 분명하니, 처음부터 커널 전담 개발자를 노리실 건지 범용 개발자에서 시작해서 확장하실 건지는 결국 스스로의 판단에 달린 문제인 것 같습니다. (제가 원체 이런 식의 하나마나한 얘기를 좋아합니다... ;)
----
$PWD `date`

$PWD `date`

swunk의 이미지

음 역시..예상했던대로 커널 관련 개발자의 밥그릇이 작군요...

그런데... 제가 나름대로 추측을 하자면,,wibro 를 필두로 하는 3.5G 혹은 4G 환경의 네트워크 환경으로 진화하기 위해서는 All IP 환경으로의 전환은 필수 불가결이라고 생각을 하구요 그 중심에는 IPv6 가 존재한다고 생각합니다.
삼성과 같은 거대 기업에서도 단말기만 열나게 만들다가 이제는 안되겠다 싶다고 생각을 해서인지 아니면 wibro 로 넘어가면서 단말기 뿐만 아니라 시스템 쪽으로도 시장을 장악하기 위해서 인지는 몰라도 "i project"인가 하는 프로젝트를 몇년전 부터 시작을 해서 유비게이트 같은 스위치,라우터 장비를 생산해내기 시작하였고(기존의 삼성이 소극적으로 만들던 네트워크 장비의 개념이 아닌 아주 적극적으로 대쉬를 한다고 들었습니다. 해당 프로젝트의 관리자도 Cisco 에 있던 양반을 데려왔다고 하던데..) 와이브로에서도 (M)IPv6 의 도입이 상당부분 고려되고 있는 것으로 알고 있습니다. 이제는 삼성이 뭘좀 한다고 하면 다르게 들리더군요...

그렇다면 IPv6 엔지니어들, 프로토콜/시스템 관련 엔지니어들에 대한 수요가 상당부분 필요하게 될것이고, 그런 시스템들에서 control plane 쪽은 아무래도 리눅스 기반으로 가지 않을까 하는 생각을 해 보게 됩니다.
그렇게 된다면 리눅스 커널/프로토콜스택/시스템에 대한 이해를 하고 있는 개발자들이 많이 필요하지 않을까 해서 나름대로 준비를 해보자고 해서 시작을 하였는데...
ㅋㅎㅎㅎ 이러다가 죽도 밥도 안되서 쫄쫄 굼는건 아닌지 모르갔습니다. 순간 다 때려치고 동네에서 비디오 가게나 하나 하면서 탱자탱자 살고 싶은 생각이 밀려 드네요...

kwanglink의 이미지

다음과 같이 생각해 보았습니다.
사실 완벽하게 검증을 해 본 것이 아니기 때문에 같이 검토해 보았으면 합니다.

Network card의 RX interrupt 상황에 대해 생각해 보겠습니다.

RX interrupt가 걸려서 pending된 상황에서는 일반적인 NAPI driver 같은 경우 RX interrupt을 disable시켜 놓은 상황입니다. 따라서 가까운 시간 동안에는 다른 interrupt가 걸리지 않는 한 do_softirq가 다시 실행될 가능성은 낮을 것입니다.

do_softirq에서 빠져 나오기 전에 이 pending을 check하여 ksoftirqd를 wake up 시키고 빠져 나오게 됩니다. 이 때 wakup_process가 수행될텐데 이것은 current process의 need_resched를 1로 만들어 주게 될 것입니다. 만약 이 CPU가 idle 상태에 있었다면 바로 schedule에 의해서 ksoftirqd가 수행될 것입니다. 하지만 ksoftirqd는 priority가 낮기 때문에 다른 user process가 수행될 수 있는 조건이 되면 preemption될 것입니다. 즉, ksoftirqd와 같이 낮은 priority의 kernel thread 밑에서 do_softirq가 수행되게 하여 do_softirq에 의해서 starvation이 일어나는 것을 막기 위한 방법이 아닐까 생각됩니다.

pak2536의 이미지

오래된 글이라 리플을 남길까 말까 고민했지만 남깁니다.

사실 간단하게 생각한다면, ksoftirqd가 없다면 softirq의 실행을 트리거해줄 수 있는 수단은 인터럽트와 시스템콜 밖에 없습니다.

이것만 말해도 뒷 내용은 술술 풀려나갈 겁니다. 커널 스레드가 없는 상황에서 위 2가지 트리거만 기대한다면 제대로된 처리가 안될 가능성이 높을 거라고 봅니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.