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

Annotation of src/sys/fs/puffs/puffs_subr.c, Revision 1.27

1.27    ! pooka       1: /*     $NetBSD: puffs_subr.c,v 1.26 2007/03/29 16:04:26 pooka Exp $    */
1.1       pooka       2:
                      3: /*
                      4:  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
                      5:  *
                      6:  * Development of this software was supported by the
                      7:  * Google Summer of Code program and the Ulla Tuominen Foundation.
                      8:  * The Google SoC project was mentored by Bill Studenmund.
                      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:  * 3. The name of the company nor the name of the author may be used to
                     19:  *    endorse or promote products derived from this software without specific
                     20:  *    prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     23:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     24:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     25:  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     28:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
                     34:
                     35: #include <sys/cdefs.h>
1.27    ! pooka      36: __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.26 2007/03/29 16:04:26 pooka Exp $");
1.1       pooka      37:
                     38: #include <sys/param.h>
                     39: #include <sys/conf.h>
1.16      pooka      40: #include <sys/hash.h>
1.1       pooka      41: #include <sys/malloc.h>
                     42: #include <sys/mount.h>
                     43: #include <sys/socketvar.h>
                     44: #include <sys/vnode.h>
                     45: #include <sys/kauth.h>
                     46: #include <sys/namei.h>
                     47:
                     48: #include <fs/puffs/puffs_msgif.h>
                     49: #include <fs/puffs/puffs_sys.h>
                     50:
1.7       pooka      51: #include <miscfs/genfs/genfs_node.h>
1.4       pooka      52: #include <miscfs/specfs/specdev.h>
                     53:
1.26      pooka      54: struct pool puffs_pnpool;
1.1       pooka      55:
1.19      pooka      56: #ifdef PUFFSDEBUG
1.10      pooka      57: int puffsdebug;
                     58: #endif
                     59:
1.16      pooka      60: static __inline struct puffs_node_hashlist
                     61:        *puffs_cookie2hashlist(struct puffs_mount *, void *);
                     62: static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *, void *);
1.7       pooka      63:
                     64: static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
                     65: static void puffs_gop_markupdate(struct vnode *, int);
                     66:
                     67: static const struct genfs_ops puffs_genfsops = {
                     68:        .gop_size = puffs_gop_size,
                     69:        .gop_write = genfs_gop_write,
                     70:        .gop_markupdate = puffs_gop_markupdate,
                     71: #if 0
                     72:        .gop_alloc, should ask userspace
                     73: #endif
                     74: };
                     75:
1.1       pooka      76: /*
                     77:  * Grab a vnode, intialize all the puffs-dependant stuff.
                     78:  */
                     79: int
1.4       pooka      80: puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
1.7       pooka      81:        voff_t vsize, dev_t rdev, struct vnode **vpp)
1.1       pooka      82: {
                     83:        struct puffs_mount *pmp;
1.4       pooka      84:        struct vnode *vp, *nvp;
1.1       pooka      85:        struct puffs_node *pnode;
1.16      pooka      86:        struct puffs_node_hashlist *plist;
1.1       pooka      87:        int error;
                     88:
                     89:        pmp = MPTOPUFFSMP(mp);
                     90:
1.2       pooka      91:        /*
                     92:         * XXX: there is a deadlock condition between vfs_busy() and
                     93:         * vnode locks.  For an unmounting file system the mountpoint
                     94:         * is frozen, but in unmount(FORCE) vflush() wants to access all
                     95:         * of the vnodes.  If we are here waiting for the mountpoint
                     96:         * lock while holding on to a vnode lock, well, we ain't
                     97:         * just pining for the fjords anymore.  If we release the
                     98:         * vnode lock, we will be in the situation "mount point
                     99:         * is dying" and panic() will ensue in insmntque.  So as a
                    100:         * temporary workaround, get a vnode without putting it on
                    101:         * the mount point list, check if mount point is still alive
                    102:         * and kicking and only then add the vnode to the list.
                    103:         */
                    104:        error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
                    105:        if (error)
1.1       pooka     106:                return error;
1.2       pooka     107:        vp->v_vnlock = NULL;
1.4       pooka     108:        vp->v_type = type;
1.2       pooka     109:
                    110:        /*
                    111:         * Check what mount point isn't going away.  This will work
                    112:         * until we decide to remove biglock or make the kernel
                    113:         * preemptive.  But hopefully the real problem will be fixed
                    114:         * by then.
                    115:         *
                    116:         * XXX: yes, should call vfs_busy(), but thar be rabbits with
                    117:         * vicious streaks a mile wide ...
                    118:         */
                    119:        if (mp->mnt_iflag & IMNT_UNMOUNT) {
                    120:                DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
                    121:                    "vnode for cookie %p\n", mp, cookie));
                    122:                ungetnewvnode(vp);
                    123:                return ENXIO;
