[BACK]Return to ufs_extattr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ufs / ufs

Annotation of src/sys/ufs/ufs/ufs_extattr.c, Revision 1.9.4.2

1.9.4.2 ! yamt        1: /*     $NetBSD: ufs_extattr.c,v 1.9.4.1 2006/06/21 15:12:39 yamt Exp $ */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 1999-2002 Robert N. M. Watson
        !             5:  * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This software was developed by Robert Watson for the TrustedBSD Project.
        !             9:  *
        !            10:  * This software was developed for the FreeBSD Project in part by Network
        !            11:  * Associates Laboratories, the Security Research Division of Network
        !            12:  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
        !            13:  * as part of the DARPA CHATS research program.
        !            14:  *
        !            15:  * Redistribution and use in source and binary forms, with or without
        !            16:  * modification, are permitted provided that the following conditions
        !            17:  * are met:
        !            18:  * 1. Redistributions of source code must retain the above copyright
        !            19:  *    notice, this list of conditions and the following disclaimer.
        !            20:  * 2. Redistributions in binary form must reproduce the above copyright
        !            21:  *    notice, this list of conditions and the following disclaimer in the
        !            22:  *    documentation and/or other materials provided with the distribution.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  */
        !            37:
        !            38: /*
        !            39:  * Support for file system extended attributes on the UFS1 file system.
        !            40:  *
        !            41:  * Extended attributes are defined in the form name=value, where name is
        !            42:  * a nul-terminated string in the style of a file name, and value is a
        !            43:  * binary blob of zero or more bytes.  The UFS1 extended attribute service
        !            44:  * layers support for extended attributes onto a backing file, in the style
        !            45:  * of the quota implementation, meaning that it requires no underlying format
        !            46:  * changes to the file system.  This design choice exchanges simplicity,
        !            47:  * usability, and easy deployment for performance.
        !            48:  */
        !            49:
        !            50: #include <sys/cdefs.h>
        !            51: __RCSID("$NetBSD: ufs_extattr.c,v 1.9.4.1 2006/06/21 15:12:39 yamt Exp $");
        !            52:
        !            53: #include "opt_ffs.h"
        !            54:
        !            55: #include <sys/param.h>
        !            56: #include <sys/systm.h>
        !            57: #include <sys/reboot.h>
        !            58: #include <sys/kauth.h>
        !            59: #include <sys/kernel.h>
        !            60: #include <sys/namei.h>
        !            61: #include <sys/malloc.h>
        !            62: #include <sys/fcntl.h>
        !            63: #include <sys/lwp.h>
        !            64: #include <sys/vnode.h>
        !            65: #include <sys/mount.h>
        !            66: #include <sys/lock.h>
        !            67: #include <sys/dirent.h>
        !            68: #include <sys/extattr.h>
        !            69: #include <sys/sysctl.h>
        !            70:
        !            71: #include <ufs/ufs/dir.h>
        !            72: #include <ufs/ufs/extattr.h>
        !            73: #include <ufs/ufs/quota.h>
        !            74: #include <ufs/ufs/ufsmount.h>
        !            75: #include <ufs/ufs/inode.h>
        !            76: #include <ufs/ufs/ufs_bswap.h>
        !            77: #include <ufs/ufs/ufs_extern.h>
        !            78:
        !            79: static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute");
        !            80:
        !            81: int ufs_extattr_sync = 1;
        !            82:
        !            83: static int     ufs_extattr_valid_attrname(int attrnamespace,
        !            84:                    const char *attrname);
        !            85: static int     ufs_extattr_enable_with_open(struct ufsmount *ump,
        !            86:                    struct vnode *vp, int attrnamespace, const char *attrname,
        !            87:                    struct lwp *l);
        !            88: static int     ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
        !            89:                    const char *attrname, struct vnode *backing_vnode,
        !            90:                    struct lwp *l);
        !            91: static int     ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
        !            92:                    const char *attrname, struct lwp *l);
        !            93: static int     ufs_extattr_get(struct vnode *vp, int attrnamespace,
        !            94:                    const char *name, struct uio *uio, size_t *size,
        !            95:                    kauth_cred_t cred, struct lwp *l);
        !            96: static int     ufs_extattr_set(struct vnode *vp, int attrnamespace,
        !            97:                    const char *name, struct uio *uio, kauth_cred_t cred,
        !            98:                    struct lwp *l);
        !            99: static int     ufs_extattr_rm(struct vnode *vp, int attrnamespace,
        !           100:                    const char *name, kauth_cred_t cred, struct lwp *l);
        !           101:
        !           102: /*
        !           103:  * Per-FS attribute lock protecting attribute operations.
        !           104:  * XXX Right now there is a lot of lock contention due to having a single
        !           105:  * lock per-FS; really, this should be far more fine-grained.
        !           106:  */
        !           107: static void
        !           108: ufs_extattr_uepm_lock(struct ufsmount *ump)
        !           109: {
        !           110:
        !           111:        /* Ideally, LK_CANRECURSE would not be used, here. */
        !           112:        lockmgr(&ump->um_extattr.uepm_lock, LK_EXCLUSIVE |
        !           113:            LK_CANRECURSE, NULL);
        !           114: }
        !           115:
        !           116: static void
        !           117: ufs_extattr_uepm_unlock(struct ufsmount *ump)
        !           118: {
        !           119:
        !           120:        lockmgr(&ump->um_extattr.uepm_lock, LK_RELEASE, NULL);
        !           121: }
        !           122:
        !           123: /*-
        !           124:  * Determine whether the name passed is a valid name for an actual
        !           125:  * attribute.
        !           126:  *
        !           127:  * Invalid currently consists of:
        !           128:  *      NULL pointer for attrname
        !           129:  *      zero-length attrname (used to retrieve application attribute list)
        !           130:  */
        !           131: static int
        !           132: ufs_extattr_valid_attrname(int attrnamespace, const char *attrname)
        !           133: {
        !           134:
        !           135:        if (attrname == NULL)
        !           136:                return (0);
        !           137:        if (strlen(attrname) == 0)
        !           138:                return (0);
        !           139:        return (1);
        !           140: }
        !           141:
        !           142: /*
        !           143:  * Locate an attribute given a name and mountpoint.
        !           144:  * Must be holding uepm lock for the mount point.
        !           145:  */
        !           146: static struct ufs_extattr_list_entry *
        !           147: ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace,
        !           148:     const char *attrname)
        !           149: {
        !           150:        struct ufs_extattr_list_entry *search_attribute;
        !           151:
        !           152:        for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list);
        !           153:            search_attribute != NULL;
        !           154:            search_attribute = LIST_NEXT(search_attribute, uele_entries)) {
        !           155:                if (!(strncmp(attrname, search_attribute->uele_attrname,
        !           156:                    UFS_EXTATTR_MAXEXTATTRNAME)) &&
        !           157:                    (attrnamespace == search_attribute->uele_attrnamespace)) {
        !           158:                        return (search_attribute);
        !           159:                }
        !           160:        }
        !           161:
        !           162:        return (0);
        !           163: }
        !           164:
        !           165: /*
        !           166:  * Initialize per-FS structures supporting extended attributes.  Do not
        !           167:  * start extended attributes yet.
        !           168:  */
        !           169: void
        !           170: ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm)
        !           171: {
        !           172:
        !           173:        uepm->uepm_flags = 0;
        !           174:
        !           175:        LIST_INIT(&uepm->uepm_list);
        !           176:        /* XXX is PVFS right, here? */
        !           177:        lockinit(&uepm->uepm_lock, PVFS, "ufsea", 0, 0);
        !           178:        uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED;
        !           179: }
        !           180:
        !           181: /*
        !           182:  * Destroy per-FS structures supporting extended attributes.  Assumes
        !           183:  * that EAs have already been stopped, and will panic if not.
        !           184:  */
        !           185: void
        !           186: ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm)
        !           187: {
        !           188:
        !           189:        if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
        !           190:                panic("ufs_extattr_uepm_destroy: not initialized");
        !           191:
        !           192:        if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED))
        !           193:                panic("ufs_extattr_uepm_destroy: called while still started");
        !           194:
        !           195:        /*
        !           196:         * It's not clear that either order for the next two lines is
        !           197:         * ideal, and it should never be a problem if this is only called
        !           198:         * during unmount, and with vfs_busy().
        !           199:         */
        !           200:        uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED;
        !           201:        lockmgr(&uepm->uepm_lock, LK_DRAIN, NULL);
        !           202: }
        !           203:
        !           204: /*
        !           205:  * Start extended attribute support on an FS.
        !           206:  */
        !           207: int
        !           208: ufs_extattr_start(struct mount *mp, struct lwp *l)
        !           209: {
        !           210:        struct ufsmount *ump;
        !           211:        int error = 0;
        !           212:
        !           213:        ump = VFSTOUFS(mp);
        !           214:
        !           215:        ufs_extattr_uepm_lock(ump);
        !           216:
        !           217:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) {
        !           218:                error = EOPNOTSUPP;
        !           219:                goto unlock;
        !           220:        }
        !           221:        if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) {
        !           222:                error = EBUSY;
        !           223:                goto unlock;
        !           224:        }
        !           225:
        !           226:        ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
        !           227:
        !           228:        ump->um_extattr.uepm_ucred = l->l_proc->p_cred;
        !           229:        kauth_cred_hold(ump->um_extattr.uepm_ucred);
        !           230:
        !           231:  unlock:
        !           232:        ufs_extattr_uepm_unlock(ump);
        !           233:
        !           234:        return (error);
        !           235: }
        !           236:
        !           237: #ifdef UFS_EXTATTR_AUTOSTART
        !           238: /*
        !           239:  * Helper routine: given a locked parent directory and filename, return
        !           240:  * the locked vnode of the inode associated with the name.  Will not
        !           241:  * follow symlinks, may return any type of vnode.  Lock on parent will
        !           242:  * be released even in the event of a failure.  In the event that the
        !           243:  * target is the parent (i.e., "."), there will be two references and
        !           244:  * one lock, requiring the caller to possibly special-case.
        !           245:  */
        !           246: static int
        !           247: ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, const char *dirname,
        !           248:     struct vnode **vp, struct lwp *l)
        !           249: {
        !           250:        struct vop_lookup_args vargs;
        !           251:        struct componentname cnp;
        !           252:        struct vnode *target_vp;
        !           253:        int error;
        !           254:
        !           255:        KASSERT(VOP_ISLOCKED(start_dvp) == LK_EXCLUSIVE);
        !           256:
        !           257:        memset(&cnp, 0, sizeof(cnp));
        !           258:        cnp.cn_nameiop = LOOKUP;
        !           259:        cnp.cn_flags = ISLASTCN | lockparent;
        !           260:        cnp.cn_lwp = l;
        !           261:        cnp.cn_cred = l->l_proc->p_cred;
        !           262:        cnp.cn_pnbuf = PNBUF_GET();
        !           263:        cnp.cn_nameptr = cnp.cn_pnbuf;
        !           264:        error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN,
        !           265:            (size_t *) &cnp.cn_namelen);
        !           266:        if (error) {
        !           267:                if (lockparent == 0) {
        !           268:                        VOP_UNLOCK(start_dvp, 0);
        !           269:                }
        !           270:                PNBUF_PUT(cnp.cn_pnbuf);
        !           271:                printf("ufs_extattr_lookup: copystr failed\n");
        !           272:                return (error);
        !           273:        }
        !           274:        cnp.cn_namelen--;       /* trim nul termination */
        !           275:        vargs.a_desc = NULL;
        !           276:        vargs.a_dvp = start_dvp;
        !           277:        vargs.a_vpp = &target_vp;
        !           278:        vargs.a_cnp = &cnp;
        !           279:        error = ufs_lookup(&vargs);
        !           280:        PNBUF_PUT(cnp.cn_pnbuf);
        !           281:        if (error) {
        !           282:                /*
        !           283:                 * Error condition, may have to release the lock on the parent
        !           284:                 * if ufs_lookup() didn't.
        !           285:                 */
        !           286:                if ((cnp.cn_flags & PDIRUNLOCK) == 0) {
        !           287:                        KASSERT(VOP_ISLOCKED(start_dvp) == LK_EXCLUSIVE);
        !           288:                        if (lockparent == 0)
        !           289:                                VOP_UNLOCK(start_dvp, 0);
        !           290:                }
        !           291:
        !           292:                /*
        !           293:                 * Check that ufs_lookup() didn't release the lock when we
        !           294:                 * didn't want it to.
        !           295:                 */
        !           296:                if ((cnp.cn_flags & PDIRUNLOCK) && lockparent)
        !           297:                        panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK");
        !           298:
        !           299:                return (error);
        !           300:        }
        !           301: #if 0
        !           302:        if (target_vp == start_dvp)
        !           303:                panic("ufs_extattr_lookup: target_vp == start_dvp");
        !           304: #endif
        !           305:
        !           306:        KASSERT(VOP_ISLOCKED(target_vp) == LK_EXCLUSIVE);
        !           307:
        !           308:        if (target_vp != start_dvp &&
        !           309:            (cnp.cn_flags & PDIRUNLOCK) == 0 && lockparent == 0)
        !           310:                panic("ufs_extattr_lookup: !lockparent but !PDIRUNLOCK");
        !           311:
        !           312:        if ((cnp.cn_flags & PDIRUNLOCK) && lockparent)
        !           313:                panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK");
        !           314:
        !           315:        *vp = target_vp;
        !           316:        return (0);
        !           317: }
        !           318: #endif /* !UFS_EXTATTR_AUTOSTART */
        !           319:
        !           320: /*
        !           321:  * Enable an EA using the passed filesystem, backing vnode, attribute name,
        !           322:  * namespace, and proc.  Will perform a VOP_OPEN() on the vp, so expects vp
        !           323:  * to be locked when passed in.  The vnode will be returned unlocked,
        !           324:  * regardless of success/failure of the function.  As a result, the caller
        !           325:  * will always need to vrele(), but not vput().
        !           326:  */
        !           327: static int
        !           328: ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
        !           329:     int attrnamespace, const char *attrname, struct lwp *l)
        !           330: {
        !           331:        int error;
        !           332:
        !           333:        error = VOP_OPEN(vp, FREAD|FWRITE, l->l_proc->p_cred, l);
        !           334:        if (error) {
        !           335:                printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
        !           336:                    "with %d\n", error);
        !           337:                VOP_UNLOCK(vp, 0);
        !           338:                return (error);
        !           339:        }
        !           340:
        !           341:        vp->v_writecount++;
        !           342:
        !           343:        vref(vp);
        !           344:
        !           345:        VOP_UNLOCK(vp, 0);
        !           346:
        !           347:        error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, l);
        !           348:        if (error != 0)
        !           349:                vn_close(vp, FREAD|FWRITE, l->l_proc->p_cred, l);
        !           350:        return (error);
        !           351: }
        !           352:
        !           353: #ifdef UFS_EXTATTR_AUTOSTART
        !           354: /*
        !           355:  * Given a locked directory vnode, iterate over the names in the directory
        !           356:  * and use ufs_extattr_lookup() to retrieve locked vnodes of potential
        !           357:  * attribute files.  Then invoke ufs_extattr_enable_with_open() on each
        !           358:  * to attempt to start the attribute.  Leaves the directory locked on
        !           359:  * exit.
        !           360:  */
        !           361: static int
        !           362: ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
        !           363:     int attrnamespace, struct lwp *l)
        !           364: {
        !           365:        struct vop_readdir_args vargs;
        !           366:        struct dirent *dp, *edp;
        !           367:        struct vnode *attr_vp;
        !           368:        struct uio auio;
        !           369:        struct iovec aiov;
        !           370:        char *dirbuf;
        !           371:        int error, eofflag = 0;
        !           372:
        !           373:        if (dvp->v_type != VDIR)
        !           374:                return (ENOTDIR);
        !           375:
        !           376:        MALLOC(dirbuf, char *, DIRBLKSIZ, M_TEMP, M_WAITOK);
        !           377:
        !           378:        auio.uio_iov = &aiov;
        !           379:        auio.uio_iovcnt = 1;
        !           380:        auio.uio_rw = UIO_READ;
        !           381:        auio.uio_offset = 0;
        !           382:        UIO_SETUP_SYSSPACE(&auio);
        !           383:
        !           384:        vargs.a_desc = NULL;
        !           385:        vargs.a_vp = dvp;
        !           386:        vargs.a_uio = &auio;
        !           387:        vargs.a_cred = l->l_proc->p_cred;
        !           388:        vargs.a_eofflag = &eofflag;
        !           389:        vargs.a_ncookies = NULL;
        !           390:        vargs.a_cookies = NULL;
        !           391:
        !           392:        while (!eofflag) {
        !           393:                auio.uio_resid = DIRBLKSIZ;
        !           394:                aiov.iov_base = dirbuf;
        !           395:                aiov.iov_len = DIRBLKSIZ;
        !           396:                error = ufs_readdir(&vargs);
        !           397:                if (error) {
        !           398:                        printf("ufs_extattr_iterate_directory: ufs_readdir "
        !           399:                            "%d\n", error);
        !           400:                        return (error);
        !           401:                }
        !           402:
        !           403:                /*
        !           404:                 * XXXRW: While in UFS, we always get DIRBLKSIZ returns from
        !           405:                 * the directory code on success, on other file systems this
        !           406:                 * may not be the case.  For portability, we should check the
        !           407:                 * read length on return from ufs_readdir().
        !           408:                 */
        !           409:                edp = (struct dirent *)&dirbuf[DIRBLKSIZ];
        !           410:                for (dp = (struct dirent *)dirbuf; dp < edp; ) {
        !           411:                        if (dp->d_reclen == 0)
        !           412:                                break;
        !           413:                        /* Skip "." and ".." */
        !           414:                        if (dp->d_name[0] == '.' &&
        !           415:                            (dp->d_name[1] == '\0' ||
        !           416:                             (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
        !           417:                                goto next;
        !           418:                        error = ufs_extattr_lookup(dvp, LOCKPARENT,
        !           419:                            dp->d_name, &attr_vp, l);
        !           420:                        if (error) {
        !           421:                                printf("ufs_extattr_iterate_directory: lookup "
        !           422:                                    "%s %d\n", dp->d_name, error);
        !           423:                        } else if (attr_vp == dvp) {
        !           424:                                vrele(attr_vp);
        !           425:                        } else if (attr_vp->v_type != VREG) {
        !           426:                                vput(attr_vp);
        !           427:                        } else {
        !           428:                                error = ufs_extattr_enable_with_open(ump,
        !           429:                                    attr_vp, attrnamespace, dp->d_name, l);
        !           430:                                vrele(attr_vp);
        !           431:                                if (error) {
        !           432:                                        printf("ufs_extattr_iterate_directory: "
        !           433:                                            "enable %s %d\n", dp->d_name,
        !           434:                                            error);
        !           435:                                } else if (1 || bootverbose) {
        !           436:                                        printf("UFS autostarted EA %s\n",
        !           437:                                            dp->d_name);
        !           438:                                }
        !           439:                        }
        !           440:  next:
        !           441:                        dp = (struct dirent *) ((char *)dp + dp->d_reclen);
        !           442:                        if (dp >= edp)
        !           443:                                break;
        !           444:                }
        !           445:        }
        !           446:        FREE(dirbuf, M_TEMP);
        !           447:
        !           448:        return (0);
        !           449: }
        !           450:
        !           451: /*
        !           452:  * Auto-start of extended attributes, to be executed (optionally) at
        !           453:  * mount-time.
        !           454:  */
        !           455: int
        !           456: ufs_extattr_autostart(struct mount *mp, struct lwp *l)
        !           457: {
        !           458:        struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
        !           459:        int error;
        !           460:
        !           461:        /*
        !           462:         * Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root?
        !           463:         * If so, automatically start EA's.
        !           464:         */
        !           465:        error = VFS_ROOT(mp, &rvp);
        !           466:        if (error) {
        !           467:                printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n",
        !           468:                    error);
        !           469:                return (error);
        !           470:        }
        !           471:
        !           472:        KASSERT(VOP_ISLOCKED(rvp) == LK_EXCLUSIVE);
        !           473:
        !           474:        error = ufs_extattr_lookup(rvp, 0,
        !           475:            UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, l);
        !           476:        if (error) {
        !           477:                /* rvp ref'd but now unlocked */
        !           478:                KASSERT(VOP_ISLOCKED(rvp) == 0);
        !           479:                vrele(rvp);
        !           480:                return (error);
        !           481:        }
        !           482:        if (rvp == attr_dvp) {
        !           483:                /* Should never happen. */
        !           484:                KASSERT(VOP_ISLOCKED(rvp) == LK_EXCLUSIVE);
        !           485:                vrele(attr_dvp);
        !           486:                vput(rvp);
        !           487:                return (EINVAL);
        !           488:        }
        !           489:        KASSERT(VOP_ISLOCKED(rvp) == 0);
        !           490:        vrele(rvp);
        !           491:
        !           492:        KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
        !           493:
        !           494:        if (attr_dvp->v_type != VDIR) {
        !           495:                printf("ufs_extattr_autostart: %s != VDIR\n",
        !           496:                    UFS_EXTATTR_FSROOTSUBDIR);
        !           497:                goto return_vput_attr_dvp;
        !           498:        }
        !           499:
        !           500:        error = ufs_extattr_start(mp, l);
        !           501:        if (error) {
        !           502:                printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
        !           503:                    error);
        !           504:                goto return_vput_attr_dvp;
        !           505:        }
        !           506:
        !           507:        /*
        !           508:         * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM,
        !           509:         * UFS_EXTATTR_SUBDIR_USER.  For each, iterate over the sub-directory,
        !           510:         * and start with appropriate type.  Failures in either don't
        !           511:         * result in an over-all failure.  attr_dvp is left locked to
        !           512:         * be cleaned up on exit.
        !           513:         */
        !           514:        error = ufs_extattr_lookup(attr_dvp, LOCKPARENT,
        !           515:            UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, l);
        !           516:        KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
        !           517:        if (error == 0) {
        !           518:                KASSERT(VOP_ISLOCKED(attr_system_dvp) == LK_EXCLUSIVE);
        !           519:                error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
        !           520:                    attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, l);
        !           521:                if (error)
        !           522:                        printf("ufs_extattr_iterate_directory returned %d\n",
        !           523:                            error);
        !           524:                KASSERT(VOP_ISLOCKED(attr_system_dvp) == LK_EXCLUSIVE);
        !           525:                vput(attr_system_dvp);
        !           526:        }
        !           527:
        !           528:        error = ufs_extattr_lookup(attr_dvp, LOCKPARENT,
        !           529:            UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, l);
        !           530:        KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
        !           531:        if (error == 0) {
        !           532:                KASSERT(VOP_ISLOCKED(attr_user_dvp) == LK_EXCLUSIVE);
        !           533:                error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
        !           534:                    attr_user_dvp, EXTATTR_NAMESPACE_USER, l);
        !           535:                if (error)
        !           536:                        printf("ufs_extattr_iterate_directory returned %d\n",
        !           537:                            error);
        !           538:                KASSERT(VOP_ISLOCKED(attr_user_dvp) == LK_EXCLUSIVE);
        !           539:                vput(attr_user_dvp);
        !           540:        }
        !           541:
        !           542:        /* Mask startup failures in sub-directories. */
        !           543:        error = 0;
        !           544:
        !           545:  return_vput_attr_dvp:
        !           546:        KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
        !           547:        vput(attr_dvp);
        !           548:
        !           549:        return (error);
        !           550: }
        !           551: #endif /* !UFS_EXTATTR_AUTOSTART */
        !           552:
        !           553: /*
        !           554:  * Stop extended attribute support on an FS.
        !           555:  */
        !           556: int
        !           557: ufs_extattr_stop(struct mount *mp, struct lwp *l)
        !           558: {
        !           559:        struct ufs_extattr_list_entry *uele;
        !           560:        struct ufsmount *ump = VFSTOUFS(mp);
        !           561:        int error = 0;
        !           562:
        !           563:        ufs_extattr_uepm_lock(ump);
        !           564:
        !           565:        /*
        !           566:         * If we haven't been started, no big deal.  Just short-circuit
        !           567:         * the processing work.
        !           568:         */
        !           569:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
        !           570:                error = EOPNOTSUPP;
        !           571:                goto unlock;
        !           572:        }
        !           573:
        !           574:        while (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) {
        !           575:                uele = LIST_FIRST(&ump->um_extattr.uepm_list);
        !           576:                ufs_extattr_disable(ump, uele->uele_attrnamespace,
        !           577:                    uele->uele_attrname, l);
        !           578:        }
        !           579:
        !           580:        ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
        !           581:
        !           582:        kauth_cred_free(ump->um_extattr.uepm_ucred);
        !           583:        ump->um_extattr.uepm_ucred = NULL;
        !           584:
        !           585:  unlock:
        !           586:        ufs_extattr_uepm_unlock(ump);
        !           587:
        !           588:        return (error);
        !           589: }
        !           590:
        !           591: /*
        !           592:  * Enable a named attribute on the specified filesystem; provide an
        !           593:  * unlocked backing vnode to hold the attribute data.
        !           594:  */
        !           595: static int
        !           596: ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
        !           597:     const char *attrname, struct vnode *backing_vnode, struct lwp *l)
        !           598: {
        !           599:        struct ufs_extattr_list_entry *attribute;
        !           600:        struct iovec aiov;
        !           601:        struct uio auio;
        !           602:        int error = 0;
        !           603:
        !           604:        if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
        !           605:                return (EINVAL);
        !           606:        if (backing_vnode->v_type != VREG)
        !           607:                return (EINVAL);
        !           608:
        !           609:        attribute = malloc(sizeof(*attribute), M_UFS_EXTATTR,
        !           610:            M_WAITOK | M_ZERO);
        !           611:
        !           612:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
        !           613:                error = EOPNOTSUPP;
        !           614:                goto free_exit;
        !           615:        }
        !           616:
        !           617:        if (ufs_extattr_find_attr(ump, attrnamespace, attrname)) {
        !           618:                error = EEXIST;
        !           619:                goto free_exit;
        !           620:        }
        !           621:
        !           622:        strncpy(attribute->uele_attrname, attrname,
        !           623:            UFS_EXTATTR_MAXEXTATTRNAME);
        !           624:        attribute->uele_attrnamespace = attrnamespace;
        !           625:        bzero(&attribute->uele_fileheader,
        !           626:            sizeof(struct ufs_extattr_fileheader));
        !           627:
        !           628:        attribute->uele_backing_vnode = backing_vnode;
        !           629:
        !           630:        auio.uio_iov = &aiov;
        !           631:        auio.uio_iovcnt = 1;
        !           632:        aiov.iov_base = (caddr_t) &attribute->uele_fileheader;
        !           633:        aiov.iov_len = sizeof(struct ufs_extattr_fileheader);
        !           634:        auio.uio_resid = sizeof(struct ufs_extattr_fileheader);
        !           635:        auio.uio_offset = (off_t) 0;
        !           636:        auio.uio_rw = UIO_READ;
        !           637:        UIO_SETUP_SYSSPACE(&auio);
        !           638:
        !           639:        VOP_LEASE(backing_vnode, l, l->l_proc->p_cred, LEASE_WRITE);
        !           640:        vn_lock(backing_vnode, LK_SHARED | LK_RETRY);
        !           641:        error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED,
        !           642:            ump->um_extattr.uepm_ucred);
        !           643:
        !           644:        if (error)
        !           645:                goto unlock_free_exit;
        !           646:
        !           647:        if (auio.uio_resid != 0) {
        !           648:                printf("ufs_extattr_enable: malformed attribute header\n");
        !           649:                error = EINVAL;
        !           650:                goto unlock_free_exit;
        !           651:        }
        !           652:
        !           653:        /*
        !           654:         * Try to determine the byte order of the attribute file.
        !           655:         */
        !           656:        if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
        !           657:                attribute->uele_flags |= UELE_F_NEEDSWAP;
        !           658:                attribute->uele_fileheader.uef_magic =
        !           659:                    ufs_rw32(attribute->uele_fileheader.uef_magic,
        !           660:                             UELE_NEEDSWAP(attribute));
        !           661:                if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
        !           662:                        printf("ufs_extattr_enable: invalid attribute header "
        !           663:                               "magic\n");
        !           664:                        error = EINVAL;
        !           665:                        goto unlock_free_exit;
        !           666:                }
        !           667:        }
        !           668:        attribute->uele_fileheader.uef_version =
        !           669:            ufs_rw32(attribute->uele_fileheader.uef_version,
        !           670:                     UELE_NEEDSWAP(attribute));
        !           671:        attribute->uele_fileheader.uef_size =
        !           672:            ufs_rw32(attribute->uele_fileheader.uef_size,
        !           673:                     UELE_NEEDSWAP(attribute));
        !           674:
        !           675:        if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) {
        !           676:                printf("ufs_extattr_enable: incorrect attribute header "
        !           677:                    "version\n");
        !           678:                error = EINVAL;
        !           679:                goto unlock_free_exit;
        !           680:        }
        !           681:
        !           682:        LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute,
        !           683:            uele_entries);
        !           684:
        !           685:        VOP_UNLOCK(backing_vnode, 0);
        !           686:        return (0);
        !           687:
        !           688:  unlock_free_exit:
        !           689:        VOP_UNLOCK(backing_vnode, 0);
        !           690:
        !           691:  free_exit:
        !           692:        free(attribute, M_UFS_EXTATTR);
        !           693:        return (error);
        !           694: }
        !           695:
        !           696: /*
        !           697:  * Disable extended attribute support on an FS.
        !           698:  */
        !           699: static int
        !           700: ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
        !           701:     const char *attrname, struct lwp *l)
        !           702: {
        !           703:        struct ufs_extattr_list_entry *uele;
        !           704:        int error = 0;
        !           705:
        !           706:        if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
        !           707:                return (EINVAL);
        !           708:
        !           709:        uele = ufs_extattr_find_attr(ump, attrnamespace, attrname);
        !           710:        if (!uele)
        !           711:                return (ENOATTR);
        !           712:
        !           713:        LIST_REMOVE(uele, uele_entries);
        !           714:
        !           715:        error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE,
        !           716:            l->l_proc->p_cred, l);
        !           717:
        !           718:        free(uele, M_UFS_EXTATTR);
        !           719:
        !           720:        return (error);
        !           721: }
        !           722:
        !           723: /*
        !           724:  * VFS call to manage extended attributes in UFS.  If filename_vp is
        !           725:  * non-NULL, it must be passed in locked, and regardless of errors in
        !           726:  * processing, will be unlocked.
        !           727:  */
        !           728: int
        !           729: ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
        !           730:     int attrnamespace, const char *attrname, struct lwp *l)
        !           731: {
        !           732:        struct ufsmount *ump = VFSTOUFS(mp);
        !           733:        int error;
        !           734:
        !           735:        /*
        !           736:         * Only privileged processes can configure extended attributes.
        !           737:         */
        !           738:        if ((error = kauth_authorize_generic(l->l_proc->p_cred, KAUTH_GENERIC_ISSUSER,
        !           739:                                       &l->l_proc->p_acflag)) != 0) {
        !           740:                if (filename_vp != NULL)
        !           741:                        VOP_UNLOCK(filename_vp, 0);
        !           742:                return (error);
        !           743:        }
        !           744:
        !           745:        switch(cmd) {
        !           746:        case UFS_EXTATTR_CMD_START:
        !           747:                if (filename_vp != NULL) {
        !           748:                        VOP_UNLOCK(filename_vp, 0);
        !           749:                        return (EINVAL);
        !           750:                }
        !           751:                if (attrname != NULL)
        !           752:                        return (EINVAL);
        !           753:
        !           754:                error = ufs_extattr_start(mp, l);
        !           755:                return (error);
        !           756:
        !           757:        case UFS_EXTATTR_CMD_STOP:
        !           758:                if (filename_vp != NULL) {
        !           759:                        VOP_UNLOCK(filename_vp, 0);
        !           760:                        return (EINVAL);
        !           761:                }
        !           762:                if (attrname != NULL)
        !           763:                        return (EINVAL);
        !           764:
        !           765:                error = ufs_extattr_stop(mp, l);
        !           766:                return (error);
        !           767:
        !           768:        case UFS_EXTATTR_CMD_ENABLE:
        !           769:                if (filename_vp == NULL)
        !           770:                        return (EINVAL);
        !           771:                if (attrname == NULL) {
        !           772:                        VOP_UNLOCK(filename_vp, 0);
        !           773:                        return (EINVAL);
        !           774:                }
        !           775:
        !           776:                /*
        !           777:                 * ufs_extattr_enable_with_open() will always unlock the
        !           778:                 * vnode, regardless of failure.
        !           779:                 */
        !           780:                ufs_extattr_uepm_lock(ump);
        !           781:                error = ufs_extattr_enable_with_open(ump, filename_vp,
        !           782:                    attrnamespace, attrname, l);
        !           783:                ufs_extattr_uepm_unlock(ump);
        !           784:                return (error);
        !           785:
        !           786:        case UFS_EXTATTR_CMD_DISABLE:
        !           787:                if (filename_vp != NULL) {
        !           788:                        VOP_UNLOCK(filename_vp, 0);
        !           789:                        return (EINVAL);
        !           790:                }
        !           791:                if (attrname == NULL)
        !           792:                        return (EINVAL);
        !           793:
        !           794:                ufs_extattr_uepm_lock(ump);
        !           795:                error = ufs_extattr_disable(ump, attrnamespace, attrname, l);
        !           796:                ufs_extattr_uepm_unlock(ump);
        !           797:                return (error);
        !           798:
        !           799:        default:
        !           800:                return (EINVAL);
        !           801:        }
        !           802: }
        !           803:
        !           804: /*
        !           805:  * Vnode operation to retrieve a named extended attribute.
        !           806:  */
        !           807: int
        !           808: ufs_getextattr(struct vop_getextattr_args *ap)
        !           809: /*
        !           810: vop_getextattr {
        !           811:        IN struct vnode *a_vp;
        !           812:        IN int a_attrnamespace;
        !           813:        IN const char *a_name;
        !           814:        INOUT struct uio *a_uio;
        !           815:        OUT size_t *a_size;
        !           816:        IN kauth_cred_t a_cred;
        !           817:        IN struct lwp *a_l;
        !           818: };
        !           819: */
        !           820: {
        !           821:        struct mount *mp = ap->a_vp->v_mount;
        !           822:        struct ufsmount *ump = VFSTOUFS(mp);
        !           823:        int error;
        !           824:
        !           825:        ufs_extattr_uepm_lock(ump);
        !           826:
        !           827:        error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name,
        !           828:            ap->a_uio, ap->a_size, ap->a_cred, ap->a_l);
        !           829:
        !           830:        ufs_extattr_uepm_unlock(ump);
        !           831:
        !           832:        return (error);
        !           833: }
        !           834:
        !           835: /*
        !           836:  * Real work associated with retrieving a named attribute--assumes that
        !           837:  * the attribute lock has already been grabbed.
        !           838:  */
        !           839: static int
        !           840: ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
        !           841:     struct uio *uio, size_t *size, kauth_cred_t cred, struct lwp *l)
        !           842: {
        !           843:        struct ufs_extattr_list_entry *attribute;
        !           844:        struct ufs_extattr_header ueh;
        !           845:        struct iovec local_aiov;
        !           846:        struct uio local_aio;
        !           847:        struct mount *mp = vp->v_mount;
        !           848:        struct ufsmount *ump = VFSTOUFS(mp);
        !           849:        struct inode *ip = VTOI(vp);
        !           850:        off_t base_offset;
        !           851:        size_t len, old_len;
        !           852:        int error = 0;
        !           853:
        !           854:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
        !           855:                return (EOPNOTSUPP);
        !           856:
        !           857:        if (strlen(name) == 0)
        !           858:                return (EINVAL);
        !           859:
        !           860:        error = extattr_check_cred(vp, attrnamespace, cred, l, IREAD);
        !           861:        if (error)
        !           862:                return (error);
        !           863:
        !           864:        attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
        !           865:        if (!attribute)
        !           866:                return (ENOATTR);
        !           867:
        !           868:        /*
        !           869:         * Allow only offsets of zero to encourage the read/replace
        !           870:         * extended attribute semantic.  Otherwise we can't guarantee
        !           871:         * atomicity, as we don't provide locks for extended attributes.
        !           872:         */
        !           873:        if (uio != NULL && uio->uio_offset != 0)
        !           874:                return (ENXIO);
        !           875:
        !           876:        /*
        !           877:         * Find base offset of header in file based on file header size, and
        !           878:         * data header size + maximum data size, indexed by inode number.
        !           879:         */
        !           880:        base_offset = sizeof(struct ufs_extattr_fileheader) +
        !           881:            ip->i_number * (sizeof(struct ufs_extattr_header) +
        !           882:            attribute->uele_fileheader.uef_size);
        !           883:
        !           884:        /*
        !           885:         * Read in the data header to see if the data is defined, and if so
        !           886:         * how much.
        !           887:         */
        !           888:        memset(&ueh, 0, sizeof(struct ufs_extattr_header));
        !           889:        local_aiov.iov_base = &ueh;
        !           890:        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
        !           891:        local_aio.uio_iov = &local_aiov;
        !           892:        local_aio.uio_iovcnt = 1;
        !           893:        local_aio.uio_rw = UIO_READ;
        !           894:        local_aio.uio_offset = base_offset;
        !           895:        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
        !           896:        UIO_SETUP_SYSSPACE(&local_aio);
        !           897:
        !           898:        /*
        !           899:         * Acquire locks.
        !           900:         */
        !           901:        VOP_LEASE(attribute->uele_backing_vnode, l, cred, LEASE_READ);
        !           902:        /*
        !           903:         * Don't need to get a lock on the backing file if the getattr is
        !           904:         * being applied to the backing file, as the lock is already held.
        !           905:         */
        !           906:        if (attribute->uele_backing_vnode != vp)
        !           907:                vn_lock(attribute->uele_backing_vnode, LK_SHARED |
        !           908:                    LK_RETRY);
        !           909:
        !           910:        error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
        !           911:            IO_NODELOCKED, ump->um_extattr.uepm_ucred);
        !           912:        if (error)
        !           913:                goto vopunlock_exit;
        !           914:
        !           915:        /*
        !           916:         * Attribute headers are kept in file system byte order.
        !           917:         * XXX What about the blob of data?
        !           918:         */
        !           919:        ueh.ueh_flags = ufs_rw32(ueh.ueh_flags, UELE_NEEDSWAP(attribute));
        !           920:        ueh.ueh_len   = ufs_rw32(ueh.ueh_len, UELE_NEEDSWAP(attribute));
        !           921:        ueh.ueh_i_gen = ufs_rw32(ueh.ueh_i_gen, UELE_NEEDSWAP(attribute));
        !           922:
        !           923:        /* Defined? */
        !           924:        if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
        !           925:                error = ENOATTR;
        !           926:                goto vopunlock_exit;
        !           927:        }
        !           928:
        !           929:        /* Valid for the current inode generation? */
        !           930:        if (ueh.ueh_i_gen != ip->i_gen) {
        !           931:                /*
        !           932:                 * The inode itself has a different generation number
        !           933:                 * than the attribute data.  For now, the best solution
        !           934:                 * is to coerce this to undefined, and let it get cleaned
        !           935:                 * up by the next write or extattrctl clean.
        !           936:                 */
        !           937:                printf("ufs_extattr_get (%s): inode gen inconsistency (%u, %jd)\n",
        !           938:                    mp->mnt_stat.f_mntonname, ueh.ueh_i_gen,
        !           939:                    (intmax_t)ip->i_gen);
        !           940:                error = ENOATTR;
        !           941:                goto vopunlock_exit;
        !           942:        }
        !           943:
        !           944:        /* Local size consistency check. */
        !           945:        if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
        !           946:                error = ENXIO;
        !           947:                goto vopunlock_exit;
        !           948:        }
        !           949:
        !           950:        /* Return full data size if caller requested it. */
        !           951:        if (size != NULL)
        !           952:                *size = ueh.ueh_len;
        !           953:
        !           954:        /* Return data if the caller requested it. */
        !           955:        if (uio != NULL) {
        !           956:                /* Allow for offset into the attribute data. */
        !           957:                uio->uio_offset = base_offset + sizeof(struct
        !           958:                    ufs_extattr_header);
        !           959:
        !           960:                /*
        !           961:                 * Figure out maximum to transfer -- use buffer size and
        !           962:                 * local data limit.
        !           963:                 */
        !           964:                len = MIN(uio->uio_resid, ueh.ueh_len);
        !           965:                old_len = uio->uio_resid;
        !           966:                uio->uio_resid = len;
        !           967:
        !           968:                error = VOP_READ(attribute->uele_backing_vnode, uio,
        !           969:                    IO_NODELOCKED, ump->um_extattr.uepm_ucred);
        !           970:                if (error)
        !           971:                        goto vopunlock_exit;
        !           972:
        !           973:                uio->uio_resid = old_len - (len - uio->uio_resid);
        !           974:        }
        !           975:
        !           976:  vopunlock_exit:
        !           977:
        !           978:        if (uio != NULL)
        !           979:                uio->uio_offset = 0;
        !           980:
        !           981:        if (attribute->uele_backing_vnode != vp)
        !           982:                VOP_UNLOCK(attribute->uele_backing_vnode, 0);
        !           983:
        !           984:        return (error);
        !           985: }
        !           986:
        !           987: /*
        !           988:  * Vnode operation to remove a named attribute.
        !           989:  */
        !           990: int
        !           991: ufs_deleteextattr(struct vop_deleteextattr_args *ap)
        !           992: /*
        !           993: vop_deleteextattr {
        !           994:        IN struct vnode *a_vp;
        !           995:        IN int a_attrnamespace;
        !           996:        IN const char *a_name;
        !           997:        IN kauth_cred_t a_cred;
        !           998:        IN struct lwp *a_l;
        !           999: };
        !          1000: */
        !          1001: {
        !          1002:        struct mount *mp = ap->a_vp->v_mount;
        !          1003:        struct ufsmount *ump = VFSTOUFS(mp);
        !          1004:        int error;
        !          1005:
        !          1006:        ufs_extattr_uepm_lock(ump);
        !          1007:
        !          1008:        error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, ap->a_name,
        !          1009:            ap->a_cred, ap->a_l);
        !          1010:
        !          1011:        ufs_extattr_uepm_unlock(ump);
        !          1012:
        !          1013:        return (error);
        !          1014: }
        !          1015:
        !          1016: /*
        !          1017:  * Vnode operation to set a named attribute.
        !          1018:  */
        !          1019: int
        !          1020: ufs_setextattr(struct vop_setextattr_args *ap)
        !          1021: /*
        !          1022: vop_setextattr {
        !          1023:        IN struct vnode *a_vp;
        !          1024:        IN int a_attrnamespace;
        !          1025:        IN const char *a_name;
        !          1026:        INOUT struct uio *a_uio;
        !          1027:        IN kauth_cred_t a_cred;
        !          1028:        IN struct lwp *a_l;
        !          1029: };
        !          1030: */
        !          1031: {
        !          1032:        struct mount *mp = ap->a_vp->v_mount;
        !          1033:        struct ufsmount *ump = VFSTOUFS(mp);
        !          1034:        int error;
        !          1035:
        !          1036:        ufs_extattr_uepm_lock(ump);
        !          1037:
        !          1038:        /*
        !          1039:         * XXX: No longer a supported way to delete extended attributes.
        !          1040:         */
        !          1041:        if (ap->a_uio == NULL)
        !          1042:                return (EINVAL);
        !          1043:
        !          1044:        error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name,
        !          1045:            ap->a_uio, ap->a_cred, ap->a_l);
        !          1046:
        !          1047:        ufs_extattr_uepm_unlock(ump);
        !          1048:
        !          1049:        return (error);
        !          1050: }
        !          1051:
        !          1052: /*
        !          1053:  * Real work associated with setting a vnode's extended attributes;
        !          1054:  * assumes that the attribute lock has already been grabbed.
        !          1055:  */
        !          1056: static int
        !          1057: ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
        !          1058:     struct uio *uio, kauth_cred_t cred, struct lwp *l)
        !          1059: {
        !          1060:        struct ufs_extattr_list_entry *attribute;
        !          1061:        struct ufs_extattr_header ueh;
        !          1062:        struct iovec local_aiov;
        !          1063:        struct uio local_aio;
        !          1064:        struct mount *mp = vp->v_mount;
        !          1065:        struct ufsmount *ump = VFSTOUFS(mp);
        !          1066:        struct inode *ip = VTOI(vp);
        !          1067:        off_t base_offset;
        !          1068:        int error = 0, ioflag;
        !          1069:
        !          1070:        if (vp->v_mount->mnt_flag & MNT_RDONLY)
        !          1071:                return (EROFS);
        !          1072:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
        !          1073:                return (EOPNOTSUPP);
        !          1074:        if (!ufs_extattr_valid_attrname(attrnamespace, name))
        !          1075:                return (EINVAL);
        !          1076:
        !          1077:        error = extattr_check_cred(vp, attrnamespace, cred, l, IWRITE);
        !          1078:        if (error)
        !          1079:                return (error);
        !          1080:
        !          1081:        attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
        !          1082:        if (!attribute)
        !          1083:                return (ENOATTR);
        !          1084:
        !          1085:        /*
        !          1086:         * Early rejection of invalid offsets/length.
        !          1087:         * Reject: any offset but 0 (replace)
        !          1088:         *       Any size greater than attribute size limit
        !          1089:         */
        !          1090:        if (uio->uio_offset != 0 ||
        !          1091:            uio->uio_resid > attribute->uele_fileheader.uef_size)
        !          1092:                return (ENXIO);
        !          1093:
        !          1094:        /*
        !          1095:         * Find base offset of header in file based on file header size, and
        !          1096:         * data header size + maximum data size, indexed by inode number.
        !          1097:         */
        !          1098:        base_offset = sizeof(struct ufs_extattr_fileheader) +
        !          1099:            ip->i_number * (sizeof(struct ufs_extattr_header) +
        !          1100:            attribute->uele_fileheader.uef_size);
        !          1101:
        !          1102:        /*
        !          1103:         * Write out a data header for the data.
        !          1104:         */
        !          1105:        ueh.ueh_len = ufs_rw32((uint32_t) uio->uio_resid,
        !          1106:            UELE_NEEDSWAP(attribute));
        !          1107:        ueh.ueh_flags = ufs_rw32(UFS_EXTATTR_ATTR_FLAG_INUSE,
        !          1108:                                 UELE_NEEDSWAP(attribute));
        !          1109:        ueh.ueh_i_gen = ufs_rw32(ip->i_gen, UELE_NEEDSWAP(attribute));
        !          1110:        local_aiov.iov_base = &ueh;
        !          1111:        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
        !          1112:        local_aio.uio_iov = &local_aiov;
        !          1113:        local_aio.uio_iovcnt = 1;
        !          1114:        local_aio.uio_rw = UIO_WRITE;
        !          1115:        local_aio.uio_offset = base_offset;
        !          1116:        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
        !          1117:        UIO_SETUP_SYSSPACE(&local_aio);
        !          1118:
        !          1119:        /*
        !          1120:         * Acquire locks.
        !          1121:         */
        !          1122:        VOP_LEASE(attribute->uele_backing_vnode, l, cred, LEASE_WRITE);
        !          1123:
        !          1124:        /*
        !          1125:         * Don't need to get a lock on the backing file if the setattr is
        !          1126:         * being applied to the backing file, as the lock is already held.
        !          1127:         */
        !          1128:        if (attribute->uele_backing_vnode != vp)
        !          1129:                vn_lock(attribute->uele_backing_vnode,
        !          1130:                    LK_EXCLUSIVE | LK_RETRY);
        !          1131:
        !          1132:        ioflag = IO_NODELOCKED;
        !          1133:        if (ufs_extattr_sync)
        !          1134:                ioflag |= IO_SYNC;
        !          1135:        error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
        !          1136:            ump->um_extattr.uepm_ucred);
        !          1137:        if (error)
        !          1138:                goto vopunlock_exit;
        !          1139:
        !          1140:        if (local_aio.uio_resid != 0) {
        !          1141:                error = ENXIO;
        !          1142:                goto vopunlock_exit;
        !          1143:        }
        !          1144:
        !          1145:        /*
        !          1146:         * Write out user data.
        !          1147:         * XXX NOT ATOMIC WITH RESPECT TO THE HEADER.
        !          1148:         */
        !          1149:        uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
        !          1150:
        !          1151:        ioflag = IO_NODELOCKED;
        !          1152:        if (ufs_extattr_sync)
        !          1153:                ioflag |= IO_SYNC;
        !          1154:        error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
        !          1155:            ump->um_extattr.uepm_ucred);
        !          1156:
        !          1157:  vopunlock_exit:
        !          1158:        uio->uio_offset = 0;
        !          1159:
        !          1160:        if (attribute->uele_backing_vnode != vp)
        !          1161:                VOP_UNLOCK(attribute->uele_backing_vnode, 0);
        !          1162:
        !          1163:        return (error);
        !          1164: }
        !          1165:
        !          1166: /*
        !          1167:  * Real work associated with removing an extended attribute from a vnode.
        !          1168:  * Assumes the attribute lock has already been grabbed.
        !          1169:  */
        !          1170: static int
        !          1171: ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
        !          1172:     kauth_cred_t cred, struct lwp *l)
        !          1173: {
        !          1174:        struct ufs_extattr_list_entry *attribute;
        !          1175:        struct ufs_extattr_header ueh;
        !          1176:        struct iovec local_aiov;
        !          1177:        struct uio local_aio;
        !          1178:        struct mount *mp = vp->v_mount;
        !          1179:        struct ufsmount *ump = VFSTOUFS(mp);
        !          1180:        struct inode *ip = VTOI(vp);
        !          1181:        off_t base_offset;
        !          1182:        int error = 0, ioflag;
        !          1183:
        !          1184:        if (vp->v_mount->mnt_flag & MNT_RDONLY)
        !          1185:                return (EROFS);
        !          1186:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
        !          1187:                return (EOPNOTSUPP);
        !          1188:        if (!ufs_extattr_valid_attrname(attrnamespace, name))
        !          1189:                return (EINVAL);
        !          1190:
        !          1191:        error = extattr_check_cred(vp, attrnamespace, cred, l, IWRITE);
        !          1192:        if (error)
        !          1193:                return (error);
        !          1194:
        !          1195:        attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
        !          1196:        if (!attribute)
        !          1197:                return (ENOATTR);
        !          1198:
        !          1199:        /*
        !          1200:         * Find base offset of header in file based on file header size, and
        !          1201:         * data header size + maximum data size, indexed by inode number.
        !          1202:         */
        !          1203:        base_offset = sizeof(struct ufs_extattr_fileheader) +
        !          1204:            ip->i_number * (sizeof(struct ufs_extattr_header) +
        !          1205:            attribute->uele_fileheader.uef_size);
        !          1206:
        !          1207:        /*
        !          1208:         * Check to see if currently defined.
        !          1209:         */
        !          1210:        memset(&ueh, 0, sizeof(struct ufs_extattr_header));
        !          1211:
        !          1212:        local_aiov.iov_base = &ueh;
        !          1213:        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
        !          1214:        local_aio.uio_iov = &local_aiov;
        !          1215:        local_aio.uio_iovcnt = 1;
        !          1216:        local_aio.uio_rw = UIO_READ;
        !          1217:        local_aio.uio_offset = base_offset;
        !          1218:        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
        !          1219:        UIO_SETUP_SYSSPACE(&local_aio);
        !          1220:
        !          1221:        VOP_LEASE(attribute->uele_backing_vnode, l, cred, LEASE_WRITE);
        !          1222:
        !          1223:        /*
        !          1224:         * Don't need to get the lock on the backing vnode if the vnode we're
        !          1225:         * modifying is it, as we already hold the lock.
        !          1226:         */
        !          1227:        if (attribute->uele_backing_vnode != vp)
        !          1228:                vn_lock(attribute->uele_backing_vnode,
        !          1229:                    LK_EXCLUSIVE | LK_RETRY);
        !          1230:
        !          1231:        error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
        !          1232:            IO_NODELOCKED, ump->um_extattr.uepm_ucred);
        !          1233:        if (error)
        !          1234:                goto vopunlock_exit;
        !          1235:
        !          1236:        /*
        !          1237:         * Attribute headers are kept in file system byte order.
        !          1238:         */
        !          1239:        ueh.ueh_flags = ufs_rw32(ueh.ueh_flags, UELE_NEEDSWAP(attribute));
        !          1240:        ueh.ueh_len   = ufs_rw32(ueh.ueh_len, UELE_NEEDSWAP(attribute));
        !          1241:        ueh.ueh_i_gen = ufs_rw32(ueh.ueh_i_gen, UELE_NEEDSWAP(attribute));
        !          1242:
        !          1243:        /* Defined? */
        !          1244:        if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
        !          1245:                error = ENOATTR;
        !          1246:                goto vopunlock_exit;
        !          1247:        }
        !          1248:
        !          1249:        /* Valid for the current inode generation? */
        !          1250:        if (ueh.ueh_i_gen != ip->i_gen) {
        !          1251:                /*
        !          1252:                 * The inode itself has a different generation number than
        !          1253:                 * the attribute data.  For now, the best solution is to
        !          1254:                 * coerce this to undefined, and let it get cleaned up by
        !          1255:                 * the next write or extattrctl clean.
        !          1256:                 */
        !          1257:                printf("ufs_extattr_rm (%s): inode number inconsistency (%u, %jd)\n",
        !          1258:                    mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
        !          1259:                error = ENOATTR;
        !          1260:                goto vopunlock_exit;
        !          1261:        }
        !          1262:
        !          1263:        /* Flag it as not in use. */
        !          1264:        ueh.ueh_flags = 0;              /* No need to byte swap 0 */
        !          1265:        ueh.ueh_len = 0;                /* ...ditto... */
        !          1266:
        !          1267:        local_aiov.iov_base = &ueh;
        !          1268:        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
        !          1269:        local_aio.uio_iov = &local_aiov;
        !          1270:        local_aio.uio_iovcnt = 1;
        !          1271:        local_aio.uio_rw = UIO_WRITE;
        !          1272:        local_aio.uio_offset = base_offset;
        !          1273:        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
        !          1274:        UIO_SETUP_SYSSPACE(&local_aio);
        !          1275:
        !          1276:        ioflag = IO_NODELOCKED;
        !          1277:        if (ufs_extattr_sync)
        !          1278:                ioflag |= IO_SYNC;
        !          1279:        error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
        !          1280:            ump->um_extattr.uepm_ucred);
        !          1281:        if (error)
        !          1282:                goto vopunlock_exit;
        !          1283:
        !          1284:        if (local_aio.uio_resid != 0)
        !          1285:                error = ENXIO;
        !          1286:
        !          1287:  vopunlock_exit:
        !          1288:        VOP_UNLOCK(attribute->uele_backing_vnode, 0);
        !          1289:
        !          1290:        return (error);
        !          1291: }
        !          1292:
        !          1293: /*
        !          1294:  * Called by UFS when an inode is no longer active and should have its
        !          1295:  * attributes stripped.
        !          1296:  */
        !          1297: void
        !          1298: ufs_extattr_vnode_inactive(struct vnode *vp, struct lwp *l)
        !          1299: {
        !          1300:        struct ufs_extattr_list_entry *uele;
        !          1301:        struct mount *mp = vp->v_mount;
        !          1302:        struct ufsmount *ump = VFSTOUFS(mp);
        !          1303:
        !          1304:        /*
        !          1305:         * In that case, we cannot lock. We should not have any active vnodes
        !          1306:         * on the fs if this is not yet initialized but is going to be, so
        !          1307:         * this can go unlocked.
        !          1308:         */
        !          1309:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
        !          1310:                return;
        !          1311:
        !          1312:        ufs_extattr_uepm_lock(ump);
        !          1313:
        !          1314:        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
        !          1315:                ufs_extattr_uepm_unlock(ump);
        !          1316:                return;
        !          1317:        }
        !          1318:
        !          1319:        LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
        !          1320:                ufs_extattr_rm(vp, uele->uele_attrnamespace,
        !          1321:                    uele->uele_attrname, proc0.p_cred, l);
        !          1322:
        !          1323:        ufs_extattr_uepm_unlock(ump);
        !          1324: }

CVSweb <webmaster@jp.NetBSD.org>