Date: Mon, 4 Aug 2008 13:17:51 GMT From: Edward Tomasz Napierala <trasz@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 146619 for review Message-ID: <200808041317.m74DHpoZ054590@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=146619 Change 146619 by trasz@trasz_traszkan on 2008/08/04 13:17:47 Get rid of VOP_GRANULAR. Affected files ... .. //depot/projects/soc2008/trasz_nfs4acl/TODO#26 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c#6 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_nfs4.c#14 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_posix1e.c#7 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_default.c#3 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_subr.c#8 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_vnops.c#3 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vnode_if.src#6 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/sys/vnode.h#7 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_acl.c#7 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_lookup.c#10 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_vnops.c#8 edit Differences ... ==== //depot/projects/soc2008/trasz_nfs4acl/TODO#26 (text+ko) ==== @@ -2,6 +2,9 @@ - Make setfacl(1) error messages more user friendly. +- Correctly handle the situation in which we can stat, but cannot + read ACL, in ls(1). + - Decide what to do with write vs append on regular files. - Either add or extend existing manual pages for new API routines: @@ -12,8 +15,6 @@ - Add granular access control to ZFS. -- Get rid of the VOP_GRANULAR; merge its functionality back into VOP_ACCESS. - - Write code to do the same operations on UFS and ZFS and compare results. - Make 'struct acl' variable size. ==== //depot/projects/soc2008/trasz_nfs4acl/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c#6 (text+ko) ==== @@ -3210,8 +3210,13 @@ struct thread *a_td; } */ *ap; { + int error; + vaccess_t mode = ap->a_mode; + + if (unixify_vaccess(&mode, &error)) + return (error); - return (zfs_access(ap->a_vp, ap->a_mode, 0, ap->a_cred)); + return (zfs_access(ap->a_vp, mode, 0, ap->a_cred)); } static int @@ -3600,7 +3605,7 @@ /* Mostly taken from common/syscall/acl.c. */ - error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td); + error = VOP_ACCESS(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td); if (error != 0) return (error); ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_nfs4.c#14 (text+ko) ==== @@ -51,18 +51,35 @@ #endif #ifdef _KERNEL + +static struct { + vaccess_t mode; + int mask; +} mode2mask[] = {{VREAD, ACL_READ_DATA}, + {VWRITE, ACL_WRITE_DATA}, + {VAPPEND, ACL_APPEND_DATA}, + {VEXEC, ACL_EXECUTE}, + {VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, + {VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, + {VDELETE_CHILD, ACL_DELETE_CHILD}, + {VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {VDELETE, ACL_DELETE}, + {VREAD_ACL, ACL_READ_ACL}, + {VWRITE_ACL, ACL_WRITE_ACL}, + {VWRITE_OWNER, ACL_WRITE_OWNER}, + {VSYNCHRONIZE, ACL_SYNCHRONIZE}, + {0, 0}}; + static int _access_mask_from_mode(vaccess_t mode) { - int access_mask = 0; + int access_mask = 0, i; - /* XXX: VSTAT? */ - - if (mode & VREAD) - access_mask |= ACL_READ_DATA; - - if (mode & VWRITE) - access_mask |= ACL_WRITE_DATA; + for (i = 0; mode2mask[i].mode != 0; i++) { + if (mode & mode2mask[i].mode) + access_mask |= mode2mask[i].mask; + } if (mode & VAPPEND) { /* @@ -72,13 +89,9 @@ * permission to write is not required to append, * permission to append is sufficient. */ - access_mask |= ACL_APPEND_DATA; access_mask &= ~ACL_WRITE_DATA; } - if (mode & VEXEC) - access_mask |= ACL_EXECUTE; - return (access_mask); } @@ -149,36 +162,19 @@ int vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, - struct acl *aclp, vaccess_t acc_mode, int needed_bits, struct ucred *cred, - int *privused) + struct acl *aclp, vaccess_t acc_mode, struct ucred *cred, int *privused) { vaccess_t priv_granted = 0; - int denied, explicitly_denied, is_directory, must_be_owner = 0; + int denied, explicitly_denied, needed_bits, is_directory, + must_be_owner = 0; if (privused != NULL) *privused = 0; - if (acc_mode & VADMIN) { - /* - * XXX: This conditional will go away - * after removing VOP_GRANULAR> - */ - if (needed_bits == 0) { - must_be_owner = 1; - } else { - /* - * This is the case of - * VOP_GRANULAR(..., VADMIN, ACL_WRITE_OWNER, ...). - * In other words, we don't want actual VADMIN - * here, just one of the permissions typically - * reserved for file owner. - */ - must_be_owner = 0; - } - } + if (acc_mode & VADMIN) + must_be_owner = 1; - if (needed_bits == 0) - needed_bits = _access_mask_from_mode(acc_mode); + needed_bits = _access_mask_from_mode(acc_mode); if (type == VDIR) is_directory = 1; @@ -249,11 +245,14 @@ !priv_check_cred(cred, PRIV_VFS_WRITE, 0)) priv_granted |= (VWRITE | VAPPEND); - if ((acc_mode & VADMIN) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0)) - priv_granted |= VADMIN; + if ((acc_mode & VADMIN_PERMS) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0)) + priv_granted |= VADMIN_PERMS; - if ((acc_mode & VSTAT) && !priv_check_cred(cred, PRIV_VFS_READ, 0)) - priv_granted |= VSTAT; + /* + * XXX: PRIV_VFS_STAT? + */ + if ((acc_mode & VSTAT_PERMS) && !priv_check_cred(cred, PRIV_VFS_READ, 0)) + priv_granted |= VSTAT_PERMS; if ((acc_mode & priv_granted) == acc_mode) { if (privused != NULL) @@ -262,9 +261,7 @@ return (0); } - if ((acc_mode & VADMIN) || needed_bits & (ACL_DELETE_CHILD | - ACL_DELETE | ACL_WRITE_ATTRIBUTES | ACL_WRITE_ACL | - ACL_WRITE_OWNER)) + if (acc_mode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE)) denied = EPERM; else denied = EACCES; ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_posix1e.c#7 (text+ko) ==== @@ -59,7 +59,7 @@ vaccess_t dac_granted; vaccess_t priv_granted; vaccess_t acl_mask_granted; - int group_matched, i; + int group_matched, i, error; /* * Look for a normal, non-privileged way to access the file/directory @@ -71,14 +71,8 @@ if (privused != NULL) *privused = 0; - if (acc_mode == VSTAT) - return (0); - - /* - * Unix does not provide any explicit "deny" access rules. - */ - if (acc_mode & VEXPLICIT_DENY) - return (0); + if (unixify_vaccess(&acc_mode, &error)) + return (error); /* * Determine privileges now, but don't apply until we've found a DAC ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_default.c#3 (text+ko) ==== @@ -83,7 +83,6 @@ .vop_fsync = VOP_NULL, .vop_getpages = vop_stdgetpages, .vop_getwritemount = vop_stdgetwritemount, - .vop_granular = vop_stdgranular, .vop_inactive = VOP_NULL, .vop_ioctl = VOP_ENOTTY, .vop_kqfilter = vop_stdkqfilter, @@ -511,19 +510,6 @@ return (error); } -int -vop_stdgranular(ap) - struct vop_granular_args /* { - struct vnode *a_vp; - int a_mode; - int a_access_mask; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - return (VOP_ACCESS(ap->a_vp, ap->a_mode, ap->a_cred, ap->a_td)); -} - /* XXX Needs good comment and more info in the manpage (VOP_GETPAGES(9)). */ int vop_stdgetpages(ap) ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_subr.c#8 (text+ko) ==== @@ -3445,6 +3445,7 @@ vaccess(enum vtype type, mode_t file_mode, uid_t file_uid, gid_t file_gid, vaccess_t acc_mode, struct ucred *cred, int *privused) { + int error; vaccess_t dac_granted; vaccess_t priv_granted; @@ -3458,15 +3459,9 @@ dac_granted = 0; - if (acc_mode == VSTAT) - return (0); + if (unixify_vaccess(&acc_mode, &error)) + return (error); - /* - * Unix does not provide any explicit "deny" access rules. - */ - if (acc_mode & VEXPLICIT_DENY) - return (0); - /* Check the owner. */ if (cred->cr_uid == file_uid) { dac_granted |= VADMIN; @@ -3579,11 +3574,9 @@ case EXTATTR_NAMESPACE_USER: #ifdef SunOS_doesnt_do_that if (access == VREAD) - return (VOP_GRANULAR(vp, access, ACL_READ_NAMED_ATTRS, - cred, td)); + return (VOP_ACCESS(vp, VREAD_NAMED_ATTRS, cred, td)); if (access == VWRITE) - return (VOP_GRANULAR(vp, access, ACL_WRITE_NAMED_ATTRS, - cred, td)); + return (VOP_ACCESS(vp, VWRITE_NAMED_ATTRS, cred, td)); #endif /* XXX: Is this possible for "access" to not be any of the two above? */ return (VOP_ACCESS(vp, access, cred, td)); @@ -4194,3 +4187,44 @@ (void)VOP_SETATTR(vp, &atimeattr, td->td_ucred, td); } } + +/* + * The purpose of this routine is to remove granularity from vaccess_t, + * reducing it into standard unix access bits. + * + * This routine is supposed to be called from the beginning of vaccess + * implementations that don't know anything about granularity. If it + * returns 1, then the caller is supposed to return whatever this routine + * puts into variable pointed to by "error". + */ +int +unixify_vaccess(vaccess_t *mode, int *error) +{ + /* + * Unix does not provide any explicit "deny" access rules. + */ + if (*mode & VEXPLICIT_DENY) { + *error = 0; + return (1); + } + + if (*mode & (VDELETE_CHILD | VDELETE)) { + *error = EPERM; + return (1); + } + + if (*mode & (VWRITE_NAMED_ATTRS | VWRITE_ATTRIBUTES | VWRITE_ACL | VWRITE_OWNER)) { + *mode &= ~(VWRITE_NAMED_ATTRS | VWRITE_ATTRIBUTES | VWRITE_ACL | VWRITE_OWNER); + *mode |= VADMIN; + } + + *mode &= ~(VREAD_NAMED_ATTRS | VREAD_ATTRIBUTES | VREAD_ACL | VSYNCHRONIZE); + + if (*mode == 0) { + *error = 0; + return (1); + } + + return (0); +} + ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_vnops.c#3 (text+ko) ==== @@ -701,7 +701,7 @@ if (error) return (error); #endif - error = VOP_GRANULAR(vp, VSTAT, ACL_READ_ATTRIBUTES, active_cred, td); + error = VOP_ACCESS(vp, VREAD_ATTRIBUTES, active_cred, td); if (error) return (error); ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vnode_if.src#6 (text+ko) ==== @@ -153,17 +153,6 @@ }; -%% granular vp L L L - -vop_granular { - IN struct vnode *vp; - IN vaccess_t mode; - IN int access_mask; - IN struct ucred *cred; - IN struct thread *td; -}; - - %% getattr vp L L L vop_getattr { ==== //depot/projects/soc2008/trasz_nfs4acl/sys/sys/vnode.h#7 (text+ko) ==== @@ -312,17 +312,29 @@ /* * Modes. Some values same as Ixxx entries from inode.h for now. */ -#define VEXEC 0000100 /* execute/search permission */ -#define VWRITE 0000200 /* write permission */ -#define VREAD 0000400 /* read permission */ -#define VSVTX 0001000 /* save swapped text even after use */ -#define VSGID 0002000 /* set group id on execution */ -#define VSUID 0004000 /* set user id on execution */ -#define VADMIN 0010000 /* permission to administer */ -#define VSTAT 0020000 /* permission to retrieve attrs */ -#define VAPPEND 0040000 /* permission to write/append */ -#define VEXPLICIT_DENY 0100000 /* return EPERM only if permission was denied explicitly */ +#define VEXEC 000000000100 /* execute/search permission */ +#define VWRITE 000000000200 /* write permission */ +#define VREAD 000000000400 /* read permission */ +#define VSVTX 000000001000 /* save swapped text even after use */ +#define VSGID 000000002000 /* set group id on execution */ +#define VSUID 000000004000 /* set user id on execution */ +#define VADMIN 000000010000 /* permission to administer */ +#define VSTAT 000000020000 /* permission to retrieve attrs */ +#define VAPPEND 000000040000 /* permission to write/append */ +#define VEXPLICIT_DENY 000000100000 /* return EPERM only if permission was denied explicitly */ +#define VREAD_NAMED_ATTRS 000000200000 +#define VWRITE_NAMED_ATTRS 000000400000 +#define VDELETE_CHILD 000001000000 +#define VREAD_ATTRIBUTES 000002000000 +#define VWRITE_ATTRIBUTES 000004000000 +#define VDELETE 000010000000 +#define VREAD_ACL 000020000000 +#define VWRITE_ACL 000040000000 +#define VWRITE_OWNER 000100000000 +#define VSYNCHRONIZE 000200000000 #define VALLPERM (VEXEC | VWRITE | VREAD | VADMIN | VSTAT | VAPPEND) +#define VADMIN_PERMS (VADMIN | VWRITE_NAMED_ATTRS | VWRITE_ATTRIBUTES | VWRITE_ACL | VWRITE_OWNER) +#define VSTAT_PERMS (VSTAT | VREAD_NAMED_ATTRS | VREAD_ATTRIBUTES | VREAD_ACL | VSYNCHRONIZE) /* * Token indicating no attribute value yet assigned. @@ -596,7 +608,8 @@ struct ucred *cred, int *privused); int vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, struct acl *acl, vaccess_t acc_mode, - int access_mask, struct ucred *cred, int *privused); + struct ucred *cred, int *privused); +int unixify_vaccess(vaccess_t *mode, int *error); void vattr_null(struct vattr *vap); int vcount(struct vnode *vp); void vdrop(struct vnode *); @@ -653,7 +666,6 @@ int vop_stdbmap(struct vop_bmap_args *); int vop_stdfsync(struct vop_fsync_args *); int vop_stdgetwritemount(struct vop_getwritemount_args *); -int vop_stdgranular(struct vop_granular_args *); int vop_stdgetpages(struct vop_getpages_args *); int vop_stdinactive(struct vop_inactive_args *); int vop_stdislocked(struct vop_islocked_args *); ==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_acl.c#7 (text+ko) ==== @@ -380,7 +380,7 @@ /* * Must hold VADMIN (be file owner) or have appropriate privilege. */ - if ((error = VOP_GRANULAR(ap->a_vp, VADMIN, ACL_WRITE_ACL, ap->a_cred, ap->a_td))) + if ((error = VOP_ACCESS(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td))) return (error); if (acl_nfs4_is_trivial(ap->a_aclp)) { ==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_lookup.c#10 (text+ko) ==== @@ -93,20 +93,19 @@ /* * XXX: Is this check required? */ - error = VOP_GRANULAR(vdp, VEXEC, ACL_EXECUTE, cred, td); + error = VOP_ACCESS(vdp, VEXEC, cred, td); if (error) return (error); - error = VOP_GRANULAR(tdp, VADMIN, ACL_DELETE, cred, td); + error = VOP_ACCESS(tdp, VDELETE, cred, td); if (error == 0) return (0); - error = VOP_GRANULAR(vdp, VADMIN, ACL_DELETE_CHILD, cred, td); + error = VOP_ACCESS(vdp, VDELETE_CHILD, cred, td); if (error == 0) return (0); - error = VOP_GRANULAR(vdp, VADMIN | VEXPLICIT_DENY, - ACL_DELETE_CHILD, cred, td); + error = VOP_ACCESS(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); if (error) return (error); @@ -115,7 +114,7 @@ /* * Standard Unix access control - delete access requires VWRITE. */ - error = VOP_GRANULAR(vdp, VWRITE, ACL_WRITE_DATA, cred, td); + error = VOP_ACCESS(vdp, VWRITE, cred, td); if (error) return (error); @@ -466,9 +465,9 @@ * XXX: Fix the comment above. */ if (flags & WILLBEDIR) - error = VOP_GRANULAR(vdp, VWRITE, ACL_APPEND_DATA, cred, cnp->cn_thread); + error = VOP_ACCESS(vdp, VAPPEND, cred, cnp->cn_thread); else - error = VOP_GRANULAR(vdp, VWRITE, ACL_WRITE_DATA, cred, cnp->cn_thread); + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); if (error) return (error); /* @@ -590,11 +589,9 @@ */ if (nameiop == RENAME && (flags & ISLASTCN)) { if (flags & WILLBEDIR) - error = VOP_GRANULAR(vdp, VWRITE, ACL_APPEND_DATA, - cred, cnp->cn_thread); + error = VOP_ACCESS(vdp, VAPPEND, cred, cnp->cn_thread); else - error = VOP_GRANULAR(vdp, VWRITE, ACL_WRITE_DATA, - cred, cnp->cn_thread); + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); if (error) return (error); /* @@ -613,16 +610,14 @@ * error. Assume that we want to rename directory "a" * to a file "b", and that we have no ACL_WRITE_DATA on * a containing directory, but we _do_ have ACL_APPEND_DATA. - * In that case, the VOP_GRANULAR check above will return 0, + * In that case, the VOP_ACCESS check above will return 0, * and the operation will fail with ENOTDIR instead * of EACCESS. */ if (tdp->v_type == VDIR) - error = VOP_GRANULAR(vdp, VWRITE, ACL_APPEND_DATA, - cred, cnp->cn_thread); + error = VOP_ACCESS(vdp, VAPPEND, cred, cnp->cn_thread); else - error = VOP_GRANULAR(vdp, VWRITE, ACL_WRITE_DATA, - cred, cnp->cn_thread); + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); if (error) { vput(tdp); return (error); ==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_vnops.c#8 (text+ko) ==== @@ -96,7 +96,6 @@ static vop_close_t ufs_close; static vop_create_t ufs_create; static vop_getattr_t ufs_getattr; -static vop_granular_t ufs_granular; static vop_link_t ufs_link; static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *); static vop_mkdir_t ufs_mkdir; @@ -299,11 +298,10 @@ } static int -ufs_granular(ap) - struct vop_granular_args /* { +ufs_access(ap) + struct vop_access_args /* { struct vnode *a_vp; vaccess_t a_mode; - int a_access_mask; struct ucred *a_cred; struct thread *a_td; } */ *ap; @@ -357,8 +355,7 @@ case 0: if (type == ACL_TYPE_NFS4) { error = vaccess_acl_nfs4(vp->v_type, ip->i_uid, - ip->i_gid, acl, ap->a_mode, - ap->a_access_mask, ap->a_cred, NULL); + ip->i_gid, acl, ap->a_mode, ap->a_cred, NULL); } else { error = vaccess_acl_posix1e(vp->v_type, ip->i_uid, ip->i_gid, acl, ap->a_mode, ap->a_cred, NULL); @@ -384,18 +381,6 @@ return (error); } -static int -ufs_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - vaccess_t a_mode; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - return (VOP_GRANULAR(ap->a_vp, ap->a_mode, 0, ap->a_cred, ap->a_td)); -} - /* ARGSUSED */ static int ufs_getattr(ap) @@ -622,15 +607,11 @@ * * XXX: Calling it four times seems a little excessive. */ - error = VOP_GRANULAR(vp, VADMIN, ACL_WRITE_DATA, cred, td); + error = VOP_ACCESS(vp, VWRITE_ATTRIBUTES, cred, td); if (error) - error = VOP_GRANULAR(vp, VADMIN, ACL_WRITE_ATTRIBUTES, cred, td); - if (error) - error = VOP_GRANULAR(vp, VWRITE, ACL_WRITE_DATA, cred, td); - if (error) - error = VOP_GRANULAR(vp, VWRITE, ACL_WRITE_ATTRIBUTES, cred, td); + error = VOP_ACCESS(vp, VWRITE, cred, td); } else - error = VOP_GRANULAR(vp, VADMIN, ACL_WRITE_ATTRIBUTES, cred, td); + error = VOP_ACCESS(vp, VWRITE_ATTRIBUTES, cred, td); if (error) return (error); if (vap->va_atime.tv_sec != VNOVAL) @@ -719,7 +700,7 @@ * To modify the permissions on a file, must possess VADMIN * for that file. */ - if ((error = VOP_GRANULAR(vp, VADMIN, ACL_WRITE_ACL, cred, td))) + if ((error = VOP_ACCESS(vp, VWRITE_ACL, cred, td))) return (error); /* * Privileged processes may set the sticky bit on non-directories, @@ -776,7 +757,7 @@ * To modify the ownership of a file, must possess VADMIN for that * file. */ - if ((error = VOP_GRANULAR(vp, VADMIN, ACL_WRITE_OWNER, cred, td))) + if ((error = VOP_ACCESS(vp, VWRITE_OWNER, cred, td))) return (error); /* * To change the owner of a file, or change the group of a file to a @@ -2566,7 +2547,6 @@ .vop_close = ufs_close, .vop_create = ufs_create, .vop_getattr = ufs_getattr, - .vop_granular = ufs_granular, .vop_inactive = ufs_inactive, .vop_link = ufs_link, .vop_lookup = vfs_cache_lookup, @@ -2607,7 +2587,6 @@ .vop_access = ufs_access, .vop_close = ufsfifo_close, .vop_getattr = ufs_getattr, - .vop_granular = ufs_granular, .vop_inactive = ufs_inactive, .vop_kqfilter = ufsfifo_kqfilter, .vop_print = ufs_print,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200808041317.m74DHpoZ054590>