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

Cache object: 869ba2b849adafdc908c44a58fef5d94


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