]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_cnode.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_cnode.c
index d59163ab59ee0c803b40bb190fda4adb69cba911..3abf79b4fff25c4db6e150da0e51a1ee43090c2b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -62,6 +62,9 @@ hfs_inactive(ap)
        int recycle = 0;
        int forkcount = 0;
        int truncated = 0;
+       int started_tr = 0, grabbed_lock = 0;
+       cat_cookie_t cookie;
+       int cat_reserve = 0;
 
        if (prtactive && vp->v_usecount != 0)
                vprint("hfs_inactive: pushing active", vp);
@@ -72,7 +75,7 @@ hfs_inactive(ap)
        if (cp->c_mode == 0)
                goto out;
 
-       if (vp->v_mount->mnt_flag & MNT_RDONLY)
+       if (hfsmp->hfs_flags & HFS_READ_ONLY)
                goto out;
 
        if (cp->c_datafork)
@@ -81,12 +84,13 @@ hfs_inactive(ap)
                ++forkcount;
 
        /* If needed, get rid of any fork's data for a deleted file */
-       if ((cp->c_flag & C_DELETED) &&
-           vp->v_type == VREG &&
-           (VTOF(vp)->ff_blocks != 0)) {                       
-               error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p);
-               if (error) goto out;
-               truncated = 1;
+       if ((vp->v_type == VREG) && (cp->c_flag & C_DELETED)) {
+               if (VTOF(vp)->ff_blocks != 0) {
+                       error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p);
+                       if (error)
+                               goto out;
+                       truncated = 1;
+               }
                recycle = 1;
        }
 
@@ -96,13 +100,33 @@ hfs_inactive(ap)
         */
        if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) {                     
                /*
-                * Mark cnode in transit so that one can get this 
+                * Mark cnode in transit so that no one can get this 
                 * cnode from cnode hash.
                 */
                SET(cp->c_flag, C_TRANSIT);
                cp->c_flag &= ~C_DELETED;
                cp->c_rdev = 0;
-               
+
+               // XXXdbg
+               hfs_global_shared_lock_acquire(hfsmp);
+               grabbed_lock = 1;
+               if (hfsmp->jnl) {
+                   if (journal_start_transaction(hfsmp->jnl) != 0) {
+                               error = EINVAL;
+                               goto out;
+                   }
+                   started_tr = 1;
+               }
+
+               /*
+                * Reserve some space in the Catalog file.
+                */
+               if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) {
+                       goto out;
+               }
+               cat_reserve = 1;
+
+
                /* Lock catalog b-tree */
                error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
                if (error) goto out;
@@ -131,8 +155,7 @@ hfs_inactive(ap)
                if (error) goto out;
 
 #if QUOTA
-               if (!hfs_getinoquota(cp))
-                       (void)hfs_chkiq(cp, -1, NOCRED, 0);
+               (void)hfs_chkiq(cp, -1, NOCRED, 0);
 #endif /* QUOTA */
 
                cp->c_mode = 0;
@@ -142,17 +165,29 @@ hfs_inactive(ap)
                        hfs_volupdate(hfsmp, VOL_RMFILE, 0);
        }
 
