aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/inode.c29
-rw-r--r--fs/btrfs/transaction.c8
3 files changed, 39 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 7b73a9c3d86..ad4eacca7f5 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1544,6 +1544,9 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
u64 isize);
/* inode.c */
+void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name,
+ int namelen);
+
int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
size_t size, struct bio *bio);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 1569fb86451..31aa4ba06fc 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2642,6 +2642,31 @@ static void btrfs_truncate(struct inode *inode)
btrfs_throttle(root);
}
+/*
+ * Invalidate a single dcache entry at the root of the filesystem.
+ * Needed after creation of snapshot or subvolume.
+ */
+void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name,
+ int namelen)
+{
+ struct dentry *alias, *entry;
+ struct qstr qstr;
+
+ alias = d_find_alias(root->fs_info->sb->s_root->d_inode);
+ if (alias) {
+ qstr.name = name;
+ qstr.len = namelen;
+ /* change me if btrfs ever gets a d_hash operation */
+ qstr.hash = full_name_hash(qstr.name, qstr.len);
+ entry = d_lookup(alias, &qstr);
+ dput(alias);
+ if (entry) {
+ d_invalidate(entry);
+ dput(entry);
+ }
+ }
+}
+
static int noinline create_subvol(struct btrfs_root *root, char *name,
int namelen)
{
@@ -2761,6 +2786,10 @@ static int noinline create_subvol(struct btrfs_root *root, char *name,
ret = btrfs_update_inode(trans, new_root, inode);
if (ret)
goto fail;
+
+ /* Invalidate existing dcache entry for new subvolume. */
+ btrfs_invalidate_dcache_root(root, name, namelen);
+
fail:
nr = trans->blocks_used;
err = btrfs_commit_transaction(trans, new_root);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 1cb084efd6e..f04684f7fea 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -560,6 +560,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_root *root = pending->root;
struct extent_buffer *tmp;
int ret;
+ int namelen;
u64 objectid;
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
@@ -595,8 +596,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
* insert the directory item
*/
key.offset = (u64)-1;
+ namelen = strlen(pending->name);
ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
- pending->name, strlen(pending->name),
+ pending->name, namelen,
root->fs_info->sb->s_root->d_inode->i_ino,
&key, BTRFS_FT_DIR);
@@ -606,6 +608,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
pending->name, strlen(pending->name), objectid,
root->fs_info->sb->s_root->d_inode->i_ino);
+
+ /* Invalidate existing dcache entry for new snapshot. */
+ btrfs_invalidate_dcache_root(root, pending->name, namelen);
+
fail:
kfree(new_root_item);
return ret;