]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_cnode.c
xnu-1228.0.2.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_cnode.c
CommitLineData
9bccf70c 1/*
2d21ac55 2 * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
9bccf70c 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
9bccf70c 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
9bccf70c
A
27 */
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/proc.h>
31#include <sys/vnode.h>
32#include <sys/mount.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
91447636 35#include <sys/time.h>
9bccf70c
A
36#include <sys/ubc.h>
37#include <sys/quota.h>
91447636
A
38#include <sys/kdebug.h>
39
40#include <kern/locks.h>
9bccf70c
A
41
42#include <miscfs/specfs/specdev.h>
43#include <miscfs/fifofs/fifo.h>
44
45#include <hfs/hfs.h>
46#include <hfs/hfs_catalog.h>
47#include <hfs/hfs_cnode.h>
48#include <hfs/hfs_quota.h>
49
50extern int prtactive;
51
91447636
A
52extern lck_attr_t * hfs_lock_attr;
53extern lck_grp_t * hfs_mutex_group;
54extern lck_grp_t * hfs_rwlock_group;
55
56static int hfs_filedone(struct vnode *vp, vfs_context_t context);
57
58static void hfs_reclaim_cnode(struct cnode *);
59
91447636
A
60static int hfs_isordered(struct cnode *, struct cnode *);
61
9bccf70c
A
62
63/*
64 * Last reference to an cnode. If necessary, write or delete it.
65 */
66__private_extern__
67int
91447636 68hfs_vnop_inactive(struct vnop_inactive_args *ap)
9bccf70c
A
69{
70 struct vnode *vp = ap->a_vp;
91447636 71 struct cnode *cp;
9bccf70c 72 struct hfsmount *hfsmp = VTOHFS(vp);
91447636 73 struct proc *p = vfs_context_proc(ap->a_context);
9bccf70c
A
74 int error = 0;
75 int recycle = 0;
76 int forkcount = 0;
77 int truncated = 0;
91447636
A
78 int started_tr = 0;
79 int took_trunc_lock = 0;
55e303ae
A
80 cat_cookie_t cookie;
81 int cat_reserve = 0;
91447636
A
82 int lockflags;
83 enum vtype v_type;
9bccf70c 84
91447636
A
85 v_type = vnode_vtype(vp);
86 cp = VTOC(vp);
9bccf70c 87
3a60a9f5
A
88 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || vnode_issystem(vp) ||
89 (hfsmp->hfs_freezing_proc == p)) {
91447636
A
90 return (0);
91 }
3a60a9f5 92
9bccf70c
A
93 /*
94 * Ignore nodes related to stale file handles.
95 */
91447636
A
96 if (cp->c_mode == 0) {
97 vnode_recycle(vp);
98 return (0);
99 }
100
2d21ac55 101 if ((v_type == VREG || v_type == VLNK)) {
91447636
A
102 hfs_lock_truncate(cp, TRUE);
103 took_trunc_lock = 1;
104 }
105
2d21ac55
A
106 (void) hfs_lock(cp, HFS_FORCE_LOCK);
107
91447636 108 /*
2d21ac55
A
109 * We should lock cnode before checking the flags in the
110 * condition below and should unlock the cnode before calling
111 * ubc_setsize() as cluster code can call other HFS vnops which
112 * will try to acquire the same cnode lock and cause deadlock.
91447636
A
113 */
114 if ((v_type == VREG || v_type == VLNK) &&
115 (cp->c_flag & C_DELETED) &&
116 (VTOF(vp)->ff_blocks != 0)) {
2d21ac55 117 hfs_unlock(cp);
91447636 118 ubc_setsize(vp, 0);
2d21ac55 119 (void) hfs_lock(cp, HFS_FORCE_LOCK);
91447636
A
120 }
121
91447636
A
122 if (v_type == VREG && !ISSET(cp->c_flag, C_DELETED) && VTOF(vp)->ff_blocks) {
123 hfs_filedone(vp, ap->a_context);
124 }
125 /*
2d21ac55 126 * Remove any directory hints or cached origins
91447636 127 */
2d21ac55 128 if (v_type == VDIR) {
91447636 129 hfs_reldirhints(cp, 0);
2d21ac55
A
130 if (cp->c_flag & C_HARDLINK)
131 hfs_relorigins(cp);
132 }
9bccf70c
A
133
134 if (cp->c_datafork)
135 ++forkcount;
136 if (cp->c_rsrcfork)
137 ++forkcount;
138
139 /* If needed, get rid of any fork's data for a deleted file */
91447636 140 if ((v_type == VREG || v_type == VLNK) && (cp->c_flag & C_DELETED)) {
55e303ae 141 if (VTOF(vp)->ff_blocks != 0) {
91447636
A
142 /*
143 * Since we're already inside a transaction,
144 * tell hfs_truncate to skip the ubc_setsize.
145 */
146 error = hfs_truncate(vp, (off_t)0, IO_NDELAY, 1, ap->a_context);
55e303ae
A
147 if (error)
148 goto out;
149 truncated = 1;
150 }
9bccf70c 151 recycle = 1;
2d21ac55
A
152
153 /*
154 * Check if there's any resource fork blocks that need to
155 * be reclaimed. This covers the case where there is a
156 * resource fork but its not in core.
157 */
158 if ((cp->c_blocks > 0) && (forkcount == 1) && (vp != cp->c_rsrc_vp)) {
159 struct vnode *rvp = NULLVP;
160
161 error = hfs_vgetrsrc(hfsmp, vp, &rvp, FALSE);
162 if (error)
163 goto out;
164 /*
165 * Defer the vnode_put and ubc_setsize on rvp until hfs_unlock().
166 */
167 cp->c_flag |= C_NEED_RVNODE_PUT | C_NEED_RSRC_SETSIZE;
168 error = hfs_truncate(rvp, (off_t)0, IO_NDELAY, 1, ap->a_context);
169 if (error)
170 goto out;
171 vnode_recycle(rvp); /* all done with this vnode */
172 }
173 }
174
175 // If needed, get rid of any xattrs that this file may have.
176 // Note that this must happen outside of any other transactions
177 // because it starts/ends its own transactions and grabs its
178 // own locks. This is to prevent a file with a lot of attributes
179 // from creating a transaction that is too large (which panics).
180 //
181 if ((cp->c_attr.ca_recflags & kHFSHasAttributesMask) != 0 && (cp->c_flag & C_DELETED)) {
182 hfs_removeallattr(hfsmp, cp->c_fileid);
9bccf70c
A
183 }
184
185 /*
186 * Check for a postponed deletion.
187 * (only delete cnode when the last fork goes inactive)
188 */
189 if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) {
190 /*
55e303ae 191 * Mark cnode in transit so that no one can get this
9bccf70c
A
192 * cnode from cnode hash.
193 */
2d21ac55
A
194 // hfs_chash_mark_in_transit(cp);
195 // XXXdbg - remove the cnode from the hash table since it's deleted
196 // otherwise someone could go to sleep on the cnode and not
197 // be woken up until this vnode gets recycled which could be
198 // a very long time...
199 hfs_chashremove(cp);
91447636 200
91447636 201 cp->c_flag |= C_NOEXISTS; // XXXdbg
9bccf70c 202 cp->c_rdev = 0;
55e303ae 203
91447636
A
204 if (started_tr == 0) {
205 if (hfs_start_transaction(hfsmp) != 0) {
206 error = EINVAL;
207 goto out;
b4c24cb9
A
208 }
209 started_tr = 1;
210 }
91447636 211
55e303ae
A
212 /*
213 * Reserve some space in the Catalog file.
214 */
215 if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) {
216 goto out;
217 }
218 cat_reserve = 1;
219
91447636 220 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
9bccf70c
A
221
222 if (cp->c_blocks > 0)
223 printf("hfs_inactive: attempting to delete a non-empty file!");
224
91447636
A
225
226 //
227 // release the name pointer in the descriptor so that
228 // cat_delete() will use the file-id to do the deletion.
229 // in the case of hard links this is imperative (in the
230 // case of regular files the fileid and cnid are the
231 // same so it doesn't matter).
232 //
233 cat_releasedesc(&cp->c_desc);
234
9bccf70c
A
235 /*
236 * The descriptor name may be zero,
237 * in which case the fileid is used.
238 */
239 error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr);
240
241 if (error && truncated && (error != ENXIO))
242 printf("hfs_inactive: couldn't delete a truncated file!");
243
244 /* Update HFS Private Data dir */
245 if (error == 0) {
2d21ac55
A
246 hfsmp->hfs_private_attr[FILE_HARDLINKS].ca_entries--;
247 if (vnode_isdir(vp)) {
248 DEC_FOLDERCOUNT(hfsmp, hfsmp->hfs_private_attr[FILE_HARDLINKS]);
249 }
250 (void)cat_update(hfsmp, &hfsmp->hfs_private_desc[FILE_HARDLINKS],
251 &hfsmp->hfs_private_attr[FILE_HARDLINKS], NULL, NULL);
91447636
A
252 }
253
254 hfs_systemfile_unlock(hfsmp, lockflags);
255
256 if (error)
257 goto out;
9bccf70c
A
258
259#if QUOTA
2d21ac55
A
260 if (hfsmp->hfs_flags & HFS_QUOTAS)
261 (void)hfs_chkiq(cp, -1, NOCRED, 0);
9bccf70c
A
262#endif /* QUOTA */
263
264 cp->c_mode = 0;
2d21ac55 265 cp->c_flag &= ~C_DELETED;
91447636
A
266 cp->c_touch_chgtime = TRUE;
267 cp->c_touch_modtime = TRUE;
9bccf70c
A
268
269 if (error == 0)
2d21ac55 270 hfs_volupdate(hfsmp, (v_type == VDIR) ? VOL_RMDIR : VOL_RMFILE, 0);
9bccf70c
A
271 }
272
91447636
A
273 if ((cp->c_flag & C_MODIFIED) ||
274 cp->c_touch_acctime || cp->c_touch_chgtime || cp->c_touch_modtime) {
275 hfs_update(vp, 0);
b4c24cb9 276 }
9bccf70c 277out:
55e303ae
A
278 if (cat_reserve)
279 cat_postflight(hfsmp, &cookie, p);
280
b4c24cb9
A
281 // XXXdbg - have to do this because a goto could have come here
282 if (started_tr) {
91447636 283 hfs_end_transaction(hfsmp);
b4c24cb9
A
284 started_tr = 0;
285 }
b4c24cb9 286
91447636
A
287 hfs_unlock(cp);
288
289 if (took_trunc_lock)
2d21ac55 290 hfs_unlock_truncate(cp, TRUE);
91447636 291
9bccf70c
A
292 /*
293 * If we are done with the vnode, reclaim it
294 * so that it can be reused immediately.
295 */
296 if (cp->c_mode == 0 || recycle)
91447636 297 vnode_recycle(vp);
9bccf70c
A
298
299 return (error);
300}
301
91447636
A
302/*
303 * File clean-up (zero fill and shrink peof).
304 */
305static int
306hfs_filedone(struct vnode *vp, vfs_context_t context)
307{
308 struct cnode *cp;
309 struct filefork *fp;
310 struct hfsmount *hfsmp;
311 off_t leof;
312 u_long blks, blocksize;
313
314 cp = VTOC(vp);
315 fp = VTOF(vp);
316 hfsmp = VTOHFS(vp);
317 leof = fp->ff_size;
318
319 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || (fp->ff_blocks == 0))
320 return (0);
321
322 hfs_unlock(cp);
323 (void) cluster_push(vp, IO_CLOSE);
324 hfs_lock(cp, HFS_FORCE_LOCK);
325
326 /*
327 * Explicitly zero out the areas of file
328 * that are currently marked invalid.
329 */
330 while (!CIRCLEQ_EMPTY(&fp->ff_invalidranges)) {
331 struct rl_entry *invalid_range = CIRCLEQ_FIRST(&fp->ff_invalidranges);
332 off_t start = invalid_range->rl_start;
333 off_t end = invalid_range->rl_end;
334
335 /* The range about to be written must be validated
336 * first, so that VNOP_BLOCKMAP() will return the
337 * appropriate mapping for the cluster code:
338 */
339 rl_remove(start, end, &fp->ff_invalidranges);
340
341 hfs_unlock(cp);
342 (void) cluster_write(vp, (struct uio *) 0,
343 leof, end + 1, start, (off_t)0,
344 IO_HEADZEROFILL | IO_NOZERODIRTY | IO_NOCACHE);
345 hfs_lock(cp, HFS_FORCE_LOCK);
346 cp->c_flag |= C_MODIFIED;
347 }
348 cp->c_flag &= ~C_ZFWANTSYNC;
349 cp->c_zftimeout = 0;
350 blocksize = VTOVCB(vp)->blockSize;
351 blks = leof / blocksize;
352 if (((off_t)blks * (off_t)blocksize) != leof)
353 blks++;
354 /*
355 * Shrink the peof to the smallest size neccessary to contain the leof.
356 */
357 if (blks < fp->ff_blocks)
358 (void) hfs_truncate(vp, leof, IO_NDELAY, 0, context);
359 hfs_unlock(cp);
360 (void) cluster_push(vp, IO_CLOSE);
361 hfs_lock(cp, HFS_FORCE_LOCK);
362
363 /*
364 * If the hfs_truncate didn't happen to flush the vnode's
365 * information out to disk, force it to be updated now that
366 * all invalid ranges have been zero-filled and validated:
367 */
368 if (cp->c_flag & C_MODIFIED) {
369 hfs_update(vp, 0);
370 }
371 return (0);
372}
373
9bccf70c
A
374
375/*
376 * Reclaim a cnode so that it can be used for other purposes.
377 */
378__private_extern__
379int
91447636 380hfs_vnop_reclaim(struct vnop_reclaim_args *ap)
9bccf70c
A
381{
382 struct vnode *vp = ap->a_vp;
91447636 383 struct cnode *cp;
9bccf70c
A
384 struct filefork *fp = NULL;
385 struct filefork *altfp = NULL;
91447636 386 int reclaim_cnode = 0;
9bccf70c 387
91447636
A
388 (void) hfs_lock(VTOC(vp), HFS_FORCE_LOCK);
389 cp = VTOC(vp);
9bccf70c 390
55e303ae
A
391 /*
392 * Keep track of an inactive hot file.
393 */
2d21ac55
A
394 if (!vnode_isdir(vp) &&
395 !vnode_issystem(vp) &&
396 !(cp->c_flag & (C_DELETED | C_NOEXISTS)) ) {
91447636 397 (void) hfs_addhotfile(vp);
2d21ac55 398 }
91447636 399 vnode_removefsref(vp);
9bccf70c
A
400
401 /*
402 * Find file fork for this vnode (if any)
403 * Also check if another fork is active
404 */
91447636
A
405 if (cp->c_vp == vp) {
406 fp = cp->c_datafork;
407 altfp = cp->c_rsrcfork;
408
9bccf70c
A
409 cp->c_datafork = NULL;
410 cp->c_vp = NULL;
91447636
A
411 } else if (cp->c_rsrc_vp == vp) {
412 fp = cp->c_rsrcfork;
413 altfp = cp->c_datafork;
414
9bccf70c
A
415 cp->c_rsrcfork = NULL;
416 cp->c_rsrc_vp = NULL;
9bccf70c 417 } else {
91447636 418 panic("hfs_vnop_reclaim: vp points to wrong cnode\n");
9bccf70c 419 }
9bccf70c
A
420 /*
421 * On the last fork, remove the cnode from its hash chain.
422 */
91447636
A
423 if (altfp == NULL) {
424 /* If we can't remove it then the cnode must persist! */
425 if (hfs_chashremove(cp) == 0)
426 reclaim_cnode = 1;
427 /*
428 * Remove any directory hints
429 */
430 if (vnode_isdir(vp)) {
431 hfs_reldirhints(cp, 0);
432 }
433 }
434 /* Release the file fork and related data */
9bccf70c 435 if (fp) {
9bccf70c 436 /* Dump cached symlink data */
91447636 437 if (vnode_islnk(vp) && (fp->ff_symlinkptr != NULL)) {
9bccf70c 438 FREE(fp->ff_symlinkptr, M_TEMP);
91447636 439 }
9bccf70c 440 FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK);
9bccf70c
A
441 }
442
9bccf70c
A
443 /*
444 * If there was only one active fork then we can release the cnode.
445 */
91447636
A
446 if (reclaim_cnode) {
447 hfs_chashwakeup(cp, H_ALLOC | H_TRANSIT);
448 hfs_reclaim_cnode(cp);
449 } else /* cnode in use */ {
450 hfs_unlock(cp);
9bccf70c
A
451 }
452
91447636 453 vnode_clearfsnode(vp);
9bccf70c
A
454 return (0);
455}
456
457
91447636
A
458extern int (**hfs_vnodeop_p) (void *);
459extern int (**hfs_specop_p) (void *);
2d21ac55 460#if FIFO
91447636 461extern int (**hfs_fifoop_p) (void *);
2d21ac55 462#endif
9bccf70c
A
463
464/*
465 * hfs_getnewvnode - get new default vnode
466 *
91447636 467 * The vnode is returned with an iocount and the cnode locked
9bccf70c 468 */
9bccf70c
A
469__private_extern__
470int
91447636
A
471hfs_getnewvnode(
472 struct hfsmount *hfsmp,
473 struct vnode *dvp,
474 struct componentname *cnp,
475 struct cat_desc *descp,
2d21ac55 476 int flags,
91447636
A
477 struct cat_attr *attrp,
478 struct cat_fork *forkp,
9bccf70c
A
479 struct vnode **vpp)
480{
481 struct mount *mp = HFSTOVFS(hfsmp);
482 struct vnode *vp = NULL;
91447636
A
483 struct vnode **cvpp;
484 struct vnode *tvp = NULLVP;
485 struct cnode *cp = NULL;
9bccf70c 486 struct filefork *fp = NULL;
9bccf70c 487 int retval;
91447636 488 int issystemfile;
2d21ac55 489 int wantrsrc;
91447636
A
490 struct vnode_fsparam vfsp;
491 enum vtype vtype;
2d21ac55
A
492#if QUOTA
493 int i;
494#endif /* QUOTA */
91447636
A
495
496 if (attrp->ca_fileid == 0) {
9bccf70c 497 *vpp = NULL;
91447636 498 return (ENOENT);
9bccf70c
A
499 }
500
501#if !FIFO
502 if (IFTOVT(attrp->ca_mode) == VFIFO) {
503 *vpp = NULL;
91447636 504 return (ENOTSUP);
9bccf70c 505 }
2d21ac55 506#endif /* !FIFO */
91447636
A
507 vtype = IFTOVT(attrp->ca_mode);
508 issystemfile = (descp->cd_flags & CD_ISMETA) && (vtype == VREG);
2d21ac55
A
509 wantrsrc = flags & GNV_WANTRSRC;
510
511#ifdef HFS_CHECK_LOCK_ORDER
512 /*
513 * The only case were its permissible to hold the parent cnode
514 * lock is during a create operation (hfs_makenode) or when
515 * we don't need the cnode lock (GNV_SKIPLOCK).
516 */
517 if ((dvp != NULL) &&
518 (flags & (GNV_CREATE | GNV_SKIPLOCK)) == 0 &&
519 VTOC(dvp)->c_lockowner == current_thread()) {
520 panic("hfs_getnewvnode: unexpected hold of parent cnode %p", VTOC(dvp));
521 }
522#endif /* HFS_CHECK_LOCK_ORDER */
91447636
A
523
524 /*
525 * Get a cnode (new or existing)
91447636 526 */
2d21ac55
A
527 cp = hfs_chash_getcnode(hfsmp->hfs_raw_dev, attrp->ca_fileid, vpp, wantrsrc, (flags & GNV_SKIPLOCK));
528
529 /*
530 * If the id is no longer valid for lookups we'll get back a NULL cp.
531 */
532 if (cp == NULL) {
533 return (ENOENT);
534 }
91447636
A
535
536 /* Hardlinks may need an updated catalog descriptor */
537 if ((cp->c_flag & C_HARDLINK) && descp->cd_nameptr && descp->cd_namelen > 0) {
538 replace_desc(cp, descp);
9bccf70c 539 }
91447636
A
540 /* Check if we found a matching vnode */
541 if (*vpp != NULL)
542 return (0);
9bccf70c 543
91447636
A
544 /*
545 * If this is a new cnode then initialize it.
546 */
547 if (ISSET(cp->c_hflag, H_ALLOC)) {
548 lck_rw_init(&cp->c_truncatelock, hfs_rwlock_group, hfs_lock_attr);
549
550 /* Make sure its still valid (ie exists on disk). */
2d21ac55
A
551 if (!(flags & GNV_CREATE) &&
552 !hfs_valid_cnode(hfsmp, dvp, (wantrsrc ? NULL : cnp), cp->c_fileid)) {
91447636
A
553 hfs_chash_abort(cp);
554 hfs_reclaim_cnode(cp);
555 *vpp = NULL;
556 return (ENOENT);
9bccf70c 557 }
9bccf70c
A
558 bcopy(attrp, &cp->c_attr, sizeof(struct cat_attr));
559 bcopy(descp, &cp->c_desc, sizeof(struct cat_desc));
9bccf70c 560
9bccf70c
A
561 /* The name was inherited so clear descriptor state... */
562 descp->cd_namelen = 0;
563 descp->cd_nameptr = NULL;
564 descp->cd_flags &= ~CD_HASBUF;
565
566 /* Tag hardlinks */
2d21ac55
A
567 if ((vtype == VREG || vtype == VDIR) &&
568 ((descp->cd_cnid != attrp->ca_fileid) ||
569 (attrp->ca_recflags & kHFSHasLinkChainMask))) {
9bccf70c
A
570 cp->c_flag |= C_HARDLINK;
571 }
2d21ac55
A
572 /*
573 * Fix-up dir link counts.
574 *
575 * Earlier versions of Leopard used ca_linkcount for posix
576 * nlink support (effectively the sub-directory count + 2).
577 * That is now accomplished using the ca_dircount field with
578 * the corresponding kHFSHasFolderCountMask flag.
579 *
580 * For directories the ca_linkcount is the true link count,
581 * tracking the number of actual hardlinks to a directory.
582 *
583 * We only do this if the mount has HFS_FOLDERCOUNT set;
584 * at the moment, we only set that for HFSX volumes.
585 */
586 if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) &&
587 (vtype == VDIR) &&
588 !(attrp->ca_recflags & kHFSHasFolderCountMask) &&
589 (cp->c_attr.ca_linkcount > 1)) {
590 if (cp->c_attr.ca_entries == 0)
591 cp->c_attr.ca_dircount = 0;
592 else
593 cp->c_attr.ca_dircount = cp->c_attr.ca_linkcount - 2;
9bccf70c 594
2d21ac55
A
595 cp->c_attr.ca_linkcount = 1;
596 cp->c_attr.ca_recflags |= kHFSHasFolderCountMask;
597 if ( !(hfsmp->hfs_flags & HFS_READ_ONLY) )
598 cp->c_flag |= C_MODIFIED;
9bccf70c
A
599 }
600#if QUOTA
2d21ac55
A
601 if (hfsmp->hfs_flags & HFS_QUOTAS) {
602 for (i = 0; i < MAXQUOTAS; i++)
603 cp->c_dquot[i] = NODQUOT;
604 }
9bccf70c
A
605#endif /* QUOTA */
606 }
607
2d21ac55 608 if (vtype == VDIR) {
91447636
A
609 if (cp->c_vp != NULL)
610 panic("hfs_getnewvnode: orphaned vnode (data)");
611 cvpp = &cp->c_vp;
612 } else {
9bccf70c
A
613 if (forkp && attrp->ca_blocks < forkp->cf_blocks)
614 panic("hfs_getnewvnode: bad ca_blocks (too small)");
615 /*
616 * Allocate and initialize a file fork...
617 */
618 MALLOC_ZONE(fp, struct filefork *, sizeof(struct filefork),
619 M_HFSFORK, M_WAITOK);
9bccf70c
A
620 fp->ff_cp = cp;
621 if (forkp)
55e303ae 622 bcopy(forkp, &fp->ff_data, sizeof(struct cat_fork));
91447636
A
623 else
624 bzero(&fp->ff_data, sizeof(struct cat_fork));
9bccf70c 625 rl_init(&fp->ff_invalidranges);
91447636
A
626 fp->ff_sysfileinfo = 0;
627
9bccf70c
A
628 if (wantrsrc) {
629 if (cp->c_rsrcfork != NULL)
91447636
A
630 panic("hfs_getnewvnode: orphaned rsrc fork");
631 if (cp->c_rsrc_vp != NULL)
632 panic("hfs_getnewvnode: orphaned vnode (rsrc)");
9bccf70c 633 cp->c_rsrcfork = fp;
91447636
A
634 cvpp = &cp->c_rsrc_vp;
635 if ( (tvp = cp->c_vp) != NULLVP )
636 cp->c_flag |= C_NEED_DVNODE_PUT;
9bccf70c
A
637 } else {
638 if (cp->c_datafork != NULL)
91447636
A
639 panic("hfs_getnewvnode: orphaned data fork");
640 if (cp->c_vp != NULL)
641 panic("hfs_getnewvnode: orphaned vnode (data)");
9bccf70c 642 cp->c_datafork = fp;
91447636
A
643 cvpp = &cp->c_vp;
644 if ( (tvp = cp->c_rsrc_vp) != NULLVP)
645 cp->c_flag |= C_NEED_RVNODE_PUT;
9bccf70c
A
646 }
647 }
91447636
A
648 if (tvp != NULLVP) {
649 /*
650 * grab an iocount on the vnode we weren't
651 * interested in (i.e. we want the resource fork
652 * but the cnode already has the data fork)
653 * to prevent it from being
654 * recycled by us when we call vnode_create
655 * which will result in a deadlock when we
656 * try to take the cnode lock in hfs_vnop_fsync or
657 * hfs_vnop_reclaim... vnode_get can be called here
658 * because we already hold the cnode lock which will
659 * prevent the vnode from changing identity until
660 * we drop it.. vnode_get will not block waiting for
661 * a change of state... however, it will return an
662 * error if the current iocount == 0 and we've already
663 * started to terminate the vnode... we don't need/want to
664 * grab an iocount in the case since we can't cause
665 * the fileystem to be re-entered on this thread for this vp
666 *
667 * the matching vnode_put will happen in hfs_unlock
668 * after we've dropped the cnode lock
669 */
670 if ( vnode_get(tvp) != 0)
671 cp->c_flag &= ~(C_NEED_RVNODE_PUT | C_NEED_DVNODE_PUT);
672 }
673 vfsp.vnfs_mp = mp;
674 vfsp.vnfs_vtype = vtype;
675 vfsp.vnfs_str = "hfs";
2d21ac55
A
676 if ((cp->c_flag & C_HARDLINK) && (vtype == VDIR)) {
677 vfsp.vnfs_dvp = NULL; /* no parent for me! */
678 vfsp.vnfs_cnp = NULL; /* no name for me! */
679 } else {
680 vfsp.vnfs_dvp = dvp;
681 vfsp.vnfs_cnp = cnp;
682 }
91447636 683 vfsp.vnfs_fsnode = cp;
2d21ac55 684#if FIFO
91447636
A
685 if (vtype == VFIFO )
686 vfsp.vnfs_vops = hfs_fifoop_p;
2d21ac55
A
687 else
688#endif
689 if (vtype == VBLK || vtype == VCHR)
91447636
A
690 vfsp.vnfs_vops = hfs_specop_p;
691 else
692 vfsp.vnfs_vops = hfs_vnodeop_p;
693
694 if (vtype == VBLK || vtype == VCHR)
695 vfsp.vnfs_rdev = attrp->ca_rdev;
696 else
697 vfsp.vnfs_rdev = 0;
9bccf70c 698
91447636
A
699 if (forkp)
700 vfsp.vnfs_filesize = forkp->cf_size;
701 else
702 vfsp.vnfs_filesize = 0;
703
2d21ac55
A
704 vfsp.vnfs_flags = VNFS_ADDFSREF;
705 if (dvp == NULLVP || cnp == NULL || !(cnp->cn_flags & MAKEENTRY))
706 vfsp.vnfs_flags |= VNFS_NOCACHE;
9bccf70c
A
707
708 /* Tag system files */
91447636
A
709 vfsp.vnfs_marksystem = issystemfile;
710
9bccf70c 711 /* Tag root directory */
91447636
A
712 if (descp->cd_cnid == kHFSRootFolderID)
713 vfsp.vnfs_markroot = 1;
714 else
715 vfsp.vnfs_markroot = 0;
716
717 if ((retval = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, cvpp))) {
718 if (fp) {
719 if (fp == cp->c_datafork)
720 cp->c_datafork = NULL;
721 else
722 cp->c_rsrcfork = NULL;
723
724 FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK);
725 }
726 /*
727 * If this is a newly created cnode or a vnode reclaim
728 * occurred during the attachment, then cleanup the cnode.
729 */
730 if ((cp->c_vp == NULL) && (cp->c_rsrc_vp == NULL)) {
731 hfs_chash_abort(cp);
732 hfs_reclaim_cnode(cp);
733 } else {
734 hfs_chashwakeup(cp, H_ALLOC | H_ATTACH);
735 hfs_unlock(cp);
736 }
737 *vpp = NULL;
738 return (retval);
739 }
740 vp = *cvpp;
91447636 741 vnode_settag(vp, VT_HFS);
2d21ac55
A
742 if (cp->c_flag & C_HARDLINK) {
743 vnode_setmultipath(vp);
744 }
91447636
A
745 hfs_chashwakeup(cp, H_ALLOC | H_ATTACH);
746
747 /*
748 * Stop tracking an active hot file.
749 */
2d21ac55 750 if (!(flags & GNV_CREATE) && (vtype != VDIR) && !issystemfile) {
91447636 751 (void) hfs_removehotfile(vp);
2d21ac55 752 }
91447636
A
753
754 *vpp = vp;
755 return (0);
756}
757
758
759static void
760hfs_reclaim_cnode(struct cnode *cp)
761{
762#if QUOTA
763 int i;
764
765 for (i = 0; i < MAXQUOTAS; i++) {
766 if (cp->c_dquot[i] != NODQUOT) {
767 dqreclaim(cp->c_dquot[i]);
768 cp->c_dquot[i] = NODQUOT;
769 }
770 }
771#endif /* QUOTA */
772
91447636
A
773 /*
774 * If the descriptor has a name then release it
775 */
2d21ac55
A
776 if ((cp->c_desc.cd_flags & CD_HASBUF) && (cp->c_desc.cd_nameptr != 0)) {
777 const char *nameptr;
91447636 778
2d21ac55 779 nameptr = (const char *) cp->c_desc.cd_nameptr;
91447636
A
780 cp->c_desc.cd_nameptr = 0;
781 cp->c_desc.cd_flags &= ~CD_HASBUF;
782 cp->c_desc.cd_namelen = 0;
783 vfs_removename(nameptr);
784 }
785
786 lck_rw_destroy(&cp->c_rwlock, hfs_rwlock_group);
787 lck_rw_destroy(&cp->c_truncatelock, hfs_rwlock_group);
788 bzero(cp, sizeof(struct cnode));
789 FREE_ZONE(cp, sizeof(struct cnode), M_HFSNODE);
790}
791
792
2d21ac55
A
793__private_extern__
794int
91447636
A
795hfs_valid_cnode(struct hfsmount *hfsmp, struct vnode *dvp, struct componentname *cnp, cnid_t cnid)
796{
797 struct cat_attr attr;
798 struct cat_desc cndesc;
799 int stillvalid = 0;
800 int lockflags;
9bccf70c 801
91447636
A
802 /* System files are always valid */
803 if (cnid < kHFSFirstUserCatalogNodeID)
804 return (1);
805
806 /* XXX optimization: check write count in dvp */
807
808 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
809
810 if (dvp && cnp) {
811 bzero(&cndesc, sizeof(cndesc));
2d21ac55 812 cndesc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr;
91447636 813 cndesc.cd_namelen = cnp->cn_namelen;
2d21ac55 814 cndesc.cd_parentcnid = VTOC(dvp)->c_fileid;
91447636
A
815 cndesc.cd_hint = VTOC(dvp)->c_childhint;
816
817 if ((cat_lookup(hfsmp, &cndesc, 0, NULL, &attr, NULL, NULL) == 0) &&
818 (cnid == attr.ca_fileid)) {
819 stillvalid = 1;
820 }
9bccf70c 821 } else {
2d21ac55 822 if (cat_idlookup(hfsmp, cnid, 0, NULL, NULL, NULL) == 0) {
91447636
A
823 stillvalid = 1;
824 }
825 }
826 hfs_systemfile_unlock(hfsmp, lockflags);
827
828 return (stillvalid);
829}
830
831/*
832 * Touch cnode times based on c_touch_xxx flags
833 *
834 * cnode must be locked exclusive
835 *
836 * This will also update the volume modify time
837 */
838__private_extern__
839void
840hfs_touchtimes(struct hfsmount *hfsmp, struct cnode* cp)
841{
2d21ac55
A
842 /* don't modify times if volume is read-only */
843 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
844 cp->c_touch_acctime = FALSE;
845 cp->c_touch_chgtime = FALSE;
846 cp->c_touch_modtime = FALSE;
847 }
848 else if (hfsmp->hfs_flags & HFS_STANDARD) {
91447636 849 /* HFS Standard doesn't support access times */
91447636 850 cp->c_touch_acctime = FALSE;
9bccf70c
A
851 }
852
2d21ac55
A
853 /*
854 * Skip access time updates if:
855 * . MNT_NOATIME is set
856 * . a file system freeze is in progress
857 * . a file system resize is in progress
858 */
859 if (cp->c_touch_acctime) {
860 if ((vfs_flags(hfsmp->hfs_mp) & MNT_NOATIME) ||
861 (hfsmp->hfs_freezing_proc != NULL) ||
862 (hfsmp->hfs_flags & HFS_RESIZE_IN_PROGRESS))
863 cp->c_touch_acctime = FALSE;
864 }
91447636
A
865 if (cp->c_touch_acctime || cp->c_touch_chgtime || cp->c_touch_modtime) {
866 struct timeval tv;
867 int touchvol = 0;
9bccf70c 868
91447636
A
869 microtime(&tv);
870
871 if (cp->c_touch_acctime) {
872 cp->c_atime = tv.tv_sec;
9bccf70c 873 /*
91447636
A
874 * When the access time is the only thing changing
875 * then make sure its sufficiently newer before
876 * committing it to disk.
9bccf70c 877 */
91447636
A
878 if ((((u_int32_t)cp->c_atime - (u_int32_t)(cp)->c_attr.ca_atimeondisk) >
879 ATIME_ONDISK_ACCURACY)) {
880 cp->c_flag |= C_MODIFIED;
881 }
882 cp->c_touch_acctime = FALSE;
883 }
884 if (cp->c_touch_modtime) {
885 cp->c_mtime = tv.tv_sec;
886 cp->c_touch_modtime = FALSE;
887 cp->c_flag |= C_MODIFIED;
888 touchvol = 1;
889#if 1
9bccf70c 890 /*
91447636 891 * HFS dates that WE set must be adjusted for DST
9bccf70c 892 */
91447636
A
893 if ((hfsmp->hfs_flags & HFS_STANDARD) && gTimeZone.tz_dsttime) {
894 cp->c_mtime += 3600;
895 }
9bccf70c 896#endif
91447636
A
897 }
898 if (cp->c_touch_chgtime) {
899 cp->c_ctime = tv.tv_sec;
900 cp->c_touch_chgtime = FALSE;
901 cp->c_flag |= C_MODIFIED;
902 touchvol = 1;
903 }
904
905 /* Touch the volume modtime if needed */
906 if (touchvol) {
2d21ac55 907 MarkVCBDirty(hfsmp);
91447636
A
908 HFSTOVCB(hfsmp)->vcbLsMod = tv.tv_sec;
909 }
9bccf70c 910 }
91447636
A
911}
912
913/*
914 * Lock a cnode.
915 */
916__private_extern__
917int
918hfs_lock(struct cnode *cp, enum hfslocktype locktype)
919{
920 void * thread = current_thread();
921
2d21ac55 922 if (cp->c_lockowner == thread) {
91447636 923 /*
2d21ac55 924 * Only the extents and bitmap file's support lock recursion.
91447636 925 */
2d21ac55
A
926 if ((cp->c_fileid == kHFSExtentsFileID) ||
927 (cp->c_fileid == kHFSAllocationFileID)) {
928 cp->c_syslockcount++;
91447636 929 } else {
2d21ac55 930 panic("hfs_lock: locking against myself!");
91447636
A
931 }
932 } else if (locktype == HFS_SHARED_LOCK) {
933 lck_rw_lock_shared(&cp->c_rwlock);
934 cp->c_lockowner = HFS_SHARED_OWNER;
2d21ac55
A
935
936 } else /* HFS_EXCLUSIVE_LOCK */ {
91447636
A
937 lck_rw_lock_exclusive(&cp->c_rwlock);
938 cp->c_lockowner = thread;
2d21ac55
A
939
940 /*
941 * Only the extents and bitmap file's support lock recursion.
942 */
943 if ((cp->c_fileid == kHFSExtentsFileID) ||
944 (cp->c_fileid == kHFSAllocationFileID)) {
945 cp->c_syslockcount = 1;
946 }
947 }
948
949#ifdef HFS_CHECK_LOCK_ORDER
950 /*
951 * Regular cnodes (non-system files) cannot be locked
952 * while holding the journal lock or a system file lock.
953 */
954 if (!(cp->c_desc.cd_flags & CD_ISMETA) &&
955 ((cp->c_fileid > kHFSFirstUserCatalogNodeID) || (cp->c_fileid == kHFSRootFolderID))) {
956 vnode_t vp = NULLVP;
957
958 /* Find corresponding vnode. */
959 if (cp->c_vp != NULLVP && VTOC(cp->c_vp) == cp) {
960 vp = cp->c_vp;
961 } else if (cp->c_rsrc_vp != NULLVP && VTOC(cp->c_rsrc_vp) == cp) {
962 vp = cp->c_rsrc_vp;
963 }
964 if (vp != NULLVP) {
965 struct hfsmount *hfsmp = VTOHFS(vp);
966
967 if (hfsmp->jnl && (journal_owner(hfsmp->jnl) == thread)) {
968 /* This will eventually be a panic here. */
969 printf("hfs_lock: bad lock order (cnode after journal)\n");
970 }
971 if (hfsmp->hfs_catalog_cp && hfsmp->hfs_catalog_cp->c_lockowner == thread) {
972 panic("hfs_lock: bad lock order (cnode after catalog)");
973 }
974 if (hfsmp->hfs_attribute_cp && hfsmp->hfs_attribute_cp->c_lockowner == thread) {
975 panic("hfs_lock: bad lock order (cnode after attribute)");
976 }
977 if (hfsmp->hfs_extents_cp && hfsmp->hfs_extents_cp->c_lockowner == thread) {
978 panic("hfs_lock: bad lock order (cnode after extents)");
979 }
980 }
91447636 981 }
2d21ac55
A
982#endif /* HFS_CHECK_LOCK_ORDER */
983
55e303ae 984 /*
91447636 985 * Skip cnodes that no longer exist (were deleted).
55e303ae 986 */
91447636
A
987 if ((locktype != HFS_FORCE_LOCK) &&
988 ((cp->c_desc.cd_flags & CD_ISMETA) == 0) &&
989 (cp->c_flag & C_NOEXISTS)) {
990 hfs_unlock(cp);
991 return (ENOENT);
992 }
993 return (0);
994}
55e303ae 995
91447636
A
996/*
997 * Lock a pair of cnodes.
998 */
999__private_extern__
1000int
1001hfs_lockpair(struct cnode *cp1, struct cnode *cp2, enum hfslocktype locktype)
1002{
1003 struct cnode *first, *last;
1004 int error;
1005
1006 /*
1007 * If cnodes match then just lock one.
1008 */
1009 if (cp1 == cp2) {
1010 return hfs_lock(cp1, locktype);
9bccf70c
A
1011 }
1012
91447636 1013 /*
2d21ac55 1014 * Lock in cnode address order.
91447636 1015 */
2d21ac55 1016 if (cp1 < cp2) {
91447636
A
1017 first = cp1;
1018 last = cp2;
1019 } else {
1020 first = cp2;
1021 last = cp1;
1022 }
1023
1024 if ( (error = hfs_lock(first, locktype))) {
1025 return (error);
1026 }
1027 if ( (error = hfs_lock(last, locktype))) {
1028 hfs_unlock(first);
1029 return (error);
1030 }
9bccf70c
A
1031 return (0);
1032}
1033
91447636
A
1034/*
1035 * Check ordering of two cnodes. Return true if they are are in-order.
1036 */
1037static int
1038hfs_isordered(struct cnode *cp1, struct cnode *cp2)
1039{
1040 if (cp1 == cp2)
1041 return (0);
1042 if (cp1 == NULL || cp2 == (struct cnode *)0xffffffff)
1043 return (1);
1044 if (cp2 == NULL || cp1 == (struct cnode *)0xffffffff)
1045 return (0);
2d21ac55
A
1046 /*
1047 * Locking order is cnode address order.
1048 */
1049 return (cp1 < cp2);
91447636
A
1050}
1051
1052/*
1053 * Acquire 4 cnode locks.
2d21ac55 1054 * - locked in cnode address order (lesser address first).
91447636
A
1055 * - all or none of the locks are taken
1056 * - only one lock taken per cnode (dup cnodes are skipped)
1057 * - some of the cnode pointers may be null
1058 */
1059__private_extern__
1060int
1061hfs_lockfour(struct cnode *cp1, struct cnode *cp2, struct cnode *cp3,
1062 struct cnode *cp4, enum hfslocktype locktype)
1063{
1064 struct cnode * a[3];
1065 struct cnode * b[3];
1066 struct cnode * list[4];
1067 struct cnode * tmp;
1068 int i, j, k;
1069 int error;
1070
1071 if (hfs_isordered(cp1, cp2)) {
1072 a[0] = cp1; a[1] = cp2;
1073 } else {
1074 a[0] = cp2; a[1] = cp1;
1075 }
1076 if (hfs_isordered(cp3, cp4)) {
1077 b[0] = cp3; b[1] = cp4;
1078 } else {
1079 b[0] = cp4; b[1] = cp3;
1080 }
1081 a[2] = (struct cnode *)0xffffffff; /* sentinel value */
1082 b[2] = (struct cnode *)0xffffffff; /* sentinel value */
1083
1084 /*
1085 * Build the lock list, skipping over duplicates
1086 */
1087 for (i = 0, j = 0, k = 0; (i < 2 || j < 2); ) {
1088 tmp = hfs_isordered(a[i], b[j]) ? a[i++] : b[j++];
1089 if (k == 0 || tmp != list[k-1])
1090 list[k++] = tmp;
1091 }
1092
1093 /*
1094 * Now we can lock using list[0 - k].
1095 * Skip over NULL entries.
1096 */
1097 for (i = 0; i < k; ++i) {
1098 if (list[i])
1099 if ((error = hfs_lock(list[i], locktype))) {
1100 /* Drop any locks we acquired. */
1101 while (--i >= 0) {
1102 if (list[i])
1103 hfs_unlock(list[i]);
1104 }
1105 return (error);
1106 }
1107 }
1108 return (0);
1109}
1110
1111
1112/*
1113 * Unlock a cnode.
1114 */
1115__private_extern__
1116void
1117hfs_unlock(struct cnode *cp)
1118{
1119 vnode_t rvp = NULLVP;
0c530ab8 1120 vnode_t vp = NULLVP;
2d21ac55
A
1121 u_int32_t c_flag;
1122 void *lockowner;
91447636 1123
2d21ac55
A
1124 /*
1125 * Only the extents and bitmap file's support lock recursion.
1126 */
1127 if ((cp->c_fileid == kHFSExtentsFileID) ||
1128 (cp->c_fileid == kHFSAllocationFileID)) {
1129 if (--cp->c_syslockcount > 0) {
1130 return;
91447636
A
1131 }
1132 }
0c530ab8
A
1133 c_flag = cp->c_flag;
1134 cp->c_flag &= ~(C_NEED_DVNODE_PUT | C_NEED_RVNODE_PUT | C_NEED_DATA_SETSIZE | C_NEED_RSRC_SETSIZE);
2d21ac55 1135
0c530ab8 1136 if (c_flag & (C_NEED_DVNODE_PUT | C_NEED_DATA_SETSIZE)) {
2d21ac55 1137 vp = cp->c_vp;
0c530ab8
A
1138 }
1139 if (c_flag & (C_NEED_RVNODE_PUT | C_NEED_RSRC_SETSIZE)) {
2d21ac55 1140 rvp = cp->c_rsrc_vp;
0c530ab8 1141 }
6601e61a 1142
2d21ac55
A
1143 lockowner = cp->c_lockowner;
1144 if (lockowner == current_thread()) {
1145 cp->c_lockowner = NULL;
1146 lck_rw_unlock_exclusive(&cp->c_rwlock);
1147 } else {
1148 lck_rw_unlock_shared(&cp->c_rwlock);
1149 }
91447636 1150
0c530ab8
A
1151 /* Perform any vnode post processing after cnode lock is dropped. */
1152 if (vp) {
1153 if (c_flag & C_NEED_DATA_SETSIZE)
1154 ubc_setsize(vp, 0);
1155 if (c_flag & C_NEED_DVNODE_PUT)
1156 vnode_put(vp);
1157 }
1158 if (rvp) {
1159 if (c_flag & C_NEED_RSRC_SETSIZE)
1160 ubc_setsize(rvp, 0);
1161 if (c_flag & C_NEED_RVNODE_PUT)
2d21ac55 1162 vnode_put(rvp);
0c530ab8 1163 }
91447636
A
1164}
1165
1166/*
1167 * Unlock a pair of cnodes.
1168 */
1169__private_extern__
1170void
1171hfs_unlockpair(struct cnode *cp1, struct cnode *cp2)
1172{
1173 hfs_unlock(cp1);
1174 if (cp2 != cp1)
1175 hfs_unlock(cp2);
1176}
1177
1178/*
1179 * Unlock a group of cnodes.
1180 */
1181__private_extern__
1182void
1183hfs_unlockfour(struct cnode *cp1, struct cnode *cp2, struct cnode *cp3, struct cnode *cp4)
1184{
1185 struct cnode * list[4];
1186 int i, k = 0;
1187
1188 if (cp1) {
1189 hfs_unlock(cp1);
1190 list[k++] = cp1;
1191 }
1192 if (cp2) {
1193 for (i = 0; i < k; ++i) {
1194 if (list[i] == cp2)
1195 goto skip1;
1196 }
1197 hfs_unlock(cp2);
1198 list[k++] = cp2;
1199 }
1200skip1:
1201 if (cp3) {
1202 for (i = 0; i < k; ++i) {
1203 if (list[i] == cp3)
1204 goto skip2;
1205 }
1206 hfs_unlock(cp3);
1207 list[k++] = cp3;
1208 }
1209skip2:
1210 if (cp4) {
1211 for (i = 0; i < k; ++i) {
1212 if (list[i] == cp4)
1213 return;
1214 }
1215 hfs_unlock(cp4);
1216 }
1217}
1218
1219
1220/*
1221 * Protect a cnode against a truncation.
1222 *
1223 * Used mainly by read/write since they don't hold the
1224 * cnode lock across calls to the cluster layer.
1225 *
1226 * The process doing a truncation must take the lock
1227 * exclusive. The read/write processes can take it
1228 * non-exclusive.
1229 */
1230__private_extern__
1231void
1232hfs_lock_truncate(struct cnode *cp, int exclusive)
1233{
2d21ac55 1234#ifdef HFS_CHECK_LOCK_ORDER
91447636 1235 if (cp->c_lockowner == current_thread())
2d21ac55
A
1236 panic("hfs_lock_truncate: cnode %p locked!", cp);
1237#endif /* HFS_CHECK_LOCK_ORDER */
91447636
A
1238
1239 if (exclusive)
1240 lck_rw_lock_exclusive(&cp->c_truncatelock);
1241 else
1242 lck_rw_lock_shared(&cp->c_truncatelock);
1243}
1244
1245__private_extern__
1246void
2d21ac55 1247hfs_unlock_truncate(struct cnode *cp, int exclusive)
91447636 1248{
2d21ac55
A
1249 if (exclusive) {
1250 lck_rw_unlock_exclusive(&cp->c_truncatelock);
1251 } else {
1252 lck_rw_unlock_shared(&cp->c_truncatelock);
1253 }
91447636
A
1254}
1255
1256
1257
1258