10
|
1 #include "types.h"
|
|
2 #include "defs.h"
|
|
3 #include "param.h"
|
|
4 #include "stat.h"
|
|
5 #include "mmu.h"
|
|
6 #include "proc.h"
|
|
7 #include "spinlock.h"
|
|
8 #include "buf.h"
|
|
9 #include "fs.h"
|
|
10 #include "file.h"
|
|
11 #interface "Err.h"
|
|
12 #interface "fs.dg"
|
|
13
|
|
14 fs* createfs_impl(struct Context* cbc_context) {
|
|
15 struct fs* fs = new fs();
|
|
16 struct fs_impl* fs_impl = new fs_impl();
|
|
17 fs->fs = (union Data*)fs_impl;
|
|
18 fs_impl->fs_impl = NULL;
|
|
19 fs_impl->sb = NULL;
|
|
20 fs_impl->ret = 0;
|
|
21 fs_impl->dev = 0;
|
|
22 fs_impl->type = 0;
|
|
23 fs_impl->bp = NULL;
|
|
24 fs_impl->dip = NULL;
|
|
25 fs_impl->inum = 0;
|
|
26 fs_impl->dp = NULL;
|
|
27 fs_impl->name = NULL;
|
|
28 fs_impl->off = 0;
|
|
29 fs_impl->poff = NULL;
|
|
30 fs_impl->de = NULL;
|
|
31 fs_impl->tot = 0;
|
|
32 fs_impl->m = 0;
|
|
33 fs_impl->dst = NULL;
|
|
34 fs_impl->n = 0;
|
|
35 fs_impl->src = NULL;
|
|
36 fs_impl->allocinode = C_allocinode;
|
|
37 fs_impl->allocinode_loop = C_allocinode_loop;
|
|
38 fs_impl->allocinode_loopcheck = C_allocinode_loopcheck;
|
|
39 fs_impl->allocinode_noloop = C_allocinode_noloop;
|
|
40 fs_impl->lockinode1 = C_lockinode1;
|
|
41 fs_impl->lockinode2 = C_lockinode2;
|
|
42 fs_impl->lockinode_sleepcheck = C_lockinode_sleepcheck;
|
|
43 fs_impl->iput_check = C_iput_check;
|
|
44 fs_impl->iput_inode_nolink = C_iput_inode_nolink;
|
|
45 fs_impl->readi_check_diskinode = C_readi_check_diskinode;
|
|
46 fs_impl->readi_loopcheck = C_readi_loopcheck;
|
|
47 fs_impl->readi_loop = C_readi_loop;
|
|
48 fs_impl->readi_noloop = C_readi_noloop;
|
|
49 fs_impl->writei_check_diskinode = C_writei_check_diskinode;
|
|
50 fs_impl->writei_loopcheck = C_writei_loopcheck;
|
|
51 fs_impl->writei_loop = C_writei_loop;
|
|
52 fs_impl->writei_noloop = C_writei_noloop;
|
|
53 fs_impl->dirlookup_loopcheck = C_dirlookup_loopcheck;
|
|
54 fs_impl->dirlookup_loop = C_dirlookup_loop;
|
|
55 fs_impl->dirlookup_noloop = C_dirlookup_noloop;
|
|
56 fs_impl->dirlink_namecheck = C_dirlink_namecheck;
|
|
57 fs_impl->dirlink_loopcheck = C_dirlink_loopcheck;
|
|
58 fs_impl->dirlink_loop = C_dirlink_loop;
|
|
59 fs_impl->dirlink_noloop = C_dirlink_noloop;
|
|
60 fs->readsb = C_readsbfs_impl;
|
|
61 fs->iinit = C_iinitfs_impl;
|
|
62 fs->ialloc = C_iallocfs_impl;
|
|
63 fs->iupdate = C_iupdatefs_impl;
|
|
64 fs->idup = C_idupfs_impl;
|
|
65 fs->ilock = C_ilockfs_impl;
|
|
66 fs->iunlock = C_iunlockfs_impl;
|
|
67 fs->iput = C_iputfs_impl;
|
|
68 fs->iunlockput = C_iunlockputfs_impl;
|
|
69 fs->stati = C_statifs_impl;
|
|
70 fs->readi = C_readifs_impl;
|
|
71 fs->writei = C_writeifs_impl;
|
|
72 fs->namecmp = C_namecmpfs_impl;
|
|
73 fs->dirlookup = C_dirlookupfs_impl;
|
|
74 fs->dirlink = C_dirlinkfs_impl;
|
|
75 fs->namei = C_nameifs_impl;
|
|
76 fs->nameiparent = C_nameiparentfs_impl;
|
|
77 return fs;
|
|
78 }
|
|
79
|
|
80 typedef struct superblock superblock;
|
|
81 __code readsbfs_impl(struct fs_impl* fs, uint dev, struct superblock* sb, __code next(...)) { //:skip
|
|
82
|
|
83 struct buf* bp;
|
|
84
|
|
85 bp = bread(dev, 1);
|
|
86 memmove(sb, bp->data, sizeof(*sb));
|
|
87 brelse(bp);
|
|
88
|
|
89 goto next(...);
|
|
90 }
|
|
91
|
|
92 struct {
|
|
93 struct spinlock lock;
|
|
94 struct inode inode[NINODE];
|
|
95 } icache;
|
|
96
|
|
97 __code iinitfs_impl(struct fs_impl* fs, __code next(...)) {
|
|
98
|
|
99 initlock(&icache.lock, "icache");
|
|
100
|
|
101 goto next(...);
|
|
102 }
|
|
103
|
|
104 __code iallocfs_impl(struct fs_impl* fs, uint dev, short type, __code next(...)) {
|
|
105 goto allocinode(fs, dev, sb, next(...));
|
|
106 }
|
|
107
|
|
108 __code iupdatefs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) {
|
|
109
|
|
110 struct buf *bp;
|
|
111 struct dinode *dip;
|
|
112
|
|
113 bp = bread(ip->dev, IBLOCK(ip->inum));
|
|
114
|
|
115 dip = (struct dinode*) bp->data + ip->inum % IPB;
|
|
116 dip->type = ip->type;
|
|
117 dip->major = ip->major;
|
|
118 dip->minor = ip->minor;
|
|
119 dip->nlink = ip->nlink;
|
|
120 dip->size = ip->size;
|
|
121
|
|
122 memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
|
|
123 log_write(bp);
|
|
124 brelse(bp);
|
|
125
|
|
126 goto next(...);
|
|
127 }
|
|
128
|
|
129 __code idupfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) {
|
|
130
|
|
131 acquire(&icache.lock);
|
|
132 ip->ref++;
|
|
133 release(&icache.lock);
|
15
|
134
|
10
|
135 goto next(ip, ...);
|
|
136
|
|
137 }
|
|
138
|
|
139 __code ilockfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) {
|
|
140
|
|
141 goto lockinode1(fs, ip, bp, dip, next(...));
|
|
142 }
|
|
143
|
|
144 __code iunlockfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) {
|
15
|
145
|
10
|
146 if (ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1) {
|
|
147 char* msg = "iunlock";
|
|
148 struct Err* err = createKernelError(&proc->cbc_context);
|
|
149 Gearef(cbc_context, Err)->msg = msg;
|
|
150 goto meta(cbc_context, err->panic);
|
|
151 }
|
|
152
|
|
153 acquire(&icache.lock);
|
|
154 ip->flags &= ~I_BUSY;
|
|
155 wakeup(ip);
|
|
156 release(&icache.lock);
|
|
157
|
|
158 goto next(...);
|
|
159 }
|
|
160
|
|
161 __code iputfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) {
|
|
162 if (next == C_iputfs_impl) {
|
|
163 next = fs->next2;
|
|
164 }
|
15
|
165 goto iput_check(fs, ip, next(...));
|
10
|
166 }
|
|
167
|
15
|
168 __code iunlockputfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) {
|
|
169 fs->next2 = next;
|
10
|
170 goto iunlockfs_impl(ip, fs->iput, ...);
|
|
171 }
|
|
172
|
|
173 typedef struct stat stat;
|
|
174 __code statifs_impl(struct fs_impl* fs , struct inode* ip, struct stat* st, __code next(...)) { //:skip
|
|
175 st->dev = ip->dev;
|
|
176 st->ino = ip->inum;
|
|
177 st->type = ip->type;
|
|
178 st->nlink = ip->nlink;
|
|
179 st->size = ip->size;
|
|
180 goto next(...);
|
|
181 }
|
|
182
|
|
183 __code readifs_impl(struct fs_impl* fs, struct inode* ip, char* dst, uint off, uint tot, uint n, __code next(int ret, ...)) {
|
|
184 if (ip->type == T_DEV) {
|
|
185 goto readi_check_diskinode(fs, ip, dst, n, next(...));
|
|
186 }
|
|
187
|
|
188 if (off > ip->size || off + n < off) {
|
|
189 ret = -1;
|
|
190 goto next(ret, ...);
|
|
191 }
|
|
192
|
|
193 if (off + n > ip->size) {
|
|
194 n = ip->size - off;
|
|
195 }
|
|
196 Gearef(cbc_context, fs)->tot = 0;
|
|
197 goto readi_loopcheck(fs, tot, m, dst, off, n, next(...));
|
|
198 }
|
|
199
|
|
200 __code writeifs_impl(struct fs_impl* fs, struct inode* ip, char* src, uint off, uint tot, uint n, __code next(int ret, ...)) {
|
15
|
201 if (ip->type == T_DEV) {
|
10
|
202 goto writei_check_diskinode(fs, ip, src, n, next(...));
|
|
203 }
|
15
|
204
|
10
|
205 if (off > ip->size || off + n < off) {
|
|
206 ret = -1;
|
|
207 goto next(ret, ...);
|
|
208 }
|
15
|
209
|
10
|
210 if (off + n > MAXFILE * BSIZE) {
|
|
211 ret = -1;
|
|
212 goto next(ret, ...);
|
|
213 }
|
|
214 Gearef(cbc_context, fs)->tot = 0;
|
|
215 goto writei_loopcheck(fs, tot, m, src, off, n, next(...));
|
|
216 }
|
|
217
|
|
218
|
|
219 __code namecmpfs_impl(struct fs_impl* fs, const char* s, const char* t, __code next(int strncmp_val, ...)) {
|
|
220 strncmp_val = strncmp(s, t, DIRSIZ);
|
|
221 goto next(strncmp_val, ...);
|
|
222 }
|
|
223
|
|
224 __code dirlookupfs_impl(struct fs_impl* fs, struct inode* dp, char* name, uint off, uint* poff, dirent* de, __code next(...)) { //:skip
|
15
|
225 if (dp->type != T_DIR) {
|
10
|
226 char* msg = "dirlookup not DIR";
|
|
227 struct Err* err = createKernelError(&proc->cbc_context);
|
|
228 Gearef(cbc_context, Err)->msg = msg;
|
|
229 goto meta(cbc_context, err->panic);
|
|
230 }
|
|
231 Gearef(cbc_context, fs)->off = 0;
|
|
232 goto dirlookup_loopcheck(fs, dp, name, off, poff, de, next(...));
|
|
233 }
|
|
234
|
|
235 __code dirlinkfs_impl(struct fs_impl* fs, struct inode* ip, struct dirent* de, struct inode* dp, char* name, uint off, uint inum, __code next(...)) { //:skip
|
|
236 if ((ip = dirlookup(dp, name, 0)) != 0) {
|
|
237 goto dirlink_namecheck(fs, ip, next(...));
|
|
238 }
|
|
239 Gearef(cbc_context, fs)->off = 0;
|
|
240 goto dirlink_loopcheck(fs, de, dp, off, next(...));
|
|
241 }
|
|
242
|
|
243 static struct inode* iget (uint dev, uint inum)
|
|
244 {
|
|
245 struct inode *ip, *empty;
|
|
246
|
|
247 acquire(&icache.lock);
|
|
248
|
|
249 empty = 0;
|
|
250
|
|
251 for (ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++) {
|
|
252 if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) {
|
|
253 ip->ref++;
|
|
254 release(&icache.lock);
|
|
255 return ip;
|
|
256 }
|
|
257
|
|
258 if (empty == 0 && ip->ref == 0) { // Remember empty slot.
|
|
259 empty = ip;
|
|
260 }
|
|
261 }
|
|
262 if (empty == 0) {
|
|
263 panic("iget: no inodes");
|
|
264 }
|
|
265
|
|
266 ip = empty;
|
|
267 ip->dev = dev;
|
|
268 ip->inum = inum;
|
|
269 ip->ref = 1;
|
|
270 ip->flags = 0;
|
|
271 release(&icache.lock);
|
|
272
|
|
273 return ip;
|
|
274 }
|
|
275
|
|
276 static char* skipelem (char *path, char *name)
|
|
277 {
|
|
278 char *s;
|
|
279 int len;
|
|
280
|
|
281 while (*path == '/') {
|
|
282 path++;
|
|
283 }
|
|
284
|
|
285 if (*path == 0) {
|
|
286 return 0;
|
|
287 }
|
|
288
|
|
289 s = path;
|
|
290
|
|
291 while (*path != '/' && *path != 0) {
|
|
292 path++;
|
|
293 }
|
|
294
|
|
295 len = path - s;
|
|
296
|
|
297 if (len >= DIRSIZ) {
|
|
298 memmove(name, s, DIRSIZ);
|
|
299 } else {
|
|
300 memmove(name, s, len);
|
|
301 name[len] = 0;
|
|
302 }
|
|
303
|
|
304 while (*path == '/') {
|
|
305 path++;
|
|
306 }
|
|
307
|
|
308 return path;
|
|
309 }
|
|
310
|
|
311
|
|
312 static struct inode* namex (char *path, int nameiparent, char *name)
|
|
313 {
|
|
314 struct inode *ip, *next;
|
|
315
|
|
316 if (*path == '/') {
|
|
317 ip = iget(ROOTDEV, ROOTINO);
|
|
318 } else {
|
|
319 ip = idup(proc->cwd);
|
|
320 }
|
|
321
|
|
322 while ((path = skipelem(path, name)) != 0) {
|
|
323 ilock(ip);
|
|
324
|
|
325 if (ip->type != T_DIR) {
|
|
326 iunlockput(ip);
|
|
327 return 0;
|
|
328 }
|
|
329
|
|
330 if (nameiparent && *path == '\0') {
|
|
331 iunlock(ip);
|
|
332 return ip;
|
|
333 }
|
|
334
|
|
335 if ((next = dirlookup(ip, name, 0)) == 0) {
|
|
336 iunlockput(ip);
|
|
337 return 0;
|
|
338 }
|
|
339
|
|
340 iunlockput(ip);
|
|
341 ip = next;
|
|
342 }
|
|
343
|
|
344 if (nameiparent) {
|
|
345 iput(ip);
|
|
346 return 0;
|
|
347 }
|
|
348
|
|
349 return ip;
|
|
350 }
|
|
351
|
|
352 __code nameifs_impl(struct fs_impl* fs, char* path, __code next(int namex_val, ...)) {
|
|
353 char name[DIRSIZ];
|
|
354 namex_val = namex(path, 0, name);
|
|
355 goto next(namex_val, ...);
|
|
356 }
|
|
357
|
|
358 __code nameiparentfs_impl(struct fs_impl* fs, char* path, char* name, __code next(int namex_val, ...)) {
|
|
359
|
|
360 namex_val = namex(path, 1, name);
|
|
361 goto next(namex_val, ...);
|
|
362
|
|
363 }
|