/*
* Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
*
* Development of this software was supported by the
* Ulla Tuominen Foundation and the Finnish Cultural Foundation and the
* Research Foundation of Helsinki University of Technology
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* putter instance structures. these are always allocated and freed
* from the context of the transport user.
*/
struct putter_instance {
pid_t pi_pid;
int pi_idx;
int pi_fd;
struct selinfo pi_sel;
/*
* Poll query interface. The question is only if an event
* can be read from us.
*/
#define PUTTERPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
static int
putter_fop_poll(file_t *fp, int events)
{
struct putter_instance *pi = fp->f_data;
int revents;
KERNEL_LOCK(1, NULL);
if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) {
printf("putter_fop_ioctl: putter %d not inited\n", pi->pi_idx);
KERNEL_UNLOCK_ONE(NULL);
return ENOENT;
}
/*
* device close = forced unmount.
*
* unmounting is a frightfully complex operation to avoid races
*/
static int
putter_fop_close(file_t *fp)
{
struct putter_instance *pi = fp->f_data;
int rv;
DPRINTF(("putter_fop_close: device closed\n"));
KERNEL_LOCK(1, NULL);
restart:
mutex_enter(&pi_mtx);
/*
* First check if the driver was never born. In that case
* remove the instance from the list. If mount is attempted later,
* it will simply fail.
*/
if (pi->pi_private == PUTTER_EMBRYO) {
TAILQ_REMOVE(&putter_ilist, pi, pi_entries);
mutex_exit(&pi_mtx);
DPRINTF(("putter_fop_close: data associated with fp %p was "
"embryonic\n", fp));
goto out;
}
/*
* Next, analyze if unmount was called and the instance is dead.
* In this case we can just free the structure and go home, it
* was removed from the list by putter_rmprivate().
*/
if (pi->pi_private == PUTTER_DEAD) {
mutex_exit(&pi_mtx);
out:
KERNEL_UNLOCK_ONE(NULL);
/*
* Finally, release the instance information. It was already
* removed from the list by putter_rmprivate() and we know it's
* dead, so no need to lock.
*/
kmem_free(pi, sizeof(struct putter_instance));
return 0;
}
static int
putter_fop_stat(file_t *fp, struct stat *st)
{
struct putter_instance *pi = fp->f_data;
int
puttercdclose(dev_t dev, int flags, int fmt, struct lwp *l)
{
panic("puttercdclose impossible\n");
return 0;
}
/*
* Set the private structure for the file descriptor. This is
* typically done immediately when the counterpart has knowledge
* about the private structure's address and the file descriptor
* (e.g. vfs mount routine).
*
* We only want to make sure that the caller had the right to open the
* device, we don't so much care about which context it gets in case
* the same process opened multiple (since they are equal at this point).
*/
struct putter_instance *
putter_attach(pid_t pid, int fd, void *ppriv, struct putter_ops *pop)
{
struct putter_instance *pi = NULL;
/* search sorted list of instances for free minor, sorted insert arg */
static int
get_pi_idx(struct putter_instance *pi_i)
{
struct putter_instance *pi;
int i;
KASSERT(mutex_owned(&pi_mtx));
i = 0;
TAILQ_FOREACH(pi, &putter_ilist, pi_entries) {
if (i != pi->pi_idx)
break;
i++;
}