Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/fs/smbfs use NT DIRECTORY CHANGE NOTIFY to watch for dir...
details: https://anonhg.NetBSD.org/src/rev/892d30bfe3d6
branches: trunk
changeset: 545361:892d30bfe3d6
user: jdolecek <jdolecek%NetBSD.org@localhost>
date: Mon Apr 07 12:04:15 2003 +0000
description:
use NT DIRECTORY CHANGE NOTIFY to watch for directory kevents if the
server supports it
for this, need NT CREATE AND X a directory in smbfs_open(), so that
we get the FID handle used for DIRECTORY CHANGE NOTIFY SMB
this could eventually be used to 'watch' even regular files, by
watching its parent directory and lookup/VN_KNOTE() when we get
REMOVED/RENAMED/MODIFIED action
also reorganize the kqueue code somewhat to use simplify locking
and knote detach
diffstat:
sys/fs/smbfs/smbfs_kq.c | 290 ++++++++++++++++++++++++++++++++------------
sys/fs/smbfs/smbfs_smb.c | 273 +++++++++++++++++++++++++++++++++++++++++-
sys/fs/smbfs/smbfs_subr.h | 6 +-
sys/fs/smbfs/smbfs_vnops.c | 48 ++++--
4 files changed, 514 insertions(+), 103 deletions(-)
diffs (truncated from 902 to 300 lines):
diff -r f4fce6270ac9 -r 892d30bfe3d6 sys/fs/smbfs/smbfs_kq.c
--- a/sys/fs/smbfs/smbfs_kq.c Mon Apr 07 11:45:55 2003 +0000
+++ b/sys/fs/smbfs/smbfs_kq.c Mon Apr 07 12:04:15 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: smbfs_kq.c,v 1.2 2003/03/24 06:39:51 jdolecek Exp $ */
+/* $NetBSD: smbfs_kq.c,v 1.3 2003/04/07 12:04:15 jdolecek Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: smbfs_kq.c,v 1.2 2003/03/24 06:39:51 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: smbfs_kq.c,v 1.3 2003/04/07 12:04:15 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -53,6 +53,7 @@
#include <sys/malloc.h>
#include <sys/kthread.h>
#include <sys/file.h>
+#include <sys/dirent.h>
#include <machine/limits.h>
@@ -62,6 +63,7 @@
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
#include <fs/smbfs/smbfs.h>
#include <fs/smbfs/smbfs_node.h>
@@ -69,34 +71,51 @@
#include <miscfs/genfs/genfs.h>
+/*
+ * The maximum of outstanding SMB requests is 65536, since the
+ * message id is 16bit. Don't consume all. If there is more
+ * than 30k directory notify requests, fall back to polling mode.
+ */
+#define DNOTIFY_MAX 30000
+
struct kevq {
- SLIST_ENTRY(kevq) kev_link;
+ SLIST_ENTRY(kevq) kev_link; /* link on kevlist */
+ SLIST_ENTRY(kevq) k_link; /* link on poll/dn list */
+
struct vnode *vp;
u_int usecount;
u_int flags;
#define KEVQ_BUSY 0x01 /* currently being processed */
#define KEVQ_WANT 0x02 /* want to change this entry */
+#define KEVQ_DNOT 0x04 /* kevent using NT directory change notify */
struct timespec omtime; /* old modification time */
struct timespec octime; /* old change time */
nlink_t onlink; /* old number of references to file */
+ struct smb_rq *rq; /* request structure */
};
-SLIST_HEAD(kevqlist, kevq);
+
+static struct proc *smbkqp; /* the kevent handler */
+static struct smb_cred smbkq_scred;
-static struct lock smbfskevq_lock;
-static struct proc *psmbfskq;
-static struct kevqlist kevlist = SLIST_HEAD_INITIALIZER(kevlist);
+static struct simplelock smbkq_lock = SIMPLELOCK_INITIALIZER;
+ /* guard access to k*evlist */
+static SLIST_HEAD(, kevq) kevlist = SLIST_HEAD_INITIALIZER(kevlist);
+static SLIST_HEAD(, kevq) kplist = SLIST_HEAD_INITIALIZER(kplist);
+static SLIST_HEAD(, kevq) kdnlist = SLIST_HEAD_INITIALIZER(kdnlist);
-void
-smbfs_kqinit(void)
-{
- lockinit(&smbfskevq_lock, PSOCK, "smbkqlck", 0, 0);
-}
+static int dnot_num = 0; /* number of active dir notifications */
+static u_int32_t kevs;
+
+static void smbfskq_dirnotify(void *);
/*
- * This quite simplistic routine periodically checks for server changes
- * of any of the watched files every NFS_MINATTRTIME/2 seconds.
+ * This routine periodically checks server for change
+ * of any of the watched files every SMBFS_MINATTRTIME/2 seconds.
* Only changes in size, modification time, change time and nlinks
* are being checked, everything else is ignored.
+ * Directory events are watched via NT DIRECTORY CHANGE NOTIFY
+ * if the server supports it.
+ *
* The routine only calls VOP_GETATTR() when it's likely it would get
* some new data, i.e. when the vnode expires from attrcache. This
* should give same result as periodically running stat(2) from userland,
@@ -113,12 +132,15 @@
struct kevq *ke;
struct vattr attr;
int error;
- struct proc *p = psmbfskq;
+ struct proc *p = smbkqp;
u_quad_t osize;
+ int needwake;
for(;;) {
- lockmgr(&smbfskevq_lock, LK_EXCLUSIVE, NULL);
- SLIST_FOREACH(ke, &kevlist, kev_link) {
+ simple_lock(&smbkq_lock);
+
+ /* check all entries on poll list for changes */
+ SLIST_FOREACH(ke, &kplist, k_link) {
/* skip if still in attrcache */
if (smbfs_attr_cachelookup(ke->vp, &attr) != ENOENT)
continue;
@@ -128,14 +150,17 @@
* for changes.
*/
ke->flags |= KEVQ_BUSY;
- lockmgr(&smbfskevq_lock, LK_RELEASE, NULL);
+ simple_unlock(&smbkq_lock);
/* save v_size, smbfs_getattr() updates it */
osize = ke->vp->v_size;
error = VOP_GETATTR(ke->vp, &attr, p->p_ucred, p);
- if (error)
+ if (error) {
+ /* relock and proceed with next */
+ simple_lock(&smbkq_lock);
continue;
+ }
/* following is a bit fragile, but about best
* we can get */
@@ -161,7 +186,7 @@
ke->onlink = attr.va_nlink;
}
- lockmgr(&smbfskevq_lock, LK_EXCLUSIVE, NULL);
+ simple_lock(&smbkq_lock);
ke->flags &= ~KEVQ_BUSY;
if (ke->flags & KEVQ_WANT) {
ke->flags &= ~KEVQ_WANT;
@@ -169,59 +194,132 @@
}
}
- if (SLIST_EMPTY(&kevlist)) {
- /* Nothing more to watch, exit */
- psmbfskq = NULL;
- lockmgr(&smbfskevq_lock, LK_RELEASE, NULL);
- kthread_exit(0);
+ /* Exit if there are no more kevents to watch for */
+ if (kevs == 0) {
+ smbkqp = NULL;
+ simple_unlock(&smbkq_lock);
+ break;
}
- lockmgr(&smbfskevq_lock, LK_RELEASE, NULL);
+
+ /* only wake periodically if poll list is nonempty */
+ needwake = !SLIST_EMPTY(&kplist);
/* wait a while before checking for changes again */
- tsleep(psmbfskq, PSOCK, "smbkqpw",
- SMBFS_ATTRTIMO * hz / 2);
+ error = ltsleep(smbkqp, PSOCK, "smbkqidl",
+ needwake ? (SMBFS_ATTRTIMO * hz / 2) : 0, &smbkq_lock);
+
+ if (!error) {
+ /* woken up, check if any pending notifications */
+ while (!SLIST_EMPTY(&kdnlist)) {
+ int s, hint;
+
+ s = splnet();
+ ke = SLIST_FIRST(&kdnlist);
+ SLIST_REMOVE_HEAD(&kdnlist, k_link);
+ SLIST_NEXT(ke, k_link) = NULL;
+ splx(s);
+
+ error = smbfs_smb_nt_dirnotify_fetch(ke->rq,
+ &hint);
+ ke->rq = NULL; /* rq deallocated by now */
+ if (error) {
+ /*
+ * if there is error, switch to
+ * polling for this one
+ */
+ ke->flags &= KEVQ_DNOT;
+ SLIST_INSERT_HEAD(&kplist, ke, k_link);
+ continue;
+ }
+ VN_KNOTE(ke->vp, hint);
+
+ /* reissue the notify request */
+ (void) smbfs_smb_nt_dirnotify_setup(
+ VTOSMB(ke->vp),
+ &ke->rq, &smbkq_scred,
+ smbfskq_dirnotify, ke);
+ }
+ }
}
+
+ kthread_exit(0);
+}
+
+static void
+smbfskq_dirnotify(void *arg)
+{
+ struct kevq *ke = arg;
+
+ if (SLIST_NEXT(ke, k_link)) {
+ /* already on notify list */
+ return;
+ }
+
+ SLIST_INSERT_HEAD(&kdnlist, ke, k_link);
+ wakeup(smbkqp);
}
static void
filt_smbfsdetach(struct knote *kn)
{
- struct vnode *vp = (struct vnode *)kn->kn_hook;
- struct kevq *ke;
+ struct kevq *ke = (struct kevq *)kn->kn_hook;
+ struct smb_rq *rq = NULL;
/* XXXLUKEM lock the struct? */
- SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
+ SLIST_REMOVE(&ke->vp->v_klist, kn, knote, kn_selnext);
/* Remove the vnode from watch list */
- lockmgr(&smbfskevq_lock, LK_EXCLUSIVE, NULL);
- SLIST_FOREACH(ke, &kevlist, kev_link) {
- if (ke->vp == vp) {
- while (ke->flags & KEVQ_BUSY) {
- ke->flags |= KEVQ_WANT;
- lockmgr(&smbfskevq_lock, LK_RELEASE, NULL);
- (void) tsleep(ke, PSOCK, "smbkqdet", 0);
- lockmgr(&smbfskevq_lock, LK_EXCLUSIVE, NULL);
- }
+ simple_lock(&smbkq_lock);
+
+ /* the handler does something to it, wait */
+ while (ke->flags & KEVQ_BUSY) {
+ ke->flags |= KEVQ_WANT;
+ ltsleep(ke, PSOCK, "smbkqdw", 0, &smbkq_lock);
+ }
+
+ if (ke->usecount > 1) {
+ /* keep, other kevents need this */
+ ke->usecount--;
+ } else {
+ /* last user, g/c */
+ if (ke->flags & KEVQ_DNOT) {
+ dnot_num--;
+ rq = ke->rq;
- if (ke->usecount > 1) {
- /* keep, other kevents need this */
- ke->usecount--;
- } else {
- /* last user, g/c */
- SLIST_REMOVE(&kevlist, ke, kevq, kev_link);
- FREE(ke, M_KEVENT);
- }
- break;
- }
+ /* If on dirnotify list, remove */
+ if (SLIST_NEXT(ke, k_link))
+ SLIST_REMOVE(&kdnlist, ke, kevq, k_link);
+ } else
+ SLIST_REMOVE(&kplist, ke, kevq, k_link);
+ SLIST_REMOVE(&kevlist, ke, kevq, kev_link);
+ FREE(ke, M_KEVENT);
}
- lockmgr(&smbfskevq_lock, LK_RELEASE, NULL);
+ kevs--;
+
+ simple_unlock(&smbkq_lock);
+
+ /* If there was request still pending, cancel it now */
+ if (rq) {
+ smb_iod_removerq(rq);
+
+ /*
+ * Explicitly cancel the request, so that server can
+ * free directory change notify resources.
+ */
+ smbfs_smb_ntcancel(SSTOCP(rq->sr_share), rq->sr_mid,
+ &smbkq_scred);
+
+ /* Free */
+ smb_rq_done(rq);
+ }
Home |
Main Index |
Thread Index |
Old Index