这段时间看tgt源码,遇到个很闹心的问题:“找不到”函数声明和定义,但是make却不报错。
经过好几个星期,偶然发现了它的藏身之所,跟老师学习了一下,方知有这样的惯用写法,特此mark一下备忘。
1. 先看调用处代码,红色函数找不到定义:
static int iscsi_target_cmd_queue(struct iscsi_task *task)
{
struct scsi_cmd *scmd = &task->scmd;
struct iscsi_connection *conn = task->conn;
struct iscsi_cmd *req = (struct iscsi_cmd *) &task->req;
uint32_t data_len;
uint8_t *ahs;
int ahslen;
int err;
enum data_direction dir = scsi_get_data_dir(scmd);
......
data_len = ntohl(req->data_length);
/* figure out incoming (write) and outgoing (read) sizes */
if (dir == DATA_WRITE || dir == DATA_BIDIRECTIONAL) {
scsi_set_out_length(scmd, data_len);
scsi_set_out_buffer(scmd, task->data);
} else if (dir == DATA_READ) {
scsi_set_in_length(scmd, data_len);
scsi_set_in_buffer(scmd, task->data);
}
}
2. 在另一个头文件中,有如下宏定义:
struct scsi_cmd {
struct target *c_target;
/* linked it_nexus->cmd_hash_list */
struct list_head c_hlist;
struct list_head qlist;
uint64_t dev_id;
struct scsi_lu *dev;
unsigned long state;
enum data_direction data_dir;
struct scsi_data_buffer in_sdb;
struct scsi_data_buffer out_sdb;
uint64_t cmd_itn_id;
uint64_t offset;
uint32_t tl;
uint8_t *scb;
int scb_len;
uint8_t lun[8];
int attribute;
uint64_t tag;
int result;
struct mgmt_req *mreq;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
int sense_len;
struct list_head bs_list;
struct it_nexus *it_nexus;
struct it_nexus_lu_info *itn_lu_info;
};
#define scsi_cmnd_accessor(field, type) \
static inline void scsi_set_##field(struct scsi_cmd *scmd, type val) \
{ \
scmd->field = val; \
} \
static inline type scsi_get_##field(struct scsi_cmd *scmd) \
{ \
return scmd->field; \
}
scsi_cmnd_accessor(result, int);
scsi_cmnd_accessor(data_dir, enum data_direction);
#define scsi_data_buffer_accessor(field, type, set_cast, get_cast) \
scsi_data_buffer_function(in, field, type, set_cast, get_cast) \
scsi_data_buffer_function(out, field, type, set_cast, get_cast)
#define scsi_data_buffer_function(dir, field, type, set_cast, get_cast) \
static inline void scsi_set_##dir##_##field(struct scsi_cmd *scmd, type val) \
{ \
scmd->dir##_sdb.field = set_cast (val); \
} \
static inline type scsi_get_##dir##_##field(struct scsi_cmd *scmd) \
{ \
return get_cast (scmd->dir##_sdb.field); \
}
scsi_data_buffer_accessor(length, uint32_t, ,);
scsi_data_buffer_accessor(transfer_len, uint32_t, ,);
scsi_data_buffer_accessor(resid, int32_t, ,);
scsi_data_buffer_accessor(buffer, void *, (unsigned long), (void *)(unsigned long));
3. 将此宏展开来之后,总算是找到函数定义了:
gcc -E usr/scsi_cmnd.h -o temp.h
less temp.h:
static inline void scsi_set_result(struct scsi_cmd *scmd, int val) {
scmd->result = val;
}
static inline int scsi_get_result(struct scsi_cmd *scmd) {
return scmd->result;
};
static inline void scsi_set_data_dir(struct scsi_cmd *scmd, enum data_direction val) {
scmd->data_dir = val;
}
static inline enum data_direction scsi_get_data_dir(struct scsi_cmd *scmd) {
return scmd->data_dir;
};
static inline void scsi_set_in_length(struct scsi_cmd *scmd, uint32_t val) {
scmd->in_sdb.length = (val);
}
static inline uint32_t scsi_get_in_length(struct scsi_cmd *scmd) {
return (scmd->in_sdb.length);
}
static inline void scsi_set_out_length(struct scsi_cmd *scmd, uint32_t val) {
scmd->out_sdb.length = (val);
}
static inline uint32_t scsi_get_out_length(struct scsi_cmd *scmd) {
return (scmd->out_sdb.length);
};
static inline void scsi_set_in_transfer_len(struct scsi_cmd *scmd, uint32_t val) {
scmd->in_sdb.transfer_len = (val);
}
static inline uint32_t scsi_get_in_transfer_len(struct scsi_cmd *scmd) {
return (scmd->in_sdb.transfer_len);
}
static inline void scsi_set_out_transfer_len(struct scsi_cmd *scmd, uint32_t val) {
scmd->out_sdb.transfer_len = (val);
}
static inline uint32_t scsi_get_out_transfer_len(struct scsi_cmd *scmd) {
return (scmd->out_sdb.transfer_len);
};
static inline void scsi_set_in_resid(struct scsi_cmd *scmd, int32_t val) {
scmd->in_sdb.resid = (val);
}
static inline int32_t scsi_get_in_resid(struct scsi_cmd *scmd) {
return (scmd->in_sdb.resid);
}
static inline void scsi_set_out_resid(struct scsi_cmd *scmd, int32_t val) {
scmd->out_sdb.resid = (val);
}
static inline int32_t scsi_get_out_resid(struct scsi_cmd *scmd) {
return (scmd->out_sdb.resid);
};
static inline void scsi_set_in_buffer(struct scsi_cmd *scmd, void * val) {
scmd->in_sdb.buffer = (unsigned long) (val);
}
static inline void * scsi_get_in_buffer(struct scsi_cmd *scmd) {
return (void *)(unsigned long) (scmd->in_sdb.buffer);
}
static inline void scsi_set_out_buffer(struct scsi_cmd *scmd, void * val) {
scmd->out_sdb.buffer = (unsigned long) (val);
}
static inline void * scsi_get_out_buffer(struct scsi_cmd *scmd) {
return (void *)(unsigned long) (scmd->out_sdb.buffer);
};
4.总结一下,关键的宏定义如下:
#define scsi_cmnd_accessor(field, type) \
static inline void scsi_set_##field(struct scsi_cmd *scmd, type val) \
{ \
scmd->field = val; \
} \
static inline type scsi_get_##field(struct scsi_cmd *scmd) \
{ \
return scmd->field; \
}
这里定义了一个成员的get和set函数,通过宏参数将成员名和成员类型传入。
然后通过宏调用来为result和data_dir两个字段生成getter和setter:
scsi_cmnd_accessor(result, int);
scsi_cmnd_accessor(data_dir, enum data_direction);
后续需要增加其他字段时,只需修改struct,增加新字段的宏调用,即可很方便的生成getter和setter。
很赞的方法!