On Mon, 2024-04-08 at 08:24 -0700, Yonghong Song wrote: [...] > +/* Handle the following two cases: > + * case 1: link != NULL, prog != NULL, old != NULL > + * case 2: link != NULL, prog != NULL, old == NULL > + */ > +static int sock_map_link_update_prog(struct bpf_link *link, > + struct bpf_prog *prog, > + struct bpf_prog *old) > +{ > + const struct sockmap_link *sockmap_link = container_of(link, struct sockmap_link, link); > + struct bpf_prog **pprog, *old_link_prog; > + struct bpf_link **plink; > + int ret = 0; > + > + mutex_lock(&sockmap_mutex); > + > + /* If old prog is not NULL, ensure old prog is the same as link->prog. */ > + if (old && link->prog != old) { > + ret = -EPERM; > + goto out; > + } > + /* Ensure link->prog has the same type/attach_type as the new prog. */ > + if (link->prog->type != prog->type || > + link->prog->expected_attach_type != prog->expected_attach_type) { > + ret = -EINVAL; > + goto out; > + } > + > + ret = sock_map_prog_link_lookup(sockmap_link->map, &pprog, &plink, > + sockmap_link->attach_type); > + if (ret) > + goto out; > + > + /* return error if the stored bpf_link does not match the incoming bpf_link. */ > + if (link != *plink) > + return -EBUSY; Hi Yonghong, Sorry, this was a mistake on my side, this needs a 'goto out' in order to unlock the mutex. Thanks, Eduard > + > + if (old) { > + ret = psock_replace_prog(pprog, prog, old); > + if (ret) > + goto out; > + } else { > + psock_set_prog(pprog, prog); > + } > + > + bpf_prog_inc(prog); > + old_link_prog = xchg(&link->prog, prog); > + bpf_prog_put(old_link_prog); > + > +out: > + mutex_unlock(&sockmap_mutex); > + return ret; > +}