2012-08-16 13:25:43 +04:00
|
|
|
/* $NetBSD: dispatcher.c,v 1.44 2012/08/16 09:25:43 manu Exp $ */
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
/*
|
2008-01-28 21:35:49 +03:00
|
|
|
* Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
|
2007-05-12 01:42:42 +04:00
|
|
|
*
|
|
|
|
* Development of this software was supported by the
|
2008-01-28 21:35:49 +03:00
|
|
|
* Ulla Tuominen Foundation, the Finnish Cultural Foundation and
|
|
|
|
* Research Foundation of Helsinki University of Technology.
|
2007-05-12 01:42:42 +04:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
#if !defined(lint)
|
2012-08-16 13:25:43 +04:00
|
|
|
__RCSID("$NetBSD: dispatcher.c,v 1.44 2012/08/16 09:25:43 manu Exp $");
|
2007-05-12 01:42:42 +04:00
|
|
|
#endif /* !lint */
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
2007-05-18 17:53:54 +04:00
|
|
|
#include <sys/poll.h>
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
2007-10-26 21:35:01 +04:00
|
|
|
#include <pthread.h>
|
2007-05-12 01:42:42 +04:00
|
|
|
#include <puffs.h>
|
|
|
|
#include <puffsdump.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "puffs_priv.h"
|
|
|
|
|
Add PUFFS_KFLAG_CACHE_FS_TTL flag to puffs_init(3) to use name and
attribute cache with filesystem provided TTL.
lookup, create, mknod, mkdir, symlink, getattr and setattr messages
have been extended so that attributes and their TTL can be provided
by the filesytem. lookup, create, mknod, mkdir, and symlink messages
are also extended so that the filesystem can provide name TTL.
The filesystem updates attributes and TTL using
puffs_pn_getvap(3), puffs_pn_getvattl(3), and puffs_pn_getcnttl(3)
2012-04-08 19:07:45 +04:00
|
|
|
#define PUFFS_USE_FS_TTL(pu) (pu->pu_flags & PUFFS_KFLAG_CACHE_FS_TTL)
|
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
static void dispatch(struct puffs_cc *);
|
2007-10-26 21:35:01 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
/* for our eyes only */
|
|
|
|
void
|
|
|
|
puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
|
|
|
{
|
|
|
|
struct puffs_cc *pcc = puffs_cc_getcc(pu);
|
|
|
|
struct puffs_req *preq;
|
2007-10-26 21:35:01 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
pcc->pcc_pb = pb;
|
|
|
|
pcc->pcc_flags |= PCC_MLCONT;
|
|
|
|
dispatch(pcc);
|
2007-10-26 21:35:01 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
/* Put result to kernel sendqueue if necessary */
|
|
|
|
preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
|
|
|
if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
|
|
|
|
if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
|
|
|
|
puffsdump_rv(preq);
|
2007-10-26 21:35:01 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
puffs_framev_enqueue_justsend(pu, pu->pu_fd,
|
|
|
|
pcc->pcc_pb, 0, 0);
|
|
|
|
} else {
|
|
|
|
puffs_framebuf_destroy(pcc->pcc_pb);
|
|
|
|
}
|
2007-10-26 21:35:01 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
/* who needs information when you're living on borrowed time? */
|
|
|
|
if (pcc->pcc_flags & PCC_BORROWED) {
|
|
|
|
puffs_cc_yield(pcc); /* back to borrow source */
|
2007-10-26 21:35:01 +04:00
|
|
|
}
|
2008-01-28 21:35:49 +03:00
|
|
|
pcc->pcc_flags = 0;
|
2007-10-26 21:35:01 +04:00
|
|
|
}
|
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
/* public, but not really tested and only semi-supported */
|
2007-05-12 01:42:42 +04:00
|
|
|
int
|
2008-01-28 21:35:49 +03:00
|
|
|
puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
|
|
|
struct puffs_cc **pccp)
|
2007-05-12 01:42:42 +04:00
|
|
|
{
|
2008-01-28 21:35:49 +03:00
|
|
|
struct puffs_cc *pcc;
|
2007-09-28 01:14:49 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
if (puffs__cc_create(pu, dispatch, &pcc) == -1)
|
|
|
|
return -1;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
pcc->pcc_pb = pb;
|
|
|
|
*pccp = pcc;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
return 0;
|
2007-05-12 01:42:42 +04:00
|
|
|
}
|
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
int
|
|
|
|
puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
|
2007-05-12 01:42:42 +04:00
|
|
|
{
|
2008-01-28 21:35:49 +03:00
|
|
|
int rv;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
puffs_cc_continue(pcc);
|
2007-12-05 00:24:10 +03:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
if (pcc->pcc_flags & PCC_DONE) {
|
|
|
|
rv = 1;
|
|
|
|
*pbp = pcc->pcc_pb;
|
|
|
|
pcc->pcc_flags = 0;
|
|
|
|
puffs__cc_destroy(pcc, 0);
|
|
|
|
} else {
|
|
|
|
rv = 0;
|
2007-05-12 01:42:42 +04:00
|
|
|
}
|
2007-12-05 00:24:10 +03:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
return rv;
|
2007-05-12 01:42:42 +04:00
|
|
|
}
|
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
static void
|
|
|
|
dispatch(struct puffs_cc *pcc)
|
2007-05-12 01:42:42 +04:00
|
|
|
{
|
|
|
|
struct puffs_usermount *pu = pcc->pcc_pu;
|
|
|
|
struct puffs_ops *pops = &pu->pu_ops;
|
2007-12-05 00:24:10 +03:00
|
|
|
struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
2008-03-20 18:28:03 +03:00
|
|
|
void *auxbuf; /* help with typecasting */
|
2008-08-12 23:44:39 +04:00
|
|
|
puffs_cookie_t opcookie;
|
2012-08-16 13:25:43 +04:00
|
|
|
int error = 0, buildpath, pncookie;
|
2008-03-20 18:28:03 +03:00
|
|
|
|
|
|
|
/* XXX: smaller hammer, please */
|
|
|
|
if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS &&
|
|
|
|
preq->preq_optype == PUFFS_VFS_VPTOFH)) ||
|
|
|
|
(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN &&
|
|
|
|
(preq->preq_optype == PUFFS_VN_READDIR
|
|
|
|
|| preq->preq_optype == PUFFS_VN_READ))) {
|
|
|
|
if (puffs_framebuf_reserve_space(pcc->pcc_pb,
|
|
|
|
PUFFS_MSG_MAXSIZE) == -1)
|
|
|
|
error = errno;
|
|
|
|
preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
|
|
|
}
|
|
|
|
|
|
|
|
auxbuf = preq;
|
|
|
|
opcookie = preq->preq_cookie;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
assert((pcc->pcc_flags & PCC_DONE) == 0);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
|
2012-08-16 13:25:43 +04:00
|
|
|
pncookie = pu->pu_flags & PUFFS_FLAG_PNCOOKIE;
|
|
|
|
assert(!buildpath || pncookie);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
preq->preq_setbacks = 0;
|
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
|
|
|
|
puffsdump_req(preq);
|
|
|
|
|
|
|
|
puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
|
|
|
|
|
|
|
|
/* pre-operation */
|
2007-10-28 21:40:30 +03:00
|
|
|
if (pu->pu_oppre)
|
2007-11-30 22:02:28 +03:00
|
|
|
pu->pu_oppre(pu);
|
2007-10-28 21:40:30 +03:00
|
|
|
|
2008-03-20 18:28:03 +03:00
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
/* Execute actual operation */
|
2007-05-12 01:42:42 +04:00
|
|
|
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
|
|
|
|
switch (preq->preq_optype) {
|
|
|
|
case PUFFS_VFS_UNMOUNT:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vfsmsg_unmount *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING);
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags);
|
2007-05-12 01:42:42 +04:00
|
|
|
if (!error)
|
|
|
|
PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
|
|
|
|
else
|
|
|
|
PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VFS_STATVFS:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vfsmsg_statvfs *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VFS_SYNC:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vfsmsg_sync *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_fs_sync(pu,
|
2007-11-27 14:31:17 +03:00
|
|
|
auxt->pvfsr_waitfor, pcr);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VFS_FHTOVP:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vfsmsg_fhtonode *auxt = auxbuf;
|
2007-07-01 22:39:39 +04:00
|
|
|
struct puffs_newinfo pni;
|
|
|
|
|
|
|
|
pni.pni_cookie = &auxt->pvfsr_fhcookie;
|
|
|
|
pni.pni_vtype = &auxt->pvfsr_vtype;
|
|
|
|
pni.pni_size = &auxt->pvfsr_size;
|
|
|
|
pni.pni_rdev = &auxt->pvfsr_rdev;
|
2012-04-18 04:57:21 +04:00
|
|
|
pni.pni_va = NULL;
|
|
|
|
pni.pni_va_ttl = NULL;
|
|
|
|
pni.pni_cn_ttl = NULL;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data,
|
2007-07-01 22:39:39 +04:00
|
|
|
auxt->pvfsr_dsize, &pni);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VFS_VPTOFH:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vfsmsg_nodetofh *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_fs_nodetofh(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
auxt->pvfsr_fhcookie, auxt->pvfsr_data,
|
|
|
|
&auxt->pvfsr_dsize);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-05-21 14:50:52 +04:00
|
|
|
case PUFFS_VFS_EXTATTRCTL:
|
2007-05-12 01:42:42 +04:00
|
|
|
{
|
2010-05-21 14:50:52 +04:00
|
|
|
struct puffs_vfsmsg_extattrctl *auxt = auxbuf;
|
|
|
|
const char *attrname;
|
|
|
|
int flags;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2010-05-21 14:50:52 +04:00
|
|
|
if (pops->puffs_fs_extattrctl == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
2010-05-21 14:50:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME)
|
|
|
|
attrname = auxt->pvfsr_attrname;
|
|
|
|
else
|
|
|
|
attrname = NULL;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2010-05-21 14:50:52 +04:00
|
|
|
flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE;
|
|
|
|
error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd,
|
|
|
|
opcookie, flags,
|
|
|
|
auxt->pvfsr_attrnamespace, attrname);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* I guess the kernel sees this one coming
|
|
|
|
*/
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: audit return values */
|
|
|
|
/* XXX: sync with kernel */
|
|
|
|
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
|
|
|
|
switch (preq->preq_optype) {
|
|
|
|
case PUFFS_VN_LOOKUP:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_lookup *auxt = auxbuf;
|
2007-07-01 22:39:39 +04:00
|
|
|
struct puffs_newinfo pni;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
Add PUFFS_KFLAG_CACHE_FS_TTL flag to puffs_init(3) to use name and
attribute cache with filesystem provided TTL.
lookup, create, mknod, mkdir, symlink, getattr and setattr messages
have been extended so that attributes and their TTL can be provided
by the filesytem. lookup, create, mknod, mkdir, and symlink messages
are also extended so that the filesystem can provide name TTL.
The filesystem updates attributes and TTL using
puffs_pn_getvap(3), puffs_pn_getvattl(3), and puffs_pn_getcnttl(3)
2012-04-08 19:07:45 +04:00
|
|
|
struct puffs_node *pn = NULL;
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
2007-07-01 22:39:39 +04:00
|
|
|
pni.pni_cookie = &auxt->pvnr_newnode;
|
|
|
|
pni.pni_vtype = &auxt->pvnr_vtype;
|
|
|
|
pni.pni_size = &auxt->pvnr_size;
|
|
|
|
pni.pni_rdev = &auxt->pvnr_rdev;
|
2012-04-18 04:57:21 +04:00
|
|
|
pni.pni_va = &auxt->pvnr_va;
|
|
|
|
pni.pni_va_ttl = &auxt->pvnr_va_ttl;
|
|
|
|
pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
|
2007-07-01 19:30:15 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn, opcookie);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lookup *must* be present */
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_lookup(pu, opcookie,
|
2007-07-01 22:39:39 +04:00
|
|
|
&pni, &pcn);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
if (buildpath) {
|
|
|
|
if (error) {
|
|
|
|
pu->pu_pathfree(pu, &pcn.pcn_po_full);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* did we get a new node or a
|
|
|
|
* recycled node?
|
|
|
|
*/
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
if (pn->pn_po.po_path == NULL)
|
|
|
|
pn->pn_po = pcn.pcn_po_full;
|
|
|
|
else
|
|
|
|
pu->pu_pathfree(pu,
|
|
|
|
&pcn.pcn_po_full);
|
|
|
|
}
|
|
|
|
}
|
- Improve PUFFS_KFLAG_CACHE_FS_TTL by reclaiming older inactive nodes.
The normal kernel behavior is to retain inactive nodes in the freelist
until it runs out of vnodes. This has some merit for local filesystems,
where the cost of an allocation is about the same as the cost of a
lookup. But that situation is not true for distributed filesystems.
On the other hand, keeping inactive nodes for a long time hold memory
in the file server process, and when the kernel runs out of vnodes, it
produce reclaim avalanches that increase lattency for other operations.
We do not reclaim inactive vnodes immediatly either, as they may be
looked up again shortly. Instead we introduce a grace time and we
reclaim nodes that have been inactive beyond the grace time.
- Fix lookup/reclaim race condition.
The above improvement undercovered a race condition between lookup and
reclaim. If we reclaimed a vnode associated with a userland cookie while
a lookup returning that same cookiewas inprogress, then the kernel ends
up with a vnode associated with a cookie that has been reclaimed in
userland. Next operation on the cookie will crash (or at least confuse)
the filesystem.
We fix this by introducing a lookup count in kernel and userland. On
reclaim, the kernel sends the count, which enable userland to detect
situation where it initiated a lookup that is not completed in kernel.
In such a situation, the reclaim must be ignored, as the node is about
to be looked up again.
2012-07-21 09:17:10 +04:00
|
|
|
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pncookie && !error) {
|
- Improve PUFFS_KFLAG_CACHE_FS_TTL by reclaiming older inactive nodes.
The normal kernel behavior is to retain inactive nodes in the freelist
until it runs out of vnodes. This has some merit for local filesystems,
where the cost of an allocation is about the same as the cost of a
lookup. But that situation is not true for distributed filesystems.
On the other hand, keeping inactive nodes for a long time hold memory
in the file server process, and when the kernel runs out of vnodes, it
produce reclaim avalanches that increase lattency for other operations.
We do not reclaim inactive vnodes immediatly either, as they may be
looked up again shortly. Instead we introduce a grace time and we
reclaim nodes that have been inactive beyond the grace time.
- Fix lookup/reclaim race condition.
The above improvement undercovered a race condition between lookup and
reclaim. If we reclaimed a vnode associated with a userland cookie while
a lookup returning that same cookiewas inprogress, then the kernel ends
up with a vnode associated with a cookie that has been reclaimed in
userland. Next operation on the cookie will crash (or at least confuse)
the filesystem.
We fix this by introducing a lookup count in kernel and userland. On
reclaim, the kernel sends the count, which enable userland to detect
situation where it initiated a lookup that is not completed in kernel.
In such a situation, the reclaim must be ignored, as the node is about
to be looked up again.
2012-07-21 09:17:10 +04:00
|
|
|
if (pn == NULL)
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_nlookup++;
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_CREATE:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_create *auxt = auxbuf;
|
2007-07-01 22:39:39 +04:00
|
|
|
struct puffs_newinfo pni;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
2012-08-10 12:42:10 +04:00
|
|
|
struct puffs_node *pn = NULL;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_create == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
|
|
|
|
2007-07-01 22:39:39 +04:00
|
|
|
memset(&pni, 0, sizeof(pni));
|
|
|
|
pni.pni_cookie = &auxt->pvnr_newnode;
|
2012-04-18 04:57:21 +04:00
|
|
|
pni.pni_va = &auxt->pvnr_va;
|
|
|
|
pni.pni_va_ttl = &auxt->pvnr_va_ttl;
|
|
|
|
pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn, opcookie);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_create(pu,
|
2007-07-01 22:39:39 +04:00
|
|
|
opcookie, &pni, &pcn, &auxt->pvnr_va);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
if (buildpath) {
|
|
|
|
if (error) {
|
|
|
|
pu->pu_pathfree(pu, &pcn.pcn_po_full);
|
|
|
|
} else {
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_po = pcn.pcn_po_full;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pncookie && !error) {
|
2012-08-10 12:42:10 +04:00
|
|
|
if (pn == NULL)
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_nlookup++;
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_MKNOD:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_mknod *auxt = auxbuf;
|
2007-07-01 22:39:39 +04:00
|
|
|
struct puffs_newinfo pni;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
2012-08-10 12:42:10 +04:00
|
|
|
struct puffs_node *pn = NULL;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_mknod == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
|
|
|
|
2007-07-01 22:39:39 +04:00
|
|
|
memset(&pni, 0, sizeof(pni));
|
|
|
|
pni.pni_cookie = &auxt->pvnr_newnode;
|
2012-04-18 04:57:21 +04:00
|
|
|
pni.pni_va = &auxt->pvnr_va;
|
|
|
|
pni.pni_va_ttl = &auxt->pvnr_va_ttl;
|
|
|
|
pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn, opcookie);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_mknod(pu,
|
2007-07-01 22:39:39 +04:00
|
|
|
opcookie, &pni, &pcn, &auxt->pvnr_va);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
if (buildpath) {
|
|
|
|
if (error) {
|
|
|
|
pu->pu_pathfree(pu, &pcn.pcn_po_full);
|
|
|
|
} else {
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_po = pcn.pcn_po_full;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pncookie && !error) {
|
2012-08-10 12:42:10 +04:00
|
|
|
if (pn == NULL)
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_nlookup++;
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_OPEN:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_open *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_open == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_open(pu,
|
2007-11-27 14:31:17 +03:00
|
|
|
opcookie, auxt->pvnr_mode, pcr);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_CLOSE:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_close *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_close == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_close(pu,
|
2007-11-27 14:31:17 +03:00
|
|
|
opcookie, auxt->pvnr_fflag, pcr);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_ACCESS:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_access *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_access == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_access(pu,
|
2007-11-27 14:31:17 +03:00
|
|
|
opcookie, auxt->pvnr_mode, pcr);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_GETATTR:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_getattr *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
if (PUFFS_USE_FS_TTL(pu)) {
|
|
|
|
if (pops->puffs_node_getattr_ttl == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
Add PUFFS_KFLAG_CACHE_FS_TTL flag to puffs_init(3) to use name and
attribute cache with filesystem provided TTL.
lookup, create, mknod, mkdir, symlink, getattr and setattr messages
have been extended so that attributes and their TTL can be provided
by the filesytem. lookup, create, mknod, mkdir, and symlink messages
are also extended so that the filesystem can provide name TTL.
The filesystem updates attributes and TTL using
puffs_pn_getvap(3), puffs_pn_getvattl(3), and puffs_pn_getcnttl(3)
2012-04-08 19:07:45 +04:00
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
error = pops->puffs_node_getattr_ttl(pu,
|
|
|
|
opcookie, &auxt->pvnr_va, pcr,
|
|
|
|
&auxt->pvnr_va_ttl);
|
|
|
|
} else {
|
|
|
|
if (pops->puffs_node_getattr == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
Add PUFFS_KFLAG_CACHE_FS_TTL flag to puffs_init(3) to use name and
attribute cache with filesystem provided TTL.
lookup, create, mknod, mkdir, symlink, getattr and setattr messages
have been extended so that attributes and their TTL can be provided
by the filesytem. lookup, create, mknod, mkdir, and symlink messages
are also extended so that the filesystem can provide name TTL.
The filesystem updates attributes and TTL using
puffs_pn_getvap(3), puffs_pn_getvattl(3), and puffs_pn_getcnttl(3)
2012-04-08 19:07:45 +04:00
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
error = pops->puffs_node_getattr(pu,
|
|
|
|
opcookie, &auxt->pvnr_va, pcr);
|
Add PUFFS_KFLAG_CACHE_FS_TTL flag to puffs_init(3) to use name and
attribute cache with filesystem provided TTL.
lookup, create, mknod, mkdir, symlink, getattr and setattr messages
have been extended so that attributes and their TTL can be provided
by the filesytem. lookup, create, mknod, mkdir, and symlink messages
are also extended so that the filesystem can provide name TTL.
The filesystem updates attributes and TTL using
puffs_pn_getvap(3), puffs_pn_getvattl(3), and puffs_pn_getcnttl(3)
2012-04-08 19:07:45 +04:00
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_SETATTR:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_setattr *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
if (PUFFS_USE_FS_TTL(pu)) {
|
2012-06-27 17:25:23 +04:00
|
|
|
int xflag = 0;
|
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
if (pops->puffs_node_setattr_ttl == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2012-06-27 17:25:23 +04:00
|
|
|
if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
|
|
|
|
xflag |= PUFFS_SETATTR_FAF;
|
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
error = pops->puffs_node_setattr_ttl(pu,
|
|
|
|
opcookie, &auxt->pvnr_va, pcr,
|
2012-06-27 17:25:23 +04:00
|
|
|
&auxt->pvnr_va_ttl, xflag);
|
2012-04-18 04:57:21 +04:00
|
|
|
} else {
|
|
|
|
if (pops->puffs_node_setattr == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
Add PUFFS_KFLAG_CACHE_FS_TTL flag to puffs_init(3) to use name and
attribute cache with filesystem provided TTL.
lookup, create, mknod, mkdir, symlink, getattr and setattr messages
have been extended so that attributes and their TTL can be provided
by the filesytem. lookup, create, mknod, mkdir, and symlink messages
are also extended so that the filesystem can provide name TTL.
The filesystem updates attributes and TTL using
puffs_pn_getvap(3), puffs_pn_getvattl(3), and puffs_pn_getcnttl(3)
2012-04-08 19:07:45 +04:00
|
|
|
|
2012-04-18 04:57:21 +04:00
|
|
|
error = pops->puffs_node_setattr(pu,
|
|
|
|
opcookie, &auxt->pvnr_va, pcr);
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_MMAP:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_mmap *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_mmap == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_mmap(pu,
|
2007-11-27 14:31:17 +03:00
|
|
|
opcookie, auxt->pvnr_prot, pcr);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_FSYNC:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_fsync *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_fsync == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_fsync(pu, opcookie, pcr,
|
2007-05-12 01:42:42 +04:00
|
|
|
auxt->pvnr_flags, auxt->pvnr_offlo,
|
2007-11-27 14:31:17 +03:00
|
|
|
auxt->pvnr_offhi);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_SEEK:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_seek *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_seek == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_seek(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_oldoff,
|
2007-07-01 19:30:15 +04:00
|
|
|
auxt->pvnr_newoff, pcr);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_REMOVE:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_remove *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
|
|
|
if (pops->puffs_node_remove == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_remove(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_cookie_targ, &pcn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_LINK:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_link *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
|
|
|
if (pops->puffs_node_link == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn, opcookie);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_link(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_cookie_targ, &pcn);
|
|
|
|
if (buildpath)
|
|
|
|
pu->pu_pathfree(pu, &pcn.pcn_po_full);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_RENAME:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_rename *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn_src, pcn_targ;
|
|
|
|
struct puffs_node *pn_src;
|
|
|
|
|
|
|
|
if (pops->puffs_node_rename == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn_src.pcn_cred,
|
|
|
|
&auxt->pvnr_cn_src_cred);
|
2007-07-01 21:22:13 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn_targ.pcn_cred,
|
|
|
|
&auxt->pvnr_cn_targ_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
pn_src = auxt->pvnr_cookie_src;
|
|
|
|
pcn_src.pcn_po_full = pn_src->pn_po;
|
|
|
|
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn_targ,
|
|
|
|
auxt->pvnr_cookie_targdir);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_rename(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_cookie_src,
|
|
|
|
&pcn_src, auxt->pvnr_cookie_targdir,
|
|
|
|
auxt->pvnr_cookie_targ, &pcn_targ);
|
|
|
|
|
|
|
|
if (buildpath) {
|
|
|
|
if (error) {
|
|
|
|
pu->pu_pathfree(pu,
|
|
|
|
&pcn_targ.pcn_po_full);
|
|
|
|
} else {
|
|
|
|
struct puffs_pathinfo pi;
|
|
|
|
struct puffs_pathobj po_old;
|
|
|
|
|
|
|
|
/* handle this node */
|
|
|
|
po_old = pn_src->pn_po;
|
|
|
|
pn_src->pn_po = pcn_targ.pcn_po_full;
|
|
|
|
|
|
|
|
if (pn_src->pn_va.va_type != VDIR) {
|
|
|
|
pu->pu_pathfree(pu, &po_old);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle all child nodes for DIRs */
|
|
|
|
pi.pi_old = &pcn_src.pcn_po_full;
|
|
|
|
pi.pi_new = &pcn_targ.pcn_po_full;
|
|
|
|
|
2007-10-29 18:52:44 +03:00
|
|
|
PU_LOCK();
|
2007-05-12 01:42:42 +04:00
|
|
|
if (puffs_pn_nodewalk(pu,
|
|
|
|
puffs_path_prefixadj, &pi) != NULL)
|
|
|
|
error = ENOMEM;
|
2007-10-29 18:52:44 +03:00
|
|
|
PU_UNLOCK();
|
2007-05-12 01:42:42 +04:00
|
|
|
pu->pu_pathfree(pu, &po_old);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_MKDIR:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_mkdir *auxt = auxbuf;
|
2007-07-01 22:39:39 +04:00
|
|
|
struct puffs_newinfo pni;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
2012-08-10 12:42:10 +04:00
|
|
|
struct puffs_node *pn = NULL;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_mkdir == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
|
|
|
|
2007-07-01 22:39:39 +04:00
|
|
|
memset(&pni, 0, sizeof(pni));
|
|
|
|
pni.pni_cookie = &auxt->pvnr_newnode;
|
2012-04-18 04:57:21 +04:00
|
|
|
pni.pni_va = &auxt->pvnr_va;
|
|
|
|
pni.pni_va_ttl = &auxt->pvnr_va_ttl;
|
|
|
|
pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn, opcookie);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_mkdir(pu,
|
2007-07-01 22:39:39 +04:00
|
|
|
opcookie, &pni, &pcn, &auxt->pvnr_va);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
if (buildpath) {
|
|
|
|
if (error) {
|
|
|
|
pu->pu_pathfree(pu, &pcn.pcn_po_full);
|
|
|
|
} else {
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_po = pcn.pcn_po_full;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pncookie && !error) {
|
2012-08-10 12:42:10 +04:00
|
|
|
if (pn == NULL)
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_nlookup++;
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_RMDIR:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_rmdir *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
|
|
|
if (pops->puffs_node_rmdir == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_rmdir(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_cookie_targ, &pcn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_SYMLINK:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_symlink *auxt = auxbuf;
|
2007-07-01 22:39:39 +04:00
|
|
|
struct puffs_newinfo pni;
|
2007-05-12 01:42:42 +04:00
|
|
|
struct puffs_cn pcn;
|
2012-08-10 12:42:10 +04:00
|
|
|
struct puffs_node *pn = NULL;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_symlink == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
|
|
|
|
2007-07-01 22:39:39 +04:00
|
|
|
memset(&pni, 0, sizeof(pni));
|
|
|
|
pni.pni_cookie = &auxt->pvnr_newnode;
|
2012-04-18 04:57:21 +04:00
|
|
|
pni.pni_va = &auxt->pvnr_va;
|
|
|
|
pni.pni_va_ttl = &auxt->pvnr_va_ttl;
|
|
|
|
pni.pni_cn_ttl = &auxt->pvnr_cn_ttl;
|
2007-07-01 22:39:39 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (buildpath) {
|
|
|
|
error = puffs_path_pcnbuild(pu, &pcn, opcookie);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_symlink(pu,
|
2007-07-01 22:39:39 +04:00
|
|
|
opcookie, &pni, &pcn,
|
|
|
|
&auxt->pvnr_va, auxt->pvnr_link);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
if (buildpath) {
|
|
|
|
if (error) {
|
|
|
|
pu->pu_pathfree(pu, &pcn.pcn_po_full);
|
|
|
|
} else {
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_po = pcn.pcn_po_full;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pncookie && !error) {
|
2012-08-10 12:42:10 +04:00
|
|
|
if (pn == NULL)
|
|
|
|
pn = PU_CMAP(pu, auxt->pvnr_newnode);
|
|
|
|
pn->pn_nlookup++;
|
|
|
|
}
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_READDIR:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_readdir *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
2007-05-12 01:42:42 +04:00
|
|
|
struct dirent *dent;
|
|
|
|
off_t *cookies;
|
|
|
|
size_t res, origcookies;
|
|
|
|
|
|
|
|
if (pops->puffs_node_readdir == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auxt->pvnr_ncookies) {
|
|
|
|
/* LINTED: pvnr_data is __aligned() */
|
|
|
|
cookies = (off_t *)auxt->pvnr_data;
|
|
|
|
origcookies = auxt->pvnr_ncookies;
|
|
|
|
} else {
|
|
|
|
cookies = NULL;
|
|
|
|
origcookies = 0;
|
|
|
|
}
|
|
|
|
/* LINTED: dentoff is aligned in the kernel */
|
|
|
|
dent = (struct dirent *)
|
|
|
|
(auxt->pvnr_data + auxt->pvnr_dentoff);
|
|
|
|
|
|
|
|
res = auxt->pvnr_resid;
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_readdir(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, dent, &auxt->pvnr_offset,
|
2007-07-01 19:30:15 +04:00
|
|
|
&auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag,
|
|
|
|
cookies, &auxt->pvnr_ncookies);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
/* much easier to track non-working NFS */
|
|
|
|
assert(auxt->pvnr_ncookies <= origcookies);
|
|
|
|
|
|
|
|
/* need to move a bit more */
|
2007-10-11 23:41:13 +04:00
|
|
|
preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir)
|
2007-05-12 01:42:42 +04:00
|
|
|
+ auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_READLINK:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_readlink *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_readlink == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-07-01 19:30:15 +04:00
|
|
|
/*LINTED*/
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_readlink(pu, opcookie, pcr,
|
2007-05-12 01:42:42 +04:00
|
|
|
auxt->pvnr_link, &auxt->pvnr_linklen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_RECLAIM:
|
|
|
|
{
|
- Improve PUFFS_KFLAG_CACHE_FS_TTL by reclaiming older inactive nodes.
The normal kernel behavior is to retain inactive nodes in the freelist
until it runs out of vnodes. This has some merit for local filesystems,
where the cost of an allocation is about the same as the cost of a
lookup. But that situation is not true for distributed filesystems.
On the other hand, keeping inactive nodes for a long time hold memory
in the file server process, and when the kernel runs out of vnodes, it
produce reclaim avalanches that increase lattency for other operations.
We do not reclaim inactive vnodes immediatly either, as they may be
looked up again shortly. Instead we introduce a grace time and we
reclaim nodes that have been inactive beyond the grace time.
- Fix lookup/reclaim race condition.
The above improvement undercovered a race condition between lookup and
reclaim. If we reclaimed a vnode associated with a userland cookie while
a lookup returning that same cookiewas inprogress, then the kernel ends
up with a vnode associated with a cookie that has been reclaimed in
userland. Next operation on the cookie will crash (or at least confuse)
the filesystem.
We fix this by introducing a lookup count in kernel and userland. On
reclaim, the kernel sends the count, which enable userland to detect
situation where it initiated a lookup that is not completed in kernel.
In such a situation, the reclaim must be ignored, as the node is about
to be looked up again.
2012-07-21 09:17:10 +04:00
|
|
|
struct puffs_vnmsg_reclaim *auxt = auxbuf;
|
|
|
|
struct puffs_node *pn;
|
|
|
|
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pops->puffs_node_reclaim2 != NULL) {
|
|
|
|
error = pops->puffs_node_reclaim2(pu, opcookie,
|
|
|
|
auxt->pvnr_nlookup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_reclaim == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
- Improve PUFFS_KFLAG_CACHE_FS_TTL by reclaiming older inactive nodes.
The normal kernel behavior is to retain inactive nodes in the freelist
until it runs out of vnodes. This has some merit for local filesystems,
where the cost of an allocation is about the same as the cost of a
lookup. But that situation is not true for distributed filesystems.
On the other hand, keeping inactive nodes for a long time hold memory
in the file server process, and when the kernel runs out of vnodes, it
produce reclaim avalanches that increase lattency for other operations.
We do not reclaim inactive vnodes immediatly either, as they may be
looked up again shortly. Instead we introduce a grace time and we
reclaim nodes that have been inactive beyond the grace time.
- Fix lookup/reclaim race condition.
The above improvement undercovered a race condition between lookup and
reclaim. If we reclaimed a vnode associated with a userland cookie while
a lookup returning that same cookiewas inprogress, then the kernel ends
up with a vnode associated with a cookie that has been reclaimed in
userland. Next operation on the cookie will crash (or at least confuse)
the filesystem.
We fix this by introducing a lookup count in kernel and userland. On
reclaim, the kernel sends the count, which enable userland to detect
situation where it initiated a lookup that is not completed in kernel.
In such a situation, the reclaim must be ignored, as the node is about
to be looked up again.
2012-07-21 09:17:10 +04:00
|
|
|
/*
|
|
|
|
* This fixes a race condition,
|
|
|
|
* where a node in reclaimed by kernel
|
|
|
|
* after a lookup request is sent,
|
|
|
|
* but before the reply, leaving the kernel
|
|
|
|
* with a invalid vnode/cookie reference.
|
|
|
|
*/
|
2012-08-16 13:25:43 +04:00
|
|
|
if (pncookie) {
|
|
|
|
pn = PU_CMAP(pu, opcookie);
|
|
|
|
pn->pn_nlookup -= auxt->pvnr_nlookup;
|
|
|
|
if (pn->pn_nlookup >= 1) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
- Improve PUFFS_KFLAG_CACHE_FS_TTL by reclaiming older inactive nodes.
The normal kernel behavior is to retain inactive nodes in the freelist
until it runs out of vnodes. This has some merit for local filesystems,
where the cost of an allocation is about the same as the cost of a
lookup. But that situation is not true for distributed filesystems.
On the other hand, keeping inactive nodes for a long time hold memory
in the file server process, and when the kernel runs out of vnodes, it
produce reclaim avalanches that increase lattency for other operations.
We do not reclaim inactive vnodes immediatly either, as they may be
looked up again shortly. Instead we introduce a grace time and we
reclaim nodes that have been inactive beyond the grace time.
- Fix lookup/reclaim race condition.
The above improvement undercovered a race condition between lookup and
reclaim. If we reclaimed a vnode associated with a userland cookie while
a lookup returning that same cookiewas inprogress, then the kernel ends
up with a vnode associated with a cookie that has been reclaimed in
userland. Next operation on the cookie will crash (or at least confuse)
the filesystem.
We fix this by introducing a lookup count in kernel and userland. On
reclaim, the kernel sends the count, which enable userland to detect
situation where it initiated a lookup that is not completed in kernel.
In such a situation, the reclaim must be ignored, as the node is about
to be looked up again.
2012-07-21 09:17:10 +04:00
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_reclaim(pu, opcookie);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_INACTIVE:
|
|
|
|
{
|
2007-07-01 21:22:13 +04:00
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_inactive == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_inactive(pu, opcookie);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_PATHCONF:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_pathconf *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_pathconf == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_pathconf(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_name,
|
|
|
|
&auxt->pvnr_retval);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_ADVLOCK:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_advlock *auxt = auxbuf;
|
2007-05-12 01:42:42 +04:00
|
|
|
if (pops->puffs_node_advlock == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_advlock(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_id, auxt->pvnr_op,
|
|
|
|
&auxt->pvnr_fl, auxt->pvnr_flags);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_PRINT:
|
|
|
|
{
|
|
|
|
if (pops->puffs_node_print == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_print(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-10-18 03:19:52 +04:00
|
|
|
case PUFFS_VN_ABORTOP:
|
|
|
|
{
|
|
|
|
struct puffs_vnmsg_abortop *auxt = auxbuf;
|
|
|
|
struct puffs_cn pcn;
|
|
|
|
|
|
|
|
if (pops->puffs_node_abortop == NULL) {
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcn.pcn_pkcnp = &auxt->pvnr_cn;
|
|
|
|
PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred);
|
|
|
|
|
|
|
|
error = pops->puffs_node_abortop(pu, opcookie, &pcn);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
case PUFFS_VN_READ:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_read *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
2007-05-12 01:42:42 +04:00
|
|
|
size_t res;
|
|
|
|
|
|
|
|
if (pops->puffs_node_read == NULL) {
|
|
|
|
error = EIO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = auxt->pvnr_resid;
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_read(pu,
|
2007-05-12 01:42:42 +04:00
|
|
|
opcookie, auxt->pvnr_data,
|
|
|
|
auxt->pvnr_offset, &auxt->pvnr_resid,
|
2007-07-01 19:30:15 +04:00
|
|
|
pcr, auxt->pvnr_ioflag);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
|
|
|
/* need to move a bit more */
|
2007-10-11 23:41:13 +04:00
|
|
|
preq->preq_buflen = sizeof(struct puffs_vnmsg_read)
|
2007-05-12 01:42:42 +04:00
|
|
|
+ (res - auxt->pvnr_resid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_WRITE:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_write *auxt = auxbuf;
|
2007-07-01 19:30:15 +04:00
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
2007-05-12 01:42:42 +04:00
|
|
|
|
2012-06-27 17:25:23 +04:00
|
|
|
if (pops->puffs_node_write2 != NULL) {
|
|
|
|
int xflag = 0;
|
|
|
|
|
|
|
|
if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
|
|
|
|
xflag |= PUFFS_SETATTR_FAF;
|
|
|
|
|
|
|
|
error = pops->puffs_node_write2(pu,
|
|
|
|
opcookie, auxt->pvnr_data,
|
|
|
|
auxt->pvnr_offset, &auxt->pvnr_resid,
|
|
|
|
pcr, auxt->pvnr_ioflag, xflag);
|
|
|
|
|
|
|
|
} else if (pops->puffs_node_write != NULL) {
|
|
|
|
error = pops->puffs_node_write(pu,
|
|
|
|
opcookie, auxt->pvnr_data,
|
|
|
|
auxt->pvnr_offset, &auxt->pvnr_resid,
|
|
|
|
pcr, auxt->pvnr_ioflag);
|
|
|
|
} else {
|
2007-05-12 01:42:42 +04:00
|
|
|
error = EIO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* don't need to move data back to the kernel */
|
2007-10-11 23:41:13 +04:00
|
|
|
preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
|
2007-05-12 01:42:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-18 17:53:54 +04:00
|
|
|
case PUFFS_VN_POLL:
|
|
|
|
{
|
2007-10-11 23:41:13 +04:00
|
|
|
struct puffs_vnmsg_poll *auxt = auxbuf;
|
2007-07-01 21:22:13 +04:00
|
|
|
|
2007-05-18 17:53:54 +04:00
|
|
|
if (pops->puffs_node_poll == NULL) {
|
|
|
|
error = 0;
|
|
|
|
|
|
|
|
/* emulate genfs_poll() */
|
|
|
|
auxt->pvnr_events &= (POLLIN | POLLOUT
|
|
|
|
| POLLRDNORM | POLLWRNORM);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:02:28 +03:00
|
|
|
error = pops->puffs_node_poll(pu,
|
2007-11-27 14:31:17 +03:00
|
|
|
opcookie, &auxt->pvnr_events);
|
2007-05-18 17:53:54 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-05-21 14:50:52 +04:00
|
|
|
case PUFFS_VN_GETEXTATTR:
|
|
|
|
{
|
|
|
|
struct puffs_vnmsg_getextattr *auxt = auxbuf;
|
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
size_t res, *resp, *sizep;
|
|
|
|
uint8_t *data;
|
|
|
|
|
|
|
|
if (pops->puffs_node_getextattr == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auxt->pvnr_datasize)
|
|
|
|
sizep = &auxt->pvnr_datasize;
|
|
|
|
else
|
|
|
|
sizep = NULL;
|
|
|
|
|
|
|
|
res = auxt->pvnr_resid;
|
|
|
|
if (res > 0) {
|
|
|
|
data = auxt->pvnr_data;
|
|
|
|
resp = &auxt->pvnr_resid;
|
|
|
|
} else {
|
|
|
|
data = NULL;
|
|
|
|
resp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = pops->puffs_node_getextattr(pu,
|
|
|
|
opcookie, auxt->pvnr_attrnamespace,
|
|
|
|
auxt->pvnr_attrname, sizep, data, resp, pcr);
|
|
|
|
|
|
|
|
/* need to move a bit more? */
|
|
|
|
preq->preq_buflen =
|
|
|
|
sizeof(struct puffs_vnmsg_getextattr)
|
|
|
|
+ (res - auxt->pvnr_resid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_SETEXTATTR:
|
|
|
|
{
|
|
|
|
struct puffs_vnmsg_setextattr *auxt = auxbuf;
|
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
size_t *resp;
|
|
|
|
uint8_t *data;
|
|
|
|
|
|
|
|
if (pops->puffs_node_setextattr == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auxt->pvnr_resid > 0) {
|
|
|
|
data = auxt->pvnr_data;
|
|
|
|
resp = &auxt->pvnr_resid;
|
|
|
|
} else {
|
|
|
|
data = NULL;
|
|
|
|
resp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = pops->puffs_node_setextattr(pu,
|
|
|
|
opcookie, auxt->pvnr_attrnamespace,
|
|
|
|
auxt->pvnr_attrname, data, resp, pcr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_LISTEXTATTR:
|
|
|
|
{
|
|
|
|
struct puffs_vnmsg_listextattr *auxt = auxbuf;
|
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
size_t res, *resp, *sizep;
|
2011-07-04 12:07:29 +04:00
|
|
|
int flag;
|
2010-05-21 14:50:52 +04:00
|
|
|
uint8_t *data;
|
|
|
|
|
|
|
|
if (pops->puffs_node_listextattr == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auxt->pvnr_datasize)
|
|
|
|
sizep = &auxt->pvnr_datasize;
|
|
|
|
else
|
|
|
|
sizep = NULL;
|
|
|
|
|
|
|
|
res = auxt->pvnr_resid;
|
|
|
|
if (res > 0) {
|
|
|
|
data = auxt->pvnr_data;
|
|
|
|
resp = &auxt->pvnr_resid;
|
|
|
|
} else {
|
|
|
|
data = NULL;
|
|
|
|
resp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = auxt->pvnr_resid;
|
2011-07-04 12:07:29 +04:00
|
|
|
flag = auxt->pvnr_flag;
|
2010-05-21 14:50:52 +04:00
|
|
|
error = pops->puffs_node_listextattr(pu,
|
|
|
|
opcookie, auxt->pvnr_attrnamespace,
|
2011-07-04 12:07:29 +04:00
|
|
|
sizep, data, resp, flag, pcr);
|
2010-05-21 14:50:52 +04:00
|
|
|
|
|
|
|
/* need to move a bit more? */
|
|
|
|
preq->preq_buflen =
|
|
|
|
sizeof(struct puffs_vnmsg_listextattr)
|
|
|
|
+ (res - auxt->pvnr_resid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PUFFS_VN_DELETEEXTATTR:
|
|
|
|
{
|
|
|
|
struct puffs_vnmsg_deleteextattr *auxt = auxbuf;
|
|
|
|
PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
|
|
|
|
|
|
|
|
if (pops->puffs_node_deleteextattr == NULL) {
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = pops->puffs_node_deleteextattr(pu,
|
|
|
|
opcookie, auxt->pvnr_attrnamespace,
|
|
|
|
auxt->pvnr_attrname, pcr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-12 01:42:42 +04:00
|
|
|
default:
|
|
|
|
printf("inval op %d\n", preq->preq_optype);
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2008-01-28 21:35:49 +03:00
|
|
|
|
2009-10-18 03:19:52 +04:00
|
|
|
#if 0
|
|
|
|
/* not issued by kernel currently */
|
2008-01-28 21:35:49 +03:00
|
|
|
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
|
|
|
|
struct puffs_cacheinfo *pci = (void *)preq;
|
|
|
|
|
|
|
|
if (pu->pu_ops.puffs_cache_write) {
|
|
|
|
pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
|
|
|
|
pci->pcache_nruns, pci->pcache_runs);
|
|
|
|
}
|
|
|
|
error = 0;
|
2009-10-18 03:19:52 +04:00
|
|
|
#endif
|
2008-01-28 21:35:49 +03:00
|
|
|
|
|
|
|
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
|
|
|
|
struct puffs_error *perr = (void *)preq;
|
|
|
|
|
|
|
|
pu->pu_errnotify(pu, preq->preq_optype,
|
|
|
|
perr->perr_error, perr->perr_str, preq->preq_cookie);
|
|
|
|
error = 0;
|
2007-05-12 01:42:42 +04:00
|
|
|
} else {
|
|
|
|
/*
|
2008-01-28 21:35:49 +03:00
|
|
|
* I guess the kernel sees this one coming also
|
2007-05-12 01:42:42 +04:00
|
|
|
*/
|
|
|
|
error = EINVAL;
|
|
|
|
}
|
2008-03-20 18:28:03 +03:00
|
|
|
|
|
|
|
out:
|
2007-05-12 01:42:42 +04:00
|
|
|
preq->preq_rv = error;
|
2007-05-15 17:44:46 +04:00
|
|
|
|
2007-10-28 21:40:30 +03:00
|
|
|
if (pu->pu_oppost)
|
2007-11-30 22:02:28 +03:00
|
|
|
pu->pu_oppost(pu);
|
2007-10-28 21:40:30 +03:00
|
|
|
|
2008-01-28 21:35:49 +03:00
|
|
|
pcc->pcc_flags |= PCC_DONE;
|
2007-05-12 01:42:42 +04:00
|
|
|
}
|