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

Cache object: 7a7aef8b6702b82c96067c565a26c2cf


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