iscsi kernel 모듈 - 네트워크 부분
인터페이스가 ioctl인데 뭐라고 정의할 게 없어요. 상하문에 static DECLAREMUTEX(ioctl_sem); 한 번에 하나의 ioctl만 호출할 수 있도록 제한하는 데 주로
Session/Conn/volume 추가 Param 구성 수정 사항 감소
잠깐 볼게요. iet.socket_bind
struct iscsi_conn {
struct list_head list; /* list entry in session list */
struct iscsi_session *session; /* owning session */
u16 cid;
unsigned long state;
u32 stat_sn;
u32 exp_stat_sn;
int hdigest_type;
int ddigest_type;
struct list_head poll_list;
struct file *file;
/* BSD socket socket->sk*/
struct socket *sock;
//...
};
static void iet_socket_bind(struct iscsi_conn *conn)
{
int opt = 1;
mm_segment_t oldfs;
struct iscsi_session *session = conn->session;
struct iscsi_target *target = session->target;
dprintk(D_GENERIC, "%llu
", (unsigned long long) session->sid);
/*userspace struct file sock */
conn->sock = SOCKET_I(conn->file->f_dentry->d_inode);
conn->sock->sk->sk_user_data = conn;
/* iscsi socket , kernel */
write_lock_bh(&conn->sock->sk->sk_callback_lock);
/*sk_state_change: callback to indicate change in the state of the sock*/
target->nthread_info.old_state_change = conn->sock->sk->sk_state_change;
conn->sock->sk->sk_state_change = iet_state_change;
/*sk_data_ready: callback to indicate there is data to be processed*/
target->nthread_info.old_data_ready = conn->sock->sk->sk_data_ready;
conn->sock->sk->sk_data_ready = iet_data_ready;
target->nthread_info.old_write_space = conn->sock->sk->sk_write_space;
conn->sock->sk->sk_write_space = iet_write_space;
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
/* int kernel_setsockopt(struct socket *sock, int level, int optname,
char *optval, unsigned int optlen)*/
oldfs = get_fs();
set_fs(get_ds());
conn->sock->ops->setsockopt(conn->sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt));
set_fs(oldfs);
}
매우 유명한 함수: 최적화의 원천voidsockinit_데이터(struct socket*sock,struct sock*sk) 초기화 sock 구조 및 IP 관련 확장 가능한 인터페이스 부분
void sock_init_data(struct socket *sock, struct sock *sk)
{
//...
sk->sk_state_change = sock_def_wakeup;
/* wake_up_interruptible_sync_poll socket_wq CPU*/
sk->sk_data_ready = sock_def_readable;
sk->sk_write_space = sock_def_write_space;
sk->sk_error_report = sock_def_error_report;
sk->sk_destruct = sock_def_destruct;
//...
}
struct socket_wq {
wait_queue_head_t wait;
struct fasync_struct *fasync_list;
struct rcu_head rcu;
} ____cacheline_aligned_in_smp;
static void sock_def_wakeup(struct sock *sk)
{
struct socket_wq *wq;
rcu_read_lock();
wq = rcu_dereference(sk->sk_wq);
/* ture*/
if (wq_has_sleeper(wq))
wake_up_interruptible_all(&wq->wait);
rcu_read_unlock();
}
static void iet_data_ready(struct sock*sk, int len) {struct iscsi conn*conn = sk->sk user data;struct iscsi target*target=conn->session->target;/*는 wake up process(info->task)를 호출하고, struct task struct *task;;가 일어나 처리하라고 알린다*/nthread wakeup(target), target->nthread infoldsk realdy reale}
static int is_data_available(struct iscsi_conn *conn){ int avail, res; mm_segment_t oldfs; struct socket *sock = conn->sock;
oldfs = get_fs(); set_fs(get_ds());/*여기 작가가 게으르네요. 직접 FIONREAD를 통해 데이터 상황을 얻을 수 있어요. */res = sock->ops->ioctl(sock,SIOCINQ,(unsigned long) &avail). set_fs(oldfs); return (res >= 0) ? avail : res;}
다음은 addconnstatic int add_conn(struct iscsi target*target, unsigned long ptr) {//...err = copy from user(&info, (void*) ptr, sizeof(info);if(err) return-EFAULT;/* 대응 세션 찾기*/session = session lookup(target, info.sid);if(!session) return-ENOENT;return conaddursension, info &
int conn_dd(struct iscsi session *session, struct conn info *info) {//.../* 있으면 삭제하고 재생성 */conn = conn lookup(session, info->cid), if(conn) conn close(conn);
err = iet_conn_alloc(session, info); if (!err && conn) err = -EEXIST;
return err;}
iet_conn_alloc 초기화 iscsiconn 구조체, 모든 핵심 조작과 관련static int ietconn_alloc(struct iscsi_session *session, struct conn_info *info){ struct iscsi_conn *conn;
dprintk(D_SETUP, "%#Lx:%u", (unsigned long long) session->sid, info->cid);
conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) return -ENOMEM;
//... spin_lock_init(&conn->list_lock); atomic_set(&conn->nr_cmnds, 0); atomic_set(&conn->nr_busy_cmnds, 0); INIT_LIST_HEAD(&conn->pdu_list); INIT_LIST_HEAD(&conn->write_list); INIT_LIST_HEAD(&conn->poll_list); init_timer(&conn->nop_timer);/*연결 제한 시간*/
list_add(&conn->list, &session->conn_list);
set_bit(CONN_ACTIVE, &conn->state);/* 사용자 공간에 구축된 연결 전송 처리 */conn->file = fget(info->fd); iet_socket_bind(conn);/*이session의 활성화 링크에 자신을 추가합니다 */listadd(&conn->poll_list, &session->target->nthread_info.active_conns);
nthread_wakeup(conn->session->target);
return 0;}
add_session()->session_add()-> iet_session_alloc
위와 유사하지만 명령을 만드는hash수 그룹 체인 테이블
{//...for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++) INIT_LIST_HEAD(&session->cmnd_hash[i]);
spin_lock_init(&session->ua_hash_lock); for (i = 0; i < ARRAY_SIZE(session->ua_hash); i++) INIT_LIST_HEAD(&session->ua_hash[i]);
list_for_each_entry(vol, &target->volumes, list) /* power-on, reset, or bus device reset occurred */ ua_establish_for_session(session, vol->lun, 0x29, 0x0);//...
}
그리고 일의 진행을 보도록 하겠습니다.
static long ioctl(struct file *file, unsigned int cmd, unsigned long arg){//... if (cmd == ADD_TARGET) { err = add_target(arg); goto done; }//... }
add_target() -> 사용자를 통해 target 참여info 초기화 targetadd () -> 필요한 검사 iscsitarget_create()->target 라인 시작 구조체 초기화 targetthread_start()->
int nthread_start(struct iscsi_target *target){//...
task = kthread_run(istd, target, "istd%d", target->tid);//...}
이것은 가장 중요한 백그라운드 프로세스이다
static int istd(void *arg)
{
struct iscsi_target *target = arg;
struct network_thread_info *info = &target->nthread_info;
struct iscsi_conn *conn, *tmp;
/* */
__set_current_state(TASK_RUNNING);
do {
spin_lock_bh(&info->nthread_lock);
__set_current_state(TASK_INTERRUPTIBLE);
/* ( , )*/
if (!test_bit(D_DATA_READY, &info->flags)) {
spin_unlock_bh(&info->nthread_lock);
schedule();
spin_lock_bh(&info->nthread_lock);
}
__set_current_state(TASK_RUNNING);
clear_bit(D_DATA_READY, &info->flags);
spin_unlock_bh(&info->nthread_lock);
target_lock(target, 0);
list_for_each_entry_safe(conn, tmp, &info->active_conns, poll_list) {
if (test_bit(CONN_ACTIVE, &conn->state))
process_io(conn);/* IO */
else
close_conn(conn);
}
target_unlock(target);
} while (!kthread_should_stop());
return 0;
}
먼저 socket->ops의 함수 포인터 구조를 되돌아봅시다
struct proto_ops {
//...
ssize_t (*sendpage) (struct socket *sock, struct page *page,
int offset, size_t size, int flags);
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
//
...
} tcp4에서는 주로 struct proto tcpprot = { .sendpage = tcp_sendpage,
}
Tcp_sendpage 즉 Dotcp_sendpages 먼저 페이지를 분리한 후 skwrite_queue에서 필요에 따라 통과tcp_push_pending_frames tcppush_원 (한 페이지 머리) 발송.
static void process_io(struct iscsi_conn *conn)
{
struct iscsi_target *target = conn->session->target;
int res, wakeup = 0;
/* */
res = recv(conn);
//...
/* */
res = send(conn);
/* */
if (!list_empty(&conn->write_list) || conn->write_cmnd) {
conn_reset_nop_timer(conn);
wakeup = 1;
}
//...
return;
}
함수 쉬워요. 할 말 없어요. recv 봐요.
static int recv(struct iscsi_conn *conn) --> case RX_DATA: do_recv()
여기 작가님은 아직 게으르세요.
직접res = sockrecvmsg(conn->sock, &msg, len, MSG_DONTWAIT | MSG_NOSIGNAL);
그 다음은 send static int send(struct iscsi conn *conn)-> 먼저case TXINIT:cmnd_tx_start(cmnd); case ISCSI_OP_SCSI_RSP:
static void cmnd_send_pdu(struct iscsi conn *conn, struct iscsi cmnd *cmnd)는 iscsiconn-> write_tcmnd->tio 이tio는 다음do 를 통과합니다send()--->write_데이터 () -->sendpage 보내기
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.