Module Name:    src
Committed By:   manu
Date:           Thu Sep 23 16:02:34 UTC 2010

Modified Files:
        src/lib/libperfuse: debug.c ops.c perfuse.c perfuse_if.h perfuse_priv.h
            subr.c
        src/usr.sbin/perfused: perfused.c

Log Message:
== file close operations ==
- use PUFFS_KFLAG_WTCACHE to puffs_init so that all writes are
immediatly send to the filesystem, and we do not have anymore write
after inactive. As a consequence, we can close files at inactive
stage, and there is not any concern left with files opened at
create time. We also do not have anymore to open ourselves in readdir and
fsync.

- Fsync on close (inactive stage). That makes sure we will not need to
do these operations once the file is closed (FUSE want an open file).
short sircuit the request that come after the close, bu not fsinc'ing
closed files,

- Use PUFFS_KFLAG_IAONDEMAND to get less inactive calls

== Removed nodes ==
- more ENOENT retunred for operations on removed node (but there
are probably some still missing): getattr, ooen, setattr, fsync

- set PND_REMOVE before sending the UNLINK/RMDIR operations so that we avoid
races during UNLINK completion. Also set PND_REMOVED on node we overwirte
in rename

== Filehandle fixes ==
- queue open operation to avoid getting two fh for one file

- set FH in getattr, if the file is open

- Just requires a read FH for fsyncdir, as we always opendir in read
mode. Ok, this is misleading :-)

== Misc ==
- do not set FUSE_FATTR_ATIME_NOW in setattr, as we provide the time

- short circuit nilpotent operations in setattr

- add a filename diagnostic flag to dump file names


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/lib/libperfuse/debug.c
cvs rdiff -u -r1.16 -r1.17 src/lib/libperfuse/ops.c
cvs rdiff -u -r1.7 -r1.8 src/lib/libperfuse/perfuse.c
cvs rdiff -u -r1.8 -r1.9 src/lib/libperfuse/perfuse_if.h
cvs rdiff -u -r1.11 -r1.12 src/lib/libperfuse/perfuse_priv.h
cvs rdiff -u -r1.5 -r1.6 src/lib/libperfuse/subr.c
cvs rdiff -u -r1.9 -r1.10 src/usr.sbin/perfused/perfused.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libperfuse/debug.c
diff -u src/lib/libperfuse/debug.c:1.2 src/lib/libperfuse/debug.c:1.3
--- src/lib/libperfuse/debug.c:1.2	Wed Sep 15 01:51:43 2010
+++ src/lib/libperfuse/debug.c	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: debug.c,v 1.2 2010/09/15 01:51:43 manu Exp $ */
+/*  $NetBSD: debug.c,v 1.3 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -79,7 +79,13 @@
 	{ 0, "UNKNOWN" },
 };
 
-const char *perfuse_qtypestr[] = { "READDIR", "READ", "WRITE", "AFTERWRITE" };
+const char *perfuse_qtypestr[] = { 
+	"READDIR",
+	"READ",
+	"WRITE",
+	"AFTERWRITE",
+	"OPEN"
+};
 
 const char *
 perfuse_opname(opcode)

Index: src/lib/libperfuse/ops.c
diff -u src/lib/libperfuse/ops.c:1.16 src/lib/libperfuse/ops.c:1.17
--- src/lib/libperfuse/ops.c:1.16	Mon Sep 20 07:00:21 2010
+++ src/lib/libperfuse/ops.c	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: ops.c,v 1.16 2010/09/20 07:00:21 manu Exp $ */
+/*  $NetBSD: ops.c,v 1.17 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -180,9 +180,10 @@
 	ps = puffs_getspecific(pu);
 
 #ifdef PERFUSE_DEBUG
-	if ((perfuse_diagflags & PDF_FUSE) && (opc != 0))
-		DPRINTF("file = \"%s\"\n", 
-			(char *)PNPATH((struct puffs_node *)opc));
+	if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0))
+		DPRINTF("file = \"%s\" flags = 0x%x\n", 
+			(char *)PNPATH((struct puffs_node *)opc), 
+			PERFUSE_NODE_DATA(opc)->pnd_flags);
 #endif
 	error = ps->ps_xchg_msg(pu, pm, len, wait);
 
@@ -324,6 +325,11 @@
 	if (pnp != NULL)
 		*pnp = pn;
 
+#ifdef PERFUSE_DEBUG
+	if (perfuse_diagflags & PDF_FILENAME)
+		DPRINTF("%s: opc = %p, looked up opc = %p, file = \"%s\"\n",
+			__func__, (void *)opc, pn, (char *)PNPATH(pn));
+#endif
 out: 
 	ps->ps_destroy_msg(pm);
 
@@ -989,13 +995,6 @@
 		if (error != 0)	
 			return error;
 
-		/*
-		 * This node has been open in the filesystem,
-		 * but not by the kernel. We will have to close
-		 * it on our own to avoid a leak
-		 */
-		PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_OPENFS;
-
 		return 0;
 	}
 
