* [PATCH 1/6] btrfs: send: remove prepared member from fs_path
2014-02-03 18:21 [PATCH 0/6] Btrfs send updates - reduce memory consumption David Sterba
@ 2014-02-03 18:23 ` David Sterba
2014-02-03 18:23 ` [PATCH 2/6] btrfs: send: remove virtual_mem " David Sterba
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2014-02-03 18:23 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
The member is used only to return value back from
fs_path_prepare_for_add, we can do it locally and save 8 bytes for the
inline_buf path.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/send.c | 26 +++++++++++++-------------
1 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 04c07ed51df5..524086a882f9 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -51,7 +51,6 @@ struct fs_path {
struct {
char *start;
char *end;
- char *prepared;
char *buf;
int buf_len;
@@ -338,7 +337,8 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
return 0;
}
-static int fs_path_prepare_for_add(struct fs_path *p, int name_len)
+static int fs_path_prepare_for_add(struct fs_path *p, int name_len,
+ char **prepared)
{
int ret;
int new_len;
@@ -354,11 +354,11 @@ static int fs_path_prepare_for_add(struct fs_path *p, int name_len)
if (p->start != p->end)
*--p->start = '/';
p->start -= name_len;
- p->prepared = p->start;
+ *prepared = p->start;
} else {
if (p->start != p->end)
*p->end++ = '/';
- p->prepared = p->end;
+ *prepared = p->end;
p->end += name_len;
*p->end = 0;
}
@@ -370,12 +370,12 @@ out:
static int fs_path_add(struct fs_path *p, const char *name, int name_len)
{
int ret;
+ char *prepared;
- ret = fs_path_prepare_for_add(p, name_len);
+ ret = fs_path_prepare_for_add(p, name_len, &prepared);
if (ret < 0)
goto out;
- memcpy(p->prepared, name, name_len);
- p->prepared = NULL;
+ memcpy(prepared, name, name_len);
out:
return ret;
@@ -384,12 +384,12 @@ out:
static int fs_path_add_path(struct fs_path *p, struct fs_path *p2)
{
int ret;
+ char *prepared;
- ret = fs_path_prepare_for_add(p, p2->end - p2->start);
+ ret = fs_path_prepare_for_add(p, p2->end - p2->start, &prepared);
if (ret < 0)
goto out;
- memcpy(p->prepared, p2->start, p2->end - p2->start);
- p->prepared = NULL;
+ memcpy(prepared, p2->start, p2->end - p2->start);
out:
return ret;
@@ -400,13 +400,13 @@ static int fs_path_add_from_extent_buffer(struct fs_path *p,
unsigned long off, int len)
{
int ret;
+ char *prepared;
- ret = fs_path_prepare_for_add(p, len);
+ ret = fs_path_prepare_for_add(p, len, &prepared);
if (ret < 0)
goto out;
- read_extent_buffer(eb, p->prepared, off, len);
- p->prepared = NULL;
+ read_extent_buffer(eb, prepared, off, len);
out:
return ret;
--
1.7.9
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/6] btrfs: send: remove virtual_mem member from fs_path
2014-02-03 18:21 [PATCH 0/6] Btrfs send updates - reduce memory consumption David Sterba
2014-02-03 18:23 ` [PATCH 1/6] btrfs: send: remove prepared member from fs_path David Sterba
@ 2014-02-03 18:23 ` David Sterba
2014-02-03 18:23 ` [PATCH 3/6] btrfs: send: squeeze bitfilelds in fs_path David Sterba
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2014-02-03 18:23 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
We don't need to keep track of that, it's available via is_vmalloc_addr.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/send.c | 8 ++------
1 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 524086a882f9..ea427624e842 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -55,7 +55,6 @@ struct fs_path {
char *buf;
int buf_len;
unsigned int reversed:1;
- unsigned int virtual_mem:1;
char inline_buf[];
};
char pad[PAGE_SIZE];
@@ -241,7 +240,6 @@ static struct fs_path *fs_path_alloc(void)
if (!p)
return NULL;
p->reversed = 0;
- p->virtual_mem = 0;
p->buf = p->inline_buf;
p->buf_len = FS_PATH_INLINE_SIZE;
fs_path_reset(p);
@@ -265,7 +263,7 @@ static void fs_path_free(struct fs_path *p)
if (!p)
return;
if (p->buf != p->inline_buf) {
- if (p->virtual_mem)
+ if (is_vmalloc_addr(p->buf))
vfree(p->buf);
else
kfree(p->buf);
@@ -299,13 +297,12 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
tmp_buf = vmalloc(len);
if (!tmp_buf)
return -ENOMEM;
- p->virtual_mem = 1;
}
memcpy(tmp_buf, p->buf, p->buf_len);
p->buf = tmp_buf;
p->buf_len = len;
} else {
- if (p->virtual_mem) {
+ if (is_vmalloc_addr(p->buf)) {
tmp_buf = vmalloc(len);
if (!tmp_buf)
return -ENOMEM;
@@ -319,7 +316,6 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
return -ENOMEM;
memcpy(tmp_buf, p->buf, p->buf_len);
kfree(p->buf);
- p->virtual_mem = 1;
}
}
p->buf = tmp_buf;
--
1.7.9
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/6] btrfs: send: squeeze bitfilelds in fs_path
2014-02-03 18:21 [PATCH 0/6] Btrfs send updates - reduce memory consumption David Sterba
2014-02-03 18:23 ` [PATCH 1/6] btrfs: send: remove prepared member from fs_path David Sterba
2014-02-03 18:23 ` [PATCH 2/6] btrfs: send: remove virtual_mem " David Sterba
@ 2014-02-03 18:23 ` David Sterba
2014-02-03 18:23 ` [PATCH 4/6] btrfs: send: lower memory requirements in common case David Sterba
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2014-02-03 18:23 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
We know that buf_len is at most PATH_MAX, 4k, and can merge it with the
reversed member. This saves 3 bytes in favor of inline_buf.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/send.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index ea427624e842..cb12c2ec37dc 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -53,8 +53,8 @@ struct fs_path {
char *end;
char *buf;
- int buf_len;
- unsigned int reversed:1;
+ unsigned short buf_len:15;
+ unsigned short reversed:1;
char inline_buf[];
};
char pad[PAGE_SIZE];
--
1.7.9
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/6] btrfs: send: lower memory requirements in common case
2014-02-03 18:21 [PATCH 0/6] Btrfs send updates - reduce memory consumption David Sterba
` (2 preceding siblings ...)
2014-02-03 18:23 ` [PATCH 3/6] btrfs: send: squeeze bitfilelds in fs_path David Sterba
@ 2014-02-03 18:23 ` David Sterba
2014-02-03 18:24 ` [PATCH 5/6] btrfs: send: remove BUG from process_all_refs David Sterba
2014-02-03 18:24 ` [PATCH 6/6] btrfs: send: remove BUG_ON from name_cache_delete David Sterba
5 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2014-02-03 18:23 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
The fs_path structure uses an inline buffer and falls back to a chain of
allocations, but vmalloc is not necessary because PATH_MAX fits into
PAGE_SIZE.
The size of fs_path has been reduced to 256 bytes from PAGE_SIZE,
usually 4k. Experimental measurements show that most paths on a single
filesystem do not exceed 200 bytes, and these get stored into the inline
buffer directly, which is now 230 bytes. Longer paths are kmalloced when
needed.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/send.c | 103 ++++++++++++++++++-------------------------------------
1 files changed, 34 insertions(+), 69 deletions(-)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index cb12c2ec37dc..4e3a3d413417 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -57,7 +57,12 @@ struct fs_path {
unsigned short reversed:1;
char inline_buf[];
};
- char pad[PAGE_SIZE];
+ /*
+ * Average path length does not exceed 200 bytes, we'll have
+ * better packing in the slab and higher chance to satisfy
+ * a allocation later during send.
+ */
+ char pad[256];
};
};
#define FS_PATH_INLINE_SIZE \
@@ -262,12 +267,8 @@ static void fs_path_free(struct fs_path *p)
{
if (!p)
return;
- if (p->buf != p->inline_buf) {
- if (is_vmalloc_addr(p->buf))
- vfree(p->buf);
- else
- kfree(p->buf);
- }
+ if (p->buf != p->inline_buf)
+ kfree(p->buf);
kfree(p);
}
@@ -287,40 +288,28 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
if (p->buf_len >= len)
return 0;
- path_len = p->end - p->start;
- old_buf_len = p->buf_len;
- len = PAGE_ALIGN(len);
-
+ /*
+ * First time the inline_buf does not suffice
+ */
if (p->buf == p->inline_buf) {
- tmp_buf = kmalloc(len, GFP_NOFS | __GFP_NOWARN);
- if (!tmp_buf) {
- tmp_buf = vmalloc(len);
- if (!tmp_buf)
- return -ENOMEM;
- }
- memcpy(tmp_buf, p->buf, p->buf_len);
- p->buf = tmp_buf;
- p->buf_len = len;
+ p->buf = kmalloc(len, GFP_NOFS);
+ if (!p->buf)
+ return -ENOMEM;
+ /*
+ * The real size of the buffer is bigger, this will let the
+ * fast path happen most of the time
+ */
+ p->buf_len = ksize(p->buf);
} else {
- if (is_vmalloc_addr(p->buf)) {
- tmp_buf = vmalloc(len);
- if (!tmp_buf)
- return -ENOMEM;
- memcpy(tmp_buf, p->buf, p->buf_len);
- vfree(p->buf);
- } else {
- tmp_buf = krealloc(p->buf, len, GFP_NOFS);
- if (!tmp_buf) {
- tmp_buf = vmalloc(len);
- if (!tmp_buf)
- return -ENOMEM;
- memcpy(tmp_buf, p->buf, p->buf_len);
- kfree(p->buf);
- }
- }
- p->buf = tmp_buf;
- p->buf_len = len;
+ p->buf = krealloc(p->buf, len, GFP_NOFS);
+ if (!p->buf)
+ return -ENOMEM;
+ p->buf_len = ksize(p->buf);
}
+
+ path_len = p->end - p->start;
+ old_buf_len = p->buf_len;
+
if (p->reversed) {
tmp_buf = p->buf + old_buf_len - path_len - 1;
p->end = p->buf + p->buf_len - 1;
@@ -911,9 +900,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_dir_item *di;
struct btrfs_key di_key;
char *buf = NULL;
- char *buf2 = NULL;
- int buf_len;
- int buf_virtual = 0;
+ const int buf_len = PATH_MAX;
u32 name_len;
u32 data_len;
u32 cur;
@@ -923,7 +910,6 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
int num;
u8 type;
- buf_len = PAGE_SIZE;
buf = kmalloc(buf_len, GFP_NOFS);
if (!buf) {
ret = -ENOMEM;
@@ -945,30 +931,12 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
type = btrfs_dir_type(eb, di);
btrfs_dir_item_key_to_cpu(eb, di, &di_key);
+ /*
+ * Path too long
+ */
if (name_len + data_len > buf_len) {
- buf_len = PAGE_ALIGN(name_len + data_len);
- if (buf_virtual) {
- buf2 = vmalloc(buf_len);
- if (!buf2) {
- ret = -ENOMEM;
- goto out;
- }
- vfree(buf);
- } else {
- buf2 = krealloc(buf, buf_len, GFP_NOFS);
- if (!buf2) {
- buf2 = vmalloc(buf_len);
- if (!buf2) {
- ret = -ENOMEM;
- goto out;
- }
- kfree(buf);
- buf_virtual = 1;
- }
- }
-
- buf = buf2;
- buf2 = NULL;
+ ret = -ENAMETOOLONG;
+ goto out;
}
read_extent_buffer(eb, buf, (unsigned long)(di + 1),
@@ -991,10 +959,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
}
out:
- if (buf_virtual)
- vfree(buf);
- else
- kfree(buf);
+ kfree(buf);
return ret;
}
--
1.7.9
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 5/6] btrfs: send: remove BUG from process_all_refs
2014-02-03 18:21 [PATCH 0/6] Btrfs send updates - reduce memory consumption David Sterba
` (3 preceding siblings ...)
2014-02-03 18:23 ` [PATCH 4/6] btrfs: send: lower memory requirements in common case David Sterba
@ 2014-02-03 18:24 ` David Sterba
2014-02-03 18:24 ` [PATCH 6/6] btrfs: send: remove BUG_ON from name_cache_delete David Sterba
5 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2014-02-03 18:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
There are only 2 static callers, the BUG would normally be never
reached, but let's be nice.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/send.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 4e3a3d413417..b0bf4ff40b5b 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -3568,7 +3568,10 @@ static int process_all_refs(struct send_ctx *sctx,
root = sctx->parent_root;
cb = __record_deleted_ref;
} else {
- BUG();
+ btrfs_err(sctx->send_root->fs_info,
+ "Wrong command %d in process_all_refs", cmd);
+ ret = -EINVAL;
+ goto out;
}
key.objectid = sctx->cmp_key->objectid;
--
1.7.9
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 6/6] btrfs: send: remove BUG_ON from name_cache_delete
2014-02-03 18:21 [PATCH 0/6] Btrfs send updates - reduce memory consumption David Sterba
` (4 preceding siblings ...)
2014-02-03 18:24 ` [PATCH 5/6] btrfs: send: remove BUG from process_all_refs David Sterba
@ 2014-02-03 18:24 ` David Sterba
5 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2014-02-03 18:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
If cleaning the name cache fails, we could try to proceed at the cost of
some memory leak. This is not expected to happen often.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
fs/btrfs/send.c | 11 +++++++++--
1 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index b0bf4ff40b5b..7b17b778eaf7 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -1849,13 +1849,20 @@ static void name_cache_delete(struct send_ctx *sctx,
nce_head = radix_tree_lookup(&sctx->name_cache,
(unsigned long)nce->ino);
- BUG_ON(!nce_head);
+ if (!nce_head) {
+ btrfs_err(sctx->send_root->fs_info,
+ "name_cache_delete lookup failed ino %llu cache size %d, leaking memory",
+ nce->ino, sctx->name_cache_size);
+ }
list_del(&nce->radix_list);
list_del(&nce->list);
sctx->name_cache_size--;
- if (list_empty(nce_head)) {
+ /*
+ * We may not get to the final release of nce_head if the lookup fails
+ */
+ if (nce_head && list_empty(nce_head)) {
radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
kfree(nce_head);
}
--
1.7.9
^ permalink raw reply related [flat|nested] 7+ messages in thread