[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.21

1.21    ! ad          1: /*     $NetBSD: puffs_subr.c,v 1.20 2007/02/16 16:37:55 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.21    ! ad         36: __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.20 2007/02/16 16:37:55 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.1       pooka      54: POOL_INIT(puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, "puffspnpl",
                     55:     &pool_allocator_nointr);
                     56:
1.19      pooka      57: #ifdef PUFFSDEBUG
1.10      pooka      58: int puffsdebug;
                     59: #endif
                     60:
1.16      pooka      61: static __inline struct puffs_node_hashlist
                     62:        *puffs_cookie2hashlist(struct puffs_mount *, void *);
                     63: static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *, void *);
1.7       pooka      64:
                     65: static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
                     66: static void puffs_gop_markupdate(struct vnode *, int);
                     67:
                     68: static const struct genfs_ops puffs_genfsops = {
                     69:        .gop_size = puffs_gop_size,
                     70:        .gop_write = genfs_gop_write,
                     71:        .gop_markupdate = puffs_gop_markupdate,
                     72: #if 0
                     73:        .gop_alloc, should ask userspace
                     74: #endif
                     75: };
                     76:
1.1       pooka      77: /*
                     78:  * Grab a vnode, intialize all the puffs-dependant stuff.
                     79:  */
                     80: int
1.4       pooka      81: puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
1.7       pooka      82:        voff_t vsize, dev_t rdev, struct vnode **vpp)
1.1       pooka      83: {
                     84:        struct puffs_mount *pmp;
1.4       pooka      85:        struct vnode *vp, *nvp;
1.1       pooka      86:        struct puffs_node *pnode;
1.16      pooka      87:        struct puffs_node_hashlist *plist;
1.1       pooka      88:        int error;
                     89:
                     90:        pmp = MPTOPUFFSMP(mp);
                     91:
1.2       pooka      92:        /*
                     93:         * XXX: there is a deadlock condition between vfs_busy() and
                     94:         * vnode locks.  For an unmounting file system the mountpoint
                     95:         * is frozen, but in unmount(FORCE) vflush() wants to access all
                     96:         * of the vnodes.  If we are here waiting for the mountpoint
                     97:         * lock while holding on to a vnode lock, well, we ain't
                     98:         * just pining for the fjords anymore.  If we release the
                     99:         * vnode lock, we will be in the situation "mount point
                    100:         * is dying" and panic() will ensue in insmntque.  So as a
                    101:         * temporary workaround, get a vnode without putting it on
                    102:         * the mount point list, check if mount point is still alive
                    103:         * and kicking and only then add the vnode to the list.
                    104:         */
                    105:        error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
                    106:        if (error)
1.1       pooka     107:                return error;
1.2       pooka     108:        vp->v_vnlock = NULL;
1.4       pooka     109:        vp->v_type = type;
1.2       pooka     110:
                    111:        /*
                    112:         * Check what mount point isn't going away.  This will work
                    113:         * until we decide to remove biglock or make the kernel
                    114:         * preemptive.  But hopefully the real problem will be fixed
                    115:         * by then.
                    116:         *
                    117:         * XXX: yes, should call vfs_busy(), but thar be rabbits with
                    118:         * vicious streaks a mile wide ...
                    119:         */
                    120:        if (mp->mnt_iflag & IMNT_UNMOUNT) {
                    121:                DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
                    122:                    "vnode for cookie %p\n", mp, cookie));
                    123:                ungetnewvnode(vp);
                    124:                return ENXIO;
1.1       pooka     125:        }
                    126:
1.2       pooka     127:        /* So it's not dead yet.. good.. inform new vnode of its master */
                    128:        simple_lock(&mntvnode_slock);
1.16      pooka     129:        TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
1.2       pooka     130:        simple_unlock(&mntvnode_slock);
                    131:        vp->v_mount = mp;
                    132:
1.4       pooka     133:        /*
                    134:         * clerical tasks & footwork
                    135:         */
                    136:
                    137:        /* dances based on vnode type. almost ufs_vinit(), but not quite */
                    138:        switch (type) {
                    139:        case VCHR:
                    140:        case VBLK:
                    141:                /*
                    142:                 * replace vnode operation vector with the specops vector.
                    143:                 * our user server has very little control over the node
                    144:                 * if it decides its a character or block special file
                    145:                 */
                    146:                vp->v_op = puffs_specop_p;
                    147:
                    148:                /* do the standard checkalias-dance */
                    149:                if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
                    150:                        /*
1.6       pooka     151:                         * found: release & unallocate aliased
1.4       pooka     152:                         * old (well, actually, new) node
                    153:                         */
                    154:                        vp->v_op = spec_vnodeop_p;
                    155:                        vp->v_flag &= ~VLOCKSWORK;
                    156:                        vrele(vp);
                    157:                        vgone(vp); /* cya */
                    158:
                    159:                        /* init "new" vnode */
                    160:                        vp = nvp;
                    161:                        vp->v_vnlock = NULL;
                    162:                        vp->v_mount = mp;
                    163:                }
                    164:                break;
