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/fs/ext2fs/ext2_extattr.c

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

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2017, Fedor Uporov
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD: releng/12.0/sys/fs/ext2fs/ext2_extattr.c 327977 2018-01-14 20:46:39Z fsu $
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/types.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/vnode.h>
   37 #include <sys/bio.h>
   38 #include <sys/buf.h>
   39 #include <sys/endian.h>
   40 #include <sys/conf.h>
   41 #include <sys/extattr.h>
   42 
   43 #include <fs/ext2fs/fs.h>
   44 #include <fs/ext2fs/ext2fs.h>
   45 #include <fs/ext2fs/inode.h>
   46 #include <fs/ext2fs/ext2_dinode.h>
   47 #include <fs/ext2fs/ext2_mount.h>
   48 #include <fs/ext2fs/ext2_extattr.h>
   49 #include <fs/ext2fs/ext2_extern.h>
   50 
   51 static int
   52 ext2_extattr_attrnamespace_to_bsd(int attrnamespace)
   53 {
   54 
   55         switch (attrnamespace) {
   56         case EXT4_XATTR_INDEX_SYSTEM:
   57                 return (EXTATTR_NAMESPACE_SYSTEM);
   58 
   59         case EXT4_XATTR_INDEX_USER:
   60                 return (EXTATTR_NAMESPACE_USER);
   61 
   62         case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT:
   63                 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE);
   64 
   65         case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS:
   66                 return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE);
   67         }
   68 
   69         return (EXTATTR_NAMESPACE_EMPTY);
   70 }
   71 
   72 static const char *
   73 ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len)
   74 {
   75 
   76         if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM)
   77                 return (name);
   78         else if (attrnamespace == EXT4_XATTR_INDEX_USER)
   79                 return (name);
   80         else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) {
   81                 *name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
   82                 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
   83         } else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) {
   84                 *name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME);
   85                 return (POSIX1E_ACL_ACCESS_EXTATTR_NAME);
   86         }
   87 
   88         /*
   89          * XXX: Not all linux namespaces are mapped to bsd for now,
   90          * return NULL, which will be converted to ENOTSUP on upper layer.
   91          */
   92 #ifdef EXT2FS_DEBUG
   93         printf("can not convert ext2fs name to bsd: namespace=%d\n", attrnamespace);
   94 #endif
   95 
   96         return (NULL);
   97 }
   98 
   99 static int
  100 ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name)
  101 {
  102 
  103         if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE &&
  104             !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME))
  105                 return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT);
  106 
  107         if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE &&
  108             !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME))
  109                 return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS);
  110 
  111         switch (attrnamespace) {
  112         case EXTATTR_NAMESPACE_SYSTEM:
  113                 return (EXT4_XATTR_INDEX_SYSTEM);
  114 
  115         case EXTATTR_NAMESPACE_USER:
  116                 return (EXT4_XATTR_INDEX_USER);
  117         }
  118 
  119         /*
  120          * In this case namespace conversion should be unique,
  121          * so this point is unreachable.
  122          */
  123         return (-1);
  124 }
  125 
  126 static const char *
  127 ext2_extattr_name_to_linux(int attrnamespace, const char *name)
  128 {
  129 
  130         if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE ||
  131             attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE)
  132                 return ("");
  133         else
  134                 return (name);
  135 }
  136 
  137 int
  138 ext2_extattr_valid_attrname(int attrnamespace, const char *attrname)
  139 {
  140         if (attrnamespace == EXTATTR_NAMESPACE_EMPTY)
  141                 return (EINVAL);
  142 
  143         if (strlen(attrname) == 0)
  144                 return (EINVAL);
  145 
  146         if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX)
  147                 return (ENAMETOOLONG);
  148 
  149         return (0);
  150 }
  151 
  152 static int
  153 ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end)
  154 {
  155         struct ext2fs_extattr_entry *next;
  156 
  157         while (!EXT2_IS_LAST_ENTRY(entry)) {
  158                 next = EXT2_EXTATTR_NEXT(entry);
  159                 if ((char *)next >= end)
  160                         return (EIO);
  161 
  162                 entry = next;
  163         }
  164 
  165         return (0);
  166 }
  167 
  168 static int
  169 ext2_extattr_block_check(struct inode *ip, struct buf *bp)
  170 {
  171         struct ext2fs_extattr_header *header;
  172         int error;
  173 
  174         header = (struct ext2fs_extattr_header *)bp->b_data;
  175 
  176         error = ext2_extattr_check(EXT2_IFIRST(header),
  177             bp->b_data + bp->b_bufsize);
  178         if (error)
  179                 return (error);
  180 
  181         return (ext2_extattr_blk_csum_verify(ip, bp));
  182 }
  183 
  184 int
  185 ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
  186     struct uio *uio, size_t *size)
  187 {
  188         struct m_ext2fs *fs;
  189         struct buf *bp;
  190         struct ext2fs_extattr_dinode_header *header;
  191         struct ext2fs_extattr_entry *entry;
  192         const char *attr_name;
  193         int name_len;
  194         int error;
  195 
  196         fs = ip->i_e2fs;
  197 
  198         if ((error = bread(ip->i_devvp,
  199             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  200             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  201                 brelse(bp);
  202                 return (error);
  203         }
  204 
  205         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  206             ((char *)bp->b_data +
  207             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  208 
  209         /* Check attributes magic value */
  210         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  211             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  212 
  213         if (header->h_magic != EXTATTR_MAGIC) {
  214                 brelse(bp);
  215                 return (0);
  216         }
  217 
  218         error = ext2_extattr_check(EXT2_IFIRST(header),
  219             (char *)dinode + EXT2_INODE_SIZE(fs));
  220         if (error) {
  221                 brelse(bp);
  222                 return (error);
  223         }
  224 
  225         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  226             entry = EXT2_EXTATTR_NEXT(entry)) {
  227                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  228                     attrnamespace)
  229                         continue;
  230 
  231                 name_len = entry->e_name_len;
  232                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  233                     entry->e_name, &name_len);
  234                 if (!attr_name) {
  235                         brelse(bp);
  236                         return (ENOTSUP);
  237                 }
  238 
  239                 if (size != NULL)
  240                         *size += name_len + 1;
  241 
  242                 if (uio != NULL) {
  243                         char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
  244                         name[0] = name_len;
  245                         memcpy(&name[1], attr_name, name_len);
  246                         error = uiomove(name, name_len + 1, uio);
  247                         free(name, M_TEMP);
  248                         if (error)
  249                                 break;
  250                 }
  251         }
  252 
  253         brelse(bp);
  254 
  255         return (error);
  256 }
  257 
  258 int
  259 ext2_extattr_block_list(struct inode *ip, int attrnamespace,
  260     struct uio *uio, size_t *size)
  261 {
  262         struct m_ext2fs *fs;
  263         struct buf *bp;
  264         struct ext2fs_extattr_header *header;
  265         struct ext2fs_extattr_entry *entry;
  266         const char *attr_name;
  267         int name_len;
  268         int error;
  269 
  270         fs = ip->i_e2fs;
  271 
  272         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  273             fs->e2fs_bsize, NOCRED, &bp);
  274         if (error) {
  275                 brelse(bp);
  276                 return (error);
  277         }
  278 
  279         /* Check attributes magic value */
  280         header = EXT2_HDR(bp);
  281         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
  282                 brelse(bp);
  283                 return (EINVAL);
  284         }
  285 
  286         error = ext2_extattr_block_check(ip, bp);
  287         if (error) {
  288                 brelse(bp);
  289                 return (error);
  290         }
  291 
  292         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  293             entry = EXT2_EXTATTR_NEXT(entry)) {
  294                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  295                     attrnamespace)
  296                         continue;
  297 
  298                 name_len = entry->e_name_len;
  299                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  300                     entry->e_name, &name_len);
  301                 if (!attr_name) {
  302                         brelse(bp);
  303                         return (ENOTSUP);
  304                 }
  305 
  306                 if (size != NULL)
  307                         *size += name_len + 1;
  308 
  309                 if (uio != NULL) {
  310                         char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
  311                         name[0] = name_len;
  312                         memcpy(&name[1], attr_name, name_len);
  313                         error = uiomove(name, name_len + 1, uio);
  314                         free(name, M_TEMP);
  315                         if (error)
  316                                 break;
  317                 }
  318         }
  319 
  320         brelse(bp);
  321 
  322         return (error);
  323 }
  324 
  325 int
  326 ext2_extattr_inode_get(struct inode *ip, int attrnamespace,
  327     const char *name, struct uio *uio, size_t *size)
  328 {
  329         struct m_ext2fs *fs;
  330         struct buf *bp;
  331         struct ext2fs_extattr_dinode_header *header;
  332         struct ext2fs_extattr_entry *entry;
  333         const char *attr_name;
  334         int name_len;
  335         int error;
  336 
  337         fs = ip->i_e2fs;
  338 
  339         if ((error = bread(ip->i_devvp,
  340             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  341             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  342                 brelse(bp);
  343                 return (error);
  344         }
  345 
  346         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  347             ((char *)bp->b_data +
  348             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  349 
  350         /* Check attributes magic value */
  351         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  352             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  353 
  354         if (header->h_magic != EXTATTR_MAGIC) {
  355                 brelse(bp);
  356                 return (ENOATTR);
  357         }
  358 
  359         error = ext2_extattr_check(EXT2_IFIRST(header),
  360             (char *)dinode + EXT2_INODE_SIZE(fs));
  361         if (error) {
  362                 brelse(bp);
  363                 return (error);
  364         }
  365 
  366         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  367             entry = EXT2_EXTATTR_NEXT(entry)) {
  368                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  369                     attrnamespace)
  370                         continue;
  371 
  372                 name_len = entry->e_name_len;
  373                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  374                     entry->e_name, &name_len);
  375                 if (!attr_name) {
  376                         brelse(bp);
  377                         return (ENOTSUP);
  378                 }
  379 
  380                 if (strlen(name) == name_len &&
  381                     0 == strncmp(attr_name, name, name_len)) {
  382                         if (size != NULL)
  383                                 *size += entry->e_value_size;
  384 
  385                         if (uio != NULL)
  386                                 error = uiomove(((char *)EXT2_IFIRST(header)) +
  387                                     entry->e_value_offs, entry->e_value_size, uio);
  388 
  389                         brelse(bp);
  390                         return (error);
  391                 }
  392          }
  393 
  394         brelse(bp);
  395 
  396         return (ENOATTR);
  397 }
  398 
  399 int
  400 ext2_extattr_block_get(struct inode *ip, int attrnamespace,
  401     const char *name, struct uio *uio, size_t *size)
  402 {
  403         struct m_ext2fs *fs;
  404         struct buf *bp;
  405         struct ext2fs_extattr_header *header;
  406         struct ext2fs_extattr_entry *entry;
  407         const char *attr_name;
  408         int name_len;
  409         int error;
  410 
  411         fs = ip->i_e2fs;
  412 
  413         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  414             fs->e2fs_bsize, NOCRED, &bp);
  415         if (error) {
  416                 brelse(bp);
  417                 return (error);
  418         }
  419 
  420         /* Check attributes magic value */
  421         header = EXT2_HDR(bp);
  422         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
  423                 brelse(bp);
  424                 return (EINVAL);
  425         }
  426 
  427         error = ext2_extattr_block_check(ip, bp);
  428         if (error) {
  429                 brelse(bp);
  430                 return (error);
  431         }
  432 
  433         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  434             entry = EXT2_EXTATTR_NEXT(entry)) {
  435                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  436                     attrnamespace)
  437                         continue;
  438 
  439                 name_len = entry->e_name_len;
  440                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  441                     entry->e_name, &name_len);
  442                 if (!attr_name) {
  443                         brelse(bp);
  444                         return (ENOTSUP);
  445                 }
  446 
  447                 if (strlen(name) == name_len &&
  448                     0 == strncmp(attr_name, name, name_len)) {
  449                         if (size != NULL)
  450                                 *size += entry->e_value_size;
  451 
  452                         if (uio != NULL)
  453                                 error = uiomove(bp->b_data + entry->e_value_offs,
  454                                     entry->e_value_size, uio);
  455 
  456                         brelse(bp);
  457                         return (error);
  458                 }
  459          }
  460 
  461         brelse(bp);
  462 
  463         return (ENOATTR);
  464 }
  465 
  466 static uint16_t
  467 ext2_extattr_delete_value(char *off,
  468     struct ext2fs_extattr_entry *first_entry,
  469     struct ext2fs_extattr_entry *entry, char *end)
  470 {
  471         uint16_t min_offs;
  472         struct ext2fs_extattr_entry *next;
  473 
  474         min_offs = end - off;
  475         next = first_entry;
  476         while (!EXT2_IS_LAST_ENTRY(next)) {
  477                 if (min_offs > next->e_value_offs && next->e_value_offs > 0)
  478                         min_offs = next->e_value_offs;
  479 
  480                 next = EXT2_EXTATTR_NEXT(next);
  481         }
  482 
  483         if (entry->e_value_size == 0)
  484                 return (min_offs);
  485 
  486         memmove(off + min_offs + EXT2_EXTATTR_SIZE(entry->e_value_size),
  487             off + min_offs, entry->e_value_offs - min_offs);
  488 
  489         /* Adjust all value offsets */
  490         next = first_entry;
  491         while (!EXT2_IS_LAST_ENTRY(next))
  492         {
  493                 if (next->e_value_offs > 0 &&
  494                     next->e_value_offs < entry->e_value_offs)
  495                         next->e_value_offs +=
  496                             EXT2_EXTATTR_SIZE(entry->e_value_size);
  497 
  498                 next = EXT2_EXTATTR_NEXT(next);
  499         }
  500 
  501         min_offs += EXT2_EXTATTR_SIZE(entry->e_value_size);
  502 
  503         return (min_offs);
  504 }
  505 
  506 static void
  507 ext2_extattr_delete_entry(char *off,
  508     struct ext2fs_extattr_entry *first_entry,
  509     struct ext2fs_extattr_entry *entry, char *end)
  510 {
  511         char *pad;
  512         struct ext2fs_extattr_entry *next;
  513 
  514         /* Clean entry value */
  515         ext2_extattr_delete_value(off, first_entry, entry, end);
  516 
  517         /* Clean the entry */
  518         next = first_entry;
  519         while (!EXT2_IS_LAST_ENTRY(next))
  520                 next = EXT2_EXTATTR_NEXT(next);
  521 
  522         pad = (char*)next + sizeof(uint32_t);
  523 
  524         memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len),
  525             pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len)));
  526 }
  527 
  528 int
  529 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
  530 {
  531         struct m_ext2fs *fs;
  532         struct buf *bp;
  533         struct ext2fs_extattr_dinode_header *header;
  534         struct ext2fs_extattr_entry *entry;
  535         const char *attr_name;
  536         int name_len;
  537         int error;
  538 
  539         fs = ip->i_e2fs;
  540 
  541         if ((error = bread(ip->i_devvp,
  542             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  543             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  544                 brelse(bp);
  545                 return (error);
  546         }
  547 
  548         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  549             ((char *)bp->b_data +
  550             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  551 
  552         /* Check attributes magic value */
  553         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  554             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  555 
  556         if (header->h_magic != EXTATTR_MAGIC) {
  557                 brelse(bp);
  558                 return (ENOATTR);
  559         }
  560 
  561         error = ext2_extattr_check(EXT2_IFIRST(header),
  562             (char *)dinode + EXT2_INODE_SIZE(fs));
  563         if (error) {
  564                 brelse(bp);
  565                 return (error);
  566         }
  567 
  568         /* If I am last entry, just make magic zero */
  569         entry = EXT2_IFIRST(header);
  570         if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) &&
  571             (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
  572             attrnamespace)) {
  573 
  574                 name_len = entry->e_name_len;
  575                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  576                     entry->e_name, &name_len);
  577                 if (!attr_name) {
  578                         brelse(bp);
  579                         return (ENOTSUP);
  580                 }
  581 
  582                 if (strlen(name) == name_len &&
  583                     0 == strncmp(attr_name, name, name_len)) {
  584                         memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
  585 
  586                         return (bwrite(bp));
  587                 }
  588         }
  589 
  590         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  591             entry = EXT2_EXTATTR_NEXT(entry)) {
  592                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  593                     attrnamespace)
  594                         continue;
  595 
  596                 name_len = entry->e_name_len;
  597                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  598                     entry->e_name, &name_len);
  599                 if (!attr_name) {
  600                         brelse(bp);
  601                         return (ENOTSUP);
  602                 }
  603 
  604                 if (strlen(name) == name_len &&
  605                     0 == strncmp(attr_name, name, name_len)) {
  606                         ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
  607                             EXT2_IFIRST(header), entry,
  608                             (char *)dinode + EXT2_INODE_SIZE(fs));
  609 
  610                         return (bwrite(bp));
  611                 }
  612         }
  613 
  614         brelse(bp);
  615 
  616         return (ENOATTR);
  617 }
  618 
  619 static int
  620 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp)
  621 {
  622         struct m_ext2fs *fs;
  623         struct buf *sbp;
  624         struct buf *cbp;
  625         struct ext2fs_extattr_header *header;
  626         uint64_t facl;
  627 
  628         fs = ip->i_e2fs;
  629         sbp = *bpp;
  630 
  631         header = EXT2_HDR(sbp);
  632         if (header->h_magic != EXTATTR_MAGIC || header->h_refcount == 1)
  633                 return (EINVAL);
  634 
  635         facl = ext2_alloc_meta(ip);
  636         if (!facl)
  637                 return (ENOSPC);
  638 
  639         cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0);
  640         if (!cbp) {
  641                 ext2_blkfree(ip, facl, fs->e2fs_bsize);
  642                 return (EIO);
  643         }
  644 
  645         memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize);
  646         header->h_refcount--;
  647         bwrite(sbp);
  648 
  649         ip->i_facl = facl;
  650         ext2_update(ip->i_vnode, 1);
  651 
  652         header = EXT2_HDR(cbp);
  653         header->h_refcount = 1;
  654 
  655         *bpp = cbp;
  656 
  657         return (0);
  658 }
  659 
  660 int
  661 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
  662 {
  663         struct m_ext2fs *fs;
  664         struct buf *bp;
  665         struct ext2fs_extattr_header *header;
  666         struct ext2fs_extattr_entry *entry;
  667         const char *attr_name;
  668         int name_len;
  669         int error;
  670 
  671         fs = ip->i_e2fs;
  672 
  673         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  674             fs->e2fs_bsize, NOCRED, &bp);
  675         if (error) {
  676                 brelse(bp);
  677                 return (error);
  678         }
  679 
  680         /* Check attributes magic value */
  681         header = EXT2_HDR(bp);
  682         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
  683                 brelse(bp);
  684                 return (EINVAL);
  685         }
  686 
  687         error = ext2_extattr_block_check(ip, bp);
  688         if (error) {
  689                 brelse(bp);
  690                 return (error);
  691         }
  692 
  693         if (header->h_refcount > 1) {
  694                 error = ext2_extattr_block_clone(ip, &bp);
  695                 if (error) {
  696                         brelse(bp);
  697                         return (error);
  698                 }
  699         }
  700 
  701         /* If I am last entry, clean me and free the block */
  702         entry = EXT2_FIRST_ENTRY(bp);
  703         if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
  704             (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
  705             attrnamespace)) {
  706 
  707                 name_len = entry->e_name_len;
  708                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  709                     entry->e_name, &name_len);
  710                 if (!attr_name) {
  711                         brelse(bp);
  712                         return (ENOTSUP);
  713                 }
  714 
  715                 if (strlen(name) == name_len &&
  716                     0 == strncmp(attr_name, name, name_len)) {
  717                         ip->i_blocks -= btodb(fs->e2fs_bsize);
  718                         ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
  719                         ip->i_facl = 0;
  720                         error = ext2_update(ip->i_vnode, 1);
  721 
  722                         brelse(bp);
  723                         return (error);
  724                 }
  725         }
  726 
  727         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  728             entry = EXT2_EXTATTR_NEXT(entry)) {
  729                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  730                     attrnamespace)
  731                         continue;
  732 
  733                 name_len = entry->e_name_len;
  734                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  735                     entry->e_name, &name_len);
  736                 if (!attr_name) {
  737                         brelse(bp);
  738                         return (ENOTSUP);
  739                 }
  740 
  741                 if (strlen(name) == name_len &&
  742                     0 == strncmp(attr_name, name, name_len)) {
  743                         ext2_extattr_delete_entry(bp->b_data,
  744                             EXT2_FIRST_ENTRY(bp), entry,
  745                             bp->b_data + bp->b_bufsize);
  746 
  747                         return (bwrite(bp));
  748                 }
  749         }
  750 
  751         brelse(bp);
  752 
  753         return (ENOATTR);
  754 }
  755 
  756 static struct ext2fs_extattr_entry *
  757 allocate_entry(const char *name, int attrnamespace, uint16_t offs,
  758     uint32_t size, uint32_t hash)
  759 {
  760         const char *attr_name;
  761         int name_len;
  762         struct ext2fs_extattr_entry *entry;
  763 
  764         attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
  765         name_len = strlen(attr_name);
  766 
  767         entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
  768             M_TEMP, M_WAITOK);
  769 
  770         entry->e_name_len = name_len;
  771         entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
  772         entry->e_value_offs = offs;
  773         entry->e_value_block = 0;
  774         entry->e_value_size = size;
  775         entry->e_hash = hash;
  776         memcpy(entry->e_name, name, name_len);
  777 
  778         return (entry);
  779 }
  780 
  781 static void
  782 free_entry(struct ext2fs_extattr_entry *entry)
  783 {
  784 
  785         free(entry, M_TEMP);
  786 }
  787 
  788 static int
  789 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry,
  790     struct ext2fs_extattr_entry *exist_entry, int header_size,
  791     int name_len, int new_size)
  792 {
  793         struct ext2fs_extattr_entry *entry;
  794         int size;
  795 
  796         size = header_size;
  797         size += sizeof(uint32_t);
  798 
  799         if (NULL == exist_entry) {
  800                 size += EXT2_EXTATTR_LEN(name_len);
  801                 size += EXT2_EXTATTR_SIZE(new_size);
  802         }
  803 
  804         if (first_entry)
  805                 for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry);
  806                     entry = EXT2_EXTATTR_NEXT(entry)) {
  807                         if (entry != exist_entry)
  808                                 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
  809                                     EXT2_EXTATTR_SIZE(entry->e_value_size);
  810                         else
  811                                 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
  812                                     EXT2_EXTATTR_SIZE(new_size);
  813                 }
  814 
  815         return (size);
  816 }
  817 
  818 static void
  819 ext2_extattr_set_exist_entry(char *off,
  820     struct ext2fs_extattr_entry *first_entry,
  821     struct ext2fs_extattr_entry *entry,
  822     char *end, struct uio *uio)
  823 {
  824         uint16_t min_offs;
  825 
  826         min_offs = ext2_extattr_delete_value(off, first_entry, entry, end);
  827 
  828         entry->e_value_size = uio->uio_resid;
  829         if (entry->e_value_size)
  830                 entry->e_value_offs = min_offs -
  831                     EXT2_EXTATTR_SIZE(uio->uio_resid);
  832         else
  833                 entry->e_value_offs = 0;
  834 
  835         uiomove(off + entry->e_value_offs, entry->e_value_size, uio);
  836 }
  837 
  838 static struct ext2fs_extattr_entry *
  839 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry,
  840     const char *name, int attrnamespace, char *end, struct uio *uio)
  841 {
  842         int name_len;
  843         char *pad;
  844         uint16_t min_offs;
  845         struct ext2fs_extattr_entry *entry;
  846         struct ext2fs_extattr_entry *new_entry;
  847 
  848         /* Find pad's */
  849         min_offs = end - off;
  850         entry = first_entry;
  851         while (!EXT2_IS_LAST_ENTRY(entry)) {
  852                 if (min_offs > entry->e_value_offs && entry->e_value_offs > 0)
  853                         min_offs = entry->e_value_offs;
  854 
  855                 entry = EXT2_EXTATTR_NEXT(entry);
  856         }
  857 
  858         pad = (char*)entry + sizeof(uint32_t);
  859 
  860         /* Find entry insert position */
  861         name_len = strlen(name);
  862         entry = first_entry;
  863         while (!EXT2_IS_LAST_ENTRY(entry)) {
  864                 if (!(attrnamespace - entry->e_name_index) &&
  865                     !(name_len - entry->e_name_len))
  866                         if (memcmp(name, entry->e_name, name_len) <= 0)
  867                                 break;
  868 
  869                 entry = EXT2_EXTATTR_NEXT(entry);
  870         }
  871 
  872         /* Create new entry and insert it */
  873         new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0);
  874         memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry,
  875             pad - (char*)entry);
  876 
  877         memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len));
  878         free_entry(new_entry);
  879 
  880         new_entry = entry;
  881         if (new_entry->e_value_size > 0)
  882                 new_entry->e_value_offs = min_offs -
  883                     EXT2_EXTATTR_SIZE(new_entry->e_value_size);
  884 
  885         uiomove(off + new_entry->e_value_offs, new_entry->e_value_size, uio);
  886 
  887         return (new_entry);
  888 }
  889 
  890 int
  891 ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
  892     const char *name, struct uio *uio)
  893 {
  894         struct m_ext2fs *fs;
  895         struct buf *bp;
  896         struct ext2fs_extattr_dinode_header *header;
  897         struct ext2fs_extattr_entry *entry;
  898         const char *attr_name;
  899         int name_len;
  900         size_t size = 0, max_size;
  901         int error;
  902 
  903         fs = ip->i_e2fs;
  904 
  905         if ((error = bread(ip->i_devvp,
  906             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  907             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  908                 brelse(bp);
  909                 return (error);
  910         }
  911 
  912         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  913             ((char *)bp->b_data +
  914             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  915 
  916         /* Check attributes magic value */
  917         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  918             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  919 
  920         if (header->h_magic != EXTATTR_MAGIC) {
  921                 brelse(bp);
  922                 return (ENOSPC);
  923         }
  924 
  925         error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode +
  926             EXT2_INODE_SIZE(fs));
  927         if (error) {
  928                 brelse(bp);
  929                 return (error);
  930         }
  931 
  932         /* Find if entry exist */
  933         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  934             entry = EXT2_EXTATTR_NEXT(entry)) {
  935                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  936                     attrnamespace)
  937                         continue;
  938 
  939                 name_len = entry->e_name_len;
  940                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  941                     entry->e_name, &name_len);
  942                 if (!attr_name) {
  943                         brelse(bp);
  944                         return (ENOTSUP);
  945                 }
  946 
  947                 if (strlen(name) == name_len &&
  948                     0 == strncmp(attr_name, name, name_len))
  949                         break;
  950         }
  951 
  952         max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE -
  953             dinode->e2di_extra_isize;
  954 
  955         if (!EXT2_IS_LAST_ENTRY(entry)) {
  956                 size = ext2_extattr_get_size(EXT2_IFIRST(header), entry,
  957                     sizeof(struct ext2fs_extattr_dinode_header),
  958                     entry->e_name_len, uio->uio_resid);
  959                 if (size > max_size) {
  960                         brelse(bp);
  961                         return (ENOSPC);
  962                 }
  963 
  964                 ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header),
  965                     EXT2_IFIRST(header), entry, (char *)header + max_size, uio);
  966         } else {
  967                 /* Ensure that the same entry does not exist in the block */
  968                 if (ip->i_facl) {
  969                         error = ext2_extattr_block_get(ip, attrnamespace, name,
  970                             NULL, &size);
  971                         if (error != ENOATTR || size > 0) {
  972                                 brelse(bp);
  973                                 if (size > 0)
  974                                         error = ENOSPC;
  975 
  976                                 return (error);
  977                         }
  978                 }
  979 
  980                 size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL,
  981                     sizeof(struct ext2fs_extattr_dinode_header),
  982                     entry->e_name_len, uio->uio_resid);
  983                 if (size > max_size) {
  984                         brelse(bp);
  985                         return (ENOSPC);
  986                 }
  987 
  988                 ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header),
  989                     EXT2_IFIRST(header), name, attrnamespace,
  990                     (char *)header + max_size, uio);
  991         }
  992 
  993         return (bwrite(bp));
  994 }
  995 
  996 static void
  997 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header,
  998     struct ext2fs_extattr_entry *entry)
  999 {
 1000         uint32_t hash = 0;
 1001         char *name = entry->e_name;
 1002         int n;
 1003 
 1004         for (n=0; n < entry->e_name_len; n++) {
 1005                 hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^
 1006                     (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^
 1007                     (*name++);
 1008         }
 1009 
 1010         if (entry->e_value_block == 0 && entry->e_value_size != 0) {
 1011                 uint32_t *value = (uint32_t *)((char *)header + entry->e_value_offs);
 1012                 for (n = (entry->e_value_size +
 1013                     EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) {
 1014                         hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^
 1015                             (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^
 1016                             (*value++);
 1017                 }
 1018         }
 1019 
 1020         entry->e_hash = hash;
 1021 }
 1022 
 1023 static void
 1024 ext2_extattr_rehash(struct ext2fs_extattr_header *header,
 1025     struct ext2fs_extattr_entry *entry)
 1026 {
 1027         struct ext2fs_extattr_entry *here;
 1028         uint32_t hash = 0;
 1029 
 1030         ext2_extattr_hash_entry(header, entry);
 1031 
 1032         here = EXT2_ENTRY(header+1);
 1033         while (!EXT2_IS_LAST_ENTRY(here)) {
 1034                 if (!here->e_hash) {
 1035                         /* Block is not shared if an entry's hash value == 0 */
 1036                         hash = 0;
 1037                         break;
 1038                 }
 1039 
 1040                 hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^
 1041                     (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^
 1042                     here->e_hash;
 1043 
 1044                 here = EXT2_EXTATTR_NEXT(here);
 1045         }
 1046 
 1047         header->h_hash = hash;
 1048 }
 1049 
 1050 int
 1051 ext2_extattr_block_set(struct inode *ip, int attrnamespace,
 1052     const char *name, struct uio *uio)
 1053 {
 1054         struct m_ext2fs *fs;
 1055         struct buf *bp;
 1056         struct ext2fs_extattr_header *header;
 1057         struct ext2fs_extattr_entry *entry;
 1058         const char *attr_name;
 1059         int name_len;
 1060         size_t size;
 1061         int error;
 1062 
 1063         fs = ip->i_e2fs;
 1064 
 1065         if (ip->i_facl) {
 1066                 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
 1067                     fs->e2fs_bsize, NOCRED, &bp);
 1068                 if (error) {
 1069                         brelse(bp);
 1070                         return (error);
 1071                 }
 1072 
 1073                 /* Check attributes magic value */
 1074                 header = EXT2_HDR(bp);
 1075                 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
 1076                         brelse(bp);
 1077                         return (EINVAL);
 1078                 }
 1079 
 1080                 error = ext2_extattr_block_check(ip, bp);
 1081                 if (error) {
 1082                         brelse(bp);
 1083                         return (error);
 1084                 }
 1085 
 1086                 if (header->h_refcount > 1) {
 1087                         error = ext2_extattr_block_clone(ip, &bp);
 1088                         if (error) {
 1089                                 brelse(bp);
 1090                                 return (error);
 1091                         }
 1092 
 1093                         header = EXT2_HDR(bp);
 1094                 }
 1095 
 1096                 /* Find if entry exist */
 1097                 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
 1098                     entry = EXT2_EXTATTR_NEXT(entry)) {
 1099                         if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
 1100                             attrnamespace)
 1101                                 continue;
 1102 
 1103                         name_len = entry->e_name_len;
 1104                         attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
 1105                             entry->e_name, &name_len);
 1106                         if (!attr_name) {
 1107                                 brelse(bp);
 1108                                 return (ENOTSUP);
 1109                         }
 1110 
 1111                         if (strlen(name) == name_len &&
 1112                             0 == strncmp(attr_name, name, name_len))
 1113                                 break;
 1114                 }
 1115 
 1116                 if (!EXT2_IS_LAST_ENTRY(entry)) {
 1117                         size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry,
 1118                             sizeof(struct ext2fs_extattr_header),
 1119                             entry->e_name_len, uio->uio_resid);
 1120                         if (size > bp->b_bufsize) {
 1121                                 brelse(bp);
 1122                                 return (ENOSPC);
 1123                         }
 1124 
 1125                         ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1126                             entry, bp->b_data + bp->b_bufsize, uio);
 1127                 } else {
 1128                         size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL,
 1129                             sizeof(struct ext2fs_extattr_header),
 1130                             strlen(name), uio->uio_resid);
 1131                         if (size > bp->b_bufsize) {
 1132                                 brelse(bp);
 1133                                 return (ENOSPC);
 1134                         }
 1135 
 1136                         entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1137                             name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
 1138 
 1139                         /* Clean the same entry in the inode */
 1140                         error = ext2_extattr_inode_delete(ip, attrnamespace, name);
 1141                         if (error && error != ENOATTR) {
 1142                                 brelse(bp);
 1143                                 return (error);
 1144                         }
 1145                 }
 1146 
 1147                 ext2_extattr_rehash(header, entry);
 1148                 ext2_extattr_blk_csum_set(ip, bp);
 1149 
 1150                 return (bwrite(bp));
 1151         }
 1152 
 1153         size = ext2_extattr_get_size(NULL, NULL,
 1154             sizeof(struct ext2fs_extattr_header),
 1155             strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
 1156         if (size > fs->e2fs_bsize)
 1157                 return (ENOSPC);
 1158 
 1159         /* Allocate block, fill EA header and insert entry */
 1160         ip->i_facl = ext2_alloc_meta(ip);
 1161         if (0 == ip->i_facl)
 1162                 return (ENOSPC);
 1163 
 1164         ip->i_blocks += btodb(fs->e2fs_bsize);
 1165         ext2_update(ip->i_vnode, 1);
 1166 
 1167         bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0);
 1168         if (!bp) {
 1169                 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
 1170                 ip->i_blocks -= btodb(fs->e2fs_bsize);
 1171                 ip->i_facl = 0;
 1172                 ext2_update(ip->i_vnode, 1);
 1173                 return (EIO);
 1174         }
 1175 
 1176         header = EXT2_HDR(bp);
 1177         header->h_magic = EXTATTR_MAGIC;
 1178         header->h_refcount = 1;
 1179         header->h_blocks = 1;
 1180         header->h_hash = 0;
 1181         memset(header->h_reserved, 0, sizeof(header->h_reserved));
 1182         memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header));
 1183         memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t));
 1184 
 1185         entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1186             name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
 1187 
 1188         /* Clean the same entry in the inode */
 1189         error = ext2_extattr_inode_delete(ip, attrnamespace, name);
 1190         if (error && error != ENOATTR) {
 1191                 brelse(bp);
 1192                 return (error);
 1193         }
 1194 
 1195         ext2_extattr_rehash(header, entry);
 1196         ext2_extattr_blk_csum_set(ip, bp);
 1197 
 1198         return (bwrite(bp));
 1199 }
 1200 
 1201 int ext2_extattr_free(struct inode *ip)
 1202 {
 1203         struct m_ext2fs *fs;
 1204         struct buf *bp;
 1205         struct ext2fs_extattr_header *header;
 1206         int error;
 1207 
 1208         fs = ip->i_e2fs;
 1209 
 1210         if (!ip->i_facl)
 1211                 return (0);
 1212 
 1213         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
 1214             fs->e2fs_bsize, NOCRED, &bp);
 1215         if (error) {
 1216                 brelse(bp);
 1217                 return (error);
 1218         }
 1219 
 1220         /* Check attributes magic value */
 1221         header = EXT2_HDR(bp);
 1222         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
 1223                 brelse(bp);
 1224                 return (EINVAL);
 1225         }
 1226 
 1227         error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
 1228             bp->b_data + bp->b_bufsize);
 1229         if (error) {
 1230                 brelse(bp);
 1231                 return (error);
 1232         }
 1233 
 1234         if (header->h_refcount > 1) {
 1235                 header->h_refcount--;
 1236                 bwrite(bp);
 1237         } else {
 1238                 ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize);
 1239                 brelse(bp);
 1240         }
 1241 
 1242         ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize);
 1243         ip->i_facl = 0;
 1244         ext2_update(ip->i_vnode, 1);
 1245 
 1246         return (0);
 1247 }

Cache object: 9784cfeea87af9cb339531fd398cc1b0


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