version 1.163, 2012/01/17 09:30:16 |
version 1.163.2.4, 2012/08/12 13:13:20 |
Line 40 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 40 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/namei.h> |
#include <sys/namei.h> |
#include <sys/vnode.h> |
#include <sys/vnode.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
|
#include <sys/kernel.h> /* For hz, hardclock_ticks */ |
|
|
#include <uvm/uvm.h> |
#include <uvm/uvm.h> |
|
|
Line 298 const struct vnodeopv_entry_desc puffs_m |
|
Line 299 const struct vnodeopv_entry_desc puffs_m |
|
const struct vnodeopv_desc puffs_msgop_opv_desc = |
const struct vnodeopv_desc puffs_msgop_opv_desc = |
{ &puffs_msgop_p, puffs_msgop_entries }; |
{ &puffs_msgop_p, puffs_msgop_entries }; |
|
|
|
/* |
|
* for dosetattr / update_va |
|
*/ |
|
#define SETATTR_CHSIZE 0x01 |
|
#define SETATTR_ASYNC 0x02 |
|
|
#define ERROUT(err) \ |
#define ERROUT(err) \ |
do { \ |
do { \ |
Line 408 static int callremove(struct puffs_mount |
|
Line 414 static int callremove(struct puffs_mount |
|
static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t, |
static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t, |
struct componentname *); |
struct componentname *); |
static void callinactive(struct puffs_mount *, puffs_cookie_t, int); |
static void callinactive(struct puffs_mount *, puffs_cookie_t, int); |
static void callreclaim(struct puffs_mount *, puffs_cookie_t); |
static void callreclaim(struct puffs_mount *, puffs_cookie_t, int); |
static int flushvncache(struct vnode *, off_t, off_t, bool); |
static int flushvncache(struct vnode *, off_t, off_t, bool); |
|
static void update_va(struct vnode *, struct vattr *, struct vattr *, |
|
struct timespec *, struct timespec *, int); |
|
static void update_parent(struct vnode *, struct vnode *); |
|
|
|
|
#define PUFFS_ABORT_LOOKUP 1 |
#define PUFFS_ABORT_LOOKUP 1 |
Line 438 puffs_abortbutton(struct puffs_mount *pm |
|
Line 447 puffs_abortbutton(struct puffs_mount *pm |
|
} |
} |
|
|
callinactive(pmp, ck, 0); |
callinactive(pmp, ck, 0); |
callreclaim(pmp, ck); |
callreclaim(pmp, ck, 1); |
} |
} |
|
|
/* |
/* |
Line 455 puffs_abortbutton(struct puffs_mount *pm |
|
Line 464 puffs_abortbutton(struct puffs_mount *pm |
|
* don't want to think of the consequences for the time being. |
* don't want to think of the consequences for the time being. |
*/ |
*/ |
|
|
|
#define TTL_TO_TIMEOUT(ts) \ |
|
(hardclock_ticks + (ts->tv_sec * hz) + (ts->tv_nsec * hz / 1000000000)) |
|
#define TTL_VALID(ts) \ |
|
((ts != NULL) && !((ts->tv_sec == 0) && (ts->tv_nsec == 0))) |
|
#define TIMED_OUT(expire) \ |
|
((int)((unsigned int)hardclock_ticks - (unsigned int)expire) > 0) |
int |
int |
puffs_vnop_lookup(void *v) |
puffs_vnop_lookup(void *v) |
{ |
{ |
Line 467 puffs_vnop_lookup(void *v) |
|
Line 482 puffs_vnop_lookup(void *v) |
|
PUFFS_MSG_VARS(vn, lookup); |
PUFFS_MSG_VARS(vn, lookup); |
struct puffs_mount *pmp; |
struct puffs_mount *pmp; |
struct componentname *cnp; |
struct componentname *cnp; |
struct vnode *vp, *dvp; |
struct vnode *vp, *dvp, *cvp; |
struct puffs_node *dpn; |
struct puffs_node *dpn, *cpn; |
int isdot; |
int isdot; |
int error; |
int error; |
|
|
pmp = MPTOPUFFSMP(ap->a_dvp->v_mount); |
pmp = MPTOPUFFSMP(ap->a_dvp->v_mount); |
cnp = ap->a_cnp; |
cnp = ap->a_cnp; |
dvp = ap->a_dvp; |
dvp = ap->a_dvp; |
|
cvp = NULL; |
|
cpn = NULL; |
*ap->a_vpp = NULL; |
*ap->a_vpp = NULL; |
|
|
/* r/o fs? we check create later to handle EEXIST */ |
/* r/o fs? we check create later to handle EEXIST */ |
Line 489 puffs_vnop_lookup(void *v) |
|
Line 506 puffs_vnop_lookup(void *v) |
|
cnp->cn_nameptr, dvp, cnp->cn_nameiop)); |
cnp->cn_nameptr, dvp, cnp->cn_nameiop)); |
|
|
/* |
/* |
|
* If dotdot cache is enabled, unlock parent, lock .. |
|
* (grand-parent) and relock parent. |
|
*/ |
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && (cnp->cn_flags & ISDOTDOT)) { |
|
VOP_UNLOCK(dvp); |
|
|
|
vp = VPTOPP(ap->a_dvp)->pn_parent; |
|
vref(vp); |
|
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
|
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); |
|
|
|
*ap->a_vpp = vp; |
|
return 0; |
|
} |
|
|
|
/* |
* Check if someone fed it into the cache |
* Check if someone fed it into the cache |
*/ |
*/ |
if (PUFFS_USE_NAMECACHE(pmp)) { |
if (!isdot && PUFFS_USE_NAMECACHE(pmp)) { |
error = cache_lookup(dvp, ap->a_vpp, cnp); |
error = cache_lookup(dvp, ap->a_vpp, cnp); |
|
|
|
if ((error == 0) && PUFFS_USE_FS_TTL(pmp)) { |
|
cvp = *ap->a_vpp; |
|
cpn = VPTOPP(cvp); |
|
|
|
if (TIMED_OUT(cpn->pn_cn_timeout)) { |
|
cache_purge(cvp); |
|
/* |
|
* cached vnode (cvp) is still locked |
|
* so that we can reuse it upon a new |
|
* successful lookup. |
|
*/ |
|
*ap->a_vpp = NULL; |
|
error = -1; |
|
} |
|
} |
|
|
|
/* |
|
* Do not use negative caching, since the filesystem |
|
* provides no TTL for it. |
|
*/ |
|
if ((error == ENOENT) && PUFFS_USE_FS_TTL(pmp)) |
|
error = -1; |
|
|
if (error >= 0) |
if (error >= 0) |
return error; |
return error; |
} |
} |
Line 509 puffs_vnop_lookup(void *v) |
|
Line 566 puffs_vnop_lookup(void *v) |
|
return 0; |
return 0; |
} |
} |
|
|
|
if (cvp != NULL) |
|
mutex_enter(&cpn->pn_sizemtx); |
|
|
PUFFS_MSG_ALLOC(vn, lookup); |
PUFFS_MSG_ALLOC(vn, lookup); |
puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred, |
puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred, |
cnp, PUFFS_USE_FULLPNBUF(pmp)); |
cnp, PUFFS_USE_FULLPNBUF(pmp)); |
Line 544 puffs_vnop_lookup(void *v) |
|
Line 604 puffs_vnop_lookup(void *v) |
|
|
|
/* save negative cache entry */ |
/* save negative cache entry */ |
} else { |
} else { |
if ((cnp->cn_flags & MAKEENTRY) |
if (PUFFS_USE_NAMECACHE(pmp) && |
&& PUFFS_USE_NAMECACHE(pmp)) |
!PUFFS_USE_FS_TTL(pmp)) |
cache_enter(dvp, NULL, cnp); |
cache_enter(dvp, NULL, cnp); |
} |
} |
} |
} |
Line 564 puffs_vnop_lookup(void *v) |
|
Line 624 puffs_vnop_lookup(void *v) |
|
goto out; |
goto out; |
} |
} |
|
|
error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, 1, &vp); |
/* |
|
* Check if we looked up the cached vnode |
|
*/ |
|
vp = NULL; |
|
if (cvp && (VPTOPP(cvp)->pn_cookie == lookup_msg->pvnr_newnode)) { |
|
int grace; |
|
|
|
/* |
|
* Bump grace time of this node so that it does not get |
|
* reclaimed too fast. We try to increase a bit more the |
|
* lifetime of busiest * nodes - with some limits. |
|
*/ |
|
grace = 10 * puffs_sopreq_expire_timeout; |
|
cpn->pn_cn_grace = hardclock_ticks + grace; |
|
vp = cvp; |
|
} |
|
|
|
/* |
|
* No cached vnode available, or the cached vnode does not |
|
* match the userland cookie anymore: is the node known? |
|
*/ |
|
if (vp == NULL) { |
|
error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, |
|
1, 1, &vp); |
|
} |
|
|
if (error == PUFFS_NOSUCHCOOKIE) { |
if (error == PUFFS_NOSUCHCOOKIE) { |
error = puffs_getvnode(dvp->v_mount, |
error = puffs_getvnode(dvp->v_mount, |
lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype, |
lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype, |
lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp); |
lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp); |
if (error) { |
if (error) { |
puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp), |
puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, |
lookup_msg->pvnr_newnode, ap->a_cnp); |
VPTOPNC(dvp), lookup_msg->pvnr_newnode, |
|
ap->a_cnp); |
goto out; |
goto out; |
} |
} |
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
} else if (error) { |
} else if (error) { |
puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp), |
puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp), |
Line 581 puffs_vnop_lookup(void *v) |
|
Line 668 puffs_vnop_lookup(void *v) |
|
goto out; |
goto out; |
} |
} |
|
|
|
/* |
|
* Update cache and TTL |
|
*/ |
|
if (PUFFS_USE_FS_TTL(pmp)) { |
|
struct timespec *va_ttl = &lookup_msg->pvnr_va_ttl; |
|
struct timespec *cn_ttl = &lookup_msg->pvnr_cn_ttl; |
|
update_va(vp, NULL, &lookup_msg->pvnr_va, |
|
va_ttl, cn_ttl, SETATTR_CHSIZE); |
|
} |
|
|
|
KASSERT(lookup_msg->pvnr_newnode == VPTOPP(vp)->pn_cookie); |
*ap->a_vpp = vp; |
*ap->a_vpp = vp; |
|
|
if ((cnp->cn_flags & MAKEENTRY) != 0 && PUFFS_USE_NAMECACHE(pmp)) |
if (PUFFS_USE_NAMECACHE(pmp)) |
cache_enter(dvp, vp, cnp); |
cache_enter(dvp, vp, cnp); |
|
|
/* XXX */ |
/* XXX */ |
Line 593 puffs_vnop_lookup(void *v) |
|
Line 691 puffs_vnop_lookup(void *v) |
|
cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume, |
cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume, |
strlen(cnp->cn_nameptr) - cnp->cn_namelen); |
strlen(cnp->cn_nameptr) - cnp->cn_namelen); |
|
|
|
VPTOPP(vp)->pn_nlookup++; |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
|
(VPTOPP(vp)->pn_parent != dvp)) |
|
update_parent(vp, dvp); |
|
|
out: |
out: |
|
if (cvp != NULL) { |
|
mutex_exit(&cpn->pn_sizemtx); |
|
|
|
if (error || (cvp != vp)) |
|
vput(cvp); |
|
} |
|
|
if (cnp->cn_flags & ISDOTDOT) |
if (cnp->cn_flags & ISDOTDOT) |
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); |
|
|
Line 658 puffs_vnop_create(void *v) |
|
Line 769 puffs_vnop_create(void *v) |
|
|
|
error = puffs_newnode(mp, dvp, ap->a_vpp, |
error = puffs_newnode(mp, dvp, ap->a_vpp, |
create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0); |
create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0); |
if (error) |
if (error) { |
puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie, |
puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie, |
create_msg->pvnr_newnode, cnp); |
create_msg->pvnr_newnode, cnp); |
|
goto out; |
|
} |
|
|
|
if (PUFFS_USE_FS_TTL(pmp)) { |
|
struct timespec *va_ttl = &create_msg->pvnr_va_ttl; |
|
struct timespec *cn_ttl = &create_msg->pvnr_cn_ttl; |
|
struct vattr *rvap = &create_msg->pvnr_va; |
|
|
|
update_va(*ap->a_vpp, NULL, rvap, |
|
va_ttl, cn_ttl, SETATTR_CHSIZE); |
|
} |
|
|
|
VPTOPP(*ap->a_vpp)->pn_nlookup++; |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
|
(VPTOPP(*ap->a_vpp)->pn_parent != dvp)) |
|
update_parent(*ap->a_vpp, dvp); |
|
|
out: |
out: |
vput(dvp); |
vput(dvp); |
Line 704 puffs_vnop_mknod(void *v) |
|
Line 832 puffs_vnop_mknod(void *v) |
|
error = puffs_newnode(mp, dvp, ap->a_vpp, |
error = puffs_newnode(mp, dvp, ap->a_vpp, |
mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type, |
mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type, |
ap->a_vap->va_rdev); |
ap->a_vap->va_rdev); |
if (error) |
if (error) { |
puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie, |
puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie, |
mknod_msg->pvnr_newnode, cnp); |
mknod_msg->pvnr_newnode, cnp); |
|
goto out; |
|
} |
|
|
|
if (PUFFS_USE_FS_TTL(pmp)) { |
|
struct timespec *va_ttl = &mknod_msg->pvnr_va_ttl; |
|
struct timespec *cn_ttl = &mknod_msg->pvnr_cn_ttl; |
|
struct vattr *rvap = &mknod_msg->pvnr_va; |
|
|
|
update_va(*ap->a_vpp, NULL, rvap, |
|
va_ttl, cn_ttl, SETATTR_CHSIZE); |
|
} |
|
|
|
VPTOPP(*ap->a_vpp)->pn_nlookup++; |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
|
(VPTOPP(*ap->a_vpp)->pn_parent != dvp)) |
|
update_parent(*ap->a_vpp, dvp); |
|
|
out: |
out: |
vput(dvp); |
vput(dvp); |
Line 822 puffs_vnop_access(void *v) |
|
Line 967 puffs_vnop_access(void *v) |
|
return error; |
return error; |
} |
} |
|
|
|
static void |
|
update_va(struct vnode *vp, struct vattr *vap, struct vattr *rvap, |
|
struct timespec *va_ttl, struct timespec *cn_ttl, int flags) |
|
{ |
|
struct puffs_node *pn = VPTOPP(vp); |
|
|
|
if (TTL_VALID(cn_ttl)) { |
|
pn->pn_cn_timeout = TTL_TO_TIMEOUT(cn_ttl); |
|
pn->pn_cn_grace = MAX(pn->pn_cn_timeout, pn->pn_cn_grace); |
|
} |
|
|
|
/* |
|
* Don't listen to the file server regarding special device |
|
* size info, the file server doesn't know anything about them. |
|
*/ |
|
if (vp->v_type == VBLK || vp->v_type == VCHR) |
|
rvap->va_size = vp->v_size; |
|
|
|
/* Ditto for blocksize (ufs comment: this doesn't belong here) */ |
|
if (vp->v_type == VBLK) |
|
rvap->va_blocksize = BLKDEV_IOSIZE; |
|
else if (vp->v_type == VCHR) |
|
rvap->va_blocksize = MAXBSIZE; |
|
|
|
if (vap != NULL) { |
|
(void) memcpy(vap, rvap, sizeof(struct vattr)); |
|
vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; |
|
|
|
if (pn->pn_stat & PNODE_METACACHE_ATIME) |
|
vap->va_atime = pn->pn_mc_atime; |
|
if (pn->pn_stat & PNODE_METACACHE_CTIME) |
|
vap->va_ctime = pn->pn_mc_ctime; |
|
if (pn->pn_stat & PNODE_METACACHE_MTIME) |
|
vap->va_mtime = pn->pn_mc_mtime; |
|
if (pn->pn_stat & PNODE_METACACHE_SIZE) |
|
vap->va_size = pn->pn_mc_size; |
|
} |
|
|
|
if (!(pn->pn_stat & PNODE_METACACHE_SIZE) && (flags & SETATTR_CHSIZE)) { |
|
if (rvap->va_size != VNOVAL |
|
&& vp->v_type != VBLK && vp->v_type != VCHR) { |
|
uvm_vnp_setsize(vp, rvap->va_size); |
|
pn->pn_serversize = rvap->va_size; |
|
} |
|
} |
|
|
|
if ((va_ttl != NULL) && TTL_VALID(va_ttl)) { |
|
if (pn->pn_va_cache == NULL) |
|
pn->pn_va_cache = pool_get(&puffs_vapool, PR_WAITOK); |
|
|
|
(void)memcpy(pn->pn_va_cache, rvap, sizeof(*rvap)); |
|
|
|
pn->pn_va_timeout = TTL_TO_TIMEOUT(va_ttl); |
|
} |
|
} |
|
|
|
static void |
|
update_parent(struct vnode *vp, struct vnode *dvp) |
|
{ |
|
struct puffs_node *pn = VPTOPP(vp); |
|
|
|
if (pn->pn_parent != NULL) { |
|
KASSERT(pn->pn_parent != dvp); |
|
vrele(pn->pn_parent); |
|
} |
|
|
|
vref(dvp); |
|
pn->pn_parent = dvp; |
|
} |
|
|
int |
int |
puffs_vnop_getattr(void *v) |
puffs_vnop_getattr(void *v) |
{ |
{ |
Line 837 puffs_vnop_getattr(void *v) |
|
Line 1052 puffs_vnop_getattr(void *v) |
|
struct puffs_mount *pmp = MPTOPUFFSMP(mp); |
struct puffs_mount *pmp = MPTOPUFFSMP(mp); |
struct vattr *vap, *rvap; |
struct vattr *vap, *rvap; |
struct puffs_node *pn = VPTOPP(vp); |
struct puffs_node *pn = VPTOPP(vp); |
|
struct timespec *va_ttl = NULL; |
int error = 0; |
int error = 0; |
|
|
/* |
/* |
Line 857 puffs_vnop_getattr(void *v) |
|
Line 1073 puffs_vnop_getattr(void *v) |
|
REFPN(pn); |
REFPN(pn); |
vap = ap->a_vap; |
vap = ap->a_vap; |
|
|
|
if (PUFFS_USE_FS_TTL(pmp)) { |
|
if (!TIMED_OUT(pn->pn_va_timeout)) { |
|
update_va(vp, vap, pn->pn_va_cache, |
|
NULL, NULL, SETATTR_CHSIZE); |
|
goto out2; |
|
} |
|
} |
|
|
PUFFS_MSG_ALLOC(vn, getattr); |
PUFFS_MSG_ALLOC(vn, getattr); |
vattr_null(&getattr_msg->pvnr_va); |
vattr_null(&getattr_msg->pvnr_va); |
puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred); |
puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred); |
Line 869 puffs_vnop_getattr(void *v) |
|
Line 1093 puffs_vnop_getattr(void *v) |
|
goto out; |
goto out; |
|
|
rvap = &getattr_msg->pvnr_va; |
rvap = &getattr_msg->pvnr_va; |
/* |
|
* Don't listen to the file server regarding special device |
|
* size info, the file server doesn't know anything about them. |
|
*/ |
|
if (vp->v_type == VBLK || vp->v_type == VCHR) |
|
rvap->va_size = vp->v_size; |
|
|
|
/* Ditto for blocksize (ufs comment: this doesn't belong here) */ |
if (PUFFS_USE_FS_TTL(pmp)) |
if (vp->v_type == VBLK) |
va_ttl = &getattr_msg->pvnr_va_ttl; |
rvap->va_blocksize = BLKDEV_IOSIZE; |
|
else if (vp->v_type == VCHR) |
|
rvap->va_blocksize = MAXBSIZE; |
|
|
|
(void) memcpy(vap, rvap, sizeof(struct vattr)); |
|
vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; |
|
|
|
if (pn->pn_stat & PNODE_METACACHE_ATIME) |
update_va(vp, vap, rvap, va_ttl, NULL, SETATTR_CHSIZE); |
vap->va_atime = pn->pn_mc_atime; |
|
if (pn->pn_stat & PNODE_METACACHE_CTIME) |
|
vap->va_ctime = pn->pn_mc_ctime; |
|
if (pn->pn_stat & PNODE_METACACHE_MTIME) |
|
vap->va_mtime = pn->pn_mc_mtime; |
|
if (pn->pn_stat & PNODE_METACACHE_SIZE) { |
|
vap->va_size = pn->pn_mc_size; |
|
} else { |
|
if (rvap->va_size != VNOVAL |
|
&& vp->v_type != VBLK && vp->v_type != VCHR) { |
|
uvm_vnp_setsize(vp, rvap->va_size); |
|
pn->pn_serversize = rvap->va_size; |
|
} |
|
} |
|
|
|
out: |
out: |
puffs_releasenode(pn); |
|
PUFFS_MSG_RELEASE(getattr); |
PUFFS_MSG_RELEASE(getattr); |
|
|
|
out2: |
|
puffs_releasenode(pn); |
|
|
mutex_exit(&pn->pn_sizemtx); |
mutex_exit(&pn->pn_sizemtx); |
|
|
return error; |
return error; |
} |
} |
|
|
#define SETATTR_CHSIZE 0x01 |
|
#define SETATTR_ASYNC 0x02 |
|
static int |
static int |
dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags) |
dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags) |
{ |
{ |
Line 954 dosetattr(struct vnode *vp, struct vattr |
|
Line 1152 dosetattr(struct vnode *vp, struct vattr |
|
pn->pn_stat &= ~PNODE_METACACHE_MASK; |
pn->pn_stat &= ~PNODE_METACACHE_MASK; |
} |
} |
|
|
|
/* |
|
* Flush attribute cache so that another thread do |
|
* not get a stale value during the operation. |
|
*/ |
|
if (PUFFS_USE_FS_TTL(pmp)) |
|
pn->pn_va_timeout = 0; |
|
|
PUFFS_MSG_ALLOC(vn, setattr); |
PUFFS_MSG_ALLOC(vn, setattr); |
(void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr)); |
(void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr)); |
puffs_credcvt(&setattr_msg->pvnr_cred, cred); |
puffs_credcvt(&setattr_msg->pvnr_cred, cred); |
Line 965 dosetattr(struct vnode *vp, struct vattr |
|
Line 1170 dosetattr(struct vnode *vp, struct vattr |
|
puffs_msg_enqueue(pmp, park_setattr); |
puffs_msg_enqueue(pmp, park_setattr); |
if ((flags & SETATTR_ASYNC) == 0) |
if ((flags & SETATTR_ASYNC) == 0) |
error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL); |
error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL); |
|
|
|
if ((error == 0) && PUFFS_USE_FS_TTL(pmp)) { |
|
struct timespec *va_ttl = &setattr_msg->pvnr_va_ttl; |
|
struct vattr *rvap = &setattr_msg->pvnr_va; |
|
|
|
update_va(vp, NULL, rvap, va_ttl, NULL, flags); |
|
} |
|
|
PUFFS_MSG_RELEASE(setattr); |
PUFFS_MSG_RELEASE(setattr); |
if ((flags & SETATTR_ASYNC) == 0) { |
if ((flags & SETATTR_ASYNC) == 0) { |
error = checkerr(pmp, error, __func__); |
error = checkerr(pmp, error, __func__); |
Line 1046 puffs_vnop_inactive(void *v) |
|
Line 1259 puffs_vnop_inactive(void *v) |
|
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_node *pnode; |
struct puffs_node *pnode; |
|
bool recycle = false; |
int error; |
int error; |
|
|
pnode = vp->v_data; |
pnode = vp->v_data; |
Line 1069 puffs_vnop_inactive(void *v) |
|
Line 1283 puffs_vnop_inactive(void *v) |
|
*/ |
*/ |
if (pnode->pn_stat & PNODE_NOREFS) { |
if (pnode->pn_stat & PNODE_NOREFS) { |
pnode->pn_stat |= PNODE_DYING; |
pnode->pn_stat |= PNODE_DYING; |
*ap->a_recycle = true; |
recycle = true; |
} |
} |
|
|
|
/* |
|
* Handle node TTL. |
|
* If grace has already timed out, make it reclaimed. |
|
* Otherwise, we queue its expiration by sop thread, so |
|
* that it does not remain for ages in the freelist, |
|
* holding memory in userspace, while we will have |
|
* to look it up again anyway. |
|
*/ |
|
if (PUFFS_USE_FS_TTL(pmp) && !(vp->v_vflag & VV_ROOT) && !recycle) { |
|
bool incache = !TIMED_OUT(pnode->pn_cn_timeout); |
|
bool ingrace = !TIMED_OUT(pnode->pn_cn_grace); |
|
bool reclaimqueued = pnode->pn_stat & PNODE_SOPEXP; |
|
|
|
if (!incache && !ingrace && !reclaimqueued) { |
|
pnode->pn_stat |= PNODE_DYING; |
|
recycle = true; |
|
} |
|
|
|
if (!recycle && !reclaimqueued) { |
|
struct puffs_sopreq *psopr; |
|
int at = MAX(pnode->pn_cn_grace, pnode->pn_cn_timeout); |
|
|
|
KASSERT(curlwp != uvm.pagedaemon_lwp); |
|
psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP); |
|
psopr->psopr_ck = VPTOPNC(pnode->pn_vp); |
|
psopr->psopr_sopreq = PUFFS_SOPREQ_EXPIRE; |
|
psopr->psopr_at = at; |
|
|
|
mutex_enter(&pmp->pmp_sopmtx); |
|
|
|
/* |
|
* If thread has disapeared, just give up. The |
|
* fs is being unmounted and the node will be |
|
* be reclaimed anyway. |
|
* |
|
* Otherwise, we queue the request but do not |
|
* immediatly signal the thread, as the node |
|
* has not been expired yet. |
|
*/ |
|
if (pmp->pmp_sopthrcount == 0) { |
|
kmem_free(psopr, sizeof(*psopr)); |
|
} else { |
|
TAILQ_INSERT_TAIL(&pmp->pmp_sopnodereqs, |
|
psopr, psopr_entries); |
|
pnode->pn_stat |= PNODE_SOPEXP; |
|
} |
|
|
|
mutex_exit(&pmp->pmp_sopmtx); |
|
} |
|
} |
|
|
|
*ap->a_recycle = recycle; |
|
|
mutex_exit(&pnode->pn_sizemtx); |
mutex_exit(&pnode->pn_sizemtx); |
VOP_UNLOCK(vp); |
VOP_UNLOCK(vp); |
|
|
Line 1079 puffs_vnop_inactive(void *v) |
|
Line 1346 puffs_vnop_inactive(void *v) |
|
} |
} |
|
|
static void |
static void |
callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck) |
callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck, int nlookup) |
{ |
{ |
PUFFS_MSG_VARS(vn, reclaim); |
PUFFS_MSG_VARS(vn, reclaim); |
|
|
Line 1087 callreclaim(struct puffs_mount *pmp, puf |
|
Line 1354 callreclaim(struct puffs_mount *pmp, puf |
|
return; |
return; |
|
|
PUFFS_MSG_ALLOC(vn, reclaim); |
PUFFS_MSG_ALLOC(vn, reclaim); |
|
reclaim_msg->pvnr_nlookup = nlookup; |
puffs_msg_setfaf(park_reclaim); |
puffs_msg_setfaf(park_reclaim); |
puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck); |
puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck); |
|
|
puffs_msg_enqueue(pmp, park_reclaim); |
puffs_msg_enqueue(pmp, park_reclaim); |
PUFFS_MSG_RELEASE(reclaim); |
PUFFS_MSG_RELEASE(reclaim); |
|
return; |
} |
} |
|
|
/* |
/* |
Line 1131 puffs_vnop_reclaim(void *v) |
|
Line 1400 puffs_vnop_reclaim(void *v) |
|
*/ |
*/ |
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
LIST_REMOVE(pnode, pn_hashent); |
LIST_REMOVE(pnode, pn_hashent); |
|
if (PUFFS_USE_NAMECACHE(pmp)) |
|
cache_purge(vp); |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
|
if (notifyserver) |
if (notifyserver) { |
callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp)); |
int nlookup = VPTOPP(vp)->pn_nlookup; |
|
|
|
callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp), nlookup); |
|
} |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp)) { |
|
if (__predict_true(VPTOPP(vp)->pn_parent != NULL)) |
|
vrele(VPTOPP(vp)->pn_parent); |
|
else |
|
KASSERT(vp->v_vflag & VV_ROOT); |
|
} |
|
|
puffs_putvnode(vp); |
puffs_putvnode(vp); |
vp->v_data = NULL; |
vp->v_data = NULL; |
Line 1340 flushvncache(struct vnode *vp, off_t off |
|
Line 1621 flushvncache(struct vnode *vp, off_t off |
|
pflags = PGO_CLEANIT; |
pflags = PGO_CLEANIT; |
if (wait) |
if (wait) |
pflags |= PGO_SYNCIO; |
pflags |= PGO_SYNCIO; |
|
|
mutex_enter(vp->v_interlock); |
mutex_enter(vp->v_interlock); |
return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags); |
return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags); |
} |
} |
Line 1550 puffs_vnop_mkdir(void *v) |
|
Line 1832 puffs_vnop_mkdir(void *v) |
|
|
|
error = puffs_newnode(mp, dvp, ap->a_vpp, |
error = puffs_newnode(mp, dvp, ap->a_vpp, |
mkdir_msg->pvnr_newnode, cnp, VDIR, 0); |
mkdir_msg->pvnr_newnode, cnp, VDIR, 0); |
if (error) |
if (error) { |
puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie, |
puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie, |
mkdir_msg->pvnr_newnode, cnp); |
mkdir_msg->pvnr_newnode, cnp); |
|
goto out; |
|
} |
|
|
|
if (PUFFS_USE_FS_TTL(pmp)) { |
|
struct timespec *va_ttl = &mkdir_msg->pvnr_va_ttl; |
|
struct timespec *cn_ttl = &mkdir_msg->pvnr_cn_ttl; |
|
struct vattr *rvap = &mkdir_msg->pvnr_va; |
|
|
|
update_va(*ap->a_vpp, NULL, rvap, |
|
va_ttl, cn_ttl, SETATTR_CHSIZE); |
|
} |
|
|
|
VPTOPP(*ap->a_vpp)->pn_nlookup++; |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
|
(VPTOPP(*ap->a_vpp)->pn_parent != dvp)) |
|
update_parent(*ap->a_vpp, dvp); |
|
|
out: |
out: |
vput(dvp); |
vput(dvp); |
Line 1703 puffs_vnop_symlink(void *v) |
|
Line 2002 puffs_vnop_symlink(void *v) |
|
|
|
error = puffs_newnode(mp, dvp, ap->a_vpp, |
error = puffs_newnode(mp, dvp, ap->a_vpp, |
symlink_msg->pvnr_newnode, cnp, VLNK, 0); |
symlink_msg->pvnr_newnode, cnp, VLNK, 0); |
if (error) |
if (error) { |
puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie, |
puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie, |
symlink_msg->pvnr_newnode, cnp); |
symlink_msg->pvnr_newnode, cnp); |
|
goto out; |
|
} |
|
|
|
if (PUFFS_USE_FS_TTL(pmp)) { |
|
struct timespec *va_ttl = &symlink_msg->pvnr_va_ttl; |
|
struct timespec *cn_ttl = &symlink_msg->pvnr_cn_ttl; |
|
struct vattr *rvap = &symlink_msg->pvnr_va; |
|
|
|
update_va(*ap->a_vpp, NULL, rvap, |
|
va_ttl, cn_ttl, SETATTR_CHSIZE); |
|
} |
|
|
|
VPTOPP(*ap->a_vpp)->pn_nlookup++; |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
|
(VPTOPP(*ap->a_vpp)->pn_parent != dvp)) |
|
update_parent(*ap->a_vpp, dvp); |
|
|
out: |
out: |
vput(dvp); |
vput(dvp); |
Line 1804 puffs_vnop_rename(void *v) |
|
Line 2120 puffs_vnop_rename(void *v) |
|
* XXX: stay in touch with the cache. I don't like this, but |
* XXX: stay in touch with the cache. I don't like this, but |
* don't have a better solution either. See also puffs_link(). |
* don't have a better solution either. See also puffs_link(). |
*/ |
*/ |
if (error == 0) |
if (error == 0) { |
puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0); |
puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0); |
|
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
|
(VPTOPP(fvp)->pn_parent != tdvp)) |
|
update_parent(fvp, tdvp); |
|
} |
|
|
|
|
out: |
out: |
if (doabort) |
if (doabort) |
VOP_ABORTOP(tdvp, ap->a_tcnp); |
VOP_ABORTOP(tdvp, ap->a_tcnp); |
Line 1862 puffs_vnop_read(void *v) |
|
Line 2184 puffs_vnop_read(void *v) |
|
const int advice = IO_ADV_DECODE(ap->a_ioflag); |
const int advice = IO_ADV_DECODE(ap->a_ioflag); |
|
|
while (uio->uio_resid > 0) { |
while (uio->uio_resid > 0) { |
|
if (vp->v_size <= uio->uio_offset) { |
|
break; |
|
} |
bytelen = MIN(uio->uio_resid, |
bytelen = MIN(uio->uio_resid, |
vp->v_size - uio->uio_offset); |
vp->v_size - uio->uio_offset); |
if (bytelen == 0) |
if (bytelen == 0) |