Merge branch 'btrfs-3.0' into for-linus
[pandora-kernel.git] / fs / btrfs / inode.c
index edd45f7..377e9bb 100644 (file)
@@ -1786,7 +1786,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                          &ordered_extent->list);
 
        ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
-       if (!ret) {
+       if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
                ret = btrfs_update_inode(trans, root, inode);
                BUG_ON(ret);
        }
@@ -3510,15 +3510,19 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                        err = btrfs_drop_extents(trans, inode, cur_offset,
                                                 cur_offset + hole_size,
                                                 &hint_byte, 1);
-                       if (err)
+                       if (err) {
+                               btrfs_end_transaction(trans, root);
                                break;
+                       }
 
                        err = btrfs_insert_file_extent(trans, root,
                                        btrfs_ino(inode), cur_offset, 0,
                                        0, hole_size, 0, hole_size,
                                        0, 0, 0);
-                       if (err)
+                       if (err) {
+                               btrfs_end_transaction(trans, root);
                                break;
+                       }
 
                        btrfs_drop_extent_cache(inode, hole_start,
                                        last_byte - 1, 0);
@@ -4005,12 +4009,19 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        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);
@@ -4065,16 +4076,16 @@ static int btrfs_dentry_delete(const struct dentry *dentry)
        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[] = {
@@ -4093,6 +4104,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        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;
@@ -4113,7 +4125,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
 
        /* 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;
@@ -4122,7 +4135,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        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;
@@ -4182,6 +4195,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
 
                while (di_cur < di_total) {
                        struct btrfs_key location;
+                       struct dentry *tmp;
 
                        if (verify_dir_item(root, leaf, di))
                                break;
@@ -4202,6 +4216,33 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                        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
                         */
@@ -4463,7 +4504,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        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;
@@ -4508,7 +4549,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 
        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) ||
@@ -4762,11 +4803,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        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;
@@ -5784,7 +5824,7 @@ again:
 
        add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
        ret = btrfs_ordered_update_i_size(inode, 0, ordered);
-       if (!ret)
+       if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags))
                btrfs_update_inode(trans, root, inode);
        ret = 0;
 out_unlock:
@@ -6878,7 +6918,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
 {
        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;
@@ -7046,9 +7086,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        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:
@@ -7313,15 +7352,19 @@ 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)
+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 = {
@@ -7341,10 +7384,12 @@ 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 = {
@@ -7413,6 +7458,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
        .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,
@@ -7422,6 +7468,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
        .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,
@@ -7433,8 +7480,10 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
        .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,
 };