summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/inode.c55
2 files changed, 39 insertions, 18 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 04021335939..cecf29e0363 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1700,6 +1700,8 @@ struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
struct btrfs_root *root);
struct inode *btrfs_ilookup(struct super_block *s, u64 objectid,
u64 root_objectid);
+struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
+ struct btrfs_root *root, int *is_new);
int btrfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to);
struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 38d7a81763c..266ca5514b3 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1840,6 +1840,33 @@ struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
return inode;
}
+/* Get an inode object given its location and corresponding root.
+ * Returns in *is_new if the inode was read from disk
+ */
+struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
+ struct btrfs_root *root, int *is_new)
+{
+ struct inode *inode;
+
+ inode = btrfs_iget_locked(s, location->objectid, root);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+
+ if (inode->i_state & I_NEW) {
+ BTRFS_I(inode)->root = root;
+ memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
+ btrfs_read_locked_inode(inode);
+ unlock_new_inode(inode);
+ if (is_new)
+ *is_new = 1;
+ } else {
+ if (is_new)
+ *is_new = 0;
+ }
+
+ return inode;
+}
+
static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
@@ -1848,7 +1875,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
struct btrfs_root *root = bi->root;
struct btrfs_root *sub_root = root;
struct btrfs_key location;
- int ret, do_orphan = 0;
+ int ret, new, do_orphan = 0;
if (dentry->d_name.len > BTRFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
@@ -1866,23 +1893,15 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(ret);
if (ret > 0)
return ERR_PTR(-ENOENT);
-
- inode = btrfs_iget_locked(dir->i_sb, location.objectid,
- sub_root);
- if (!inode)
- return ERR_PTR(-EACCES);
- if (inode->i_state & I_NEW) {
- /* the inode and parent dir are two different roots */
- if (sub_root != root) {
- igrab(inode);
- sub_root->inode = inode;
- do_orphan = 1;
- }
- BTRFS_I(inode)->root = sub_root;
- memcpy(&BTRFS_I(inode)->location, &location,
- sizeof(location));
- btrfs_read_locked_inode(inode);
- unlock_new_inode(inode);
+ inode = btrfs_iget(dir->i_sb, &location, sub_root, &new);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+
+ /* the inode and parent dir are two different roots */
+ if (new && root != sub_root) {
+ igrab(inode);
+ sub_root->inode = inode;
+ do_orphan = 1;
}
}