1.7       pooka     165:
1.5       pooka     166:        case VFIFO:
                    167:                vp->v_op = puffs_fifoop_p;
                    168:                break;
1.7       pooka     169:
                    170:        case VREG:
                    171:                uvm_vnp_setsize(vp, vsize);
                    172:                break;
                    173:
1.5       pooka     174:        case VDIR:
                    175:        case VLNK:
                    176:        case VSOCK:
                    177:                break;
1.4       pooka     178:        default:
1.5       pooka     179: #ifdef DIAGNOSTIC
                    180:                panic("puffs_getvnode: invalid vtype %d", type);
                    181: #endif
1.4       pooka     182:                break;
                    183:        }
                    184:
1.2       pooka     185:        pnode = pool_get(&puffs_pnpool, PR_WAITOK);
1.1       pooka     186:        pnode->pn_cookie = cookie;
                    187:        pnode->pn_stat = 0;
1.16      pooka     188:        plist = puffs_cookie2hashlist(pmp, cookie);
                    189:        LIST_INSERT_HEAD(plist, pnode, pn_hashent);
1.1       pooka     190:        vp->v_data = pnode;
1.4       pooka     191:        vp->v_type = type;
1.1       pooka     192:        pnode->pn_vp = vp;
                    193:
1.7       pooka     194:        genfs_node_init(vp, &puffs_genfsops);
1.1       pooka     195:        *vpp = vp;
                    196:
                    197:        DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
                    198:            pnode, pnode->pn_cookie));
                    199:
                    200:        return 0;
                    201: }
                    202:
                    203: /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
                    204: int
                    205: puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
1.4       pooka     206:        void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
1.1       pooka     207: {
1.13      pooka     208:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1       pooka     209:        struct vnode *vp;
                    210:        int error;
                    211:
                    212:        /* userspace probably has this as a NULL op */
                    213:        if (cookie == NULL) {
                    214:                error = EOPNOTSUPP;
1.3       pooka     215:                return error;
1.1       pooka     216:        }
                    217:
1.15      pooka     218:        /*
                    219:         * Check for previous node with the same designation.
1.20      pooka     220:         * Explicitly check the root node cookie, since it might be
                    221:         * reclaimed from the kernel when this check is made.
1.15      pooka     222:         *
                    223:         * XXX: technically this error check should punish the fs,
                    224:         * not the caller.
                    225:         */
                    226:        simple_lock(&pmp->pmp_lock);
1.20      pooka     227:        if (cookie == pmp->pmp_rootcookie
                    228:            || puffs_cookie2pnode(pmp, cookie) != NULL) {
1.15      pooka     229:                simple_unlock(&pmp->pmp_lock);
                    230:                error = EEXIST;
                    231:                return error;
                    232:        }
                    233:        simple_unlock(&pmp->pmp_lock);
                    234:
1.7       pooka     235:        error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
1.1       pooka     236:        if (error)
1.3       pooka     237:                return error;
1.1       pooka     238:
                    239:        vp->v_type = type;
                    240:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    241:        *vpp = vp;
                    242:
1.13      pooka     243:        if ((cnp->cn_flags & MAKEENTRY) && PUFFS_DOCACHE(pmp))
                    244:                cache_enter(dvp, vp, cnp);
                    245:
1.3       pooka     246:        return 0;
1.1       pooka     247: }
                    248:
                    249: void
                    250: puffs_putvnode(struct vnode *vp)
                    251: {
                    252:        struct puffs_mount *pmp;
                    253:        struct puffs_node *pnode;
                    254:
                    255:        pmp = VPTOPUFFSMP(vp);
                    256:        pnode = VPTOPP(vp);
                    257:
                    258: #ifdef DIAGNOSTIC
                    259:        if (vp->v_tag != VT_PUFFS)
                    260:                panic("puffs_putvnode: %p not a puffs vnode", vp);
                    261: #endif
                    262:
1.16      pooka     263:        LIST_REMOVE(pnode, pn_hashent);
1.21    ! ad        264:        genfs_node_destroy(vp);
1.1       pooka     265:        pool_put(&puffs_pnpool, vp->v_data);
                    266:        vp->v_data = NULL;
                    267:
                    268:        return;
                    269: }
                    270:
