From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
To: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Xenomai <xenomai@xenomai.org>
Subject: Re: [Xenomai] forge: Trying to understand new semaphore code
Date: Mon, 16 Dec 2013 19:33:40 +0100 [thread overview]
Message-ID: <52AF4784.8030801@xenomai.org> (raw)
In-Reply-To: <52AF4211.80203@siemens.com>
On 12/16/2013 07:10 PM, Jan Kiszka wrote:
> Hi Gilles,
>
> while rebasing my half-done ftrace instrumentation over next, I got
> stuck reading nsem_open. Find my questions inline:
>
>> static struct __shadow_sem __user *
>> nsem_open(struct __shadow_sem __user *ushadow, const char *name,
>> int oflags, mode_t mode, unsigned value)
>> {
>> struct __shadow_sem shadow;
>> struct cobalt_sem *sem;
>> struct nsem *u, *v;
>> xnhandle_t handle;
>> spl_t s;
>> int rc;
>>
>> trace_xn_sys_sem_open(name, oflags, mode, value);
>>
>> if (name[0] != '/' || name[1] == '\0')
>> return ERR_PTR(-EINVAL);
>>
>> retry_bind:
>> rc = xnregistry_bind(&name[1], XN_NONBLOCK, XN_RELATIVE, &handle);
>> switch (rc) {
>> case 0:
>> /* Found */
>> if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
>> return ERR_PTR(-EEXIST);
>>
>> xnlock_get_irqsave(&nsem_lock, s);
>> u = nsem_hash_search(handle, current->mm);
>> if (u) {
>> ++u->refs;
>> xnlock_put_irqrestore(&nsem_lock, s);
>> return u->usem;
>> }
>> xnlock_put_irqrestore(&nsem_lock, s);
>>
>> xnlock_get_irqsave(&nklock, s);
>> sem = xnregistry_fetch(handle);
>> if (sem && sem->magic != COBALT_SEM_MAGIC) {
>> xnlock_put_irqrestore(&nklock, s);
>> return ERR_PTR(-EINVAL);
>> }
>>
>> if (sem) {
>> ++sem->refs;
>> xnlock_put_irqrestore(&nklock, s);
>> } else {
>> xnlock_put_irqrestore(&nklock, s);
>> goto retry_bind;
>> }
>> break;
>>
>> case -EWOULDBLOCK:
>> /* Not found */
>> if ((oflags & O_CREAT) == 0)
>> return ERR_PTR(-ENOENT);
>>
>> rc = cobalt_sem_init_inner
>> (&name[1], &shadow, SEM_PSHARED, value);
>> if (rc < 0) {
>> if (rc == -EEXIST)
>> goto retry_bind;
>> return ERR_PTR(rc);
>> }
>>
>> if (__xn_safe_copy_to_user(ushadow, &shadow, sizeof(shadow))) {
>> cobalt_sem_destroy_inner(shadow.handle);
>> return ERR_PTR(-EFAULT);
>> }
>> handle = shadow.handle;
>> sem = xnregistry_fetch(handle);
>> ++sem->refs;
>
> Why doesn't this lookup and referencing require nklock protection? After
> cobalt_sem_init_inner, sem is now globally visible, so someone else
> (like a competing nsem_open) could fetch it and reference it, no?
The idea was that the semaphore is new and "nobody knows it yet", but
then the xnregistry_enter was moved inside cobalt_sem_inner, which
breaks this assumption. I need to rethink about this code, indeed. That
said, the xnregistry_fetch can not fail, the current code holds a
reference to the sem structure, and any concurrent bind will have
incremented the reference counter, a decrement of the reference counter
can only correspond to a previous increment. The simplest solution is to
set the reference counter to 2 instead of 1 inside cobalt_sem_init_inner
when the semaphore is named.
>
>> }
>>
>> u = xnmalloc(sizeof(*u));
>> if (u == NULL)
>> return ERR_PTR(-ENOMEM);
>>
>> u->sem = sem;
>> u->mm = current->mm;
>> u->usem = ushadow;
>> u->refs = 1;
>>
>> xnlock_get_irqsave(&nsem_lock, s);
>> v = nsem_hash_search(handle, current->mm);
>> if (v) {
>> ++v->refs;
>> xnlock_put_irqrestore(&nsem_lock, s);
>> xnlock_get_irqsave(&nklock, s);
>> --sem->refs;
>> xnlock_put_irqrestore(&nklock, s);
>>
>> if (rc == -EWOULDBLOCK)
>> cobalt_sem_destroy_inner(sem->handle);
>
> I'm still not sure I fully understand the reason (and safety) of this
> release. We get here when we lost the race to enter handle in the
> current process' nsem hash table, right? So v != u, ok. But both v and u
> must point to a sem object with the same handle value, otherwise they
> wouldn't end up in the same hash table slot.
This part of the code is useless. When we reach this code, we have got
one sem, one way or another corresponding to the opened name, the thing
this code is trying to prevent is the concurrent creation of another
nsem structure for the same handle (and the same process). There is no
reason to destroy the semaphore, which is necessarily valid. There is
only one semaphore.
Note that the corresponding code for file descriptors will be simpler:
what makes things complicated here is that it is required by the POSIX
specification that two sem_open with the same name return the sem_t
pointer for the same process.
--
Gilles.
next prev parent reply other threads:[~2013-12-16 18:33 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-16 18:10 [Xenomai] forge: Trying to understand new semaphore code Jan Kiszka
2013-12-16 18:33 ` Gilles Chanteperdrix [this message]
2013-12-16 22:27 ` Gilles Chanteperdrix
2013-12-17 8:10 ` Philippe Gerum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52AF4784.8030801@xenomai.org \
--to=gilles.chanteperdrix@xenomai.org \
--cc=jan.kiszka@siemens.com \
--cc=xenomai@xenomai.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.