1.1       pooka     124:        }
                    125:
1.2       pooka     126:        /* So it's not dead yet.. good.. inform new vnode of its master */
                    127:        simple_lock(&mntvnode_slock);
1.16      pooka     128:        TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
1.2       pooka     129:        simple_unlock(&mntvnode_slock);
                    130:        vp->v_mount = mp;
                    131:
1.4       pooka     132:        /*
                    133:         * clerical tasks & footwork
                    134:         */
                    135:
                    136:        /* dances based on vnode type. almost ufs_vinit(), but not quite */
                    137:        switch (type) {
                    138:        case VCHR:
                    139:        case VBLK:
                    140:                /*
                    141:                 * replace vnode operation vector with the specops vector.
                    142:                 * our user server has very little control over the node
                    143:                 * if it decides its a character or block special file
                    144:                 */
                    145:                vp->v_op = puffs_specop_p;
                    146:
                    147:                /* do the standard checkalias-dance */
                    148:                if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
                    149:                        /*
1.6       pooka     150:                         * found: release & unallocate aliased
1.4       pooka     151:                         * old (well, actually, new) node
                    152:                         */
                    153:                        vp->v_op = spec_vnodeop_p;
                    154:                        vp->v_flag &= ~VLOCKSWORK;
                    155:                        vrele(vp);
                    156:                        vgone(vp); /* cya */
                    157:
                    158:                        /* init "new" vnode */
                    159:                        vp = nvp;
                    160:                        vp->v_vnlock = NULL;
                    161:                        vp->v_mount = mp;
                    162:                }
                    163:                break;
1.7       pooka     164:
1.5       pooka     165:        case VFIFO:
                    166:                vp->v_op = puffs_fifoop_p;
                    167:                break;
1.7       pooka     168:
                    169:        case VREG:
                    170:                uvm_vnp_setsize(vp, vsize);
                    171:                break;
                    172:
1.5       pooka     173:        case VDIR:
                    174:        case VLNK:
                    175:        case VSOCK:
                    176:                break;
1.4       pooka     177:        default:
1.5       pooka     178: #ifdef DIAGNOSTIC
                    179:                panic("puffs_getvnode: invalid vtype %d", type);
                    180: #endif
1.4       pooka     181:                break;
                    182:        }
                    183:
1.2       pooka     184:        pnode = pool_get(&puffs_pnpool, PR_WAITOK);
1.1       pooka     185:        pnode->pn_cookie = cookie;
                    186:        pnode->pn_stat = 0;
1.16      pooka     187:        plist = puffs_cookie2hashlist(pmp, cookie);
                    188:        LIST_INSERT_HEAD(plist, pnode, pn_hashent);
1.1       pooka     189:        vp->v_data = pnode;
1.4       pooka     190:        vp->v_type = type;
1.1       pooka     191:        pnode->pn_vp = vp;
                    192:
