Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Written by Paul Popelka (paulp@uts.amdahl.com) | |
3 | * | |
4 | * You can do anything you want with this software, | |
5 | * just don't say you wrote it, | |
6 | * and don't reoove this notice. | |
7 | * | |
8 | * This software is provided "as is". | |
9 | * | |
10 | * The authop supplies this software to be publicly | |
11 | * redistributed on the understanding that the author | |
12 | * is not responsible for the correct functioning of | |
13 | * this software in any circumstances and is not liable | |
14 | * for any damages caused by this software. | |
15 | * | |
16 | * October 1992 | |
17 | * | |
78ed81a3 | 18 | * $Id$ |
15637ed4 RG |
19 | */ |
20 | ||
21 | #include "param.h" | |
22 | #include "systm.h" | |
23 | #include "mount.h" | |
24 | #include "proc.h" | |
25 | #include "buf.h" | |
26 | #include "vnode.h" | |
27 | #include "kernel.h" /* defines "time" */ | |
28 | ||
29 | #include "bpb.h" | |
30 | #include "pcfsmount.h" | |
31 | #include "direntry.h" | |
32 | #include "denode.h" | |
33 | #include "fat.h" | |
34 | ||
35 | #define DEHSZ 512 | |
36 | #if ((DEHSZ & (DEHSZ-1)) == 0) | |
37 | #define DEHASH(dev, deno) (((dev)+(deno)+((deno)>>16))&(DEHSZ-1)) | |
38 | #else | |
39 | #define DEHASH(dev, deno) (((dev)+(deno)+((deno)>>16))%DEHSZ) | |
40 | #endif /* ((DEHSZ & (DEHSZ-1)) == 0) */ | |
41 | ||
42 | union dehead { | |
43 | union dehead *deh_head[2]; | |
44 | struct denode *deh_chain[2]; | |
45 | } dehead[DEHSZ]; | |
46 | ||
47 | pcfs_init() | |
48 | { | |
49 | int i; | |
50 | union dehead *deh; | |
51 | ||
52 | if (VN_MAXPRIVATE < sizeof(struct denode)) | |
53 | panic("pcfs_init: vnode too small"); | |
54 | ||
55 | for (i = DEHSZ, deh = dehead; --i >= 0; deh++) { | |
56 | deh->deh_head[0] = deh; | |
57 | deh->deh_head[1] = deh; | |
58 | } | |
59 | } | |
60 | ||
61 | /* | |
62 | * If deget() succeeds it returns with the gotten denode | |
63 | * locked(). | |
64 | * pmp - address of pcfsmount structure of the filesystem | |
65 | * containing the denode of interest. The pm_dev field | |
66 | * and the address of the pcfsmount structure are used. | |
67 | * dirclust - which cluster bp contains, if dirclust is 0 | |
68 | * (root directory) diroffset is relative to the beginning | |
69 | * of the root directory, otherwise it is cluster relative. | |
70 | * diroffset - offset past begin of cluster of denode we | |
71 | * want | |
72 | * direntptr - address of the direntry structure of interest. | |
73 | * direntptr is NULL, the block is read if necessary. | |
74 | * depp - returns the address of the gotten denode. | |
75 | */ | |
76 | int | |
77 | deget (pmp, dirclust, diroffset, direntptr, depp) | |
78 | struct pcfsmount *pmp; /* so we know the maj/min number */ | |
79 | u_long dirclust; /* cluster this dir entry came from */ | |
80 | u_long diroffset; /* index of entry within the cluster */ | |
81 | struct direntry *direntptr; | |
82 | struct denode **depp; /* returns the addr of the gotten denode*/ | |
83 | { | |
84 | int error; | |
85 | dev_t dev = pmp->pm_dev; | |
86 | union dehead *deh; | |
87 | struct mount *mntp = pmp->pm_mountp; | |
88 | extern struct vnodeops pcfs_vnodeops; | |
89 | struct denode *ldep; | |
90 | struct vnode *nvp; | |
91 | struct buf *bp; | |
92 | #if defined(PCFSDEBUG) | |
93 | printf("deget(pmp %08x, dirclust %d, diroffset %x, direntptr %x, depp %08x)\n", | |
94 | pmp, dirclust, diroffset, direntptr, depp); | |
95 | #endif /* defined(PCFSDEBUG) */ | |
96 | ||
97 | /* If dir entry is given and refers to a directory, convert to | |
98 | * canonical form | |
99 | */ | |
100 | if (direntptr && (direntptr->deAttributes & ATTR_DIRECTORY)) { | |
101 | dirclust = direntptr->deStartCluster; | |
102 | if (dirclust == PCFSROOT) | |
103 | diroffset = PCFSROOT_OFS; | |
104 | else | |
105 | diroffset = 0; | |
106 | } | |
107 | ||
108 | /* | |
109 | * See if the denode is in the denode cache. Use the location of | |
110 | * the directory entry to compute the hash value. | |
111 | * For subdir use address of "." entry. | |
112 | * for root dir use cluster PCFSROOT, offset PCFSROOT_OFS | |
113 | * | |
114 | * NOTE: The check for de_refcnt > 0 below insures the denode | |
115 | * being examined does not represent an unlinked but | |
116 | * still open file. These files are not to be accessible | |
117 | * even when the directory entry that represented the | |
118 | * file happens to be reused while the deleted file is still | |
119 | * open. | |
120 | */ | |
121 | deh = &dehead[DEHASH(dev, dirclust + diroffset)]; | |
122 | loop: | |
123 | for (ldep = deh->deh_chain[0]; ldep != (struct denode *)deh; | |
124 | ldep = ldep->de_forw) { | |
125 | if (dev != ldep->de_dev || ldep->de_refcnt == 0) | |
126 | continue; | |
127 | if (dirclust != ldep->de_dirclust | |
128 | || diroffset != ldep->de_diroffset) | |
129 | continue; | |
130 | if (ldep->de_flag & DELOCKED) { | |
131 | /* should we brelse() the passed buf hdr to | |
132 | * avoid some potential deadlock? */ | |
133 | ldep->de_flag |= DEWANT; | |
134 | sleep((caddr_t)ldep, PINOD); | |
135 | goto loop; | |
136 | } | |
137 | if (vget(DETOV(ldep))) | |
138 | goto loop; | |
139 | *depp = ldep; | |
140 | return 0; | |
141 | } | |
142 | ||
143 | ||
144 | /* | |
145 | * Directory entry was not in cache, have to create | |
146 | * a vnode and copy it from the passed disk buffer. | |
147 | */ | |
148 | /* getnewvnode() does a VREF() on the vnode */ | |
149 | if (error = getnewvnode(VT_PCFS, mntp, &pcfs_vnodeops, &nvp)) { | |
150 | *depp = 0; | |
151 | return error; | |
152 | } | |
153 | ldep = VTODE(nvp); | |
154 | ldep->de_vnode = nvp; | |
155 | ldep->de_flag = 0; | |
156 | ldep->de_devvp = 0; | |
157 | ldep->de_lockf = 0; | |
158 | ldep->de_dev = dev; | |
159 | fc_purge(ldep, 0); /* init the fat cache for this denode */ | |
160 | ||
161 | /* | |
162 | * Insert the denode into the hash queue and lock the | |
163 | * denode so it can't be accessed until we've read it | |
164 | * in and have done what we need to it. | |
165 | */ | |
166 | insque(ldep, deh); | |
167 | DELOCK(ldep); | |
168 | ||
169 | /* | |
170 | * Copy the directory entry into the denode area of the | |
171 | * vnode. | |
172 | */ | |
173 | if (dirclust == PCFSROOT && diroffset == PCFSROOT_OFS) { | |
174 | /* Directory entry for the root directory. | |
175 | * There isn't one, so we manufacture one. | |
176 | * We should probably rummage through the root directory and | |
177 | * find a label entry (if it exists), and then use the time | |
178 | * and date from that entry as the time and date for the | |
179 | * root denode. | |
180 | */ | |
181 | ldep->de_Attributes = ATTR_DIRECTORY; | |
182 | ldep->de_StartCluster = PCFSROOT; | |
183 | ldep->de_FileSize = pmp->pm_rootdirsize * 512; /* Jim Jegers*/ | |
184 | /* fill in time and date so that dos2unixtime() doesn't | |
185 | * spit up when called from pcfs_getattr() with root denode */ | |
186 | ldep->de_Time = 0x0000; /* 00:00:00 */ | |
187 | ldep->de_Date = (0 << 9) | (1 << 5) | (1 << 0); | |
188 | /* Jan 1, 1980 */ | |
189 | /* leave the other fields as garbage */ | |
190 | } | |
191 | else { | |
192 | bp = NULL; | |
193 | if (!direntptr) { | |
194 | error = readep(pmp, dirclust, diroffset, &bp, | |
195 | &direntptr); | |
196 | if (error) | |
197 | return error; | |
198 | } | |
199 | ldep->de_de = *direntptr; | |
200 | if (bp) | |
201 | brelse (bp); | |
202 | } | |
203 | ||
204 | /* | |
205 | * Fill in a few fields of the vnode and finish filling | |
206 | * in the denode. Then return the address of the found | |
207 | * denode. | |
208 | */ | |
209 | ldep->de_pmp = pmp; | |
210 | ldep->de_devvp = pmp->pm_devvp; | |
211 | ldep->de_refcnt = 1; | |
212 | ldep->de_dirclust = dirclust; | |
213 | ldep->de_diroffset = diroffset; | |
214 | if (ldep->de_Attributes & ATTR_DIRECTORY) { | |
215 | /* | |
216 | * Since DOS directory entries that describe directories | |
217 | * have 0 in the filesize field, we take this opportunity | |
218 | * to find out the length of the directory and plug it | |
219 | * into the denode structure. | |
220 | */ | |
221 | u_long size; | |
222 | ||
223 | nvp->v_type = VDIR; | |
224 | if (ldep->de_StartCluster == PCFSROOT) | |
225 | nvp->v_flag |= VROOT; | |
226 | else { | |
227 | error = pcbmap(ldep, 0xffff, 0, &size); | |
228 | if (error == E2BIG) { | |
229 | ldep->de_FileSize = size << pmp->pm_cnshift; | |
230 | error = 0; | |
231 | } | |
232 | else | |
233 | printf("deget(): pcbmap returned %d\n", error); | |
234 | } | |
235 | } | |
236 | else | |
237 | nvp->v_type = VREG; | |
238 | VREF(ldep->de_devvp); | |
239 | *depp = ldep; | |
240 | return 0; | |
241 | } | |
242 | ||
243 | void | |
244 | deput(dep) | |
245 | struct denode *dep; | |
246 | { | |
247 | if ((dep->de_flag & DELOCKED) == 0) | |
248 | panic("deput: denode not locked"); | |
249 | DEUNLOCK(dep); | |
250 | vrele(DETOV(dep)); | |
251 | } | |
252 | ||
253 | int | |
254 | deupdat(dep, tp, waitfor) | |
255 | struct denode *dep; | |
256 | struct timeval *tp; | |
257 | int waitfor; | |
258 | { | |
259 | int error; | |
260 | daddr_t bn; | |
261 | int diro; | |
262 | struct buf *bp; | |
263 | struct direntry *dirp; | |
264 | struct pcfsmount *pmp = dep->de_pmp; | |
265 | struct vnode *vp = DETOV(dep); | |
266 | #if defined(PCFSDEBUG) | |
267 | printf("deupdat(): dep %08x\n", dep); | |
268 | #endif /* defined(PCFSDEBUG) */ | |
269 | ||
270 | /* | |
271 | * If the update bit is off, or this denode is from | |
272 | * a readonly filesystem, or this denode is for a | |
273 | * directory, or the denode represents an open but | |
274 | * unlinked file then don't do anything. DOS directory | |
275 | * entries that describe a directory do not ever | |
276 | * get updated. This is the way dos treats them. | |
277 | */ | |
278 | if ((dep->de_flag & DEUPD) == 0 || | |
279 | vp->v_mount->mnt_flag & MNT_RDONLY || | |
280 | dep->de_Attributes & ATTR_DIRECTORY || | |
281 | dep->de_refcnt <= 0) | |
282 | return 0; | |
283 | ||
284 | /* | |
285 | * Read in the cluster containing the directory entry | |
286 | * we want to update. | |
287 | */ | |
288 | if (error = readde(dep, &bp, &dirp)) | |
289 | return error; | |
290 | ||
291 | /* | |
292 | * Put the passed in time into the directory entry. | |
293 | */ | |
294 | unix2dostime(&time, (union dosdate *)&dep->de_Date, | |
295 | (union dostime *)&dep->de_Time); | |
296 | dep->de_flag &= ~DEUPD; | |
297 | ||
298 | /* | |
299 | * Copy the directory entry out of the denode into | |
300 | * the cluster it came from. | |
301 | */ | |
302 | *dirp = dep->de_de; /* structure copy */ | |
303 | ||
304 | /* | |
305 | * Write the cluster back to disk. If they asked | |
306 | * for us to wait for the write to complete, then | |
307 | * use bwrite() otherwise use bdwrite(). | |
308 | */ | |
309 | error = 0; /* note that error is 0 from above, but ... */ | |
310 | if (waitfor) | |
311 | error = bwrite(bp); | |
312 | else | |
313 | bdwrite(bp); | |
314 | return error; | |
315 | } | |
316 | ||
317 | /* | |
318 | * Truncate the file described by dep to the length | |
319 | * specified by length. | |
320 | */ | |
321 | int | |
322 | detrunc(dep, length, flags) | |
323 | struct denode *dep; | |
324 | u_long length; | |
325 | int flags; | |
326 | { | |
327 | int error; | |
328 | int allerror; | |
329 | u_long eofentry; | |
330 | u_long chaintofree; | |
331 | daddr_t bn; | |
332 | int boff; | |
333 | int isadir = dep->de_Attributes & ATTR_DIRECTORY; | |
334 | struct buf *bp; | |
335 | struct pcfsmount *pmp = dep->de_pmp; | |
336 | #if defined(PCFSDEBUG) | |
337 | printf("detrunc(): file %s, length %d, flags %d\n", dep->de_Name, length, flags); | |
338 | #endif /* defined(PCFSDEBUG) */ | |
339 | ||
340 | /* | |
341 | * Disallow attempts to truncate the root directory | |
342 | * since it is of fixed size. That's just the way | |
343 | * dos filesystems are. We use the VROOT bit in the | |
344 | * vnode because checking for the directory bit and | |
345 | * a startcluster of 0 in the denode is not adequate | |
346 | * to recognize the root directory at this point in | |
347 | * a file or directory's life. | |
348 | */ | |
349 | if (DETOV(dep)->v_flag & VROOT) { | |
350 | printf("detrunc(): can't truncate root directory, clust %d, offset %d\n", | |
351 | dep->de_dirclust, dep->de_diroffset); | |
352 | return EINVAL; | |
353 | } | |
354 | ||
355 | vnode_pager_setsize(DETOV(dep), length); | |
356 | ||
357 | if (dep->de_FileSize <= length) { | |
358 | dep->de_flag |= DEUPD; | |
359 | error = deupdat(dep, &time, 1); | |
360 | #if defined(PCFSDEBUG) | |
361 | printf("detrunc(): file is shorter return point, errno %d\n", error); | |
362 | #endif /* defined(PCFSDEBUG) */ | |
363 | return error; | |
364 | } | |
365 | ||
366 | /* | |
367 | * If the desired length is 0 then remember the starting | |
368 | * cluster of the file and set the StartCluster field in | |
369 | * the directory entry to 0. If the desired length is | |
370 | * not zero, then get the number of the last cluster in | |
371 | * the shortened file. Then get the number of the first | |
372 | * cluster in the part of the file that is to be freed. | |
373 | * Then set the next cluster pointer in the last cluster | |
374 | * of the file to CLUST_EOFE. | |
375 | */ | |
376 | if (length == 0) { | |
377 | chaintofree = dep->de_StartCluster; | |
378 | dep->de_StartCluster = 0; | |
379 | eofentry = ~0; | |
380 | } else { | |
381 | error = pcbmap(dep, (length-1) >> pmp->pm_cnshift, | |
382 | 0, &eofentry); | |
383 | if (error) { | |
384 | #if defined(PCFSDEBUG) | |
385 | printf("detrunc(): pcbmap fails %d\n", error); | |
386 | #endif /* defined(PCFSDEBUG) */ | |
387 | return error; | |
388 | } | |
389 | } | |
390 | ||
391 | fc_purge(dep, (length + pmp->pm_crbomask) >> pmp->pm_cnshift); | |
392 | ||
393 | /* | |
394 | * If the new length is not a multiple of the cluster size | |
395 | * then we must zero the tail end of the new last cluster in case | |
396 | * it becomes part of the file again because of a seek. | |
397 | */ | |
398 | if ((boff = length & pmp->pm_crbomask) != 0) { | |
399 | /* should read from file vnode or | |
400 | * filesystem vnode depending on if file or dir */ | |
401 | if (isadir) { | |
402 | bn = cntobn(pmp, eofentry); | |
403 | error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, | |
404 | NOCRED, &bp); | |
405 | } else { | |
406 | bn = (length-1) >> pmp->pm_cnshift; | |
407 | error = bread(DETOV(dep), bn, pmp->pm_bpcluster, | |
408 | NOCRED, &bp); | |
409 | } | |
410 | if (error) { | |
411 | #if defined(PCFSDEBUG) | |
412 | printf("detrunc(): bread fails %d\n", error); | |
413 | #endif /* defined(PCFSDEBUG) */ | |
414 | return error; | |
415 | } | |
416 | vnode_pager_uncache(DETOV(dep)); /* what's this for? */ | |
417 | /* is this the right | |
418 | * place for it? */ | |
419 | bzero(bp->b_un.b_addr + boff, pmp->pm_bpcluster - boff); | |
420 | if (flags & IO_SYNC) | |
421 | bwrite(bp); | |
422 | else | |
423 | bdwrite(bp); | |
424 | } | |
425 | ||
426 | /* | |
427 | * Write out the updated directory entry. Even | |
428 | * if the update fails we free the trailing clusters. | |
429 | */ | |
430 | dep->de_FileSize = length; | |
431 | dep->de_flag |= DEUPD; | |
432 | vinvalbuf(DETOV(dep), length > 0); | |
433 | allerror = deupdat(dep, &time, MNT_WAIT); | |
434 | #if defined(PCFSDEBUG) | |
435 | printf("detrunc(): allerror %d, eofentry %d\n", | |
436 | allerror, eofentry); | |
437 | #endif /* defined(PCFSDEBUG) */ | |
438 | ||
439 | /* | |
440 | * If we need to break the cluster chain for the file | |
441 | * then do it now. | |
442 | */ | |
443 | if (eofentry != ~0) { | |
444 | error = fatentry(FAT_GET_AND_SET, pmp, eofentry, | |
445 | &chaintofree, CLUST_EOFE); | |
446 | if (error) { | |
447 | #if defined(PCFSDEBUG) | |
448 | printf("detrunc(): fatentry errors %d\n", error); | |
449 | #endif /* defined(PCFSDEBUG) */ | |
450 | return error; | |
451 | } | |
452 | fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift, | |
453 | eofentry); | |
454 | } | |
455 | ||
456 | /* | |
457 | * Now free the clusters removed from the file because | |
458 | * of the truncation. | |
459 | */ | |
460 | if (chaintofree != 0 && !PCFSEOF(chaintofree)) | |
461 | freeclusterchain(pmp, chaintofree); | |
462 | ||
463 | return allerror; | |
464 | } | |
465 | ||
466 | /* | |
467 | * Move a denode to its correct hash queue after | |
468 | * the file it represents has been moved to a new | |
469 | * directory. | |
470 | */ | |
471 | reinsert(dep) | |
472 | struct denode *dep; | |
473 | { | |
474 | struct pcfsmount *pmp = dep->de_pmp; | |
475 | union dehead *deh; | |
476 | ||
477 | /* | |
478 | * Fix up the denode cache. If the denode is | |
479 | * for a directory, there is nothing to do since the | |
480 | * hash is based on the starting cluster of the directory | |
481 | * file and that hasn't changed. If for a file the hash | |
482 | * is based on the location | |
483 | * of the directory entry, so we must remove it from the | |
484 | * cache and re-enter it with the hash based on the new | |
485 | * location of the directory entry. | |
486 | */ | |
487 | if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { | |
488 | remque(dep); | |
489 | deh = &dehead[DEHASH(pmp->pm_dev, | |
490 | dep->de_dirclust + dep->de_diroffset)]; | |
491 | insque(dep, deh); | |
492 | } | |
493 | } | |
494 | ||
495 | int pcfs_prtactive; /* print reclaims of active vnodes */ | |
496 | ||
497 | int | |
498 | pcfs_reclaim(vp) | |
499 | struct vnode *vp; | |
500 | { | |
501 | struct denode *dep = VTODE(vp); | |
502 | int i; | |
503 | #if defined(PCFSDEBUG) | |
504 | printf("pcfs_reclaim(): dep %08x, file %s, refcnt %d\n", | |
505 | dep, dep->de_Name, dep->de_refcnt); | |
506 | #endif /* defined(PCFSDEBUG) */ | |
507 | ||
508 | if (pcfs_prtactive && vp->v_usecount != 0) | |
509 | vprint("pcfs_reclaim(): pushing active", vp); | |
510 | ||
511 | /* | |
512 | * Remove the denode from the denode hash chain we | |
513 | * are in. | |
514 | */ | |
515 | remque(dep); | |
516 | dep->de_forw = dep; | |
517 | dep->de_back = dep; | |
518 | ||
519 | cache_purge(vp); | |
520 | /* | |
521 | * Indicate that one less file on the filesystem is open. | |
522 | */ | |
523 | if (dep->de_devvp) { | |
524 | vrele(dep->de_devvp); | |
525 | dep->de_devvp = 0; | |
526 | } | |
527 | ||
528 | dep->de_flag = 0; | |
529 | return 0; | |
530 | } | |
531 | ||
532 | int | |
533 | pcfs_inactive(vp, p) | |
534 | struct vnode *vp; | |
535 | struct proc *p; | |
536 | { | |
537 | struct denode *dep = VTODE(vp); | |
538 | int error = 0; | |
539 | #if defined(PCFSDEBUG) | |
540 | printf("pcfs_inactive(): dep %08x, de_Name[0] %x\n", dep, dep->de_Name[0]); | |
541 | #endif /* defined(PCFSDEBUG) */ | |
542 | ||
543 | if (pcfs_prtactive && vp->v_usecount != 0) | |
544 | vprint("pcfs_inactive(): pushing active", vp); | |
545 | ||
546 | /* | |
547 | * Get rid of denodes related to stale file handles. | |
548 | * Hmmm, what does this really do? | |
549 | */ | |
550 | if (dep->de_Name[0] == SLOT_DELETED) { | |
551 | if ((vp->v_flag & VXLOCK) == 0) | |
552 | vgone(vp); | |
553 | return 0; | |
554 | } | |
555 | ||
556 | /* | |
557 | * If the file has been deleted and it is on a read/write | |
558 | * filesystem, then truncate the file, and mark the directory | |
559 | * slot as empty. (This may not be necessary for the dos | |
560 | * filesystem. | |
561 | */ | |
562 | #if defined(PCFSDEBUG) | |
563 | printf("pcfs_inactive(): dep %08x, refcnt %d, mntflag %x, MNT_RDONLY %x\n", | |
564 | dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY); | |
565 | #endif /* defined(PCFSDEBUG) */ | |
566 | DELOCK(dep); | |
567 | if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { | |
568 | error = detrunc(dep, (u_long)0, 0); | |
569 | dep->de_flag |= DEUPD; | |
570 | dep->de_Name[0] = SLOT_DELETED; | |
571 | } | |
572 | DEUPDAT(dep, &time, 0); | |
573 | DEUNLOCK(dep); | |
574 | dep->de_flag = 0; | |
575 | ||
576 | /* | |
577 | * If we are done with the denode, then reclaim | |
578 | * it so that it can be reused now. | |
579 | */ | |
580 | #if defined(PCFSDEBUG) | |
581 | printf("pcfs_inactive(): v_usecount %d, de_Name[0] %x\n", vp->v_usecount, | |
582 | dep->de_Name[0]); | |
583 | #endif /* defined(PCFSDEBUG) */ | |
584 | if (vp->v_usecount == 0 && dep->de_Name[0] == SLOT_DELETED) | |
585 | vgone(vp); | |
586 | return error; | |
587 | } | |
588 | ||
589 | int | |
590 | delock(dep) | |
591 | struct denode *dep; | |
592 | { | |
593 | while (dep->de_flag & DELOCKED) { | |
594 | dep->de_flag |= DEWANT; | |
595 | if (dep->de_spare0 == curproc->p_pid) | |
596 | panic("delock: locking against myself"); | |
597 | dep->de_spare1 = curproc->p_pid; | |
598 | (void) sleep((caddr_t)dep, PINOD); | |
599 | } | |
600 | dep->de_spare1 = 0; | |
601 | dep->de_spare0 = curproc->p_pid; | |
602 | dep->de_flag |= DELOCKED; | |
603 | ||
604 | return 0; | |
605 | } | |
606 | ||
607 | int | |
608 | deunlock(dep) | |
609 | struct denode *dep; | |
610 | { | |
611 | if ((dep->de_flag & DELOCKED) == 0) | |
612 | vprint("deunlock: found unlocked denode", DETOV(dep)); | |
613 | dep->de_spare0 = 0; | |
614 | dep->de_flag &= ~DELOCKED; | |
615 | if (dep->de_flag & DEWANT) { | |
616 | dep->de_flag &= ~DEWANT; | |
617 | wakeup((caddr_t)dep); | |
618 | } | |
619 | ||
620 | return 0; | |
621 | } |