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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
|
#define KNAMELEN 28 /* max length of name held in kernel */
#define DOMLEN 64
#define BLOCKALIGN 8
typedef struct Alarms Alarms;
typedef struct Block Block;
typedef struct CSN CSN;
typedef struct Chan Chan;
typedef struct Cmdbuf Cmdbuf;
typedef struct Cmdtab Cmdtab;
typedef struct Cname Cname;
typedef struct Conf Conf;
typedef struct Dev Dev;
typedef struct Dirtab Dirtab;
typedef struct Edfinterface Edfinterface;
typedef struct Egrp Egrp;
typedef struct Evalue Evalue;
typedef struct Fgrp Fgrp;
typedef struct FPsave FPsave;
typedef struct DevConf DevConf;
typedef struct Label Label;
typedef struct List List;
typedef struct Log Log;
typedef struct Logflag Logflag;
typedef struct Mntcache Mntcache;
typedef struct Mount Mount;
typedef struct Mntrpc Mntrpc;
typedef struct Mntwalk Mntwalk;
typedef struct Mnt Mnt;
typedef struct Mhead Mhead;
typedef struct Note Note;
typedef struct Page Page;
typedef struct Palloc Palloc;
typedef struct Perf Perf;
typedef struct Pgrps Pgrps;
typedef struct PhysUart PhysUart;
typedef struct Pgrp Pgrp;
typedef struct Physseg Physseg;
typedef struct Proc Proc;
typedef struct Pte Pte;
typedef struct Pthash Pthash;
typedef struct Queue Queue;
typedef struct Ref Ref;
typedef struct Rendez Rendez;
typedef struct Rgrp Rgrp;
typedef struct RWlock RWlock;
typedef struct Schedq Schedq;
typedef struct Segment Segment;
typedef struct Session Session;
typedef struct Task Task;
typedef struct Talarm Talarm;
typedef struct Timer Timer;
typedef struct Uart Uart;
typedef struct Ureg Ureg;
typedef struct Waitq Waitq;
typedef struct Walkqid Walkqid;
typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
#include "fcall.h"
enum
{
SnarfSize = 64*1024,
};
struct Conf
{
ulong nmach; /* processors */
ulong nproc; /* processes */
ulong monitor; /* has monitor? */
ulong npage0; /* total physical pages of memory */
ulong npage1; /* total physical pages of memory */
ulong npage; /* total physical pages of memory */
ulong upages; /* user page pool */
ulong nimage; /* number of page cache image headers */
ulong nswap; /* number of swap pages */
int nswppo; /* max # of pageouts per segment pass */
ulong base0; /* base of bank 0 */
ulong base1; /* base of bank 1 */
ulong copymode; /* 0 is copy on write, 1 is copy on reference */
ulong ialloc; /* max interrupt time allocation in bytes */
ulong pipeqsize; /* size in bytes of pipe queues */
int nuart; /* number of uart devices */
};
struct Label
{
jmp_buf buf;
};
struct Ref
{
Lock lk;
long ref;
};
struct Rendez
{
Lock lk;
Proc *p;
};
struct RWlock /* changed from kernel */
{
int readers;
Lock lk;
QLock x;
QLock k;
};
struct Talarm
{
Lock lk;
Proc *list;
};
struct Alarms
{
QLock lk;
Proc *head;
};
/*
* Access types in namec & channel flags
*/
enum
{
Aaccess, /* as in stat, wstat */
Abind, /* for left-hand-side of bind */
Atodir, /* as in chdir */
Aopen, /* for i/o */
Amount, /* to be mounted or mounted upon */
Acreate, /* is to be created */
Aremove, /* will be removed by caller */
COPEN = 0x0001, /* for i/o */
CMSG = 0x0002, /* the message channel for a mount */
/* CCREATE = 0x0004, permits creation if c->mnt */
CCEXEC = 0x0008, /* close on exec */
CFREE = 0x0010, /* not in use */
CRCLOSE = 0x0020, /* remove on close */
CCACHE = 0x0080, /* client cache */
};
/* flag values */
enum
{
BINTR = (1<<0),
BFREE = (1<<1),
Bipck = (1<<2), /* ip checksum */
Budpck = (1<<3), /* udp checksum */
Btcpck = (1<<4), /* tcp checksum */
Bpktck = (1<<5), /* packet checksum */
};
struct Block
{
Block* next;
Block* list;
uchar* rp; /* first unconsumed byte */
uchar* wp; /* first empty byte */
uchar* lim; /* 1 past the end of the buffer */
uchar* base; /* start of the buffer */
void (*free)(Block*);
ushort flag;
ushort checksum; /* IP checksum of complete packet (minus media header) */
};
#define BLEN(s) ((s)->wp - (s)->rp)
#define BALLOC(s) ((s)->lim - (s)->base)
struct Chan
{
Ref ref;
Chan* next; /* allocation */
Chan* link;
vlong offset; /* in file */
ushort type;
ulong dev;
ushort mode; /* read/write */
ushort flag;
Qid qid;
int fid; /* for devmnt */
ulong iounit; /* chunk size for i/o; 0==default */
Mhead* umh; /* mount point that derived Chan; used in unionread */
Chan* umc; /* channel in union; held for union read */
QLock umqlock; /* serialize unionreads */
int uri; /* union read index */
int dri; /* devdirread index */
ulong mountid;
Mntcache *mcp; /* Mount cache pointer */
Mnt *mux; /* Mnt for clients using me for messages */
void* aux;
Qid pgrpid; /* for #p/notepg */
ulong mid; /* for ns in devproc */
Chan* mchan; /* channel to mounted server */
Qid mqid; /* qid of root of mount point */
Session*session;
Cname *name;
};
struct Cname
{
Ref ref;
int alen; /* allocated length */
int len; /* strlen(s) */
char *s;
};
struct Dev
{
int dc;
char* name;
void (*reset)(void);
void (*init)(void);
void (*shutdown)(void);
Chan* (*attach)(char*);
Walkqid* (*walk)(Chan*, Chan*, char**, int);
int (*stat)(Chan*, uchar*, int);
Chan* (*open)(Chan*, int);
void (*create)(Chan*, char*, int, ulong);
void (*close)(Chan*);
long (*read)(Chan*, void*, long, vlong);
Block* (*bread)(Chan*, long, ulong);
long (*write)(Chan*, void*, long, vlong);
long (*bwrite)(Chan*, Block*, ulong);
void (*remove)(Chan*);
int (*wstat)(Chan*, uchar*, int);
void (*power)(int); /* power mgt: power(1) => on, power (0) => off */
int (*config)(int, char*, DevConf*); // returns nil on error
};
struct Dirtab
{
char name[KNAMELEN];
Qid qid;
vlong length;
ulong perm;
};
struct Walkqid
{
Chan *clone;
int nqid;
Qid qid[1];
};
enum
{
NSMAX = 1000,
NSLOG = 7,
NSCACHE = (1<<NSLOG),
};
struct Mntwalk /* state for /proc/#/ns */
{
int cddone;
ulong id;
Mhead* mh;
Mount* cm;
};
struct Mount
{
ulong mountid;
Mount* next;
Mhead* head;
Mount* copy;
Mount* order;
Chan* to; /* channel replacing channel */
int mflag;
char *spec;
};
struct Mhead
{
Ref ref;
RWlock lock;
Chan* from; /* channel mounted upon */
Mount* mount; /* what's mounted upon it */
Mhead* hash; /* Hash chain */
};
struct Mnt
{
Lock lk;
/* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
Chan *c; /* Channel to file service */
Proc *rip; /* Reader in progress */
Mntrpc *queue; /* Queue of pending requests on this channel */
ulong id; /* Multiplexer id for channel check */
Mnt *list; /* Free list */
int flags; /* cache */
int msize; /* data + IOHDRSZ */
char *version; /* 9P version */
Queue *q; /* input queue */
};
enum
{
NUser, /* note provided externally */
NExit, /* deliver note quietly */
NDebug, /* print debug message */
};
struct Note
{
char msg[ERRMAX];
int flag; /* whether system posted it */
};
enum
{
RENDLOG = 5,
RENDHASH = 1<<RENDLOG, /* Hash to lookup rendezvous tags */
MNTLOG = 5,
MNTHASH = 1<<MNTLOG, /* Hash to walk mount table */
NFD = 100, /* per process file descriptors */
PGHLOG = 9,
PGHSIZE = 1<<PGHLOG, /* Page hash for image lookup */
};
#define REND(p,s) ((p)->rendhash[(s)&((1<<RENDLOG)-1)])
#define MOUNTH(p,qid) ((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])
struct Pgrp
{
Ref ref; /* also used as a lock when mounting */
int noattach;
ulong pgrpid;
QLock debug; /* single access via devproc.c */
RWlock ns; /* Namespace n read/one write lock */
Mhead *mnthash[MNTHASH];
};
struct Rgrp
{
Ref ref;
Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */
};
struct Egrp
{
Ref ref;
RWlock lk;
Evalue **ent;
int nent;
int ment;
ulong path; /* qid.path of next Evalue to be allocated */
ulong vers; /* of Egrp */
};
struct Evalue
{
char *name;
char *value;
int len;
Evalue *link;
Qid qid;
};
struct Fgrp
{
Ref ref;
Chan **fd;
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
int exceed; /* debugging */
};
enum
{
DELTAFD = 20, /* incremental increase in Fgrp.fd's */
NERR = 20
};
typedef uvlong Ticks;
enum
{
Running,
Rendezvous,
Wakeme,
};
struct Proc
{
uint state;
uint mach;
ulong pid;
ulong parentpid;
Pgrp *pgrp; /* Process group for namespace */
Fgrp *fgrp; /* File descriptor group */
Rgrp *rgrp;
Lock rlock; /* sync sleep/wakeup with postnote */
Rendez *r; /* rendezvous point slept on */
Rendez sleep; /* place for syssleep/debug */
int notepending; /* note issued but not acted on */
int kp; /* true if a kernel process */
void* rendtag; /* Tag for rendezvous */
void* rendval; /* Value for rendezvous */
Proc *rendhash; /* Hash list for tag values */
int nerrlab;
Label errlab[NERR];
char user[KNAMELEN];
char *syserrstr; /* last error from a system call, errbuf0 or 1 */
char *errstr; /* reason we're unwinding the error stack, errbuf1 or 0 */
char errbuf0[ERRMAX];
char errbuf1[ERRMAX];
char genbuf[128]; /* buffer used e.g. for last name element from namec */
char text[KNAMELEN];
Chan *slash;
Chan *dot;
Proc *qnext;
void (*fn)(void*);
void *arg;
char oproc[1024]; /* reserved for os */
};
enum
{
PRINTSIZE = 256,
MAXCRYPT = 127,
NUMSIZE = 12, /* size of formatted number */
MB = (1024*1024),
READSTR = 1000, /* temporary buffer size for device reads */
};
extern char* conffile;
extern int cpuserver;
extern Dev* devtab[];
extern char *eve;
extern char hostdomain[];
extern uchar initcode[];
extern Queue* kbdq;
extern Queue* kprintoq;
extern Ref noteidalloc;
extern Palloc palloc;
extern Queue *serialoq;
extern char* statename[];
extern int nsyscall;
extern char *sysname;
extern uint qiomaxatomic;
extern Conf conf;
enum
{
LRESPROF = 3,
};
/*
* action log
*/
struct Log {
Lock lk;
int opens;
char* buf;
char *end;
char *rptr;
int len;
int nlog;
int minread;
int logmask; /* mask of things to debug */
QLock readq;
Rendez readr;
};
struct Logflag {
char* name;
int mask;
};
enum
{
NCMDFIELD = 128
};
struct Cmdbuf
{
char *buf;
char **f;
int nf;
};
struct Cmdtab
{
int index; /* used by client to switch on result */
char *cmd; /* command name */
int narg; /* expected #args; 0 ==> variadic */
};
/* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */
enum
{
/* Queue.state */
Qstarve = (1<<0), /* consumer starved */
Qmsg = (1<<1), /* message stream */
Qclosed = (1<<2), /* queue has been closed/hungup */
Qflow = (1<<3), /* producer flow controlled */
Qcoalesce = (1<<4), /* coallesce packets on read */
Qkick = (1<<5), /* always call the kick routine after qwrite */
};
#define DEVDOTDOT -1
extern Proc *_getproc(void);
extern void _setproc(Proc*);
#define up (_getproc())
|