* [Xenomai] forge: Trying to understand new semaphore code @ 2013-12-16 18:10 Jan Kiszka 2013-12-16 18:33 ` Gilles Chanteperdrix 0 siblings, 1 reply; 4+ messages in thread From: Jan Kiszka @ 2013-12-16 18:10 UTC (permalink / raw) To: Gilles Chanteperdrix; +Cc: Xenomai 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? > } > > 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. But which of those sem objects is now registered with the xnregistry? I mean, is this destroy really working on the right one, the one we created in the current context? > > xnfree(u); > u = v; > } else { > nsem_hash_enter(handle, u); > list_add(&u->link, &cobalt_process_context()->usems); > xnlock_put_irqrestore(&nsem_lock, s); > } > > trace_xn_sys_sem_open_return(handle); > > return u->usem; > } Jan -- Siemens AG, Corporate Technology, CT RTC ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Xenomai] forge: Trying to understand new semaphore code 2013-12-16 18:10 [Xenomai] forge: Trying to understand new semaphore code Jan Kiszka @ 2013-12-16 18:33 ` Gilles Chanteperdrix 2013-12-16 22:27 ` Gilles Chanteperdrix 0 siblings, 1 reply; 4+ messages in thread From: Gilles Chanteperdrix @ 2013-12-16 18:33 UTC (permalink / raw) To: Jan Kiszka; +Cc: Xenomai 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. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Xenomai] forge: Trying to understand new semaphore code 2013-12-16 18:33 ` Gilles Chanteperdrix @ 2013-12-16 22:27 ` Gilles Chanteperdrix 2013-12-17 8:10 ` Philippe Gerum 0 siblings, 1 reply; 4+ messages in thread From: Gilles Chanteperdrix @ 2013-12-16 22:27 UTC (permalink / raw) To: Jan Kiszka; +Cc: Xenomai Hi, here comes the fix for the two issues. If we are allowed to rebase the next branch, I suggest to fold it with the original semaphore commit. Otherwise, I can push this commit on my branch. diff --git a/kernel/cobalt/posix/nsem.c b/kernel/cobalt/posix/nsem.c index 7e66ea8..72edacb 100644 --- a/kernel/cobalt/posix/nsem.c +++ b/kernel/cobalt/posix/nsem.c @@ -119,9 +119,10 @@ nsem_open(struct __shadow_sem __user *ushadow, const char *name, if ((oflags & O_CREAT) == 0) return ERR_PTR(-ENOENT); - rc = cobalt_sem_init_inner + sem = cobalt_sem_init_inner (&name[1], &shadow, SEM_PSHARED, value); - if (rc < 0) { + if (IS_ERR(sem)) { + rc = PTR_ERR(sem); if (rc == -EEXIST) goto retry_bind; return ERR_PTR(rc); @@ -132,8 +133,6 @@ nsem_open(struct __shadow_sem __user *ushadow, const char *name, return ERR_PTR(-EFAULT); } handle = shadow.handle; - sem = xnregistry_fetch(handle); - ++sem->refs; } u = xnmalloc(sizeof(*u)); @@ -154,9 +153,6 @@ nsem_open(struct __shadow_sem __user *ushadow, const char *name, --sem->refs; xnlock_put_irqrestore(&nklock, s); - if (rc == -EWOULDBLOCK) - cobalt_sem_destroy_inner(sem->handle); - xnfree(u); u = v; } else { diff --git a/kernel/cobalt/posix/sem.c b/kernel/cobalt/posix/sem.c index 2f632f6..93fb6d8 100644 --- a/kernel/cobalt/posix/sem.c +++ b/kernel/cobalt/posix/sem.c @@ -32,6 +32,7 @@ *@{*/ #include <stddef.h> +#include <linux/err.h> #include "internal.h" #include "thread.h" #include "clock.h" @@ -82,8 +83,9 @@ int cobalt_sem_destroy_inner(xnhandle_t handle) return ret; } -int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, - int flags, unsigned int value) +struct cobalt_sem * +cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, + int flags, unsigned int value) { struct list_head *semq; struct cobalt_sem *sem, *osem; @@ -94,11 +96,11 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, spl_t s; if ((flags & SEM_PULSE) != 0 && value > 0) - return -EINVAL; + return ERR_PTR(-EINVAL); sem = xnmalloc(sizeof(*sem)); if (sem == NULL) - return -ENOSPC; + return ERR_PTR(-ENOSPC); snprintf(sem->name, sizeof(sem->name), "%s", name); @@ -159,7 +161,7 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, datp->flags = flags; sem->flags = flags; sem->owningq = kq; - sem->refs = 1; + sem->refs = name[0] ? 2 : 1; sm->magic = name[0] ? COBALT_NAMED_SEM_MAGIC : COBALT_SEM_MAGIC; sm->handle = sem->handle; @@ -168,7 +170,7 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, sm->datp_offset = -sm->datp_offset; xnlock_put_irqrestore(&nklock, s); - return 0; + return sem; err_lock_put: xnlock_put_irqrestore(&nklock, s); @@ -176,7 +178,7 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, err_free_sem: xnfree(sem); - return ret; + return ERR_PTR(ret); } /** @@ -653,14 +655,15 @@ static int sem_getvalue(xnhandle_t handle, int *value) int cobalt_sem_init(struct __shadow_sem __user *u_sem, int pshared, unsigned value) { struct __shadow_sem sm; + struct cobalt_sem *sem; int err; if (__xn_safe_copy_from_user(&sm, u_sem, sizeof(sm))) return -EFAULT; - err = cobalt_sem_init_inner("", &sm, pshared ? SEM_PSHARED : 0, value); - if (err < 0) - return err; + sem = cobalt_sem_init_inner("", &sm, pshared ? SEM_PSHARED : 0, value); + if (IS_ERR(sem)) + return PTR_ERR(sem); return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)); } @@ -735,6 +738,7 @@ int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, int flags, unsigned value) { struct __shadow_sem sm; + struct cobalt_sem *sem; int err; if (__xn_safe_copy_from_user(&sm, u_sem, sizeof(sm))) @@ -744,9 +748,9 @@ int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, SEM_WARNDEL|SEM_RAWCLOCK|SEM_NOBUSYDEL)) return -EINVAL; - err = cobalt_sem_init_inner("", &sm, flags, value); - if (err < 0) - return err; + sem = cobalt_sem_init_inner("", &sm, flags, value); + if (IS_ERR(sem)) + return PTR_ERR(sem); return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)); } diff --git a/kernel/cobalt/posix/sem.h b/kernel/cobalt/posix/sem.h index 1548e66..7667976 100644 --- a/kernel/cobalt/posix/sem.h +++ b/kernel/cobalt/posix/sem.h @@ -57,7 +57,8 @@ typedef struct #define SEM_VALUE_MAX (INT_MAX) #define SEM_FAILED NULL -int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sem, +struct cobalt_sem * +cobalt_sem_init_inner(const char *name, struct __shadow_sem *sem, int flags, unsigned value); int cobalt_sem_destroy_inner(xnhandle_t handle); -- Gilles. ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Xenomai] forge: Trying to understand new semaphore code 2013-12-16 22:27 ` Gilles Chanteperdrix @ 2013-12-17 8:10 ` Philippe Gerum 0 siblings, 0 replies; 4+ messages in thread From: Philippe Gerum @ 2013-12-17 8:10 UTC (permalink / raw) To: Gilles Chanteperdrix, Jan Kiszka; +Cc: Xenomai On 12/16/2013 11:27 PM, Gilles Chanteperdrix wrote: > > Hi, > > here comes the fix for the two issues. If we are allowed to rebase > the next branch, I suggest to fold it with the original semaphore > commit. Otherwise, I can push this commit on my branch. Rebasing is always allowed on -next, I'll pick this up. Thanks. > > diff --git a/kernel/cobalt/posix/nsem.c b/kernel/cobalt/posix/nsem.c > index 7e66ea8..72edacb 100644 > --- a/kernel/cobalt/posix/nsem.c > +++ b/kernel/cobalt/posix/nsem.c > @@ -119,9 +119,10 @@ nsem_open(struct __shadow_sem __user *ushadow, const char *name, > if ((oflags & O_CREAT) == 0) > return ERR_PTR(-ENOENT); > > - rc = cobalt_sem_init_inner > + sem = cobalt_sem_init_inner > (&name[1], &shadow, SEM_PSHARED, value); > - if (rc < 0) { > + if (IS_ERR(sem)) { > + rc = PTR_ERR(sem); > if (rc == -EEXIST) > goto retry_bind; > return ERR_PTR(rc); > @@ -132,8 +133,6 @@ nsem_open(struct __shadow_sem __user *ushadow, const char *name, > return ERR_PTR(-EFAULT); > } > handle = shadow.handle; > - sem = xnregistry_fetch(handle); > - ++sem->refs; > } > > u = xnmalloc(sizeof(*u)); > @@ -154,9 +153,6 @@ nsem_open(struct __shadow_sem __user *ushadow, const char *name, > --sem->refs; > xnlock_put_irqrestore(&nklock, s); > > - if (rc == -EWOULDBLOCK) > - cobalt_sem_destroy_inner(sem->handle); > - > xnfree(u); > u = v; > } else { > diff --git a/kernel/cobalt/posix/sem.c b/kernel/cobalt/posix/sem.c > index 2f632f6..93fb6d8 100644 > --- a/kernel/cobalt/posix/sem.c > +++ b/kernel/cobalt/posix/sem.c > @@ -32,6 +32,7 @@ > *@{*/ > > #include <stddef.h> > +#include <linux/err.h> > #include "internal.h" > #include "thread.h" > #include "clock.h" > @@ -82,8 +83,9 @@ int cobalt_sem_destroy_inner(xnhandle_t handle) > return ret; > } > > -int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, > - int flags, unsigned int value) > +struct cobalt_sem * > +cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, > + int flags, unsigned int value) > { > struct list_head *semq; > struct cobalt_sem *sem, *osem; > @@ -94,11 +96,11 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, > spl_t s; > > if ((flags & SEM_PULSE) != 0 && value > 0) > - return -EINVAL; > + return ERR_PTR(-EINVAL); > > sem = xnmalloc(sizeof(*sem)); > if (sem == NULL) > - return -ENOSPC; > + return ERR_PTR(-ENOSPC); > > snprintf(sem->name, sizeof(sem->name), "%s", name); > > @@ -159,7 +161,7 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, > datp->flags = flags; > sem->flags = flags; > sem->owningq = kq; > - sem->refs = 1; > + sem->refs = name[0] ? 2 : 1; > > sm->magic = name[0] ? COBALT_NAMED_SEM_MAGIC : COBALT_SEM_MAGIC; > sm->handle = sem->handle; > @@ -168,7 +170,7 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, > sm->datp_offset = -sm->datp_offset; > xnlock_put_irqrestore(&nklock, s); > > - return 0; > + return sem; > > err_lock_put: > xnlock_put_irqrestore(&nklock, s); > @@ -176,7 +178,7 @@ int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, > err_free_sem: > xnfree(sem); > > - return ret; > + return ERR_PTR(ret); > } > > /** > @@ -653,14 +655,15 @@ static int sem_getvalue(xnhandle_t handle, int *value) > int cobalt_sem_init(struct __shadow_sem __user *u_sem, int pshared, unsigned value) > { > struct __shadow_sem sm; > + struct cobalt_sem *sem; > int err; > > if (__xn_safe_copy_from_user(&sm, u_sem, sizeof(sm))) > return -EFAULT; > > - err = cobalt_sem_init_inner("", &sm, pshared ? SEM_PSHARED : 0, value); > - if (err < 0) > - return err; > + sem = cobalt_sem_init_inner("", &sm, pshared ? SEM_PSHARED : 0, value); > + if (IS_ERR(sem)) > + return PTR_ERR(sem); > > return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)); > } > @@ -735,6 +738,7 @@ int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, > int flags, unsigned value) > { > struct __shadow_sem sm; > + struct cobalt_sem *sem; > int err; > > if (__xn_safe_copy_from_user(&sm, u_sem, sizeof(sm))) > @@ -744,9 +748,9 @@ int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, > SEM_WARNDEL|SEM_RAWCLOCK|SEM_NOBUSYDEL)) > return -EINVAL; > > - err = cobalt_sem_init_inner("", &sm, flags, value); > - if (err < 0) > - return err; > + sem = cobalt_sem_init_inner("", &sm, flags, value); > + if (IS_ERR(sem)) > + return PTR_ERR(sem); > > return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)); > } > diff --git a/kernel/cobalt/posix/sem.h b/kernel/cobalt/posix/sem.h > index 1548e66..7667976 100644 > --- a/kernel/cobalt/posix/sem.h > +++ b/kernel/cobalt/posix/sem.h > @@ -57,7 +57,8 @@ typedef struct > #define SEM_VALUE_MAX (INT_MAX) > #define SEM_FAILED NULL > > -int cobalt_sem_init_inner(const char *name, struct __shadow_sem *sem, > +struct cobalt_sem * > +cobalt_sem_init_inner(const char *name, struct __shadow_sem *sem, > int flags, unsigned value); > > int cobalt_sem_destroy_inner(xnhandle_t handle); > > > -- Philippe. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-12-17 8:10 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-12-16 18:10 [Xenomai] forge: Trying to understand new semaphore code Jan Kiszka 2013-12-16 18:33 ` Gilles Chanteperdrix 2013-12-16 22:27 ` Gilles Chanteperdrix 2013-12-17 8:10 ` Philippe Gerum
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.