/*
- * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/kauth.h>
#include <sys/ubc.h>
+#include <sys/ubc_internal.h>
#include <sys/vnode_internal.h>
#include <sys/mount_internal.h>
#include <sys/sysctl.h>
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);
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);
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
*/
*
* 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;
{
struct cnode *cp;
struct hfs_reload_cargs *args;
+ int lockflags;
args = (struct hfs_reload_cargs *)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);
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));
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);
}
} 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 */
}
}
cnid_t nextlinkid;
cnid_t prevlinkid;
struct cat_desc linkdesc;
+ int lockflags;
cnattr.ca_linkref = linkref;
*/
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));
}
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);
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);
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;
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;
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;
}
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));