xref: /plan9-contrib/sys/src/cmd/dossrv/xfile.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include "iotrack.h"
4 #include "dat.h"
5 #include "fns.h"
6 
7 #define	FIDMOD	127	/* prime */
8 
9 static Xfs	*xhead;
10 static Xfile	*xfiles[FIDMOD], *freelist;
11 static Lock	xlock, xlocks[FIDMOD], freelock;
12 
13 int	client;
14 
15 Xfs *
16 getxfs(char *name)
17 {
18 	int fd; Dir dir; Xfs *xf, *fxf;
19 
20 	if(name==0 || name[0]==0)
21 		name = deffile;
22 	if(name == 0){
23 		errno = Enofilsys;
24 		return 0;
25 	}
26 	fd = open(name, ORDWR);
27 	if(fd < 0){
28 		errno = Enonexist;
29 		return 0;
30 	}
31 	if(dirfstat(fd, &dir) < 0){
32 		errno = Eio;
33 		close(fd);
34 		return 0;
35 	}
36 	lock(&xlock);
37 	for(fxf=0,xf=xhead; xf; xf=xf->next){
38 		if(xf->ref == 0){
39 			if(fxf == 0)
40 				fxf = xf;
41 			continue;
42 		}
43 		if(xf->qid.path != dir.qid.path || xf->qid.vers != dir.qid.vers)
44 			continue;
45 		if(strcmp(xf->name, name) != 0 || xf->dev < 0)
46 			continue;
47 		if(devcheck(xf) < 0) /* look for media change */
48 			continue;
49 		chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
50 		++xf->ref;
51 		unlock(&xlock);
52 		close(fd);
53 		return xf;
54 	}
55 	if(fxf==0){
56 		fxf = malloc(sizeof(Xfs));
57 		if(fxf==0){
58 			unlock(&xlock);
59 			close(fd);
60 			errno = Enomem;
61 			return 0;
62 		}
63 		fxf->next = xhead;
64 		xhead = fxf;
65 	}
66 	chat("alloc \"%s\", dev=%d...", name, fd);
67 	fxf->name = strdup(name);
68 	fxf->ref = 1;
69 	fxf->qid = dir.qid;
70 	fxf->dev = fd;
71 	fxf->fmt = 0;
72 	fxf->offset = 0;
73 	fxf->ptr = 0;
74 	unlock(&xlock);
75 	return fxf;
76 }
77 
78 void
79 refxfs(Xfs *xf, int delta)
80 {
81 	lock(&xlock);
82 	xf->ref += delta;
83 	if(xf->ref == 0){
84 		chat("free \"%s\", dev=%d...", xf->name, xf->dev);
85 		free(xf->name);
86 		free(xf->ptr);
87 		purgebuf(xf);
88 		if(xf->dev >= 0){
89 			close(xf->dev);
90 			xf->dev = -1;
91 		}
92 	}
93 	unlock(&xlock);
94 }
95 
96 Xfile *
97 xfile(int fid, int flag)
98 {
99 	int k = ((ulong)fid^(ulong)client)%FIDMOD;
100 	Xfile **hp=&xfiles[k], *f, *pf;
101 
102 	lock(&xlocks[k]);
103 	for(f=*hp,pf=0; f; pf=f, f=f->next)
104 		if(f->fid == fid && f->client == client)
105 			break;
106 	if(f && pf){
107 		pf->next = f->next;
108 		f->next = *hp;
109 		*hp = f;
110 	}
111 	switch(flag){
112 	default:
113 		panic("xfile");
114 	case Asis:
115 		unlock(&xlocks[k]);
116 		return (f && f->xf && f->xf->dev < 0) ? 0 : f;
117 	case Clean:
118 		break;
119 	case Clunk:
120 		if(f){
121 			*hp = f->next;
122 			unlock(&xlocks[k]);
123 			clean(f);
124 			lock(&freelock);
125 			f->next = freelist;
126 			freelist = f;
127 			unlock(&freelock);
128 		} else
129 			unlock(&xlocks[k]);
130 		return 0;
131 	}
132 	unlock(&xlocks[k]);
133 	if(f)
134 		return clean(f);
135 	lock(&freelock);
136 	if(f = freelist){	/* assign = */
137 		freelist = f->next;
138 		unlock(&freelock);
139 	} else {
140 		unlock(&freelock);
141 		f = malloc(sizeof(Xfile));
142 	}
143 	lock(&xlocks[k]);
144 	f->next = *hp;
145 	*hp = f;
146 	unlock(&xlocks[k]);
147 	f->fid = fid;
148 	f->client = client;
149 	f->flags = 0;
150 	f->qid = (Qid){0,0};
151 	f->xf = 0;
152 	f->ptr = 0;
153 	return f;
154 }
155 
156 Xfile *
157 clean(Xfile *f)
158 {
159 	if(f->ptr){
160 		free(f->ptr);
161 		f->ptr = 0;
162 	}
163 	if(f->xf){
164 		refxfs(f->xf, -1);
165 		f->xf = 0;
166 	}
167 	f->xf = 0;
168 	f->flags = 0;
169 	f->qid = (Qid){0,0};
170 	return f;
171 }
172 
173 int
174 xfspurge(void)
175 {
176 	Xfile **hp, *f, *pf, *nf;
177 	int k, count=0;
178 
179 	for(k=0; k<FIDMOD; k++){
180 		lock(&xlocks[k]);
181 		hp=&xfiles[k];
182 		for(f=*hp,pf=0; f; f=nf){
183 			nf = f->next;
184 			if(f->client != client){
185 				pf = f;
186 				continue;
187 			}
188 			if (pf)
189 				pf->next = f->next;
190 			else
191 				*hp = f->next;
192 			clean(f);
193 			lock(&freelock);
194 			f->next = freelist;
195 			freelist = f;
196 			unlock(&freelock);
197 			++count;
198 		}
199 		unlock(&xlocks[k]);
200 	}
201 	return count;
202 }
203