summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason2012-04-27 20:23:22 +0200
committerChris Mason2012-04-27 20:23:22 +0200
commitfede766f28dd766d4e8feb321fdb19edb21ef6fb (patch)
tree86e59f6bf94ad77c2fa1b232faa8f8b63b8675cb
parentBtrfs: Fix space checking during fs resize (diff)
downloadkernel-qcow2-linux-fede766f28dd766d4e8feb321fdb19edb21ef6fb.tar.gz
kernel-qcow2-linux-fede766f28dd766d4e8feb321fdb19edb21ef6fb.tar.xz
kernel-qcow2-linux-fede766f28dd766d4e8feb321fdb19edb21ef6fb.zip
Btrfs: avoid deadlocks from GFP_KERNEL allocations during btrfs_real_readdir
Btrfs has an optimization where it will preallocate dentries during readdir to fill in enough information to open the inode without an extra lookup. But, we're calling d_alloc, which is doing GFP_KERNEL allocations, and that leads to deadlocks because our readdir code has tree locks held. For now, disable this optimization. We'll fix the gfp mask in the next merge window. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/inode.c30
1 files changed, 1 insertions, 29 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d953f8820464..3ce7805d1117 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4192,7 +4192,6 @@ 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;
@@ -4283,7 +4282,6 @@ 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;
@@ -4304,33 +4302,7 @@ 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.
*