Beispiel #1
0
/*
 *  called with s->lk locked
 */
void
mfreeseg(Segment *s, ulong start, int pages)
{
	int i, j, size;
	ulong soff;
	Page *pg;
	Page *list;

	soff = start-s->base;
	j = (soff&(PTEMAPMEM-1))/BY2PG;

	size = s->mapsize;
	list = nil;
	for(i = soff/PTEMAPMEM; i < size; i++) {
		if(pages <= 0)
			break;
		if(s->map[i] == 0) {
			pages -= PTEPERTAB-j;
			j = 0;
			continue;
		}
		while(j < PTEPERTAB) {
			pg = s->map[i]->pages[j];
			/*
			 * We want to zero s->map[i]->page[j] and putpage(pg),
			 * but we have to make sure other processors flush the
			 * entry from their TLBs before the page is freed.
			 * We construct a list of the pages to be freed, zero
			 * the entries, then (below) call procflushseg, and call
			 * putpage on the whole list.
			 *
			 * Swapped-out pages don't appear in TLBs, so it's okay
			 * to putswap those pages before procflushseg.
			 */
			if(pg){
				if(onswap(pg))
					putswap(pg);
				else{
					pg->next = list;
					list = pg;
				}
				s->map[i]->pages[j] = 0;
			}
			if(--pages == 0)
				goto out;
			j++;
		}
		j = 0;
	}
out:
	/* flush this seg in all other processes */
	if(s->ref > 1)
		procflushseg(s);

	/* free the pages */
	for(pg = list; pg != nil; pg = list){
		list = list->next;
		putpage(pg);
	}
}
Beispiel #2
0
static int
pageout(Proc *p, Segment *s)
{
	Proc *up = externup();
	int i, size, n;
	Pte *l;
	Page **pg, *entry;

	if((s->type&SG_TYPE) != SG_LOAD && (s->type&SG_TYPE) != SG_TEXT)
		panic("pageout");

	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */
		return 0;

	if(s->steal){		/* Protected by /dev/proc */
		qunlock(&s->lk);
		return 0;
	}

	if(!canflush(p, s)){	/* Able to invalidate all tlbs with references */
		qunlock(&s->lk);
		putseg(s);
		return 0;
	}

	if(waserror()){
		qunlock(&s->lk);
		putseg(s);
		return 0;
	}

	/* Pass through the pte tables looking for text memory pages to put */
	n = 0;
	size = s->mapsize;
	for(i = 0; i < size; i++){
		l = s->map[i];
		if(l == 0)
			continue;
		for(pg = l->first; pg < l->last; pg++){
			entry = *pg;
			if(pagedout(entry))
				continue;
			n++;
			if(entry->modref & PG_REF){
				entry->modref &= ~PG_REF;
				continue;
			}
			putpage(*pg);
			*pg = nil;
		}
	}
	poperror();
	qunlock(&s->lk);
	putseg(s);
	return n;
}
Beispiel #3
0
static Page*
mmupdballoc(ulong va, void *mpdb)
{
	int s;
	Page *page;
	Page *badpages, *pg;

	s = splhi();
	/*
	 * All page tables must be read-only.  We will mark them
	 * readwrite later when we free them and they are no
	 * longer used as page tables.
	 */
	if(m->pdbpool == 0){
		spllo();
		badpages = 0;
		for (;;) {
			page = newpage(0, 0, 0);
			page->va = VA(kmap(page));
			if(mpdb)
				memmove((void*)page->va, mpdb, BY2PG);
			else
				memset((void*)page->va, 0, BY2PG);
			if (xenpgdpin(page->va))
				break;
			/*
			 * XXX Plan 9 is a bit lax about putting pages on the free list when they are
			 * still mapped (r/w) by some process's page table.  From Plan 9's point
			 * of view this is safe because the any such process will have up->newtlb set,
			 * so the mapping will be cleared before the process is dispatched.  But the Xen
			 * hypervisor has no way of knowing this, so it refuses to pin the page for use
			 * as a pagetable.
			 */
			if(0) print("bad pgdpin %lux va %lux copy %lux %s\n", MFN(PADDR(page->va)), va, (ulong)mpdb, up? up->text: "");
			page->next = badpages;
			badpages = page;
		}
		while (badpages != 0) {
			pg = badpages;
			badpages = badpages->next;
			putpage(pg);
		}
	}
	else{
		page = m->pdbpool;
		m->pdbpool = page->next;
		m->pdbcnt--;
		if (!xenpgdpin(page->va))
			panic("xenpgdpin");
	}
	splx(s);

	page->next = 0;
	return page;
}
Beispiel #4
0
static void
pagepte(int type, Page **pg)
{
	ulong daddr;
	Page *outp;

	outp = *pg;
	switch(type) {
	case SG_TEXT:				/* Revert to demand load */
		putpage(outp);
		*pg = 0;
		break;

	case SG_DATA:
	case SG_BSS:
	case SG_STACK:
	case SG_SHARED:
		/*
		 *  get a new swap address and clear any pages
		 *  referring to it from the cache
		 */
		daddr = newswap();
		if(daddr == ~0)
			break;
		cachedel(&swapimage, daddr);

		lock(&outp->lk);

		/* forget anything that it used to cache */
		uncachepage(outp);

		/*
		 *  incr the reference count to make sure it sticks around while
		 *  being written
		 */
		outp->ref++;

		/*
		 *  enter it into the cache so that a fault happening
		 *  during the write will grab the page from the cache
		 *  rather than one partially written to the disk
		 */
		outp->daddr = daddr;
		cachepage(outp, &swapimage);
		*pg = (Page*)(daddr|PG_ONSWAP);
		unlock(&outp->lk);

		/* Add page to IO transaction list */
		iolist[ioptr++] = outp;
		break;
	}
}
Beispiel #5
0
static	int
print(char *name)
{
	static	int	notfirst = 0;
	char	*date = NULL;
	char	*head = NULL;
	int	c;

	if (Multi != 'm' && mustopen(name, &Files[0]) == NULL)
		return (0);
	if (Multi == 'm' && Nfiles == 0 && mustopen(name, &Files[0]) == NULL)
		die("cannot open stdin");
	if (Buffer)
		(void) ungetwc(Files->f_nextc, Files->f_f);
	if (Lnumb)
		Lnumb = 1;
	for (Page = 0; ; putpage()) {
		if (C == WEOF && !(fold && Buffer))
			break;
		if (Buffer)
			nexbuf();
		Inpos = 0;
		if (get(0) == WEOF)
			break;
		(void) fflush(stdout);
		if (++Page >= Fpage) {
			/* Pause if -p and not first page */
			if (Ttyout && Pause && !notfirst++) {
				PROMPT();	/* prompt with bell and pause */
				while ((c = getc(Ttyin)) != EOF && c != '\n')
					;
			}
			if (Margin == 0)
				continue;
			if (date == NULL)
				date = GETDATE();
			if (head == NULL)
				head = Head != NULL ? Head :
				    Nfiles < 2 ? Files->f_name : nulls;
			(void) printf("\n\n");
			Nspace = Offset;
			putspace();
			(void) printf(HEAD);
		}
	}
	C = '\0';
	return (1);
}
Beispiel #6
0
int
pr(char *name)
{
	char *date = 0, *head = 0;

	if(Multi != 'm' && mustopen(name, &Files[0]) == 0)
		return 0;
	if(Buffer)
		Bungetc(Files->f_f);
	if(Lnumb)
		Lnumb = 1;
	for(Page = 0;; putpage()) {
		if(C == -1)
			break;
		if(Buffer)
			nexbuf();
		Inpos = 0;
		if(get(0) == -1)
			break;
		Bflush(&bout);
		Page++;
		if(Page >= Fpage) {
			if(Margin == 0)
				continue;
			if(date == 0)
				date = getdate();
			if(head == 0)
				head = Head != 0 ? Head :
					Nfiles < 2? Files->f_name: nulls;
			Bprint(&bout, "\n\n");
			Nspace = Offset;
			putspace();
			Bprint(&bout, HEAD);
		}
	}
	if(Padodd && (Page&1) == 1) {
		Line = 0;
		if(Formfeed)
			put('\f');
		else
			while(Line < Len)
				put('\n');
	}
	C = '\0';
	return 1;
}
Beispiel #7
0
int area_destroy(aspace_t *aspace, int area_id)
{
	area_t *area;
	pagegroup_t *pg;
	
    if(!(area = rsrc_find_area(area_id))) return ERR_RESOURCE;
	
	/* find and unchain the area from its aspace -- complain if it is foreign */
	if(list_remove(&aspace->areas, area)) return ERR_RESOURCE;
	
	/* unmap the memory */
	aspace_clr(aspace, area->virt_addr, area->length);
	
	pg = area->pgroup;
	
	/* remove this area from the pgroup's area list */
	list_remove(&pg->areas, area);
	
	/* decr the pagegroup refcount and tear it down if zero */
	pg->refcount--;
	
	if(pg->refcount == 0){
		int release = !(pg->flags & AREA_PHYSMAP);
		int count = 0;
		phys_page_t *pp;

		while((pp = pg->pages)){
			pg->pages = pp->next;
			if(release){
				for(count=0;pg->size && (count < 6);count++){
					putpage(pp->addr[count]);
					pg->size--;
				}
			}
			kfree(phys_page_t, pp);
		}	
		kfree(pagegroup_t, pg);
	}

	rsrc_release(&area->rsrc);
	
	kfree(area_t, area);
	return ERR_NONE;
}
Beispiel #8
0
int
cpgmove(Extent *e, uchar *buf, int boff, int len)
{
	Page *p;
	KMap *k;

	p = cpage(e);
	if(p == 0)
		return 0;

	k = kmap(p);
	if(waserror()) {		/* Since buf may be virtual */
		kunmap(k);
		nexterror();
	}

	memmove((uchar*)VA(k)+boff, buf, len);

	poperror();
	kunmap(k);
	putpage(p);

	return 1;
}
Beispiel #9
0
static void
executeio(void)
{
	Page *out;
	int i, n;
	Chan *c;
	char *kaddr;
	KMap *k;

	c = swapimage.c;

	for(i = 0; i < ioptr; i++) {
		if(ioptr > conf.nswppo)
			panic("executeio: ioptr %d > %d\n", ioptr, conf.nswppo);
		out = iolist[i];
		k = kmap(out);
		kaddr = (char*)VA(k);

		if(waserror())
			panic("executeio: page out I/O error");

		n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
		if(n != BY2PG)
			nexterror();

		kunmap(k);
		poperror();

		/* Free up the page after I/O */
		lock(&out->lk);
		out->ref--;
		unlock(&out->lk);
		putpage(out);
	}
	ioptr = 0;
}
Beispiel #10
0
int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, s32 *ctl_len,
			char *data_buf, int data_maxlen, s32 *data_len, int *flags_p)
{
	int error;
	int oldflags;
	struct file *filp;
	struct inode *ino;
	struct sol_socket_struct *sock;
	struct T_unitdata_ind udi;
	mm_segment_t old_fs = get_fs();
	long args[6];
	char *tmpbuf;
	int tmplen;
	int (*sys_socketcall)(int, unsigned long *) =
		(int (*)(int, unsigned long *))SYS(socketcall);
	int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *);
	
	SOLD("entry");
	SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
	filp = current->files->fd[fd];
	ino = filp->f_dentry->d_inode;
	sock = (struct sol_socket_struct *)filp->private_data;
	SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
	if ( ctl_maxlen > 0 && !sock->pfirst && ino->u.socket_i.type == SOCK_STREAM
		&& sock->state == TS_IDLE) {
		SOLD("calling LISTEN");
		args[0] = fd;
		args[1] = -1;
		set_fs(KERNEL_DS);
		sys_socketcall(SYS_LISTEN, args);
		set_fs(old_fs);
		SOLD("LISTEN done");
	}
	if (!(filp->f_flags & O_NONBLOCK)) {
		poll_table wait_table, *wait;

		poll_initwait(&wait_table);
		wait = &wait_table;
		for(;;) {
			SOLD("loop");
			set_current_state(TASK_INTERRUPTIBLE);
			/* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
			/* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
			/* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
			/* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */ 
			/* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */ 
			/* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */ 
			if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
				break;
			SOLD("cond 1 passed");
			if (
			#if 1
				*flags_p != MSG_HIPRI &&
			#endif
				((filp->f_op->poll(filp, wait) & POLLIN) ||
				(filp->f_op->poll(filp, NULL) & POLLIN) ||
				signal_pending(current))
			) {
				break;
			}
			if( *flags_p == MSG_HIPRI ) {
				SOLD("avoiding lockup");
				break ;
			}
			if(wait_table.error) {
				SOLD("wait-table error");
				poll_freewait(&wait_table);
				return wait_table.error;
			}
			SOLD("scheduling");
			schedule();
		}
		SOLD("loop done");
		current->state = TASK_RUNNING;
		poll_freewait(&wait_table);
		if (signal_pending(current)) {
			SOLD("signal pending");
			return -EINTR;
		}
	}
	if (ctl_maxlen >= 0 && sock->pfirst) {
		struct T_primsg *it = sock->pfirst;
		int l = min_t(int, ctl_maxlen, it->length);
		SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
		SOLD("purting ctl data");
		if(copy_to_user(ctl_buf,
			(char*)&it->type + sock->offset, l))
			return -EFAULT;
		SOLD("pur it");
		if(put_user(l, ctl_len))
			return -EFAULT;
		SOLD("set ctl_len");
		*flags_p = it->pri;
		it->length -= l;
		if (it->length) {
			SOLD("more ctl");
			sock->offset += l;
			return MORECTL;
		} else {
			SOLD("removing message");
			sock->pfirst = it->next;
			if (!sock->pfirst)
				sock->plast = NULL;
			SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
			mykfree(it);
			sock->offset = 0;
			SOLD("ctl done");
			return 0;
		}
	}
	*flags_p = 0;
	if (ctl_maxlen >= 0) {
		SOLD("ACCEPT perhaps?");
		if (ino->u.socket_i.type == SOCK_STREAM && sock->state == TS_IDLE) {
			struct T_conn_ind ind;
			char *buf = getpage();
			int len = BUF_SIZE;

			SOLD("trying ACCEPT");
			if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
				return -EFAULT;
			args[0] = fd;
			args[1] = (long)buf;
			args[2] = (long)&len;
			oldflags = filp->f_flags;
			filp->f_flags |= O_NONBLOCK;
			SOLD("calling ACCEPT");
			set_fs(KERNEL_DS);
			error = sys_socketcall(SYS_ACCEPT, args);
			set_fs(old_fs);
			filp->f_flags = oldflags;
			if (error < 0) {
				SOLD("some error");
				putpage(buf);
				return error;
			}
			if (error) {
				SOLD("connect");
				putpage(buf);
				if (sizeof(ind) > ctl_maxlen) {
					SOLD("generating CONN_IND");
					ind.PRIM_type = T_CONN_IND;
					ind.SRC_length = len;
					ind.SRC_offset = sizeof(ind);
					ind.OPT_length = ind.OPT_offset = 0;
					ind.SEQ_number = error;
					if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
					   put_user(sizeof(ind)+ind.SRC_length,ctl_len))
						return -EFAULT;
					SOLD("CONN_IND created");
				}
				if (data_maxlen >= 0)
					put_user(0, data_len);
				SOLD("CONN_IND done");
				return 0;
			}
			if (len>ctl_maxlen) {
				SOLD("data don't fit");
				putpage(buf);
				return -EFAULT;		/* XXX - is this ok ? */
			}
			if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
				SOLD("can't copy data");
				putpage(buf);
				return -EFAULT;
			}
			SOLD("ACCEPT done");
			putpage(buf);
		}
	}
	SOLD("checking data req");
	if (data_maxlen <= 0) {
		if (data_maxlen == 0)
			put_user(0, data_len);
		if (ctl_maxlen >= 0)
			put_user(0, ctl_len);
		return -EAGAIN;
	}
	SOLD("wants data");
	if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
		SOLD("udi fits");
		tmpbuf = ctl_buf + sizeof(udi);
		tmplen = ctl_maxlen - sizeof(udi);
	} else {
		SOLD("udi does not fit");
		tmpbuf = NULL;
		tmplen = 0;
	}
	if (put_user(tmplen, ctl_len))
		return -EFAULT;
	SOLD("set ctl_len");
	oldflags = filp->f_flags;
	filp->f_flags |= O_NONBLOCK;
	SOLD("calling recvfrom");
	sys_recvfrom = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom);
	error = sys_recvfrom(fd, data_buf, data_maxlen, 0, (struct sockaddr*)tmpbuf, ctl_len);
	filp->f_flags = oldflags;
	if (error < 0)
		return error;
	SOLD("error >= 0" ) ;
	if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
		SOLD("generating udi");
		udi.PRIM_type = T_UNITDATA_IND;
		get_user(udi.SRC_length, ctl_len);
		udi.SRC_offset = sizeof(udi);
		udi.OPT_length = udi.OPT_offset = 0;
		copy_to_user(ctl_buf, &udi, sizeof(udi));
		put_user(sizeof(udi)+udi.SRC_length, ctl_len);
		SOLD("udi done");
	} else
		put_user(0, ctl_len);
	put_user(error, data_len);
	SOLD("done");
	return 0;
}
Beispiel #11
0
int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
			char *data_buf, int data_len, int flags)
{
	int ret, error, terror;
	char *buf;
	struct file *filp;
	struct inode *ino;
	struct sol_socket_struct *sock;
	mm_segment_t old_fs = get_fs();
	long args[6];
	int (*sys_socketcall)(int, unsigned long *) =
		(int (*)(int, unsigned long *))SYS(socketcall);
	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =
		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto);
	filp = current->files->fd[fd];
	ino = filp->f_dentry->d_inode;
	sock = (struct sol_socket_struct *)filp->private_data;
	SOLD("entry");
	if (get_user(ret, (int *)A(ctl_buf)))
		return -EFAULT;
	switch (ret) {
	case T_BIND_REQ:
	{
		struct T_bind_req req;
		
		SOLDD(("bind %016lx(%016lx)\n", sock, filp));
		SOLD("T_BIND_REQ");
		if (sock->state != TS_UNBND) {
			timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
			return 0;
		}
		SOLD("state ok");
		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
			timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
			return 0;
		}
		SOLD("got ctl req");
		if (req.ADDR_offset && req.ADDR_length) {
			if (req.ADDR_length > BUF_SIZE) {
				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
				return 0;
			}
			SOLD("req size ok");
			buf = getpage();
			if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
				putpage(buf);
				return 0;
			}
			SOLD("got ctl data");
			args[0] = fd;
			args[1] = (long)buf;
			args[2] = req.ADDR_length;
			SOLD("calling BIND");
			set_fs(KERNEL_DS);
			error = sys_socketcall(SYS_BIND, args);
			set_fs(old_fs);
			putpage(buf);
			SOLD("BIND returned");
		} else 
			error = 0;
		if (!error) {
			struct T_primsg *it;
			if (req.CONIND_number) {
	  			args[0] = fd;
  				args[1] = req.CONIND_number;
  				SOLD("calling LISTEN");
  				set_fs(KERNEL_DS);
	  			error = sys_socketcall(SYS_LISTEN, args);
  				set_fs(old_fs);
  				SOLD("LISTEN done");
  			}
			it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
			if (it) {
				struct T_bind_ack *ack;

				ack = (struct T_bind_ack *)&it->type;
				ack->PRIM_type = T_BIND_ACK;
				ack->ADDR_offset = sizeof(*ack);
				ack->ADDR_length = sizeof(struct sockaddr);
				ack->CONIND_number = req.CONIND_number;
				args[0] = fd;
				args[1] = (long)(ack+sizeof(*ack));
				args[2] = (long)&ack->ADDR_length;
				set_fs(KERNEL_DS);
				sys_socketcall(SYS_GETSOCKNAME,args);
				set_fs(old_fs);
				sock->state = TS_IDLE;
				timod_ok(fd, T_BIND_REQ);
				timod_queue_end(fd, it);
				SOLD("BIND done");
				return 0;
			}
		}
		SOLD("some error");
		switch (error) {
			case -EINVAL:
				terror = TOUTSTATE;
				error = 0;
				break;
			case -EACCES:
				terror = TACCES;
				error = 0;
				break;
			case -EADDRNOTAVAIL:
			case -EADDRINUSE:
				terror = TNOADDR;
				error = 0;
				break;
			default:
				terror = TSYSERR;
				break;
		}
		timod_error(fd, T_BIND_REQ, terror, -error);
		SOLD("BIND done");
		return 0;
	}
	case T_CONN_REQ:
	{
		struct T_conn_req req;
		unsigned short oldflags;
		struct T_primsg *it;
		SOLD("T_CONN_REQ");
		if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
			return 0;
		}
		SOLD("state ok");
		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
			return 0;
		}
		SOLD("got ctl req");
		if (ctl_len > BUF_SIZE) {
			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
			return 0;
		}
		SOLD("req size ok");
		buf = getpage();
		if (copy_from_user(buf, ctl_buf, ctl_len)) {
			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
			putpage(buf);
			return 0;
		}
