diff options
author | praks <none@none> | 2007-08-14 17:10:25 -0700 |
---|---|---|
committer | praks <none@none> | 2007-08-14 17:10:25 -0700 |
commit | df2381bfa5cf7dd654bcf30b2f5af53f34f3043a (patch) | |
tree | 64f247ef81041ed83c44dc2d9aadf46ed66b5ab3 | |
parent | 2038334ab26baaa43c9083f35def041511c3cc1f (diff) | |
download | illumos-gate-df2381bfa5cf7dd654bcf30b2f5af53f34f3043a.tar.gz |
PSARC/2007/027 File Events Notification API
6367770 RFE: add userland interface to fem (file event monitoring)
--HG--
rename : deleted_files/usr/src/uts/common/fs/portfs/port_fop.c => usr/src/uts/common/fs/portfs/port_fop.c
35 files changed, 869 insertions, 130 deletions
diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt index 536c80831a..0baf923310 100644 --- a/usr/src/lib/libbsm/audit_event.txt +++ b/usr/src/lib/libbsm/audit_event.txt @@ -344,6 +344,7 @@ 298:AUE_PF_POLICY_FLIP:Flip IPsec policy:as 299:AUE_PF_POLICY_FLUSH:Flush IPsec policy rules:as 300:AUE_PF_POLICY_ALGS:Update IPsec algorithms:as +301:AUE_PORTFS:portfs(2) - file events source:fa # # user level audit events # 2048 - 6143 Reserved diff --git a/usr/src/uts/common/c2/audit_event.c b/usr/src/uts/common/c2/audit_event.c index 5dfc75ec04..8b99857df6 100644 --- a/usr/src/uts/common/c2/audit_event.c +++ b/usr/src/uts/common/c2/audit_event.c @@ -74,6 +74,8 @@ #include <sys/socketvar.h> #include <netinet/in.h> #include <sys/ddi.h> +#include <sys/port_impl.h> + extern token_t *au_to_sock_inet(struct sockaddr_in *); @@ -92,6 +94,7 @@ static au_event_t aui_execv(au_event_t); static au_event_t aui_execve(au_event_t); static au_event_t aui_memcntl(au_event_t); static au_event_t aui_sysinfo(au_event_t); +static au_event_t aui_portfs(au_event_t); static au_event_t aui_auditsys(au_event_t); static au_event_t aui_modctl(au_event_t); static au_event_t aui_acl(au_event_t); @@ -577,7 +580,7 @@ aui_null, AUE_NULL, aus_null, /* 180 (loadable) kaio */ auf_null, 0, aui_null, AUE_NULL, aus_null, /* 181 (loadable) */ auf_null, 0, -aui_null, AUE_NULL, aus_null, /* 182 (loadable) */ +aui_portfs, AUE_PORTFS, aus_null, /* 182 (loadable) portfs */ auf_null, 0, aui_null, AUE_NULL, aus_null, /* 183 (loadable) */ auf_null, 0, @@ -5608,3 +5611,34 @@ aui_forksys(au_event_t e) return (e); } + +/*ARGSUSED*/ +static au_event_t +aui_portfs(au_event_t e) +{ + struct a { /* portfs */ + long a1; + long a2; + long a3; + } *uap = (struct a *)ttolwp(curthread)->lwp_ap; + + /* + * check opcode + */ + switch (((uint_t)uap->a1) & PORT_CODE_MASK) { + case PORT_ASSOCIATE: + case PORT_DISSOCIATE: + /* + * check source + */ + if ((uint_t)uap->a3 == PORT_SOURCE_FILE) { + e = AUE_PORTFS; + } else { + e = AUE_NULL; + } + break; + default: + e = AUE_NULL; + } + return (e); +} diff --git a/usr/src/uts/common/c2/audit_kevents.h b/usr/src/uts/common/c2/audit_kevents.h index 01a522ba5b..dbb7323185 100644 --- a/usr/src/uts/common/c2/audit_kevents.h +++ b/usr/src/uts/common/c2/audit_kevents.h @@ -337,9 +337,10 @@ extern "C" { #define AUE_PF_POLICY_FLIP 298 /* =as Flip IPsec policy */ #define AUE_PF_POLICY_FLUSH 299 /* =as Flush IPsec policy rules */ #define AUE_PF_POLICY_ALGS 300 /* =as Update IPsec algorithms */ +#define AUE_PORTFS 301 /* =fa */ /* NOTE: update MAX_KEVENTS below if events are added. */ -#define MAX_KEVENTS 300 +#define MAX_KEVENTS 301 #ifdef __cplusplus diff --git a/usr/src/uts/common/fs/autofs/auto_vnops.c b/usr/src/uts/common/fs/autofs/auto_vnops.c index 0587ed066e..dec18bd6e1 100644 --- a/usr/src/uts/common/fs/autofs/auto_vnops.c +++ b/usr/src/uts/common/fs/autofs/auto_vnops.c @@ -105,6 +105,7 @@ const fs_operation_def_t auto_vnodeops_template[] = { VOPNAME_FRLOCK, { .error = fs_error }, VOPNAME_DISPOSE, { .error = fs_error }, VOPNAME_SHRLOCK, { .error = fs_error }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, NULL, NULL }; diff --git a/usr/src/uts/common/fs/fem.c b/usr/src/uts/common/fs/fem.c index 93cae4d737..04886984e4 100644 --- a/usr/src/uts/common/fs/fem.c +++ b/usr/src/uts/common/fs/fem.c @@ -1595,7 +1595,7 @@ vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, } static int -vhead_vnevent(vnode_t *vp, vnevent_t vnevent) +vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname) { femarg_t farg; struct fem_list *femsp; @@ -1607,7 +1607,7 @@ vhead_vnevent(vnode_t *vp, vnevent_t vnevent) func = (int (*)()) (vp->v_op->vop_vnevent); arg0 = vp; fem_unlock(vp->v_femhead); - errc = (*func)(arg0, vnevent); + errc = (*func)(arg0, vnevent, dvp, cname); } else { fem_addref(femsp); fem_unlock(vp->v_femhead); @@ -1615,7 +1615,7 @@ vhead_vnevent(vnode_t *vp, vnevent_t vnevent) farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; vsop_find(&farg, &func, int, &arg0, vop_vnevent, femop_vnevent); - errc = (*func)(arg0, vnevent); + errc = (*func)(arg0, vnevent, dvp, cname); fem_release(femsp); } return (errc); @@ -2583,7 +2583,7 @@ vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag, } int -vnext_vnevent(femarg_t *vf, vnevent_t vnevent) +vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname) { int (*func)() = NULL; void *arg0 = NULL; @@ -2593,7 +2593,7 @@ vnext_vnevent(femarg_t *vf, vnevent_t vnevent) vsop_find(vf, &func, int, &arg0, vop_vnevent, femop_vnevent); ASSERT(func != NULL); ASSERT(arg0 != NULL); - return ((*func)(arg0, vnevent)); + return ((*func)(arg0, vnevent, dvp, cname)); } int diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c index 0fe058556d..c88e8b3268 100644 --- a/usr/src/uts/common/fs/fs_subr.c +++ b/usr/src/uts/common/fs/fs_subr.c @@ -633,7 +633,7 @@ fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr) /*ARGSUSED1*/ int -fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent) +fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname) { ASSERT(vp != NULL); return (ENOTSUP); @@ -641,7 +641,7 @@ fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent) /*ARGSUSED1*/ int -fs_vnevent_support(vnode_t *vp, vnevent_t vnevent) +fs_vnevent_support(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname) { ASSERT(vp != NULL); return (0); diff --git a/usr/src/uts/common/fs/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h index 2f2056e6f3..f0b536d0f0 100644 --- a/usr/src/uts/common/fs/fs_subr.h +++ b/usr/src/uts/common/fs/fs_subr.h @@ -22,7 +22,7 @@ /* All Rights Reserved */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -78,8 +78,8 @@ extern void fs_nodispose(struct vnode *, page_t *, int, int, struct cred *); extern int fs_fab_acl(struct vnode *, vsecattr_t *, int flag, cred_t *); extern int fs_shrlock(struct vnode *, int, struct shrlock *, int, cred_t *); -extern int fs_vnevent_nosupport(vnode_t *, vnevent_t); -extern int fs_vnevent_support(vnode_t *, vnevent_t); +extern int fs_vnevent_nosupport(vnode_t *, vnevent_t, vnode_t *, char *); +extern int fs_vnevent_support(vnode_t *, vnevent_t, vnode_t *, char *); extern int fs_acl_nontrivial(struct vnode *vp, struct cred *cr); extern int fs_need_estale_retry(int); diff --git a/usr/src/uts/common/fs/mntfs/mntvfsops.c b/usr/src/uts/common/fs/mntfs/mntvfsops.c index f148bb4af4..9f44902892 100644 --- a/usr/src/uts/common/fs/mntfs/mntvfsops.c +++ b/usr/src/uts/common/fs/mntfs/mntvfsops.c @@ -104,7 +104,7 @@ _info(struct modinfo *modinfop) * is ever modified to become unloadable. */ -static int mntfstype; +extern int mntfstype; static major_t mnt_major; static minor_t mnt_minor; static kmutex_t mnt_minor_lock; diff --git a/usr/src/uts/common/fs/mntfs/mntvnops.c b/usr/src/uts/common/fs/mntfs/mntvnops.c index 79f3a090b7..9083d5c5b2 100644 --- a/usr/src/uts/common/fs/mntfs/mntvnops.c +++ b/usr/src/uts/common/fs/mntfs/mntvnops.c @@ -46,6 +46,7 @@ static mntnode_t *mntgetnode(vnode_t *); vnodeops_t *mntvnodeops; +extern void vfs_mnttab_readop(void); /* * Design of kernel mnttab accounting. @@ -633,7 +634,7 @@ mntfs_snapshot(mntnode_t *mnp, int forread, int datamodel) mntfs_freesnap(snap); return (ENOMEM); } - + vfs_mnttab_readop(); return (0); } @@ -760,7 +761,7 @@ mntread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, caller_context_t *ct) error = uiomove(buf, len, UIO_READ, uio); } kmem_free(buf, len); - + vfs_mnttab_readop(); return (error); } @@ -1128,7 +1129,6 @@ mntioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, return (error); } - /* * /mntfs vnode operations vector */ diff --git a/usr/src/uts/common/fs/nfs/nfs3_vnops.c b/usr/src/uts/common/fs/nfs/nfs3_vnops.c index 7a9355b4a4..39bdc1aa00 100644 --- a/usr/src/uts/common/fs/nfs/nfs3_vnops.c +++ b/usr/src/uts/common/fs/nfs/nfs3_vnops.c @@ -257,6 +257,7 @@ const fs_operation_def_t nfs3_vnodeops_template[] = { VOPNAME_SETSECATTR, { .vop_setsecattr = nfs3_setsecattr }, VOPNAME_GETSECATTR, { .vop_getsecattr = nfs3_getsecattr }, VOPNAME_SHRLOCK, { .vop_shrlock = nfs3_shrlock }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, NULL, NULL }; @@ -2225,8 +2226,13 @@ top: nfs_rw_exit(&drp->r_rwlock); if (error) { VN_RELE(vp); - } else + } else { + /* + * existing file got truncated, notify. + */ + vnevent_create(vp); *vpp = vp; + } return (error); } @@ -2861,6 +2867,9 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr) } } + if (error == 0) { + vnevent_remove(vp, dvp, nm); + } VN_RELE(vp); nfs_rw_exit(&drp->r_rwlock); @@ -2936,6 +2945,12 @@ nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr) nfs_rw_exit(&tdrp->r_rwlock); + if (!error) { + /* + * Notify the source file of this link operation. + */ + vnevent_link(svp); + } return (error); } @@ -2962,7 +2977,7 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) RENAME3args args; RENAME3res res; int douprintf; - vnode_t *nvp; + vnode_t *nvp = NULL; vnode_t *ovp = NULL; char *tmpname; rnode_t *rp; @@ -3120,8 +3135,6 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) } mutex_exit(&rp->r_statelock); } - - VN_RELE(nvp); } if (ovp == NULL) { @@ -3144,6 +3157,9 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) if (error) { nfs_rw_exit(&odrp->r_rwlock); nfs_rw_exit(&ndrp->r_rwlock); + if (nvp) { + VN_RELE(nvp); + } return (error); } ASSERT(ovp != NULL); @@ -3170,6 +3186,9 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) VN_RELE(ovp); nfs_rw_exit(&odrp->r_rwlock); nfs_rw_exit(&ndrp->r_rwlock); + if (nvp) { + VN_RELE(nvp); + } return (error); } @@ -3232,6 +3251,19 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) error = EEXIST; } + if (error == 0) { + if (nvp) + vnevent_rename_dest(nvp, ndvp, nnm); + + if (odvp != ndvp) + vnevent_rename_dest_dir(ndvp); + ASSERT(ovp != NULL); + vnevent_rename_src(ovp, odvp, onm); + } + + if (nvp) { + VN_RELE(nvp); + } VN_RELE(ovp); nfs_rw_exit(&odrp->r_rwlock); @@ -3436,6 +3468,9 @@ nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr) error = EEXIST; } + if (error == 0) { + vnevent_rmdir(vp, dvp, nm); + } VN_RELE(vp); nfs_rw_exit(&drp->r_rwlock); @@ -4687,9 +4722,9 @@ again: } if (!readahead_issued && !error) { - mutex_enter(&rp->r_statelock); - rp->r_nextr = io_off + io_len; - mutex_exit(&rp->r_statelock); + mutex_enter(&rp->r_statelock); + rp->r_nextr = io_off + io_len; + mutex_exit(&rp->r_statelock); } } } diff --git a/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c b/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c index 8ac83ac53c..90cd69efb4 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c +++ b/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -346,10 +345,13 @@ deleg_setsecattr( return (vnext_setsecattr(arg, vsap, flag, cr)); } +/* ARGSUSED */ int deleg_vnevent( femarg_t *arg, - vnevent_t vnevent) + vnevent_t vnevent, + vnode_t *dvp, + char *name) { clock_t rc; rfs4_file_t *fp; @@ -380,5 +382,5 @@ deleg_vnevent( default: break; } - return (vnext_vnevent(arg, vnevent)); + return (vnext_vnevent(arg, vnevent, dvp, name)); } diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c index 565dd58e32..897e8fac60 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c +++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c @@ -404,6 +404,7 @@ const fs_operation_def_t nfs4_vnodeops_template[] = { VOPNAME_SETSECATTR, { .vop_setsecattr = nfs4_setsecattr }, VOPNAME_GETSECATTR, { .vop_getsecattr = nfs4_getsecattr }, VOPNAME_SHRLOCK, { .vop_shrlock = nfs4_shrlock }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, NULL, NULL }; @@ -6387,6 +6388,7 @@ nfs4_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, vnode_t *tempvp; enum createmode4 createmode; bool_t must_trunc = FALSE; + int truncating = 0; if (nfs_zone() != VTOMI4(dvp)->mi_zone) return (EPERM); @@ -6517,6 +6519,7 @@ top: AT_TYPE | AT_MODE); vattr.va_type = VREG; createmode = UNCHECKED4; + truncating = 1; goto create_otw; } } @@ -6526,6 +6529,18 @@ top: if (error) { VN_RELE(vp); } else { + vnode_t *tvp; + rnode4_t *trp; + /* + * existing file got truncated, notify. + */ + tvp = vp; + if (vp->v_type == VREG) { + trp = VTOR4(vp); + if (IS_SHADOW(vp, trp)) + tvp = RTOV4(trp); + } + vnevent_create(tvp); *vpp = vp; } return (error); @@ -6620,6 +6635,18 @@ create_otw: goto top; } nfs_rw_exit(&drp->r_rwlock); + if (truncating && !error && *vpp) { + vnode_t *tvp; + rnode4_t *trp; + /* + * existing file got truncated, notify. + */ + tvp = *vpp; + trp = VTOR4(tvp); + if (IS_SHADOW(tvp, trp)) + tvp = RTOV4(trp); + vnevent_create(tvp); + } return (error); } @@ -7262,6 +7289,15 @@ recov_retry: if (resp) (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp); + if (e.error == 0) { + vnode_t *tvp; + rnode4_t *trp; + trp = VTOR4(vp); + tvp = vp; + if (IS_SHADOW(vp, trp)) + tvp = RTOV4(trp); + vnevent_remove(tvp, dvp, nm); + } VN_RELE(vp); return (e.error); } @@ -7472,6 +7508,18 @@ recov_retry: ASSERT(nfs4_consistent_type(nvp)); VN_RELE(nvp); + if (!e.error) { + vnode_t *tvp; + rnode4_t *trp; + /* + * Notify the source file of this link operation. + */ + trp = VTOR4(svp); + tvp = svp; + if (IS_SHADOW(svp, trp)) + tvp = RTOV4(trp); + vnevent_link(tvp); + } out: kmem_free(argop, argoplist_size); if (resp) @@ -7507,7 +7555,7 @@ nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) { int error; mntinfo4_t *mi; - vnode_t *nvp; + vnode_t *nvp = NULL; vnode_t *ovp = NULL; char *tmpname = NULL; rnode4_t *rp; @@ -7706,7 +7754,6 @@ link_call: (void) nfs4delegreturn(VTOR4(nvp), NFS4_DR_PUSH|NFS4_DR_REOPEN); ASSERT(nfs4_consistent_type(nvp)); - VN_RELE(nvp); } if (ovp == NULL) { @@ -7728,6 +7775,9 @@ link_call: if (error) { nfs_rw_exit(&odrp->r_rwlock); nfs_rw_exit(&ndrp->r_rwlock); + if (nvp) { + VN_RELE(nvp); + } return (error); } ASSERT(ovp != NULL); @@ -7755,6 +7805,9 @@ link_call: VN_RELE(ovp); nfs_rw_exit(&odrp->r_rwlock); nfs_rw_exit(&ndrp->r_rwlock); + if (nvp) { + VN_RELE(nvp); + } return (EINVAL); } @@ -7811,6 +7864,9 @@ link_call: } mutex_exit(&rp->r_statelock); + if (nvp) { + VN_RELE(nvp); + } goto link_call; } @@ -7818,6 +7874,9 @@ link_call: VN_RELE(ovp); nfs_rw_exit(&odrp->r_rwlock); nfs_rw_exit(&ndrp->r_rwlock); + if (nvp) { + VN_RELE(nvp); + } return (error); } @@ -7853,6 +7912,47 @@ link_call: } mutex_exit(&rp->r_statelock); + /* + * Notify the rename vnevents to source vnode, and to the target + * vnode if it already existed. + */ + if (error == 0) { + vnode_t *tvp; + rnode4_t *trp; + /* + * Notify the vnode. Each links is represented by + * a different vnode, in nfsv4. + */ + if (nvp) { + trp = VTOR4(nvp); + tvp = nvp; + if (IS_SHADOW(nvp, trp)) + tvp = RTOV4(trp); + vnevent_rename_dest(tvp, ndvp, nnm); + } + + /* + * if the source and destination directory are not the + * same notify the destination directory. + */ + if (VTOR4(odvp) != VTOR4(ndvp)) { + trp = VTOR4(ndvp); + tvp = ndvp; + if (IS_SHADOW(ndvp, trp)) + tvp = RTOV4(trp); + vnevent_rename_dest_dir(tvp); + } + + trp = VTOR4(ovp); + tvp = ovp; + if (IS_SHADOW(ovp, trp)) + tvp = RTOV4(trp); + vnevent_rename_src(tvp, odvp, onm); + } + + if (nvp) { + VN_RELE(nvp); + } VN_RELE(ovp); nfs_rw_exit(&odrp->r_rwlock); @@ -8561,6 +8661,16 @@ recov_retry: if (resp) (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp); + if (e.error == 0) { + vnode_t *tvp; + rnode4_t *trp; + trp = VTOR4(vp); + tvp = vp; + if (IS_SHADOW(vp, trp)) + tvp = RTOV4(trp); + vnevent_rmdir(tvp, dvp, nm); + } + VN_RELE(vp); return (e.error); @@ -10768,7 +10878,14 @@ nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, static int nfs4_realvp(vnode_t *vp, vnode_t **vpp) { - return (EINVAL); + rnode4_t *rp; + rp = VTOR4(vp); + + if (vp->v_type == VREG && IS_SHADOW(vp, rp)) { + vp = RTOV4(rp); + } + *vpp = vp; + return (0); } /* diff --git a/usr/src/uts/common/fs/nfs/nfs_vnops.c b/usr/src/uts/common/fs/nfs/nfs_vnops.c index 5e587027d7..96b7044e6a 100644 --- a/usr/src/uts/common/fs/nfs/nfs_vnops.c +++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c @@ -218,6 +218,7 @@ const fs_operation_def_t nfs_vnodeops_template[] = { VOPNAME_SETSECATTR, { .vop_setsecattr = nfs_setsecattr }, VOPNAME_GETSECATTR, { .vop_getsecattr = nfs_getsecattr }, VOPNAME_SHRLOCK, { .vop_shrlock = nfs_shrlock }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, NULL, NULL }; @@ -1964,8 +1965,13 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, nfs_rw_exit(&drp->r_rwlock); if (error) { VN_RELE(vp); - } else + } else { + /* + * existing file got truncated, notify. + */ + vnevent_create(vp); *vpp = vp; + } return (error); } @@ -2246,6 +2252,9 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr) } } + if (error == 0) { + vnevent_remove(vp, dvp, nm); + } VN_RELE(vp); nfs_rw_exit(&drp->r_rwlock); @@ -2297,6 +2306,12 @@ nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr) nfs_rw_exit(&tdrp->r_rwlock); + if (!error) { + /* + * Notify the source file of this link operation. + */ + vnevent_link(svp); + } return (error); } @@ -2323,7 +2338,7 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) enum nfsstat status; struct nfsrnmargs args; int douprintf; - vnode_t *nvp; + vnode_t *nvp = NULL; vnode_t *ovp = NULL; char *tmpname; rnode_t *rp; @@ -2479,8 +2494,6 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) } mutex_exit(&rp->r_statelock); } - - VN_RELE(nvp); } if (ovp == NULL) { @@ -2504,6 +2517,9 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) if (error) { nfs_rw_exit(&odrp->r_rwlock); nfs_rw_exit(&ndrp->r_rwlock); + if (nvp) { + VN_RELE(nvp); + } return (error); } ASSERT(ovp != NULL); @@ -2577,6 +2593,20 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) } } + if (error == 0) { + if (nvp) + vnevent_rename_dest(nvp, ndvp, nnm); + + if (odvp != ndvp) + vnevent_rename_dest_dir(ndvp); + + ASSERT(ovp != NULL); + vnevent_rename_src(ovp, odvp, onm); + } + + if (nvp) { + VN_RELE(nvp); + } VN_RELE(ovp); nfs_rw_exit(&odrp->r_rwlock); @@ -2758,6 +2788,9 @@ nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr) error = EEXIST; } + if (error == 0) { + vnevent_rmdir(vp, dvp, nm); + } VN_RELE(vp); nfs_rw_exit(&drp->r_rwlock); diff --git a/usr/src/uts/common/fs/pcfs/pc_dir.c b/usr/src/uts/common/fs/pcfs/pc_dir.c index 88b895a212..616efe23cb 100644 --- a/usr/src/uts/common/fs/pcfs/pc_dir.c +++ b/usr/src/uts/common/fs/pcfs/pc_dir.c @@ -467,9 +467,9 @@ pc_dirremove( if (error == 0) { if (type == VDIR) { - vnevent_rmdir(PCTOV(pcp)); + vnevent_rmdir(PCTOV(pcp), vp, namep); } else { - vnevent_remove(PCTOV(pcp)); + vnevent_remove(PCTOV(pcp), vp, namep); } } @@ -633,7 +633,7 @@ top: newisdir = tpcp->pc_entry.pcd_attr & PCA_DIR; brelse(slot.sl_bp); - vnevent_rename_dest(PCTOV(tpcp)); + vnevent_rename_dest(PCTOV(tpcp), PCTOV(tdp), tnm); VN_RELE(PCTOV(tpcp)); /* @@ -815,7 +815,11 @@ top: } } out: - vnevent_rename_src(PCTOV(pcp)); + vnevent_rename_src(PCTOV(pcp), PCTOV(dp), snm); + if (dp != tdp) { + vnevent_rename_dest_dir(PCTOV(tdp)); + } + VN_RELE(PCTOV(pcp)); return (error); diff --git a/usr/src/uts/common/fs/pcfs/pc_vnops.c b/usr/src/uts/common/fs/pcfs/pc_vnops.c index 1e6252aceb..bb49ad5ea2 100644 --- a/usr/src/uts/common/fs/pcfs/pc_vnops.c +++ b/usr/src/uts/common/fs/pcfs/pc_vnops.c @@ -1052,8 +1052,11 @@ pcfs_create( } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && (vap->va_size == 0)) { error = pc_truncate(pcp, 0L); - if (error) + if (error) { VN_RELE(PCTOV(pcp)); + } else { + vnevent_create(PCTOV(pcp)); + } } } if (error) { diff --git a/usr/src/uts/common/fs/portfs/port.c b/usr/src/uts/common/fs/portfs/port.c index a2d6b95170..14be8cbbae 100644 --- a/usr/src/uts/common/fs/portfs/port.c +++ b/usr/src/uts/common/fs/portfs/port.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -79,6 +79,8 @@ * (see port_alert(3c)). * PORT_SOURCE_USER : events submitted by applications with * port_send(3c) or port_sendn(3c). + * PORT_SOURCE_FILE : events submitted per file being watched for file + * change events (see port_create(3c). * * There is a user API implemented in the libc library as well as a * kernel API implemented in port_subr.c in genunix. @@ -172,6 +174,21 @@ * This type of event is generated from user level using the port_send() * function to send a user event to a port or the port_sendn() function * to send an event to a list of ports. + * PORT_SOURCE_FILE: + * This event source uses the port_associate() interface to register + * a file to be monitored for changes. The file name that needs to be + * monitored is specified in the file_obj_t structure, a pointer to which + * is passed as an argument. The event types to be monitored are specified + * in the events argument. + * A file events monitor is represented internal per port per object + * address(the file_obj_t pointer). Which means there can be multiple + * watches registered on the same file using different file_obj_t + * structure pointer. With the help of the FEM(File Event Monitoring) + * hooks, the file's vnode ops are intercepted and relevant events + * delivered. The port_dissociate() function is used to de-register a + * file events monitor on a file. When the specified file is + * removed/renamed, the file events watch/monitor is automatically + * removed. * * EVENT DELIVERY / RETRIEVING EVENTS * Events remain in the port queue until: @@ -215,6 +232,8 @@ * This type of event is not shareable between processes. * PORT_SOURCE_TIMER events * This type of event is not shareable between processes. + * PORT_SOURCE_FILE events + * This type of event is not shareable between processes. * * FORK BEHAVIOUR * On fork(2) the child process inherits all opened file descriptors from @@ -622,13 +641,19 @@ portfs(int opcode, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, } case PORT_ASSOCIATE: { - /* currently only PORT_SOURCE_FD is implemented */ - if ((int)a1 != PORT_SOURCE_FD) { + switch ((int)a1) { + case PORT_SOURCE_FD: + error = port_associate_fd(pp, (int)a1, (uintptr_t)a2, + (int)a3, (void *)a4); + break; + case PORT_SOURCE_FILE: + error = port_associate_fop(pp, (int)a1, (uintptr_t)a2, + (int)a3, (void *)a4); + break; + default: error = EINVAL; break; } - error = port_associate_fd(pp, (int)a1, (uintptr_t)a2, (int)a3, - (void *)a4); break; } case PORT_SEND: @@ -654,12 +679,17 @@ portfs(int opcode, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, } case PORT_DISSOCIATE: { - /* currently only PORT_SOURCE_FD is implemented */ - if ((int)a1 != PORT_SOURCE_FD) { + switch ((int)a1) { + case PORT_SOURCE_FD: + error = port_dissociate_fd(pp, (uintptr_t)a2); + break; + case PORT_SOURCE_FILE: + error = port_dissociate_fop(pp, (uintptr_t)a2); + break; + default: error = EINVAL; break; } - error = port_dissociate_fd(pp, (uintptr_t)a2); break; } case PORT_ALERT: diff --git a/usr/src/uts/common/fs/portfs/port_fd.c b/usr/src/uts/common/fs/portfs/port_fd.c index d40756e0b4..dd26b0af9c 100644 --- a/usr/src/uts/common/fs/portfs/port_fd.c +++ b/usr/src/uts/common/fs/portfs/port_fd.c @@ -285,7 +285,7 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events, * Remove any events that where already fired * for this fd and are still in the port queue. */ - port_remove_done_event(pkevp); + (void) port_remove_done_event(pkevp); } else { mutex_exit(&pkevp->portkev_lock); } diff --git a/deleted_files/usr/src/uts/common/fs/portfs/port_fop.c b/usr/src/uts/common/fs/portfs/port_fop.c index d7ccf8253f..8e07046236 100644 --- a/deleted_files/usr/src/uts/common/fs/portfs/port_fop.c +++ b/usr/src/uts/common/fs/portfs/port_fop.c @@ -80,7 +80,7 @@ * After an event is delivered, the file events watch gets de-activated. To * receive the next event, the process will have to re-register the watch and * activate it by calling port_associate() again. This behavior is intentional - * and support proper multi threaded programming when using file events + * and supports proper multi threaded programming when using file events * notification API. * * @@ -88,19 +88,19 @@ * ------------------------ * * Each file events watch is represented by 'portfop_t' in the kernel. A - * cache(portfop_cache_t) of these file portfop_t's are maintained per event + * cache(in portfop_cache_t) of these portfop_t's are maintained per event * port by this source. The object here is the pointer to the file_obj * structure. The portfop_t's are hashed in using the object pointer. Therefore - * it is possible to have multiple file event watches on a file by the same + * it is possible to have multiple file events watches on a file by the same * process by using different object structure(file_obj_t) and hence can * receive multiple event notification for a file. These watches can be for * different event types. * * The cached entries of these file objects are retained, even after delivering - * an event makring them inactive, for performance reason. The assumption + * an event, marking them inactive for performance reasons. The assumption * is that the process would come back and re-register the file to receive * further events. When there are more then 'port_fop_maxpfps' watches per file - * it will attempt to free the oldest inactive watch. + * it will attempt to free the oldest inactive watches. * * In case the event that is being delivered is an exception event, the cached * entries get removed. An exception event on a file or directory means its @@ -116,7 +116,7 @@ * * The list of file event watches per file are managed by the data structure * portfop_vp_t. The first time a file events watch is registered for a file, - * the portfop_vp_t is installed on the vnode_t's member v_fopdata. This gets + * a portfop_vp_t is installed on the vnode_t's member v_fopdata. This gets * removed and freed only when the vnode becomes inactive. The FEM hooks are * also installed when the first watch is registered on a file. The FEM hooks * get un-installed when all the watches are removed. @@ -139,7 +139,7 @@ * File system support: * ------------------- * - * The file systems implementation has to provide vnode event notifications + * The file system implementation has to provide vnode event notifications * (vnevents) in order to support watching any files on that file system. * The vnode events(vnevents) are notifications provided by the file system * for name based file operations like rename, remove etc, which do not go @@ -176,9 +176,9 @@ #include <sys/atomic.h> /* - * For special case support of /etc/mnttab + * For special case support of mnttab (/etc/mnttab). */ -extern struct vnode *mntdummyvp; +extern struct vnode *vfs_mntdummyvp; extern int mntfstype; #define PORTFOP_PVFSH(vfsp) (&portvfs_hash[PORTFOP_PVFSHASH(vfsp)]) @@ -1168,13 +1168,14 @@ port_resolve_vp(vnode_t *vp) { vnode_t *rvp; /* - * special case /etc/mnttab, the only mntfs type - * file that can exist. + * special case /etc/mnttab(mntfs type). The mntfstype != 0 + * if mntfs got mounted. */ - if (mntdummyvp && vp->v_vfsp->vfs_fstype == mntfstype) { + if (vfs_mntdummyvp && mntfstype != 0 && + vp->v_vfsp->vfs_fstype == mntfstype) { VN_RELE(vp); - vp = mntdummyvp; - VN_HOLD(mntdummyvp); + vp = vfs_mntdummyvp; + VN_HOLD(vfs_mntdummyvp); } /* @@ -1369,7 +1370,7 @@ port_associate_fop(port_t *pp, int source, uintptr_t object, int events, pfp->pfop_events = events; /* - * check if this pfp is being removed. Port_fop_excep() + * check if this pfp is being removed. port_fop_excep() * will deliver an exception event. */ if (pfp->pfop_flags & PORT_FOP_REMOVING) { @@ -1788,14 +1789,14 @@ port_fop_sendevent(vnode_t *vp, int events, vnode_t *dvp, char *cname) mutex_exit(&pvp->pvp_mutex); /* - * contain the list size. + * trim the list. */ port_fop_trimpfplist(vp); } } /* - * Given the file operation, map it to the events types and send. + * Given the file operation, map it to the event types and send. */ void port_fop(vnode_t *vp, int op, int retval) @@ -1971,9 +1972,7 @@ port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr, if (vap->va_mask & AT_ATIME) { events |= FOP_FILE_SETATTR_ATIME; } - if (vap->va_mask & (AT_SIZE|AT_CTIME)) { - events |= FOP_FILE_SETATTR_CTIME; - } + events |= FOP_FILE_SETATTR_CTIME; port_fop(vp, events, retval); return (retval); @@ -1993,11 +1992,13 @@ port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl, * modification time of the directory to determine if the * file was actually created. */ + vatt.va_mask = AT_ATIME|AT_MTIME|AT_CTIME; if (VOP_GETATTR(vp, &vatt, 0, CRED())) { got = 0; } retval = vnext_create(vf, name, vap, excl, mode, vpp, cr, flag); + vatt1.va_mask = AT_ATIME|AT_MTIME|AT_CTIME; if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED())) { if ((vatt1.va_mtime.tv_sec > vatt.va_mtime.tv_sec || (vatt1.va_mtime.tv_sec = vatt.va_mtime.tv_sec && diff --git a/usr/src/uts/common/fs/tmpfs/tmp_dir.c b/usr/src/uts/common/fs/tmpfs/tmp_dir.c index de405078c3..682cac326b 100644 --- a/usr/src/uts/common/fs/tmpfs/tmp_dir.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_dir.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -345,8 +344,12 @@ tdirenter( error = tdirrename(fromparent, tp, dir, name, found, tdp, cred); if (error == 0) { - vnevent_rename_dest(TNTOV(found)); + if (found != NULL) { + vnevent_rename_dest(TNTOV(found), + TNTOV(dir), name); + } } + tmpnode_rele(found); break; @@ -402,9 +405,6 @@ tdirenter( } } - if ((op == DE_RENAME) && (error == 0)) { - vnevent_rename_src(TNTOV(tp)); - } out: if (error && (op == DE_LINK || op == DE_RENAME)) { /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c index 8932732a29..c2d921bba9 100644 --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c @@ -975,6 +975,10 @@ again: } *vpp = newvp; } + + if (error == 0) { + vnevent_create(*vpp); + } return (0); } @@ -1043,7 +1047,7 @@ tmp_remove(struct vnode *dvp, char *nm, struct cred *cred) rw_exit(&tp->tn_rwlock); rw_exit(&parent->tn_rwlock); - vnevent_remove(TNTOV(tp)); + vnevent_remove(TNTOV(tp), dvp, nm); tmpnode_rele(tp); TRACE_3(TR_FAC_TMPFS, TR_TMPFS_REMOVE, @@ -1093,6 +1097,9 @@ tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred) error = tdirenter(tm, parent, tnm, DE_LINK, (struct tmpnode *)NULL, from, NULL, (struct tmpnode **)NULL, cred); rw_exit(&parent->tn_rwlock); + if (error == 0) { + vnevent_link(srcvp); + } return (error); } @@ -1184,6 +1191,15 @@ tmp_rename( error = 0; goto done; } + vnevent_rename_src(TNTOV(fromtp), odvp, onm); + + /* + * Notify the target directory if not same as + * source directory. + */ + if (ndvp != odvp) { + vnevent_rename_dest_dir(ndvp); + } /* * Unlink from source. @@ -1338,7 +1354,7 @@ done: done1: rw_exit(&self->tn_rwlock); rw_exit(&parent->tn_rwlock); - vnevent_rmdir(TNTOV(self)); + vnevent_rmdir(TNTOV(self), dvp, nm); tmpnode_rele(self); return (error); diff --git a/usr/src/uts/common/fs/udfs/udf_dir.c b/usr/src/uts/common/fs/udfs/udf_dir.c index d97a80bb40..d470a2588a 100644 --- a/usr/src/uts/common/fs/udfs/udf_dir.c +++ b/usr/src/uts/common/fs/udfs/udf_dir.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -556,9 +555,13 @@ out: */ if (err == 0) { if (tip) { - vnevent_rename_dest(ITOV(tip)); + vnevent_rename_dest(ITOV(tip), ITOV(tdp), + namep); + } + + if (sdp != tdp) { + vnevent_rename_dest_dir(ITOV(tdp)); } - vnevent_rename_src(ITOV(sip)); } /* @@ -849,9 +852,9 @@ out_novfs: */ if (err == 0) { if (op == DR_REMOVE) { - vnevent_remove(ITOV(ip)); + vnevent_remove(ITOV(ip), ITOV(dp), namep); } else if (op == DR_RMDIR) { - vnevent_rmdir(ITOV(ip)); + vnevent_rmdir(ITOV(ip), ITOV(dp), namep); } } VN_RELE(ITOV(ip)); diff --git a/usr/src/uts/common/fs/udfs/udf_vnops.c b/usr/src/uts/common/fs/udfs/udf_vnops.c index b67d80c394..defbd544f5 100644 --- a/usr/src/uts/common/fs/udfs/udf_vnops.c +++ b/usr/src/uts/common/fs/udfs/udf_vnops.c @@ -732,6 +732,7 @@ udf_create(struct vnode *dvp, (void) ud_itrunc(ip, 0, 0, cr); rw_exit(&ip->i_rwlock); } + vnevent_create(ITOV(ip)); } } @@ -820,6 +821,10 @@ udf_link(struct vnode *tdvp, ITIMES(sip); ITIMES(tdp); + if (error == 0) { + vnevent_link(svp); + } + return (error); } @@ -913,6 +918,7 @@ udf_rename(struct vnode *sdvp, rw_exit(&tdp->i_rwlock); goto errout; } + vnevent_rename_src(ITOV(sip), sdvp, snm); rw_exit(&tdp->i_rwlock); rw_enter(&sdp->i_rwlock, RW_WRITER); diff --git a/usr/src/uts/common/fs/ufs/ufs_vnops.c b/usr/src/uts/common/fs/ufs/ufs_vnops.c index fe903b11e9..414aa037c4 100644 --- a/usr/src/uts/common/fs/ufs/ufs_vnops.c +++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c @@ -2985,6 +2985,10 @@ again: cr); rw_exit(&ip->i_rwlock); } + + } + if (error == 0) { + vnevent_create(ITOV(ip)); } } } @@ -3131,7 +3135,7 @@ retry_remove: if (rmvp != NULL) { /* Only send the event if there were no errors */ if (error == 0) - vnevent_remove(rmvp); + vnevent_remove(rmvp, vp, nm); VN_RELE(rmvp); } out: @@ -3210,6 +3214,10 @@ unlock: TRANS_END_CSYNC(ufsvfsp, error, issync, TOP_LINK, trans_size); ufs_lockfs_end(ulp); } + + if (!error) { + vnevent_link(svp); + } out: return (error); } @@ -3590,14 +3598,22 @@ unlock: */ if (error == 0) { if (tvp != NULL) - vnevent_rename_dest(tvp); + vnevent_rename_dest(tvp, tdvp, tnm); + + /* + * Notify the target directory of the rename event + * if source and target directories are not same. + */ + if (sdvp != tdvp) + vnevent_rename_dest_dir(tdvp); + /* * Note that if ufs_direnter_lr() returned ESAME then * this event will still be sent. This isn't expected * to be a problem for anticipated usage by consumers. */ if (sip != NULL) - vnevent_rename_src(ITOV(sip)); + vnevent_rename_src(ITOV(sip), sdvp, snm); } if (tvp != NULL) @@ -3743,7 +3759,7 @@ retry_rmdir: if (rmvp != NULL) { /* Only send the event if there were no errors */ if (error == 0) - vnevent_rmdir(rmvp); + vnevent_rmdir(rmvp, vp, nm); VN_RELE(rmvp); } out: diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c index c00879da35..f7b38950f8 100644 --- a/usr/src/uts/common/fs/vfs.c +++ b/usr/src/uts/common/fs/vfs.c @@ -108,6 +108,7 @@ static char **vfs_copycancelopt_extend(char **const, int); static void vfs_freecancelopt(char **); static char *getrootfs(void); static int getmacpath(dev_info_t *, void *); +static void vfs_mnttabvp_setup(void); struct ipmnt { struct ipmnt *mip_next; @@ -140,6 +141,8 @@ timespec_t vfs_mnttab_ctime; /* mnttab created time */ timespec_t vfs_mnttab_mtime; /* mnttab last modified time */ char *vfs_dummyfstype = "\0"; struct pollhead vfs_pollhd; /* for mnttab pollers */ +struct vnode *vfs_mntdummyvp; /* to fake mnttab read/write for file events */ +int mntfstype; /* will be set once mnt fs is mounted */ /* * Table for generic options recognized in the VFS layer and acted @@ -916,6 +919,7 @@ vfs_mountroot(void) #endif } kmem_free(path, plen + MAXPATHLEN); + vfs_mnttabvp_setup(); } /* @@ -1437,6 +1441,10 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp, vfs_setresource(vfsp, resource); vfs_setmntpoint(vfsp, mountpt); + /* + * going to mount on this vnode, so notify. + */ + vnevent_mountedover(vp); error = VFS_MOUNT(vfsp, vp, uap, credp); if (uap->flags & MS_RDONLY) @@ -2566,6 +2574,132 @@ vfs_freeopttbl(mntopts_t *mp) } } + +/* ARGSUSED */ +static int +vfs_mntdummyread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, + caller_context_t *ct) +{ + return (0); +} + +/* ARGSUSED */ +static int +vfs_mntdummywrite(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, + caller_context_t *ct) +{ + return (0); +} + +/* + * The dummy vnode is currently used only by file events notification + * module which is just interested in the timestamps. + */ +/* ARGSUSED */ +static int +vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) +{ + bzero(vap, sizeof (vattr_t)); + vap->va_type = VREG; + vap->va_nlink = 1; + vap->va_ctime = vfs_mnttab_ctime; + /* + * it is ok to just copy mtime as the time will be monotonically + * increasing. + */ + vap->va_mtime = vfs_mnttab_mtime; + vap->va_atime = vap->va_mtime; + return (0); +} + +static void +vfs_mnttabvp_setup(void) +{ + vnode_t *tvp; + vnodeops_t *vfs_mntdummyvnops; + const fs_operation_def_t mnt_dummyvnodeops_template[] = { + VOPNAME_READ, { .vop_read = vfs_mntdummyread }, + VOPNAME_WRITE, { .vop_write = vfs_mntdummywrite }, + VOPNAME_GETATTR, { .vop_getattr = vfs_mntdummygetattr }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, + NULL, NULL + }; + + if (vn_make_ops("mnttab", mnt_dummyvnodeops_template, + &vfs_mntdummyvnops) != 0) { + cmn_err(CE_WARN, "vfs_mnttabvp_setup: vn_make_ops failed"); + /* Shouldn't happen, but not bad enough to panic */ + return; + } + + /* + * A global dummy vnode is allocated to represent mntfs files. + * The mntfs file (/etc/mnttab) can be monitored for file events + * and receive an event when mnttab changes. Dummy VOP calls + * will be made on this vnode. The file events notification module + * intercepts this vnode and delivers relevant events. + */ + tvp = vn_alloc(KM_SLEEP); + tvp->v_flag = VNOMOUNT|VNOMAP|VNOSWAP|VNOCACHE; + vn_setops(tvp, vfs_mntdummyvnops); + tvp->v_type = VREG; + /* + * The mnt dummy ops do not reference v_data. + * No other module intercepting this vnode should either. + * Just set it to point to itself. + */ + tvp->v_data = (caddr_t)tvp; + tvp->v_vfsp = rootvfs; + vfs_mntdummyvp = tvp; +} + +/* + * performs fake read/write ops + */ +static void +vfs_mnttab_rwop(int rw) +{ + struct uio uio; + struct iovec iov; + char buf[1]; + + if (vfs_mntdummyvp == NULL) + return; + + bzero(&uio, sizeof (uio)); + bzero(&iov, sizeof (iov)); + iov.iov_base = buf; + iov.iov_len = 0; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_loffset = 0; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_resid = 0; + if (rw) { + (void) VOP_WRITE(vfs_mntdummyvp, &uio, 0, kcred, NULL); + } else { + (void) VOP_READ(vfs_mntdummyvp, &uio, 0, kcred, NULL); + } +} + +/* + * Generate a write operation. + */ +void +vfs_mnttab_writeop(void) +{ + vfs_mnttab_rwop(1); +} + +/* + * Generate a read operation. + */ +void +vfs_mnttab_readop(void) +{ + vfs_mnttab_rwop(0); +} + /* * Free any mnttab information recorded in the vfs struct. * The vfs must not be on the vfs list. @@ -2649,6 +2783,7 @@ vfs_mnttab_modtimeupd() hrt2ts(newhrt, &vfs_mnttab_mtime); } pollwakeup(&vfs_pollhd, (short)POLLRDBAND); + vfs_mnttab_writeop(); } int diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c index 7129cfead9..55813947ec 100644 --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -89,6 +89,9 @@ static vopstats_t *vs_templatep; /* Kmem cache handle for vsk_anchor_t allocations */ kmem_cache_t *vsk_anchor_cache; +/* file events cleanup routine */ +extern void free_fopdata(vnode_t *); + /* * Root of AVL tree for the kstats associated with vopstats. Lock protects * updates to vsktat_tree. @@ -1988,10 +1991,10 @@ vn_cache_constructor(void *buf, void *cdrarg, int kmflags) cv_init(&vp->v_cv, NULL, CV_DEFAULT, NULL); rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL); rw_init(&vp->v_mslock, NULL, RW_DEFAULT, NULL); - vp->v_femhead = NULL; /* Must be done before vn_reinit() */ vp->v_path = NULL; vp->v_mpssdata = NULL; + vp->v_fopdata = NULL; return (0); } @@ -2058,6 +2061,10 @@ vn_recycle(vnode_t *vp) kmem_free(vp->v_path, strlen(vp->v_path) + 1); vp->v_path = NULL; } + + if (vp->v_fopdata != NULL) { + free_fopdata(vp); + } vp->v_mpssdata = NULL; } @@ -2110,6 +2117,7 @@ vn_alloc(int kmflag) if (vp != NULL) { vp->v_femhead = NULL; /* Must be done before vn_reinit() */ + vp->v_fopdata = NULL; vn_reinit(vp); } @@ -2138,6 +2146,10 @@ vn_free(vnode_t *vp) kmem_free(vp->v_femhead, sizeof (*(vp->v_femhead))); vp->v_femhead = NULL; } + + if (vp->v_fopdata != NULL) { + free_fopdata(vp); + } vp->v_mpssdata = NULL; kmem_cache_free(vn_cache, vp); } @@ -2200,43 +2212,79 @@ vnevent_support(vnode_t *vp) if (vp == NULL) return (EINVAL); - return (VOP_VNEVENT(vp, VE_SUPPORT)); + return (VOP_VNEVENT(vp, VE_SUPPORT, NULL, NULL)); +} + +void +vnevent_rename_src(vnode_t *vp, vnode_t *dvp, char *name) +{ + if (vp == NULL || vp->v_femhead == NULL) { + return; + } + (void) VOP_VNEVENT(vp, VE_RENAME_SRC, dvp, name); +} + +void +vnevent_rename_dest(vnode_t *vp, vnode_t *dvp, char *name) +{ + if (vp == NULL || vp->v_femhead == NULL) { + return; + } + (void) VOP_VNEVENT(vp, VE_RENAME_DEST, dvp, name); +} + +void +vnevent_rename_dest_dir(vnode_t *vp) +{ + if (vp == NULL || vp->v_femhead == NULL) { + return; + } + (void) VOP_VNEVENT(vp, VE_RENAME_DEST_DIR, NULL, NULL); +} + +void +vnevent_remove(vnode_t *vp, vnode_t *dvp, char *name) +{ + if (vp == NULL || vp->v_femhead == NULL) { + return; + } + (void) VOP_VNEVENT(vp, VE_REMOVE, dvp, name); } void -vnevent_rename_src(vnode_t *vp) +vnevent_rmdir(vnode_t *vp, vnode_t *dvp, char *name) { if (vp == NULL || vp->v_femhead == NULL) { return; } - (void) VOP_VNEVENT(vp, VE_RENAME_SRC); + (void) VOP_VNEVENT(vp, VE_RMDIR, dvp, name); } void -vnevent_rename_dest(vnode_t *vp) +vnevent_create(vnode_t *vp) { if (vp == NULL || vp->v_femhead == NULL) { return; } - (void) VOP_VNEVENT(vp, VE_RENAME_DEST); + (void) VOP_VNEVENT(vp, VE_CREATE, NULL, NULL); } void -vnevent_remove(vnode_t *vp) +vnevent_link(vnode_t *vp) { if (vp == NULL || vp->v_femhead == NULL) { return; } - (void) VOP_VNEVENT(vp, VE_REMOVE); + (void) VOP_VNEVENT(vp, VE_LINK, NULL, NULL); } void -vnevent_rmdir(vnode_t *vp) +vnevent_mountedover(vnode_t *vp) { if (vp == NULL || vp->v_femhead == NULL) { return; } - (void) VOP_VNEVENT(vp, VE_RMDIR); + (void) VOP_VNEVENT(vp, VE_MOUNTEDOVER, NULL, NULL); } /* @@ -3558,11 +3606,11 @@ fop_shrlock( } int -fop_vnevent(vnode_t *vp, vnevent_t vnevent) +fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm) { int err; - err = (*(vp)->v_op->vop_vnevent)(vp, vnevent); + err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm); VOPSTATS_UPDATE(vp, vnevent); return (err); } diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c index 61e6c8f483..852555b7f3 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -1165,6 +1165,10 @@ top: VN_RELE(ZTOV(zp)); goto top; } + + if (error == 0) { + vnevent_create(ZTOV(zp)); + } } } out: @@ -1250,7 +1254,7 @@ top: goto out; } - vnevent_remove(vp); + vnevent_remove(vp, dvp, name); dnlc_remove(dvp, name); @@ -1513,7 +1517,7 @@ top: goto out; } - vnevent_rmdir(vp); + vnevent_rmdir(vp, dvp, name); /* * Grab a lock on the directory to make sure that noone is @@ -2433,9 +2437,17 @@ top: } } - vnevent_rename_src(ZTOV(szp)); + vnevent_rename_src(ZTOV(szp), sdvp, snm); if (tzp) - vnevent_rename_dest(ZTOV(tzp)); + vnevent_rename_dest(ZTOV(tzp), tdvp, tnm); + + /* + * notify the target directory if it is not the same + * as source directory. + */ + if (tdvp != sdvp) { + vnevent_rename_dest_dir(tdvp); + } tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_bonus(tx, szp->z_id); /* nlink changes */ @@ -2768,6 +2780,10 @@ top: zfs_dirent_unlock(dl); + if (error == 0) { + vnevent_link(svp); + } + ZFS_EXIT(zfsvfs); return (error); } @@ -3701,6 +3717,7 @@ const fs_operation_def_t zfs_dvnodeops_template[] = { VOPNAME_PATHCONF, { .vop_pathconf = zfs_pathconf }, VOPNAME_GETSECATTR, { .vop_getsecattr = zfs_getsecattr }, VOPNAME_SETSECATTR, { .vop_setsecattr = zfs_setsecattr }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, NULL, NULL }; diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h index db7814a07c..ef4365b9d0 100644 --- a/usr/src/uts/common/nfs/nfs4.h +++ b/usr/src/uts/common/nfs/nfs4.h @@ -919,7 +919,7 @@ extern int deleg_setattr(femarg_t *, vattr_t *, int, cred_t *, extern int deleg_space(femarg_t *, int, flock64_t *, int, offset_t, cred_t *, caller_context_t *); extern int deleg_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *); -extern int deleg_vnevent(femarg_t *, vnevent_t); +extern int deleg_vnevent(femarg_t *, vnevent_t, vnode_t *, char *); extern void rfs4_mon_hold(void *); extern void rfs4_mon_rele(void *); diff --git a/usr/src/uts/common/os/port_subr.c b/usr/src/uts/common/os/port_subr.c index 11a701a78a..ab73f2dd61 100644 --- a/usr/src/uts/common/os/port_subr.c +++ b/usr/src/uts/common/os/port_subr.c @@ -197,7 +197,7 @@ port_send_event(port_kevent_t *pkevp) * ports if being polled. */ if (pkevp->portkev_source != PORT_SOURCE_FD && - portq->portq_flags & PORTQ_POLLIN) { + portq->portq_flags & PORTQ_POLLIN) { portq->portq_flags &= ~PORTQ_POLLIN; mutex_exit(&portq->portq_mutex); pollwakeup(&pkevp->portkev_port->port_pollhd, POLLIN); @@ -390,10 +390,11 @@ port_remove_event_doneq(port_kevent_t *pkevp, port_queue_t *portq) * Currently this function is required to cancel a fired event because * the application is delivering new association data (see port_associate_fd()). */ -void +int port_remove_done_event(port_kevent_t *pkevp) { port_queue_t *portq; + int removed = 0; portq = &pkevp->portkev_port->port_queue; mutex_enter(&portq->portq_mutex); @@ -411,9 +412,11 @@ port_remove_done_event(port_kevent_t *pkevp) } /* now remove event from the port queue */ port_remove_event_doneq(pkevp, portq); + removed = 1; } port_unblock(portq); mutex_exit(&portq->portq_mutex); + return (removed); } /* @@ -777,3 +780,15 @@ port_dissociate_ksource(int port, int source, port_source_t *ps) releasef(port); return (0); } + +void +free_fopdata(vnode_t *vp) +{ + portfop_vp_t *pvp; + pvp = vp->v_fopdata; + ASSERT(pvp->pvp_femp == NULL); + mutex_destroy(&pvp->pvp_mutex); + list_destroy(&pvp->pvp_pfoplist); + kmem_free(pvp, sizeof (*pvp)); + vp->v_fopdata = NULL; +} diff --git a/usr/src/uts/common/sys/fem.h b/usr/src/uts/common/sys/fem.h index 04afc1466d..2816734291 100644 --- a/usr/src/uts/common/sys/fem.h +++ b/usr/src/uts/common/sys/fem.h @@ -233,7 +233,9 @@ struct fem_head { int flag, cred_t *cr); \ int (*femop_shrlock)(femarg_t *vf, int cmd, \ struct shrlock *shr, int flag, cred_t *cr); \ - int (*femop_vnevent)(femarg_t *vf, vnevent_t vnevent) /* NB: No ";" */ + int (*femop_vnevent)(femarg_t *vf, vnevent_t vnevent, \ + vnode_t *dvp, char *cname) + /* NB: No ";" */ struct fem { const char *name; @@ -340,7 +342,8 @@ extern int vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr); extern int vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag, cred_t *cr); -extern int vnext_vnevent(femarg_t *vf, vnevent_t vevent); +extern int vnext_vnevent(femarg_t *vf, vnevent_t vevent, vnode_t *dvp, + char *cname); extern int vfsnext_mount(fsemarg_t *vf, vnode_t *mvp, struct mounta *uap, cred_t *cr); diff --git a/usr/src/uts/common/sys/port.h b/usr/src/uts/common/sys/port.h index a0ed65ffce..ccb0308255 100644 --- a/usr/src/uts/common/sys/port.h +++ b/usr/src/uts/common/sys/port.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,6 +42,7 @@ extern "C" { #define PORT_SOURCE_FD 4 #define PORT_SOURCE_ALERT 5 #define PORT_SOURCE_MQ 6 +#define PORT_SOURCE_FILE 7 typedef struct port_event { int portev_events; /* event data is source specific */ @@ -57,8 +58,24 @@ typedef struct port_notify { } port_notify_t; +typedef struct file_obj { + timestruc_t fo_atime; /* Access time from stat(2) */ + timestruc_t fo_mtime; /* Modification time from stat(2) */ + timestruc_t fo_ctime; /* Change time from stat(2) */ + uintptr_t fo_pad[3]; /* For future expansion */ + char *fo_name; /* Null terminated file name */ +} file_obj_t; + #if defined(_SYSCALL32) +typedef struct file_obj32 { + timestruc32_t fo_atime; /* Access time got from stat(2) */ + timestruc32_t fo_mtime; /* Modification time from stat(2) */ + timestruc32_t fo_ctime; /* Change time from stat(2) */ + caddr32_t fo_pad[3]; /* For future expansion */ + caddr32_t fo_name; /* Null terminated file name */ +} file_obj32_t; + typedef struct port_event32 { int portev_events; /* events detected */ ushort_t portev_source; /* user, timer, aio, etc */ @@ -79,6 +96,45 @@ typedef struct port_notify32 { #define PORT_ALERT_UPDATE 0x02 #define PORT_ALERT_INVALID (PORT_ALERT_SET | PORT_ALERT_UPDATE) +/* + * PORT_SOURCE_FILE - events + */ + +/* + * User watchable file events + */ +#define FILE_ACCESS 0x00000001 +#define FILE_MODIFIED 0x00000002 +#define FILE_ATTRIB 0x00000004 +#define FILE_NOFOLLOW 0x10000000 + +/* + * exception file events + */ + +/* + * The watched file.. + */ +#define FILE_DELETE 0x00000010 +#define FILE_RENAME_TO 0x00000020 +#define FILE_RENAME_FROM 0x00000040 +/* + * The filesystem on which the watched file resides got + * unmounted. + */ +#define UNMOUNTED 0x20000000 +/* + * Some other file/filesystem got mounted over the + * watched file/directory. + */ +#define MOUNTEDOVER 0x40000000 + +/* + * Helper type + */ +#define FILE_EXCEPTION (UNMOUNTED|FILE_DELETE|FILE_RENAME_TO \ + |FILE_RENAME_FROM|MOUNTEDOVER) + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/port_impl.h b/usr/src/uts/common/sys/port_impl.h index a80e7afc84..e463e47a6e 100644 --- a/usr/src/uts/common/sys/port_impl.h +++ b/usr/src/uts/common/sys/port_impl.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,7 @@ extern "C" { #include <sys/port.h> #include <sys/port_kernel.h> #include <sys/vnode.h> +#include <sys/fem.h> /* * port system call codes @@ -212,6 +213,138 @@ typedef struct portfd { (&(pcp)->pc_hash[((fd) % (pcp)->pc_hashsize)]) /* + * PORT_SOURCE_FILE -- File Events Notification sources + */ +#define PORT_FOP_BUCKET(pcp, id) \ + (portfop_t **)(&(pcp)->pfc_hash[(((ulong_t)id >> 8) & \ + (PORTFOP_HASHSIZE - 1))]) + +/* + * This structure is used to register a file object to be watched. + * + * The pfop_flags are protected by the vnode's pvp_mutex lock. + * The pfop list (vnode's list) is protected by the pvp_mutex when it is on + * the vnode's list. + * + * All the rest of the fields are protected by the port's source cache lock + * pfcp_lock. + */ +typedef struct portfop { + int pfop_events; + int pfop_flags; /* above flags. */ + uintptr_t pfop_object; /* object address */ + vnode_t *pfop_vp; + vnode_t *pfop_dvp; + port_t *pfop_pp; + fem_t *pfop_fem; + list_node_t pfop_node; /* list of pfop's per vnode */ + struct portfop *pfop_hashnext; /* hash list */ + pid_t pfop_pid; /* owner of portfop */ + struct portfop_cache *pfop_pcache; + port_kevent_t *pfop_pev; /* event pointers */ + char *pfop_cname; /* file component name */ + int pfop_clen; +} portfop_t; + +/* + * pfop_flags + */ +#define PORT_FOP_ACTIVE 0x1 +#define PORT_FOP_REMOVING 0x2 +#define PORT_FOP_KEV_ONQ 0x4 + +typedef struct portfop_vfs { + vfs_t *pvfs; + int pvfs_unmount; /* 1 if unmount in progress */ + list_t pvfs_pvplist; /* list of vnodes from */ + fsem_t *pvfs_fsemp; + struct portfop_vfs *pvfs_next; /* hash list */ +} portfop_vfs_t; + +typedef struct portfop_vfs_hash { + kmutex_t pvfshash_mutex; + struct portfop_vfs *pvfshash_pvfsp; +} portfop_vfs_hash_t; + +typedef struct portfop_vp { + vnode_t *pvp_vp; + kmutex_t pvp_mutex; + int pvp_cnt; /* number of watches */ + list_t pvp_pfoplist; + list_node_t pvp_pvfsnode; + struct portfop *pvp_lpfop; /* oldest pfop */ + fem_t *pvp_femp; + struct portfop_vfs *pvp_pvfsp; +} portfop_vp_t; + +#define PORTFOP_PVFSHASH_SZ 256 +#define PORTFOP_PVFSHASH(vfsp) (((uintptr_t)(vfsp) >> 4) % PORTFOP_PVFSHASH_SZ) + +/* + * file operations flag. + */ + +/* + * PORT_SOURCE_FILE - vnode operations + */ + +#define FOP_FILE_OPEN 0x00000001 +#define FOP_FILE_READ 0x00000002 +#define FOP_FILE_WRITE 0x00000004 +#define FOP_FILE_MAP 0x00000008 +#define FOP_FILE_IOCTL 0x00000010 +#define FOP_FILE_CREATE 0x00000020 +#define FOP_FILE_MKDIR 0x00000040 +#define FOP_FILE_SYMLINK 0x00000080 +#define FOP_FILE_LINK 0x00000100 +#define FOP_FILE_RENAME 0x00000200 +#define FOP_FILE_REMOVE 0x00000400 +#define FOP_FILE_RMDIR 0x00000800 +#define FOP_FILE_READDIR 0x00001000 +#define FOP_FILE_RENAMESRC 0x00002000 +#define FOP_FILE_RENAMEDST 0x00004000 +#define FOP_FILE_REMOVEFILE 0x00008000 +#define FOP_FILE_REMOVEDIR 0x00010000 +#define FOP_FILE_SETSECATTR 0x00020000 +#define FOP_FILE_SETATTR_ATIME 0x00040000 +#define FOP_FILE_SETATTR_MTIME 0x00080000 +#define FOP_FILE_SETATTR_CTIME 0x00100000 +#define FOP_FILE_LINK_SRC 0x00200000 + +/* + * File modification event. + */ +#define FOP_MODIFIED_MASK (FOP_FILE_WRITE|FOP_FILE_CREATE \ + |FOP_FILE_REMOVE|FOP_FILE_LINK \ + |FOP_FILE_RENAMESRC|FOP_FILE_RENAMEDST \ + |FOP_FILE_MKDIR|FOP_FILE_RMDIR \ + |FOP_FILE_SYMLINK|FOP_FILE_SETATTR_MTIME) + +/* + * File access event + */ +#define FOP_ACCESS_MASK (FOP_FILE_READ|FOP_FILE_READDIR \ + |FOP_FILE_MAP|FOP_FILE_SETATTR_ATIME) + +/* + * File attrib event + */ +#define FOP_ATTRIB_MASK (FOP_FILE_WRITE|FOP_FILE_CREATE \ + |FOP_FILE_REMOVE|FOP_FILE_LINK \ + |FOP_FILE_RENAMESRC|FOP_FILE_RENAMEDST \ + |FOP_FILE_MKDIR|FOP_FILE_RMDIR \ + |FOP_FILE_SYMLINK|FOP_FILE_SETATTR_CTIME \ + |FOP_FILE_LINK_SRC|FOP_FILE_SETSECATTR) + + +/* + * valid watchable events + */ +#define FILE_EVENTS_MASK (FILE_ACCESS|FILE_MODIFIED|FILE_ATTRIB \ + |FILE_NOFOLLOW) +/* --- End file events --- */ + +/* * port_kstat_t contains the event port kernel values which are * exported to kstat. * Currently only the number of active ports is exported. @@ -223,7 +356,7 @@ typedef struct port_kstat { /* misc functions */ int port_alloc_event_block(port_t *, int, int, struct port_kevent **); void port_push_eventq(port_queue_t *); -void port_remove_done_event(struct port_kevent *); +int port_remove_done_event(struct port_kevent *); struct port_kevent *port_get_kevent(list_t *, struct port_kevent *); void port_block(port_queue_t *); void port_unblock(port_queue_t *); diff --git a/usr/src/uts/common/sys/port_kernel.h b/usr/src/uts/common/sys/port_kernel.h index bfc65586fc..7456f63573 100644 --- a/usr/src/uts/common/sys/port_kernel.h +++ b/usr/src/uts/common/sys/port_kernel.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -98,12 +98,29 @@ typedef struct port_source { int portsrc_cnt; /* # of associations */ void (*portsrc_close)(void *, int, pid_t, int); void *portsrc_closearg; /* callback arg */ + void *portsrc_data; /* Private data of source */ struct port_source *portsrc_next; struct port_source *portsrc_prev; } port_source_t; /* + * PORT_SOURCE_FILE cache structure. + */ +#define PORTFOP_HASHSIZE 256 /* cache space for fop events */ + +/* + * One cache for each port that uses PORT_SOURCE_FILE. + */ +typedef struct portfop_cache { + kmutex_t pfc_lock; /* lock to protect cache */ + kcondvar_t pfc_lclosecv; /* last close cv */ + int pfc_objcount; /* track how many file obj are hashed */ + struct portfop *pfc_hash[PORTFOP_HASHSIZE]; /* hash table */ +} portfop_cache_t; + +/* + * PORT_SOURCE_FD cache per port. * One cache for each port that uses PORT_SOURCE_FD. * pc_lock must be the first element of port_fdcache_t to keep it * synchronized with the offset of pc_lock in pollcache_t (see pollrelock()). @@ -147,6 +164,8 @@ void port_init_event(port_kevent_t *, uintptr_t, void *, int port_dup_event(port_kevent_t *, port_kevent_t **, int); int port_associate_fd(struct port *, int, uintptr_t, int, void *); int port_dissociate_fd(struct port *, uintptr_t); +int port_associate_fop(struct port *, int, uintptr_t, int, void *); +int port_dissociate_fop(struct port *, uintptr_t); /* misc functions */ void port_free_event_local(port_kevent_t *, int counter); diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h index d2494e013e..8eaf4b7fc9 100644 --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -248,6 +248,7 @@ typedef struct vnode { struct vnode *v_msnext; /* list of vnodes on an mset */ struct vnode *v_msprev; /* list of vnodes on an mset */ krwlock_t v_mslock; /* protects v_mset */ + void *v_fopdata; /* list of file ops event watches */ } vnode_t; #define IS_DEVVP(vp) \ @@ -465,7 +466,11 @@ typedef enum vnevent { VE_RENAME_SRC = 1, /* Rename, with vnode as source */ VE_RENAME_DEST = 2, /* Rename, with vnode as target/destination */ VE_REMOVE = 3, /* Remove of vnode's name */ - VE_RMDIR = 4 /* Remove of directory vnode's name */ + VE_RMDIR = 4, /* Remove of directory vnode's name */ + VE_CREATE = 5, /* Create with vnode's name which exists */ + VE_LINK = 6, /* Link with vnode's name as source */ + VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */ + VE_MOUNTEDOVER = 8 /* File or Filesystem got mounted over vnode */ } vnevent_t; /* @@ -606,7 +611,8 @@ struct pollhead; int, cred_t *); \ int (*vop_shrlock)(vnode_t *, int, struct shrlock *, \ int, cred_t *); \ - int (*vop_vnevent)(vnode_t *, vnevent_t) /* NB: No ";" */ + int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, char *) \ + /* NB: No ";" */ /* * Operations on vnodes. Note: File systems must never operate directly @@ -675,7 +681,7 @@ extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *); extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *); extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *); extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *); -extern int fop_vnevent(vnode_t *, vnevent_t); +extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *); #endif /* _KERNEL */ @@ -765,8 +771,8 @@ extern int fop_vnevent(vnode_t *, vnevent_t); fop_setsecattr(vp, vsap, f, cr) #define VOP_SHRLOCK(vp, cmd, shr, f, cr) \ fop_shrlock(vp, cmd, shr, f, cr) -#define VOP_VNEVENT(vp, vnevent) \ - fop_vnevent(vp, vnevent) +#define VOP_VNEVENT(vp, vnevent, dvp, fnm) \ + fop_vnevent(vp, vnevent, dvp, fnm) #define VOPNAME_OPEN "open" #define VOPNAME_CLOSE "close" @@ -908,10 +914,14 @@ void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp, const char *path, size_t plen); /* Vnode event notification */ -void vnevent_rename_src(vnode_t *); -void vnevent_rename_dest(vnode_t *); -void vnevent_remove(vnode_t *); -void vnevent_rmdir(vnode_t *); +void vnevent_rename_src(vnode_t *, vnode_t *, char *); +void vnevent_rename_dest(vnode_t *, vnode_t *, char *); +void vnevent_remove(vnode_t *, vnode_t *, char *); +void vnevent_rmdir(vnode_t *, vnode_t *, char *); +void vnevent_create(vnode_t *); +void vnevent_link(vnode_t *); +void vnevent_rename_dest_dir(vnode_t *); +void vnevent_mountedover(vnode_t *); int vnevent_support(vnode_t *); /* Context identification */ diff --git a/usr/src/uts/intel/portfs/Makefile b/usr/src/uts/intel/portfs/Makefile index 536b845c59..754a7b60b2 100644 --- a/usr/src/uts/intel/portfs/Makefile +++ b/usr/src/uts/intel/portfs/Makefile @@ -20,7 +20,7 @@ # # # uts/intel/portfs/Makefile -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -35,7 +35,7 @@ # UTSBASE = ../.. -PORTFS_OBJS += port.o port_vnops.o port_fd.o +PORTFS_OBJS += port.o port_vnops.o port_fd.o port_fop.o # # Define the module and object file sets. diff --git a/usr/src/uts/sparc/portfs/Makefile b/usr/src/uts/sparc/portfs/Makefile index a15476eada..b08d2828e5 100644 --- a/usr/src/uts/sparc/portfs/Makefile +++ b/usr/src/uts/sparc/portfs/Makefile @@ -20,7 +20,7 @@ # # # uts/sparc/portfs/Makefile -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -35,7 +35,7 @@ # UTSBASE = ../.. -PORTFS_OBJS += port.o port_vnops.o port_fd.o +PORTFS_OBJS += port.o port_vnops.o port_fd.o port_fop.o # # Define the module and object file sets. |