summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpraks <none@none>2007-08-14 17:10:25 -0700
committerpraks <none@none>2007-08-14 17:10:25 -0700
commitdf2381bfa5cf7dd654bcf30b2f5af53f34f3043a (patch)
tree64f247ef81041ed83c44dc2d9aadf46ed66b5ab3
parent2038334ab26baaa43c9083f35def041511c3cc1f (diff)
downloadillumos-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
-rw-r--r--usr/src/lib/libbsm/audit_event.txt1
-rw-r--r--usr/src/uts/common/c2/audit_event.c36
-rw-r--r--usr/src/uts/common/c2/audit_kevents.h3
-rw-r--r--usr/src/uts/common/fs/autofs/auto_vnops.c1
-rw-r--r--usr/src/uts/common/fs/fem.c10
-rw-r--r--usr/src/uts/common/fs/fs_subr.c4
-rw-r--r--usr/src/uts/common/fs/fs_subr.h6
-rw-r--r--usr/src/uts/common/fs/mntfs/mntvfsops.c2
-rw-r--r--usr/src/uts/common/fs/mntfs/mntvnops.c6
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_vnops.c49
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c14
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c123
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_vnops.c41
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_dir.c12
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vnops.c5
-rw-r--r--usr/src/uts/common/fs/portfs/port.c46
-rw-r--r--usr/src/uts/common/fs/portfs/port_fd.c2
-rw-r--r--usr/src/uts/common/fs/portfs/port_fop.c (renamed from deleted_files/usr/src/uts/common/fs/portfs/port_fop.c)41
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_dir.c16
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vnops.c20
-rw-r--r--usr/src/uts/common/fs/udfs/udf_dir.c19
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vnops.c6
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vnops.c24
-rw-r--r--usr/src/uts/common/fs/vfs.c135
-rw-r--r--usr/src/uts/common/fs/vnode.c72
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c25
-rw-r--r--usr/src/uts/common/nfs/nfs4.h2
-rw-r--r--usr/src/uts/common/os/port_subr.c19
-rw-r--r--usr/src/uts/common/sys/fem.h7
-rw-r--r--usr/src/uts/common/sys/port.h58
-rw-r--r--usr/src/uts/common/sys/port_impl.h137
-rw-r--r--usr/src/uts/common/sys/port_kernel.h21
-rw-r--r--usr/src/uts/common/sys/vnode.h28
-rw-r--r--usr/src/uts/intel/portfs/Makefile4
-rw-r--r--usr/src/uts/sparc/portfs/Makefile4
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.