-       /* Push any defered access times to disk */
-       if (cp->c_flag & C_ATIMEMOD) {
-               cp->c_flag &= ~C_ATIMEMOD;
-               if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
-                       cp->c_flag |= C_MODIFIED;
+       if (cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) {
+               tv = time;
+               // if the only thing being updated is the access time
+               // then set the modified bit too so that update will
+               // flush it to disk.  otherwise it'll get dropped.
+               if ((cp->c_flag & C_CHANGEMASK) == C_ACCESS) {
+                   cp->c_flag |= C_MODIFIED;
+               }
+               VOP_UPDATE(vp, &tv, &tv, 0);
        }
-        if (cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) {
-                tv = time;
-                VOP_UPDATE(vp, &tv, &tv, 0);
-        }
 out:
+       if (cat_reserve)
+               cat_postflight(hfsmp, &cookie, p);
+
+       // XXXdbg - have to do this because a goto could have come here
+       if (started_tr) {
+           journal_end_transaction(hfsmp->jnl);
+           started_tr = 0;
+       }
+       if (grabbed_lock) {
+               hfs_global_shared_lock_release(hfsmp);
+       }
+
        VOP_UNLOCK(vp, 0, p);
        /*
         * If we are done with the vnode, reclaim it
@@ -185,7 +220,12 @@ hfs_reclaim(ap)
        if (prtactive && vp->v_usecount != 0)
                vprint("hfs_reclaim(): pushing active", vp);
 
-       devvp = cp->c_devvp;            /* For later releasing */
+       /*
+        * Keep track of an inactive hot file.
+        */
+       (void) hfs_addhotfile(vp);
+
+       devvp = cp->c_devvp;            /* For later releasing */
 
        /*
         * Find file fork for this vnode (if any)
@@ -198,6 +238,9 @@ hfs_reclaim(ap)
        } else if ((fp = cp->c_rsrcfork) && (cp->c_rsrc_vp == vp)) {
                cp->c_rsrcfork = NULL;
                cp->c_rsrc_vp = NULL;
+               if (VPARENT(vp) == cp->c_vp) {
+                   cp->c_flag &= ~C_VPREFHELD;
+               }
                altfp = cp->c_datafork;
        } else {
                cp->c_vp = NULL;
@@ -241,7 +284,7 @@ hfs_reclaim(ap)
 #if QUOTA
                for (i = 0; i < MAXQUOTAS; i++) {
                        if (cp->c_dquot[i] != NODQUOT) {
-                               dqrele(vp, cp->c_dquot[i]);
+                               dqreclaim(vp, cp->c_dquot[i]);
                                cp->c_dquot[i] = NODQUOT;
                        }
                }
@@ -262,7 +305,7 @@ hfs_reclaim(ap)
                        cp->c_desc.cd_nameptr = 0;
                        cp->c_desc.cd_flags &= ~CD_HASBUF;
                        cp->c_desc.cd_namelen = 0;
-                       FREE(nameptr, M_TEMP);
+                       remove_name(nameptr);
                }
                CLR(cp->c_flag, (C_ALLOC | C_TRANSIT));
                if (ISSET(cp->c_flag, C_WALLOC) || ISSET(cp->c_flag, C_WTRANSIT))
@@ -307,12 +350,22 @@ hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wa
        cp = hfs_chashget(dev, cnid, wantrsrc, &vp, &rvp);
        if (cp != NULL) {
                /* hide open files that have been deleted */
-               if ((hfsmp->hfs_private_metadata_dir != 0)
-               &&  (cp->c_parentcnid == hfsmp->hfs_private_metadata_dir)
+               if ((hfsmp->hfs_privdir_desc.cd_cnid != 0)
+               &&  (cp->c_parentcnid == hfsmp->hfs_privdir_desc.cd_cnid)
                &&  (cp->c_nlink == 0)) {
                        retval = ENOENT;
                        goto exit;
                }
+
+               /* Hide private journal files */
+               if (hfsmp->jnl &&
+                       (cp->c_parentcnid == kRootDirID) &&
+                       ((cp->c_cnid == hfsmp->hfs_jnlfileid) ||
+                       (cp->c_cnid == hfsmp->hfs_jnlinfoblkid))) {
+                   retval = ENOENT;
+                       goto exit;
+               }
+        
                if (wantrsrc && rvp != NULL) {
                        vp = rvp;
                        rvp = NULL;
@@ -357,6 +410,7 @@ hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wa
        
                        cnattr.ca_fileid = kRootParID;
                        cnattr.ca_nlink = 2;
+                       cnattr.ca_entries = 1;
                        cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
                } else {
                        /* Lock catalog b-tree */
@@ -372,8 +426,9 @@ hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wa
                                goto exit;
        
                        /* Hide open files that have been deleted */
-                       if ((hfsmp->hfs_private_metadata_dir != 0) &&
-                               (cndesc.cd_parentcnid == hfsmp->hfs_private_metadata_dir)) {
+                       if ((hfsmp->hfs_privdir_desc.cd_cnid != 0) &&
+                           (cndesc.cd_parentcnid == hfsmp->hfs_privdir_desc.cd_cnid) &&
+                           (cnattr.ca_nlink == 0)) {
                                cat_releasedesc(&cndesc);
                                retval = ENOENT;
                                goto exit;
@@ -390,14 +445,16 @@ hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wa
                &&  cndesc.cd_namelen > 0) {
                        replace_desc(VTOC(new_vp), &cndesc);
                }
+
                cat_releasedesc(&cndesc);
        }
+
 exit:
        /* Release reference taken on opposite vnode (if any). */
        if (vp)
-               vput(vp);
+               vrele(vp);
        else if (rvp)
-               vput(rvp);
+               vrele(rvp);
 
        if (retval) {
                *vpp = NULL;
@@ -409,7 +466,8 @@ done:
        if (vp == NULL)
                panic("hfs_getcnode: missing vp!");
 
-       UBCINFOCHECK("hfs_getcnode", vp);
+       if (UBCISVALID(vp))
+               UBCINFOCHECK("hfs_getcnode", vp);
        *vpp = vp;
        return (0);
 }
@@ -442,12 +500,13 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
        int retval;
        dev_t dev;
        struct proc *p = current_proc();
-
+#if 0
        /* Bail when unmount is in progress */
        if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
                *vpp = NULL;
                return (EPERM);
        }
+#endif
 
 #if !FIFO
        if (IFTOVT(attrp->ca_mode) == VFIFO) {
@@ -466,6 +525,11 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
                SET(cp2->c_flag, C_ALLOC);
                cp2->c_cnid = descp->cd_cnid;
                cp2->c_fileid = attrp->ca_fileid;
+               if (cp2->c_fileid == 0) {
+                       FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE);
+                       *vpp = NULL;
+                       return (ENOENT);
+               }
                cp2->c_dev = dev;
                lockinit(&cp2->c_lock, PINOD, "cnode", 0, 0);
                (void) lockmgr(&cp2->c_lock, LK_EXCLUSIVE, (struct slock *)0, p);
@@ -524,9 +588,9 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
 
        /* Release reference taken on opposite vnode (if any). */
        if (rvp)
-               vput(rvp);
+               vrele(rvp);
        if (vp)
-               vput(vp);
+               vrele(vp);
 
        vp = new_vp;
        vp->v_ubcinfo = UBC_NOINFO;
@@ -568,9 +632,7 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
                bzero(fp, sizeof(struct filefork));
                fp->ff_cp = cp;
                if (forkp)
-                       bcopy(forkp, &fp->ff_data, sizeof(HFSPlusForkData));
-               if (fp->ff_clumpsize == 0)
-                       fp->ff_clumpsize = HFSTOVCB(hfsmp)->vcbClpSiz;
+                       bcopy(forkp, &fp->ff_data, sizeof(struct cat_fork));
                rl_init(&fp->ff_invalidranges);
                if (wantrsrc) {
                        if (cp->c_rsrcfork != NULL)
@@ -596,7 +658,7 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
        vp->v_type = IFTOVT(cp->c_mode);
 
        /* Tag system files */
-       if ((descp->cd_cnid < kHFSFirstUserCatalogNodeID) && (vp->v_type == VREG))
+       if ((descp->cd_flags & CD_ISMETA) && (vp->v_type == VREG))
                vp->v_flag |= VSYSTEM;
        /* Tag root directory */
        if (cp->c_cnid == kRootDirID)
@@ -637,6 +699,11 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
 #endif
        }
 
+       /*
+        * Stop tracking an active hot file.
+        */
+       (void) hfs_removehotfile(vp);
+
        /* Vnode is now initialized - see if anyone was waiting for it. */
        CLR(cp->c_flag, C_ALLOC);
        if (ISSET(cp->c_flag, C_WALLOC)) {