/*
- * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * 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 Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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 OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * 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_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright 1997,1998 Julian Elischer. All rights reserved.
* 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/vm.h>
#include <sys/uio_internal.h>
+#if CONFIG_MACF
+#include <security/mac_framework.h>
+#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)
+{
-static int devfs_update(struct vnode *vp, struct timeval *access,
- struct timeval *modify);
+ 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;
+
+ DEVFS_ATTR_LOCK_SPIN();
+ microtime(&now);
+ dn_times_locked(dnp, &now, &now, &now, just_changed_flags);
+ DEVFS_ATTR_UNLOCK();
+}
/*
*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);
/*
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:
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) */
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();
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;
{
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.
*/
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 {
} */
{
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);
} */
{
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 {
{
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));
}
{
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));
}
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;
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);
/***********************************
* 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
devnode_t * tdp;
devdirent_t * tnp;
int error = 0;
- struct timeval now;
/*
* First catch an arbitrary restriction for this FS
* 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);
devdirent_t *fnp,*tnp;
int doingdirectory = 0;
int error = 0;
- struct timeval now;
DEVFS_LOCK();
/*
/***********************************
* 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.
*/
* 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
}
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;
} */
{
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;
}
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
*/
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);
struct dirent dirent;
devnode_t * dir_node;
devdirent_t * name_node;
- char *name;
+ const char *name;
int error = 0;
int reclen;
int nodenumber;
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) {
{
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;
DEVFS_UNLOCK();
uio->uio_offset = pos;
+ devfs_consider_time_update(dir_node, DEVFS_UPDATE_ACCESS);
+
return (error);
}
} */
{
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();
*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;
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);
}
/*
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);
}
{ &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 */
{ &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 =
{ &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 */
{ &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 */
+
+