]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_vnops.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vnops.c
index 873ff095c7a850bea7b04a5e4ea0d1ebe7f76fb7..726dee5e0ff0e378e3dbb3fb0d83c83dee92dd57 100644 (file)
@@ -43,6 +43,7 @@
 #include <machine/spl.h>
 
 #include <sys/kdebug.h>
+#include <sys/sysctl.h>
 
 #include "hfs.h"
 #include "hfs_catalog.h"
@@ -65,6 +66,9 @@
 
 /* Global vfs data structures for hfs */
 
+/* Always F_FULLFSYNC? 1=yes,0=no (default due to "various" reasons is 'no') */
+int always_do_fullfsync = 0;
+SYSCTL_INT (_kern, OID_AUTO, always_do_fullfsync, CTLFLAG_RW, &always_do_fullfsync, 0, "always F_FULLFSYNC when fsync is called");
 
 extern unsigned long strtoul(const char *, char **, int);
 
@@ -101,8 +105,6 @@ static int hfs_vnop_setattr(struct vnop_setattr_args*);
 
 int hfs_write_access(struct vnode *vp, kauth_cred_t cred, struct proc *p, Boolean considerFlags);
 
-int hfs_chflags(struct vnode *vp, uint32_t flags, kauth_cred_t cred,
-                       struct proc *p);
 int hfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred,
                        struct proc *p);
 int hfs_chown(struct vnode *vp, uid_t uid, gid_t gid,
@@ -238,6 +240,7 @@ hfs_vnop_close(ap)
        if (hfsmp->hfs_freezing_proc == p && proc_exiting(p)) {
            hfsmp->hfs_freezing_proc = NULL;
            hfs_global_exclusive_lock_release(hfsmp);
+           lck_rw_unlock_exclusive(&hfsmp->hfs_insync);
        }
 
        busy = vnode_isinuse(vp, 1);
@@ -286,7 +289,7 @@ hfs_vnop_getattr(struct vnop_getattr_args *ap)
                        if (vnode_isvroot(vp)) {
                                if (hfsmp->hfs_privdir_desc.cd_cnid != 0)
                                        --entries;     /* hide private dir */
-                               if (hfsmp->jnl)
+                               if (hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))
                                        entries -= 2;  /* hide the journal files */
                        }
                        VATTR_RETURN(vap, va_nlink, (uint64_t)entries);
@@ -534,9 +537,10 @@ hfs_vnop_setattr(ap)
         * current securelevel are being changed.
         */
        VATTR_SET_SUPPORTED(vap, va_flags);
-       if (VATTR_IS_ACTIVE(vap, va_flags) &&
-           ((error = hfs_chflags(vp, vap->va_flags, cred, p)) != 0))
-           goto out;
+       if (VATTR_IS_ACTIVE(vap, va_flags)) {
+               cp->c_flags = vap->va_flags;
+               cp->c_touch_chgtime = TRUE;
+       }
 
        /*
         * If the file's extended security data is being changed, we
@@ -705,25 +709,6 @@ hfs_write_access(struct vnode *vp, kauth_cred_t cred, struct proc *p, Boolean co
 }
 
 
-
-/*
- * Change the flags on a file or directory.
- * cnode must be locked before calling.
- */
-__private_extern__
-int
-hfs_chflags(struct vnode *vp, uint32_t flags, __unused kauth_cred_t cred, __unused struct proc *p)
-{
-       register struct cnode *cp = VTOC(vp);
-
-       cp->c_flags &= SF_SETTABLE;
-       cp->c_flags |= (flags & UF_SETTABLE);
-       cp->c_touch_chgtime = TRUE;
-
-       return (0);
-}
-
-
 /*
  * Perform chown operation on cnode cp;
  * code must be locked prior to call.
@@ -982,6 +967,7 @@ hfs_vnop_exchange(ap)
        from_cp->c_uid = to_cp->c_uid;
        from_cp->c_flags = to_cp->c_flags;
        from_cp->c_mode = to_cp->c_mode;
+       from_cp->c_attr.ca_recflags = to_cp->c_attr.ca_recflags;
        bcopy(to_cp->c_finderinfo, from_cp->c_finderinfo, 32);
 
        bcopy(&tempdesc, &to_cp->c_desc, sizeof(struct cat_desc));
@@ -995,6 +981,7 @@ hfs_vnop_exchange(ap)
        to_cp->c_uid = tempattr.ca_uid;
        to_cp->c_flags = tempattr.ca_flags;
        to_cp->c_mode = tempattr.ca_mode;
+       to_cp->c_attr.ca_recflags = tempattr.ca_recflags;
        bcopy(tempattr.ca_finderinfo, to_cp->c_finderinfo, 32);
 
        /* Rehash the cnodes using their new file IDs */
@@ -1157,7 +1144,7 @@ metasync:
                cp->c_touch_acctime = FALSE;
                cp->c_touch_chgtime = FALSE;
                cp->c_touch_modtime = FALSE;