@@ -1030,17 +1029,9 @@
 	 * so that we can reuse it later
 	 */
 	pn = perfuse_new_pn(pu, opc);
-	perfuse_new_fh(pu, (puffs_cookie_t)pn, foo->fh, FWRITE);
+	perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE);
 	PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
 
-#ifdef PERFUSE_DEBUG
-	if (perfuse_diagflags & PDF_FH)
-		DPRINTF("%s: opc = %p, file = \"%s\", "
-			"ino = %"PRId64", rfh = 0x%"PRIx64"\n",
-			__func__, (void *)pn, (char *)PCNPATH(pcn),
-			feo->nodeid, foo->fh);
-#endif
-
 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
 	puffs_newinfo_setcookie(pni, pn);
 
@@ -1049,12 +1040,13 @@
 	 */
 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
 
-	/*
-	 * This node has been open in the filesystem,
-	 * but not by the kernel. We will have to close
-	 * it on our own to avoid a leak
-	 */
-	PERFUSE_NODE_DATA(pn)->pnd_flags |= PND_OPENFS;
+#ifdef PERFUSE_DEBUG
+	if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
+		DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
+			"ino = %"PRId64", wfh = 0x%"PRIx64"\n",
+			__func__, (void *)pn, (char *)PCNPATH(pcn),
+			PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid, foo->fh);
+#endif
 
 out: 
 	ps->ps_destroy_msg(pm);
@@ -1145,17 +1137,30 @@
 	int error;
 	
 	ps = puffs_getspecific(pu);
+	pn = (struct puffs_node *)opc;
 	pnd = PERFUSE_NODE_DATA(opc);
+	pm = NULL;
+	error = 0;
+
+	/*
+	 * Queue open on a node so that we do not open
+	 * twice. This would be better with read and
+	 * write distinguished.
+	 */
+	while (pnd->pnd_flags & PND_INOPEN)
+		requeue_request(pu, opc, PCQ_OPEN);
+	pnd->pnd_flags |= PND_INOPEN;
 
-	pn = (struct puffs_node *)opc;
 	if (puffs_pn_getvap(pn)->va_type == VDIR) {
 		/*
 		 * We may open removed files, but it seems much more 
 		 * troublesome to open removed directories. glusterfs says 
 		 * "OPENDIR (null) (fuse_loc_fill() failed)"
 		 */
-		if (pnd->pnd_flags & PND_REMOVED)
-			return ENOENT;
+		if (pnd->pnd_flags & PND_REMOVED) {
+			error = ENOENT;
+			goto out;
+		}
 
 		op = FUSE_OPENDIR;
 		pmode = PUFFS_VREAD|PUFFS_VEXEC;
@@ -1172,11 +1177,11 @@
 	 * Opening a file requires R-- for reading, -W- for writing
 	 * In both cases, --X is required on the parent.
 	 */
-	if (no_access((puffs_cookie_t)pnd->pnd_parent, pcr, PUFFS_VEXEC))
-		return EACCES;
-
-	if (no_access(opc, pcr, pmode))
-		return EACCES;
+	if ((no_access((puffs_cookie_t)pnd->pnd_parent, pcr, PUFFS_VEXEC)) ||
+	    (no_access(opc, pcr, pmode))) {
+		error = EACCES;
+		goto out;
+	}
 
 	/*
 	 * libfuse docs say O_CREAT should not be set.
@@ -1185,22 +1190,27 @@
 
 	/*
 	 * Do not open twice, and do not reopen for reading
-	 * if we already have write handle.
+	 * if we already have write handle. Just ask for
+	 * inactive, in case the node was open by a create
+	 * operation (we are not allowed to call puffs_setback
+	 * at create time, puffs interface forbids it)
 	 */
 	if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) ||
+	    ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) ||
 	    ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))) {
-		/*
-		 * If the file was created, it was open for
-		 * the filesystem but not for the kernel. This
-		 * is not the case anymore, therefore we cleanup
-		 * the flag to avoid an unwanted cleanup close
-		 * after PERFUSE_OPENFS_TIMEOUT.
-		 */
-		pnd->pnd_flags &= ~PND_OPENFS;
-
-		return 0;
+		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_INACT_N1);
+		error = 0;
+		goto out;
 	}
 	
