mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
sd-rtnl: message - don't reference associated rtnl object
The object is not currently used, so just drop the refenence. If/when we end up using the object in the future, we must make sure to deal with possible mutual references between rtnl busses and their queued messages; as is done in sd-bus.
This commit is contained in:
parent
bf81e792f3
commit
8c57830308
@ -46,6 +46,11 @@ int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size) {
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
|
||||
|
||||
/* Note that 'rtnl' is curretly unused, if we start using it internally
|
||||
we must take care to avoid problems due to mutual references between
|
||||
busses and their queued messages. See sd-bus.
|
||||
*/
|
||||
|
||||
m = new0(sd_rtnl_message, 1);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
@ -61,9 +66,6 @@ int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size) {
|
||||
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
m->sealed = false;
|
||||
|
||||
if (rtnl)
|
||||
m->rtnl = sd_rtnl_ref(rtnl);
|
||||
|
||||
*ret = m;
|
||||
|
||||
return 0;
|
||||
@ -275,7 +277,6 @@ sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
|
||||
if (m && REFCNT_DEC(m->n_ref) <= 0) {
|
||||
unsigned i;
|
||||
|
||||
sd_rtnl_unref(m->rtnl);
|
||||
free(m->hdr);
|
||||
|
||||
for (i = 0; i < m->n_containers; i++)
|
||||
|
@ -104,6 +104,9 @@ int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
|
||||
}
|
||||
|
||||
sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
|
||||
assert_return(rtnl, NULL);
|
||||
assert_return(!rtnl_pid_changed(rtnl), NULL);
|
||||
|
||||
if (rtnl)
|
||||
assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
|
||||
|
||||
@ -111,88 +114,40 @@ sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
|
||||
}
|
||||
|
||||
sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
|
||||
unsigned long refs;
|
||||
|
||||
if (!rtnl)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If our ref-cnt is exactly the number of internally queued messages
|
||||
* plus the ref-cnt to be dropped, then we know there's no external
|
||||
* reference to us. Hence, we look through all queued messages and if
|
||||
* they also have no external references, we're about to drop the last
|
||||
* ref. Flush the queues so the REFCNT_DEC() below will drop to 0.
|
||||
* We must be careful not to introduce inter-message references or this
|
||||
* logic will fall apart..
|
||||
*/
|
||||
assert_return(!rtnl_pid_changed(rtnl), NULL);
|
||||
|
||||
refs = rtnl->rqueue_size + rtnl->wqueue_size + 1;
|
||||
|
||||
if (REFCNT_GET(rtnl->n_ref) <= refs) {
|
||||
if (REFCNT_DEC(rtnl->n_ref) <= 0) {
|
||||
struct match_callback *f;
|
||||
bool q = true;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < rtnl->rqueue_size; i++) {
|
||||
if (REFCNT_GET(rtnl->rqueue[i]->n_ref) > 1) {
|
||||
q = false;
|
||||
break;
|
||||
} else if (rtnl->rqueue[i]->rtnl != rtnl)
|
||||
--refs;
|
||||
for (i = 0; i < rtnl->rqueue_size; i++)
|
||||
sd_rtnl_message_unref(rtnl->rqueue[i]);
|
||||
free(rtnl->rqueue);
|
||||
|
||||
for (i = 0; i < rtnl->wqueue_size; i++)
|
||||
sd_rtnl_message_unref(rtnl->wqueue[i]);
|
||||
free(rtnl->wqueue);
|
||||
|
||||
hashmap_free_free(rtnl->reply_callbacks);
|
||||
prioq_free(rtnl->reply_callbacks_prioq);
|
||||
|
||||
sd_event_source_unref(rtnl->io_event_source);
|
||||
sd_event_source_unref(rtnl->time_event_source);
|
||||
sd_event_source_unref(rtnl->exit_event_source);
|
||||
sd_event_unref(rtnl->event);
|
||||
|
||||
while ((f = rtnl->match_callbacks)) {
|
||||
LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
|
||||
free(f);
|
||||
}
|
||||
|
||||
if (q) {
|
||||
for (i = 0; i < rtnl->wqueue_size; i++) {
|
||||
if (REFCNT_GET(rtnl->wqueue[i]->n_ref) > 1) {
|
||||
q = false;
|
||||
break;
|
||||
} else if (rtnl->wqueue[i]->rtnl != rtnl)
|
||||
--refs;
|
||||
}
|
||||
}
|
||||
|
||||
if (q && REFCNT_GET(rtnl->n_ref) == refs) {
|
||||
/* Drop our own ref early to avoid recursion from:
|
||||
* sd_rtnl_message_unref()
|
||||
* sd_rtnl_unref()
|
||||
* These must enter sd_rtnl_unref() with a ref-cnt
|
||||
* smaller than us. */
|
||||
REFCNT_DEC(rtnl->n_ref);
|
||||
|
||||
for (i = 0; i < rtnl->rqueue_size; i++)
|
||||
sd_rtnl_message_unref(rtnl->rqueue[i]);
|
||||
free(rtnl->rqueue);
|
||||
|
||||
for (i = 0; i < rtnl->wqueue_size; i++)
|
||||
sd_rtnl_message_unref(rtnl->wqueue[i]);
|
||||
free(rtnl->wqueue);
|
||||
|
||||
assert_se(REFCNT_GET(rtnl->n_ref) == 0);
|
||||
|
||||
hashmap_free_free(rtnl->reply_callbacks);
|
||||
prioq_free(rtnl->reply_callbacks_prioq);
|
||||
|
||||
while ((f = rtnl->match_callbacks)) {
|
||||
LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
|
||||
free(f);
|
||||
}
|
||||
|
||||
safe_close(rtnl->fd);
|
||||
|
||||
sd_event_source_unref(rtnl->io_event_source);
|
||||
sd_event_source_unref(rtnl->time_event_source);
|
||||
sd_event_source_unref(rtnl->exit_event_source);
|
||||
sd_event_unref(rtnl->event);
|
||||
|
||||
free(rtnl);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
safe_close(rtnl->fd);
|
||||
free(rtnl);
|
||||
}
|
||||
|
||||
assert_se(REFCNT_GET(rtnl->n_ref) > 0);
|
||||
REFCNT_DEC(rtnl->n_ref);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user