1.7       pooka     193:        genfs_node_init(vp, &puffs_genfsops);
1.1       pooka     194:        *vpp = vp;
                    195:
                    196:        DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
                    197:            pnode, pnode->pn_cookie));
                    198:
                    199:        return 0;
                    200: }
                    201:
                    202: /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
                    203: int
                    204: puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
1.4       pooka     205:        void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
1.1       pooka     206: {
1.13      pooka     207:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1       pooka     208:        struct vnode *vp;
                    209:        int error;
                    210:
                    211:        /* userspace probably has this as a NULL op */
                    212:        if (cookie == NULL) {
                    213:                error = EOPNOTSUPP;
1.3       pooka     214:                return error;
1.1       pooka     215:        }
                    216:
1.15      pooka     217:        /*
                    218:         * Check for previous node with the same designation.
1.20      pooka     219:         * Explicitly check the root node cookie, since it might be
                    220:         * reclaimed from the kernel when this check is made.
1.15      pooka     221:         *
                    222:         * XXX: technically this error check should punish the fs,
                    223:         * not the caller.
                    224:         */
1.26      pooka     225:        mutex_enter(&pmp->pmp_lock);
1.20      pooka     226:        if (cookie == pmp->pmp_rootcookie
                    227:            || puffs_cookie2pnode(pmp, cookie) != NULL) {
1.26      pooka     228:                mutex_exit(&pmp->pmp_lock);
1.15      pooka     229:                error = EEXIST;
                    230:                return error;
                    231:        }
1.26      pooka     232:        mutex_exit(&pmp->pmp_lock);
1.15      pooka     233:
1.7       pooka     234:        error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
1.1       pooka     235:        if (error)
1.3       pooka     236:                return error;
1.1       pooka     237:
                    238:        vp->v_type = type;
                    239:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    240:        *vpp = vp;
                    241:
1.13      pooka     242:        if ((cnp->cn_flags & MAKEENTRY) && PUFFS_DOCACHE(pmp))
                    243:                cache_enter(dvp, vp, cnp);
                    244:
1.3       pooka     245:        return 0;
1.1       pooka     246: }
                    247:
                    248: void
                    249: puffs_putvnode(struct vnode *vp)
                    250: {
                    251:        struct puffs_mount *pmp;
                    252:        struct puffs_node *pnode;
                    253:
                    254:        pmp = VPTOPUFFSMP(vp);
                    255:        pnode = VPTOPP(vp);
                    256:
                    257: #ifdef DIAGNOSTIC
                    258:        if (vp->v_tag != VT_PUFFS)
                    259:                panic("puffs_putvnode: %p not a puffs vnode", vp);
                    260: #endif
                    261:
1.16      pooka     262:        LIST_REMOVE(pnode, pn_hashent);
1.21      ad        263:        genfs_node_destroy(vp);
1.1       pooka     264:        pool_put(&puffs_pnpool, vp->v_data);
                    265:        vp->v_data = NULL;
                    266:
                    267:        return;
                    268: }
                    269:
1.16      pooka     270: static __inline struct puffs_node_hashlist *
                    271: puffs_cookie2hashlist(struct puffs_mount *pmp, void *cookie)
                    272: {
                    273:        uint32_t hash;
                    274:
                    275:        hash = hash32_buf(&cookie, sizeof(void *), HASH32_BUF_INIT);
                    276:        return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
                    277: }
                    278:
1.1       pooka     279: /*
1.15      pooka     280:  * Translate cookie to puffs_node.  Caller must hold mountpoint
                    281:  * lock and it will be held upon return.
                    282:  */
