1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <sys/param.h>
23#include <sys/systm.h>
24#include <sys/proc.h>
25#include <sys/vnode.h>
26#include <sys/mount.h>
27#include <sys/kernel.h>
28#include <sys/malloc.h>
29#include <sys/time.h>
30#include <sys/ubc.h>
31#include <sys/quota.h>
32#include <sys/kdebug.h>
33
34#include <kern/locks.h>
35
36#include <miscfs/specfs/specdev.h>
37#include <miscfs/fifofs/fifo.h>
38
39#include <hfs/hfs.h>
40#include <hfs/hfs_catalog.h>
41#include <hfs/hfs_cnode.h>
42#include <hfs/hfs_quota.h>
43
44extern int prtactive;
45
46extern lck_attr_t * hfs_lock_attr;
47extern lck_grp_t * hfs_mutex_group;
48extern lck_grp_t * hfs_rwlock_group;
49
50static int hfs_filedone(struct vnode *vp, vfs_context_t context);
51
52static void hfs_reclaim_cnode(struct cnode *);
53
54static int hfs_valid_cnode(struct hfsmount *, struct vnode *, struct componentname *, cnid_t);
55
56static int hfs_isordered(struct cnode *, struct cnode *);
57
58int hfs_vnop_inactive(struct vnop_inactive_args *);
59
60int hfs_vnop_reclaim(struct vnop_reclaim_args *);
61
62
63
64
65
66__private_extern__
67int
68hfs_vnop_inactive(struct vnop_inactive_args *ap)
69{
70 struct vnode *vp = ap->a_vp;
71 struct cnode *cp;
72 struct hfsmount *hfsmp = VTOHFS(vp);
73 struct proc *p = vfs_context_proc(ap->a_context);
74 int error = 0;
75 int recycle = 0;
76 int forkcount = 0;
77 int truncated = 0;
78 int started_tr = 0;
79 int took_trunc_lock = 0;
80 cat_cookie_t cookie;
81 int cat_reserve = 0;
82 int lockflags;
83 enum vtype v_type;
84
85 v_type = vnode_vtype(vp);
86 cp = VTOC(vp);
87
88 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || vnode_issystem(vp) ||
89 (hfsmp->hfs_freezing_proc == p)) {
90 return (0);
91 }
92
93
94
95
96 if (cp->c_mode == 0) {
97 vnode_recycle(vp);
98 return (0);
99 }
100
101 if ((v_type == VREG) &&
102 (ISSET(cp->c_flag, C_DELETED) || VTOF(vp)->ff_blocks)) {
103 hfs_lock_truncate(cp, TRUE);
104 took_trunc_lock = 1;
105 }
106
107
108
109
110
111
112 if ((v_type == VREG || v_type == VLNK) &&
113 (cp->c_flag & C_DELETED) &&
114 (VTOF(vp)->ff_blocks != 0)) {
115 ubc_setsize(vp, 0);
116 }
117
118 (void) hfs_lock(cp, HFS_FORCE_LOCK);
119
120 if (v_type == VREG && !ISSET(cp->c_flag, C_DELETED) && VTOF(vp)->ff_blocks) {
121 hfs_filedone(vp, ap->a_context);
122 }
123
124
125
126 if (v_type == VDIR)
127 hfs_reldirhints(cp, 0);
128
129 if (cp->c_datafork)
130 ++forkcount;
131 if (cp->c_rsrcfork)
132 ++forkcount;
133
134
135 if ((v_type == VREG || v_type == VLNK) && (cp->c_flag & C_DELETED)) {
136 if (VTOF(vp)->ff_blocks != 0) {
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 error = hfs_truncate(vp, (off_t)0, IO_NDELAY, 1, ap->a_context);
158 if (error)
159 goto out;
160 truncated = 1;
161 }
162 recycle = 1;
163 }
164
165
166
167
168
169 if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) {
170
171
172
173
174 hfs_chash_mark_in_transit(cp);
175
176 cp->c_flag &= ~C_DELETED;
177 cp->c_flag |= C_NOEXISTS;
178 cp->c_rdev = 0;
179
180 if (started_tr == 0) {
181 if (hfs_start_transaction(hfsmp) != 0) {
182 error = EINVAL;
183 goto out;
184 }
185 started_tr = 1;
186 }
187
188
189
190
191 if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) {
192 goto out;
193 }
194 cat_reserve = 1;
195
196 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
197
198 if (cp->c_blocks > 0)
199 printf("hfs_inactive: attempting to delete a non-empty file!");
200
201
202
203
204
205
206
207
208
209 cat_releasedesc(&cp->c_desc);
210
211
212
213
214
215 error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr);
216
217 if (error && truncated && (error != ENXIO))
218 printf("hfs_inactive: couldn't delete a truncated file!");
219
220
221 if (error == 0) {
222 hfsmp->hfs_privdir_attr.ca_entries--;
223 (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
224 &hfsmp->hfs_privdir_attr, NULL, NULL);
225 }
226
227 if (error == 0) {
228
229 (void) hfs_removeallattr(hfsmp, cp->c_fileid);
230 }
231
232 hfs_systemfile_unlock(hfsmp, lockflags);
233
234 if (error)
235 goto out;
236
237#if QUOTA
238 (void)hfs_chkiq(cp, -1, NOCRED, 0);
239#endif
240
241 cp->c_mode = 0;
242 cp->c_flag |= C_NOEXISTS;
243 cp->c_touch_chgtime = TRUE;
244 cp->c_touch_modtime = TRUE;
245
246 if (error == 0)
247 hfs_volupdate(hfsmp, VOL_RMFILE, 0);
248 }
249
250 if ((cp->c_flag & C_MODIFIED) ||
251 cp->c_touch_acctime || cp->c_touch_chgtime || cp->c_touch_modtime) {
252 hfs_update(vp, 0);
253 }
254out:
255 if (cat_reserve)
256 cat_postflight(hfsmp, &cookie, p);
257
258
259 if (started_tr) {
260 hfs_end_transaction(hfsmp);
261 started_tr = 0;
262 }
263
264 hfs_unlock(cp);
265
266 if (took_trunc_lock)
267 hfs_unlock_truncate(cp);
268
269
270
271
272
273 if (cp->c_mode == 0 || recycle)
274 vnode_recycle(vp);
275
276 return (error);
277}
278
279
280
281
282static int
283hfs_filedone(struct vnode *vp, vfs_context_t context)
284{
285 struct cnode *cp;
286 struct filefork *fp;
287 struct hfsmount *hfsmp;
288 off_t leof;
289 u_long blks, blocksize;
290
291 cp = VTOC(vp);
292 fp = VTOF(vp);
293 hfsmp = VTOHFS(vp);
294 leof = fp->ff_size;
295
296 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || (fp->ff_blocks == 0))
297 return (0);
298
299 hfs_unlock(cp);
300 (void) cluster_push(vp, IO_CLOSE);
301 hfs_lock(cp, HFS_FORCE_LOCK);
302
303
304
305
306
307 while (!CIRCLEQ_EMPTY(&fp->ff_invalidranges)) {
308 struct rl_entry *invalid_range = CIRCLEQ_FIRST(&fp->ff_invalidranges);
309 off_t start = invalid_range->rl_start;
310 off_t end = invalid_range->rl_end;
311
312
313
314
315
316 rl_remove(start, end, &fp->ff_invalidranges);
317
318 hfs_unlock(cp);
319 (void) cluster_write(vp, (struct uio *) 0,
320 leof, end + 1, start, (off_t)0,
321 IO_HEADZEROFILL | IO_NOZERODIRTY | IO_NOCACHE);
322 hfs_lock(cp, HFS_FORCE_LOCK);
323 cp->c_flag |= C_MODIFIED;
324 }
325 cp->c_flag &= ~C_ZFWANTSYNC;
326 cp->c_zftimeout = 0;
327 blocksize = VTOVCB(vp)->blockSize;
328 blks = leof / blocksize;
329 if (((off_t)blks * (off_t)blocksize) != leof)
330 blks++;
331
332
333
334 if (blks < fp->ff_blocks)
335 (void) hfs_truncate(vp, leof, IO_NDELAY, 0, context);
336 hfs_unlock(cp);
337 (void) cluster_push(vp, IO_CLOSE);
338 hfs_lock(cp, HFS_FORCE_LOCK);
339
340
341
342
343
344
345 if (cp->c_flag & C_MODIFIED) {
346 hfs_update(vp, 0);
347 }
348 return (0);
349}
350
351
352
353
354
355__private_extern__
356int
357hfs_vnop_reclaim(struct vnop_reclaim_args *ap)
358{
359 struct vnode *vp = ap->a_vp;
360 struct cnode *cp;
361 struct filefork *fp = NULL;
362 struct filefork *altfp = NULL;
363 int reclaim_cnode = 0;
364
365 (void) hfs_lock(VTOC(vp), HFS_FORCE_LOCK);
366 cp = VTOC(vp);
367
368
369
370
371 if (!vnode_isdir(vp) && !vnode_issystem(vp))
372 (void) hfs_addhotfile(vp);
373
374 vnode_removefsref(vp);
375
376
377
378
379
380 if (cp->c_vp == vp) {
381 fp = cp->c_datafork;
382 altfp = cp->c_rsrcfork;
383
384 cp->c_datafork = NULL;
385 cp->c_vp = NULL;
386 } else if (cp->c_rsrc_vp == vp) {
387 fp = cp->c_rsrcfork;
388 altfp = cp->c_datafork;
389
390 cp->c_rsrcfork = NULL;
391 cp->c_rsrc_vp = NULL;
392 } else {
393 panic("hfs_vnop_reclaim: vp points to wrong cnode\n");
394 }
395
396
397
398 if (altfp == NULL) {
399
400 if (hfs_chashremove(cp) == 0)
401 reclaim_cnode = 1;
402
403
404
405 if (vnode_isdir(vp)) {
406 hfs_reldirhints(cp, 0);
407 }
408 }
409
410 if (fp) {
411
412 if (vnode_islnk(vp) && (fp->ff_symlinkptr != NULL)) {
413 FREE(fp->ff_symlinkptr, M_TEMP);
414 }
415 FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK);
416 }
417
418
419
420
421 if (reclaim_cnode) {
422 hfs_chashwakeup(cp, H_ALLOC | H_TRANSIT);
423 hfs_reclaim_cnode(cp);
424 } else {
425 hfs_unlock(cp);
426 }
427
428 vnode_clearfsnode(vp);
429 return (0);
430}
431
432
433extern int (**hfs_vnodeop_p) (void *);
434extern int (**hfs_specop_p) (void *);
435extern int (**hfs_fifoop_p) (void *);
436
437
438
439
440
441
442__private_extern__
443int
444hfs_getnewvnode(
445 struct hfsmount *hfsmp,
446 struct vnode *dvp,
447 struct componentname *cnp,
448 struct cat_desc *descp,
449 int wantrsrc,
450 struct cat_attr *attrp,
451 struct cat_fork *forkp,
452 struct vnode **vpp)
453{
454 struct mount *mp = HFSTOVFS(hfsmp);
455 struct vnode *vp = NULL;
456 struct vnode **cvpp;
457 struct vnode *tvp = NULLVP;
458 struct cnode *cp = NULL;
459 struct filefork *fp = NULL;
460 int i;
461 int retval;
462 int issystemfile;
463 struct vnode_fsparam vfsp;
464 enum vtype vtype;
465
466 if (attrp->ca_fileid == 0) {
467 *vpp = NULL;
468 return (ENOENT);
469 }
470
471#if !FIFO
472 if (IFTOVT(attrp->ca_mode) == VFIFO) {
473 *vpp = NULL;
474 return (ENOTSUP);
475 }
476#endif
477 vtype = IFTOVT(attrp->ca_mode);
478 issystemfile = (descp->cd_flags & CD_ISMETA) && (vtype == VREG);
479
480
481
482
483
484 cp = hfs_chash_getcnode(hfsmp->hfs_raw_dev, attrp->ca_fileid, vpp, wantrsrc, (wantrsrc == 2));
485
486
487 if ((cp->c_flag & C_HARDLINK) && descp->cd_nameptr && descp->cd_namelen > 0) {
488 replace_desc(cp, descp);
489 }
490
491 if (*vpp != NULL)
492 return (0);
493
494
495
496
497 if (ISSET(cp->c_hflag, H_ALLOC)) {
498 lck_rw_init(&cp->c_truncatelock, hfs_rwlock_group, hfs_lock_attr);
499
500
501 if (!hfs_valid_cnode(hfsmp, dvp, (wantrsrc ? NULL : cnp), cp->c_fileid)) {
502 hfs_chash_abort(cp);
503 hfs_reclaim_cnode(cp);
504 *vpp = NULL;
505 return (ENOENT);
506 }
507 bcopy(attrp, &cp->c_attr, sizeof(struct cat_attr));
508 bcopy(descp, &cp->c_desc, sizeof(struct cat_desc));
509
510
511 descp->cd_namelen = 0;
512 descp->cd_nameptr = NULL;
513 descp->cd_flags &= ~CD_HASBUF;
514
515
516 if (IFTOVT(cp->c_mode) == VREG &&
517 (descp->cd_cnid != attrp->ca_fileid)) {
518 cp->c_flag |= C_HARDLINK;
519 }
520
521
522 if (IFTOVT(cp->c_mode) != VDIR) {
523 cp->c_devvp = hfsmp->hfs_devvp;
524 vnode_ref(cp->c_devvp);
525 }
526#if QUOTA
527 for (i = 0; i < MAXQUOTAS; i++)
528 cp->c_dquot[i] = NODQUOT;
529#endif
530 }
531
532 if (IFTOVT(cp->c_mode) == VDIR) {
533 if (cp->c_vp != NULL)
534 panic("hfs_getnewvnode: orphaned vnode (data)");
535 cvpp = &cp->c_vp;
536 } else {
537 if (forkp && attrp->ca_blocks < forkp->cf_blocks)
538 panic("hfs_getnewvnode: bad ca_blocks (too small)");
539
540
541
542 MALLOC_ZONE(fp, struct filefork *, sizeof(struct filefork),
543 M_HFSFORK, M_WAITOK);
544 fp->ff_cp = cp;
545 if (forkp)
546 bcopy(forkp, &fp->ff_data, sizeof(struct cat_fork));
547 else
548 bzero(&fp->ff_data, sizeof(struct cat_fork));
549 rl_init(&fp->ff_invalidranges);
550 fp->ff_sysfileinfo = 0;
551
552 if (wantrsrc) {
553 if (cp->c_rsrcfork != NULL)
554 panic("hfs_getnewvnode: orphaned rsrc fork");
555 if (cp->c_rsrc_vp != NULL)
556 panic("hfs_getnewvnode: orphaned vnode (rsrc)");
557 cp->c_rsrcfork = fp;
558 cvpp = &cp->c_rsrc_vp;
559 if ( (tvp = cp->c_vp) != NULLVP )
560 cp->c_flag |= C_NEED_DVNODE_PUT;
561 } else {
562 if (cp->c_datafork != NULL)
563 panic("hfs_getnewvnode: orphaned data fork");
564 if (cp->c_vp != NULL)
565 panic("hfs_getnewvnode: orphaned vnode (data)");
566 cp->c_datafork = fp;
567 cvpp = &cp->c_vp;
568 if ( (tvp = cp->c_rsrc_vp) != NULLVP)
569 cp->c_flag |= C_NEED_RVNODE_PUT;
570 }
571 }
572 if (tvp != NULLVP) {
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594 if ( vnode_get(tvp) != 0)
595 cp->c_flag &= ~(C_NEED_RVNODE_PUT | C_NEED_DVNODE_PUT);
596 }
597 vfsp.vnfs_mp = mp;
598 vfsp.vnfs_vtype = vtype;
599 vfsp.vnfs_str = "hfs";
600 vfsp.vnfs_dvp = dvp;
601 vfsp.vnfs_fsnode = cp;
602 vfsp.vnfs_cnp = cnp;
603 if (vtype == VFIFO )
604 vfsp.vnfs_vops = hfs_fifoop_p;
605 else if (vtype == VBLK || vtype == VCHR)
606 vfsp.vnfs_vops = hfs_specop_p;
607 else
608 vfsp.vnfs_vops = hfs_vnodeop_p;
609
610 if (vtype == VBLK || vtype == VCHR)
611 vfsp.vnfs_rdev = attrp->ca_rdev;
612 else
613 vfsp.vnfs_rdev = 0;
614
615 if (forkp)
616 vfsp.vnfs_filesize = forkp->cf_size;
617 else
618 vfsp.vnfs_filesize = 0;
619
620 if (dvp && cnp && (cnp->cn_flags & MAKEENTRY))
621 vfsp.vnfs_flags = 0;
622 else
623 vfsp.vnfs_flags = VNFS_NOCACHE;
624
625
626 vfsp.vnfs_marksystem = issystemfile;
627
628
629 if (descp->cd_cnid == kHFSRootFolderID)
630 vfsp.vnfs_markroot = 1;
631 else
632 vfsp.vnfs_markroot = 0;
633
634 if ((retval = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, cvpp))) {
635 if (fp) {
636 if (fp == cp->c_datafork)
637 cp->c_datafork = NULL;
638 else
639 cp->c_rsrcfork = NULL;
640
641 FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK);
642 }
643
644
645
646
647 if ((cp->c_vp == NULL) && (cp->c_rsrc_vp == NULL)) {
648 hfs_chash_abort(cp);
649 hfs_reclaim_cnode(cp);
650 } else {
651 hfs_chashwakeup(cp, H_ALLOC | H_ATTACH);
652 hfs_unlock(cp);
653 }
654 *vpp = NULL;
655 return (retval);
656 }
657 vp = *cvpp;
658 vnode_addfsref(vp);
659 vnode_settag(vp, VT_HFS);
660 if (cp->c_flag & C_HARDLINK)
661 vnode_set_hard_link(vp);
662 hfs_chashwakeup(cp, H_ALLOC | H_ATTACH);
663
664
665
666
667 if (!vnode_isdir(vp) && !vnode_issystem(vp))
668 (void) hfs_removehotfile(vp);
669
670 *vpp = vp;
671 return (0);
672}
673
674
675static void
676hfs_reclaim_cnode(struct cnode *cp)
677{
678#if QUOTA
679 int i;
680
681 for (i = 0; i < MAXQUOTAS; i++) {
682 if (cp->c_dquot[i] != NODQUOT) {
683 dqreclaim(cp->c_dquot[i]);
684 cp->c_dquot[i] = NODQUOT;
685 }
686 }
687#endif
688
689 if (cp->c_devvp) {
690 struct vnode *tmp_vp = cp->c_devvp;
691
692 cp->c_devvp = NULL;
693 vnode_rele(tmp_vp);
694 }
695
696
697
698
699 if (cp->c_desc.cd_flags & CD_HASBUF) {
700 char *nameptr;
701
702 nameptr = cp->c_desc.cd_nameptr;
703 cp->c_desc.cd_nameptr = 0;
704 cp->c_desc.cd_flags &= ~CD_HASBUF;
705 cp->c_desc.cd_namelen = 0;
706 vfs_removename(nameptr);
707 }
708
709 lck_rw_destroy(&cp->c_rwlock, hfs_rwlock_group);
710 lck_rw_destroy(&cp->c_truncatelock, hfs_rwlock_group);
711 bzero(cp, sizeof(struct cnode));
712 FREE_ZONE(cp, sizeof(struct cnode), M_HFSNODE);
713}
714
715
716static int
717hfs_valid_cnode(struct hfsmount *hfsmp, struct vnode *dvp, struct componentname *cnp, cnid_t cnid)
718{
719 struct cat_attr attr;
720 struct cat_desc cndesc;
721 int stillvalid = 0;
722 int lockflags;
723
724
725 if (cnid < kHFSFirstUserCatalogNodeID)
726 return (1);
727
728
729
730 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
731
732 if (dvp && cnp) {
733 bzero(&cndesc, sizeof(cndesc));
734 cndesc.cd_nameptr = cnp->cn_nameptr;
735 cndesc.cd_namelen = cnp->cn_namelen;
736 cndesc.cd_parentcnid = VTOC(dvp)->c_cnid;
737 cndesc.cd_hint = VTOC(dvp)->c_childhint;
738
739 if ((cat_lookup(hfsmp, &cndesc, 0, NULL, &attr, NULL, NULL) == 0) &&
740 (cnid == attr.ca_fileid)) {
741 stillvalid = 1;
742 }
743 } else {
744 if (cat_idlookup(hfsmp, cnid, NULL, NULL, NULL) == 0) {
745 stillvalid = 1;
746 }
747 }
748 hfs_systemfile_unlock(hfsmp, lockflags);
749
750 return (stillvalid);
751}
752
753
754
755
756
757
758
759
760__private_extern__
761void
762hfs_touchtimes(struct hfsmount *hfsmp, struct cnode* cp)
763{
764
765 if (hfsmp->hfs_flags & HFS_STANDARD) {
766 cp->c_touch_acctime = FALSE;
767 }
768
769 if (cp->c_touch_acctime || cp->c_touch_chgtime || cp->c_touch_modtime) {
770 struct timeval tv;
771 int touchvol = 0;
772
773 microtime(&tv);
774
775 if (cp->c_touch_acctime) {
776 cp->c_atime = tv.tv_sec;
777
778
779
780
781
782 if ((((u_int32_t)cp->c_atime - (u_int32_t)(cp)->c_attr.ca_atimeondisk) >
783 ATIME_ONDISK_ACCURACY)) {
784 cp->c_flag |= C_MODIFIED;
785 }
786 cp->c_touch_acctime = FALSE;
787 }
788 if (cp->c_touch_modtime) {
789 cp->c_mtime = tv.tv_sec;
790 cp->c_touch_modtime = FALSE;
791 cp->c_flag |= C_MODIFIED;
792 touchvol = 1;
793#if 1
794
795
796
797 if ((hfsmp->hfs_flags & HFS_STANDARD) && gTimeZone.tz_dsttime) {
798 cp->c_mtime += 3600;
799 }
800#endif
801 }
802 if (cp->c_touch_chgtime) {
803 cp->c_ctime = tv.tv_sec;
804 cp->c_touch_chgtime = FALSE;
805 cp->c_flag |= C_MODIFIED;
806 touchvol = 1;
807 }
808
809
810 if (touchvol) {
811 HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00;
812 HFSTOVCB(hfsmp)->vcbLsMod = tv.tv_sec;
813 }
814 }
815}
816
817
818
819
820__private_extern__
821int
822hfs_lock(struct cnode *cp, enum hfslocktype locktype)
823{
824 void * thread = current_thread();
825
826
827 if ((cp->c_fileid < kHFSFirstUserCatalogNodeID) &&
828 (cp->c_fileid > kHFSRootFolderID) &&
829 (locktype != HFS_SHARED_LOCK)) {
830
831
832
833
834
835 if (cp->c_fileid == kHFSExtentsFileID ||
836 cp->c_fileid == kHFSAllocationFileID) {
837 if (cp->c_lockowner == thread) {
838 cp->c_syslockcount++;
839 } else {
840 lck_rw_lock_exclusive(&cp->c_rwlock);
841 cp->c_lockowner = thread;
842 cp->c_syslockcount = 1;
843 }
844 } else {
845 lck_rw_lock_exclusive(&cp->c_rwlock);
846 cp->c_lockowner = thread;
847 }
848 } else if (locktype == HFS_SHARED_LOCK) {
849 lck_rw_lock_shared(&cp->c_rwlock);
850 cp->c_lockowner = HFS_SHARED_OWNER;
851 } else {
852 lck_rw_lock_exclusive(&cp->c_rwlock);
853 cp->c_lockowner = thread;
854 }
855
856
857
858 if ((locktype != HFS_FORCE_LOCK) &&
859 ((cp->c_desc.cd_flags & CD_ISMETA) == 0) &&
860 (cp->c_flag & C_NOEXISTS)) {
861 hfs_unlock(cp);
862 return (ENOENT);
863 }
864 return (0);
865}
866
867
868
869
870__private_extern__
871int
872hfs_lockpair(struct cnode *cp1, struct cnode *cp2, enum hfslocktype locktype)
873{
874 struct cnode *first, *last;
875 int error;
876
877
878
879
880 if (cp1 == cp2) {
881 return hfs_lock(cp1, locktype);
882 }
883
884
885
886
887
888 if ((IFTOVT(cp1->c_mode) == VDIR) && (cp1->c_fileid == cp2->c_parentcnid)) {
889 first = cp1;
890 last = cp2;
891 } else if (cp1 < cp2) {
892 first = cp1;
893 last = cp2;
894 } else {
895 first = cp2;
896 last = cp1;
897 }
898
899 if ( (error = hfs_lock(first, locktype))) {
900 return (error);
901 }
902 if ( (error = hfs_lock(last, locktype))) {
903 hfs_unlock(first);
904 return (error);
905 }
906 return (0);
907}
908
909
910
911
912static int
913hfs_isordered(struct cnode *cp1, struct cnode *cp2)
914{
915 if (cp1 == cp2)
916 return (0);
917 if (cp1 == NULL || cp2 == (struct cnode *)0xffffffff)
918 return (1);
919 if (cp2 == NULL || cp1 == (struct cnode *)0xffffffff)
920 return (0);
921 if (cp1->c_fileid == cp2->c_parentcnid)
922 return (1);
923 if (cp2->c_fileid == cp1->c_parentcnid)
924 return (0);
925
926 return (cp1 < cp2);
927}
928
929
930
931
932
933
934
935
936
937__private_extern__
938int
939hfs_lockfour(struct cnode *cp1, struct cnode *cp2, struct cnode *cp3,
940 struct cnode *cp4, enum hfslocktype locktype)
941{
942 struct cnode * a[3];
943 struct cnode * b[3];
944 struct cnode * list[4];
945 struct cnode * tmp;
946 int i, j, k;
947 int error;
948
949 if (hfs_isordered(cp1, cp2)) {
950 a[0] = cp1; a[1] = cp2;
951 } else {
952 a[0] = cp2; a[1] = cp1;
953 }
954 if (hfs_isordered(cp3, cp4)) {
955 b[0] = cp3; b[1] = cp4;
956 } else {
957 b[0] = cp4; b[1] = cp3;
958 }
959 a[2] = (struct cnode *)0xffffffff;
960 b[2] = (struct cnode *)0xffffffff;
961
962
963
964
965 for (i = 0, j = 0, k = 0; (i < 2 || j < 2); ) {
966 tmp = hfs_isordered(a[i], b[j]) ? a[i++] : b[j++];
967 if (k == 0 || tmp != list[k-1])
968 list[k++] = tmp;
969 }
970
971
972
973
974
975 for (i = 0; i < k; ++i) {
976 if (list[i])
977 if ((error = hfs_lock(list[i], locktype))) {
978
979 while (--i >= 0) {
980 if (list[i])
981 hfs_unlock(list[i]);
982 }
983 return (error);
984 }
985 }
986 return (0);
987}
988
989
990
991
992
993__private_extern__
994void
995hfs_unlock(struct cnode *cp)
996{
997 vnode_t rvp = NULLVP;
998 vnode_t dvp = NULLVP;
999
1000
1001 if ((cp->c_fileid < kHFSFirstUserCatalogNodeID) &&
1002 (cp->c_fileid > kHFSRootFolderID) &&
1003 (cp->c_datafork != NULL)) {
1004
1005
1006
1007
1008 if (cp->c_fileid == kHFSExtentsFileID ||
1009 cp->c_fileid == kHFSAllocationFileID) {
1010 if (--cp->c_syslockcount > 0) {
1011 return;
1012 }
1013 }
1014 }
1015 if (cp->c_flag & C_NEED_DVNODE_PUT)
1016 dvp = cp->c_vp;
1017
1018 if (cp->c_flag & C_NEED_RVNODE_PUT)
1019 rvp = cp->c_rsrc_vp;
1020
1021 cp->c_flag &= ~(C_NEED_DVNODE_PUT | C_NEED_RVNODE_PUT);
1022
1023 cp-> c_lockowner = NULL;
1024 lck_rw_done(&cp->c_rwlock);
1025
1026 if (dvp)
1027 vnode_put(dvp);
1028 if (rvp)
1029 vnode_put(rvp);
1030}
1031
1032
1033
1034
1035__private_extern__
1036void
1037hfs_unlockpair(struct cnode *cp1, struct cnode *cp2)
1038{
1039 hfs_unlock(cp1);
1040 if (cp2 != cp1)
1041 hfs_unlock(cp2);
1042}
1043
1044
1045
1046
1047__private_extern__
1048void
1049hfs_unlockfour(struct cnode *cp1, struct cnode *cp2, struct cnode *cp3, struct cnode *cp4)
1050{
1051 struct cnode * list[4];
1052 int i, k = 0;
1053
1054 if (cp1) {
1055 hfs_unlock(cp1);
1056 list[k++] = cp1;
1057 }
1058 if (cp2) {
1059 for (i = 0; i < k; ++i) {
1060 if (list[i] == cp2)
1061 goto skip1;
1062 }
1063 hfs_unlock(cp2);
1064 list[k++] = cp2;
1065 }
1066skip1:
1067 if (cp3) {
1068 for (i = 0; i < k; ++i) {
1069 if (list[i] == cp3)
1070 goto skip2;
1071 }
1072 hfs_unlock(cp3);
1073 list[k++] = cp3;
1074 }
1075skip2:
1076 if (cp4) {
1077 for (i = 0; i < k; ++i) {
1078 if (list[i] == cp4)
1079 return;
1080 }
1081 hfs_unlock(cp4);
1082 }
1083}
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096__private_extern__
1097void
1098hfs_lock_truncate(struct cnode *cp, int exclusive)
1099{
1100 if (cp->c_lockowner == current_thread())
1101 panic("hfs_lock_truncate: cnode 0x%08x locked!", cp);
1102
1103 if (exclusive)
1104 lck_rw_lock_exclusive(&cp->c_truncatelock);
1105 else
1106 lck_rw_lock_shared(&cp->c_truncatelock);
1107}
1108
1109__private_extern__
1110void
1111hfs_unlock_truncate(struct cnode *cp)
1112{
1113 lck_rw_done(&cp->c_truncatelock);
1114}
1115
1116
1117
1118
1119