1.16      pooka     271: static __inline struct puffs_node_hashlist *
                    272: puffs_cookie2hashlist(struct puffs_mount *pmp, void *cookie)
                    273: {
                    274:        uint32_t hash;
                    275:
                    276:        hash = hash32_buf(&cookie, sizeof(void *), HASH32_BUF_INIT);
                    277:        return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
                    278: }
                    279:
1.1       pooka     280: /*
1.15      pooka     281:  * Translate cookie to puffs_node.  Caller must hold mountpoint
                    282:  * lock and it will be held upon return.
                    283:  */
1.16      pooka     284: static struct puffs_node *
1.15      pooka     285: puffs_cookie2pnode(struct puffs_mount *pmp, void *cookie)
                    286: {
1.16      pooka     287:        struct puffs_node_hashlist *plist;
1.15      pooka     288:        struct puffs_node *pnode;
                    289:
1.16      pooka     290:        plist = puffs_cookie2hashlist(pmp, cookie);
                    291:        LIST_FOREACH(pnode, plist, pn_hashent) {
1.15      pooka     292:                if (pnode->pn_cookie == cookie)
                    293:                        break;
                    294:        }
                    295:
                    296:        return pnode;
                    297: }
                    298:
                    299: /*
1.1       pooka     300:  * Locate the in-kernel vnode based on the cookie received given
1.20      pooka     301:  * from userspace.  Returns a vnode, if found, NULL otherwise.
                    302:  * The parameter "lock" control whether to lock the possible or
                    303:  * not.  Locking always might cause us to lock against ourselves
                    304:  * in situations where we want the vnode but don't care for the
                    305:  * vnode lock, e.g. file server issued putpages.
1.1       pooka     306:  */
                    307: struct vnode *
1.14      pooka     308: puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock)
1.1       pooka     309: {
                    310:        struct puffs_node *pnode;
                    311:        struct vnode *vp;
1.14      pooka     312:        int vgetflags;
1.1       pooka     313:
1.20      pooka     314:        /*
                    315:         * If we're trying to get the root vnode, return it through
                    316:         * puffs_root() to get all the right things set.  Lock must
                    317:         * be set, since VFS_ROOT() always locks the returned vnode.
                    318:         */
                    319:        if (cookie == pmp->pmp_rootcookie) {
                    320:                if (!lock)
                    321:                        return NULL;
                    322:                if (VFS_ROOT(pmp->pmp_mp, &vp))
                    323:                        return NULL;
                    324:
                    325:                return vp;
                    326:        }
                    327:
1.17      pooka     328:        vgetflags = LK_INTERLOCK;
                    329:        if (lock)
                    330:                vgetflags |= LK_EXCLUSIVE | LK_RETRY;
                    331:
1.1       pooka     332:        simple_lock(&pmp->pmp_lock);
1.15      pooka     333:        pnode = puffs_cookie2pnode(pmp, cookie);
1.14      pooka     334:
1.15      pooka     335:        if (pnode == NULL) {
                    336:                simple_unlock(&pmp->pmp_lock);
1.1       pooka     337:                return NULL;
1.15      pooka     338:        }
1.1       pooka     339:        vp = pnode->pn_vp;
1.17      pooka     340:
                    341:        simple_lock(&vp->v_interlock);
1.15      pooka     342:        simple_unlock(&pmp->pmp_lock);
1.1       pooka     343:
1.14      pooka     344:        if (vget(vp, vgetflags))
                    345:                return NULL;
                    346:
1.1       pooka     347:        return vp;
                    348: }
                    349:
                    350: void
1.12      pooka     351: puffs_makecn(struct puffs_kcn *pkcn, const struct componentname *cn)
1.1       pooka     352: {
                    353:
1.12      pooka     354:        pkcn->pkcn_nameiop = cn->cn_nameiop;
                    355:        pkcn->pkcn_flags = cn->cn_flags;
                    356:        pkcn->pkcn_pid = cn->cn_lwp->l_proc->p_pid;
                    357:        puffs_credcvt(&pkcn->pkcn_cred, cn->cn_cred);
1.1       pooka     358:
1.12      pooka     359:        (void)memcpy(&pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
                    360:        pkcn->pkcn_name[cn->cn_namelen] = '\0';
                    361:        pkcn->pkcn_namelen = cn->cn_namelen;
1.1       pooka     362: }
                    363:
                    364: /*
                    365:  * Convert given credentials to struct puffs_cred for userspace.
                    366:  */
                    367: void
                    368: puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
                    369: {
                    370:
                    371:        memset(pcr, 0, sizeof(struct puffs_cred));
                    372:
                    373:        if (cred == NOCRED || cred == FSCRED) {
                    374:                pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
                    375:                if (cred == NOCRED)
                    376:                        pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
                    377:                if (cred == FSCRED)
                    378:                        pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
                    379:        } else {
                    380:                pcr->pcr_type = PUFFCRED_TYPE_UUC;
                    381:                kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
                    382:        }
                    383: }
                    384:
                    385: /*
                    386:  * Return pid.  In case the operation is coming from within the
                    387:  * kernel without any process context, borrow the swapper's pid.
                    388:  */
                    389: pid_t
                    390: puffs_lwp2pid(struct lwp *l)
                    391: {
                    392:
                    393:        return l ? l->l_proc->p_pid : 0;
                    394: }
1.7       pooka     395:
                    396:
                    397: static void
1.8       christos  398: puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
                    399:        int flags)
