[BACK]Return to puffs_node.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / puffs

Annotation of src/sys/fs/puffs/puffs_node.c, Revision 1.22.6.1

1.22.6.1! mrg         1: /*     $NetBSD: puffs_node.c,v 1.23 2012/01/19 08:14:41 manu Exp $     */
1.1       pooka       2:
                      3: /*
                      4:  * Copyright (c) 2005, 2006, 2007  Antti Kantee.  All Rights Reserved.
                      5:  *
                      6:  * Development of this software was supported by the
                      7:  * Google Summer of Code program, the Ulla Tuominen Foundation
                      8:  * and the Finnish Cultural Foundation.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     20:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     21:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     22:  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     25:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/cdefs.h>
1.22.6.1! mrg        33: __KERNEL_RCSID(0, "$NetBSD: puffs_node.c,v 1.23 2012/01/19 08:14:41 manu Exp $");
1.1       pooka      34:
                     35: #include <sys/param.h>
                     36: #include <sys/hash.h>
                     37: #include <sys/kmem.h>
                     38: #include <sys/malloc.h>
                     39: #include <sys/mount.h>
                     40: #include <sys/namei.h>
                     41: #include <sys/vnode.h>
                     42:
1.21      manu       43: #include <uvm/uvm.h>
                     44:
1.1       pooka      45: #include <fs/puffs/puffs_msgif.h>
                     46: #include <fs/puffs/puffs_sys.h>
                     47:
                     48: #include <miscfs/genfs/genfs_node.h>
                     49: #include <miscfs/specfs/specdev.h>
                     50:
                     51: static const struct genfs_ops puffs_genfsops = {
                     52:        .gop_size = puffs_gop_size,
                     53:        .gop_write = genfs_gop_write,
                     54:        .gop_markupdate = puffs_gop_markupdate,
                     55: #if 0
                     56:        .gop_alloc, should ask userspace
                     57: #endif
                     58: };
                     59:
                     60: static __inline struct puffs_node_hashlist
1.11      pooka      61:        *puffs_cookie2hashlist(struct puffs_mount *, puffs_cookie_t);
                     62: static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *,
                     63:                                             puffs_cookie_t);
1.1       pooka      64:
                     65: struct pool puffs_pnpool;
                     66:
                     67: /*
1.19      wiz        68:  * Grab a vnode, intialize all the puffs-dependent stuff.
1.1       pooka      69:  */
                     70: int
1.11      pooka      71: puffs_getvnode(struct mount *mp, puffs_cookie_t ck, enum vtype type,
1.1       pooka      72:        voff_t vsize, dev_t rdev, struct vnode **vpp)
                     73: {
                     74:        struct puffs_mount *pmp;
                     75:        struct puffs_newcookie *pnc;
1.10      ad         76:        struct vnode *vp;
1.1       pooka      77:        struct puffs_node *pnode;
                     78:        struct puffs_node_hashlist *plist;
                     79:        int error;
                     80:
                     81:        pmp = MPTOPUFFSMP(mp);
                     82:
                     83:        error = EPROTO;
1.3       pooka      84:        if (type <= VNON || type >= VBAD) {
1.7       pooka      85:                puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
1.11      pooka      86:                    "bad node type", ck);
1.3       pooka      87:                goto bad;
                     88:        }
                     89:        if (vsize == VSIZENOTSET) {
1.7       pooka      90:                puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
1.11      pooka      91:                    "VSIZENOTSET is not a valid size", ck);
1.1       pooka      92:                goto bad;
                     93:        }
                     94:
1.18      rmind      95:        error = getnewvnode(VT_PUFFS, mp, puffs_vnodeop_p, NULL, &vp);
                     96:        if (error) {
1.1       pooka      97:                goto bad;
1.18      rmind      98:        }
1.1       pooka      99:        vp->v_type = type;
                    100:
                    101:        /*
1.4       pooka     102:         * Creation should not fail after this point.  Or if it does,
                    103:         * care must be taken so that VOP_INACTIVE() isn't called.
                    104:         */
                    105:
