X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3903760236c30e3b5ace7a4eefac3a269d68957c..eb6b6ca394357805f2bdba989abae309f718b4d8:/bsd/miscfs/nullfs/null_vnops.c diff --git a/bsd/miscfs/nullfs/null_vnops.c b/bsd/miscfs/nullfs/null_vnops.c index 389adb7e4..6afadbfab 100644 --- a/bsd/miscfs/nullfs/null_vnops.c +++ b/bsd/miscfs/nullfs/null_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Apple Inc. All rights reserved. + * Copyright (c) 2019 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -179,14 +179,14 @@ nullfs_special_getattr(struct vnop_getattr_args * args) VATTR_RETURN(args->a_vap, va_filerev, 0); VATTR_RETURN(args->a_vap, va_gen, 0); VATTR_RETURN(args->a_vap, va_flags, UF_HIDDEN); /* mark our fake directories as hidden. People - shouldn't be enocouraged to poke around in them */ + * shouldn't be enocouraged to poke around in them */ if (ino == NULL_SECOND_INO) { VATTR_RETURN(args->a_vap, va_parentid, NULL_ROOT_INO); /* no parent at the root, so - the only other vnode that - goes through this path is - second and its parent is - 1.*/ + * the only other vnode that + * goes through this path is + * second and its parent is + * 1.*/ } if (VATTR_IS_ACTIVE(args->a_vap, va_mode)) { @@ -298,10 +298,10 @@ nullfs_close(struct vnop_close_args * args) } /* get lvp's parent, if possible, even if it isn't set. - - lvp is expected to have an iocount before and after this call. - - if a dvpp is populated the returned vnode has an iocount. */ + * + * lvp is expected to have an iocount before and after this call. + * + * if a dvpp is populated the returned vnode has an iocount. */ static int null_get_lowerparent(vnode_t lvp, vnode_t * dvpp, vfs_context_t ctx) { @@ -379,7 +379,6 @@ null_special_lookup(struct vnop_lookup_args * ap) error = vnode_get(vp); } } - } else if (dvp == null_mp->nullm_secondvp) { /* handle . and .. */ if (cnp->cn_nameptr[0] == '.') { @@ -397,21 +396,21 @@ null_special_lookup(struct vnop_lookup_args * ap) /* nullmp->nullm_lowerrootvp was set at mount time so don't need to lock to * access it */ /* v_name should be null terminated but cn_nameptr is not necessarily. - cn_namelen is the number of characters before the null in either case */ + * cn_namelen is the number of characters before the null in either case */ error = vnode_getwithvid(null_mp->nullm_lowerrootvp, null_mp->nullm_lowerrootvid); if (error) { goto end; } /* We don't want to mess with case insensitivity and unicode, so the plan to - check here is - 1. try to get the lower root's parent - 2. If we get a parent, then perform a lookup on the lower file system - using the parent and the passed in cnp - 3. If that worked and we got a vp, then see if the vp is lowerrootvp. If - so we got a match - 4. Anything else results in ENOENT. - */ + * check here is + * 1. try to get the lower root's parent + * 2. If we get a parent, then perform a lookup on the lower file system + * using the parent and the passed in cnp + * 3. If that worked and we got a vp, then see if the vp is lowerrootvp. If + * so we got a match + * 4. Anything else results in ENOENT. + */ error = null_get_lowerparent(null_mp->nullm_lowerrootvp, &ldvp, ap->a_context); if (error == 0) { @@ -464,7 +463,7 @@ null_lookup(struct vnop_lookup_args * ap) mp = vnode_mount(dvp); /* rename and delete are not allowed. this is a read only file system */ if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME || cnp->cn_nameiop == CREATE) { - return (EROFS); + return EROFS; } null_mp = MOUNTTONULLMOUNT(mp); @@ -530,7 +529,7 @@ notdot: vnode_put(lvp); } - return (error); + return error; } /* @@ -541,7 +540,7 @@ null_inactive(__unused struct vnop_inactive_args * ap) { NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp); - return (0); + return 0; } static int @@ -568,9 +567,9 @@ null_reclaim(struct vnop_reclaim_args * ap) * got hashed */ if (xp->null_flags & NULL_FLAG_HASHED) { /* only call this if we actually made it into the hash list. reclaim gets - called also to - clean up a vnode that got created when it didn't need to under race - conditions */ + * called also to + * clean up a vnode that got created when it didn't need to under race + * conditions */ null_hashrem(xp); } vnode_getwithref(lowervp); @@ -635,15 +634,15 @@ nullfs_special_readdir(struct vnop_readdir_args * ap) ino_t ino = 0; const char * name = NULL; - if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) - return (EINVAL); + if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) { + return EINVAL; + } if (offset == 0) { /* . case */ if (vp == null_mp->nullm_rootvp) { ino = NULL_ROOT_INO; - } else /* only get here if vp matches nullm_rootvp or nullm_secondvp */ - { + } else { /* only get here if vp matches nullm_rootvp or nullm_secondvp */ ino = NULL_SECOND_INO; } error = store_entry_special(ino, ".", uio); @@ -670,13 +669,12 @@ nullfs_special_readdir(struct vnop_readdir_args * ap) if (vp == null_mp->nullm_rootvp) { ino = NULL_SECOND_INO; name = "d"; - } else /* only get here if vp matches nullm_rootvp or nullm_secondvp */ - { + } else { /* only get here if vp matches nullm_rootvp or nullm_secondvp */ ino = NULL_THIRD_INO; if (vnode_getwithvid(null_mp->nullm_lowerrootvp, null_mp->nullm_lowerrootvid)) { /* In this case the lower file system has been ripped out from under us, - but we don't want to error out - Instead we just want d to look empty. */ + * but we don't want to error out + * Instead we just want d to look empty. */ error = 0; goto out; } @@ -699,7 +697,7 @@ nullfs_special_readdir(struct vnop_readdir_args * ap) out: if (error == EMSGSIZE) { error = 0; /* return success if we ran out of space, but we wanted to make - sure that we didn't update offset and items incorrectly */ + * sure that we didn't update offset and items incorrectly */ } uio_setoffset(uio, offset); if (ap->a_numdirent) { @@ -834,7 +832,7 @@ nullfs_getxattr(struct vnop_getxattr_args * args) NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp); if (nullfs_checkspecialvp(args->a_vp)) { - return 0; /* nothing extra needed */ + return ENOATTR; /* no xattrs on the special vnodes */ } vp = args->a_vp; @@ -857,7 +855,7 @@ nullfs_listxattr(struct vnop_listxattr_args * args) NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp); if (nullfs_checkspecialvp(args->a_vp)) { - return 0; /* nothing extra needed */ + return 0; /* no xattrs on the special vnodes */ } vp = args->a_vp; @@ -925,13 +923,12 @@ nullfs_pagein(struct vnop_pagein_args * ap) error = VNOP_READ(lvp, auio, ((ap->a_flags & UPL_IOSYNC) ? IO_SYNC : 0), ap->a_context); bytes_remaining = uio_resid(auio); - if (bytes_remaining > 0 && bytes_remaining <= (user_ssize_t)ap->a_size) - { + if (bytes_remaining > 0 && bytes_remaining <= (user_ssize_t)ap->a_size) { /* zero bytes that weren't read in to the upl */ bzero((void*)((uintptr_t)(ioaddr + ap->a_size - bytes_remaining)), (size_t) bytes_remaining); } - exit: +exit: kret = ubc_upl_unmap(upl); if (KERN_SUCCESS != kret) { panic("nullfs_pagein: ubc_upl_unmap() failed with (%d)", kret); @@ -941,16 +938,14 @@ nullfs_pagein(struct vnop_pagein_args * ap) uio_free(auio); } - exit_no_unmap: +exit_no_unmap: if ((ap->a_flags & UPL_NOCOMMIT) == 0) { if (!error && (bytes_remaining >= 0) && (bytes_remaining <= (user_ssize_t)ap->a_size)) { /* only commit what was read in (page aligned)*/ bytes_to_commit = ap->a_size - bytes_remaining; - if (bytes_to_commit) - { + if (bytes_to_commit) { /* need to make sure bytes_to_commit and byte_remaining are page aligned before calling ubc_upl_commit_range*/ - if (bytes_to_commit & PAGE_MASK) - { + if (bytes_to_commit & PAGE_MASK) { bytes_to_commit = (bytes_to_commit & (~PAGE_MASK)) + (PAGE_MASK + 1); assert(bytes_to_commit <= (off_t)ap->a_size); @@ -958,7 +953,7 @@ nullfs_pagein(struct vnop_pagein_args * ap) } ubc_upl_commit_range(upl, ap->a_pl_offset, (upl_size_t)bytes_to_commit, UPL_COMMIT_FREE_ON_EMPTY); } - + /* abort anything thats left */ if (bytes_remaining) { ubc_upl_abort_range(upl, ap->a_pl_offset + bytes_to_commit, (upl_size_t)bytes_remaining, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY); @@ -968,7 +963,7 @@ nullfs_pagein(struct vnop_pagein_args * ap) } } vnode_put(lvp); - } else if((ap->a_flags & UPL_NOCOMMIT) == 0) { + } else if ((ap->a_flags & UPL_NOCOMMIT) == 0) { ubc_upl_abort_range(ap->a_pl, ap->a_pl_offset, (upl_size_t)ap->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY); } return error; @@ -1012,7 +1007,7 @@ nullfs_read(struct vnop_read_args * ap) if (error) { NULLFSDEBUG("VNOP_READ failed: %d\n", error); } - end: +end: vnode_put(lvp); } return error; @@ -1022,16 +1017,49 @@ nullfs_read(struct vnop_read_args * ap) * Global vfs data structures */ -static struct vnodeopv_entry_desc nullfs_vnodeop_entries[] = { - {&vnop_default_desc, (vop_t)nullfs_default}, {&vnop_getattr_desc, (vop_t)nullfs_getattr}, - {&vnop_open_desc, (vop_t)nullfs_open}, {&vnop_close_desc, (vop_t)nullfs_close}, - {&vnop_inactive_desc, (vop_t)null_inactive}, {&vnop_reclaim_desc, (vop_t)null_reclaim}, - {&vnop_lookup_desc, (vop_t)null_lookup}, {&vnop_readdir_desc, (vop_t)nullfs_readdir}, - {&vnop_readlink_desc, (vop_t)nullfs_readlink}, {&vnop_pathconf_desc, (vop_t)nullfs_pathconf}, - {&vnop_fsync_desc, (vop_t)nullfs_fsync}, {&vnop_mmap_desc, (vop_t)nullfs_mmap}, - {&vnop_mnomap_desc, (vop_t)nullfs_mnomap}, {&vnop_getxattr_desc, (vop_t)nullfs_getxattr}, - {&vnop_pagein_desc, (vop_t)nullfs_pagein}, {&vnop_read_desc, (vop_t)nullfs_read}, - {&vnop_listxattr_desc, (vop_t)nullfs_listxattr}, {NULL, NULL}, +static const struct vnodeopv_entry_desc nullfs_vnodeop_entries[] = { + {.opve_op = &vnop_default_desc, .opve_impl = (vop_t)nullfs_default}, {.opve_op = &vnop_getattr_desc, .opve_impl = (vop_t)nullfs_getattr}, + {.opve_op = &vnop_open_desc, .opve_impl = (vop_t)nullfs_open}, {.opve_op = &vnop_close_desc, .opve_impl = (vop_t)nullfs_close}, + {.opve_op = &vnop_inactive_desc, .opve_impl = (vop_t)null_inactive}, {.opve_op = &vnop_reclaim_desc, .opve_impl = (vop_t)null_reclaim}, + {.opve_op = &vnop_lookup_desc, .opve_impl = (vop_t)null_lookup}, {.opve_op = &vnop_readdir_desc, .opve_impl = (vop_t)nullfs_readdir}, + {.opve_op = &vnop_readlink_desc, .opve_impl = (vop_t)nullfs_readlink}, {.opve_op = &vnop_pathconf_desc, .opve_impl = (vop_t)nullfs_pathconf}, + {.opve_op = &vnop_fsync_desc, .opve_impl = (vop_t)nullfs_fsync}, {.opve_op = &vnop_mmap_desc, .opve_impl = (vop_t)nullfs_mmap}, + {.opve_op = &vnop_mnomap_desc, .opve_impl = (vop_t)nullfs_mnomap}, {.opve_op = &vnop_getxattr_desc, .opve_impl = (vop_t)nullfs_getxattr}, + {.opve_op = &vnop_pagein_desc, .opve_impl = (vop_t)nullfs_pagein}, {.opve_op = &vnop_read_desc, .opve_impl = (vop_t)nullfs_read}, + {.opve_op = &vnop_listxattr_desc, .opve_impl = (vop_t)nullfs_listxattr}, {.opve_op = NULL, .opve_impl = NULL}, }; -struct vnodeopv_desc nullfs_vnodeop_opv_desc = {&nullfs_vnodeop_p, nullfs_vnodeop_entries}; +const struct vnodeopv_desc nullfs_vnodeop_opv_desc = {.opv_desc_vector_p = &nullfs_vnodeop_p, .opv_desc_ops = nullfs_vnodeop_entries}; + +//NULLFS Specific helper function + +int +nullfs_getbackingvnode(vnode_t in_vp, vnode_t* out_vpp) +{ + int result = EINVAL; + + if (out_vpp == NULL || in_vp == NULL) { + goto end; + } + + struct vfsstatfs * sp = NULL; + mount_t mp = vnode_mount(in_vp); + + sp = vfs_statfs(mp); + //If this isn't a nullfs vnode or it is but it's a special vnode + if (strcmp(sp->f_fstypename, "nullfs") != 0 || nullfs_checkspecialvp(in_vp)) { + *out_vpp = NULLVP; + result = ENOENT; + goto end; + } + + vnode_t lvp = NULLVPTOLOWERVP(in_vp); + if ((result = vnode_getwithvid(lvp, NULLVPTOLOWERVID(in_vp)))) { + goto end; + } + + *out_vpp = lvp; + +end: + return result; +}