blob: 17aea22ac59a3a540d92e22da1f40eb3739574d7 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.
*/
#include <vfs.h>
#include <kfs.h>
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
enum {
Whinesecs = 10, /* frequency of out-of-resources printing */
};
static struct kref pgrpid[1] = { {(void *)1, fake_release} };
static spinlock_t mountidlock[1];
static struct kref mountid[1] = { {(void *)1, fake_release} };
#if 0
/* exception handling. We need to talk.*/
void
pgrpnote(uint32_t noteid, char *a, long n, int flag)
{
Proc *p, *ep;
char buf[ERRMAX];
if (n >= ERRMAX - 1)
error(Etoobig);
memmove(buf, a, n);
buf[n] = 0;
p = proctab(0);
pp = p + conf.nproc;
for (; p < ep; p++) {
if (p->state == Dead)
continue;
if (up != p && p->noteid == noteid && p->kp == 0) {
qlock(&p->debug);
if (p->pid == 0 || p->noteid != noteid) {
qunlock(&p->debug);
continue;
}
if (!waserror()) {
postnote(p, 0, buf, flag);
}
poperror();
qunlock(&p->debug);
}
}
}
#endif
struct pgrp *newpgrp(void)
{
struct pgrp *p;
p = kzmalloc(sizeof(struct pgrp), KMALLOC_WAIT);
kref_init(&p->ref, fake_release, 1);
kref_get(pgrpid, 1);
p->pgrpid = kref_refcnt(pgrpid);
return p;
}
void closepgrp(struct pgrp *p)
{
struct mhead **h, **e, *f, *next;
if (!kref_put(&p->ref))
return;
/* the p->debug stuff is not needed -- we think. */
//qlock(&p->debug);
wlock(&p->ns);
p->pgrpid = -1;
e = &p->mnthash[MNTHASH];
for (h = p->mnthash; h < e; h++) {
for (f = *h; f; f = next) {
wlock(&f->lock);
cclose(f->from);
mountfree(f->mount);
f->mount = NULL;
next = f->hash;
wunlock(&f->lock);
putmhead(f);
}
}
wunlock(&p->ns);
//qunlock(&p->debug);
kfree(p);
}
void pgrpinsert(struct mount **order, struct mount *m)
{
struct mount *f;
m->order = 0;
if (*order == 0) {
*order = m;
return;
}
for (f = *order; f; f = f->order) {
if (m->mountid < f->mountid) {
m->order = f;
*order = m;
return;
}
order = &f->order;
}
*order = m;
}
/*
* pgrpcpy MUST preserve the mountid allocation order of the parent group
*/
void pgrpcpy(struct pgrp *to, struct pgrp *from)
{
int i;
struct mount *n, *m, **link, *order;
struct mhead *f, **tom, **l, *mh;
wlock(&from->ns);
order = 0;
tom = to->mnthash;
for (i = 0; i < MNTHASH; i++) {
l = tom++;
for (f = from->mnthash[i]; f; f = f->hash) {
rlock(&f->lock);
mh = newmhead(f->from);
*l = mh;
l = &mh->hash;
link = &mh->mount;
for (m = f->mount; m; m = m->next) {
n = newmount(mh, m->to, m->mflag, m->spec);
m->copy = n;
pgrpinsert(&order, m);
*link = n;
link = &n->next;
}
runlock(&f->lock);
}
}
/*
* Allocate mount ids in the same sequence as the parent group
*/
spin_lock(mountidlock);
/* this may not get the ids right. */
for (m = order; m; m = m->order)
m->copy->mountid = kref_refcnt(mountid);
kref_get(mountid, 1);
spin_unlock(mountidlock);
wunlock(&from->ns);
}
struct fgrp *dupfgrp(struct fgrp *f)
{
struct fgrp *new;
struct chan *c;
int i;
new = kzmalloc(sizeof(struct fgrp), KMALLOC_WAIT);
if (f == NULL) {
new->fd = kzmalloc(DELTAFD * sizeof(struct chan *), KMALLOC_WAIT);
new->nfd = DELTAFD;
kref_init(&new->ref, fake_release, 1);
return new;
}
spin_lock(&f->lock);
if (f->closed) {
spin_unlock(&f->lock);
kfree(new);
error("File group closed");
}
/* Make new fd list shorter if possible, preserving quantization */
new->nfd = f->maxfd + 1;
i = new->nfd % DELTAFD;
if (i != 0)
new->nfd += DELTAFD - i;
new->fd = kzmalloc(new->nfd * sizeof(struct chan *), KMALLOC_WAIT);
if (new->fd == NULL) {
spin_unlock(&f->lock);
kfree(new);
error("no memory for fgrp");
}
kref_init(&new->ref, fake_release, 1);
new->maxfd = f->maxfd;
for (i = 0; i <= f->maxfd; i++) {
c = f->fd[i];
if (c) {
kref_get(&c->ref, 1);
new->fd[i] = c;
}
}
spin_unlock(&f->lock);
return new;
}
void closefgrp(struct fgrp *f)
{
int i;
struct chan *c;
/* closefgrp can't be called from proc_destroy, due to races on the fgrp.
* current->fgrp is a kref source, and we'd need some form of external sync
* to remove it, since multiple kthreads could be accessing current->fgrp.
* proc_free is synchronized, for instance. we could put some sync in the
* fgrp, but that would require splitting the deallocation (which we do
* manually), and would require not having multiple procs per fgrp (which we
* also require). another option would be to use RCU: clear current->fgrp,
* then closefgrp after a grace period. */
warn("Don't call closefgrp()");
if (f == 0)
return;
if (!kref_put(&f->ref))
return;
/*
* If we get into trouble, forceclosefgrp
* will bail us out.
*/
current->closingfgrp = f;
for (i = 0; i <= f->maxfd; i++) {
c = f->fd[i];
if (c) {
f->fd[i] = NULL;
cclose(c);
}
}
current->closingfgrp = NULL;
kfree(f->fd);
kfree(f);
}
/*
* Called from sleep because up is in the middle
* of closefgrp and just got a kill ctl message.
* This usually means that up has wedged because
* of some kind of deadly embrace with mntclose
* trying to talk to itself. To break free, hand the
* unclosed channels to the close queue. Once they
* are finished, the blocked cclose that we've
* interrupted will finish by itself.
*/
void forceclosefgrp(void)
{
int i;
struct chan *c;
struct fgrp *f;
if ( /* check that we're exiting somehow ...up->procctl != Proc_exitme || */
current->closingfgrp == NULL) {
printd("bad forceclosefgrp call");
return;
}
f = current->closingfgrp;
for (i = 0; i <= f->maxfd; i++) {
c = f->fd[i];
if (c) {
f->fd[i] = NULL;
printd("Not calling ccloseq ... fix me\n");
//ccloseq(c);
}
}
}
struct mount *newmount(struct mhead *mh, struct chan *to, int flag, char *spec)
{
struct mount *m;
m = kzmalloc(sizeof(struct mount), KMALLOC_WAIT);
m->to = to;
m->head = mh;
kref_get(&to->ref, 1);
kref_get(mountid, 1);
m->mountid = kref_refcnt(mountid);
m->mflag = flag;
if (spec != 0)
kstrdup(&m->spec, spec);
return m;
}
void mountfree(struct mount *m)
{
struct mount *f;
while (m) {
f = m->next;
cclose(m->to);
m->mountid = 0;
kfree(m->spec);
kfree(m);
m = f;
}
}
/* nah */
#if 0
void resrcwait(struct proc *up, char *reason)
{
uint32_t now;
char *p;
static uint32_t lastwhine;
if (up == 0)
panic("resrcwait");
p = up->psstate;
if (reason) {
up->psstate = reason;
now = seconds();
/* don't tie up the console with complaints */
if (now - lastwhine > Whinesecs) {
lastwhine = now;
printd("%s\n", reason);
}
}
udelay_sched(300 * 1000);
up->psstate = p;
}
#endif