Commit 3b96362c authored by Sven Wegener's avatar Sven Wegener Committed by Chris Mason

Btrfs: Invalidate dcache entry after creating snapshot and

We need to invalidate an existing dcache entry after creating a new
snapshot or subvolume, because a negative dache entry will stop us from
accessing the new snapshot or subvolume.

---
  ctree.h       |   23 +++++++++++++++++++++++
  inode.c       |    4 ++++
  transaction.c |    4 ++++
  3 files changed, 31 insertions(+)
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 48ec2cf8
...@@ -1544,6 +1544,9 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, ...@@ -1544,6 +1544,9 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path, struct btrfs_root *root, struct btrfs_path *path,
u64 isize); u64 isize);
/* inode.c */ /* 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, int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
size_t size, struct bio *bio); size_t size, struct bio *bio);
......
...@@ -2642,6 +2642,31 @@ static void btrfs_truncate(struct inode *inode) ...@@ -2642,6 +2642,31 @@ static void btrfs_truncate(struct inode *inode)
btrfs_throttle(root); 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, static int noinline create_subvol(struct btrfs_root *root, char *name,
int namelen) int namelen)
{ {
...@@ -2761,6 +2786,10 @@ static int noinline create_subvol(struct btrfs_root *root, char *name, ...@@ -2761,6 +2786,10 @@ static int noinline create_subvol(struct btrfs_root *root, char *name,
ret = btrfs_update_inode(trans, new_root, inode); ret = btrfs_update_inode(trans, new_root, inode);
if (ret) if (ret)
goto fail; goto fail;
/* Invalidate existing dcache entry for new subvolume. */
btrfs_invalidate_dcache_root(root, name, namelen);
fail: fail:
nr = trans->blocks_used; nr = trans->blocks_used;
err = btrfs_commit_transaction(trans, new_root); err = btrfs_commit_transaction(trans, new_root);
......
...@@ -560,6 +560,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -560,6 +560,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_root *root = pending->root; struct btrfs_root *root = pending->root;
struct extent_buffer *tmp; struct extent_buffer *tmp;
int ret; int ret;
int namelen;
u64 objectid; u64 objectid;
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); 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, ...@@ -595,8 +596,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
* insert the directory item * insert the directory item
*/ */
key.offset = (u64)-1; key.offset = (u64)-1;
namelen = strlen(pending->name);
ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, 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, root->fs_info->sb->s_root->d_inode->i_ino,
&key, BTRFS_FT_DIR); &key, BTRFS_FT_DIR);
...@@ -606,6 +608,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -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, ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
pending->name, strlen(pending->name), objectid, pending->name, strlen(pending->name), objectid,
root->fs_info->sb->s_root->d_inode->i_ino); 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: fail:
kfree(new_root_item); kfree(new_root_item);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment