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