+	/* 
+	 * Fail any attempt to reopen a removed file if
+	 * we do not have any file handle left.
+	 */
+	if (pnd->pnd_flags & PND_REMOVED) {
+		error = ENOENT;
+		goto out;
+	}
 
 	/*
 	 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE
@@ -1223,10 +1233,15 @@
 	 * Save the file handle in node private data 
 	 * so that we can reuse it later
 	 */
-	perfuse_new_fh(pu, (puffs_cookie_t)pn, foo->fh, mode);
+	perfuse_new_fh(opc, foo->fh, mode);
+	 
+	/*
+	 * Request inactive to be send on this node.
+	 */
+	puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_INACT_N1);
 
 #ifdef PERFUSE_DEBUG
-	if (perfuse_diagflags & PDF_FH)
+	if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
 		DPRINTF("%s: opc = %p, file = \"%s\", "
 			"ino = %"PRId64", %s%sfh = 0x%"PRIx64"\n",
 			__func__, (void *)opc, 
@@ -1236,7 +1251,11 @@
 #endif
 
 out:
-	ps->ps_destroy_msg(pm);
+	if (pm != NULL)
+		ps->ps_destroy_msg(pm);
+
+	pnd->pnd_flags &= ~PND_INOPEN;
+	(void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
 
 	return error;
 }
@@ -1249,24 +1268,16 @@
 	int flags;
 	const struct puffs_cred *pcr;
 {
-	struct puffs_node *pn;
 	struct perfuse_node_data *pnd;
 
-	pn = (struct puffs_node *)opc;
 	pnd = PERFUSE_NODE_DATA(opc);
 
 	if (!(pnd->pnd_flags & PND_OPEN))
 		return EBADF;
 
 	/* 
-	 * The NetBSD kernel will send sync and setattr(mtime, ctime)
-	 * afer a close on a regular file. Some FUSE filesystem will 
-	 * assume theses operations are performed on open files. We 
-	 * therefore postpone the close operation at reclaim time.
+	 * Actual close is postponed at inactive time.
 	 */
-	if (puffs_pn_getvap(pn)->va_type != VREG)
-		return perfuse_node_close_common(pu, opc, flags);
-
 	return 0;
 }
 
@@ -1352,7 +1363,11 @@
 	struct fuse_attr_out *fao;
 	int error;
 	
-	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
+	/*
+	 * If removed and not open, it fails
+	 */
+	if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) &&
+	    !(PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN))
 		return ENOENT;
 
 	/*
@@ -1366,13 +1381,16 @@
 
 	/*
 	 * FUSE_GETATTR_FH must be set in fgi->flags 
-	 * if we use for fgi->fh, but we do not. 
+	 * if we use for fgi->fh
 	 */
 	pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr);
 	fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
 	fgi->getattr_flags = 0; 
 	fgi->dummy = 0;
-	fgi->fh = 0;
+	fgi->fh = perfuse_get_fh(opc, FREAD);
+
+	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN)
+		fgi->getattr_flags |= FUSE_GETATTR_FH;
 
 	if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
 		goto out;
@@ -1407,22 +1425,25 @@
 	struct perfuse_state *ps;
 	struct perfuse_node_data *pnd;
 	struct fuse_setattr_in *fsi;
-	int error;
 	struct vattr *old_va;
+	int error;
 
 	ps = puffs_getspecific(pu);
 	pnd = PERFUSE_NODE_DATA(opc);
+	pm = NULL;
 
 	/*
 	 * The only operation we can do once the file is removed 
 	 * is to resize it, and we can do it only if it is open.
+	 * Do not even send the operation to the filesystem: the
+	 * file is not there anymore.
 	 */
 	if (pnd->pnd_flags & PND_REMOVED) {
 		if (!(pnd->pnd_flags & PND_OPEN))
 			return ENOENT;
 		
-		if (vap->va_size == (u_quad_t)PUFFS_VNOVAL)
-			return 0;
+		error = 0;
+		goto out;
 	}
 
 	/*
@@ -1475,11 +1496,13 @@
 		while (pnd->pnd_flags & PND_INWRITE)
 			requeue_request(pu, opc, PCQ_AFTERWRITE);
 
-
 	pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
 	fsi->valid = 0;
 
+	/*
+	 * Get a fh if the node is open for writing
+	 */
 	if (pnd->pnd_flags & PND_WFH) {
 		fh = perfuse_get_fh(opc, FWRITE);
 		fsi->fh = fh;
@@ -1492,16 +1515,17 @@
 	}
 
 	if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
-		fsi->atime = vap->va_atime.tv_sec;;
+		fsi->atime = vap->va_atime.tv_sec;
 		fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;;
