* [PATCH 1/5] btrfs: fix leak of path in btrfs_find_item
2015-01-14 18:36 [PULL] [PATCH 0/5] Btrfs: leak in btrfs_find_item and cleanups David Sterba
@ 2015-01-14 18:36 ` David Sterba
2015-01-14 18:36 ` [PATCH 2/5] btrfs: cleanup, remove inode_item_info helper David Sterba
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-01-14 18:36 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba, stable
If btrfs_find_item is called with NULL path it allocates one locally but
does not free it. Affected paths are inserting an orphan item for a file
and for a subvol root.
Move the path allocation to the callers.
CC: <stable@vger.kernel.org> # 3.14+
Fixes: 3f870c289900 ("btrfs: expand btrfs_find_item() to include find_orphan_item functionality")
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/ctree.c | 17 ++++-------------
fs/btrfs/disk-io.c | 9 ++++++++-
fs/btrfs/tree-log.c | 11 ++++++++++-
3 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 14a72ed14ef7..f54511dd287e 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -2609,32 +2609,23 @@ static int key_search(struct extent_buffer *b, struct btrfs_key *key,
return 0;
}
-int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
+int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path,
u64 iobjectid, u64 ioff, u8 key_type,
struct btrfs_key *found_key)
{
int ret;
struct btrfs_key key;
struct extent_buffer *eb;
- struct btrfs_path *path;
+
+ ASSERT(path);
key.type = key_type;
key.objectid = iobjectid;
key.offset = ioff;
- if (found_path == NULL) {
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
- } else
- path = found_path;
-
ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
- if ((ret < 0) || (found_key == NULL)) {
- if (path != found_path)
- btrfs_free_path(path);
+ if ((ret < 0) || (found_key == NULL))
return ret;
- }
eb = path->nodes[0];
if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 8c63419a7f70..6182e5493d0f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1630,6 +1630,7 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
bool check_ref)
{
struct btrfs_root *root;
+ struct btrfs_path *path;
int ret;
if (location->objectid == BTRFS_ROOT_TREE_OBJECTID)
@@ -1669,8 +1670,14 @@ again:
if (ret)
goto fail;
- ret = btrfs_find_item(fs_info->tree_root, NULL, BTRFS_ORPHAN_OBJECTID,
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ ret = btrfs_find_item(fs_info->tree_root, path, BTRFS_ORPHAN_OBJECTID,
location->objectid, BTRFS_ORPHAN_ITEM_KEY, NULL);
+ btrfs_free_path(path);
if (ret < 0)
goto fail;
if (ret == 0)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 9a02da16f2be..5be45c12dd71 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1257,10 +1257,19 @@ static int insert_orphan_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 offset)
{
int ret;
- ret = btrfs_find_item(root, NULL, BTRFS_ORPHAN_OBJECTID,
+ struct btrfs_path *path;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ ret = btrfs_find_item(root, path, BTRFS_ORPHAN_OBJECTID,
offset, BTRFS_ORPHAN_ITEM_KEY, NULL);
if (ret > 0)
ret = btrfs_insert_orphan_item(trans, root, offset);
+
+ btrfs_free_path(path);
+
return ret;
}
--
1.8.4.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/5] btrfs: cleanup, remove inode_item_info helper
2015-01-14 18:36 [PULL] [PATCH 0/5] Btrfs: leak in btrfs_find_item and cleanups David Sterba
2015-01-14 18:36 ` [PATCH 1/5] btrfs: fix leak of path in btrfs_find_item David Sterba
@ 2015-01-14 18:36 ` David Sterba
2015-01-14 18:36 ` [PATCH 3/5] btrfs: cleanup, remove inode_ref_info helper David Sterba
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-01-14 18:36 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
It's only a simple wrapper around btrfs_find_item, the locally defined
key is not used.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/backref.c | 11 -----------
fs/btrfs/backref.h | 3 ---
fs/btrfs/scrub.c | 6 +++++-
3 files changed, 5 insertions(+), 15 deletions(-)
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 2d3e32ebfd15..66554b3f7748 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -1246,17 +1246,6 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans,
return ret;
}
-/*
- * this makes the path point to (inum INODE_ITEM ioff)
- */
-int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
- struct btrfs_path *path)
-{
- struct btrfs_key key;
- return btrfs_find_item(fs_root, path, inum, ioff,
- BTRFS_INODE_ITEM_KEY, &key);
-}
-
static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
struct btrfs_path *path,
struct btrfs_key *found_key)
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
index 2a1ac6bfc724..9c41fbac3009 100644
--- a/fs/btrfs/backref.h
+++ b/fs/btrfs/backref.h
@@ -32,9 +32,6 @@ struct inode_fs_paths {
typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
void *ctx);
-int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
- struct btrfs_path *path);
-
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
struct btrfs_path *path, struct btrfs_key *found_key,
u64 *flags);
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index f2bb13a23f86..8bfe3b6fd471 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -530,7 +530,11 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
goto err;
}
- ret = inode_item_info(inum, 0, local_root, swarn->path);
+ /*
+ * this makes the path point to (inum INODE_ITEM ioff)
+ */
+ ret = btrfs_find_item(local_root, swarn->path, inum, 0,
+ BTRFS_INODE_ITEM_KEY, NULL);
if (ret) {
btrfs_release_path(swarn->path);
goto err;
--
1.8.4.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/5] btrfs: cleanup, remove inode_ref_info helper
2015-01-14 18:36 [PULL] [PATCH 0/5] Btrfs: leak in btrfs_find_item and cleanups David Sterba
2015-01-14 18:36 ` [PATCH 1/5] btrfs: fix leak of path in btrfs_find_item David Sterba
2015-01-14 18:36 ` [PATCH 2/5] btrfs: cleanup, remove inode_item_info helper David Sterba
@ 2015-01-14 18:36 ` David Sterba
2015-01-14 18:36 ` [PATCH 4/5] btrfs: simplify insert_orphan_item David Sterba
2015-01-14 18:36 ` [PATCH 5/5] btrfs: expand btrfs_find_item if found_key is NULL David Sterba
4 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-01-14 18:36 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
A simple wrapper around btrfs_find_item.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/backref.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 66554b3f7748..e715c16e9d07 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -1246,14 +1246,6 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans,
return ret;
}
-static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
- struct btrfs_path *path,
- struct btrfs_key *found_key)
-{
- return btrfs_find_item(fs_root, path, inum, ioff,
- BTRFS_INODE_REF_KEY, found_key);
-}
-
int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
u64 start_off, struct btrfs_path *path,
struct btrfs_inode_extref **ret_extref,
@@ -1363,7 +1355,8 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
btrfs_tree_read_unlock_blocking(eb);
free_extent_buffer(eb);
}
- ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
+ ret = btrfs_find_item(fs_root, path, parent, 0,
+ BTRFS_INODE_REF_KEY, &found_key);
if (ret > 0)
ret = -ENOENT;
if (ret)
@@ -1709,8 +1702,10 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
struct btrfs_key found_key;
while (!ret) {
- ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
- &found_key);
+ ret = btrfs_find_item(fs_root, path, inum,
+ parent ? parent + 1 : 0, BTRFS_INODE_REF_KEY,
+ &found_key);
+
if (ret < 0)
break;
if (ret) {
--
1.8.4.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/5] btrfs: simplify insert_orphan_item
2015-01-14 18:36 [PULL] [PATCH 0/5] Btrfs: leak in btrfs_find_item and cleanups David Sterba
` (2 preceding siblings ...)
2015-01-14 18:36 ` [PATCH 3/5] btrfs: cleanup, remove inode_ref_info helper David Sterba
@ 2015-01-14 18:36 ` David Sterba
2015-01-14 18:36 ` [PATCH 5/5] btrfs: expand btrfs_find_item if found_key is NULL David Sterba
4 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-01-14 18:36 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
We can search and add the orphan item in one go,
btrfs_insert_orphan_item will find out if the item already exists.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/tree-log.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 5be45c12dd71..25a1c363a5f4 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1254,21 +1254,13 @@ out:
}
static int insert_orphan_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 offset)
+ struct btrfs_root *root, u64 ino)
{
int ret;
- struct btrfs_path *path;
-
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
- ret = btrfs_find_item(root, path, BTRFS_ORPHAN_OBJECTID,
- offset, BTRFS_ORPHAN_ITEM_KEY, NULL);
- if (ret > 0)
- ret = btrfs_insert_orphan_item(trans, root, offset);
-
- btrfs_free_path(path);
+ ret = btrfs_insert_orphan_item(trans, root, ino);
+ if (ret == -EEXIST)
+ ret = 0;
return ret;
}
--
1.8.4.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 5/5] btrfs: expand btrfs_find_item if found_key is NULL
2015-01-14 18:36 [PULL] [PATCH 0/5] Btrfs: leak in btrfs_find_item and cleanups David Sterba
` (3 preceding siblings ...)
2015-01-14 18:36 ` [PATCH 4/5] btrfs: simplify insert_orphan_item David Sterba
@ 2015-01-14 18:36 ` David Sterba
4 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-01-14 18:36 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
If the found_key is NULL, then btrfs_find_item becomes a verbose wrapper
for simple btrfs_search_slot.
After we've removed all such callers, passing a NULL key is not valid
anymore.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/ctree.c | 3 ++-
fs/btrfs/disk-io.c | 8 ++++++--
fs/btrfs/inode.c | 10 +++++++---
fs/btrfs/scrub.c | 8 ++++++--
4 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index f54511dd287e..20d1f2b0403d 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -2618,13 +2618,14 @@ int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path,
struct extent_buffer *eb;
ASSERT(path);
+ ASSERT(found_key);
key.type = key_type;
key.objectid = iobjectid;
key.offset = ioff;
ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
- if ((ret < 0) || (found_key == NULL))
+ if (ret < 0)
return ret;
eb = path->nodes[0];
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 6182e5493d0f..8d486603e8a3 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1631,6 +1631,7 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
{
struct btrfs_root *root;
struct btrfs_path *path;
+ struct btrfs_key key;
int ret;
if (location->objectid == BTRFS_ROOT_TREE_OBJECTID)
@@ -1675,8 +1676,11 @@ again:
ret = -ENOMEM;
goto fail;
}
- ret = btrfs_find_item(fs_info->tree_root, path, BTRFS_ORPHAN_OBJECTID,
- location->objectid, BTRFS_ORPHAN_ITEM_KEY, NULL);
+ key.objectid = BTRFS_ORPHAN_OBJECTID;
+ key.type = BTRFS_ORPHAN_ITEM_KEY;
+ key.offset = location->objectid;
+
+ ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
btrfs_free_path(path);
if (ret < 0)
goto fail;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index e687bb0dc73a..cb69db7c273c 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5009,6 +5009,7 @@ static int fixup_tree_root_location(struct btrfs_root *root,
struct btrfs_root *new_root;
struct btrfs_root_ref *ref;
struct extent_buffer *leaf;
+ struct btrfs_key key;
int ret;
int err = 0;
@@ -5019,9 +5020,12 @@ static int fixup_tree_root_location(struct btrfs_root *root,
}
err = -ENOENT;
- ret = btrfs_find_item(root->fs_info->tree_root, path,
- BTRFS_I(dir)->root->root_key.objectid,
- location->objectid, BTRFS_ROOT_REF_KEY, NULL);
+ key.objectid = BTRFS_I(dir)->root->root_key.objectid;
+ key.type = BTRFS_ROOT_REF_KEY;
+ key.offset = location->objectid;
+
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, path,
+ 0, 0);
if (ret) {
if (ret < 0)
err = ret;
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 8bfe3b6fd471..0baf3b50c61f 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -520,6 +520,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
struct inode_fs_paths *ipath = NULL;
struct btrfs_root *local_root;
struct btrfs_key root_key;
+ struct btrfs_key key;
root_key.objectid = root;
root_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -533,8 +534,11 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
/*
* this makes the path point to (inum INODE_ITEM ioff)
*/
- ret = btrfs_find_item(local_root, swarn->path, inum, 0,
- BTRFS_INODE_ITEM_KEY, NULL);
+ key.objectid = inum;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(NULL, local_root, &key, swarn->path, 0, 0);
if (ret) {
btrfs_release_path(swarn->path);
goto err;
--
1.8.4.5
^ permalink raw reply related [flat|nested] 6+ messages in thread