1.7       pooka     400: {
                    401:
                    402:        *eobp = size;
                    403: }
                    404:
                    405: static void
                    406: puffs_gop_markupdate(struct vnode *vp, int flags)
                    407: {
                    408:        int uflags = 0;
                    409:
                    410:        if (flags & GOP_UPDATE_ACCESSED)
                    411:                uflags |= PUFFS_UPDATEATIME;
                    412:        if (flags & GOP_UPDATE_MODIFIED)
                    413:                uflags |= PUFFS_UPDATEMTIME;
                    414:
                    415:        puffs_updatenode(vp, uflags);
                    416: }
                    417:
                    418: void
                    419: puffs_updatenode(struct vnode *vp, int flags)
                    420: {
                    421:        struct timespec ts;
                    422:        struct puffs_vnreq_setattr *setattr_arg;
                    423:
                    424:        if (flags == 0)
                    425:                return;
                    426:
                    427:        setattr_arg = malloc(sizeof(struct puffs_vnreq_setattr), M_PUFFS,
                    428:            M_NOWAIT | M_ZERO);
                    429:        if (setattr_arg == NULL)
                    430:                return; /* 2bad */
                    431:
                    432:        nanotime(&ts);
                    433:
                    434:        VATTR_NULL(&setattr_arg->pvnr_va);
                    435:        if (flags & PUFFS_UPDATEATIME)
                    436:                setattr_arg->pvnr_va.va_atime = ts;
                    437:        if (flags & PUFFS_UPDATECTIME)
                    438:                setattr_arg->pvnr_va.va_ctime = ts;
                    439:        if (flags & PUFFS_UPDATEMTIME)
                    440:                setattr_arg->pvnr_va.va_mtime = ts;
                    441:        if (flags & PUFFS_UPDATESIZE)
                    442:                setattr_arg->pvnr_va.va_size = vp->v_size;
                    443:
                    444:        setattr_arg->pvnr_pid = 0;
                    445:        puffs_credcvt(&setattr_arg->pvnr_cred, NOCRED);
                    446:
                    447:        /* setattr_arg ownership shifted to callee */
                    448:        puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_SETATTR,
                    449:            setattr_arg, sizeof(struct puffs_vnreq_setattr), VPTOPNC(vp));
                    450: }
1.9       pooka     451:
                    452: void
                    453: puffs_updatevpsize(struct vnode *vp)
                    454: {
                    455:        struct vattr va;
                    456:
                    457:        if (VOP_GETATTR(vp, &va, FSCRED, NULL))
                    458:                return;
                    459:
                    460:        if (va.va_size != VNOVAL)
                    461:                vp->v_size = va.va_size;
                    462: }
1.11      pooka     463:
                    464: /*
                    465:  * We're dead, kaput, RIP, slightly more than merely pining for the
                    466:  * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
                    467:  * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
1.18      pooka     468:  *
                    469:  * Caller must hold puffs spinlock.
1.11      pooka     470:  */
                    471: void
                    472: puffs_userdead(struct puffs_mount *pmp)
                    473: {
                    474:        struct puffs_park *park;
                    475:
                    476:        /*
                    477:         * Mark filesystem status as dying so that operations don't
                    478:         * attempt to march to userspace any longer.
                    479:         */
                    480:        pmp->pmp_status = PUFFSTAT_DYING;
                    481:
                    482:        /* and wakeup processes waiting for a reply from userspace */
                    483:        TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) {
                    484:                park->park_preq->preq_rv = ENXIO;
                    485:                TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries);
                    486:                wakeup(park);
                    487:        }
                    488:
                    489:        /* wakeup waiters for completion of vfs/vnode requests */
                    490:        TAILQ_FOREACH(park, &pmp->pmp_req_touser, park_entries) {
                    491:                park->park_preq->preq_rv = ENXIO;
                    492:                TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries);
                    493:                wakeup(park);
                    494:        }
                    495: }

CVSweb <webmaster@jp.NetBSD.org>