-		fsi->valid |= (FUSE_FATTR_ATIME|FUSE_FATTR_ATIME_NOW);
+		fsi->valid |= FUSE_FATTR_ATIME;
 	}
 
 	if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
 		fsi->mtime = vap->va_mtime.tv_sec;;
 		fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec;;
-		fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_MTIME_NOW);
+		fsi->valid |= FUSE_FATTR_MTIME;
 	}
+		
 
 	if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
 		fsi->mode = vap->va_mode; 
@@ -1524,20 +1548,28 @@
 	}
 
 	/*
-	 * If node was removed, ignore anything but resize
-	 * This works around glusterfs'
-	 * "SETATTR (null) (fuse_loc_fill() failed), ret = -2"
+	 * If nothing remain, discard the operation.
 	 */
-	if (pnd->pnd_flags & PND_REMOVED)
-		fsi->valid &= 
-		    (FUSE_FATTR_SIZE | FUSE_FATTR_FH | FUSE_FATTR_LOCKOWNER);
+	if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
+			    FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
+		error = 0;
+		goto out;
+	}
 
 	/*
 	 * A fuse_attr_out is returned, but we ignore it.
 	 */
 	error = xchg_msg(pu, opc, pm, sizeof(struct fuse_attr_out), wait_reply);
 
-	ps->ps_destroy_msg(pm);
+out:
+	/*
+	 * Keep track of new size
+	 */
+	if ((error == 0) && (vap->va_size != (u_quad_t)PUFFS_VNOVAL))
+		pnd->pnd_size = (uint64_t)vap->va_size;
+
+	if (pm != NULL)
+		ps->ps_destroy_msg(pm);
 
 	return error;
 }
@@ -1611,12 +1643,24 @@
 	struct perfuse_node_data *pnd;
 	struct fuse_fsync_in *ffi;
 	uint64_t fh;
-	int open_self;
 	int error;
 	
 	pm = NULL;
-	open_self = 0;	
 	ps = puffs_getspecific(pu);
+	pnd = PERFUSE_NODE_DATA(opc);
+
+	/*
+	 * No need to sync a removed node
+	 */
+	if (pnd->pnd_flags & PND_REMOVED)
+		return 0;
+
+	/*
+	 * We do not sync closed files. They have been 
+	 * sync at inactive time already.
+	 */
+	if (!(pnd->pnd_flags & PND_OPEN))
+		return 0;
 
 	if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) 
 		op = FUSE_FSYNCDIR;
@@ -1627,7 +1671,6 @@
 	 * Do not sync if there are no change to sync
 	 * XXX remove that test on files if we implement mmap
 	 */
-	pnd = PERFUSE_NODE_DATA(opc);
 #ifdef PERFUSE_DEBUG
 	if (perfuse_diagflags & PDF_SYNC)
 		DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", 
@@ -1638,18 +1681,10 @@
 	if (!(pnd->pnd_flags & PND_DIRTY))
 		return 0;
 
-	/*
-	 * It seems NetBSD can call fsync without open first
-	 * glusterfs complain in such a situation:
-	 * "FSYNC() ERR => -1 (Invalid argument)"
-	 */
-	if (!(pnd->pnd_flags & PND_WFH)) {
-		if ((error = perfuse_node_open(pu, opc, FWRITE, pcr)) != 0)
-			goto out;
-		open_self = 1;
-	}
-
-	fh = perfuse_get_fh(opc, FWRITE);
+	if (op == FUSE_FSYNCDIR)
+		fh = perfuse_get_fh(opc, FREAD);
+	else
+		fh = perfuse_get_fh(opc, FWRITE);
 	
 	/*
 	 * If fsync_flags  is set, meta data should not be flushed.
@@ -1693,9 +1728,6 @@
 	if (pm != NULL)
 		ps->ps_destroy_msg(pm);
 
-	if (open_self) 
-		(void)perfuse_node_close_common(pu, opc, FWRITE);
-
 	return error;
 }
 
@@ -1708,12 +1740,14 @@
 	off_t newoff;
 	const struct puffs_cred *pcr;
 {
+	struct perfuse_node_data *pnd;
+
 	/*
-	 * XXX what should I do with oldoff?
-	 * XXX where is the newoffset returned?
-	 * XXX the held seek pointer seems just unused
+	 * seek may modify file size
 	 */
-	PERFUSE_NODE_DATA(opc)->pnd_offset = newoff;
+	pnd = PERFUSE_NODE_DATA(opc);
+	if (newoff > pnd->pnd_size)
+		pnd->pnd_size = newoff;
 
 	return 0;
 }
@@ -1744,15 +1778,27 @@
 	    pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
 		return EACCES;
 
+#ifdef PERFUSE_DEBUG
 	if (targ == NULL)
 		DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
 
