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

Cache object: 6218e0a46c8edaa5fa8a62ef951e81f5


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