Merge branch 'btrfs-3.0' into for-linus
authorChris Mason <chris.mason@oracle.com>
Sun, 18 Sep 2011 14:31:44 +0000 (10:31 -0400)
committerChris Mason <chris.mason@oracle.com>
Sun, 18 Sep 2011 14:31:44 +0000 (10:31 -0400)
1  2 
fs/btrfs/inode.c
fs/btrfs/ioctl.c

diff --combined fs/btrfs/inode.c
@@@ -4009,19 -4009,12 +4009,19 @@@ struct inode *btrfs_lookup_dentry(struc
        struct btrfs_root *sub_root = root;
        struct btrfs_key location;
        int index;
 -      int ret;
 +      int ret = 0;
  
        if (dentry->d_name.len > BTRFS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
  
 -      ret = btrfs_inode_by_name(dir, dentry, &location);
 +      if (unlikely(d_need_lookup(dentry))) {
 +              memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key));
 +              kfree(dentry->d_fsdata);
 +              dentry->d_fsdata = NULL;
 +              d_clear_need_lookup(dentry);
 +      } else {
 +              ret = btrfs_inode_by_name(dir, dentry, &location);
 +      }
  
        if (ret < 0)
                return ERR_PTR(ret);
@@@ -4076,16 -4069,16 +4076,16 @@@ static int btrfs_dentry_delete(const st
        return 0;
  }
  
 +static void btrfs_dentry_release(struct dentry *dentry)
 +{
 +      if (dentry->d_fsdata)
 +              kfree(dentry->d_fsdata);
 +}
 +
  static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                                   struct nameidata *nd)
  {
 -      struct inode *inode;
 -
 -      inode = btrfs_lookup_dentry(dir, dentry);
 -      if (IS_ERR(inode))
 -              return ERR_CAST(inode);
 -
 -      return d_splice_alias(inode, dentry);
 +      return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry);
  }
  
  unsigned char btrfs_filetype_table[] = {
@@@ -4104,7 -4097,6 +4104,7 @@@ static int btrfs_real_readdir(struct fi
        struct btrfs_path *path;
        struct list_head ins_list;
        struct list_head del_list;
 +      struct qstr q;
        int ret;
        struct extent_buffer *leaf;
        int slot;
  
        /* special case for "." */
        if (filp->f_pos == 0) {
-               over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR);
+               over = filldir(dirent, ".", 1,
+                              filp->f_pos, btrfs_ino(inode), DT_DIR);
                if (over)
                        return 0;
                filp->f_pos = 1;
        if (filp->f_pos == 1) {
                u64 pino = parent_ino(filp->f_path.dentry);
                over = filldir(dirent, "..", 2,
-                              2, pino, DT_DIR);
+                              filp->f_pos, pino, DT_DIR);
                if (over)
                        return 0;
                filp->f_pos = 2;
  
                while (di_cur < di_total) {
                        struct btrfs_key location;
 +                      struct dentry *tmp;
  
                        if (verify_dir_item(root, leaf, di))
                                break;
                        d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
                        btrfs_dir_item_key_to_cpu(leaf, di, &location);
  
 +                      q.name = name_ptr;
 +                      q.len = name_len;
 +                      q.hash = full_name_hash(q.name, q.len);
 +                      tmp = d_lookup(filp->f_dentry, &q);
 +                      if (!tmp) {
 +                              struct btrfs_key *newkey;
 +
 +                              newkey = kzalloc(sizeof(struct btrfs_key),
 +                                               GFP_NOFS);
 +                              if (!newkey)
 +                                      goto no_dentry;
 +                              tmp = d_alloc(filp->f_dentry, &q);
 +                              if (!tmp) {
 +                                      kfree(newkey);
 +                                      dput(tmp);
 +                                      goto no_dentry;
 +                              }
 +                              memcpy(newkey, &location,
 +                                     sizeof(struct btrfs_key));
 +                              tmp->d_fsdata = newkey;
 +                              tmp->d_flags |= DCACHE_NEED_LOOKUP;
 +                              d_rehash(tmp);
 +                              dput(tmp);
 +                      } else {
 +                              dput(tmp);
 +                      }
 +no_dentry:
                        /* is this a reference to our own snapshot? If so
                         * skip it
                         */
@@@ -4503,7 -4468,7 +4504,7 @@@ static struct inode *btrfs_new_inode(st
        inode->i_generation = BTRFS_I(inode)->generation;
        btrfs_set_inode_space_info(root, inode);
  
 -      if (mode & S_IFDIR)
 +      if (S_ISDIR(mode))
                owner = 0;
        else
                owner = 1;
  
        btrfs_inherit_iflags(inode, dir);
  
 -      if ((mode & S_IFREG)) {
 +      if (S_ISREG(mode)) {
                if (btrfs_test_opt(root, NODATASUM))
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
                if (btrfs_test_opt(root, NODATACOW) ||
@@@ -4802,10 -4767,11 +4803,10 @@@ static int btrfs_link(struct dentry *ol
        if (err) {
                drop_inode = 1;
        } else {
 -              struct dentry *parent = dget_parent(dentry);
 +              struct dentry *parent = dentry->d_parent;
                err = btrfs_update_inode(trans, root, inode);
                BUG_ON(err);
                btrfs_log_new_name(trans, inode, NULL, parent);
 -              dput(parent);
        }
  
        nr = trans->blocks_used;
@@@ -6917,7 -6883,7 +6918,7 @@@ static int btrfs_getattr(struct vfsmoun
  {
        struct inode *inode = dentry->d_inode;
        generic_fillattr(inode, stat);
 -      stat->dev = BTRFS_I(inode)->root->anon_super.s_dev;
 +      stat->dev = BTRFS_I(inode)->root->anon_dev;
        stat->blksize = PAGE_CACHE_SIZE;
        stat->blocks = (inode_get_bytes(inode) +
                        BTRFS_I(inode)->delalloc_bytes) >> 9;
@@@ -7085,8 -7051,9 +7086,8 @@@ static int btrfs_rename(struct inode *o
        BUG_ON(ret);
  
        if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
 -              struct dentry *parent = dget_parent(new_dentry);
 +              struct dentry *parent = new_dentry->d_parent;
                btrfs_log_new_name(trans, old_inode, old_dir, parent);
 -              dput(parent);
                btrfs_end_log_trans(root);
        }
  out_fail:
@@@ -7351,19 -7318,15 +7352,19 @@@ static int btrfs_set_page_dirty(struct 
        return __set_page_dirty_nobuffers(page);
  }
  
 -static int btrfs_permission(struct inode *inode, int mask, unsigned int flags)
 +static int btrfs_permission(struct inode *inode, int mask)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
 +      umode_t mode = inode->i_mode;
  
 -      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);
 +      if (mask & MAY_WRITE &&
 +          (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
 +              if (btrfs_root_readonly(root))
 +                      return -EROFS;
 +              if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
 +                      return -EACCES;
 +      }
 +      return generic_permission(inode, mask);
  }
  
  static const struct inode_operations btrfs_dir_inode_operations = {
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
 +      .get_acl        = btrfs_get_acl,
  };
  static const struct inode_operations btrfs_dir_ro_inode_operations = {
        .lookup         = btrfs_lookup,
        .permission     = btrfs_permission,
 +      .get_acl        = btrfs_get_acl,
  };
  
  static const struct file_operations btrfs_dir_file_operations = {
@@@ -7457,7 -7418,6 +7458,7 @@@ static const struct inode_operations bt
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
        .fiemap         = btrfs_fiemap,
 +      .get_acl        = btrfs_get_acl,
  };
  static const struct inode_operations btrfs_special_inode_operations = {
        .getattr        = btrfs_getattr,
        .getxattr       = btrfs_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
 +      .get_acl        = btrfs_get_acl,
  };
  static const struct inode_operations btrfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .getxattr       = btrfs_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
 +      .get_acl        = btrfs_get_acl,
  };
  
  const struct dentry_operations btrfs_dentry_operations = {
        .d_delete       = btrfs_dentry_delete,
 +      .d_release      = btrfs_dentry_release,
  };
diff --combined fs/btrfs/ioctl.c
@@@ -323,7 -323,7 +323,7 @@@ static noinline int create_subvol(struc
        struct btrfs_inode_item *inode_item;
        struct extent_buffer *leaf;
        struct btrfs_root *new_root;
 -      struct dentry *parent = dget_parent(dentry);
 +      struct dentry *parent = dentry->d_parent;
        struct inode *dir;
        int ret;
        int err;
        u64 index = 0;
  
        ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
 -      if (ret) {
 -              dput(parent);
 +      if (ret)
                return ret;
 -      }
  
        dir = parent->d_inode;
  
         * 2 - dir items
         */
        trans = btrfs_start_transaction(root, 6);
 -      if (IS_ERR(trans)) {
 -              dput(parent);
 +      if (IS_ERR(trans))
                return PTR_ERR(trans);
 -      }
  
        leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
                                      0, objectid, NULL, 0, 0, 0);
  
        d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
  fail:
 -      dput(parent);
        if (async_transid) {
                *async_transid = trans->transid;
                err = btrfs_commit_transaction_async(trans, root, 1);
@@@ -451,6 -456,7 +451,6 @@@ static int create_snapshot(struct btrfs
                           bool readonly)
  {
        struct inode *inode;
 -      struct dentry *parent;
        struct btrfs_pending_snapshot *pending_snapshot;
        struct btrfs_trans_handle *trans;
        int ret;
        if (ret)
                goto fail;
  
 -      parent = dget_parent(dentry);
 -      inode = btrfs_lookup_dentry(parent->d_inode, dentry);
 -      dput(parent);
 +      inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
                goto fail;
@@@ -2177,6 -2185,11 +2177,11 @@@ static noinline long btrfs_ioctl_clone(
        if (!(src_file->f_mode & FMODE_READ))
                goto out_fput;
  
+       /* don't make the dst file partly checksummed */
+       if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
+           (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
+               goto out_fput;
        ret = -EISDIR;
        if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
                goto out_fput;
                        goto out_unlock;
        }
  
+       /* truncate page cache pages from target inode range */
+       truncate_inode_pages_range(&inode->i_data, destoff,
+                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
        /* do any pending delalloc/csum calc on src, one way or
           another, and lock file content */
        while (1) {
                btrfs_wait_ordered_range(src, off, len);
        }
  
-       /* truncate page cache pages from target inode range */
-       truncate_inode_pages_range(&inode->i_data, off,
-                                  ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
                        if (endoff > inode->i_size)
                                btrfs_i_size_write(inode, endoff);
  
-                       BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
                        ret = btrfs_update_inode(trans, root, inode);
                        BUG_ON(ret);
                        btrfs_end_transaction(trans, root);