+	if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
+		DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n",
+			__func__, (void *)opc, (void *)targ, 
+			(char *)PNPATH((struct puffs_node *)targ));
+#endif
+
 	ps = puffs_getspecific(pu);
 	pnd = PERFUSE_NODE_DATA(opc);
 	pn = (struct puffs_node *)targ;
 	name = basename_r((char *)PNPATH(pn));
 	len = strlen(name) + 1;
 
+	/*
+	 * Tag the node as removed before sending the operation.
+	 */
+	PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
+
 	pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
 	path = _GET_INPAYLOAD(ps, pm, char *);
 	(void)strlcpy(path, name, len);
@@ -1765,8 +1811,6 @@
 
 	puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
 
-	PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
-
 	/*
 	 * Reclaim should take care of decreasing pnd_childcount
 	 */
@@ -1775,6 +1819,13 @@
 	 * The parent directory needs a sync
 	 */
 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
+
+#ifdef PERFUSE_DEBUG
+	if (perfuse_diagflags & PDF_FILENAME)
+		DPRINTF("%s: remove nodeid = %"PRId64" file = \"%s\"\n",
+			__func__, PERFUSE_NODE_DATA(targ)->pnd_ino,
+			(char *)PNPATH((struct puffs_node *)targ));
+#endif
 out:
 	ps->ps_destroy_msg(pm);
 
@@ -1880,6 +1931,28 @@
 
 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
 	PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY;
+
+	/*
+	 * targ is not NULL if replaced node is removed
+	 */
+	if ((struct puffs_node *)targ != NULL)
+	PERFUSE_NODE_DATA(targ)->pnd_flags = PND_REMOVED;
+
+#ifdef PERFUSE_DEBUG
+	if (perfuse_diagflags & PDF_FILENAME)
+		DPRINTF("%s: nodeid = %"PRId64" file = \"%s\" renamed \"%s\" "
+			"from nodeid = %"PRId64" \"%s\" "
+			"to nodeid = %"PRId64" \"%s\"\n",
+	 		__func__, 
+			 PERFUSE_NODE_DATA(src)->pnd_ino,
+			(char *)PCNPATH(pcn_src),
+			(char *)PCNPATH(pcn_targ),
+			 PERFUSE_NODE_DATA(opc)->pnd_ino,
+			(char *)PNPATH((struct puffs_node *)targ_dir),
+			 PERFUSE_NODE_DATA(targ_dir)->pnd_ino,
+			(char *)PNPATH((struct puffs_node *)opc));
+#endif
+
 out:
 	ps->ps_destroy_msg(pm);
 
@@ -1951,6 +2024,11 @@
 	name = basename_r((char *)PNPATH(pn));
 	len = strlen(name) + 1;
 
+	/*
+	 * Tag the node as removed beofre sending the operation.
+	 */
+	PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
+
 	pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
 	path = _GET_INPAYLOAD(ps, pm, char *);
 	(void)strlcpy(path, name, len);
@@ -1963,12 +2041,17 @@
 
 	puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
 
-	PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
-
 	/*
 	 * The parent directory needs a sync
 	 */
 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
+
+#ifdef PERFUSE_DEBUG
+	if (perfuse_diagflags & PDF_FILENAME)
+		DPRINTF("%s: remove nodeid = %"PRId64" file = \"%s\"\n",
+			__func__, PERFUSE_NODE_DATA(targ)->pnd_ino,
+			(char *)PNPATH((struct puffs_node *)targ));
+#endif
 out:
 	ps->ps_destroy_msg(pm);
 
@@ -2037,13 +2120,11 @@
 	struct fuse_dirent *fd;
 	size_t foh_len;
 	int error;
-	int open_self;
 	uint64_t fd_offset;
 	size_t fd_maxlen;
 	
 	pm = NULL;
 	error = 0;
-	open_self = 0;
 	ps = puffs_getspecific(pu);
 
 	/*
@@ -2069,16 +2150,6 @@
 		goto out;
 	pnd->pnd_dirent_len = 0;
 	
-	/*
-	 * It seems NetBSD can call readdir without open first
-	 * libfuse will crash if it is done that way, hence open first.
-	 */
-	if (!(pnd->pnd_flags & PND_OPEN)) {
-		if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
-			goto out;
-		open_self = 1;
-	}
-
 	fh = perfuse_get_fh(opc, FREAD);
 
 #ifdef PERFUSE_DEBUG
@@ -2177,13 +2248,6 @@
 	if (pm != NULL)
 		ps->ps_destroy_msg(pm);
 
-	/*
-	 * If we opened the directory ourselves, close now
-	 * errors are ignored.
-	 */
-	if (open_self)
-		(void)perfuse_node_close(pu, opc, FWRITE, pcr);
-
 	if (error == 0)
 		error = readdir_buffered(ps, opc, dent, readoff,
 			reslen, pcr, eofflag, cookies, ncookies);
