Module Name: src Committed By: manu Date: Sun Oct 3 05:46:48 UTC 2010
Modified Files: src/lib/libperfuse: debug.c ops.c perfuse.c perfuse_priv.h subr.c Log Message: - Correctly handle rename whith overwritten destination - Keep track of file name to avoid lookups when we can. This makes sure we do not have two cookies for the same inode, a situation that cause wreak havoc when we come to remove or rename a node. - Do not use PUFFS_FLAG_BUILDPATH at all, since we now track file names - In open, queue requests after checking for access, as there is no merit to queue a will-be-denied request while we can deny it immediatly - request reclaim of removed nodes at inactive stage To generate a diff of this commit: cvs rdiff -u -r1.4 -r1.5 src/lib/libperfuse/debug.c cvs rdiff -u -r1.18 -r1.19 src/lib/libperfuse/ops.c cvs rdiff -u -r1.9 -r1.10 src/lib/libperfuse/perfuse.c cvs rdiff -u -r1.13 -r1.14 src/lib/libperfuse/perfuse_priv.h cvs rdiff -u -r1.7 -r1.8 src/lib/libperfuse/subr.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.4 src/lib/libperfuse/debug.c:1.5 --- src/lib/libperfuse/debug.c:1.4 Wed Sep 29 08:01:10 2010 +++ src/lib/libperfuse/debug.c Sun Oct 3 05:46:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: debug.c,v 1.4 2010/09/29 08:01:10 manu Exp $ */ +/* $NetBSD: debug.c,v 1.5 2010/10/03 05:46:47 manu Exp $ */ /*- * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. @@ -84,7 +84,7 @@ "READ", "WRITE", "AFTERWRITE", - "OPEN" + "OPEN", "AFTERXCHG" }; Index: src/lib/libperfuse/ops.c diff -u src/lib/libperfuse/ops.c:1.18 src/lib/libperfuse/ops.c:1.19 --- src/lib/libperfuse/ops.c:1.18 Wed Sep 29 08:01:10 2010 +++ src/lib/libperfuse/ops.c Sun Oct 3 05:46:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: ops.c,v 1.18 2010/09/29 08:01:10 manu Exp $ */ +/* $NetBSD: ops.c,v 1.19 2010/10/03 05:46:47 manu Exp $ */ /*- * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. @@ -184,7 +184,7 @@ #ifdef PERFUSE_DEBUG if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0)) DPRINTF("file = \"%s\" flags = 0x%x\n", - (char *)PNPATH((struct puffs_node *)opc), + perfuse_node_path(opc), PERFUSE_NODE_DATA(opc)->pnd_flags); #endif if (pnd) @@ -209,6 +209,14 @@ struct puffs_node *pn; struct vattr *va; + /* + * pcr is NULL for self open through fsync or readdir. + * In both case, access control is useless, as it was + * done before, at open time. + */ + if (pcr == NULL) + return 0; + pn = (struct puffs_node *)opc; va = puffs_pn_getvap(pn); @@ -291,7 +299,8 @@ namelen = PNPLEN(dpn) + 1 + namelen + 1; if ((path = malloc(namelen)) == NULL) DERR(EX_OSERR, "malloc failed"); - (void)snprintf(path, namelen, "%s/%s", (char *)PNPATH(dpn), name); + (void)snprintf(path, namelen, "%s/%s", + perfuse_node_path((puffs_cookie_t)dpn), name); error = node_lookup_common(pu, opc, path, pnp); @@ -308,6 +317,7 @@ struct puffs_node **pnp; { struct perfuse_state *ps; + struct perfuse_node_data *pnd; perfuse_msg_t *pm; struct fuse_entry_out *feo; struct puffs_node *pn; @@ -316,6 +326,35 @@ ps = puffs_getspecific(pu); +#ifdef PERFUSE_DEBUG + if (perfuse_diagflags & PDF_FILENAME) + DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n", + __func__, (void *)opc, perfuse_node_path(opc), path); +#endif + /* + * Is the node already known? + */ + TAILQ_FOREACH(pnd, &PERFUSE_NODE_DATA(opc)->pnd_children, pnd_next) { + if ((pnd->pnd_flags & PND_REMOVED) || + (strcmp(pnd->pnd_name, path) != 0)) + continue; + + /* + * We have a match + */ + if (pnp != NULL) + *pnp = (struct puffs_node *)(pnd->pnd_pn); + +#ifdef PERFUSE_DEBUG + if (perfuse_diagflags & PDF_FILENAME) + DPRINTF("%s: opc = %p, file = \"%s\" found " + "cookie = %p, ino = %"PRId64" for \"%s\"\n", + __func__, (void *)opc, perfuse_node_path(opc), + (void *)pnd->pnd_pn, pnd->pnd_ino, path); +#endif + return 0; + } + len = strlen(path) + 1; pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, NULL); @@ -326,7 +365,7 @@ feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); - pn = perfuse_new_pn(pu, opc); + pn = perfuse_new_pn(pu, path, opc); PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); @@ -376,13 +415,21 @@ if (feo->nodeid == PERFUSE_UNKNOWN_INO) DERRX(EX_SOFTWARE, "%s: no ino", __func__); - pn = perfuse_new_pn(pu, opc); + pn = perfuse_new_pn(pu, pcn->pcn_name, opc); PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); puffs_newinfo_setcookie(pni, pn); + +#ifdef PERFUSE_DEBUG + if (perfuse_diagflags & PDF_FILENAME) + DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " + "ino = %"PRId64"\n", + __func__, (void *)pn, pcn->pcn_name, + PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid); +#endif ps->ps_destroy_msg(pm); - + /* * Set owner and group */ @@ -406,6 +453,7 @@ * The parent directory needs a sync */ PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; + out: ps->ps_destroy_msg(pm); @@ -995,7 +1043,7 @@ * Save the file handle and inode in node private data * so that we can reuse it later */ - pn = perfuse_new_pn(pu, opc); + pn = perfuse_new_pn(pu, name, opc); perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE); PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; @@ -1115,15 +1163,6 @@ if (pnd->pnd_flags & PND_REMOVED) return ENOENT; - /* - * 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; - if (puffs_pn_getvap(pn)->va_type == VDIR) { op = FUSE_OPENDIR; pmode = PUFFS_VREAD|PUFFS_VEXEC; @@ -1166,6 +1205,15 @@ } /* + * 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; + + /* * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE * to O_RDONLY/O_WRONLY while perserving the other options. */ @@ -1192,8 +1240,7 @@ if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) DPRINTF("%s: opc = %p, file = \"%s\", " "ino = %"PRId64", %s%sfh = 0x%"PRIx64"\n", - __func__, (void *)opc, - (char *)PNPATH((struct puffs_node *)opc), + __func__, (void *)opc, perfuse_node_path(opc), pnd->pnd_ino, mode & FREAD ? "r" : "", mode & FWRITE ? "w" : "", foo->fh); #endif @@ -1641,8 +1688,7 @@ #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_SYNC) DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", - __func__, (void*)opc, - (char *)PNPATH((struct puffs_node *)opc), + __func__, (void*)opc, perfuse_node_path(opc), pnd->pnd_flags & PND_DIRTY ? "" : "not "); #endif if (!(pnd->pnd_flags & PND_DIRTY)) @@ -1695,8 +1741,7 @@ #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_SYNC) DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", - __func__, (void*)opc, - (char *)PNPATH((struct puffs_node *)opc)); + __func__, (void*)opc, perfuse_node_path(opc)); #endif out: @@ -1772,12 +1817,6 @@ DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n", __func__, (void *)opc, (void *)targ, pcn->pcn_name); #endif - - ps = puffs_getspecific(pu); - pnd = PERFUSE_NODE_DATA(opc); - name = pcn->pcn_name; - len = pcn->pcn_namelen + 1; - /* * Await for all operations on the deleted node to drain, * as the filesystem may be confused to have it deleted @@ -1786,6 +1825,11 @@ while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) requeue_request(pu, targ, PCQ_AFTERXCHG); + ps = puffs_getspecific(pu); + pnd = PERFUSE_NODE_DATA(opc); + name = pcn->pcn_name; + len = pcn->pcn_namelen + 1; + pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred); path = _GET_INPAYLOAD(ps, pm, char *); (void)strlcpy(path, name, len); @@ -1920,48 +1964,42 @@ if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) goto out; - PERFUSE_NODE_DATA(opc)->pnd_childcount--; - PERFUSE_NODE_DATA(targ_dir)->pnd_childcount++; + if (opc != targ_dir) { + struct perfuse_node_data *srcdir_pnd; + struct perfuse_node_data *dstdir_pnd; + struct perfuse_node_data *src_pnd; + + srcdir_pnd = PERFUSE_NODE_DATA(opc); + dstdir_pnd = PERFUSE_NODE_DATA(targ_dir); + src_pnd = PERFUSE_NODE_DATA(src); - PERFUSE_NODE_DATA(src)->pnd_parent = targ_dir; + TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next); + TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next); - PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; - PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY; + srcdir_pnd->pnd_childcount--; + dstdir_pnd->pnd_childcount++; - if ((struct puffs_node *)targ != NULL) { - struct perfuse_node_data *targ_pnd; - struct perfuse_node_data *src_pnd; + src_pnd->pnd_parent = targ_dir; - /* - * We overwrite a node. src must be freed, as it - * is associated in kernel with the old path. We - * therefore have to transfer perfuse_node_data - * from src to targ. - * - * src cannot be destroyed here as setback is not - * allowed in rename operation. The node is tagged - * with PND_REMOVED, it will be disposed at inactive - * time. - */ - targ_pnd = PERFUSE_NODE_DATA(targ); - src_pnd = PERFUSE_NODE_DATA(src); - puffs_pn_setpriv((struct puffs_node *)targ, src_pnd); - puffs_pn_setpriv((struct puffs_node *)src, targ_pnd); - - PERFUSE_NODE_DATA(src)->pnd_flags |= PND_REMOVED; + PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY; } + (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN); + + PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; + + 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, pcn_src->pcn_name, - pcn_targ->pcn_name, PERFUSE_NODE_DATA(opc)->pnd_ino, - (char *)PNPATH((struct puffs_node *)targ_dir), + "nodeid = %"PRId64" -> nodeid = %"PRId64" \"%s\"\n", + __func__, PERFUSE_NODE_DATA(src)->pnd_ino, + pcn_src->pcn_name, pcn_targ->pcn_name, + PERFUSE_NODE_DATA(opc)->pnd_ino, PERFUSE_NODE_DATA(targ_dir)->pnd_ino, - (char *)PNPATH((struct puffs_node *)opc)); + perfuse_node_path(targ_dir)); #endif out: @@ -2044,7 +2082,6 @@ while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) requeue_request(pu, targ, PCQ_AFTERXCHG); - ps = puffs_getspecific(pu); name = pcn->pcn_name; len = pcn->pcn_namelen + 1; @@ -2069,7 +2106,7 @@ 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)); + perfuse_node_path(targ)); #endif out: ps->ps_destroy_msg(pm); @@ -2369,7 +2406,7 @@ #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_RECLAIM) DPRINTF("%s (nodeid %"PRId64") reclaimed\n", - (char *)PNPATH((struct puffs_node *)opc), pnd->pnd_ino); + perfuse_node_path(opc), pnd->pnd_ino); #endif pn_root = puffs_getroot(pu); @@ -2383,7 +2420,7 @@ if (perfuse_diagflags & PDF_RECLAIM) DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, " "has childcount %d %s%s%s%s, pending ops:%s%s%s\n", - (char *)PNPATH(pn), pnd->pnd_ino, + perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_ino, pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", pnd->pnd_childcount, pnd->pnd_flags & PND_OPEN ? "open " : "not open", @@ -2440,8 +2477,10 @@ struct puffs_usermount *pu; puffs_cookie_t opc; { + struct perfuse_state *ps; struct perfuse_node_data *pnd; + ps = puffs_getspecific(pu); pnd = PERFUSE_NODE_DATA(opc); if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED))) @@ -2481,11 +2520,18 @@ if (pnd->pnd_flags & PND_RFH) (void)perfuse_node_close_common(pu, opc, FREAD); - pnd->pnd_flags &= ~PND_INOPEN; - + /* + * This will cause a reclaim to be sent + */ if (pnd->pnd_flags & PND_REMOVED) puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); + /* + * Schedule awaiting operations + */ + pnd->pnd_flags &= ~PND_INOPEN; + (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); + return 0; } @@ -2814,8 +2860,7 @@ #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_SYNC) DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n", - __func__, (void*)opc, - (char *)PNPATH((struct puffs_node *)opc)); + __func__, (void*)opc, perfuse_node_path(opc)); #endif out: if (pm != NULL) Index: src/lib/libperfuse/perfuse.c diff -u src/lib/libperfuse/perfuse.c:1.9 src/lib/libperfuse/perfuse.c:1.10 --- src/lib/libperfuse/perfuse.c:1.9 Wed Sep 29 08:01:10 2010 +++ src/lib/libperfuse/perfuse.c Sun Oct 3 05:46:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: perfuse.c,v 1.9 2010/09/29 08:01:10 manu Exp $ */ +/* $NetBSD: perfuse.c,v 1.10 2010/10/03 05:46:47 manu Exp $ */ /*- * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. @@ -58,7 +58,6 @@ (void)memset(ps, 0, sizeof(*ps)); ps->ps_max_write = UINT_MAX; ps->ps_max_readahead = UINT_MAX; - TAILQ_INIT(&ps->ps_pnd); return ps; } @@ -411,9 +410,6 @@ if (perfuse_diagflags & PDF_PUFFS) puffs_flags |= PUFFS_FLAG_OPDUMP; - if (perfuse_diagflags & PDF_FILENAME) - puffs_flags |= PUFFS_FLAG_BUILDPATH; - if ((pu = puffs_init(pops, _PATH_PUFFS, name, ps, puffs_flags)) == NULL) DERR(EX_OSERR, "puffs_init failed"); @@ -422,7 +418,7 @@ /* * Setup filesystem root */ - pn_root = perfuse_new_pn(pu, NULL); + pn_root = perfuse_new_pn(pu, "", NULL); PERFUSE_NODE_DATA(pn_root)->pnd_ino = FUSE_ROOT_ID; PERFUSE_NODE_DATA(pn_root)->pnd_parent = pn_root; puffs_setroot(pu, pn_root); Index: src/lib/libperfuse/perfuse_priv.h diff -u src/lib/libperfuse/perfuse_priv.h:1.13 src/lib/libperfuse/perfuse_priv.h:1.14 --- src/lib/libperfuse/perfuse_priv.h:1.13 Wed Sep 29 08:01:10 2010 +++ src/lib/libperfuse/perfuse_priv.h Sun Oct 3 05:46:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: perfuse_priv.h,v 1.13 2010/09/29 08:01:10 manu Exp $ */ +/* $NetBSD: perfuse_priv.h,v 1.14 2010/10/03 05:46:47 manu Exp $ */ /*- * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. @@ -65,8 +65,6 @@ perfuse_get_inpayload_fn ps_get_inpayload; perfuse_get_outhdr_fn ps_get_outhdr; perfuse_get_outpayload_fn ps_get_outpayload; - TAILQ_HEAD(, perfuse_node_data) ps_pnd; - int ps_pnd_count; }; @@ -120,6 +118,8 @@ time_t pnd_timestamp; TAILQ_ENTRY(perfuse_node_data) pnd_next; puffs_cookie_t pnd_pn; + char pnd_name[MAXPATHLEN]; /* node name */ + TAILQ_HEAD(,perfuse_node_data) pnd_children; }; #define PERFUSE_NODE_DATA(opc) \ @@ -140,13 +140,14 @@ __BEGIN_DECLS -struct puffs_node *perfuse_new_pn(struct puffs_usermount *, +struct puffs_node *perfuse_new_pn(struct puffs_usermount *, const char *, struct puffs_node *); void perfuse_destroy_pn(struct puffs_usermount *, struct puffs_node *); 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 *); +char *perfuse_node_path(puffs_cookie_t); int perfuse_node_close_common(struct puffs_usermount *, puffs_cookie_t, int); char *perfuse_fs_mount(int, ssize_t); Index: src/lib/libperfuse/subr.c diff -u src/lib/libperfuse/subr.c:1.7 src/lib/libperfuse/subr.c:1.8 --- src/lib/libperfuse/subr.c:1.7 Wed Sep 29 08:01:10 2010 +++ src/lib/libperfuse/subr.c Sun Oct 3 05:46:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: subr.c,v 1.7 2010/09/29 08:01:10 manu Exp $ */ +/* $NetBSD: subr.c,v 1.8 2010/10/03 05:46:47 manu Exp $ */ /*- * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. @@ -36,9 +36,12 @@ #include "perfuse_priv.h" +static size_t node_path(puffs_cookie_t, char *, size_t); + struct puffs_node * -perfuse_new_pn(pu, parent) +perfuse_new_pn(pu, name, parent) struct puffs_usermount *pu; + const char *name; struct puffs_node *parent; { struct perfuse_state *ps; @@ -61,13 +64,18 @@ pnd->pnd_parent = parent; pnd->pnd_timestamp = time(NULL); pnd->pnd_pn = (puffs_cookie_t)pn; + (void)strlcpy(pnd->pnd_name, name, MAXPATHLEN); TAILQ_INIT(&pnd->pnd_pcq); + TAILQ_INIT(&pnd->pnd_children); + + if (parent != NULL) { + struct perfuse_node_data *parent_pnd; - TAILQ_INSERT_TAIL(&ps->ps_pnd, pnd, pnd_next); - ps->ps_pnd_count++; + parent_pnd = PERFUSE_NODE_DATA(parent); + TAILQ_INSERT_TAIL(&parent_pnd->pnd_children, pnd, pnd_next); - if (parent != NULL) - PERFUSE_NODE_DATA(parent)->pnd_childcount++; + parent_pnd->pnd_childcount++; + } return pn; } @@ -83,8 +91,12 @@ ps = puffs_getspecific(pu); pnd = PERFUSE_NODE_DATA(pn); - TAILQ_REMOVE(&ps->ps_pnd, pnd, pnd_next); - ps->ps_pnd_count--; + if (pnd->pnd_parent != NULL) { + struct perfuse_node_data *parent_pnd; + + parent_pnd = PERFUSE_NODE_DATA(pnd->pnd_parent); + TAILQ_REMOVE(&parent_pnd->pnd_children, pnd, pnd_next); + } if ((pnd = puffs_pn_getpriv(pn)) != NULL) { if (pnd->pnd_parent != NULL) @@ -197,3 +209,34 @@ return FUSE_UNKNOWN_FH; } +static size_t +node_path(opc, buf, buflen) + puffs_cookie_t opc; + char *buf; + size_t buflen; +{ + struct perfuse_node_data *pnd; + size_t written; + + pnd = PERFUSE_NODE_DATA(opc); + if (pnd->pnd_parent == opc) + return 0; + + written = node_path(pnd->pnd_parent, buf, buflen); + buf += written; + buflen -= written; + + return written + snprintf(buf, buflen, "/%s", pnd->pnd_name); +} + +char * +perfuse_node_path(opc) + puffs_cookie_t opc; +{ + static char buf[MAXPATHLEN + 1]; + + if (node_path(opc, buf, sizeof(buf)) == 0) + sprintf(buf, "/"); + + return buf; +}