1.16      pooka     283: static struct puffs_node *
1.15      pooka     284: puffs_cookie2pnode(struct puffs_mount *pmp, void *cookie)
                    285: {
1.16      pooka     286:        struct puffs_node_hashlist *plist;
1.15      pooka     287:        struct puffs_node *pnode;
                    288:
1.16      pooka     289:        plist = puffs_cookie2hashlist(pmp, cookie);
                    290:        LIST_FOREACH(pnode, plist, pn_hashent) {
1.15      pooka     291:                if (pnode->pn_cookie == cookie)
                    292:                        break;
                    293:        }
                    294:
                    295:        return pnode;
                    296: }
                    297:
                    298: /*
1.1       pooka     299:  * Locate the in-kernel vnode based on the cookie received given
1.20      pooka     300:  * from userspace.  Returns a vnode, if found, NULL otherwise.
                    301:  * The parameter "lock" control whether to lock the possible or
                    302:  * not.  Locking always might cause us to lock against ourselves
                    303:  * in situations where we want the vnode but don't care for the
                    304:  * vnode lock, e.g. file server issued putpages.
1.1       pooka     305:  */
                    306: struct vnode *
1.14      pooka     307: puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock)
1.1       pooka     308: {
                    309:        struct puffs_node *pnode;
                    310:        struct vnode *vp;
1.14      pooka     311:        int vgetflags;
1.1       pooka     312:
1.20      pooka     313:        /*
                    314:         * If we're trying to get the root vnode, return it through
                    315:         * puffs_root() to get all the right things set.  Lock must
                    316:         * be set, since VFS_ROOT() always locks the returned vnode.
                    317:         */
                    318:        if (cookie == pmp->pmp_rootcookie) {
                    319:                if (!lock)
                    320:                        return NULL;
                    321:                if (VFS_ROOT(pmp->pmp_mp, &vp))
                    322:                        return NULL;
                    323:
                    324:                return vp;
                    325:        }
                    326:
1.17      pooka     327:        vgetflags = LK_INTERLOCK;
                    328:        if (lock)
                    329:                vgetflags |= LK_EXCLUSIVE | LK_RETRY;
                    330:
1.26      pooka     331:        mutex_enter(&pmp->pmp_lock);
1.15      pooka     332:        pnode = puffs_cookie2pnode(pmp, cookie);
1.14      pooka     333:
1.15      pooka     334:        if (pnode == NULL) {
1.26      pooka     335:                mutex_exit(&pmp->pmp_lock);
1.1       pooka     336:                return NULL;
1.15      pooka     337:        }
1.1       pooka     338:        vp = pnode->pn_vp;
1.17      pooka     339:
                    340:        simple_lock(&vp->v_interlock);
1.26      pooka     341:        mutex_exit(&pmp->pmp_lock);
1.1       pooka     342:
1.14      pooka     343:        if (vget(vp, vgetflags))
                    344:                return NULL;
                    345:
1.1       pooka     346:        return vp;
                    347: }
                    348:
                    349: void
1.12      pooka     350: puffs_makecn(struct puffs_kcn *pkcn, const struct componentname *cn)
1.1       pooka     351: {
                    352:
1.12      pooka     353:        pkcn->pkcn_nameiop = cn->cn_nameiop;
                    354:        pkcn->pkcn_flags = cn->cn_flags;
                    355:        pkcn->pkcn_pid = cn->cn_lwp->l_proc->p_pid;
                    356:        puffs_credcvt(&pkcn->pkcn_cred, cn->cn_cred);
1.1       pooka     357:
1.12      pooka     358:        (void)memcpy(&pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
                    359:        pkcn->pkcn_name[cn->cn_namelen] = '\0';
                    360:        pkcn->pkcn_namelen = cn->cn_namelen;
1.1       pooka     361: }
                    362:
                    363: /*
                    364:  * Convert given credentials to struct puffs_cred for userspace.
                    365:  */
                    366: void
                    367: puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
                    368: {
                    369:
                    370:        memset(pcr, 0, sizeof(struct puffs_cred));
                    371:
                    372:        if (cred == NOCRED || cred == FSCRED) {
                    373:                pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
                    374:                if (cred == NOCRED)
                    375:                        pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
                    376:                if (cred == FSCRED)
                    377:                        pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
                    378:        } else {
                    379:                pcr->pcr_type = PUFFCRED_TYPE_UUC;
                    380:                kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
                    381:        }
                    382: }
                    383:
                    384: /*
                    385:  * Return pid.  In case the operation is coming from within the
                    386:  * kernel without any process context, borrow the swapper's pid.
                    387:  */
                    388: pid_t
                    389: puffs_lwp2pid(struct lwp *l)
                    390: {
                    391:
                    392:        return l ? l->l_proc->p_pid : 0;
                    393: }
1.7       pooka     394:
                    395:
                    396: static void
1.8       christos  397: puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
                    398:        int flags)