1.1       pooka     106:        /* default size */
                    107:        uvm_vnp_setsize(vp, 0);
                    108:
                    109:        /* dances based on vnode type. almost ufs_vinit(), but not quite */
                    110:        switch (type) {
                    111:        case VCHR:
                    112:        case VBLK:
                    113:                /*
                    114:                 * replace vnode operation vector with the specops vector.
                    115:                 * our user server has very little control over the node
                    116:                 * if it decides its a character or block special file
                    117:                 */
                    118:                vp->v_op = puffs_specop_p;
1.10      ad        119:                spec_node_init(vp, rdev);
1.1       pooka     120:                break;
                    121:
                    122:        case VFIFO:
                    123:                vp->v_op = puffs_fifoop_p;
                    124:                break;
                    125:
                    126:        case VREG:
                    127:                uvm_vnp_setsize(vp, vsize);
                    128:                break;
                    129:
                    130:        case VDIR:
                    131:        case VLNK:
                    132:        case VSOCK:
                    133:                break;
                    134:        default:
                    135:                panic("puffs_getvnode: invalid vtype %d", type);
                    136:        }
                    137:
                    138:        pnode = pool_get(&puffs_pnpool, PR_WAITOK);
                    139:        memset(pnode, 0, sizeof(struct puffs_node));
                    140:
1.11      pooka     141:        pnode->pn_cookie = ck;
1.1       pooka     142:        pnode->pn_refcount = 1;
                    143:
                    144:        /* insert cookie on list, take off of interlock list */
                    145:        mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE);
1.12      rmind     146:        selinit(&pnode->pn_sel);
1.11      pooka     147:        plist = puffs_cookie2hashlist(pmp, ck);
1.1       pooka     148:        mutex_enter(&pmp->pmp_lock);
                    149:        LIST_INSERT_HEAD(plist, pnode, pn_hashent);
1.11      pooka     150:        if (ck != pmp->pmp_root_cookie) {
1.1       pooka     151:                LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) {
1.11      pooka     152:                        if (pnc->pnc_cookie == ck) {
1.1       pooka     153:                                LIST_REMOVE(pnc, pnc_entries);
                    154:                                kmem_free(pnc, sizeof(struct puffs_newcookie));
                    155:                                break;
                    156:                        }
                    157:                }
                    158:                KASSERT(pnc != NULL);
                    159:        }
1.20      manu      160:        mutex_init(&pnode->pn_sizemtx, MUTEX_DEFAULT, IPL_NONE);
1.1       pooka     161:        mutex_exit(&pmp->pmp_lock);
                    162:
                    163:        vp->v_data = pnode;
                    164:        vp->v_type = type;
                    165:        pnode->pn_vp = vp;
                    166:        pnode->pn_serversize = vsize;
                    167:
                    168:        genfs_node_init(vp, &puffs_genfsops);
                    169:        *vpp = vp;
                    170:
                    171:        DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
                    172:            pnode, pnode->pn_cookie));
                    173:
                    174:        return 0;
                    175:
                    176:  bad:
                    177:        /* remove staging cookie from list */
1.11      pooka     178:        if (ck != pmp->pmp_root_cookie) {
1.1       pooka     179:                mutex_enter(&pmp->pmp_lock);
                    180:                LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) {
1.11      pooka     181:                        if (pnc->pnc_cookie == ck) {
1.1       pooka     182:                                LIST_REMOVE(pnc, pnc_entries);
                    183:                                kmem_free(pnc, sizeof(struct puffs_newcookie));
                    184:                                break;
                    185:                        }
                    186:                }
                    187:                KASSERT(pnc != NULL);
                    188:                mutex_exit(&pmp->pmp_lock);
                    189:        }
                    190:
                    191:        return error;
                    192: }
                    193:
                    194: /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
                    195: int
                    196: puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
1.11      pooka     197:        puffs_cookie_t ck, struct componentname *cnp,
                    198:        enum vtype type, dev_t rdev)
