The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ufs/ufs/ufs_extattr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 78d33a2f52e2f66b9f485d923ec0d40b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.