1.7       pooka     399: {
                    400:
                    401:        *eobp = size;
                    402: }
                    403:
                    404: static void
                    405: puffs_gop_markupdate(struct vnode *vp, int flags)
                    406: {
                    407:        int uflags = 0;
                    408:
                    409:        if (flags & GOP_UPDATE_ACCESSED)
                    410:                uflags |= PUFFS_UPDATEATIME;
                    411:        if (flags & GOP_UPDATE_MODIFIED)
                    412:                uflags |= PUFFS_UPDATEMTIME;
                    413:
                    414:        puffs_updatenode(vp, uflags);
                    415: }
                    416:
                    417: void
                    418: puffs_updatenode(struct vnode *vp, int flags)
                    419: {
1.25      pooka     420:        struct puffs_node *pn;
1.7       pooka     421:        struct timespec ts;
                    422:
                    423:        if (flags == 0)
                    424:                return;
                    425:
1.25      pooka     426:        pn = VPTOPP(vp);
1.7       pooka     427:        nanotime(&ts);
                    428:
1.25      pooka     429:        if (flags & PUFFS_UPDATEATIME) {
                    430:                pn->pn_mc_atime = ts;
                    431:                pn->pn_stat |= PNODE_METACACHE_ATIME;
                    432:        }
                    433:        if (flags & PUFFS_UPDATECTIME) {
                    434:                pn->pn_mc_ctime = ts;
                    435:                pn->pn_stat |= PNODE_METACACHE_CTIME;
                    436:        }
                    437:        if (flags & PUFFS_UPDATEMTIME) {
                    438:                pn->pn_mc_mtime = ts;
                    439:                pn->pn_stat |= PNODE_METACACHE_MTIME;
                    440:        }
                    441:        if (flags & PUFFS_UPDATESIZE) {
                    442:                pn->pn_mc_size = vp->v_size;
                    443:                pn->pn_stat |= PNODE_METACACHE_SIZE;
                    444:        }
1.7       pooka     445: }
1.9       pooka     446:
                    447: void
                    448: puffs_updatevpsize(struct vnode *vp)
                    449: {
                    450:        struct vattr va;
                    451:
                    452:        if (VOP_GETATTR(vp, &va, FSCRED, NULL))
                    453:                return;
                    454:
                    455:        if (va.va_size != VNOVAL)
                    456:                vp->v_size = va.va_size;
                    457: }
1.27    ! pooka     458:
        !           459: void
        !           460: puffs_parkdone_asyncbioread(struct puffs_req *preq, void *arg)
        !           461: {
        !           462:        struct puffs_vnreq_read *read_argp = (void *)preq;
        !           463:        struct buf *bp = arg;
        !           464:        size_t moved;
        !           465:
        !           466:        bp->b_error = preq->preq_rv;
        !           467:        if (bp->b_error == 0) {
        !           468:                moved = bp->b_bcount - read_argp->pvnr_resid;
        !           469:                bp->b_resid = read_argp->pvnr_resid;
        !           470:
        !           471:                memcpy(bp->b_data, read_argp->pvnr_data, moved);
        !           472:        } else {
        !           473:                bp->b_flags |= B_ERROR;
        !           474:        }
        !           475:
        !           476:        biodone(bp);
        !           477:        free(preq, M_PUFFS);
        !           478: }

CVSweb <webmaster@jp.NetBSD.org>