summaryrefslogtreecommitdiff
path: root/emu/port/uqid.c
blob: bd43db3d0aa48a6278493f047ba9464b909116fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include	"dat.h"
#include	"fns.h"
#include	"error.h"

/*
 * unique Qid path generation,
 * for exportfs.c and various devfs-*
 */

#define	QIDMASK	(((vlong)1<<48)-1)

void
uqidinit(Uqidtab *tab)
{
	memset(tab, 0, sizeof(*tab));
}

static int
uqidhash(vlong path)
{
	ulong p;
	p = (ulong)path;
	return ((p>>16) ^ (p>>8) ^ p) & (Nqidhash-1);
}

static Uqid **
uqidlook(Uqid **tab, Chan *c, vlong path)
{
	Uqid **hp, *q;

	for(hp = &tab[uqidhash(path)]; (q = *hp) != nil; hp = &q->next)
		if(q->type == c->type && q->dev == c->dev && q->oldpath == path)
			break;
	return hp;
}

static int
uqidexists(Uqid **tab, vlong path)
{
	int i;
	Uqid *q;

	for(i=0; i<Nqidhash; i++)
		for(q = tab[i]; q != nil; q = q->next)
			if(q->newpath == path)
				return 1;
	return 0;
}

Uqid *
uqidalloc(Uqidtab *tab, Chan *c)
{
	Uqid **hp, *q;

	qlock(&tab->l);
	hp = uqidlook(tab->qids, c, c->qid.path);
	if((q = *hp) != nil){
		incref(&q->r);
		qunlock(&tab->l);
		return q;
	}
	q = mallocz(sizeof(*q), 1);
	if(q == nil){
		qunlock(&tab->l);
		error(Enomem);
	}
	q->r.ref = 1;
	q->type = c->type;
	q->dev = c->dev;
	q->oldpath = c->qid.path;
	q->newpath = c->qid.path;
	while(uqidexists(tab->qids, q->newpath)){
		if(++tab->pathgen >= (1<<16))
			tab->pathgen = 1;
		q->newpath = ((vlong)tab->pathgen<<48) | (q->newpath & QIDMASK);
	}
	q->next = nil;
	*hp = q;
	qunlock(&tab->l);
	return q;
}

void
freeuqid(Uqidtab *tab, Uqid *q)
{
	Uqid **hp;

	if(q == nil)
		return;
	qlock(&tab->l);
	if(decref(&q->r) == 0){
		hp = &tab->qids[uqidhash(q->oldpath)];
		for(; *hp != nil; hp = &(*hp)->next)
			if(*hp == q){
				*hp = q->next;
				free(q);
				break;
			}
	}
	qunlock(&tab->l);
}

Qid
mkuqid(Chan *c, Uqid *qid)
{
	Qid q;

	if(qid == nil)
		return c->qid;
	q.path = qid->newpath;
	q.vers = c->qid.vers;
	q.type = c->qid.type;
	return q;
}