#ifdef DEBUG_SOLARIS		
		{
			char * ptr = buf;
			int len = ctl_len;
			printk("returned data (%d bytes): ",len);
			while( len-- ) {
				if (!(len & 7))
					printk(" ");
				printk("%02x",(unsigned char)*ptr++);
			}
			printk("\n");
		}
#endif
		SOLD("got ctl data");
		args[0] = fd;
		args[1] = (long)buf+req.DEST_offset;
		args[2] = req.DEST_length;
		oldflags = filp->f_flags;
		filp->f_flags &= ~O_NONBLOCK;
		SOLD("calling CONNECT");
		set_fs(KERNEL_DS);
		error = sys_socketcall(SYS_CONNECT, args);
		set_fs(old_fs);
		filp->f_flags = oldflags;
		SOLD("CONNECT done");
		if (!error) {
			struct T_conn_con *con;
			SOLD("no error");
			it = timod_mkctl(ctl_len);
			if (!it) {
				putpage(buf);
				return -ENOMEM;
			}
			con = (struct T_conn_con *)&it->type;
#ifdef DEBUG_SOLARIS			
			{
				char * ptr = buf;
				int len = ctl_len;
				printk("returned data (%d bytes): ",len);
				while( len-- ) {
					if (!(len & 7))
						printk(" ");
					printk("%02x",(unsigned char)*ptr++);
				}
				printk("\n");
			}
#endif
			memcpy(con, buf, ctl_len);
			SOLD("copied ctl_buf");
			con->PRIM_type = T_CONN_CON;
			sock->state = TS_DATA_XFER;
		} else {
			struct T_discon_ind *dis;
			SOLD("some error");
			it = timod_mkctl(sizeof(*dis));
			if (!it) {
				putpage(buf);
				return -ENOMEM;
			}
			SOLD("got primsg");
			dis = (struct T_discon_ind *)&it->type;
			dis->PRIM_type = T_DISCON_IND;
			dis->DISCON_reason = -error;	/* FIXME: convert this as in iABI_errors() */
			dis->SEQ_number = 0;
		}
		putpage(buf);
		timod_ok(fd, T_CONN_REQ);
		it->pri = 0;
		timod_queue_end(fd, it);
		SOLD("CONNECT done");
		return 0;
	}
	case T_OPTMGMT_REQ:
	{
		struct T_optmgmt_req req;
		SOLD("OPTMGMT_REQ");
		if (copy_from_user(&req, ctl_buf, sizeof(req)))
			return -EFAULT;
		SOLD("got req");
		return timod_optmgmt(fd, req.MGMT_flags,
				req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
				req.OPT_length, 1);
	}
	case T_UNITDATA_REQ:
	{
		struct T_unitdata_req req;
		
		int err;
		SOLD("T_UNITDATA_REQ");
		if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
			return 0;
		}
		SOLD("state ok");
		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
			return 0;
		}
		SOLD("got ctl req");
