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