kernelnewbies.kernelnewbies.org archive mirror
 help / color / mirror / Atom feed
From: ydroneaud@opteya.com (Yann Droneaud)
To: kernelnewbies@lists.kernelnewbies.org
Subject: locking a device for exclusive use by userspace process (or kernel thread)
Date: Wed, 04 Mar 2015 18:59:04 +0100	[thread overview]
Message-ID: <1425491944.3069.29.camel@opteya.com> (raw)

Hi,

I have a device and I have to write a driver that exposes the
following three operations to kernel modules AND to userspace
programs:

- LOCK

LOCK operation is used to get exclusive access to the device.
If exclusive access is already granted, the caller will wait
for it be released.

- PROCESS

PROCESS can be issued only after a successful LOCK operation.
PROCESS operations can be issued multiple times between LOCK
and UNLOCK.

- UNLOCK

UNLOCK operation release the exclusive access to the device.
This operation can be issued only after a successful LOCK
operation.

In kernelspace, the lock would be implemented using
a semaphore (with an initial count of 1). That's the easy
part.

In userspace, it's expected LOCK and UNLOCK can be issued in
different threads within one process, and, if, while holding
the lock, a process die, either being killed or by exit(),
an implicit UNLOCK should be done.

I've initially thought I could represent the lock by a file
descriptor, map LOCK to open() and  UNLOCK() to close() (with
the added benefit that opened file descriptor will be closed
on exit):

  operation    userspace     kernelspace

    LOCK        open()         ->open()
   PROCESS      ioctl()        ->ioctl()
   UNLOCK       close()        ->release()

open() would block if the lock is already held by some other
process (and would not block if O_NONBLOCK or O_NDELAY is used).

Seems a great scheme.

But that doesn't fit well with Unix / POSIX, as both fork()
and dup{,2,3}() or fcntl(, F_DUPFD*,) creates new references
to open()'ed device:

- A child will inherit the file descriptor for the device
after parent fork(). As the child has a file descriptor for
the device, the parent couldn't UNLOCK by calling close() since
the device won't be released until the child also close() its
copy of the file descriptor.

It should be noted that even if the child has the device opened
by the vertue of inheritance, it does not own the lock, so it
should not be allowed to issue PROCESS operation. But at the
same time, it prevents the real owner from releasing the lock
(... I'm seeing dead locks). So who really own the lock ?

It seems awkward to allow an exclusive lock to be shared
between two different process even if they are parents.

- In the very same process, multiple references to the device
could be created with dup(). So close()ing the file descriptor
returned by open() won't UNLOCK the device, as the device will
only be released once the last reference would be close()'d.

It seems awkward to allow an exclusive lock to be "duplicated"
within a process.


I've tried to (ab)use ->flush() to implement UNLOCK operation so
that a call to close() on the device's file descriptor would
UNLOCK, even if a duplicated file descriptor exists in the same
process or in a child. But this has the unfortunate consequence of
allowing to UNLOCK when closing a duplicated file descriptor
(and closing the file descriptor in the child could also mean
UNLOCK).

So in the end, I'm probably not going to use open() for LOCK and
close() for UNLOCK. I think I have to use dedicated LOCK and
UNLOCK ioctls.

But I failed to find a way to be able to release the lock when
the process owning the lock die / exit.

Perhaps I need a mechanism to be notified of the death of the
process owning the lock.

Do you have such mean in mind ?

Or any other reasonable solution to implement the three operations of 
such driver ?

Regards.

-- 
Yann Droneaud
OPTEYA

             reply	other threads:[~2015-03-04 17:59 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-04 17:59 Yann Droneaud [this message]
2015-03-04 18:11 ` locking a device for exclusive use by userspace process (or kernel thread) Greg KH
2015-03-04 18:38   ` Yann Droneaud
2015-03-04 18:43     ` Greg KH
2015-03-04 18:50     ` Malte Vesper

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=1425491944.3069.29.camel@opteya.com \
    --to=ydroneaud@opteya.com \
    --cc=kernelnewbies@lists.kernelnewbies.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).