@@ -2284,7 +2348,7 @@
 #ifdef PERFUSE_DEBUG
 	if (perfuse_diagflags & PDF_RECLAIM)
 		DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, "
-			"has childcount %d %s%s%s, pending ops:%s%s%s\n", 
+			"has childcount %d %s%s%s%s, pending ops:%s%s%s\n", 
 		        (char *)PNPATH(pn), pnd->pnd_ino,
 		        pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
 		        pnd->pnd_childcount,
@@ -2293,46 +2357,28 @@
 			pnd->pnd_flags & PND_WFH ? "w" : "",
 			pnd->pnd_flags & PND_BUSY ? "" : " none",
 			pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
-			pnd->pnd_flags & PND_INWRITE ? " write" : "");
+			pnd->pnd_flags & PND_INWRITE ? " write" : "",
+			pnd->pnd_flags & PND_INOPEN ? " open" : "");
 #endif
 
 		if (!(pnd->pnd_flags & PND_RECLAIMED) ||
 		    (pnd->pnd_childcount != 0))
 			return 0;
 
-		/*
-		 * Make sure all operation are finished
-		 * There can be an ongoing write or
-		 */
-		while (pnd->pnd_flags & PND_INWRITE) {
-			requeue_request(pu, opc, PCQ_AFTERWRITE);
-
-			/*
-			 * reclaim may have been cancelled in the meantime
-			 * if the file as been look'ed up again.
-			 */
-			if (!(pnd->pnd_flags & PND_RECLAIMED)) 
-				return 0;
-		}
-
 #ifdef PERFUSE_DEBUG
-		if ((pnd->pnd_flags & (PND_INREADDIR|PND_INWRITE)) ||
+		if ((pnd->pnd_flags & PND_OPEN) ||
+		       !TAILQ_EMPTY(&pnd->pnd_pcq))
+			DERRX(EX_SOFTWARE, "%s: opc = %p: still open",
+			      __func__, (void *)opc);
+
+		if ((pnd->pnd_flags & PND_BUSY) ||
 		       !TAILQ_EMPTY(&pnd->pnd_pcq))
 			DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
 			      __func__, (void *)opc);
 #endif
 
 		/*
-		 * Close open files
-		 */
-		if (pnd->pnd_flags & PND_WFH)
-			(void)perfuse_node_close_common(pu, opc, FWRITE);
-
-		if (pnd->pnd_flags & PND_RFH)
-			(void)perfuse_node_close_common(pu, opc, FREAD);
-
-		/*
-		 * And send the FORGET message
+		 * Send the FORGET message
 		 */
 		pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET, 
 			      sizeof(*ffi), NULL);
@@ -2362,6 +2408,49 @@
 	struct puffs_usermount *pu;
 	puffs_cookie_t opc;
 {
+	struct perfuse_node_data *pnd;
+
+	pnd = PERFUSE_NODE_DATA(opc);
+
+	if (!(pnd->pnd_flags & PND_OPEN))
+		return 0;
+
+	/*
+	 * Make sure all operation are finished
+	 * There can be an ongoing write. Other
+	 * operation wit for all data before 
+	 * the close/inactive.
+	 */
+	while (pnd->pnd_flags & PND_INWRITE)
+		requeue_request(pu, opc, PCQ_AFTERWRITE);
+
+	/*
+	 * The inactive operation may be cancelled.
+	 * If no open is in progress, set PND_INOPEN
+	 * so that a new open will be queued.
+	 */
+	if (pnd->pnd_flags & PND_INOPEN)
+		return 0;
+
+	pnd->pnd_flags |= PND_INOPEN;
+
+	/*
+	 * Sync data
+	 */
+	if (pnd->pnd_flags & PND_DIRTY)
+		(void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0);
+	
+	/*
+	 * Close handles
+	 */
+	if (pnd->pnd_flags & PND_WFH)
+		(void)perfuse_node_close_common(pu, opc, FWRITE);
+
+	if (pnd->pnd_flags & PND_RFH)
+		(void)perfuse_node_close_common(pu, opc, FREAD);
+
+	pnd->pnd_flags &= ~PND_INOPEN;
+
 	return 0;
 }
 
@@ -2632,6 +2721,7 @@
 		*resid -= written;
 		offset += written;
 		buf += written;
+		pnd->pnd_size = offset; /* New file size */
 
 		ps->ps_destroy_msg(pm);
 		pm = NULL;

