Merge branch 'master' of git://git.infradead.org/users/eparis/selinux into next
authorJames Morris <jmorris@namei.org>
Tue, 8 Mar 2011 00:38:10 +0000 (11:38 +1100)
committerJames Morris <jmorris@namei.org>
Tue, 8 Mar 2011 00:38:10 +0000 (11:38 +1100)
19 files changed:
1  2 
fs/btrfs/inode.c
fs/btrfs/xattr.c
fs/ext2/namei.c
fs/ext3/namei.c
fs/ext4/ialloc.c
fs/gfs2/inode.c
fs/jfs/namei.c
fs/namespace.c
fs/ocfs2/namei.c
fs/ocfs2/refcounttree.c
fs/reiserfs/namei.c
fs/xfs/linux-2.6/xfs_iops.c
include/linux/ext3_fs.h
include/linux/security.h
kernel/sysctl.c
security/security.c
security/selinux/hooks.c
security/selinux/ss/policydb.c
security/smack/smack_lsm.c

diff --combined fs/btrfs/inode.c
@@@ -90,13 -90,14 +90,14 @@@ static noinline int cow_file_range(stru
                                   unsigned long *nr_written, int unlock);
  
  static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
-                                    struct inode *inode,  struct inode *dir)
+                                    struct inode *inode,  struct inode *dir,
+                                    const struct qstr *qstr)
  {
        int err;
  
        err = btrfs_init_acl(trans, inode, dir);
        if (!err)
-               err = btrfs_xattr_security_init(trans, inode, dir);
+               err = btrfs_xattr_security_init(trans, inode, dir, qstr);
        return err;
  }
  
@@@ -122,10 -123,10 +123,10 @@@ static noinline int insert_inline_exten
        size_t cur_size = size;
        size_t datasize;
        unsigned long offset;
 -      int use_compress = 0;
 +      int compress_type = BTRFS_COMPRESS_NONE;
  
        if (compressed_size && compressed_pages) {
 -              use_compress = 1;
 +              compress_type = root->fs_info->compress_type;
                cur_size = compressed_size;
        }
  
        btrfs_set_file_extent_ram_bytes(leaf, ei, size);
        ptr = btrfs_file_extent_inline_start(ei);
  
 -      if (use_compress) {
 +      if (compress_type != BTRFS_COMPRESS_NONE) {
                struct page *cpage;
                int i = 0;
                while (compressed_size > 0) {
                        compressed_size -= cur_size;
                }
                btrfs_set_file_extent_compression(leaf, ei,
 -                                                BTRFS_COMPRESS_ZLIB);
 +                                                compress_type);
        } else {
                page = find_get_page(inode->i_mapping,
                                     start >> PAGE_CACHE_SHIFT);
@@@ -263,7 -264,6 +264,7 @@@ struct async_extent 
        u64 compressed_size;
        struct page **pages;
        unsigned long nr_pages;
 +      int compress_type;
        struct list_head list;
  };
  
@@@ -281,8 -281,7 +282,8 @@@ static noinline int add_async_extent(st
                                     u64 start, u64 ram_size,
                                     u64 compressed_size,
                                     struct page **pages,
 -                                   unsigned long nr_pages)
 +                                   unsigned long nr_pages,
 +                                   int compress_type)
  {
        struct async_extent *async_extent;
  
        async_extent->compressed_size = compressed_size;
        async_extent->pages = pages;
        async_extent->nr_pages = nr_pages;
 +      async_extent->compress_type = compress_type;
        list_add_tail(&async_extent->list, &cow->extents);
        return 0;
  }
@@@ -335,7 -333,6 +336,7 @@@ static noinline int compress_file_range
        unsigned long max_uncompressed = 128 * 1024;
        int i;
        int will_compress;
 +      int compress_type = root->fs_info->compress_type;
  
        actual_end = min_t(u64, isize, end + 1);
  again:
                WARN_ON(pages);
                pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
  
 -              ret = btrfs_zlib_compress_pages(inode->i_mapping, start,
 -                                              total_compressed, pages,
 -                                              nr_pages, &nr_pages_ret,
 -                                              &total_in,
 -                                              &total_compressed,
 -                                              max_compressed);
 +              if (BTRFS_I(inode)->force_compress)
 +                      compress_type = BTRFS_I(inode)->force_compress;
 +
 +              ret = btrfs_compress_pages(compress_type,
 +                                         inode->i_mapping, start,
 +                                         total_compressed, pages,
 +                                         nr_pages, &nr_pages_ret,
 +                                         &total_in,
 +                                         &total_compressed,
 +                                         max_compressed);
  
                if (!ret) {
                        unsigned long offset = total_compressed &
        }
        if (start == 0) {
                trans = btrfs_join_transaction(root, 1);
 -              BUG_ON(!trans);
 +              BUG_ON(IS_ERR(trans));
                btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
                 * and will submit them to the elevator.
                 */
                add_async_extent(async_cow, start, num_bytes,
 -                               total_compressed, pages, nr_pages_ret);
 +                               total_compressed, pages, nr_pages_ret,
 +                               compress_type);
  
                if (start + num_bytes < end) {
                        start += num_bytes;
@@@ -524,8 -516,7 +525,8 @@@ cleanup_and_bail_uncompressed
                        __set_page_dirty_nobuffers(locked_page);
                        /* unlocked later on in the async handlers */
                }
 -              add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0);
 +              add_async_extent(async_cow, start, end - start + 1,
 +                               0, NULL, 0, BTRFS_COMPRESS_NONE);
                *num_added += 1;
        }
  
