/* Bundle together everything required to process a request in one memory *allocation.
*/ struct w1_cb_block {
atomic_t refcnt;
u32 portid; /* Sending process port ID */ /* maximum value for first_cn->len */
u16 maxlen; /* pointers to building up the reply message */ struct cn_msg *first_cn; /* fixed once the structure is populated */ struct cn_msg *cn; /* advances as cn_msg is appeneded */ struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */ struct w1_netlink_cmd *cmd; /* advances as cmds are appened */ struct w1_netlink_msg *cur_msg; /* currently message being processed */ /* copy of the original request follows */ struct cn_msg request_cn; /* followed by variable length: *cn_msg,data(w1_netlink_msgandw1_netlink_cmd) *oneormorestructw1_cb_node *replyfirst_cn,data(w1_netlink_msgandw1_netlink_cmd)
*/
}; struct w1_cb_node { struct w1_async_cmd async; /* pointers within w1_cb_block and cn data */ struct w1_cb_block *block; struct w1_netlink_msg *msg; struct w1_slave *sl; struct w1_master *dev;
};
/* Append cmd to msg, include cmd->data as well. This is because *anyfollowingdatagoeswiththecommandandinthecaseofareadis *theresults.
*/ staticvoid w1_netlink_queue_cmd(struct w1_cb_block *block, struct w1_netlink_cmd *cmd)
{
u32 space;
w1_reply_make_space(block, sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len);
/* There's a status message sent after each command, so no point *intryingtobundlethiscmdafteranexistingone,because *therewon'tbeone.Allocateandcopyoveranewcn_msg.
*/
w1_netlink_setup_msg(block, block->request_cn.seq + 1);
memcpy(block->msg, block->cur_msg, sizeof(*block->msg));
block->cn->len += sizeof(*block->msg);
block->msg->len = 0;
block->cmd = (struct w1_netlink_cmd *)(block->msg->data);
space = sizeof(*cmd) + cmd->len; if (block->cmd != cmd)
memcpy(block->cmd, cmd, space);
block->cn->len += space;
block->msg->len += space;
}
/* Append req_msg and req_cmd, no other commands and no data from req_cmd are *copied.
*/ staticvoid w1_netlink_queue_status(struct w1_cb_block *block, struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd, int error)
{
u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd);
w1_reply_make_space(block, space);
w1_netlink_setup_msg(block, block->request_cn.ack);
/* Get the current slave list, or search (with or without alarm) */ staticint w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd)
{ struct w1_slave *sl;
/* drop bus_mutex for search (does it's own locking), and add/remove *whichdoesn'tusethebus
*/ switch (req_cmd->cmd) { case W1_CMD_SEARCH: case W1_CMD_ALARM_SEARCH: case W1_CMD_LIST_SLAVES:
mutex_unlock(&dev->bus_mutex);
err = w1_get_slaves(dev, req_cmd);
mutex_lock(&dev->bus_mutex); break; case W1_CMD_READ: case W1_CMD_WRITE: case W1_CMD_TOUCH:
err = w1_process_command_io(dev, req_cmd); break; case W1_CMD_RESET:
err = w1_reset_bus(dev); break; case W1_CMD_SLAVE_ADD: case W1_CMD_SLAVE_REMOVE:
mutex_unlock(&dev->bus_mutex);
mutex_lock(&dev->mutex);
err = w1_process_command_addremove(dev, req_cmd);
mutex_unlock(&dev->mutex);
mutex_lock(&dev->bus_mutex); break; default:
err = -EINVAL; break;
}
if (!cmd || err)
w1_netlink_queue_status(node->block, node->msg, cmd, err);
/* ref taken in w1_search_slave or w1_search_master_id when building *theblock
*/ if (sl)
w1_unref_slave(sl); else
atomic_dec(&dev->refcnt);
dev->priv = NULL;
mutex_unlock(&dev->bus_mutex);
/* If any unknown flag is set let the application know, that way *applicationscandetecttheabsenceoffeaturesinkernelsthat *don'tknowaboutthem.http://lwn.net/Articles/587527/
*/ if (cn->flags & ~(W1_CN_BUNDLE)) {
w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL); return;
}
/* Count the number of master or slave commands there are to allocate *spaceforonecb_nodeeach.
*/
msg_len = cn->len; while (msg_len && !err) { if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
err = -E2BIG; break;
}
/* count messages for nodes and allocate any additional space *requiredforslavelists
*/ if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) {
++node_count;
w1_list_count_cmds(msg, &cmd_count, &slave_len);
}
msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
msg = (struct w1_netlink_msg *)(((u8 *)msg) + sizeof(struct w1_netlink_msg) + msg->len);
}
msg = (struct w1_netlink_msg *)(cn + 1); if (node_count) { int size; int reply_size = sizeof(*cn) + cn->len + slave_len; if (cn->flags & W1_CN_BUNDLE) { /* bundling duplicats some of the messages */
reply_size += 2 * cmd_count * (sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd));
}
reply_size = min(CONNECTOR_MAX_MSG_SIZE, reply_size);
/* allocate space for the block, a copy of the original message, *onenodepercmdtopointintotheoriginalmessage, *spaceforreplieswhichistheoriginalmessagesizeplus *spaceforanylistslavedataandstatusmessages *cn->lendoesn'tincludeitselfwhichispartoftheblock
* */
size = /* block + original message */ sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len + /* space for nodes */
node_count * sizeof(struct w1_cb_node) + /* replies */ sizeof(struct cn_msg) + reply_size;
block = kzalloc(size, GFP_KERNEL); if (!block) { /* if the system is already out of memory, *(A)willthiswork,and(B)woulditbebetter *tonottry?
*/
w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM); return;
}
atomic_set(&block->refcnt, 1);
block->portid = nsp->portid;
block->request_cn = *cn;
memcpy(block->request_cn.data, cn->data, cn->len);
node = (struct w1_cb_node *)(block->request_cn.data + cn->len);
/* Sneeky, when not bundling, reply_size is the allocated space *requiredforthereply,cn_msgisn'tpartofmaxlenso *itshouldbereply_size-sizeof(structcn_msg),however *whencheckingifthereisenoughspace,w1_reply_make_space *iscalledwiththefullmessagesizeincludingcn_msg, *becauseitisn'tknownatthattimeifanadditionalcn_msg *willneedtobeallocated.Soanextracn_msgisadded *abovein"size".
*/
block->maxlen = reply_size;
block->first_cn = (struct cn_msg *)(node + node_count);
memset(block->first_cn, 0, sizeof(*block->first_cn));
}
/* execute on this thread, no need to process later */ if (msg->type == W1_LIST_MASTERS) {
err = w1_process_command_root(cn, nsp->portid); goto out_cont;
}
/* All following message types require additional data, *checkherebeforereferencesaretaken.
*/ if (!msg->len) {
err = -EPROTO; goto out_cont;
}
/* both search calls take references */ if (msg->type == W1_MASTER_CMD) {
dev = w1_search_master_id(msg->id.mst.id);
} elseif (msg->type == W1_SLAVE_CMD) {
sl = w1_search_slave((struct w1_reg_num *)msg->id.id); if (sl)
dev = sl->master;
} else {
pr_notice("%s: cn: %x.%x, wrong type: %u, len: %u.\n",
__func__, cn->id.idx, cn->id.val,
msg->type, msg->len);
err = -EPROTO; goto out_cont;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.