Index: src/lib/libperfuse/perfuse.c
diff -u src/lib/libperfuse/perfuse.c:1.7 src/lib/libperfuse/perfuse.c:1.8
--- src/lib/libperfuse/perfuse.c:1.7	Mon Sep 20 07:00:21 2010
+++ src/lib/libperfuse/perfuse.c	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse.c,v 1.7 2010/09/20 07:00:21 manu Exp $ */
+/*  $NetBSD: perfuse.c,v 1.8 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -406,7 +406,8 @@
 	PUFFSOP_SET(pops, perfuse, node, read);
 	PUFFSOP_SET(pops, perfuse, node, write);
 
-	puffs_flags = PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_HASHPATH;
+	puffs_flags = PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_HASHPATH |
+		      PUFFS_KFLAG_WTCACHE | PUFFS_KFLAG_IAONDEMAND;
 	if (perfuse_diagflags & PDF_PUFFS)
 		puffs_flags |= PUFFS_FLAG_OPDUMP;
 

Index: src/lib/libperfuse/perfuse_if.h
diff -u src/lib/libperfuse/perfuse_if.h:1.8 src/lib/libperfuse/perfuse_if.h:1.9
--- src/lib/libperfuse/perfuse_if.h:1.8	Wed Sep 15 01:51:43 2010
+++ src/lib/libperfuse/perfuse_if.h	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse_if.h,v 1.8 2010/09/15 01:51:43 manu Exp $ */
+/*  $NetBSD: perfuse_if.h,v 1.9 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -52,6 +52,7 @@
 #define PDF_SYNC	0x100	/* fsync and dirty flags */
 #define PDF_MISC	0x200	/* Miscelaneous messages */
 #define PDF_SYSLOG	0x400	/* use syslog */
+#define PDF_FILENAME	0x800	/* File names */
 
 /*
  * Diagnostic functions

Index: src/lib/libperfuse/perfuse_priv.h
diff -u src/lib/libperfuse/perfuse_priv.h:1.11 src/lib/libperfuse/perfuse_priv.h:1.12
--- src/lib/libperfuse/perfuse_priv.h:1.11	Mon Sep 20 07:00:22 2010
+++ src/lib/libperfuse/perfuse_priv.h	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse_priv.h,v 1.11 2010/09/20 07:00:22 manu Exp $ */
+/*  $NetBSD: perfuse_priv.h,v 1.12 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -37,17 +37,6 @@
 #include "perfuse_if.h"
 #include "fuse.h"
 
-/* 
- * When a file is created, it is open for the filesystem, but not
- * for the kernel. We keep the file open to avoid re-open it, but
- * once we open PERFUSE_OPENFS_MAXFILES files, we start closing
- * on our own any file that has not been open for PERFUSE_OPENFS_TIMEOUT
- * seconds. This is to avoid file leaks and getting "Too many open 
- * files in system"
- */
-#define PERFUSE_OPENFS_TIMEOUT 3
-#define PERFUSE_OPENFS_MAXFILES 32
-
 struct perfuse_state {
 	void *ps_private;	/* Private field for libperfuse user */
 	struct puffs_usermount *ps_pu;
@@ -81,7 +70,13 @@
 };
 
 
-enum perfuse_qtype { 	PCQ_READDIR, PCQ_READ, PCQ_WRITE, PCQ_AFTERWRITE };
+enum perfuse_qtype { 
+	PCQ_READDIR,	
+	PCQ_READ,
+	PCQ_WRITE,
+	PCQ_AFTERWRITE,
+	PCQ_OPEN
+};
 
 #ifdef PERFUSE_DEBUG
 extern const char *perfuse_qtypestr[];
@@ -98,7 +93,7 @@
 	uint64_t pnd_wfh;
 	uint64_t pnd_ino;			/* inode */
 	uint64_t pnd_nlookup;			/* vnode refcount */
-	uint64_t pnd_offset;			/* seek state */
+	uint64_t pnd_size;			/* file size */
 	uint64_t pnd_lock_owner;
 	struct dirent *pnd_dirent;		/* native buffer for readdir */
 	off_t pnd_dirent_len;
@@ -113,10 +108,10 @@
 #define PND_WFH			0x010	/* Write FH allocated */
 #define PND_REMOVED		0x020	/* Node was removed */
 #define PND_INWRITE		0x040	/* write in progress */
-#define PND_OPENFS		0x080	/* Open by fs but not by kernel */
+#define PND_INOPEN		0x100	/* open in progress */
 
 #define PND_OPEN		(PND_RFH|PND_WFH)	/* File is open */
-#define PND_BUSY		(PND_INREADDIR|PND_INWRITE)
+#define PND_BUSY		(PND_INREADDIR|PND_INWRITE|PND_INOPEN)
 	puffs_cookie_t pnd_parent;
 	int pnd_childcount;
 	time_t pnd_timestamp;