-       } else /* User file */ {
+       } else if ( !(vp->v_flag & VSWAP) ) /* User file */ {
                retval = hfs_update(vp, wait);
 
                /* When MNT_WAIT is requested push out any delayed meta data */
@@ -1170,7 +1157,7 @@ metasync:
                // fsync() and if so push out any pending transactions 
                // that this file might is a part of (and get them on
                // stable storage).
-               if (fullsync) {
+               if (fullsync || always_do_fullfsync) {
                    if (hfsmp->jnl) {
                        journal_flush(hfsmp->jnl);
                    } else {
@@ -1578,18 +1565,17 @@ hfs_removefile(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
        if ((cp->c_flag & C_HARDLINK) == 0 &&
            (!dataforkbusy || !rsrcforkbusy)) {
                /*
-                * A ubc_setsize can cause a pagein here 
-                * so we need to the drop cnode lock. Note
-                * that we still hold the truncate lock.
+                * A ubc_setsize can cause a pagein so defer it
+                * until after the cnode lock is dropped.  The
+                * cnode lock cannot be dropped/reacquired here
+                * since we might already hold the journal lock.
                 */
-               hfs_unlock(cp);
                if (!dataforkbusy && cp->c_datafork->ff_blocks && !isbigfile) {
-                       ubc_setsize(vp, 0);
+                       cp->c_flag |= C_NEED_DATA_SETSIZE;
                }
                if (!rsrcforkbusy && rvp) {
-                       ubc_setsize(rvp, 0);
+                       cp->c_flag |= C_NEED_RSRC_SETSIZE;
                }
-               hfs_lock(cp, HFS_FORCE_LOCK);
        } else {
            struct cat_desc cndesc;
 
@@ -1903,6 +1889,10 @@ out:
 __private_extern__ void
 replace_desc(struct cnode *cp, struct cat_desc *cdp)
 {
+       if (&cp->c_desc == cdp) {
+               return;
+       }
+
        /* First release allocated name buffer */
        if (cp->c_desc.cd_flags & CD_HASBUF && cp->c_desc.cd_nameptr != 0) {
                char *name = cp->c_desc.cd_nameptr;
@@ -2461,6 +2451,10 @@ hfs_vnop_readdir(ap)
        if (nfs_cookies) {
                cnid_hint = (cnid_t)(uio_offset(uio) >> 32);
                uio_setoffset(uio, uio_offset(uio) & 0x00000000ffffffffLL);
+               if (cnid_hint == INT_MAX) { /* searching pass the last item */
+                       eofflag = 1;
+                       goto out;
+               }
        }
        /*
         * Synthesize entries for "." and ".."
@@ -2565,7 +2559,7 @@ hfs_vnop_readdir(ap)
                        if ( localhint.dh_desc.cd_parentcnid == cp->c_cnid) {
                                localhint.dh_index = index - 1;
                                localhint.dh_time = 0;
-                               localhint.dh_link.sle_next = 0;
+                               bzero(&localhint.dh_link, sizeof(localhint.dh_link));
                                dirhint = &localhint;  /* don't forget to release the descriptor */
                        } else {
                                cat_releasedesc(&localhint.dh_desc);
@@ -2585,7 +2579,7 @@ hfs_vnop_readdir(ap)
        }
        
        /* Pack the buffer with dirent entries. */
-       error = cat_getdirentries(hfsmp, cp->c_entries, dirhint, uio, extended, &items);
+       error = cat_getdirentries(hfsmp, cp->c_entries, dirhint, uio, extended, &items, &eofflag);
 
        hfs_systemfile_unlock(hfsmp, lockflags);
 
@@ -2834,7 +2828,7 @@ hfs_update(struct vnode *vp, __unused int waitfor)
         * we have to do the update.
         */
        if (ISSET(cp->c_flag, C_FORCEUPDATE) == 0 &&
-           (ISSET(cp->c_flag, C_DELETED) || 
+           (ISSET(cp->c_flag, C_DELETED) ||
            (dataforkp && cp->c_datafork->ff_unallocblocks) ||
            (rsrcforkp && cp->c_rsrcfork->ff_unallocblocks))) {
        //      cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_UPDATE);
@@ -2948,6 +2942,9 @@ hfs_makenode(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
        }
        attr.ca_atime = attr.ca_ctime = attr.ca_itime = attr.ca_mtime;
        attr.ca_atimeondisk = attr.ca_atime;
+       /* On HFS+ the ThreadExists flag must always be set for files. */
+       if (vnodetype != VDIR && (hfsmp->hfs_flags & HFS_STANDARD) == 0)
+               attr.ca_recflags = kHFSThreadExistsMask;
 
        attr.ca_uid = vap->va_uid;
        attr.ca_gid = vap->va_gid;
@@ -3173,6 +3170,22 @@ hfs_vgetrsrc(struct hfsmount *hfsmp, struct vnode *vp, struct vnode **rvpp, __un
                struct componentname cn;
                int lockflags;
 
+               /*
+                * Make sure cnode lock is exclusive, if not upgrade it.
+                *
+                * We assume that we were called from a read-only VNOP (getattr)
+                * and that its safe to have the cnode lock dropped and reacquired.
+                */
+               if (cp->c_lockowner != current_thread()) {
+                       /*
+                        * If the upgrade fails we loose the lock and
+                        * have to take the exclusive lock on our own.
+                        */
+                       if (lck_rw_lock_shared_to_exclusive(&cp->c_rwlock) != 0)
+                               lck_rw_lock_exclusive(&cp->c_rwlock);
+                       cp->c_lockowner = current_thread();
+               }
+
                lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
 
                /* Get resource fork data */
@@ -3699,7 +3712,6 @@ struct vnodeopv_entry_desc hfs_specop_entries[] = {
        { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf },                /* pathconf */
        { &vnop_advlock_desc, (VOPFUNC)err_advlock },           /* advlock */
        { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite },
-       { &vnop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */
        { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein },                /* Pagein */
        { &vnop_pageout_desc, (VOPFUNC)hfs_vnop_pageout },      /* Pageout */
         { &vnop_copyfile_desc, (VOPFUNC)err_copyfile },                /* copyfile */