1.1       pooka     199: {
                    200:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
                    201:        struct puffs_newcookie *pnc;
                    202:        struct vnode *vp;
                    203:        int error;
                    204:
                    205:        /* userspace probably has this as a NULL op */
1.11      pooka     206:        if (ck == NULL) {
1.1       pooka     207:                error = EOPNOTSUPP;
                    208:                return error;
                    209:        }
                    210:
                    211:        /*
                    212:         * Check for previous node with the same designation.
                    213:         * Explicitly check the root node cookie, since it might be
                    214:         * reclaimed from the kernel when this check is made.
                    215:         */
                    216:        mutex_enter(&pmp->pmp_lock);
1.11      pooka     217:        if (ck == pmp->pmp_root_cookie
                    218:            || puffs_cookie2pnode(pmp, ck) != NULL) {
1.1       pooka     219:                mutex_exit(&pmp->pmp_lock);
1.7       pooka     220:                puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST,
1.11      pooka     221:                    "cookie exists", ck);
1.1       pooka     222:                return EPROTO;
                    223:        }
                    224:
                    225:        LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) {
1.11      pooka     226:                if (pnc->pnc_cookie == ck) {
1.1       pooka     227:                        mutex_exit(&pmp->pmp_lock);
1.7       pooka     228:                        puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST,
1.14      pooka     229:                            "newcookie exists", ck);
1.1       pooka     230:                        return EPROTO;
                    231:                }
                    232:        }
1.21      manu      233:
                    234:        KASSERT(curlwp != uvm.pagedaemon_lwp);
1.1       pooka     235:        pnc = kmem_alloc(sizeof(struct puffs_newcookie), KM_SLEEP);
1.11      pooka     236:        pnc->pnc_cookie = ck;
1.1       pooka     237:        LIST_INSERT_HEAD(&pmp->pmp_newcookie, pnc, pnc_entries);
                    238:        mutex_exit(&pmp->pmp_lock);
                    239:
1.11      pooka     240:        error = puffs_getvnode(dvp->v_mount, ck, type, 0, rdev, &vp);
1.1       pooka     241:        if (error)
                    242:                return error;
                    243:
                    244:        vp->v_type = type;
                    245:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    246:        *vpp = vp;
                    247:
                    248:        if ((cnp->cn_flags & MAKEENTRY) && PUFFS_USE_NAMECACHE(pmp))
                    249:                cache_enter(dvp, vp, cnp);
                    250:
                    251:        return 0;
                    252: }
                    253:
                    254: void
                    255: puffs_putvnode(struct vnode *vp)
                    256: {
                    257:        struct puffs_mount *pmp;
                    258:        struct puffs_node *pnode;
                    259:
                    260:        pmp = VPTOPUFFSMP(vp);
                    261:        pnode = VPTOPP(vp);
                    262:
                    263: #ifdef DIAGNOSTIC
                    264:        if (vp->v_tag != VT_PUFFS)
                    265:                panic("puffs_putvnode: %p not a puffs vnode", vp);
                    266: #endif
                    267:
                    268:        genfs_node_destroy(vp);
                    269:        puffs_releasenode(pnode);
                    270:        vp->v_data = NULL;
                    271:
                    272:        return;
                    273: }
                    274:
                    275: static __inline struct puffs_node_hashlist *
1.11      pooka     276: puffs_cookie2hashlist(struct puffs_mount *pmp, puffs_cookie_t ck)
1.1       pooka     277: {
                    278:        uint32_t hash;
                    279:
1.11      pooka     280:        hash = hash32_buf(&ck, sizeof(void *), HASH32_BUF_INIT);
1.1       pooka     281:        return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
                    282: }
                    283:
                    284: /*
1.2       pooka     285:  * Translate cookie to puffs_node.  Caller must hold pmp_lock
                    286:  * and it will be held upon return.
1.1       pooka     287:  */
                    288: static struct puffs_node *