#ifdef DEBUG_SOLARIS		
		{
			char * ptr = ctl_buf+req.DEST_offset;
			int len = req.DEST_length;
			printk("socket address (%d bytes): ",len);
			while( len-- ) {
				char c;
				if (get_user(c,ptr))
					printk("??");
				else
					printk("%02x",(unsigned char)c);
				ptr++;
			}
			printk("\n");
		}
#endif		
		err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr*)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
		if (err == data_len)
			return 0;
		if(err >= 0) {
			printk("timod: sendto failed to send all the data\n");
			return 0;
		}
		timod_error(fd, T_CONN_REQ, TSYSERR, -err);
		return 0;
	}
	default:
		printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
		break;
	}
	return -EINVAL;
}
Beispiel #12
0
static int timod_optmgmt(unsigned int fd, int flag, char *opt_buf, int opt_len, int do_ret)
{
	int error, failed;
	int ret_space, ret_len;
	long args[5];
	char *ret_pos,*ret_buf;
	int (*sys_socketcall)(int, unsigned long *) =
		(int (*)(int, unsigned long *))SYS(socketcall);
	mm_segment_t old_fs = get_fs();

	SOLD("entry");
	SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
	if (!do_ret && (!opt_buf || opt_len <= 0))
		return 0;
	SOLD("getting page");
	ret_pos = ret_buf = getpage();
	ret_space = BUF_SIZE;
	ret_len = 0;
	
	error = failed = 0;
	SOLD("looping");
	while(opt_len >= sizeof(struct opthdr)) {
		struct opthdr *opt;
		int orig_opt_len; 
		SOLD("loop start");
		opt = (struct opthdr *)ret_pos; 
		if (ret_space < sizeof(struct opthdr)) {
			failed = TSYSERR;
			break;
		}
		SOLD("getting opthdr");
		if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
			opt->len > opt_len) {
			failed = TBADOPT;
			break;
		}
		SOLD("got opthdr");
		if (flag == T_NEGOTIATE) {
			char *buf;
			
			SOLD("handling T_NEGOTIATE");
			buf = ret_pos + sizeof(struct opthdr);
			if (ret_space < opt->len + sizeof(struct opthdr) ||
				copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
				failed = TSYSERR;
				break;
			}
			SOLD("got optdata");
			args[0] = fd;
			args[1] = opt->level;
			args[2] = opt->name;
			args[3] = (long)buf;
			args[4] = opt->len;
			SOLD("calling SETSOCKOPT");
			set_fs(KERNEL_DS);
			error = sys_socketcall(SYS_SETSOCKOPT, args);
			set_fs(old_fs);
			if (error) {
				failed = TBADOPT;
				break;
			}
			SOLD("SETSOCKOPT ok");
		}
		orig_opt_len = opt->len;
		opt->len = ret_space - sizeof(struct opthdr);
		if (opt->len < 0) {
			failed = TSYSERR;
			break;
		}
		args[0] = fd;
		args[1] = opt->level;
		args[2] = opt->name;
		args[3] = (long)(ret_pos+sizeof(struct opthdr));
		args[4] = (long)&opt->len;
		SOLD("calling GETSOCKOPT");
		set_fs(KERNEL_DS);
		error = sys_socketcall(SYS_GETSOCKOPT, args);
		set_fs(old_fs);;
		if (error) {
			failed = TBADOPT;
			break;
		}
		SOLD("GETSOCKOPT ok");
		ret_space -= sizeof(struct opthdr) + opt->len;
		ret_len += sizeof(struct opthdr) + opt->len;
		ret_pos += sizeof(struct opthdr) + opt->len;
		opt_len -= sizeof(struct opthdr) + orig_opt_len;
		opt_buf += sizeof(struct opthdr) + orig_opt_len;
		SOLD("loop end");
	}
	SOLD("loop done");
	if (do_ret) {
		SOLD("generating ret msg");
		if (failed)
			timod_error(fd, T_OPTMGMT_REQ, failed, -error);
		else {
			struct T_primsg *it;
			it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
			if (it) {
				struct T_optmgmt_ack *ack =
					(struct T_optmgmt_ack *)&it->type;
				SOLD("got primsg");
				ack->PRIM_type = T_OPTMGMT_ACK;
				ack->OPT_length = ret_len;
				ack->OPT_offset = sizeof(struct T_optmgmt_ack);
				ack->MGMT_flags = (failed ? T_FAILURE : flag);
				memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
					ret_buf, ret_len);
				timod_queue(fd, it);
			}
		}
	}
	SOLDD(("put_page %p\n", ret_buf));
	putpage(ret_buf);
	SOLD("done");	
	return 0;
}
Beispiel #13
0
int
fixfault(Segment *s, uintptr addr, int read, int doputmmu)
{
	int type;
	int ref;
	Pte **p, *etp;
	uintptr mmuphys=0, soff;
	Page **pg, *lkp, *new;
	Page *(*fn)(Segment*, uintptr);

	addr &= ~(BY2PG-1);
	soff = addr-s->base;
	p = &s->map[soff/PTEMAPMEM];
	if(*p == 0)
		*p = ptealloc();

	etp = *p;
	pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
	type = s->type&SG_TYPE;

	if(pg < etp->first)
		etp->first = pg;
	if(pg > etp->last)
		etp->last = pg;

	switch(type) {
	default:
		panic("fault");
		break;

	case SG_TEXT: 			/* Demand load */
		if(pagedout(*pg))
			pio(s, addr, soff, pg);

		mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
		(*pg)->modref = PG_REF;
		break;

	case SG_BSS:
	case SG_SHARED:			/* Zero fill on demand */
	case SG_STACK:
		if(*pg == 0) {
			new = newpage(1, &s, addr);
			if(s == 0)
				return -1;

			*pg = new;
		}
		goto common;

	case SG_DATA:
	common:			/* Demand load/pagein/copy on write */
		if(pagedout(*pg))
			pio(s, addr, soff, pg);

		/*
		 *  It's only possible to copy on write if
		 *  we're the only user of the segment.
		 */
		if(read && conf.copymode == 0 && s->ref == 1) {
			mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
			(*pg)->modref |= PG_REF;
			break;
		}

		lkp = *pg;
		lock(lkp);

		if(lkp->image == &swapimage)
			ref = lkp->ref + swapcount(lkp->daddr);
		else
			ref = lkp->ref;
		if(ref == 1 && lkp->image){
			/* save a copy of the original for the image cache */
			duppage(lkp);
			ref = lkp->ref;
		}
		unlock(lkp);
		if(ref > 1){
			new = newpage(0, &s, addr);
			if(s == 0)
				return -1;
			*pg = new;
			copypage(lkp, *pg);
			putpage(lkp);
		}
Beispiel #14
0
Extent*
cchain(uchar *buf, ulong offset, int len, Extent **tail)
{
	int l;
	Page *p;
	KMap *k;
	Extent *e, *start, **t;

	start = 0;
	*tail = 0;
	t = &start;
	while(len) {
		e = extentalloc();
		if(e == 0)
			break;

		p = auxpage();
		if(p == 0) {
			extentfree(e);
			break;
		}
		l = len;
		if(l > BY2PG)
			l = BY2PG;

		e->cache = p;
		e->start = offset;
		e->len = l;

		qlock(&cache);
		e->bid = cache.pgno;
		cache.pgno += BY2PG;
		/* wrap the counter; low bits are unused by pghash but checked by lookpage */
		if((cache.pgno & ~(BY2PG-1)) == 0){
			if(cache.pgno == BY2PG-1){
				print("cache wrapped\n");
				cache.pgno = 0;
			}else
				cache.pgno++;
		}
		qunlock(&cache);

		p->daddr = e->bid;
		k = kmap(p);
		if(waserror()) {		/* buf may be virtual */
			kunmap(k);
			nexterror();
		}
		memmove((void*)VA(k), buf, l);
		poperror();
		kunmap(k);

		cachepage(p, &fscache);
		putpage(p);

		buf += l;
		offset += l;
		len -= l;

		*t = e;
		*tail = e;
		t = &e->next;
	}

	return start;
}
Beispiel #15
0
int
cread(Chan *c, uchar *buf, int len, vlong off)
{
	KMap *k;
	Page *p;
	Mntcache *m;
	Extent *e, **t;
	int o, l, total;
	ulong offset;

	if(off+len > maxcache)
		return 0;

	m = c->mcp;
	if(m == 0)
		return 0;

	qlock(m);
	if(cdev(m, c) == 0) {
		qunlock(m);
		return 0;
	}

	offset = off;
	t = &m->list;
	for(e = *t; e; e = e->next) {
		if(offset >= e->start && offset < e->start+e->len)
			break;
		t = &e->next;
	}

	if(e == 0) {
		qunlock(m);
		return 0;
	}

	total = 0;
	while(len) {
		p = cpage(e);
		if(p == 0) {
			*t = e->next;
			extentfree(e);
			qunlock(m);
			return total;
		}

		o = offset - e->start;
		l = len;
		if(l > e->len-o)
			l = e->len-o;

		k = kmap(p);
		if(waserror()) {
			kunmap(k);
			putpage(p);
			qunlock(m);
			nexterror();
		}

		memmove(buf, (uchar*)VA(k) + o, l);

		poperror();
		kunmap(k);

		putpage(p);

		buf += l;
		len -= l;
		offset += l;
		total += l;
		t = &e->next;
		e = e->next;
		if(e == 0 || e->start != offset)
			break;
	}

	qunlock(m);
	return total;
}
Beispiel #16
0
void
t_page(int n)	/* do whatever new page functions */
{
	int m, i;
	char buf[1024], *bp;

	pgnum[np++] = n;
	pgadr[np] = ftell(fp);
	if (np > npmax)
		npmax = np;
	if (output == 0) {
		output = in_olist(n);
		t_init(1);
		return;
	}
	/* have just printed something, and seen p<n> for next one */
	putpage();
	fflush(stdout);
	if (nowait)
		return;

  next:
	for (bp = buf; (*bp = readch()); )
		if (*bp++ == '\n' || bp >= &buf[sizeof buf - 1])
			break;
	*bp = 0;
	switch (buf[0]) {
	case 0:
		done();
		break;
	case '\n':
		output = in_olist(n);
		t_init(1);
		return;
	case '!':
		callunix(&buf[1]);
		fputs("!\n", stderr);
		break;
	case 'e':
		erase = 1 - erase;
		break;
	case 'w':
		wflag = 1 - wflag;
		break;
	case 'a':
		aspect = atof(&buf[1]);
		break;
	case '-':
	case 'p':
		m = atoi(&buf[1]) + 1;
		if (fp == stdin) {
			fputs("you can't; it's not a file\n", stderr);
			break;
		}
		if (np - m <= 0) {
			fputs("too far back\n", stderr);
			break;
		}
		np -= m;
		fseek(fp, pgadr[np], 0);
		output = 1;
		t_init(1);
		return;
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		m = atoi(&buf[0]);
		for (i = 0; i < npmax; i++)
			if (m == pgnum[i])
				break;
		if (i >= npmax || fp == stdin) {
			fputs("you can't\n", stderr);
			break;
		}
		np = i + 1;
		fseek(fp, pgadr[np], 0);
		output = 1;
		t_init(1);
		return;
	case 'o':
		outlist(&buf[1]);
		output = 0;
		t_init(1);
		return;
	case '?':
		fputs("!cmd	unix cmd\n", stderr);
		fputs("p	print this page again\n", stderr);
		fputs("-n	go back n pages\n", stderr);
		fputs("n	print page n (previously printed)\n", stderr);
		fputs("o...	set the -o output list to ...\n", stderr);
		fputs("en	n=0 -> don't erase; n=1 -> erase\n", stderr);
		fputs("an	sets aspect ratio to n\n", stderr);
		break;
	default:
		fputs("?\n", stderr);
		break;
	}
	goto next;
}