Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/libperfuse/ops.c,v rcsdiff: /ftp/cvs/cvsroot/src/lib/libperfuse/ops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.84 retrieving revision 1.84.16.1 diff -u -p -r1.84 -r1.84.16.1 --- src/lib/libperfuse/ops.c 2015/06/03 14:07:05 1.84 +++ src/lib/libperfuse/ops.c 2019/06/10 22:05:26 1.84.16.1 @@ -1,4 +1,4 @@ -/* $NetBSD: ops.c,v 1.84 2015/06/03 14:07:05 manu Exp $ */ +/* $NetBSD: ops.c,v 1.84.16.1 2019/06/10 22:05:26 christos Exp $ */ /*- * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. @@ -105,6 +105,9 @@ const int vttoif_tab[9] = { #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) #define VTTOIF(indx) (vttoif_tab[(int)(indx)]) +#define PN_ISDIR(opc) \ + (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) + #if 0 static void print_node(const char *func, puffs_cookie_t opc) @@ -141,7 +144,7 @@ perfuse_node_close_common(struct puffs_u pn = (struct puffs_node *)opc; pnd = PERFUSE_NODE_DATA(pn); - if (puffs_pn_getvap(pn)->va_type == VDIR) { + if (PN_ISDIR(opc)) { op = FUSE_RELEASEDIR; mode = FREAD; } else { @@ -479,13 +482,14 @@ node_lookup_common(struct puffs_usermoun fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); pn->pn_va.va_gen = (u_long)(feo->generation); PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; + PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; *pnp = pn; #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_FILENAME) DPRINTF("%s: opc = %p, looked up opc = %p, " - "nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__, + "nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__, (void *)opc, pn, feo->nodeid, path); #endif @@ -500,11 +504,6 @@ node_lookup_common(struct puffs_usermoun puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); } - if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_NODELEAK) { - PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_NODELEAK; - ps->ps_nodeleakcount--; - } - ps->ps_destroy_msg(pm); return 0; @@ -538,6 +537,7 @@ node_mk_common(struct puffs_usermount *p pn = perfuse_new_pn(pu, pcn->pcn_name, opc); PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; + PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; perfuse_node_cache(ps, pn); @@ -672,7 +672,7 @@ fuse_to_dirent(struct puffs_usermount *p "failed: %d", name, error); } else { fd->ino = pn->pn_va.va_fileid; - (void)perfuse_node_reclaim(pu, pn); + (void)perfuse_node_reclaim2(pu, pn, 1); } } } @@ -1135,7 +1135,7 @@ perfuse_node_lookup(struct puffs_usermou case NAMEI_RENAME: error = sticky_access(opc, pn, pcn->pcn_cred); if (error != 0) { - (void)perfuse_node_reclaim(pu, pn); + (void)perfuse_node_reclaim2(pu, pn, 1); goto out; } break; @@ -1143,6 +1143,7 @@ perfuse_node_lookup(struct puffs_usermou break; } + PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; error = 0; @@ -1182,7 +1183,7 @@ perfuse_node_create(struct puffs_usermou error = node_lookup_common(pu, opc, NULL, pcn->pcn_name, pcn->pcn_cred, &pn); if (error == 0) { - (void)perfuse_node_reclaim(pu, pn); + (void)perfuse_node_reclaim2(pu, pn, 1); error = EEXIST; goto out; } @@ -1252,6 +1253,7 @@ perfuse_node_create(struct puffs_usermou pn = perfuse_new_pn(pu, name, opc); perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE); PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; + PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; perfuse_node_cache(ps, pn); @@ -1360,11 +1362,9 @@ perfuse_node_open2(struct puffs_usermoun int op; struct fuse_open_in *foi; struct fuse_open_out *foo; - struct puffs_node *pn; int error; ps = puffs_getspecific(pu); - pn = (struct puffs_node *)opc; pnd = PERFUSE_NODE_DATA(opc); error = 0; @@ -1373,7 +1373,7 @@ perfuse_node_open2(struct puffs_usermoun node_ref(opc); - if (puffs_pn_getvap(pn)->va_type == VDIR) + if (PN_ISDIR(opc)) op = FUSE_OPENDIR; else op = FUSE_OPEN; @@ -1597,9 +1597,9 @@ perfuse_node_getattr_ttl(struct puffs_us fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); fgi->getattr_flags = 0; fgi->dummy = 0; - fgi->fh = 0; + fgi->fh = FUSE_UNKNOWN_FH; - if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { + if (!PN_ISDIR(opc) && PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { fgi->fh = perfuse_get_fh(opc, FREAD); fgi->getattr_flags |= FUSE_GETATTR_FH; } @@ -1733,7 +1733,7 @@ perfuse_node_setattr_ttl(struct puffs_us node_ref(opc); - if (pnd->pnd_flags & PND_WFH) + if (!PN_ISDIR(opc) && pnd->pnd_flags & PND_WFH) fh = perfuse_get_fh(opc, FWRITE); else fh = FUSE_UNKNOWN_FH; @@ -1959,7 +1959,7 @@ perfuse_node_poll(struct puffs_usermount */ pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); - fpi->fh = perfuse_get_fh(opc, FREAD); + fpi->fh = PN_ISDIR(opc) ? FUSE_UNKNOWN_FH : perfuse_get_fh(opc, FREAD); fpi->kh = 0; fpi->flags = 0; @@ -2015,7 +2015,7 @@ perfuse_node_fsync(struct puffs_usermoun node_ref(opc); - if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) + if (PN_ISDIR(opc)) op = FUSE_FSYNCDIR; else /* VREG but also other types such as VLNK */ op = FUSE_FSYNC; @@ -2518,7 +2518,7 @@ perfuse_node_readdir(struct puffs_usermo goto out; } - fh = perfuse_get_fh(opc, FREAD); + fh = perfuse_get_fh(opc, FREAD); #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_FH) @@ -2682,17 +2682,22 @@ out: } int -perfuse_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) +perfuse_node_reclaim2(struct puffs_usermount *pu, + puffs_cookie_t opc, int nlookup) { struct perfuse_state *ps; perfuse_msg_t *pm; struct perfuse_node_data *pnd; struct fuse_forget_in *ffi; - int nlookup; - struct timespec now; - if (opc == 0) +#ifdef PERFUSE_DEBUG + if (perfuse_diagflags & PDF_RECLAIM) + DPRINTF("%s called with opc = %p, nlookup = %d\n", + __func__, (void *)opc, nlookup); +#endif + if (opc == 0 || nlookup == 0) { return 0; + } ps = puffs_getspecific(pu); pnd = PERFUSE_NODE_DATA(opc); @@ -2703,43 +2708,23 @@ perfuse_node_reclaim(struct puffs_usermo if (pnd->pnd_nodeid == FUSE_ROOT_ID) return 0; +#ifdef PERFUSE_DEBUG + if (perfuse_diagflags & PDF_RECLAIM) + DPRINTF("%s (nodeid %"PRId64") reclaimed, nlookup = %d/%d\n", + perfuse_node_path(ps, opc), pnd->pnd_nodeid, + nlookup, pnd->pnd_puffs_nlookup); +#endif /* - * There is a race condition between reclaim and lookup. - * When looking up an already known node, the kernel cannot - * hold a reference on the result until it gets the PUFFS - * reply. It mayy therefore reclaim the node after the - * userland looked it up, and before it gets the reply. - * On rely, the kernel re-creates the node, but at that - * time the node has been reclaimed in userland. - * - * In order to avoid this, we refuse reclaiming nodes that - * are too young since the last lookup - and that we do - * not have removed on our own, of course. - */ - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - DERR(EX_OSERR, "clock_gettime failed"); - - if (timespeccmp(&pnd->pnd_cn_expire, &now, >) && - !(pnd->pnd_flags & PND_REMOVED)) { - if (!(pnd->pnd_flags & PND_NODELEAK)) { - ps->ps_nodeleakcount++; - pnd->pnd_flags |= PND_NODELEAK; - } - DWARNX("possible leaked node:: opc = %p \"%s\"", - opc, pnd->pnd_name); + * The kernel tells us how many lookups it made, which allows + * us to detect that we have an uncompleted lookup and that the + * node should not dispear. + */ + pnd->pnd_puffs_nlookup -= nlookup; + if (pnd->pnd_puffs_nlookup > 0) return 0; - } node_ref(opc); pnd->pnd_flags |= PND_RECLAIMED; - pnd->pnd_puffs_nlookup--; - nlookup = pnd->pnd_puffs_nlookup; - -#ifdef PERFUSE_DEBUG - if (perfuse_diagflags & PDF_RECLAIM) - DPRINTF("%s (nodeid %"PRId64") reclaimed\n", - perfuse_node_path(ps, opc), pnd->pnd_nodeid); -#endif #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_RECLAIM) @@ -2751,7 +2736,7 @@ perfuse_node_reclaim(struct puffs_usermo pnd->pnd_flags & PND_OPEN ? "open " : "not open", pnd->pnd_flags & PND_RFH ? "r" : "", pnd->pnd_flags & PND_WFH ? "w" : "", - pnd->pnd_flags & PND_BUSY ? "" : " none", + pnd->pnd_flags & PND_BUSY ? " busy" : "", pnd->pnd_flags & PND_INREADDIR ? " readdir" : "", pnd->pnd_flags & PND_INWRITE ? " write" : "", pnd->pnd_flags & PND_INOPEN ? " open" : ""); @@ -2769,17 +2754,6 @@ perfuse_node_reclaim(struct puffs_usermo while (pnd->pnd_ref > 1) requeue_request(pu, opc, PCQ_REF); - /* - * reclaim cancel? - */ - if (pnd->pnd_puffs_nlookup > nlookup) { - pnd->pnd_flags &= ~PND_RECLAIMED; - perfuse_node_cache(ps, opc); - node_rele(opc); - return 0; - } - - #ifdef PERFUSE_DEBUG if ((pnd->pnd_flags & PND_OPEN) || !TAILQ_EMPTY(&pnd->pnd_pcq)) @@ -2818,6 +2792,16 @@ perfuse_node_reclaim(struct puffs_usermo return 0; } +int +perfuse_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) +{ +#ifdef PERFUSE_DEBUG + if (perfuse_diagflags & PDF_RECLAIM) + DPRINTF("perfuse_node_reclaim called\n"); +#endif + return perfuse_node_reclaim2(pu, opc, 1); +} + int perfuse_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) { @@ -2992,15 +2976,24 @@ perfuse_node_advlock(struct puffs_usermo * expect one. E.g.: if we provide none, GlusterFS logs an error * "0-glusterfs-fuse: xl is NULL" * + * There is one exception with directories where filehandle + * is not included, because libfuse uses different filehandle + * in opendir/releasedir/readdir/fsyncdir compared to other + * operations. Who locks a directory anyway? + * * We need the read file handle if the file is open read only, * in order to support shared locks on read-only files. * NB: The kernel always sends advlock for read-only * files at exit time when the process used lock, see * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK */ - if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH) { - error = EBADF; - goto out; + if (!PN_ISDIR(opc)) { + if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH) { + error = EBADF; + goto out; + } + } else { + fh = FUSE_UNKNOWN_FH; } ps = puffs_getspecific(pu); @@ -3097,6 +3090,7 @@ perfuse_node_read(struct puffs_usermount struct perfuse_node_data *pnd; const struct vattr *vap; perfuse_msg_t *pm; + uint64_t fh; struct fuse_read_in *fri; struct fuse_out_header *foh; size_t readen; @@ -3113,6 +3107,8 @@ perfuse_node_read(struct puffs_usermount if (vap->va_type == VDIR) return EISDIR; + fh = perfuse_get_fh(opc, FREAD); /* Cannot be VDIR */ + do { size_t max_read; @@ -3123,7 +3119,7 @@ perfuse_node_read(struct puffs_usermount */ pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); fri = GET_INPAYLOAD(ps, pm, fuse_read_in); - fri->fh = perfuse_get_fh(opc, FREAD); + fri->fh = fh; fri->offset = offset; fri->size = (uint32_t)MIN(*resid, max_read); fri->read_flags = 0; /* XXX Unused by libfuse? */ @@ -3184,6 +3180,7 @@ perfuse_node_write2(struct puffs_usermou struct perfuse_node_data *pnd; struct vattr *vap; perfuse_msg_t *pm; + uint64_t fh; struct fuse_write_in *fwi; struct fuse_write_out *fwo; size_t data_len; @@ -3239,6 +3236,8 @@ perfuse_node_write2(struct puffs_usermou (void *)opc, vap->va_size); #endif + fh = perfuse_get_fh(opc, FWRITE); /* Cannot be VDIR */ + do { size_t max_write; /* @@ -3262,7 +3261,7 @@ perfuse_node_write2(struct puffs_usermou */ pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); - fwi->fh = perfuse_get_fh(opc, FWRITE); + fwi->fh = fh; fwi->offset = offset; fwi->size = (uint32_t)data_len; fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1; @@ -3276,7 +3275,7 @@ perfuse_node_write2(struct puffs_usermou #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_FH) DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", " - "fh = 0x%"PRIx64"\n", __func__, + "fh = 0x%"PRIx64"\n", __func__, (void *)opc, pnd->pnd_nodeid, fwi->fh); #endif if ((error = xchg_msg(pu, opc, pm, @@ -3309,7 +3308,7 @@ out: #ifdef PERFUSE_DEBUG if (perfuse_diagflags & PDF_RESIZE) { if (offset > (off_t)vap->va_size) - DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__, + DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__, (void *)opc, vap->va_size, (long long)offset); else DPRINTF("<< %s %p \n", __func__, (void *)opc); @@ -3671,7 +3670,7 @@ perfuse_node_fallocate(struct puffs_user pm = ps->ps_new_msg(pu, opc, FUSE_FALLOCATE, sizeof(*fai), NULL); fai = GET_INPAYLOAD(ps, pm, fuse_fallocate_in); - fai->fh = perfuse_get_fh(opc, FWRITE); + fai->fh = PN_ISDIR(opc) ? FUSE_UNKNOWN_FH : perfuse_get_fh(opc, FWRITE); fai->offset = off; fai->length = len; fai->mode = 0;