1.11      pooka     289: puffs_cookie2pnode(struct puffs_mount *pmp, puffs_cookie_t ck)
1.1       pooka     290: {
                    291:        struct puffs_node_hashlist *plist;
                    292:        struct puffs_node *pnode;
                    293:
1.11      pooka     294:        plist = puffs_cookie2hashlist(pmp, ck);
1.1       pooka     295:        LIST_FOREACH(pnode, plist, pn_hashent) {
1.11      pooka     296:                if (pnode->pn_cookie == ck)
1.1       pooka     297:                        break;
                    298:        }
                    299:
                    300:        return pnode;
                    301: }
                    302:
                    303: /*
                    304:  * Make sure root vnode exists and reference it.  Does NOT lock.
                    305:  */
                    306: static int
                    307: puffs_makeroot(struct puffs_mount *pmp)
                    308: {
                    309:        struct vnode *vp;
                    310:        int rv;
                    311:
                    312:        /*
                    313:         * pmp_lock must be held if vref()'ing or vrele()'ing the
                    314:         * root vnode.  the latter is controlled by puffs_inactive().
                    315:         *
                    316:         * pmp_root is set here and cleared in puffs_reclaim().
                    317:         */
                    318:  retry:
                    319:        mutex_enter(&pmp->pmp_lock);
                    320:        vp = pmp->pmp_root;
                    321:        if (vp) {
1.18      rmind     322:                mutex_enter(vp->v_interlock);
1.1       pooka     323:                mutex_exit(&pmp->pmp_lock);
1.22.6.1! mrg       324:                switch (vget(vp, 0)) {
        !           325:                case ENOENT:
        !           326:                        goto retry;
        !           327:                case 0:
1.1       pooka     328:                        return 0;
1.22.6.1! mrg       329:                default:
        !           330:                        break;
        !           331:                }
1.1       pooka     332:        } else
                    333:                mutex_exit(&pmp->pmp_lock);
                    334:
                    335:        /*
                    336:         * So, didn't have the magic root vnode available.
                    337:         * No matter, grab another and stuff it with the cookie.
                    338:         */
                    339:        if ((rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie,
                    340:            pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp)))
                    341:                return rv;
                    342:
                    343:        /*
                    344:         * Someone magically managed to race us into puffs_getvnode?
                    345:         * Put our previous new vnode back and retry.
                    346:         */
                    347:        mutex_enter(&pmp->pmp_lock);
                    348:        if (pmp->pmp_root) {
1.14      pooka     349:                struct puffs_node *pnode = vp->v_data;
                    350:
                    351:                LIST_REMOVE(pnode, pn_hashent);
1.1       pooka     352:                mutex_exit(&pmp->pmp_lock);
                    353:                puffs_putvnode(vp);
                    354:                goto retry;
                    355:        }
                    356:
                    357:        /* store cache */
1.5       ad        358:        vp->v_vflag |= VV_ROOT;
1.1       pooka     359:        pmp->pmp_root = vp;
                    360:        mutex_exit(&pmp->pmp_lock);
                    361:
                    362:        return 0;
                    363: }
                    364:
                    365: /*
                    366:  * Locate the in-kernel vnode based on the cookie received given
                    367:  * from userspace.  Returns a vnode, if found, NULL otherwise.
                    368:  * The parameter "lock" control whether to lock the possible or
                    369:  * not.  Locking always might cause us to lock against ourselves
                    370:  * in situations where we want the vnode but don't care for the
                    371:  * vnode lock, e.g. file server issued putpages.
                    372:  */
                    373: int