@@ -145,7 +140,7 @@
 struct puffs_node *perfuse_new_pn(struct puffs_usermount *, 
     struct puffs_node *);
 void perfuse_destroy_pn(struct puffs_usermount *, struct puffs_node *);
-void perfuse_new_fh(struct puffs_usermount *, puffs_cookie_t, uint64_t, int);
+void perfuse_new_fh(puffs_cookie_t, uint64_t, int);
 void perfuse_destroy_fh(puffs_cookie_t, uint64_t);
 uint64_t perfuse_get_fh(puffs_cookie_t, int);
 uint64_t perfuse_next_unique(struct puffs_usermount *);

Index: src/lib/libperfuse/subr.c
diff -u src/lib/libperfuse/subr.c:1.5 src/lib/libperfuse/subr.c:1.6
--- src/lib/libperfuse/subr.c:1.5	Mon Sep 20 07:00:22 2010
+++ src/lib/libperfuse/subr.c	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: subr.c,v 1.5 2010/09/20 07:00:22 manu Exp $ */
+/*  $NetBSD: subr.c,v 1.6 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -113,40 +113,13 @@
 
 
 void
-perfuse_new_fh(pu, opc, fh, mode)
-	struct puffs_usermount *pu;
+perfuse_new_fh(opc, fh, mode)
 	puffs_cookie_t opc;
 	uint64_t fh;
 	int mode;
 {
-	struct perfuse_state *ps;
 	struct perfuse_node_data *pnd;
 
-	ps = puffs_getspecific(pu);
-
-	/*
-	 * Nodes file with PND_OPENFS are open by the filesystem but
-	 * not by the kernel, because of a CREATE operation. If
-	 * the kernel never opens them, we have a leak to fix. 
-	 * If we have enough open files, we start closing the
-	 * one that had been open for too long.
-	 */
-	if (ps->ps_pnd_count > PERFUSE_OPENFS_MAXFILES) {
-		time_t now;
-
-		now = time(NULL);
-
-		TAILQ_FOREACH(pnd, &ps->ps_pnd, pnd_next) {
-			if ((pnd->pnd_ino == FUSE_ROOT_ID) ||
-			    !(pnd->pnd_flags & PND_OPENFS) ||
-			    (now < pnd->pnd_timestamp + PERFUSE_OPENFS_TIMEOUT))
-				continue;
-
-		pnd->pnd_flags &= ~PND_OPENFS;
-			perfuse_node_close_common(pu, pnd->pnd_pn, FWRITE);
-		}
-	}
-
 	pnd = PERFUSE_NODE_DATA(opc);
 
 	if (mode & FWRITE) {
@@ -207,9 +180,10 @@
 
 	pnd = PERFUSE_NODE_DATA(opc);
 
-	if (mode & FWRITE) 
+	if (mode & FWRITE) {
 		if (pnd->pnd_flags & PND_WFH)
 			return pnd->pnd_wfh;
+	}
 
 	if (mode & FREAD) {
 		if (pnd->pnd_flags & PND_RFH)
@@ -217,6 +191,7 @@
 
 		if (pnd->pnd_flags & PND_WFH)
 			return pnd->pnd_wfh;
+
 	}
 
 	return FUSE_UNKNOWN_FH;

Index: src/usr.sbin/perfused/perfused.c
diff -u src/usr.sbin/perfused/perfused.c:1.9 src/usr.sbin/perfused/perfused.c:1.10
--- src/usr.sbin/perfused/perfused.c:1.9	Mon Sep 20 06:45:38 2010
+++ src/usr.sbin/perfused/perfused.c	Thu Sep 23 16:02:34 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfused.c,v 1.9 2010/09/20 06:45:38 manu Exp $ */
+/*  $NetBSD: perfused.c,v 1.10 2010/09/23 16:02:34 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -124,7 +124,7 @@
 	opt = 0;
 	if (setsockopt(fd, 0, LOCAL_CREDS, &opt, sizeof(opt)) != 0)
 		DWARN("%s: setsockopt LOCAL_CREDS failed", __func__);
-	
+
 #ifdef PERFUSE_DEBUG
 	if (perfuse_diagflags & PDF_MISC)
 		DPRINTF("perfuse lengths: source = %"PRId32", "
@@ -310,6 +310,8 @@
 			retval |= PDF_SYNC;
 		else if (strcmp(opt, "misc") == 0)
 			retval |= PDF_MISC;
+		else if (strcmp(opt, "filename") == 0)
+			retval |= PDF_FILENAME;
 		else
 			DERRX(EX_USAGE, "unknown debug flag \"%s\"", opt);
 	}

Reply via email to