X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..3e170ce000f1506b7b5d2c5c7faec85ceabb573d:/bsd/miscfs/devfs/devfs_vnops.c?ds=sidebyside diff --git a/bsd/miscfs/devfs/devfs_vnops.c b/bsd/miscfs/devfs/devfs_vnops.c index bf7f11047..207a50c01 100644 --- a/bsd/miscfs/devfs/devfs_vnops.c +++ b/bsd/miscfs/devfs/devfs_vnops.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, unlawful or unlicensed copies of an Apple operating - * system, or to circumvent, violate, or enable the circumvention or - * violation of, any terms of an Apple operating system software license - * agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright 1997,1998 Julian Elischer. All rights reserved. @@ -74,6 +72,12 @@ * Dieter Siegmund (dieter@apple.com) Fri Sep 17 09:58:38 PDT 1999 * - update the mod/access times */ +/* + * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ #include #include @@ -95,10 +99,90 @@ #include #include +#if CONFIG_MACF +#include +#endif + #include "devfsdefs.h" +#include "devfs.h" + +#if FDESC +#include "fdesc.h" +#endif /* FDESC */ + +static int devfs_update(struct vnode *vp, struct timeval *access, + struct timeval *modify); +void devfs_rele_node(devnode_t *); +static void devfs_consider_time_update(devnode_t *dnp, uint32_t just_changed_flags); +static boolean_t devfs_update_needed(long now_s, long last_s); +void dn_times_locked(devnode_t * dnp, struct timeval *t1, struct timeval *t2, struct timeval *t3, uint32_t just_changed_flags); +void dn_times_now(devnode_t *dnp, uint32_t just_changed_flags); +void dn_mark_for_delayed_times_update(devnode_t *dnp, uint32_t just_changed_flags); + +void +dn_times_locked(devnode_t * dnp, struct timeval *t1, struct timeval *t2, struct timeval *t3, uint32_t just_changed_flags) +{ + + lck_mtx_assert(&devfs_attr_mutex, LCK_MTX_ASSERT_OWNED); + + if (just_changed_flags & DEVFS_UPDATE_ACCESS) { + dnp->dn_atime.tv_sec = t1->tv_sec; + dnp->dn_atime.tv_nsec = t1->tv_usec * 1000; + dnp->dn_access = 0; + } else if (dnp->dn_access) { + dnp->dn_atime.tv_sec = MIN(t1->tv_sec, dnp->dn_atime.tv_sec + DEVFS_LAZY_UPDATE_SECONDS); + dnp->dn_atime.tv_nsec = t1->tv_usec * 1000; + dnp->dn_access = 0; + } + + if (just_changed_flags & DEVFS_UPDATE_MOD) { + dnp->dn_mtime.tv_sec = t2->tv_sec; + dnp->dn_mtime.tv_nsec = t2->tv_usec * 1000; + dnp->dn_update = 0; + } else if (dnp->dn_update) { + dnp->dn_mtime.tv_sec = MIN(t2->tv_sec, dnp->dn_mtime.tv_sec + DEVFS_LAZY_UPDATE_SECONDS); + dnp->dn_mtime.tv_nsec = t2->tv_usec * 1000; + dnp->dn_update = 0; + } + + if (just_changed_flags & DEVFS_UPDATE_CHANGE) { + dnp->dn_ctime.tv_sec = t3->tv_sec; + dnp->dn_ctime.tv_nsec = t3->tv_usec * 1000; + dnp->dn_change = 0; + } else if (dnp->dn_change) { + dnp->dn_ctime.tv_sec = MIN(t3->tv_sec, dnp->dn_ctime.tv_sec + DEVFS_LAZY_UPDATE_SECONDS); + dnp->dn_ctime.tv_nsec = t3->tv_usec * 1000; + dnp->dn_change = 0; + } +} + +void +dn_mark_for_delayed_times_update(devnode_t *dnp, uint32_t just_changed_flags) +{ + if (just_changed_flags & DEVFS_UPDATE_CHANGE) { + dnp->dn_change = 1; + } + if (just_changed_flags & DEVFS_UPDATE_ACCESS) { + dnp->dn_access = 1; + } + if (just_changed_flags & DEVFS_UPDATE_MOD) { + dnp->dn_update = 1; + } +} + +/* + * Update times based on pending updates and optionally a set of new changes. + */ +void +dn_times_now(devnode_t * dnp, uint32_t just_changed_flags) +{ + struct timeval now; -static int devfs_update(struct vnode *vp, struct timeval *access, - struct timeval *modify); + DEVFS_ATTR_LOCK_SPIN(); + microtime(&now); + dn_times_locked(dnp, &now, &now, &now, just_changed_flags); + DEVFS_ATTR_UNLOCK(); +} /* @@ -165,8 +249,7 @@ retry: *result_vnode = NULL; /* safe not sorry */ /*XXX*/ - //if (dir_vnode->v_usecount == 0) - //printf("devfs_lookup: dir had no refs "); + /* okay to look at directory vnodes ourside devfs lock as they are not aliased */ dir_node = VTODN(dir_vnode); /* @@ -336,27 +419,32 @@ devfs_getattr(struct vnop_getattr_args *ap) devnode_t * file_node; struct timeval now; - file_node = VTODN(vp); DEVFS_LOCK(); - - microtime(&now); - dn_times(file_node, &now, &now, &now); + file_node = VTODN(vp); VATTR_RETURN(vap, va_mode, file_node->dn_mode); + /* + * Note: for DEV_CDEV and DEV_BDEV, we return the device from + * the vp, not the file_node; if we getting information on a + * cloning device, we want the cloned information, not the template. + */ switch (file_node->dn_type) { case DEV_DIR: - VATTR_RETURN(vap, va_rdev, (dev_t)file_node->dn_dvm); +#if FDESC + case DEV_DEVFD: /* Like a directory */ +#endif /* FDESC */ + VATTR_RETURN(vap, va_rdev, 0); vap->va_mode |= (S_IFDIR); break; case DEV_CDEV: - VATTR_RETURN(vap, va_rdev, file_node->dn_typeinfo.dev); + VATTR_RETURN(vap, va_rdev, vp->v_rdev); vap->va_mode |= (S_IFCHR); break; case DEV_BDEV: - VATTR_RETURN(vap, va_rdev, file_node->dn_typeinfo.dev); + VATTR_RETURN(vap, va_rdev, vp->v_rdev); vap->va_mode |= (S_IFBLK); break; case DEV_SLNK: @@ -371,7 +459,7 @@ devfs_getattr(struct vnop_getattr_args *ap) VATTR_RETURN(vap, va_uid, file_node->dn_uid); VATTR_RETURN(vap, va_gid, file_node->dn_gid); VATTR_RETURN(vap, va_fsid, (uintptr_t)file_node->dn_dvm); - VATTR_RETURN(vap, va_fileid, (uintptr_t)file_node); + VATTR_RETURN(vap, va_fileid, (uintptr_t)file_node->dn_ino); VATTR_RETURN(vap, va_data_size, file_node->dn_len); /* return an override block size (advisory) */ @@ -381,6 +469,13 @@ devfs_getattr(struct vnop_getattr_args *ap) VATTR_RETURN(vap, va_iosize, MAXPHYSIO); else VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize); + + + DEVFS_ATTR_LOCK_SPIN(); + + microtime(&now); + dn_times_locked(file_node, &now, &now, &now, 0); + /* if the time is bogus, set it to the boot time */ if (file_node->dn_ctime.tv_sec == 0) { file_node->dn_ctime.tv_sec = boottime_sec(); @@ -393,11 +488,20 @@ devfs_getattr(struct vnop_getattr_args *ap) VATTR_RETURN(vap, va_change_time, file_node->dn_ctime); VATTR_RETURN(vap, va_modify_time, file_node->dn_mtime); VATTR_RETURN(vap, va_access_time, file_node->dn_atime); + + DEVFS_ATTR_UNLOCK(); + VATTR_RETURN(vap, va_gen, 0); - VATTR_RETURN(vap, va_flags, 0); VATTR_RETURN(vap, va_filerev, 0); VATTR_RETURN(vap, va_acl, NULL); + /* Hide the root so Finder doesn't display it */ + if (vnode_isvroot(vp)) { + VATTR_RETURN(vap, va_flags, UF_HIDDEN); + } else { + VATTR_RETURN(vap, va_flags, 0); + } + DEVFS_UNLOCK(); return 0; @@ -413,15 +517,13 @@ devfs_setattr(struct vnop_setattr_args *ap) { struct vnode *vp = ap->a_vp; struct vnode_attr *vap = ap->a_vap; - kauth_cred_t cred = vfs_context_ucred(ap->a_context); - struct proc *p = vfs_context_proc(ap->a_context); int error = 0; devnode_t * file_node; struct timeval atimeval, mtimeval; - file_node = VTODN(vp); - DEVFS_LOCK(); + + file_node = VTODN(vp); /* * Go through the fields and update if set. */ @@ -473,6 +575,29 @@ devfs_setattr(struct vnop_setattr_args *ap) return error; } +#if CONFIG_MACF +static int +devfs_setlabel(struct vnop_setlabel_args *ap) + /* struct vnop_setlabel_args { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + struct label *a_vl; + vfs_context_t a_context; + } */ +{ + struct vnode *vp; + struct devnode *de; + + vp = ap->a_vp; + de = VTODN(vp); + + mac_vnode_label_update(ap->a_context, vp, ap->a_vl); + mac_devfs_label_update(vp->v_mount, de, vp); + + return (0); +} +#endif + static int devfs_read(struct vnop_read_args *ap) /* struct vnop_read_args { @@ -508,13 +633,12 @@ devfs_close(struct vnop_close_args *ap) } */ { struct vnode * vp = ap->a_vp; - register devnode_t * dnp = VTODN(vp); - struct timeval now; + register devnode_t * dnp; if (vnode_isinuse(vp, 1)) { DEVFS_LOCK(); - microtime(&now); - dn_times(dnp, &now, &now, &now); + dnp = VTODN(vp); + dn_times_now(dnp, 0); DEVFS_UNLOCK(); } return (0); @@ -529,18 +653,69 @@ devfsspec_close(struct vnop_close_args *ap) } */ { struct vnode * vp = ap->a_vp; - register devnode_t * dnp = VTODN(vp); - struct timeval now; + register devnode_t * dnp; - if (vnode_isinuse(vp, 1)) { + if (vnode_isinuse(vp, 0)) { DEVFS_LOCK(); - microtime(&now); - dn_times(dnp, &now, &now, &now); + dnp = VTODN(vp); + dn_times_now(dnp, 0); DEVFS_UNLOCK(); } + return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap)); } +static boolean_t +devfs_update_needed(long now_s, long last_s) +{ + if (now_s > last_s) { + if (now_s - last_s >= DEVFS_LAZY_UPDATE_SECONDS) { + return TRUE; + } + } + + return FALSE; +} + +/* + * Given a set of time updates required [to happen at some point], check + * either make those changes (and resolve other pending updates) or mark + * the devnode for a subsequent update. + */ +static void +devfs_consider_time_update(devnode_t *dnp, uint32_t just_changed_flags) +{ + struct timeval now; + long now_s; + + microtime(&now); + now_s = now.tv_sec; + + if (dnp->dn_change || (just_changed_flags & DEVFS_UPDATE_CHANGE)) { + if (devfs_update_needed(now_s, dnp->dn_ctime.tv_sec)) { + dn_times_now(dnp, just_changed_flags); + return; + } + } + if (dnp->dn_access || (just_changed_flags & DEVFS_UPDATE_ACCESS)) { + if (devfs_update_needed(now_s, dnp->dn_atime.tv_sec)) { + dn_times_now(dnp, just_changed_flags); + return; + } + } + if (dnp->dn_update || (just_changed_flags & DEVFS_UPDATE_MOD)) { + if (devfs_update_needed(now_s, dnp->dn_mtime.tv_sec)) { + dn_times_now(dnp, just_changed_flags); + return; + } + } + + /* Not going to do anything now--mark for later update */ + dn_mark_for_delayed_times_update(dnp, just_changed_flags); + + return; +} + static int devfsspec_read(struct vnop_read_args *ap) /* struct vnop_read_args { @@ -552,7 +727,7 @@ devfsspec_read(struct vnop_read_args *ap) { register devnode_t * dnp = VTODN(ap->a_vp); - dnp->dn_access = 1; + devfs_consider_time_update(dnp, DEVFS_UPDATE_ACCESS); return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap)); } @@ -568,8 +743,7 @@ devfsspec_write(struct vnop_write_args *ap) { register devnode_t * dnp = VTODN(ap->a_vp); - dnp->dn_change = 1; - dnp->dn_update = 1; + devfs_consider_time_update(dnp, DEVFS_UPDATE_CHANGE | DEVFS_UPDATE_MOD); return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap)); } @@ -596,8 +770,12 @@ devfs_write(struct vnop_write_args *ap) return 0; /* not reached */ } +/* + * Deviates from UFS naming convention because there is a KPI function + * called devfs_remove(). + */ static int -devfs_remove(struct vnop_remove_args *ap) +devfs_vnop_remove(struct vnop_remove_args *ap) /* struct vnop_remove_args { struct vnode *a_dvp; struct vnode *a_vp; @@ -607,23 +785,22 @@ devfs_remove(struct vnop_remove_args *ap) struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; devnode_t * tp; devnode_t * tdp; devdirent_t * tnp; int doingdirectory = 0; int error = 0; - uid_t ouruid = kauth_cred_getuid(vfs_context_ucred(ctx)); /* * assume that the name is null terminated as they * are the end of the path. Get pointers to all our * devfs structures. */ + DEVFS_LOCK(); + tp = VTODN(vp); tdp = VTODN(dvp); - DEVFS_LOCK(); tnp = dev_findname(tdp, cnp->cn_nameptr); @@ -650,8 +827,7 @@ devfs_remove(struct vnop_remove_args *ap) /*********************************** * Start actually doing things.... * ***********************************/ - tdp->dn_change = 1; - tdp->dn_update = 1; + devfs_consider_time_update(tdp, DEVFS_UPDATE_CHANGE | DEVFS_UPDATE_MOD); /* * Target must be empty if a directory and have no links @@ -687,7 +863,6 @@ devfs_link(struct vnop_link_args *ap) devnode_t * tdp; devdirent_t * tnp; int error = 0; - struct timeval now; /* * First catch an arbitrary restriction for this FS @@ -703,22 +878,20 @@ devfs_link(struct vnop_link_args *ap) * are the end of the path. Get pointers to all our * devfs structures. */ + /* can lookup dnode safely for tdvp outside of devfs lock as it is not aliased */ tdp = VTODN(tdvp); - fp = VTODN(vp); if (tdvp->v_mount != vp->v_mount) { return (EXDEV); } DEVFS_LOCK(); + fp = VTODN(vp); /*********************************** * Start actually doing things.... * ***********************************/ - fp->dn_change = 1; - - microtime(&now); - error = devfs_update(vp, &now, &now); + dn_times_now(fp, DEVFS_UPDATE_CHANGE); if (!error) { error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp); @@ -778,7 +951,6 @@ devfs_rename(struct vnop_rename_args *ap) devdirent_t *fnp,*tnp; int doingdirectory = 0; int error = 0; - struct timeval now; DEVFS_LOCK(); /* @@ -859,12 +1031,8 @@ devfs_rename(struct vnop_rename_args *ap) /*********************************** * Start actually doing things.... * ***********************************/ - fp->dn_change = 1; - microtime(&now); + dn_times_now(fp, DEVFS_UPDATE_CHANGE); - if ( (error = devfs_update(fvp, &now, &now)) ) { - goto out; - } /* * Check if just deleting a link name. */ @@ -890,7 +1058,6 @@ devfs_rename(struct vnop_rename_args *ap) * We could do that as well but won't */ if (tp) { - int ouruid = kauth_cred_getuid(vfs_context_ucred(tcnp->cn_context)); /* * Target must be empty if a directory and have no links * to it. Also, ensure source and target are compatible @@ -916,13 +1083,12 @@ out: } static int -devfs_symlink(struct vnop_symlink_args *ap) - /*struct vnop_symlink_args { +devfs_mkdir(struct vnop_mkdir_args *ap) + /*struct vnop_mkdir_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; - char *a_target; vfs_context_t a_context; } */ { @@ -931,19 +1097,16 @@ devfs_symlink(struct vnop_symlink_args *ap) struct proc *p = vfs_context_proc(ctx); int error = 0; devnode_t * dir_p; - devnode_type_t typeinfo; devdirent_t * nm_p; devnode_t * dev_p; struct vnode_attr * vap = ap->a_vap; struct vnode * * vpp = ap->a_vpp; - dir_p = VTODN(ap->a_dvp); - typeinfo.Slnk.name = ap->a_target; - typeinfo.Slnk.namelen = strlen(ap->a_target); - DEVFS_LOCK(); - error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK, - &typeinfo, NULL, NULL, &nm_p); + + dir_p = VTODN(ap->a_dvp); + error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_DIR, + NULL, NULL, NULL, &nm_p); if (error) { goto failure; } @@ -960,6 +1123,91 @@ failure: return error; } +/* + * An rmdir is a special type of remove, which we already support; we wrap + * and reexpress the arguments to call devfs_remove directly. The only + * different argument is flags, which we do not set, since it's ignored. + */ +static int +devfs_rmdir(struct vnop_rmdir_args *ap) + /* struct vnop_rmdir_args { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + vfs_context_t a_context; + } */ +{ + struct vnop_remove_args ra; + + ra.a_dvp = ap->a_dvp; + ra.a_vp = ap->a_vp; + ra.a_cnp = ap->a_cnp; + ra.a_flags = 0; /* XXX */ + ra.a_context = ap->a_context; + + return devfs_vnop_remove(&ra); +} + + +static int +devfs_symlink(struct vnop_symlink_args *ap) + /*struct vnop_symlink_args { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vnode_attr *a_vap; + char *a_target; + vfs_context_t a_context; + } */ +{ + int error; + devdirent_t *newent; + + DEVFS_LOCK(); + error = devfs_make_symlink(VTODN(ap->a_dvp), ap->a_cnp->cn_nameptr, ap->a_vap->va_mode, ap->a_target, &newent); + + if (error == 0) { + error = devfs_dntovn(newent->de_dnp, ap->a_vpp, vfs_context_proc(ap->a_context)); + } + + DEVFS_UNLOCK(); + + return error; + +} + +/* Called with devfs locked */ +int +devfs_make_symlink(devnode_t *dir_p, char *name, int mode, char *target, devdirent_t **newent) +{ + int error = 0; + devnode_type_t typeinfo; + devdirent_t * nm_p; + devnode_t * dev_p; + + typeinfo.Slnk.name = target; + typeinfo.Slnk.namelen = strlen(target); + + error = dev_add_entry(name, dir_p, DEV_SLNK, + &typeinfo, NULL, NULL, &nm_p); + if (error) { + goto failure; + } + dev_p = nm_p->de_dnp; + dev_p->dn_uid = dir_p->dn_uid; + dev_p->dn_gid = dir_p->dn_gid; + dev_p->dn_mode = mode; + dn_copy_times(dev_p, dir_p); + + if (newent) { + *newent = nm_p; + } + +failure: + + return error; +} + /* * Mknod vnode call */ @@ -989,10 +1237,12 @@ devfs_mknod(struct vnop_mknod_args *ap) if (!(vap->va_type == VBLK) && !(vap->va_type == VCHR)) { return (EINVAL); /* only support mknod of special files */ } - dir_p = VTODN(dvp); typeinfo.dev = vap->va_rdev; DEVFS_LOCK(); + + dir_p = VTODN(dvp); + error = dev_add_entry(cnp->cn_nameptr, dir_p, (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV, &typeinfo, NULL, NULL, &devent); @@ -1034,7 +1284,7 @@ devfs_readdir(struct vnop_readdir_args *ap) struct dirent dirent; devnode_t * dir_node; devdirent_t * name_node; - char *name; + const char *name; int error = 0; int reclen; int nodenumber; @@ -1055,30 +1305,27 @@ devfs_readdir(struct vnop_readdir_args *ap) name_node = dir_node->dn_typeinfo.Dir.dirlist; nodenumber = 0; - dir_node->dn_access = 1; - while ((name_node || (nodenumber < 2)) && (uio_resid(uio) > 0)) { switch(nodenumber) { case 0: - dirent.d_fileno = (int32_t)(void *)dir_node; + dirent.d_fileno = dir_node->dn_ino; name = "."; dirent.d_namlen = 1; dirent.d_type = DT_DIR; break; case 1: if(dir_node->dn_typeinfo.Dir.parent) - dirent.d_fileno - = (int32_t)dir_node->dn_typeinfo.Dir.parent; + dirent.d_fileno = dir_node->dn_typeinfo.Dir.parent->dn_ino; else - dirent.d_fileno = (u_int32_t)dir_node; + dirent.d_fileno = dir_node->dn_ino; name = ".."; dirent.d_namlen = 2; dirent.d_type = DT_DIR; break; default: - dirent.d_fileno = (int32_t)(void *)name_node->de_dnp; + dirent.d_fileno = name_node->de_dnp->dn_ino; dirent.d_namlen = strlen(name_node->de_name); name = name_node->de_name; switch(name_node->de_dnp->dn_type) { @@ -1107,7 +1354,7 @@ devfs_readdir(struct vnop_readdir_args *ap) { if (uio_resid(uio) < reclen) /* will it fit? */ break; - strcpy( dirent.d_name,name); + strlcpy(dirent.d_name, name, DEVMAXNAMESIZE); if ((error = uiomove ((caddr_t)&dirent, dirent.d_reclen, uio)) != 0) break; @@ -1120,6 +1367,8 @@ devfs_readdir(struct vnop_readdir_args *ap) DEVFS_UNLOCK(); uio->uio_offset = pos; + devfs_consider_time_update(dir_node, DEVFS_UPDATE_ACCESS); + return (error); } @@ -1159,21 +1408,19 @@ devfs_reclaim(struct vnop_reclaim_args *ap) } */ { struct vnode * vp = ap->a_vp; - devnode_t * dnp = VTODN(vp); + devnode_t * dnp; DEVFS_LOCK(); + dnp = VTODN(vp); + if (dnp) { - /* - * do the same as devfs_inactive in case it is not called - * before us (can that ever happen?) - */ + /* If this is a cloning device, it didn't have a dn_vn anyway */ dnp->dn_vn = NULL; - vp->v_data = NULL; + vnode_clearfsnode(vp); - if (dnp->dn_delete) { - devnode_free(dnp); - } + /* This could delete the node, if we are the last vnode */ + devfs_rele_node(dnp); } DEVFS_UNLOCK(); @@ -1205,7 +1452,7 @@ devs_vnop_pathconf( *ap->a_retval = DEVMAXPATHSIZE - 1; /* XXX nonconformant */ break; case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; + *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ break; case _PC_NO_TRUNC: *ap->a_retval = 0; @@ -1240,7 +1487,18 @@ devs_vnop_pathconf( static int devfs_inactive(__unused struct vnop_inactive_args *ap) { - return (0); + vnode_t vp = ap->a_vp; + devnode_t *dnp = VTODN(vp); + + /* + * Cloned vnodes are not linked in anywhere, so they + * can just be recycled. + */ + if (dnp->dn_clone != NULL) { + vnode_recycle(vp); + } + + return (0); } /* @@ -1260,8 +1518,11 @@ devfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify) return (0); } + + DEVFS_ATTR_LOCK_SPIN(); microtime(&now); - dn_times(ip, access, modify, &now); + dn_times_locked(ip, access, modify, &now, DEVFS_UPDATE_ACCESS | DEVFS_UPDATE_MOD); + DEVFS_ATTR_UNLOCK(); return (0); } @@ -1287,11 +1548,11 @@ static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { { &vnop_revoke_desc, (VOPFUNC)err_revoke }, /* revoke */ { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ { &vnop_fsync_desc, (VOPFUNC)nop_fsync }, /* fsync */ - { &vnop_remove_desc, (VOPFUNC)devfs_remove }, /* remove */ + { &vnop_remove_desc, (VOPFUNC)devfs_vnop_remove }, /* remove */ { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */ { &vnop_rename_desc, (VOPFUNC)devfs_rename }, /* rename */ - { &vnop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */ - { &vnop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */ + { &vnop_mkdir_desc, (VOPFUNC)devfs_mkdir }, /* mkdir */ + { &vnop_rmdir_desc, (VOPFUNC)devfs_rmdir }, /* rmdir */ { &vnop_symlink_desc, (VOPFUNC)devfs_symlink }, /* symlink */ { &vnop_readdir_desc, (VOPFUNC)devfs_readdir }, /* readdir */ { &vnop_readlink_desc, (VOPFUNC)devfs_readlink }, /* readlink */ @@ -1307,6 +1568,9 @@ static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */ { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */ { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */ +#if CONFIG_MACF + { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */ +#endif { (struct vnodeop_desc*)NULL, (int(*)())NULL } }; struct vnodeopv_desc devfs_vnodeop_opv_desc = @@ -1330,7 +1594,7 @@ static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = { { &vnop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */ { &vnop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */ { &vnop_fsync_desc, (VOPFUNC)spec_fsync }, /* fsync */ - { &vnop_remove_desc, (VOPFUNC)devfs_remove }, /* remove */ + { &vnop_remove_desc, (VOPFUNC)devfs_vnop_remove }, /* remove */ { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */ { &vnop_rename_desc, (VOPFUNC)spec_rename }, /* rename */ { &vnop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */ @@ -1344,15 +1608,43 @@ static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = { { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */ { &vnop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */ { &vnop_bwrite_desc, (VOPFUNC)vn_bwrite }, - { &vnop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */ { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */ { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */ { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ { &vnop_blktooff_desc, (VOPFUNC)spec_blktooff }, /* blktooff */ { &vnop_blktooff_desc, (VOPFUNC)spec_offtoblk }, /* blkofftoblk */ { &vnop_blockmap_desc, (VOPFUNC)spec_blockmap }, /* blockmap */ +#if CONFIG_MACF + { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */ +#endif { (struct vnodeop_desc*)NULL, (int(*)())NULL } }; struct vnodeopv_desc devfs_spec_vnodeop_opv_desc = { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries }; + +#if FDESC +int (**devfs_devfd_vnodeop_p)(void*); +static struct vnodeopv_entry_desc devfs_devfd_vnodeop_entries[] = { + { &vnop_default_desc, (VOPFUNC)vn_default_error }, + { &vnop_lookup_desc, (VOPFUNC)devfs_devfd_lookup}, /* lookup */ + { &vnop_open_desc, (VOPFUNC)nop_open }, /* open */ + { &vnop_close_desc, (VOPFUNC)devfs_close }, /* close */ + { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */ + { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */ + { &vnop_revoke_desc, (VOPFUNC)err_revoke }, /* revoke */ + { &vnop_fsync_desc, (VOPFUNC)nop_fsync }, /* fsync */ + { &vnop_readdir_desc, (VOPFUNC)devfs_devfd_readdir}, /* readdir */ + { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */ + { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */ + { &vnop_pathconf_desc, (VOPFUNC)devs_vnop_pathconf }, /* pathconf */ +#if CONFIG_MACF + { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */ +#endif + { (struct vnodeop_desc*)NULL, (int(*)())NULL } +}; +struct vnodeopv_desc devfs_devfd_vnodeop_opv_desc = + { &devfs_devfd_vnodeop_p, devfs_devfd_vnodeop_entries}; +#endif /* FDESC */ + +