1.11      pooka     374: puffs_cookie2vnode(struct puffs_mount *pmp, puffs_cookie_t ck, int lock,
1.1       pooka     375:        int willcreate, struct vnode **vpp)
                    376: {
                    377:        struct puffs_node *pnode;
                    378:        struct puffs_newcookie *pnc;
                    379:        struct vnode *vp;
                    380:        int vgetflags, rv;
                    381:
                    382:        /*
                    383:         * Handle root in a special manner, since we want to make sure
                    384:         * pmp_root is properly set.
                    385:         */
1.11      pooka     386:        if (ck == pmp->pmp_root_cookie) {
1.1       pooka     387:                if ((rv = puffs_makeroot(pmp)))
                    388:                        return rv;
                    389:                if (lock)
                    390:                        vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
                    391:
                    392:                *vpp = pmp->pmp_root;
                    393:                return 0;
                    394:        }
                    395:
1.22.6.1! mrg       396:  retry:
1.1       pooka     397:        mutex_enter(&pmp->pmp_lock);
1.11      pooka     398:        pnode = puffs_cookie2pnode(pmp, ck);
1.1       pooka     399:        if (pnode == NULL) {
                    400:                if (willcreate) {
                    401:                        pnc = kmem_alloc(sizeof(struct puffs_newcookie),
                    402:                            KM_SLEEP);
1.11      pooka     403:                        pnc->pnc_cookie = ck;
1.1       pooka     404:                        LIST_INSERT_HEAD(&pmp->pmp_newcookie, pnc, pnc_entries);
                    405:                }
                    406:                mutex_exit(&pmp->pmp_lock);
                    407:                return PUFFS_NOSUCHCOOKIE;
                    408:        }
                    409:        vp = pnode->pn_vp;
1.18      rmind     410:        mutex_enter(vp->v_interlock);
1.1       pooka     411:        mutex_exit(&pmp->pmp_lock);
                    412:
1.16      hannken   413:        vgetflags = 0;
1.1       pooka     414:        if (lock)
1.17      hannken   415:                vgetflags |= LK_EXCLUSIVE;
1.22.6.1! mrg       416:        switch (rv = vget(vp, vgetflags)) {
        !           417:        case ENOENT:
        !           418:                goto retry;
        !           419:        case 0:
        !           420:                break;
        !           421:        default:
1.1       pooka     422:                return rv;
1.22.6.1! mrg       423:        }
1.1       pooka     424:
                    425:        *vpp = vp;
                    426:        return 0;
                    427: }
                    428:
                    429: void
1.8       pooka     430: puffs_updatenode(struct puffs_node *pn, int flags, voff_t size)
1.1       pooka     431: {
                    432:        struct timespec ts;
                    433:
                    434:        if (flags == 0)
                    435:                return;
                    436:
                    437:        nanotime(&ts);
                    438:
                    439:        if (flags & PUFFS_UPDATEATIME) {
                    440:                pn->pn_mc_atime = ts;
                    441:                pn->pn_stat |= PNODE_METACACHE_ATIME;
                    442:        }
                    443:        if (flags & PUFFS_UPDATECTIME) {
                    444:                pn->pn_mc_ctime = ts;
                    445:                pn->pn_stat |= PNODE_METACACHE_CTIME;
                    446:        }
                    447:        if (flags & PUFFS_UPDATEMTIME) {
                    448:                pn->pn_mc_mtime = ts;
                    449:                pn->pn_stat |= PNODE_METACACHE_MTIME;
                    450:        }
                    451:        if (flags & PUFFS_UPDATESIZE) {
1.8       pooka     452:                pn->pn_mc_size = size;
1.1       pooka     453:                pn->pn_stat |= PNODE_METACACHE_SIZE;
                    454:        }
                    455: }
                    456:
                    457: /*
                    458:  * Add reference to node.
                    459:  *  mutex held on entry and return
                    460:  */
                    461: void
                    462: puffs_referencenode(struct puffs_node *pn)
                    463: {
                    464:
                    465:        KASSERT(mutex_owned(&pn->pn_mtx));
                    466:        pn->pn_refcount++;
                    467: }
                    468:
                    469: /*
                    470:  * Release pnode structure which dealing with references to the
                    471:  * puffs_node instead of the vnode.  Can't use vref()/vrele() on
                    472:  * the vnode there, since that causes the lovely VOP_INACTIVE(),
                    473:  * which in turn causes the lovely deadlock when called by the one
                    474:  * who is supposed to handle it.
                    475:  */
                    476: void
                    477: puffs_releasenode(struct puffs_node *pn)
                    478: {
                    479:
                    480:        mutex_enter(&pn->pn_mtx);
                    481:        if (--pn->pn_refcount == 0) {
                    482:                mutex_exit(&pn->pn_mtx);
                    483:                mutex_destroy(&pn->pn_mtx);
1.20      manu      484:                mutex_destroy(&pn->pn_sizemtx);
1.12      rmind     485:                seldestroy(&pn->pn_sel);
1.1       pooka     486:                pool_put(&puffs_pnpool, pn);
                    487:        } else {
                    488:                mutex_exit(&pn->pn_mtx);
                    489:        }
                    490: }

CVSweb <webmaster@jp.NetBSD.org>