X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..935ed37a5c468c8a1c07408573c08b8b7ef80e8b:/bsd/hfs/hfs_vfsops.c diff --git a/bsd/hfs/hfs_vfsops.c b/bsd/hfs/hfs_vfsops.c index d5a05045b..7b67b6686 100644 --- a/bsd/hfs/hfs_vfsops.c +++ b/bsd/hfs/hfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2007 Apple Inc. All rights reserved. + * Copyright (c) 1999-2008 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -75,6 +75,7 @@ #include #include +#include #include #include #include @@ -117,6 +118,9 @@ lck_grp_t * hfs_mutex_group; lck_grp_t * hfs_rwlock_group; extern struct vnodeopv_desc hfs_vnodeop_opv_desc; +/* not static so we can re-use in hfs_readwrite.c for build_path */ +int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context); + static int hfs_changefs(struct mount *mp, struct hfs_mount_args *args); static int hfs_fhtovp(struct mount *mp, int fhlen, unsigned char *fhp, struct vnode **vpp, vfs_context_t context); @@ -135,7 +139,6 @@ static int hfs_sync(struct mount *mp, int waitfor, vfs_context_t context); static int hfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, user_addr_t newp, size_t newlen, vfs_context_t context); static int hfs_unmount(struct mount *mp, int mntflags, vfs_context_t context); -static int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context); static int hfs_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, vfs_context_t context); static int hfs_reclaimspace(struct hfsmount *hfsmp, u_long startblk, u_long reclaimblks, vfs_context_t context); @@ -371,13 +374,18 @@ hfs_changefs_callback(struct vnode *vp, void *cargs) struct cat_desc cndesc; struct cat_attr cnattr; struct hfs_changefs_cargs *args; + int lockflags; + int error; args = (struct hfs_changefs_cargs *)cargs; cp = VTOC(vp); vcb = HFSTOVCB(args->hfsmp); - if (cat_lookup(args->hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL, NULL)) { + lockflags = hfs_systemfile_lock(args->hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); + error = cat_lookup(args->hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL, NULL); + hfs_systemfile_unlock(args->hfsmp, lockflags); + if (error) { /* * If we couldn't find this guy skip to the next one */ @@ -525,8 +533,9 @@ hfs_changefs(struct mount *mp, struct hfs_mount_args *args) * * hfs_changefs_callback will be called for each vnode * hung off of this mount point - * the vnode will be - * properly referenced and unreferenced around the callback + * + * The vnode will be properly referenced and unreferenced + * around the callback */ cargs.hfsmp = hfsmp; cargs.namefix = namefix; @@ -560,6 +569,7 @@ hfs_reload_callback(struct vnode *vp, void *cargs) { struct cnode *cp; struct hfs_reload_cargs *args; + int lockflags; args = (struct hfs_reload_cargs *)cargs; /* @@ -584,8 +594,12 @@ hfs_reload_callback(struct vnode *vp, void *cargs) datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL; /* lookup by fileID since name could have changed */ - if ((args->error = cat_idlookup(args->hfsmp, cp->c_fileid, 0, &desc, &cp->c_attr, datafork))) + lockflags = hfs_systemfile_lock(args->hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); + args->error = cat_idlookup(args->hfsmp, cp->c_fileid, 0, &desc, &cp->c_attr, datafork); + hfs_systemfile_unlock(args->hfsmp, lockflags); + if (args->error) { return (VNODE_RETURNED_DONE); + } /* update cnode's catalog descriptor */ (void) replace_desc(cp, &desc); @@ -1608,7 +1622,7 @@ hfs_statfs(struct mount *mp, register struct vfsstatfs *sbp, __unused vfs_contex freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID; sbp->f_bsize = (u_int32_t)vcb->blockSize; - sbp->f_iosize = (size_t)(MAX_UPL_TRANSFER * PAGE_SIZE); + sbp->f_iosize = (size_t)cluster_max_io_size(mp, 0); sbp->f_blocks = (u_int64_t)((unsigned long)vcb->totalBlocks); sbp->f_bfree = (u_int64_t)((unsigned long )hfs_freeblks(hfsmp, 0)); sbp->f_bavail = (u_int64_t)((unsigned long )hfs_freeblks(hfsmp, 1)); @@ -2275,33 +2289,48 @@ hfs_sysctl(int *name, __unused u_int namelen, user_addr_t oldp, size_t *oldlenp, return (ENOTSUP); } - -static int +/* hfs_vfs_vget is not static since it is used in hfs_readwrite.c to support the + * build_path ioctl. We use it to leverage the code below that updates the origin + * cache if necessary. + */ +int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context) { int error; + int lockflags; + struct hfsmount *hfsmp; + + hfsmp = VFSTOHFS(mp); - error = hfs_vget(VFSTOHFS(mp), (cnid_t)ino, vpp, 1); + error = hfs_vget(hfsmp, (cnid_t)ino, vpp, 1); if (error) return (error); /* * ADLs may need to have their origin state updated - * since build_path needs a valid parent. + * since build_path needs a valid parent. The same is true + * for hardlinked files as well. There isn't a race window here in re-acquiring + * the cnode lock since we aren't pulling any data out of the cnode; instead, we're + * going back to the catalog. */ - if (vnode_isdir(*vpp) && - (VTOC(*vpp)->c_flag & C_HARDLINK) && + if ((VTOC(*vpp)->c_flag & C_HARDLINK) && (hfs_lock(VTOC(*vpp), HFS_EXCLUSIVE_LOCK) == 0)) { cnode_t *cp = VTOC(*vpp); struct cat_desc cdesc; - if (!hfs_haslinkorigin(cp) && - (cat_findname(VFSTOHFS(mp), (cnid_t)ino, &cdesc) == 0)) { - if (cdesc.cd_parentcnid != - VFSTOHFS(mp)->hfs_private_desc[DIR_HARDLINKS].cd_cnid) { - hfs_savelinkorigin(cp, cdesc.cd_parentcnid); + if (!hfs_haslinkorigin(cp)) { + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); + error = cat_findname(hfsmp, (cnid_t)ino, &cdesc); + hfs_systemfile_unlock(hfsmp, lockflags); + if (error == 0) { + if ((cdesc.cd_parentcnid != + hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) && + (cdesc.cd_parentcnid != + hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid)) { + hfs_savelinkorigin(cp, cdesc.cd_parentcnid); + } + cat_releasedesc(&cdesc); } - cat_releasedesc(&cdesc); } hfs_unlock(cp); } @@ -2398,6 +2427,7 @@ hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock) } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) && (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) { *vpp = NULL; + cat_releasedesc(&cndesc); return (ENOENT); /* open unlinked file */ } } @@ -2411,6 +2441,7 @@ hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock) cnid_t nextlinkid; cnid_t prevlinkid; struct cat_desc linkdesc; + int lockflags; cnattr.ca_linkref = linkref; @@ -2420,7 +2451,10 @@ hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock) */ if ((hfs_lookuplink(hfsmp, linkref, &prevlinkid, &nextlinkid) == 0) && (nextlinkid != 0)) { - if (cat_findname(hfsmp, nextlinkid, &linkdesc) == 0) { + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); + error = cat_findname(hfsmp, nextlinkid, &linkdesc); + hfs_systemfile_unlock(hfsmp, lockflags); + if (error == 0) { cat_releasedesc(&cndesc); bcopy(&linkdesc, &cndesc, sizeof(linkdesc)); } @@ -2450,7 +2484,7 @@ hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock) error = hfs_getnewvnode(hfsmp, NULLVP, &cn, &cndesc, 0, &cnattr, &cnfork, &vp); - if (error == 0 && (VTOC(vp)->c_flag & C_HARDLINK) && vnode_isdir(vp)) { + if ((error == 0) && (VTOC(vp)->c_flag & C_HARDLINK)) { hfs_savelinkorigin(VTOC(vp), cndesc.cd_parentcnid); } FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI); @@ -3313,6 +3347,12 @@ out: VTOC(vp)->c_blocks = fp->ff_blocks; } + /* + Regardless of whether or not the totalblocks actually increased, + we should reset the allocLimit field. If it changed, it will + get updated; if not, it will remain the same. + */ + hfsmp->allocLimit = vcb->totalBlocks; hfs_systemfile_unlock(hfsmp, lockflags); hfs_end_transaction(hfsmp); @@ -4026,6 +4066,7 @@ hfs_reclaim_journal_file(struct hfsmount *hfsmp, vfs_context_t context) journal_fork.cf_extents[0].blockCount = newBlockCount; journal_fork.cf_blocks = newBlockCount; error = cat_update(hfsmp, &journal_desc, &journal_attr, &journal_fork, NULL); + cat_releasedesc(&journal_desc); /* all done with cat descriptor */ if (error) { printf("hfs_reclaim_journal_file: cat_update returned %d\n", error); goto free_fail; @@ -4140,6 +4181,7 @@ hfs_reclaim_journal_info_block(struct hfsmount *hfsmp, vfs_context_t context) jib_fork.cf_extents[0].blockCount = 1; jib_fork.cf_blocks = 1; error = cat_update(hfsmp, &jib_desc, &jib_attr, &jib_fork, NULL); + cat_releasedesc(&jib_desc); /* all done with cat descriptor */ if (error) { printf("hfs_reclaim_journal_info_block: cat_update returned %d\n", error); goto fail; @@ -4409,7 +4451,7 @@ end_iteration: if (error) break; error = hfs_relocate(rvp, hfsmp->hfs_metazone_end + 1, kauth_cred_get(), current_proc()); - vnode_put(rvp); + VTOC(rvp)->c_flag |= C_NEED_RVNODE_PUT; if (error) break; } @@ -4556,7 +4598,7 @@ hfs_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, __unused vfs_context_t VFSATTR_RETURN(fsap, f_filecount, (u_int64_t)hfsmp->vcbFilCnt); VFSATTR_RETURN(fsap, f_dircount, (u_int64_t)hfsmp->vcbDirCnt); VFSATTR_RETURN(fsap, f_maxobjcount, (u_int64_t)0xFFFFFFFF); - VFSATTR_RETURN(fsap, f_iosize, (size_t)(MAX_UPL_TRANSFER * PAGE_SIZE)); + VFSATTR_RETURN(fsap, f_iosize, (size_t)cluster_max_io_size(mp, 0)); VFSATTR_RETURN(fsap, f_blocks, (u_int64_t)hfsmp->totalBlocks); VFSATTR_RETURN(fsap, f_bfree, (u_int64_t)hfs_freeblks(hfsmp, 0)); VFSATTR_RETURN(fsap, f_bavail, (u_int64_t)hfs_freeblks(hfsmp, 1));