@@@ -612,7 -603,6 +613,7 @@@ retry
                            GFP_NOFS);
  
                trans = btrfs_join_transaction(root, 1);
 +              BUG_ON(IS_ERR(trans));
                ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
                                        async_extent->ram_size - 1, 0);
  
                em = alloc_extent_map(GFP_NOFS);
 +              BUG_ON(!em);
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
                em->orig_start = em->start;
                em->block_start = ins.objectid;
                em->block_len = ins.offset;
                em->bdev = root->fs_info->fs_devices->latest_bdev;
 +              em->compress_type = async_extent->compress_type;
                set_bit(EXTENT_FLAG_PINNED, &em->flags);
                set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
  
                                                async_extent->ram_size - 1, 0);
                }
  
 -              ret = btrfs_add_ordered_extent(inode, async_extent->start,
 -                                             ins.objectid,
 -                                             async_extent->ram_size,
 -                                             ins.offset,
 -                                             BTRFS_ORDERED_COMPRESSED);
 +              ret = btrfs_add_ordered_extent_compress(inode,
 +                                              async_extent->start,
 +                                              ins.objectid,
 +                                              async_extent->ram_size,
 +                                              ins.offset,
 +                                              BTRFS_ORDERED_COMPRESSED,
 +                                              async_extent->compress_type);
                BUG_ON(ret);
  
                /*
@@@ -773,7 -759,7 +774,7 @@@ static noinline int cow_file_range(stru
  
        BUG_ON(root == root->fs_info->tree_root);
        trans = btrfs_join_transaction(root, 1);
 -      BUG_ON(!trans);
 +      BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
                BUG_ON(ret);
  
                em = alloc_extent_map(GFP_NOFS);
 +              BUG_ON(!em);
                em->start = start;
                em->orig_start = em->start;
                ram_size = ins.offset;
@@@ -1052,7 -1037,7 +1053,7 @@@ static noinline int run_delalloc_nocow(
        } else {
                trans = btrfs_join_transaction(root, 1);
        }
 -      BUG_ON(!trans);
 +      BUG_ON(IS_ERR(trans));
  
        cow_start = (u64)-1;
        cur_offset = start;
@@@ -1171,7 -1156,6 +1172,7 @@@ out_check
                        struct extent_map_tree *em_tree;
                        em_tree = &BTRFS_I(inode)->extent_tree;
                        em = alloc_extent_map(GFP_NOFS);
 +                      BUG_ON(!em);
                        em->start = cur_offset;
                        em->orig_start = em->start;
                        em->len = num_bytes;
@@@ -1561,7 -1545,6 +1562,7 @@@ out
  out_page:
        unlock_page(page);
        page_cache_release(page);
 +      kfree(fixup);
  }
  
  /*
@@@ -1688,7 -1671,7 +1689,7 @@@ static int btrfs_finish_ordered_io(stru
        struct btrfs_ordered_extent *ordered_extent = NULL;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_state *cached_state = NULL;
 -      int compressed = 0;
 +      int compress_type = 0;
        int ret;
        bool nolock = false;
  
                                trans = btrfs_join_transaction_nolock(root, 1);
                        else
                                trans = btrfs_join_transaction(root, 1);
 -                      BUG_ON(!trans);
 +                      BUG_ON(IS_ERR(trans));
                        btrfs_set_trans_block_group(trans, inode);
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode(trans, root, inode);
                trans = btrfs_join_transaction_nolock(root, 1);
        else
                trans = btrfs_join_transaction(root, 1);
 +      BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
 -              compressed = 1;
 +              compress_type = ordered_extent->compress_type;
        if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
 -              BUG_ON(compressed);
 +              BUG_ON(compress_type);
                ret = btrfs_mark_extent_written(trans, inode,
                                                ordered_extent->file_offset,
                                                ordered_extent->file_offset +
                                                ordered_extent->disk_len,
                                                ordered_extent->len,
                                                ordered_extent->len,
 -                                              compressed, 0, 0,
 +                                              compress_type, 0, 0,
                                                BTRFS_FILE_EXTENT_REG);
                unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
                                   ordered_extent->file_offset,
@@@ -1848,8 -1830,6 +1849,8 @@@ static int btrfs_io_failed_hook(struct 
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
                        logical = em->block_start;
                        failrec->bio_flags = EXTENT_BIO_COMPRESSED;
 +                      extent_set_compress_type(&failrec->bio_flags,
 +                                               em->compress_type);
                }
                failrec->logical = logical;
                free_extent_map(em);
@@@ -1913,7 -1893,7 +1914,7 @@@ static int btrfs_clean_io_failures(stru
  
        private = 0;
        if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
 -                           (u64)-1, 1, EXTENT_DIRTY)) {
 +                           (u64)-1, 1, EXTENT_DIRTY, 0)) {
                ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
                                        start, &private_failure);
                if (ret == 0) {
@@@ -2360,7 -2340,6 +2361,7 @@@ void btrfs_orphan_cleanup(struct btrfs_
                 */
                if (is_bad_inode(inode)) {
                        trans = btrfs_start_transaction(root, 0);
 +                      BUG_ON(IS_ERR(trans));
                        btrfs_orphan_del(trans, inode);
                        btrfs_end_transaction(trans, root);
                        iput(inode);
  
        if (root->orphan_block_rsv || root->orphan_item_inserted) {
                trans = btrfs_join_transaction(root, 1);
 +              BUG_ON(IS_ERR(trans));
                btrfs_end_transaction(trans, root);
        }
  
@@@ -2649,7 -2627,7 +2650,7 @@@ int btrfs_unlink_inode(struct btrfs_tra
        path = btrfs_alloc_path();
        if (!path) {
                ret = -ENOMEM;
 -              goto err;
 +              goto out;
        }
  
        path->leave_spinning = 1;
@@@ -2722,10 -2700,9 +2723,10 @@@ static int check_path_shared(struct btr
        struct extent_buffer *eb;
        int level;
        u64 refs = 1;
 -      int uninitialized_var(ret);
  
        for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
 +              int ret;
 +
                if (!path->nodes[level])
                        break;
                eb = path->nodes[level];
                if (refs > 1)
                        return 1;
        }
 -      return ret; /* XXX callers? */
 +      return 0;
  }
  
  /*
@@@ -3695,12 -3672,8 +3696,12 @@@ static int btrfs_setattr_size(struct in
  static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
  {
        struct inode *inode = dentry->d_inode;
 +      struct btrfs_root *root = BTRFS_I(inode)->root;
        int err;
  
 +      if (btrfs_root_readonly(root))
 +              return -EROFS;
 +
        err = inode_change_ok(inode, attr);
        if (err)
                return err;
@@@ -4112,6 -4085,8 +4113,6 @@@ struct inode *btrfs_lookup_dentry(struc
        int index;
        int ret;
  
 -      d_set_d_op(dentry, &btrfs_dentry_operations);
 -
        if (dentry->d_name.len > BTRFS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
  
        }
        srcu_read_unlock(&root->fs_info->subvol_srcu, index);
  
 -      if (root != sub_root) {
 +      if (!IS_ERR(inode) && root != sub_root) {
                down_read(&root->fs_info->cleanup_work_sem);
                if (!(inode->i_sb->s_flags & MS_RDONLY))
                        btrfs_orphan_cleanup(sub_root);
@@@ -4356,8 -4331,6 +4357,8 @@@ int btrfs_write_inode(struct inode *ino
                        trans = btrfs_join_transaction_nolock(root, 1);
                else
                        trans = btrfs_join_transaction(root, 1);
 +              if (IS_ERR(trans))
 +                      return PTR_ERR(trans);
                btrfs_set_trans_block_group(trans, inode);
                if (nolock)
                        ret = btrfs_end_transaction_nolock(trans, root);
@@@ -4383,7 -4356,6 +4384,7 @@@ void btrfs_dirty_inode(struct inode *in
                return;
  
        trans = btrfs_join_transaction(root, 1);
 +      BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
  
        ret = btrfs_update_inode(trans, root, inode);
@@@ -4704,7 -4676,7 +4705,7 @@@ static int btrfs_mknod(struct inode *di
        if (IS_ERR(inode))
                goto out_unlock;
  
-       err = btrfs_init_inode_security(trans, inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@@ -4765,7 -4737,7 +4766,7 @@@ static int btrfs_create(struct inode *d
        if (IS_ERR(inode))
                goto out_unlock;
  
-       err = btrfs_init_inode_security(trans, inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@@ -4893,7 -4865,7 +4894,7 @@@ static int btrfs_mkdir(struct inode *di
  
        drop_on_err = 1;
  
-       err = btrfs_init_inode_security(trans, inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
                goto out_fail;
  
@@@ -4959,10 -4931,8 +4960,10 @@@ static noinline int uncompress_inline(s
        size_t max_size;
        unsigned long inline_size;
        unsigned long ptr;
 +      int compress_type;
  
        WARN_ON(pg_offset != 0);
 +      compress_type = btrfs_file_extent_compression(leaf, item);
        max_size = btrfs_file_extent_ram_bytes(leaf, item);
        inline_size = btrfs_file_extent_inline_item_len(leaf,
                                        btrfs_item_nr(leaf, path->slots[0]));
        read_extent_buffer(leaf, tmp, ptr, inline_size);
  
        max_size = min_t(unsigned long, PAGE_CACHE_SIZE, max_size);
 -      ret = btrfs_zlib_decompress(tmp, page, extent_offset,
 -                                  inline_size, max_size);
 +      ret = btrfs_decompress(compress_type, tmp, page,
 +                             extent_offset, inline_size, max_size);
        if (ret) {
                char *kaddr = kmap_atomic(page, KM_USER0);
                unsigned long copy_size = min_t(u64,
@@@ -5015,7 -4985,7 +5016,7 @@@ struct extent_map *btrfs_get_extent(str
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct btrfs_trans_handle *trans = NULL;
 -      int compressed;
 +      int compress_type;
  
  again:
        read_lock(&em_tree->lock);
  
        found_type = btrfs_file_extent_type(leaf, item);
        extent_start = found_key.offset;
 -      compressed = btrfs_file_extent_compression(leaf, item);
 +      compress_type = btrfs_file_extent_compression(leaf, item);
        if (found_type == BTRFS_FILE_EXTENT_REG ||
            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
                extent_end = extent_start +
                        em->block_start = EXTENT_MAP_HOLE;
                        goto insert;
                }
 -              if (compressed) {
 +              if (compress_type != BTRFS_COMPRESS_NONE) {
                        set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
 +                      em->compress_type = compress_type;
                        em->block_start = bytenr;
                        em->block_len = btrfs_file_extent_disk_num_bytes(leaf,
                                                                         item);
                em->len = (copy_size + root->sectorsize - 1) &
                        ~((u64)root->sectorsize - 1);
                em->orig_start = EXTENT_MAP_INLINE;
 -              if (compressed)
 +              if (compress_type) {
                        set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
 +                      em->compress_type = compress_type;
 +              }
                ptr = btrfs_file_extent_inline_start(item) + extent_offset;
                if (create == 0 && !PageUptodate(page)) {
 -                      if (btrfs_file_extent_compression(leaf, item) ==
 -                          BTRFS_COMPRESS_ZLIB) {
 +                      if (btrfs_file_extent_compression(leaf, item) !=
 +                          BTRFS_COMPRESS_NONE) {
                                ret = uncompress_inline(path, inode, page,
                                                        pg_offset,
                                                        extent_offset, item);
                                em = NULL;
                                btrfs_release_path(root, path);
                                trans = btrfs_join_transaction(root, 1);
 +                              if (IS_ERR(trans))
 +                                      return ERR_CAST(trans);
                                goto again;
                        }
                        map = kmap(page);
        return em;
  }
  
 +struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
 +                                         size_t pg_offset, u64 start, u64 len,
 +                                         int create)
 +{
 +      struct extent_map *em;
 +      struct extent_map *hole_em = NULL;
 +      u64 range_start = start;
 +      u64 end;
 +      u64 found;
 +      u64 found_end;
 +      int err = 0;
 +
 +      em = btrfs_get_extent(inode, page, pg_offset, start, len, create);
 +      if (IS_ERR(em))
 +              return em;
 +      if (em) {
 +              /*
 +               * if our em maps to a hole, there might
 +               * actually be delalloc bytes behind it
 +               */
 +              if (em->block_start != EXTENT_MAP_HOLE)
 +                      return em;
 +              else
 +                      hole_em = em;
 +      }
 +
 +      /* check to see if we've wrapped (len == -1 or similar) */
 +      end = start + len;
 +      if (end < start)
 +              end = (u64)-1;
 +      else
 +              end -= 1;
 +
 +      em = NULL;
 +
 +      /* ok, we didn't find anything, lets look for delalloc */
 +      found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start,
 +                               end, len, EXTENT_DELALLOC, 1);
 +      found_end = range_start + found;
 +      if (found_end < range_start)
 +              found_end = (u64)-1;
 +
 +      /*
 +       * we didn't find anything useful, return
 +       * the original results from get_extent()
 +       */
 +      if (range_start > end || found_end <= start) {
 +              em = hole_em;
 +              hole_em = NULL;
 +              goto out;
 +      }
 +
 +      /* adjust the range_start to make sure it doesn't
 +       * go backwards from the start they passed in
 +       */
 +      range_start = max(start,range_start);
 +      found = found_end - range_start;
 +
 +      if (found > 0) {
 +              u64 hole_start = start;
 +              u64 hole_len = len;
 +
 +              em = alloc_extent_map(GFP_NOFS);
 +              if (!em) {
 +                      err = -ENOMEM;
 +                      goto out;
 +              }
 +              /*
 +               * when btrfs_get_extent can't find anything it
 +               * returns one huge hole
 +               *
 +               * make sure what it found really fits our range, and
 +               * adjust to make sure it is based on the start from
 +               * the caller
 +               */
 +              if (hole_em) {
 +                      u64 calc_end = extent_map_end(hole_em);
 +
 +                      if (calc_end <= start || (hole_em->start > end)) {
 +                              free_extent_map(hole_em);
 +                              hole_em = NULL;
 +                      } else {
 +                              hole_start = max(hole_em->start, start);
 +                              hole_len = calc_end - hole_start;
 +                      }
 +              }
 +              em->bdev = NULL;
 +              if (hole_em && range_start > hole_start) {
 +                      /* our hole starts before our delalloc, so we
 +                       * have to return just the parts of the hole
 +                       * that go until  the delalloc starts
 +                       */
 +                      em->len = min(hole_len,
 +                                    range_start - hole_start);
 +                      em->start = hole_start;
 +                      em->orig_start = hole_start;
 +                      /*
 +                       * don't adjust block start at all,
 +                       * it is fixed at EXTENT_MAP_HOLE
 +                       */
 +                      em->block_start = hole_em->block_start;
 +                      em->block_len = hole_len;
 +              } else {
 +                      em->start = range_start;
 +                      em->len = found;
 +                      em->orig_start = range_start;
 +                      em->block_start = EXTENT_MAP_DELALLOC;
 +                      em->block_len = found;
 +              }
 +      } else if (hole_em) {
 +              return hole_em;
 +      }
 +out:
 +
 +      free_extent_map(hole_em);
 +      if (err) {
 +              free_extent_map(em);
 +              return ERR_PTR(err);
 +      }
 +      return em;
 +}
 +
  static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
                                                  u64 start, u64 len)
  {
        btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
  
        trans = btrfs_join_transaction(root, 0);
 -      if (!trans)
 -              return ERR_PTR(-ENOMEM);
 +      if (IS_ERR(trans))
 +              return ERR_CAST(trans);
  
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
@@@ -5641,7 -5484,7 +5642,7 @@@ static int btrfs_get_blocks_direct(stru
                 * while we look for nocow cross refs
                 */
                trans = btrfs_join_transaction(root, 0);
 -              if (!trans)
 +              if (IS_ERR(trans))
                        goto must_cow;
  
                if (can_nocow_odirect(trans, inode, start, len) == 1) {
@@@ -5776,7 -5619,7 +5777,7 @@@ again
        BUG_ON(!ordered);
  
        trans = btrfs_join_transaction(root, 1);
 -      if (!trans) {
 +      if (IS_ERR(trans)) {
                err = -ENOMEM;
                goto out;
        }
@@@ -6224,7 -6067,7 +6225,7 @@@ out
  static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len)
  {
 -      return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent);
 +      return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
  }
  
  int btrfs_readpage(struct file *file, struct page *page)
@@@ -6637,7 -6480,7 +6638,7 @@@ struct inode *btrfs_alloc_inode(struct 
        ei->ordered_data_close = 0;
        ei->orphan_meta_reserved = 0;
        ei->dummy_inode = 0;
 -      ei->force_compress = 0;
 +      ei->force_compress = BTRFS_COMPRESS_NONE;
  
        inode = &ei->vfs_inode;
        extent_map_tree_init(&ei->extent_tree, GFP_NOFS);
@@@ -7104,7 -6947,7 +7105,7 @@@ static int btrfs_symlink(struct inode *
        if (IS_ERR(inode))
                goto out_unlock;
  
-       err = btrfs_init_inode_security(trans, inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@@ -7258,6 -7101,112 +7259,6 @@@ int btrfs_prealloc_file_range_trans(str
                                           min_size, actual_len, alloc_hint, trans);
  }
  
 -static long btrfs_fallocate(struct inode *inode, int mode,
 -                          loff_t offset, loff_t len)
 -{
 -      struct extent_state *cached_state = NULL;
 -      u64 cur_offset;
 -      u64 last_byte;
 -      u64 alloc_start;
 -      u64 alloc_end;
 -      u64 alloc_hint = 0;
 -      u64 locked_end;
 -      u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
 -      struct extent_map *em;
 -      int ret;
 -
 -      alloc_start = offset & ~mask;
 -      alloc_end =  (offset + len + mask) & ~mask;
 -
 -      /*
 -       * wait for ordered IO before we have any locks.  We'll loop again
 -       * below with the locks held.
 -       */
 -      btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
 -
 -      mutex_lock(&inode->i_mutex);
 -      ret = inode_newsize_ok(inode, alloc_end);
 -      if (ret)
 -              goto out;
 -
 -      if (alloc_start > inode->i_size) {
 -              ret = btrfs_cont_expand(inode, alloc_start);
 -              if (ret)
 -                      goto out;
 -      }
 -
 -      ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
 -      if (ret)
 -              goto out;
 -
 -      locked_end = alloc_end - 1;
 -      while (1) {
 -              struct btrfs_ordered_extent *ordered;
 -
 -              /* the extent lock is ordered inside the running
 -               * transaction
 -               */
 -              lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start,
 -                               locked_end, 0, &cached_state, GFP_NOFS);
 -              ordered = btrfs_lookup_first_ordered_extent(inode,
 -                                                          alloc_end - 1);
 -              if (ordered &&
 -                  ordered->file_offset + ordered->len > alloc_start &&
 -                  ordered->file_offset < alloc_end) {
 -                      btrfs_put_ordered_extent(ordered);
 -                      unlock_extent_cached(&BTRFS_I(inode)->io_tree,
 -                                           alloc_start, locked_end,
 -                                           &cached_state, GFP_NOFS);
 -                      /*
 -                       * we can't wait on the range with the transaction
 -                       * running or with the extent lock held
 -                       */
 -                      btrfs_wait_ordered_range(inode, alloc_start,
 -                                               alloc_end - alloc_start);
 -              } else {
 -                      if (ordered)
 -                              btrfs_put_ordered_extent(ordered);
 -                      break;
 -              }
 -      }
 -
 -      cur_offset = alloc_start;
 -      while (1) {
 -              em = btrfs_get_extent(inode, NULL, 0, cur_offset,
 -                                    alloc_end - cur_offset, 0);
 -              BUG_ON(IS_ERR(em) || !em);
 -              last_byte = min(extent_map_end(em), alloc_end);
 -              last_byte = (last_byte + mask) & ~mask;
 -              if (em->block_start == EXTENT_MAP_HOLE ||
 -                  (cur_offset >= inode->i_size &&
 -                   !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
 -                      ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
 -                                                      last_byte - cur_offset,
 -                                                      1 << inode->i_blkbits,
 -                                                      offset + len,
 -                                                      &alloc_hint);
 -                      if (ret < 0) {
 -                              free_extent_map(em);
 -                              break;
 -                      }
 -              }
 -              free_extent_map(em);
 -
 -              cur_offset = last_byte;
 -              if (cur_offset >= alloc_end) {
 -                      ret = 0;
 -                      break;
 -              }
 -      }
 -      unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
 -                           &cached_state, GFP_NOFS);
 -
 -      btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
 -out:
 -      mutex_unlock(&inode->i_mutex);
 -      return ret;
 -}
 -
  static int btrfs_set_page_dirty(struct page *page)
  {
        return __set_page_dirty_nobuffers(page);
  
  static int btrfs_permission(struct inode *inode, int mask, unsigned int flags)
  {
 +      struct btrfs_root *root = BTRFS_I(inode)->root;
 +
 +      if (btrfs_root_readonly(root) && (mask & MAY_WRITE))
 +              return -EROFS;
        if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
                return -EACCES;
        return generic_permission(inode, mask, flags, btrfs_check_acl);
@@@ -7364,6 -7309,7 +7365,6 @@@ static const struct inode_operations bt
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
 -      .fallocate      = btrfs_fallocate,
        .fiemap         = btrfs_fiemap,
  };
  static const struct inode_operations btrfs_special_inode_operations = {
diff --combined fs/btrfs/xattr.c
@@@ -316,15 -316,6 +316,15 @@@ ssize_t btrfs_getxattr(struct dentry *d
  int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                   size_t size, int flags)
  {
 +      struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
 +
 +      /*
 +       * The permission on security.* and system.* is not checked
 +       * in permission().
 +       */
 +      if (btrfs_root_readonly(root))
 +              return -EROFS;
 +
        /*
         * If this is a request for a synthetic attribute in the system.*
         * namespace use the generic infrastructure to resolve a handler
  
  int btrfs_removexattr(struct dentry *dentry, const char *name)
  {
 +      struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
 +
 +      /*
 +       * The permission on security.* and system.* is not checked
 +       * in permission().
 +       */
 +      if (btrfs_root_readonly(root))
 +              return -EROFS;
 +
        /*
         * If this is a request for a synthetic attribute in the system.*
         * namespace use the generic infrastructure to resolve a handler
  }
  
  int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
-                             struct inode *inode, struct inode *dir)
+                             struct inode *inode, struct inode *dir,
+                             const struct qstr *qstr)
  {
        int err;
        size_t len;
        char *suffix;
        char *name;
  
-       err = security_inode_init_security(inode, dir, &suffix, &value, &len);
+       err = security_inode_init_security(inode, dir, qstr, &suffix, &value,
+                                          &len);
        if (err) {
                if (err == -EOPNOTSUPP)
                        return 0;
diff --combined fs/ext2/namei.c
@@@ -67,7 -67,7 +67,7 @@@ static struct dentry *ext2_lookup(struc
        inode = NULL;
        if (ino) {
                inode = ext2_iget(dir->i_sb, ino);
 -              if (unlikely(IS_ERR(inode))) {
 +              if (IS_ERR(inode)) {
                        if (PTR_ERR(inode) == -ESTALE) {
                                ext2_error(dir->i_sb, __func__,
                                                "deleted inode referenced: %lu",
@@@ -104,7 -104,7 +104,7 @@@ static int ext2_create (struct inode * 
  
        dquot_initialize(dir);
  
-       inode = ext2_new_inode(dir, mode);
+       inode = ext2_new_inode(dir, mode, &dentry->d_name);
        if (IS_ERR(inode))
                return PTR_ERR(inode);
  
@@@ -133,7 -133,7 +133,7 @@@ static int ext2_mknod (struct inode * d
  
        dquot_initialize(dir);
  
-       inode = ext2_new_inode (dir, mode);
+       inode = ext2_new_inode (dir, mode, &dentry->d_name);
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                init_special_inode(inode, inode->i_mode, rdev);
@@@ -159,7 -159,7 +159,7 @@@ static int ext2_symlink (struct inode 
  
        dquot_initialize(dir);
  
-       inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO);
+       inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out;
@@@ -230,7 -230,7 +230,7 @@@ static int ext2_mkdir(struct inode * di
  
        inode_inc_link_count(dir);
  
-       inode = ext2_new_inode (dir, S_IFDIR | mode);
+       inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out_dir;
@@@ -344,6 -344,7 +344,6 @@@ static int ext2_rename (struct inode * 
                new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
 -              inode_inc_link_count(old_inode);
                ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
                        if (new_dir->i_nlink >= EXT2_LINK_MAX)
                                goto out_dir;
                }
 -              inode_inc_link_count(old_inode);
                err = ext2_add_link(new_dentry, old_inode);
 -              if (err) {
 -                      inode_dec_link_count(old_inode);
 +              if (err)
                        goto out_dir;
 -              }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
        /*
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
 -       * inode_dec_link_count() will mark the inode dirty.
         */
        old_inode->i_ctime = CURRENT_TIME_SEC;
 +      mark_inode_dirty(old_inode);
  
        ext2_delete_entry (old_de, old_page);
 -      inode_dec_link_count(old_inode);
  
        if (dir_de) {
                if (old_dir != new_dir)
diff --combined fs/ext3/namei.c
@@@ -858,7 -858,6 +858,7 @@@ static struct buffer_head *ext3_find_en
        struct buffer_head * bh_use[NAMEI_RA_SIZE];
        struct buffer_head * bh, *ret = NULL;
        unsigned long start, block, b;
 +      const u8 *name = entry->name;
        int ra_max = 0;         /* Number of bh's in the readahead
                                   buffer, bh_use[] */
        int ra_ptr = 0;         /* Current index into readahead
        namelen = entry->len;
        if (namelen > EXT3_NAME_LEN)
                return NULL;
 +      if ((namelen <= 2) && (name[0] == '.') &&
 +          (name[1] == '.' || name[1] == 0)) {
 +              /*
 +               * "." or ".." will only be in the first block
 +               * NFS may look up ".."; "." should be handled by the VFS
 +               */
 +              block = start = 0;
 +              nblocks = 1;
 +              goto restart;
 +      }
        if (is_dx(dir)) {
                bh = ext3_dx_find_entry(dir, entry, res_dir, &err);
                /*
@@@ -972,35 -961,55 +972,35 @@@ static struct buffer_head * ext3_dx_fin
                        struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
                        int *err)
  {
 -      struct super_block * sb;
 +      struct super_block *sb = dir->i_sb;
        struct dx_hash_info     hinfo;
 -      u32 hash;
        struct dx_frame frames[2], *frame;
 -      struct ext3_dir_entry_2 *de, *top;
        struct buffer_head *bh;
        unsigned long block;
        int retval;
 -      int namelen = entry->len;
 -      const u8 *name = entry->name;
  
 -      sb = dir->i_sb;
 -      /* NFS may look up ".." - look at dx_root directory block */
 -      if (namelen > 2 || name[0] != '.'|| (namelen == 2 && name[1] != '.')) {
 -              if (!(frame = dx_probe(entry, dir, &hinfo, frames, err)))
 -                      return NULL;
 -      } else {
 -              frame = frames;
 -              frame->bh = NULL;                       /* for dx_release() */
 -              frame->at = (struct dx_entry *)frames;  /* hack for zero entry*/
 -              dx_set_block(frame->at, 0);             /* dx_root block is 0 */
 -      }
 -      hash = hinfo.hash;
 +      if (!(frame = dx_probe(entry, dir, &hinfo, frames, err)))
 +              return NULL;
        do {
                block = dx_get_block(frame->at);
                if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
                        goto errout;
 -              de = (struct ext3_dir_entry_2 *) bh->b_data;
 -              top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize -
 -                                     EXT3_DIR_REC_LEN(0));
 -              for (; de < top; de = ext3_next_entry(de)) {
 -                      int off = (block << EXT3_BLOCK_SIZE_BITS(sb))
 -                                + ((char *) de - bh->b_data);
 -
 -                      if (!ext3_check_dir_entry(__func__, dir, de, bh, off)) {
 -                              brelse(bh);
 -                              *err = ERR_BAD_DX_DIR;
 -                              goto errout;
 -                      }
  
 -                      if (ext3_match(namelen, name, de)) {
 -                              *res_dir = de;
 -                              dx_release(frames);
 -                              return bh;
 -                      }
 +              retval = search_dirblock(bh, dir, entry,
 +                                       block << EXT3_BLOCK_SIZE_BITS(sb),
 +                                       res_dir);
 +              if (retval == 1) {
 +                      dx_release(frames);
 +                      return bh;
                }
 -              brelse (bh);
 +              brelse(bh);
 +              if (retval == -1) {
 +                      *err = ERR_BAD_DX_DIR;
 +                      goto errout;
 +              }
 +
                /* Check to see if we should continue to search */
 -              retval = ext3_htree_next_block(dir, hash, frame,
 +              retval = ext3_htree_next_block(dir, hinfo.hash, frame,
                                               frames, NULL);
                if (retval < 0) {
                        ext3_warning(sb, __func__,
@@@ -1038,7 -1047,7 +1038,7 @@@ static struct dentry *ext3_lookup(struc
                        return ERR_PTR(-EIO);
                }
                inode = ext3_iget(dir->i_sb, ino);
 -              if (unlikely(IS_ERR(inode))) {
 +              if (IS_ERR(inode)) {
                        if (PTR_ERR(inode) == -ESTALE) {
                                ext3_error(dir->i_sb, __func__,
                                                "deleted inode referenced: %lu",
@@@ -1598,9 -1607,7 +1598,9 @@@ static int ext3_dx_add_entry(handle_t *
                        if (err)
                                goto journal_error;
                }
 -              ext3_journal_dirty_metadata(handle, frames[0].bh);
 +              err = ext3_journal_dirty_metadata(handle, frames[0].bh);
 +              if (err)
 +                      goto journal_error;
        }
        de = do_split(handle, dir, &bh, frame, &hinfo, &err);
        if (!de)
@@@ -1637,13 -1644,8 +1637,13 @@@ static int ext3_delete_entry (handle_t 
                if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i))
                        return -EIO;
                if (de == de_del)  {
 +                      int err;
 +
                        BUFFER_TRACE(bh, "get_write_access");
 -                      ext3_journal_get_write_access(handle, bh);
 +                      err = ext3_journal_get_write_access(handle, bh);
 +                      if (err)
 +                              goto journal_error;
 +
                        if (pde)
                                pde->rec_len = ext3_rec_len_to_disk(
                                        ext3_rec_len_from_disk(pde->rec_len) +
                                de->inode = 0;
                        dir->i_version++;
                        BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 -                      ext3_journal_dirty_metadata(handle, bh);
 +                      err = ext3_journal_dirty_metadata(handle, bh);
 +                      if (err) {
 +journal_error:
 +                              ext3_std_error(dir->i_sb, err);
 +                              return err;
 +                      }
                        return 0;
                }
                i += ext3_rec_len_from_disk(de->rec_len);
@@@ -1710,7 -1707,7 +1710,7 @@@ retry
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
  
-       inode = ext3_new_inode (handle, dir, mode);
+       inode = ext3_new_inode (handle, dir, &dentry->d_name, mode);
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                inode->i_op = &ext3_file_inode_operations;
@@@ -1746,7 -1743,7 +1746,7 @@@ retry
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
  
-       inode = ext3_new_inode (handle, dir, mode);
+       inode = ext3_new_inode (handle, dir, &dentry->d_name, mode);
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                init_special_inode(inode, inode->i_mode, rdev);
@@@ -1765,7 -1762,7 +1765,7 @@@ static int ext3_mkdir(struct inode * di
  {
        handle_t *handle;
        struct inode * inode;
 -      struct buffer_head * dir_block;
 +      struct buffer_head * dir_block = NULL;
        struct ext3_dir_entry_2 * de;
        int err, retries = 0;
  
@@@ -1784,7 -1781,7 +1784,7 @@@ retry
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
  
-       inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
+       inode = ext3_new_inode (handle, dir, &dentry->d_name, S_IFDIR | mode);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out_stop;
        inode->i_fop = &ext3_dir_operations;
        inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
        dir_block = ext3_bread (handle, inode, 0, 1, &err);
 -      if (!dir_block) {
 -              drop_nlink(inode); /* is this nlink == 0? */
 -              unlock_new_inode(inode);
 -              ext3_mark_inode_dirty(handle, inode);
 -              iput (inode);
 -              goto out_stop;
 -      }
 +      if (!dir_block)
 +              goto out_clear_inode;
 +
        BUFFER_TRACE(dir_block, "get_write_access");
 -      ext3_journal_get_write_access(handle, dir_block);
 +      err = ext3_journal_get_write_access(handle, dir_block);
 +      if (err)
 +              goto out_clear_inode;
 +
        de = (struct ext3_dir_entry_2 *) dir_block->b_data;
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
        ext3_set_de_type(dir->i_sb, de, S_IFDIR);
        inode->i_nlink = 2;
        BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
 -      ext3_journal_dirty_metadata(handle, dir_block);
 -      brelse (dir_block);
 -      ext3_mark_inode_dirty(handle, inode);
 -      err = ext3_add_entry (handle, dentry, inode);
 +      err = ext3_journal_dirty_metadata(handle, dir_block);
 +      if (err)
 +              goto out_clear_inode;
 +
 +      err = ext3_mark_inode_dirty(handle, inode);
 +      if (!err)
 +              err = ext3_add_entry (handle, dentry, inode);
 +
        if (err) {
 +out_clear_inode:
                inode->i_nlink = 0;
                unlock_new_inode(inode);
                ext3_mark_inode_dirty(handle, inode);
        }
        inc_nlink(dir);
        ext3_update_dx_flag(dir);
 -      ext3_mark_inode_dirty(handle, dir);
 +      err = ext3_mark_inode_dirty(handle, dir);
 +      if (err)
 +              goto out_clear_inode;
 +
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
  out_stop:
 +      brelse(dir_block);
        ext3_journal_stop(handle);
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
@@@ -2206,7 -2195,7 +2206,7 @@@ retry
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
  
-       inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
+       inode = ext3_new_inode (handle, dir, &dentry->d_name, S_IFLNK|S_IRWXUGO);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out_stop;
@@@ -2364,9 -2353,7 +2364,9 @@@ static int ext3_rename (struct inode * 
                        goto end_rename;
        } else {
                BUFFER_TRACE(new_bh, "get write access");
 -              ext3_journal_get_write_access(handle, new_bh);
 +              retval = ext3_journal_get_write_access(handle, new_bh);
 +              if (retval)
 +                      goto journal_error;
                new_de->inode = cpu_to_le32(old_inode->i_ino);
                if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
                                              EXT3_FEATURE_INCOMPAT_FILETYPE))
                new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME_SEC;
                ext3_mark_inode_dirty(handle, new_dir);
                BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata");
 -              ext3_journal_dirty_metadata(handle, new_bh);
 +              retval = ext3_journal_dirty_metadata(handle, new_bh);
 +              if (retval)
 +                      goto journal_error;
                brelse(new_bh);
                new_bh = NULL;
        }
        ext3_update_dx_flag(old_dir);
        if (dir_bh) {
                BUFFER_TRACE(dir_bh, "get_write_access");
 -              ext3_journal_get_write_access(handle, dir_bh);
 +              retval = ext3_journal_get_write_access(handle, dir_bh);
 +              if (retval)
 +                      goto journal_error;
                PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata");
 -              ext3_journal_dirty_metadata(handle, dir_bh);
 +              retval = ext3_journal_dirty_metadata(handle, dir_bh);
 +              if (retval) {
 +journal_error:
 +                      ext3_std_error(new_dir->i_sb, retval);
 +                      goto end_rename;
 +              }
                drop_nlink(old_dir);
                if (new_inode) {
                        drop_nlink(new_inode);
diff --combined fs/ext4/ialloc.c
@@@ -1027,7 -1027,7 +1027,7 @@@ got
        inode->i_generation = sbi->s_next_generation++;
        spin_unlock(&sbi->s_next_gen_lock);
  
 -      ei->i_state_flags = 0;
 +      ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
        ext4_set_inode_state(inode, EXT4_STATE_NEW);
  
        ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
        if (err)
                goto fail_free_drop;
  
-       err = ext4_init_security(handle, inode, dir);
+       err = ext4_init_security(handle, inode, dir, qstr);
        if (err)
                goto fail_free_drop;
  
diff --combined fs/gfs2/inode.c
@@@ -74,14 -74,16 +74,14 @@@ static struct inode *gfs2_iget(struct s
  }
  
  /**
 - * GFS2 lookup code fills in vfs inode contents based on info obtained
 - * from directory entry inside gfs2_inode_lookup(). This has caused issues
 - * with NFS code path since its get_dentry routine doesn't have the relevant
 - * directory entry when gfs2_inode_lookup() is invoked. Part of the code
 - * segment inside gfs2_inode_lookup code needs to get moved around.
 + * gfs2_set_iop - Sets inode operations
 + * @inode: The inode with correct i_mode filled in
   *
 - * Clears I_NEW as well.
 - **/
 + * GFS2 lookup code fills in vfs inode contents based on info obtained
 + * from directory entry inside gfs2_inode_lookup().
 + */
  
 -void gfs2_set_iop(struct inode *inode)
 +static void gfs2_set_iop(struct inode *inode)
  {
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        umode_t mode = inode->i_mode;
                inode->i_op = &gfs2_file_iops;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
        }
 -
 -      unlock_new_inode(inode);
  }
  
  /**
   * Returns: A VFS inode, or an error
   */
  
 -struct inode *gfs2_inode_lookup(struct super_block *sb,
 -                              unsigned int type,
 -                              u64 no_addr,
 -                              u64 no_formal_ino)
 +struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
 +                              u64 no_addr, u64 no_formal_ino)
  {
        struct inode *inode;
        struct gfs2_inode *ip;
                error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
                if (unlikely(error))
                        goto fail_iopen;
 -              ip->i_iopen_gh.gh_gl->gl_object = ip;
  
 +              ip->i_iopen_gh.gh_gl->gl_object = ip;
                gfs2_glock_put(io_gl);
                io_gl = NULL;
  
 -              if ((type == DT_UNKNOWN) && (no_formal_ino == 0))
 -                      goto gfs2_nfsbypass;
 -
 -              inode->i_mode = DT2IF(type);
 -
 -              /*
 -               * We must read the inode in order to work out its type in
 -               * this case. Note that this doesn't happen often as we normally
 -               * know the type beforehand. This code path only occurs during
 -               * unlinked inode recovery (where it is safe to do this glock,
 -               * which is not true in the general case).
 -               */
                if (type == DT_UNKNOWN) {
 -                      struct gfs2_holder gh;
 -                      error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
 -                      if (unlikely(error))
 -                              goto fail_glock;
 -                      /* Inode is now uptodate */
 -                      gfs2_glock_dq_uninit(&gh);
 +                      /* Inode glock must be locked already */
 +                      error = gfs2_inode_refresh(GFS2_I(inode));
 +                      if (error)
 +                              goto fail_refresh;
 +              } else {
 +                      inode->i_mode = DT2IF(type);
                }
  
                gfs2_set_iop(inode);
 +              unlock_new_inode(inode);
        }
  
 -gfs2_nfsbypass:
        return inode;
 -fail_glock:
 -      gfs2_glock_dq(&ip->i_iopen_gh);
 +
 +fail_refresh:
 +      ip->i_iopen_gh.gh_gl->gl_object = NULL;
 +      gfs2_glock_dq_uninit(&ip->i_iopen_gh);
  fail_iopen:
        if (io_gl)
                gfs2_glock_put(io_gl);
  fail_put:
 -      if (inode->i_state & I_NEW)
 -              ip->i_gl->gl_object = NULL;
 +      ip->i_gl->gl_object = NULL;
        gfs2_glock_put(ip->i_gl);
  fail:
 -      if (inode->i_state & I_NEW)
 -              iget_failed(inode);
 -      else
 -              iput(inode);
 +      iget_failed(inode);
        return ERR_PTR(error);
  }
  
@@@ -201,6 -221,14 +201,6 @@@ struct inode *gfs2_lookup_by_inum(struc
        if (IS_ERR(inode))
                goto fail;
  
 -      error = gfs2_inode_refresh(GFS2_I(inode));
 -      if (error)
 -              goto fail_iput;
 -
 -      /* Pick up the works we bypass in gfs2_inode_lookup */
 -      if (inode->i_state & I_NEW) 
 -              gfs2_set_iop(inode);
 -
        /* Two extra checks for NFS only */
        if (no_formal_ino) {
                error = -ESTALE;
@@@ -763,14 -791,15 +763,15 @@@ fail
        return error;
  }
  
- static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
+ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
+                             const struct qstr *qstr)
  {
        int err;
        size_t len;
        void *value;
        char *name;
  
-       err = security_inode_init_security(&ip->i_inode, &dip->i_inode,
+       err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
                                           &name, &value, &len);
  
        if (err) {
@@@ -854,7 -883,7 +855,7 @@@ struct inode *gfs2_createi(struct gfs2_
        if (error)
                goto fail_gunlock2;
  
-       error = gfs2_security_init(dip, GFS2_I(inode));
+       error = gfs2_security_init(dip, GFS2_I(inode), name);
        if (error)
                goto fail_gunlock2;
  
diff --combined fs/jfs/namei.c
@@@ -115,7 -115,7 +115,7 @@@ static int jfs_create(struct inode *dip
        if (rc)
                goto out3;
  
-       rc = jfs_init_security(tid, ip, dip);
+       rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
        if (rc) {
                txAbort(tid, 0);
                goto out3;
@@@ -253,7 -253,7 +253,7 @@@ static int jfs_mkdir(struct inode *dip
        if (rc)
                goto out3;
  
-       rc = jfs_init_security(tid, ip, dip);
+       rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
        if (rc) {
                txAbort(tid, 0);
                goto out3;
@@@ -932,7 -932,7 +932,7 @@@ static int jfs_symlink(struct inode *di
        mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
        mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
  
-       rc = jfs_init_security(tid, ip, dip);
+       rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
        if (rc)
                goto out3;
  
@@@ -1395,7 -1395,7 +1395,7 @@@ static int jfs_mknod(struct inode *dir
        if (rc)
                goto out3;
  
-       rc = jfs_init_security(tid, ip, dir);
+       rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
        if (rc) {
                txAbort(tid, 0);
                goto out3;
@@@ -1465,6 -1465,9 +1465,6 @@@ static struct dentry *jfs_lookup(struc
  
        jfs_info("jfs_lookup: name = %s", name);
  
 -      if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
 -              d_set_d_op(dentry, &jfs_ci_dentry_operations);
 -
        if ((name[0] == '.') && (len == 1))
                inum = dip->i_ino;
        else if (strcmp(name, "..") == 0)
                return ERR_CAST(ip);
        }
  
 -      dentry = d_splice_alias(ip, dentry);
 -
 -      if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
 -              d_set_d_op(dentry, &jfs_ci_dentry_operations);
 -
 -      return dentry;
 +      return d_splice_alias(ip, dentry);
  }
  
  static struct inode *jfs_nfs_get_inode(struct super_block *sb,
diff --combined fs/namespace.c
@@@ -183,7 -183,7 +183,7 @@@ static inline void mnt_dec_count(struc
  unsigned int mnt_get_count(struct vfsmount *mnt)
  {
  #ifdef CONFIG_SMP
 -      unsigned int count = atomic_read(&mnt->mnt_longrefs);
 +      unsigned int count = 0;
        int cpu;
  
        for_each_possible_cpu(cpu) {
@@@ -217,7 -217,7 +217,7 @@@ struct vfsmount *alloc_vfsmnt(const cha
                if (!mnt->mnt_pcp)
                        goto out_free_devname;
  
 -              atomic_set(&mnt->mnt_longrefs, 1);
 +              this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
  #else
                mnt->mnt_count = 1;
                mnt->mnt_writers = 0;
@@@ -611,21 -611,6 +611,21 @@@ static void attach_mnt(struct vfsmount 
        list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts);
  }
  
 +static inline void __mnt_make_longterm(struct vfsmount *mnt)
 +{
 +#ifdef CONFIG_SMP
 +      atomic_inc(&mnt->mnt_longterm);
 +#endif
 +}
 +
 +/* needs vfsmount lock for write */
 +static inline void __mnt_make_shortterm(struct vfsmount *mnt)
 +{
 +#ifdef CONFIG_SMP
 +      atomic_dec(&mnt->mnt_longterm);
 +#endif
 +}
 +
  /*
   * vfsmount lock must be held for write
   */
@@@ -639,11 -624,8 +639,11 @@@ static void commit_tree(struct vfsmoun
        BUG_ON(parent == mnt);
  
        list_add_tail(&head, &mnt->mnt_list);
 -      list_for_each_entry(m, &head, mnt_list)
 +      list_for_each_entry(m, &head, mnt_list) {
                m->mnt_ns = n;
 +              __mnt_make_longterm(m);
 +      }
 +
        list_splice(&head, n->list.prev);
  
        list_add_tail(&mnt->mnt_hash, mount_hashtable +
@@@ -752,30 -734,51 +752,30 @@@ static inline void mntfree(struct vfsmo
        deactivate_super(sb);
  }
  
 -#ifdef CONFIG_SMP
 -static inline void __mntput(struct vfsmount *mnt, int longrefs)
 +static void mntput_no_expire(struct vfsmount *mnt)
  {
 -      if (!longrefs) {
  put_again:
 -              br_read_lock(vfsmount_lock);
 -              if (likely(atomic_read(&mnt->mnt_longrefs))) {
 -                      mnt_dec_count(mnt);
 -                      br_read_unlock(vfsmount_lock);
 -                      return;
 -              }
 +#ifdef CONFIG_SMP
 +      br_read_lock(vfsmount_lock);
 +      if (likely(atomic_read(&mnt->mnt_longterm))) {
 +              mnt_dec_count(mnt);
                br_read_unlock(vfsmount_lock);
 -      } else {
 -              BUG_ON(!atomic_read(&mnt->mnt_longrefs));
 -              if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1))
 -                      return;
 +              return;
        }
 +      br_read_unlock(vfsmount_lock);
  
        br_write_lock(vfsmount_lock);
 -      if (!longrefs)
 -              mnt_dec_count(mnt);
 -      else
 -              atomic_dec(&mnt->mnt_longrefs);
 +      mnt_dec_count(mnt);
        if (mnt_get_count(mnt)) {
                br_write_unlock(vfsmount_lock);
                return;
        }
 -      if (unlikely(mnt->mnt_pinned)) {
 -              mnt_add_count(mnt, mnt->mnt_pinned + 1);
 -              mnt->mnt_pinned = 0;
 -              br_write_unlock(vfsmount_lock);
 -              acct_auto_close_mnt(mnt);
 -              goto put_again;
 -      }
 -      br_write_unlock(vfsmount_lock);
 -      mntfree(mnt);
 -}
  #else
 -static inline void __mntput(struct vfsmount *mnt, int longrefs)
 -{
 -put_again:
        mnt_dec_count(mnt);
        if (likely(mnt_get_count(mnt)))
                return;
        br_write_lock(vfsmount_lock);
 +#endif
        if (unlikely(mnt->mnt_pinned)) {
                mnt_add_count(mnt, mnt->mnt_pinned + 1);
                mnt->mnt_pinned = 0;
        br_write_unlock(vfsmount_lock);
        mntfree(mnt);
  }
 -#endif
 -
 -static void mntput_no_expire(struct vfsmount *mnt)
 -{
 -      __mntput(mnt, 0);
 -}
  
  void mntput(struct vfsmount *mnt)
  {
                /* avoid cacheline pingpong, hope gcc doesn't get "smart" */
                if (unlikely(mnt->mnt_expiry_mark))
                        mnt->mnt_expiry_mark = 0;
 -              __mntput(mnt, 0);
 +              mntput_no_expire(mnt);
        }
  }
  EXPORT_SYMBOL(mntput);
@@@ -806,6 -815,33 +806,6 @@@ struct vfsmount *mntget(struct vfsmoun
  }
  EXPORT_SYMBOL(mntget);
  
 -void mntput_long(struct vfsmount *mnt)
 -{
 -#ifdef CONFIG_SMP
 -      if (mnt) {
 -              /* avoid cacheline pingpong, hope gcc doesn't get "smart" */
 -              if (unlikely(mnt->mnt_expiry_mark))
 -                      mnt->mnt_expiry_mark = 0;
 -              __mntput(mnt, 1);
 -      }
 -#else
 -      mntput(mnt);
 -#endif
 -}
 -EXPORT_SYMBOL(mntput_long);
 -
 -struct vfsmount *mntget_long(struct vfsmount *mnt)
 -{
 -#ifdef CONFIG_SMP
 -      if (mnt)
 -              atomic_inc(&mnt->mnt_longrefs);
 -      return mnt;
 -#else
 -      return mntget(mnt);
 -#endif
 -}
 -EXPORT_SYMBOL(mntget_long);
 -
  void mnt_pin(struct vfsmount *mnt)
  {
        br_write_lock(vfsmount_lock);
@@@ -1180,7 -1216,7 +1180,7 @@@ void release_mounts(struct list_head *h
                        dput(dentry);
                        mntput(m);
                }
 -              mntput_long(mnt);
 +              mntput(mnt);
        }
  }
  
   */
  void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
  {
 +      LIST_HEAD(tmp_list);
        struct vfsmount *p;
  
        for (p = mnt; p; p = next_mnt(p, mnt))
 -              list_move(&p->mnt_hash, kill);
 +              list_move(&p->mnt_hash, &tmp_list);
  
        if (propagate)
 -              propagate_umount(kill);
 +              propagate_umount(&tmp_list);
  
 -      list_for_each_entry(p, kill, mnt_hash) {
 +      list_for_each_entry(p, &tmp_list, mnt_hash) {
                list_del_init(&p->mnt_expire);
                list_del_init(&p->mnt_list);
                __touch_mnt_namespace(p->mnt_ns);
                p->mnt_ns = NULL;
 +              __mnt_make_shortterm(p);
                list_del_init(&p->mnt_child);
                if (p->mnt_parent != p) {
                        p->mnt_parent->mnt_ghosts++;
                }
                change_mnt_propagation(p, MS_PRIVATE);
        }
 +      list_splice(&tmp_list, kill);
  }
  
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);
@@@ -1244,7 -1277,7 +1244,7 @@@ static int do_umount(struct vfsmount *m
                 */
                br_write_lock(vfsmount_lock);
                if (mnt_get_count(mnt) != 2) {
 -                      br_write_lock(vfsmount_lock);
 +                      br_write_unlock(vfsmount_lock);
                        return -EBUSY;
                }
                br_write_unlock(vfsmount_lock);
@@@ -1767,6 -1800,10 +1767,10 @@@ static int do_remount(struct path *path
        if (path->dentry != path->mnt->mnt_root)
                return -EINVAL;
  
+       err = security_sb_remount(sb, data);
+       if (err)
+               return err;
        down_write(&sb->s_umount);
        if (flags & MS_BIND)
                err = change_mount_flags(path->mnt, flags);
@@@ -1811,10 -1848,9 +1815,10 @@@ static int do_move_mount(struct path *p
                return err;
  
        down_write(&namespace_sem);
 -      while (d_mountpoint(path->dentry) &&
 -             follow_down(path))
 -              ;
 +      err = follow_down(path, true);
 +      if (err < 0)
 +              goto out;
 +
        err = -EINVAL;
        if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
                goto out;
@@@ -1872,8 -1908,6 +1876,8 @@@ out
        return err;
  }
  
 +static int do_add_mount(struct vfsmount *, struct path *, int);
 +
  /*
   * create a new mount for userspace and request it to be added into the
   * namespace's tree
@@@ -1882,7 -1916,6 +1886,7 @@@ static int do_new_mount(struct path *pa
                        int mnt_flags, char *name, void *data)
  {
        struct vfsmount *mnt;
 +      int err;
  
        if (!type)
                return -EINVAL;
        if (IS_ERR(mnt))
                return PTR_ERR(mnt);
  
 -      return do_add_mount(mnt, path, mnt_flags, NULL);
 +      err = do_add_mount(mnt, path, mnt_flags);
 +      if (err)
 +              mntput(mnt);
 +      return err;
 +}
 +
 +int finish_automount(struct vfsmount *m, struct path *path)
 +{
 +      int err;
 +      /* The new mount record should have at least 2 refs to prevent it being
 +       * expired before we get a chance to add it
 +       */
 +      BUG_ON(mnt_get_count(m) < 2);
 +
 +      if (m->mnt_sb == path->mnt->mnt_sb &&
 +          m->mnt_root == path->dentry) {
 +              err = -ELOOP;
 +              goto fail;
 +      }
 +
 +      err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
 +      if (!err)
 +              return 0;
 +fail:
 +      /* remove m from any expiration list it may be on */
 +      if (!list_empty(&m->mnt_expire)) {
 +              down_write(&namespace_sem);
 +              br_write_lock(vfsmount_lock);
 +              list_del_init(&m->mnt_expire);
 +              br_write_unlock(vfsmount_lock);
 +              up_write(&namespace_sem);
 +      }
 +      mntput(m);
 +      mntput(m);
 +      return err;
  }
  
  /*
   * add a mount into a namespace's mount tree
 - * - provide the option of adding the new mount to an expiration list
   */
 -int do_add_mount(struct vfsmount *newmnt, struct path *path,
 -               int mnt_flags, struct list_head *fslist)
 +static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
  {
        int err;
  
  
        down_write(&namespace_sem);
        /* Something was mounted here while we slept */
 -      while (d_mountpoint(path->dentry) &&
 -             follow_down(path))
 -              ;
 +      err = follow_down(path, true);
 +      if (err < 0)
 +              goto unlock;
 +
        err = -EINVAL;
        if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
                goto unlock;
                goto unlock;
  
        newmnt->mnt_flags = mnt_flags;
 -      if ((err = graft_tree(newmnt, path)))
 -              goto unlock;
 -
 -      if (fslist) /* add to the specified expiration list */
 -              list_add_tail(&newmnt->mnt_expire, fslist);
 -
 -      up_write(&namespace_sem);
 -      return 0;
 +      err = graft_tree(newmnt, path);
  
  unlock:
        up_write(&namespace_sem);
 -      mntput_long(newmnt);
        return err;
  }
  
 -EXPORT_SYMBOL_GPL(do_add_mount);
 +/**
 + * mnt_set_expiry - Put a mount on an expiration list
 + * @mnt: The mount to list.
 + * @expiry_list: The list to add the mount to.
 + */
 +void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
 +{
 +      down_write(&namespace_sem);
 +      br_write_lock(vfsmount_lock);
 +
 +      list_add_tail(&mnt->mnt_expire, expiry_list);
 +
 +      br_write_unlock(vfsmount_lock);
 +      up_write(&namespace_sem);
 +}
 +EXPORT_SYMBOL(mnt_set_expiry);
  
  /*
   * process a list of expirable mountpoints with the intent of discarding any
@@@ -2273,22 -2266,6 +2277,22 @@@ static struct mnt_namespace *alloc_mnt_
        return new_ns;
  }
  
 +void mnt_make_longterm(struct vfsmount *mnt)
 +{
 +      __mnt_make_longterm(mnt);
 +}
 +
 +void mnt_make_shortterm(struct vfsmount *mnt)
 +{
 +#ifdef CONFIG_SMP
 +      if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
 +              return;
 +      br_write_lock(vfsmount_lock);
 +      atomic_dec(&mnt->mnt_longterm);
 +      br_write_unlock(vfsmount_lock);
 +#endif
 +}
 +
  /*
   * Allocate a new namespace structure and populate it with contents
   * copied from the namespace of the passed in task structure.
@@@ -2326,19 -2303,14 +2330,19 @@@ static struct mnt_namespace *dup_mnt_ns
        q = new_ns->root;
        while (p) {
                q->mnt_ns = new_ns;
 +              __mnt_make_longterm(q);
                if (fs) {
                        if (p == fs->root.mnt) {
 +                              fs->root.mnt = mntget(q);
 +                              __mnt_make_longterm(q);
 +                              mnt_make_shortterm(p);
                                rootmnt = p;
 -                              fs->root.mnt = mntget_long(q);
                        }
                        if (p == fs->pwd.mnt) {
 +                              fs->pwd.mnt = mntget(q);
 +                              __mnt_make_longterm(q);
 +                              mnt_make_shortterm(p);
                                pwdmnt = p;
 -                              fs->pwd.mnt = mntget_long(q);
                        }
                }
                p = next_mnt(p, mnt_ns->root);
        up_write(&namespace_sem);
  
        if (rootmnt)
 -              mntput_long(rootmnt);
 +              mntput(rootmnt);
        if (pwdmnt)
 -              mntput_long(pwdmnt);
 +              mntput(pwdmnt);
  
        return new_ns;
  }
@@@ -2382,7 -2354,6 +2386,7 @@@ struct mnt_namespace *create_mnt_ns(str
        new_ns = alloc_mnt_ns();
        if (!IS_ERR(new_ns)) {
                mnt->mnt_ns = new_ns;
 +              __mnt_make_longterm(mnt);
                new_ns->root = mnt;
                list_add(&new_ns->list, &new_ns->root->mnt_list);
        }
diff --combined fs/ocfs2/namei.c
@@@ -147,6 -147,7 +147,6 @@@ static struct dentry *ocfs2_lookup(stru
        spin_unlock(&oi->ip_lock);
  
  bail_add:
 -      d_set_d_op(dentry, &ocfs2_dentry_ops);
        ret = d_splice_alias(inode, dentry);
  
        if (inode) {
@@@ -293,7 -294,7 +293,7 @@@ static int ocfs2_mknod(struct inode *di
        }
  
        /* get security xattr */
-       status = ocfs2_init_security_get(inode, dir, &si);
+       status = ocfs2_init_security_get(inode, dir, &dentry->d_name, &si);
        if (status) {
                if (status == -EOPNOTSUPP)
                        si.enable = 0;
                mlog_errno(status);
                goto leave;
        }
 -      d_set_d_op(dentry, &ocfs2_dentry_ops);
  
        status = ocfs2_add_entry(handle, dentry, inode,
                                 OCFS2_I(inode)->ip_blkno, parent_fe_bh,
@@@ -741,6 -743,7 +741,6 @@@ static int ocfs2_link(struct dentry *ol
        }
  
        ihold(inode);
 -      d_set_d_op(dentry, &ocfs2_dentry_ops);
        d_instantiate(dentry, inode);
  
  out_commit:
@@@ -1014,11 -1017,8 +1014,11 @@@ static int ocfs2_double_lock(struct ocf
                 * An error return must mean that no cluster locks
                 * were held on function exit.
                 */
 -              if (oi1->ip_blkno != oi2->ip_blkno)
 +              if (oi1->ip_blkno != oi2->ip_blkno) {
                        ocfs2_inode_unlock(inode2, 1);
 +                      brelse(*bh2);
 +                      *bh2 = NULL;
 +              }
  
                if (status != -ENOENT)
                        mlog_errno(status);
@@@ -1665,7 -1665,7 +1665,7 @@@ static int ocfs2_symlink(struct inode *
        }
  
        /* get security xattr */
-       status = ocfs2_init_security_get(inode, dir, &si);
+       status = ocfs2_init_security_get(inode, dir, &dentry->d_name, &si);
        if (status) {
                if (status == -EOPNOTSUPP)
                        si.enable = 0;
                mlog_errno(status);
                goto bail;
        }
 -      d_set_d_op(dentry, &ocfs2_dentry_ops);
  
        status = ocfs2_add_entry(handle, dentry, inode,
                                 le64_to_cpu(fe->i_blkno), parent_fe_bh,
@@@ -2458,6 -2459,7 +2458,6 @@@ int ocfs2_mv_orphaned_inode_to_new(stru
                goto out_commit;
        }
  
 -      d_set_d_op(dentry, &ocfs2_dentry_ops);
        d_instantiate(dentry, inode);
        status = 0;
  out_commit:
diff --combined fs/ocfs2/refcounttree.c
@@@ -3228,7 -3228,7 +3228,7 @@@ static int ocfs2_make_clusters_writable
                                        u32 num_clusters, unsigned int e_flags)
  {
        int ret, delete, index, credits =  0;
 -      u32 new_bit, new_len;
 +      u32 new_bit, new_len, orig_num_clusters;
        unsigned int set_len;
        struct ocfs2_super *osb = OCFS2_SB(sb);
        handle_t *handle;
                goto out;
        }
  
 +      orig_num_clusters = num_clusters;
 +
        while (num_clusters) {
                ret = ocfs2_get_refcount_rec(ref_ci, context->ref_root_bh,
                                             p_cluster, num_clusters,
         * in write-back mode.
         */
        if (context->get_clusters == ocfs2_di_get_clusters) {
 -              ret = ocfs2_cow_sync_writeback(sb, context, cpos, num_clusters);
 +              ret = ocfs2_cow_sync_writeback(sb, context, cpos,
 +                                             orig_num_clusters);
                if (ret)
                        mlog_errno(ret);
        }
@@@ -4328,7 -4325,8 +4328,8 @@@ static int ocfs2_reflink(struct dentry 
  
        /* If the security isn't preserved, we need to re-initialize them. */
        if (!preserve) {
-               error = ocfs2_init_security_and_acl(dir, new_orphan_inode);
+               error = ocfs2_init_security_and_acl(dir, new_orphan_inode,
+                                                   &new_dentry->d_name);
                if (error)
                        mlog_errno(error);
        }
diff --combined fs/reiserfs/namei.c
@@@ -593,7 -593,7 +593,7 @@@ static int reiserfs_create(struct inod
        new_inode_init(inode, dir, mode);
  
        jbegin_count += reiserfs_cache_default_acl(dir);
-       retval = reiserfs_security_init(dir, inode, &security);
+       retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
        if (retval < 0) {
                drop_new_inode(inode);
                return retval;
@@@ -667,7 -667,7 +667,7 @@@ static int reiserfs_mknod(struct inode 
        new_inode_init(inode, dir, mode);
  
        jbegin_count += reiserfs_cache_default_acl(dir);
-       retval = reiserfs_security_init(dir, inode, &security);
+       retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
        if (retval < 0) {
                drop_new_inode(inode);
                return retval;
@@@ -747,7 -747,7 +747,7 @@@ static int reiserfs_mkdir(struct inode 
        new_inode_init(inode, dir, mode);
  
        jbegin_count += reiserfs_cache_default_acl(dir);
-       retval = reiserfs_security_init(dir, inode, &security);
+       retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
        if (retval < 0) {
                drop_new_inode(inode);
                return retval;
                                        EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
                                        dentry, inode, &security);
        if (retval) {
 -              dir->i_nlink--;
 +              DEC_DIR_INODE_NLINK(dir)
                goto out_failed;
        }
  
@@@ -1032,7 -1032,8 +1032,8 @@@ static int reiserfs_symlink(struct inod
        }
        new_inode_init(inode, parent_dir, mode);
  
-       retval = reiserfs_security_init(parent_dir, inode, &security);
+       retval = reiserfs_security_init(parent_dir, inode, &dentry->d_name,
+                                       &security);
        if (retval < 0) {
                drop_new_inode(inode);
                return retval;
@@@ -46,6 -46,7 +46,6 @@@
  #include <linux/namei.h>
  #include <linux/posix_acl.h>
  #include <linux/security.h>
 -#include <linux/falloc.h>
  #include <linux/fiemap.h>
  #include <linux/slab.h>
  
@@@ -102,7 -103,8 +102,8 @@@ xfs_mark_inode_dirty
  STATIC int
  xfs_init_security(
        struct inode    *inode,
-       struct inode    *dir)
+       struct inode    *dir,
+       const struct qstr *qstr)
  {
        struct xfs_inode *ip = XFS_I(inode);
        size_t          length;
        unsigned char   *name;
        int             error;
  
-       error = security_inode_init_security(inode, dir, (char **)&name,
+       error = security_inode_init_security(inode, dir, qstr, (char **)&name,
                                             &value, &length);
        if (error) {
                if (error == -EOPNOTSUPP)
@@@ -194,7 -196,7 +195,7 @@@ xfs_vn_mknod
  
        inode = VFS_I(ip);
  
-       error = xfs_init_security(inode, dir);
+       error = xfs_init_security(inode, dir, &dentry->d_name);
        if (unlikely(error))
                goto out_cleanup_inode;
  
@@@ -367,7 -369,7 +368,7 @@@ xfs_vn_symlink
  
        inode = VFS_I(cip);
  
-       error = xfs_init_security(inode, dir);
+       error = xfs_init_security(inode, dir, &dentry->d_name);
        if (unlikely(error))
                goto out_cleanup_inode;
  
@@@ -504,6 -506,58 +505,6 @@@ xfs_vn_setattr
        return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0);
  }
  
 -STATIC long
 -xfs_vn_fallocate(
 -      struct inode    *inode,
 -      int             mode,
 -      loff_t          offset,
 -      loff_t          len)
 -{
 -      long            error;
 -      loff_t          new_size = 0;
 -      xfs_flock64_t   bf;
 -      xfs_inode_t     *ip = XFS_I(inode);
 -
 -      /* preallocation on directories not yet supported */
 -      error = -ENODEV;
 -      if (S_ISDIR(inode->i_mode))
 -              goto out_error;
 -
 -      bf.l_whence = 0;
 -      bf.l_start = offset;
 -      bf.l_len = len;
 -
 -      xfs_ilock(ip, XFS_IOLOCK_EXCL);
 -
 -      /* check the new inode size is valid before allocating */
 -      if (!(mode & FALLOC_FL_KEEP_SIZE) &&
 -          offset + len > i_size_read(inode)) {
 -              new_size = offset + len;
 -              error = inode_newsize_ok(inode, new_size);
 -              if (error)
 -                      goto out_unlock;
 -      }
 -
 -      error = -xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf,
 -                                     0, XFS_ATTR_NOLOCK);
 -      if (error)
 -              goto out_unlock;
 -
 -      /* Change file size if needed */
 -      if (new_size) {
 -              struct iattr iattr;
 -
 -              iattr.ia_valid = ATTR_SIZE;
 -              iattr.ia_size = new_size;
 -              error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK);
 -      }
 -
 -out_unlock:
 -      xfs_iunlock(ip, XFS_IOLOCK_EXCL);
 -out_error:
 -      return error;
 -}
 -
  #define XFS_FIEMAP_FLAGS      (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
  
  /*
@@@ -597,6 -651,7 +598,6 @@@ static const struct inode_operations xf
        .getxattr               = generic_getxattr,
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
 -      .fallocate              = xfs_vn_fallocate,
        .fiemap                 = xfs_vn_fiemap,
  };
  
diff --combined include/linux/ext3_fs.h
@@@ -724,30 -724,21 +724,30 @@@ struct ext3_dir_entry_2 
                                         ~EXT3_DIR_ROUND)
  #define EXT3_MAX_REC_LEN              ((1<<16)-1)
  
 +/*
 + * Tests against MAX_REC_LEN etc were put in place for 64k block
 + * sizes; if that is not possible on this arch, we can skip
 + * those tests and speed things up.
 + */
  static inline unsigned ext3_rec_len_from_disk(__le16 dlen)
  {
        unsigned len = le16_to_cpu(dlen);
  
 +#if (PAGE_CACHE_SIZE >= 65536)
        if (len == EXT3_MAX_REC_LEN)
                return 1 << 16;
 +#endif
        return len;
  }
  
  static inline __le16 ext3_rec_len_to_disk(unsigned len)
  {
 +#if (PAGE_CACHE_SIZE >= 65536)
        if (len == (1 << 16))
                return cpu_to_le16(EXT3_MAX_REC_LEN);
        else if (len > (1 << 16))
                BUG();
 +#endif
        return cpu_to_le16(len);
  }
  
@@@ -865,7 -856,6 +865,7 @@@ extern struct ext3_group_desc * ext3_ge
  extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
  extern void ext3_init_block_alloc_info(struct inode *);
  extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv);
 +extern int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range);
  
  /* dir.c */
  extern int ext3_check_dir_entry(const char *, struct inode *,
@@@ -884,7 -874,8 +884,8 @@@ extern int ext3fs_dirhash(const char *n
                          dx_hash_info *hinfo);
  
  /* ialloc.c */
- extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
+ extern struct inode * ext3_new_inode (handle_t *, struct inode *,
+                                     const struct qstr *, int);
  extern void ext3_free_inode (handle_t *, struct inode *);
  extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
  extern unsigned long ext3_count_free_inodes (struct super_block *);
diff --combined include/linux/security.h
@@@ -25,6 -25,7 +25,7 @@@
  #include <linux/fs.h>
  #include <linux/fsnotify.h>
  #include <linux/binfmts.h>
+ #include <linux/dcache.h>
  #include <linux/signal.h>
  #include <linux/resource.h>
  #include <linux/sem.h>
@@@ -267,6 -268,12 +268,12 @@@ static inline void security_free_mnt_op
   *    @orig the original mount data copied from userspace.
   *    @copy copied data which will be passed to the security module.
   *    Returns 0 if the copy was successful.
+  * @sb_remount:
+  *    Extracts security system specifc mount options and verifys no changes
+  *    are being made to those options.
+  *    @sb superblock being remounted
+  *    @data contains the filesystem-specific data.
+  *    Return 0 if permission is granted.
   * @sb_umount:
   *    Check permission before the @mnt file system is unmounted.
   *    @mnt contains the mounted file system.
   *    then it should return -EOPNOTSUPP to skip this processing.
   *    @inode contains the inode structure of the newly created inode.
   *    @dir contains the inode structure of the parent directory.
+  *    @qstr contains the last path component of the new object
   *    @name will be set to the allocated name suffix (e.g. selinux).
   *    @value will be set to the allocated attribute value.
   *    @len will be set to the length of the value.
   *    @cap contains the capability <include/linux/capability.h>.
   *    @audit: Whether to write an audit message or not
   *    Return 0 if the capability is granted for @tsk.
-  * @sysctl:
-  *    Check permission before accessing the @table sysctl variable in the
-  *    manner specified by @op.
-  *    @table contains the ctl_table structure for the sysctl variable.
-  *    @op contains the operation (001 = search, 002 = write, 004 = read).
-  *    Return 0 if permission is granted.
   * @syslog:
   *    Check permission before accessing the kernel message ring or changing
   *    logging to the console.
@@@ -1383,7 -1385,6 +1385,6 @@@ struct security_operations 
                       const kernel_cap_t *permitted);
        int (*capable) (struct task_struct *tsk, const struct cred *cred,
                        int cap, int audit);
-       int (*sysctl) (struct ctl_table *table, int op);
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
        int (*quota_on) (struct dentry *dentry);
        int (*syslog) (int type);
        int (*sb_alloc_security) (struct super_block *sb);
        void (*sb_free_security) (struct super_block *sb);
        int (*sb_copy_data) (char *orig, char *copy);
+       int (*sb_remount) (struct super_block *sb, void *data);
        int (*sb_kern_mount) (struct super_block *sb, int flags, void *data);
        int (*sb_show_options) (struct seq_file *m, struct super_block *sb);
        int (*sb_statfs) (struct dentry *dentry);
        int (*inode_alloc_security) (struct inode *inode);
        void (*inode_free_security) (struct inode *inode);
        int (*inode_init_security) (struct inode *inode, struct inode *dir,
-                                   char **name, void **value, size_t *len);
+                                   const struct qstr *qstr, char **name,
+                                   void **value, size_t *len);
        int (*inode_create) (struct inode *dir,
                             struct dentry *dentry, int mode);
        int (*inode_link) (struct dentry *old_dentry,
@@@ -1662,10 -1665,9 +1665,9 @@@ int security_capset(struct cred *new, c
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
 -int security_capable(int cap);
 +int security_capable(const struct cred *cred, int cap);
  int security_real_capable(struct task_struct *tsk, int cap);
  int security_real_capable_noaudit(struct task_struct *tsk, int cap);
- int security_sysctl(struct ctl_table *table, int op);
  int security_quotactl(int cmds, int type, int id, struct super_block *sb);
  int security_quota_on(struct dentry *dentry);
  int security_syslog(int type);
@@@ -1681,6 -1683,7 +1683,7 @@@ int security_bprm_secureexec(struct lin
  int security_sb_alloc(struct super_block *sb);
  void security_sb_free(struct super_block *sb);
  int security_sb_copy_data(char *orig, char *copy);
+ int security_sb_remount(struct super_block *sb, void *data);
  int security_sb_kern_mount(struct super_block *sb, int flags, void *data);
  int security_sb_show_options(struct seq_file *m, struct super_block *sb);
  int security_sb_statfs(struct dentry *dentry);
@@@ -1696,7 -1699,8 +1699,8 @@@ int security_sb_parse_opts_str(char *op
  int security_inode_alloc(struct inode *inode);
  void security_inode_free(struct inode *inode);
  int security_inode_init_security(struct inode *inode, struct inode *dir,
-                                 char **name, void **value, size_t *len);
+                                const struct qstr *qstr, char **name,
+                                void **value, size_t *len);
  int security_inode_create(struct inode *dir, struct dentry *dentry, int mode);
  int security_inode_link(struct dentry *old_dentry, struct inode *dir,
                         struct dentry *new_dentry);
@@@ -1856,9 -1860,9 +1860,9 @@@ static inline int security_capset(struc
        return cap_capset(new, old, effective, inheritable, permitted);
  }
  
 -static inline int security_capable(int cap)
 +static inline int security_capable(const struct cred *cred, int cap)
  {
 -      return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
 +      return cap_capable(current, cred, cap, SECURITY_CAP_AUDIT);
  }
  
  static inline int security_real_capable(struct task_struct *tsk, int cap)
@@@ -1883,11 -1887,6 +1887,6 @@@ int security_real_capable_noaudit(struc
        return ret;
  }
  
- static inline int security_sysctl(struct ctl_table *table, int op)
- {
-       return 0;
- }
  static inline int security_quotactl(int cmds, int type, int id,
                                     struct super_block *sb)
  {
@@@ -1964,6 -1963,11 +1963,11 @@@ static inline int security_sb_copy_data
        return 0;
  }
  
+ static inline int security_sb_remount(struct super_block *sb, void *data)
+ {
+       return 0;
+ }
  static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
  {
        return 0;
@@@ -2023,6 -2027,7 +2027,7 @@@ static inline void security_inode_free(
  
  static inline int security_inode_init_security(struct inode *inode,
                                                struct inode *dir,
+                                               const struct qstr *qstr,
                                                char **name,
                                                void **value,
                                                size_t *len)
diff --combined kernel/sysctl.c
@@@ -24,7 -24,6 +24,7 @@@
  #include <linux/slab.h>
  #include <linux/sysctl.h>
  #include <linux/signal.h>
 +#include <linux/printk.h>
  #include <linux/proc_fs.h>
  #include <linux/security.h>
  #include <linux/ctype.h>
@@@ -170,8 -169,7 +170,8 @@@ static int proc_taint(struct ctl_table 
  #endif
  
  #ifdef CONFIG_MAGIC_SYSRQ
 -static int __sysrq_enabled; /* Note: sysrq code ises it's own private copy */
 +/* Note: sysrq code uses it's own private copy */
 +static int __sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
  
  static int sysrq_sysctl_handler(ctl_table *table, int write,
                                void __user *buffer, size_t *lenp,
@@@ -247,6 -245,10 +247,6 @@@ static struct ctl_table root_table[] = 
                .mode           = 0555,
                .child          = dev_table,
        },
 -/*
 - * NOTE: do not add new entries to this table unless you have read
 - * Documentation/sysctl/ctl_unnumbered.txt
 - */
        { }
  };
  
@@@ -708,15 -710,6 +708,15 @@@ static struct ctl_table kern_table[] = 
                .extra1         = &zero,
                .extra2         = &one,
        },
 +      {
 +              .procname       = "kptr_restrict",
 +              .data           = &kptr_restrict,
 +              .maxlen         = sizeof(int),
 +              .mode           = 0644,
 +              .proc_handler   = proc_dointvec_minmax,
 +              .extra1         = &zero,
 +              .extra2         = &two,
 +      },
  #endif
        {
                .procname       = "ngroups_max",
                .proc_handler   = proc_dointvec,
        },
  #endif
 -/*
 - * NOTE: do not add new entries to this table unless you have read
 - * Documentation/sysctl/ctl_unnumbered.txt
 - */
        { }
  };
  
@@@ -1329,6 -1326,11 +1329,6 @@@ static struct ctl_table vm_table[] = 
                .extra2         = &one,
        },
  #endif
 -
 -/*
 - * NOTE: do not add new entries to this table unless you have read
 - * Documentation/sysctl/ctl_unnumbered.txt
 - */
        { }
  };
  
@@@ -1484,6 -1486,10 +1484,6 @@@ static struct ctl_table fs_table[] = 
                .proc_handler   = &pipe_proc_fn,
                .extra1         = &pipe_min_size,
        },
 -/*
 - * NOTE: do not add new entries to this table unless you have read
 - * Documentation/sysctl/ctl_unnumbered.txt
 - */
        { }
  };
  
@@@ -1685,13 -1691,8 +1685,8 @@@ static int test_perm(int mode, int op
  
  int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
  {
-       int error;
        int mode;
  
-       error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));
-       if (error)
-               return error;
        if (root->permissions)
                mode = root->permissions(root, current->nsproxy, table);
        else
@@@ -2893,7 -2894,7 +2888,7 @@@ int proc_do_large_bitmap(struct ctl_tab
        }
  }
  
 -#else /* CONFIG_PROC_FS */
 +#else /* CONFIG_PROC_SYSCTL */
  
  int proc_dostring(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos)
@@@ -2945,7 -2946,7 +2940,7 @@@ int proc_doulongvec_ms_jiffies_minmax(s
  }
  
  
 -#endif /* CONFIG_PROC_FS */
 +#endif /* CONFIG_PROC_SYSCTL */
  
  /*
   * No sense putting this after each symbol definition, twice,
diff --combined security/security.c
@@@ -154,9 -154,10 +154,9 @@@ int security_capset(struct cred *new, c
                                    effective, inheritable, permitted);
  }
  
 -int security_capable(int cap)
 +int security_capable(const struct cred *cred, int cap)
  {
 -      return security_ops->capable(current, current_cred(), cap,
 -                                   SECURITY_CAP_AUDIT);
 +      return security_ops->capable(current, cred, cap, SECURITY_CAP_AUDIT);
  }
  
  int security_real_capable(struct task_struct *tsk, int cap)
@@@ -181,11 -182,6 +181,6 @@@ int security_real_capable_noaudit(struc
        return ret;
  }
  
- int security_sysctl(struct ctl_table *table, int op)
- {
-       return security_ops->sysctl(table, op);
- }
  int security_quotactl(int cmds, int type, int id, struct super_block *sb)
  {
        return security_ops->quotactl(cmds, type, id, sb);
@@@ -271,6 -267,11 +266,11 @@@ int security_sb_copy_data(char *orig, c
  }
  EXPORT_SYMBOL(security_sb_copy_data);
  
+ int security_sb_remount(struct super_block *sb, void *data)
+ {
+       return security_ops->sb_remount(sb, data);
+ }
  int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
  {
        return security_ops->sb_kern_mount(sb, flags, data);
@@@ -335,11 -336,13 +335,13 @@@ void security_inode_free(struct inode *
  }
  
  int security_inode_init_security(struct inode *inode, struct inode *dir,
-                                 char **name, void **value, size_t *len)
+                                const struct qstr *qstr, char **name,
+                                void **value, size_t *len)
  {
        if (unlikely(IS_PRIVATE(inode)))
                return -EOPNOTSUPP;
-       return security_ops->inode_init_security(inode, dir, name, value, len);
+       return security_ops->inode_init_security(inode, dir, qstr, name, value,
+                                                len);
  }
  EXPORT_SYMBOL(security_inode_init_security);
  
diff --combined security/selinux/hooks.c
   */
  
  #include <linux/init.h>
+ #include <linux/kd.h>
  #include <linux/kernel.h>
  #include <linux/tracehook.h>
  #include <linux/errno.h>
+ #include <linux/ext2_fs.h>
  #include <linux/sched.h>
  #include <linux/security.h>
  #include <linux/xattr.h>
  #include <linux/mman.h>
  #include <linux/slab.h>
  #include <linux/pagemap.h>
+ #include <linux/proc_fs.h>
  #include <linux/swap.h>
  #include <linux/spinlock.h>
  #include <linux/syscalls.h>
+ #include <linux/dcache.h>
  #include <linux/file.h>
  #include <linux/fdtable.h>
  #include <linux/namei.h>
  #include <linux/mount.h>
- #include <linux/proc_fs.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/netfilter_ipv6.h>
  #include <linux/tty.h>
@@@ -70,7 -73,6 +73,6 @@@
  #include <net/ipv6.h>
  #include <linux/hugetlb.h>
  #include <linux/personality.h>
- #include <linux/sysctl.h>
  #include <linux/audit.h>
  #include <linux/string.h>
  #include <linux/selinux.h>
@@@ -1120,39 -1122,35 +1122,35 @@@ static inline u16 socket_type_to_securi
  }
  
  #ifdef CONFIG_PROC_FS
- static int selinux_proc_get_sid(struct proc_dir_entry *de,
+ static int selinux_proc_get_sid(struct dentry *dentry,
                                u16 tclass,
                                u32 *sid)
  {
-       int buflen, rc;
-       char *buffer, *path, *end;
+       int rc;
+       char *buffer, *path;
  
        buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
  
-       buflen = PAGE_SIZE;
-       end = buffer+buflen;
-       *--end = '\0';
-       buflen--;
-       path = end-1;
-       *path = '/';
-       while (de && de != de->parent) {
-               buflen -= de->namelen + 1;
-               if (buflen < 0)
-                       break;
-               end -= de->namelen;
-               memcpy(end, de->name, de->namelen);
-               *--end = '/';
-               path = end;
-               de = de->parent;
+       path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
+       if (IS_ERR(path))
+               rc = PTR_ERR(path);
+       else {
+               /* each process gets a /proc/PID/ entry. Strip off the
+                * PID part to get a valid selinux labeling.
+                * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
+               while (path[1] >= '0' && path[1] <= '9') {
+                       path[1] = '/';
+                       path++;
+               }
+               rc = security_genfs_sid("proc", path, tclass, sid);
        }
-       rc = security_genfs_sid("proc", path, tclass, sid);
        free_page((unsigned long)buffer);
        return rc;
  }
  #else
- static int selinux_proc_get_sid(struct proc_dir_entry *de,
+ static int selinux_proc_get_sid(struct dentry *dentry,
                                u16 tclass,
                                u32 *sid)
  {
@@@ -1300,10 -1298,8 +1298,8 @@@ static int inode_doinit_with_dentry(str
  
                /* Try to obtain a transition SID. */
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-               rc = security_transition_sid(isec->task_sid,
-                                            sbsec->sid,
-                                            isec->sclass,
-                                            &sid);
+               rc = security_transition_sid(isec->task_sid, sbsec->sid,
+                                            isec->sclass, NULL, &sid);
                if (rc)
                        goto out_unlock;
                isec->sid = sid;
                isec->sid = sbsec->sid;
  
                if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
-                       struct proc_inode *proci = PROC_I(inode);
-                       if (proci->pde) {
+                       if (opt_dentry) {
                                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-                               rc = selinux_proc_get_sid(proci->pde,
+                               rc = selinux_proc_get_sid(opt_dentry,
                                                          isec->sclass,
                                                          &sid);
                                if (rc)
@@@ -1578,7 -1573,7 +1573,7 @@@ static int may_create(struct inode *dir
                return rc;
  
        if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
-               rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
+               rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid);
                if (rc)
                        return rc;
        }
@@@ -1862,82 -1857,6 +1857,6 @@@ static int selinux_capable(struct task_
        return task_has_capability(tsk, cred, cap, audit);
  }
  
- static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
- {
-       int buflen, rc;
-       char *buffer, *path, *end;
-       rc = -ENOMEM;
-       buffer = (char *)__get_free_page(GFP_KERNEL);
-       if (!buffer)
-               goto out;
-       buflen = PAGE_SIZE;
-       end = buffer+buflen;
-       *--end = '\0';
-       buflen--;
-       path = end-1;
-       *path = '/';
-       while (table) {
-               const char *name = table->procname;
-               size_t namelen = strlen(name);
-               buflen -= namelen + 1;
-               if (buflen < 0)
-                       goto out_free;
-               end -= namelen;
-               memcpy(end, name, namelen);
-               *--end = '/';
-               path = end;
-               table = table->parent;
-       }
-       buflen -= 4;
-       if (buflen < 0)
-               goto out_free;
-       end -= 4;
-       memcpy(end, "/sys", 4);
-       path = end;
-       rc = security_genfs_sid("proc", path, tclass, sid);
- out_free:
-       free_page((unsigned long)buffer);
- out:
-       return rc;
- }
- static int selinux_sysctl(ctl_table *table, int op)
- {
-       int error = 0;
-       u32 av;
-       u32 tsid, sid;
-       int rc;
-       sid = current_sid();
-       rc = selinux_sysctl_get_sid(table, (op == 0001) ?
-                                   SECCLASS_DIR : SECCLASS_FILE, &tsid);
-       if (rc) {
-               /* Default to the well-defined sysctl SID. */
-               tsid = SECINITSID_SYSCTL;
-       }
-       /* The op values are "defined" in sysctl.c, thereby creating
-        * a bad coupling between this module and sysctl.c */
-       if (op == 001) {
-               error = avc_has_perm(sid, tsid,
-                                    SECCLASS_DIR, DIR__SEARCH, NULL);
-       } else {
-               av = 0;
-               if (op & 004)
-                       av |= FILE__READ;
-               if (op & 002)
-                       av |= FILE__WRITE;
-               if (av)
-                       error = avc_has_perm(sid, tsid,
-                                            SECCLASS_FILE, av, NULL);
-       }
-       return error;
- }
  static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
  {
        const struct cred *cred = current_cred();
@@@ -2060,7 -1979,8 +1979,8 @@@ static int selinux_bprm_set_creds(struc
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(old_tsec->sid, isec->sid,
-                                            SECCLASS_PROCESS, &new_tsec->sid);
+                                            SECCLASS_PROCESS, NULL,
+                                            &new_tsec->sid);
                if (rc)
                        return rc;
        }
        return rc;
  }
  
+ static int selinux_sb_remount(struct super_block *sb, void *data)
+ {
+       int rc, i, *flags;
+       struct security_mnt_opts opts;
+       char *secdata, **mount_options;
+       struct superblock_security_struct *sbsec = sb->s_security;
+       if (!(sbsec->flags & SE_SBINITIALIZED))
+               return 0;
+       if (!data)
+               return 0;
+       if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
+               return 0;
+       security_init_mnt_opts(&opts);
+       secdata = alloc_secdata();
+       if (!secdata)
+               return -ENOMEM;
+       rc = selinux_sb_copy_data(data, secdata);
+       if (rc)
+               goto out_free_secdata;
+       rc = selinux_parse_opts_str(secdata, &opts);
+       if (rc)
+               goto out_free_secdata;
+       mount_options = opts.mnt_opts;
+       flags = opts.mnt_opts_flags;
+       for (i = 0; i < opts.num_mnt_opts; i++) {
+               u32 sid;
+               size_t len;
+               if (flags[i] == SE_SBLABELSUPP)
+                       continue;
+               len = strlen(mount_options[i]);
+               rc = security_context_to_sid(mount_options[i], len, &sid);
+               if (rc) {
+                       printk(KERN_WARNING "SELinux: security_context_to_sid"
+                              "(%s) failed for (dev %s, type %s) errno=%d\n",
+                              mount_options[i], sb->s_id, sb->s_type->name, rc);
+                       goto out_free_opts;
+               }
+               rc = -EINVAL;
+               switch (flags[i]) {
+               case FSCONTEXT_MNT:
+                       if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+                               goto out_bad_option;
+                       break;
+               case CONTEXT_MNT:
+                       if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+                               goto out_bad_option;
+                       break;
+               case ROOTCONTEXT_MNT: {
+                       struct inode_security_struct *root_isec;
+                       root_isec = sb->s_root->d_inode->i_security;
+                       if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+                               goto out_bad_option;
+                       break;
+               }
+               case DEFCONTEXT_MNT:
+                       if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+                               goto out_bad_option;
+                       break;
+               default:
+                       goto out_free_opts;
+               }
+       }
+       rc = 0;
+ out_free_opts:
+       security_free_mnt_opts(&opts);
+ out_free_secdata:
+       free_secdata(secdata);
+       return rc;
+ out_bad_option:
+       printk(KERN_WARNING "SELinux: unable to change security options "
+              "during remount (dev %s, type=%s)\n", sb->s_id,
+              sb->s_type->name);
+       goto out_free_opts;
+ }
  static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
  {
        const struct cred *cred = current_cred();
@@@ -2509,8 -2514,8 +2514,8 @@@ static void selinux_inode_free_security
  }
  
  static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
-                                      char **name, void **value,
-                                      size_t *len)
+                                      const struct qstr *qstr, char **name,
+                                      void **value, size_t *len)
  {
        const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
-                                            &newsid);
+                                            qstr, &newsid);
                if (rc) {
                        printk(KERN_WARNING "%s:  "
                               "security_transition_sid failed, rc=%d (dev=%s "
@@@ -2932,16 -2937,47 +2937,47 @@@ static int selinux_file_ioctl(struct fi
                              unsigned long arg)
  {
        const struct cred *cred = current_cred();
-       u32 av = 0;
+       int error = 0;
  
-       if (_IOC_DIR(cmd) & _IOC_WRITE)
-               av |= FILE__WRITE;
-       if (_IOC_DIR(cmd) & _IOC_READ)
-               av |= FILE__READ;
-       if (!av)
-               av = FILE__IOCTL;
+       switch (cmd) {
+       case FIONREAD:
+       /* fall through */
+       case FIBMAP:
+       /* fall through */
+       case FIGETBSZ:
+       /* fall through */
+       case EXT2_IOC_GETFLAGS:
+       /* fall through */
+       case EXT2_IOC_GETVERSION:
+               error = file_has_perm(cred, file, FILE__GETATTR);
+               break;
+       case EXT2_IOC_SETFLAGS:
+       /* fall through */
+       case EXT2_IOC_SETVERSION:
+               error = file_has_perm(cred, file, FILE__SETATTR);
+               break;
+       /* sys_ioctl() checks */
+       case FIONBIO:
+       /* fall through */
+       case FIOASYNC:
+               error = file_has_perm(cred, file, 0);
+               break;
  
-       return file_has_perm(cred, file, av);
+       case KDSKBENT:
+       case KDSKBSENT:
+               error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG,
+                                           SECURITY_CAP_AUDIT);
+               break;
+       /* default case assumes that the command will go
+        * to the file's ioctl() function.
+        */
+       default:
+               error = file_has_perm(cred, file, FILE__IOCTL);
+       }
+       return error;
  }
  
  static int default_noexec;
@@@ -3198,11 -3234,7 +3234,11 @@@ static void selinux_cred_free(struct cr
  {
        struct task_security_struct *tsec = cred->security;
  
 -      BUG_ON((unsigned long) cred->security < PAGE_SIZE);
 +      /*
 +       * cred->security == NULL if security_cred_alloc_blank() or
 +       * security_prepare_creds() returned an error.
 +       */
 +      BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
        cred->security = (void *) 0x7UL;
        kfree(tsec);
  }
@@@ -3644,9 -3676,16 +3680,16 @@@ static int selinux_skb_peerlbl_sid(stru
  
  /* socket security operations */
  
- static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
+ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
+                                u16 secclass, u32 *socksid)
  {
-       return tsec->sockcreate_sid ? : tsec->sid;
+       if (tsec->sockcreate_sid > SECSID_NULL) {
+               *socksid = tsec->sockcreate_sid;
+               return 0;
+       }
+       return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
+                                      socksid);
  }
  
  static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
@@@ -3670,12 -3709,16 +3713,16 @@@ static int selinux_socket_create(int fa
        const struct task_security_struct *tsec = current_security();
        u32 newsid;
        u16 secclass;
+       int rc;
  
        if (kern)
                return 0;
  
-       newsid = socket_sockcreate_sid(tsec);
        secclass = socket_type_to_security_class(family, type, protocol);
+       rc = socket_sockcreate_sid(tsec, secclass, &newsid);
+       if (rc)
+               return rc;
        return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
  }
  
@@@ -3687,12 -3730,16 +3734,16 @@@ static int selinux_socket_post_create(s
        struct sk_security_struct *sksec;
        int err = 0;
  
+       isec->sclass = socket_type_to_security_class(family, type, protocol);
        if (kern)
                isec->sid = SECINITSID_KERNEL;
-       else
-               isec->sid = socket_sockcreate_sid(tsec);
+       else {
+               err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
+               if (err)
+                       return err;
+       }
  
-       isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->initialized = 1;
  
        if (sock->sk) {
@@@ -4002,7 -4049,6 +4053,6 @@@ static int selinux_sock_rcv_skb_compat(
  {
        int err = 0;
        struct sk_security_struct *sksec = sk->sk_security;
-       u32 peer_sid;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
        char *addrp;
                        return err;
        }
  
-       if (selinux_policycap_netpeer) {
-               err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
-               if (err)
-                       return err;
-               err = avc_has_perm(sk_sid, peer_sid,
-                                  SECCLASS_PEER, PEER__RECV, &ad);
-               if (err)
-                       selinux_netlbl_err(skb, err, 0);
-       } else {
-               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
-               if (err)
-                       return err;
-               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
-       }
+       err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
+       if (err)
+               return err;
+       err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
  
        return err;
  }
@@@ -4529,9 -4565,8 +4569,8 @@@ static unsigned int selinux_ip_postrout
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP_ERR(-ECONNREFUSED);
  
-       if (selinux_policycap_netpeer)
-               if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
-                       return NF_DROP_ERR(-ECONNREFUSED);
+       if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
+               return NF_DROP_ERR(-ECONNREFUSED);
  
        return NF_ACCEPT;
  }
@@@ -4574,27 -4609,14 +4613,14 @@@ static unsigned int selinux_ip_postrout
         * from the sending socket, otherwise use the kernel's sid */
        sk = skb->sk;
        if (sk == NULL) {
-               switch (family) {
-               case PF_INET:
-                       if (IPCB(skb)->flags & IPSKB_FORWARDED)
-                               secmark_perm = PACKET__FORWARD_OUT;
-                       else
-                               secmark_perm = PACKET__SEND;
-                       break;
-               case PF_INET6:
-                       if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
-                               secmark_perm = PACKET__FORWARD_OUT;
-                       else
-                               secmark_perm = PACKET__SEND;
-                       break;
-               default:
-                       return NF_DROP_ERR(-ECONNREFUSED);
-               }
-               if (secmark_perm == PACKET__FORWARD_OUT) {
+               if (skb->skb_iif) {
+                       secmark_perm = PACKET__FORWARD_OUT;
                        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
                                return NF_DROP;
-               } else
+               } else {
+                       secmark_perm = PACKET__SEND;
                        peer_sid = SECINITSID_KERNEL;
+               }
        } else {
                struct sk_security_struct *sksec = sk->sk_security;
                peer_sid = sksec->sid;
@@@ -4848,7 -4870,7 +4874,7 @@@ static int selinux_msg_queue_msgsnd(str
                 * message queue this message will be stored in
                 */
                rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
-                                            &msec->sid);
+                                            NULL, &msec->sid);
                if (rc)
                        return rc;
        }
@@@ -5402,7 -5424,6 +5428,6 @@@ static struct security_operations selin
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset =                       selinux_capset,
-       .sysctl =                       selinux_sysctl,
        .capable =                      selinux_capable,
        .quotactl =                     selinux_quotactl,
        .quota_on =                     selinux_quota_on,
        .sb_alloc_security =            selinux_sb_alloc_security,
        .sb_free_security =             selinux_sb_free_security,
        .sb_copy_data =                 selinux_sb_copy_data,
+       .sb_remount =                   selinux_sb_remount,
        .sb_kern_mount =                selinux_sb_kern_mount,
        .sb_show_options =              selinux_sb_show_options,
        .sb_statfs =                    selinux_sb_statfs,
@@@ -123,6 -123,11 +123,11 @@@ static struct policydb_compat_info poli
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
+       {
+               .version        = POLICYDB_VERSION_FILENAME_TRANS,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       },
  };
  
  static struct policydb_compat_info *policydb_lookup_compat(int version)
@@@ -501,8 -506,8 +506,8 @@@ static int policydb_index(struct policy
        if (rc)
                goto out;
  
 -      rc = -ENOMEM;
 -      if (cond_init_bool_indexes(p))
 +      rc = cond_init_bool_indexes(p);
 +      if (rc)
                goto out;
  
        for (i = 0; i < SYM_NUM; i++) {
@@@ -704,6 -709,7 +709,7 @@@ void policydb_destroy(struct policydb *
        int i;
        struct role_allow *ra, *lra = NULL;
        struct role_trans *tr, *ltr = NULL;
+       struct filename_trans *ft, *nft;
  
        for (i = 0; i < SYM_NUM; i++) {
                cond_resched();
                }
                flex_array_free(p->type_attr_map_array);
        }
+       ft = p->filename_trans;
+       while (ft) {
+               nft = ft->next;
+               kfree(ft->name);
+               kfree(ft);
+               ft = nft;
+       }
        ebitmap_destroy(&p->policycaps);
        ebitmap_destroy(&p->permissive_map);
  
        return rc;
  }
  
+ static int filename_trans_read(struct policydb *p, void *fp)
+ {
+       struct filename_trans *ft, *last;
+       u32 nel, len;
+       char *name;
+       __le32 buf[4];
+       int rc, i;
+       if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
+               return 0;
+       rc = next_entry(buf, fp, sizeof(u32));
+       if (rc)
+               goto out;
+       nel = le32_to_cpu(buf[0]);
+       printk(KERN_ERR "%s: nel=%d\n", __func__, nel);
+       last = p->filename_trans;
+       while (last && last->next)
+               last = last->next;
+       for (i = 0; i < nel; i++) {
+               rc = -ENOMEM;
+               ft = kzalloc(sizeof(*ft), GFP_KERNEL);
+               if (!ft)
+                       goto out;
+               /* add it to the tail of the list */
+               if (!last)
+                       p->filename_trans = ft;
+               else
+                       last->next = ft;
+               last = ft;
+               /* length of the path component string */
+               rc = next_entry(buf, fp, sizeof(u32));
+               if (rc)
+                       goto out;
+               len = le32_to_cpu(buf[0]);
+               rc = -ENOMEM;
+               name = kmalloc(len + 1, GFP_KERNEL);
+               if (!name)
+                       goto out;
+               ft->name = name;
+               /* path component string */
+               rc = next_entry(name, fp, len);
+               if (rc)
+                       goto out;
+               name[len] = 0;
+               printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name);
+               rc = next_entry(buf, fp, sizeof(u32) * 4);
+               if (rc)
+                       goto out;
+               ft->stype = le32_to_cpu(buf[0]);
+               ft->ttype = le32_to_cpu(buf[1]);
+               ft->tclass = le32_to_cpu(buf[2]);
+               ft->otype = le32_to_cpu(buf[3]);
+       }
+       rc = 0;
+ out:
+       return rc;
+ }
  static int genfs_read(struct policydb *p, void *fp)
  {
        int i, j, rc;
@@@ -2251,6 -2336,10 +2336,10 @@@ int policydb_read(struct policydb *p, v
                lra = ra;
        }
  
+       rc = filename_trans_read(p, fp);
+       if (rc)
+               goto bad;
        rc = policydb_index(p);
        if (rc)
                goto bad;
@@@ -3025,6 -3114,43 +3114,43 @@@ static int range_write(struct policydb 
        return 0;
  }
  
+ static int filename_trans_write(struct policydb *p, void *fp)
+ {
+       struct filename_trans *ft;
+       u32 len, nel = 0;
+       __le32 buf[4];
+       int rc;
+       for (ft = p->filename_trans; ft; ft = ft->next)
+               nel++;
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       for (ft = p->filename_trans; ft; ft = ft->next) {
+               len = strlen(ft->name);
+               buf[0] = cpu_to_le32(len);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               rc = put_entry(ft->name, sizeof(char), len, fp);
+               if (rc)
+                       return rc;
+               buf[0] = ft->stype;
+               buf[1] = ft->ttype;
+               buf[2] = ft->tclass;
+               buf[3] = ft->otype;
+               rc = put_entry(buf, sizeof(u32), 4, fp);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+ }
  /*
   * Write the configuration data in a policy database
   * structure to a policy database binary representation
@@@ -3135,6 -3261,10 +3261,10 @@@ int policydb_write(struct policydb *p, 
        if (rc)
                return rc;
  
+       rc = filename_trans_write(p, fp);
+       if (rc)
+               return rc;
        rc = ocontext_write(p, info, fp);
        if (rc)
                return rc;
@@@ -33,6 -33,7 +33,7 @@@
  #include <net/cipso_ipv4.h>
  #include <linux/audit.h>
  #include <linux/magic.h>
+ #include <linux/dcache.h>
  #include "smack.h"
  
  #define task_security(task)   (task_cred_xxx((task), security))
@@@ -501,6 -502,7 +502,7 @@@ static void smack_inode_free_security(s
   * smack_inode_init_security - copy out the smack from an inode
   * @inode: the inode
   * @dir: unused
+  * @qstr: unused
   * @name: where to put the attribute name
   * @value: where to put the attribute value
   * @len: where to put the length of the attribute
   * Returns 0 if it all works out, -ENOMEM if there's no memory
   */
  static int smack_inode_init_security(struct inode *inode, struct inode *dir,
-                                    char **name, void **value, size_t *len)
+                                    const struct qstr *qstr, char **name,
+                                    void **value, size_t *len)
  {
        char *isp = smk_of_inode(inode);
        char *dsp = smk_of_inode(dir);
@@@ -1109,6 -1112,38 +1112,6 @@@ static int smack_file_fcntl(struct fil
        return rc;
  }
  
 -/**
 - * smk_mmap_list_check - the mmap check
 - * @sub: subject label
 - * @obj: object label
 - * @access: access mode
 - * @local: the task specific rule list
 - *
 - * Returns 0 if acces is permitted, -EACCES otherwise
 - */
 -static int smk_mmap_list_check(char *sub, char *obj, int access,
 -                              struct list_head *local)
 -{
 -      int may;
 -
 -      /*
 -       * If there is not a global rule that
 -       * allows access say no.
 -       */
 -      may = smk_access_entry(sub, obj, &smack_rule_list);
 -      if (may == -ENOENT || (may & access) != access)
 -              return -EACCES;
 -      /*
 -       * If there is a task local rule that
 -       * denies access say no.
 -       */
 -      may = smk_access_entry(sub, obj, local);
 -      if (may != -ENOENT && (may & access) != access)
 -              return -EACCES;
 -
 -      return 0;
 -}
 -
  /**
   * smack_file_mmap :
   * Check permissions for a mmap operation.  The @file may be NULL, e.g.
@@@ -1128,12 -1163,8 +1131,12 @@@ static int smack_file_mmap(struct file 
        struct task_smack *tsp;
        char *sp;
        char *msmack;
 +      char *osmack;
        struct inode_smack *isp;
        struct dentry *dp;
 +      int may;
 +      int mmay;
 +      int tmay;
        int rc;
  
        /* do DAC check on address space usage */
        list_for_each_entry_rcu(srp, &smack_rule_list, list) {
                if (srp->smk_subject != sp)
                        continue;
 +
 +              osmack = srp->smk_object;
                /*
                 * Matching labels always allows access.
                 */
 -              if (msmack == srp->smk_object)
 +              if (msmack == osmack)
                        continue;
 +              /*
 +               * If there is a matching local rule take
 +               * that into account as well.
 +               */
 +              may = smk_access_entry(srp->smk_subject, osmack,
 +                                      &tsp->smk_rules);
 +              if (may == -ENOENT)
 +                      may = srp->smk_access;
 +              else
 +                      may &= srp->smk_access;
 +              /*
 +               * If may is zero the SMACK64MMAP subject can't
 +               * possibly have less access.
 +               */
 +              if (may == 0)
 +                      continue;
 +
 +              /*
 +               * Fetch the global list entry.
 +               * If there isn't one a SMACK64MMAP subject
 +               * can't have as much access as current.
 +               */
 +              mmay = smk_access_entry(msmack, osmack, &smack_rule_list);
 +              if (mmay == -ENOENT) {
 +                      rc = -EACCES;
 +                      break;
 +              }
 +              /*
 +               * If there is a local entry it modifies the
 +               * potential access, too.
 +               */
 +              tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules);
 +              if (tmay != -ENOENT)
 +                      mmay &= tmay;
  
 -              rc = smk_mmap_list_check(msmack, srp->smk_object,
 -                                       srp->smk_access, &tsp->smk_rules);
 -              if (rc != 0)
 +              /*
 +               * If there is any access available to current that is
 +               * not available to a SMACK64MMAP subject
 +               * deny access.
 +               */
 +              if ((may | mmay) != mmay) {
 +                      rc = -EACCES;
                        break;
 +              }
        }
  
        rcu_read_unlock();