Compare commits

..

2 Commits

Author SHA1 Message Date
Zach Brown
1259f899a3 srch compaction needs to prepare alloc for commit
The srch client compaction work initializes allocators, dirties blocks,
and writes them out as its transaction.  It forgot to call the
pre-commit allocator prepare function.

The prepare function drops block references used by the meta allocator
during the transaction.  This leaked block references which kept blocks
from being freed by the shrinker under memory pressure.  Eventually
memory was full of leaked blocks and the shrinker walked all of them
looking blocks to free, resulting in an effective livelock that ground
the system to a crawl.

Signed-off-by: Zach Brown <zab@versity.com>
2021-04-01 13:04:40 -07:00
Zach Brown
2d393f435b Warn on leaked block refs on unmount
By the time we get to destroying the block cache we should have put all
our block references.  Warn as we tear down the blocks if we see any
blocks that still have references, implying a ref leak.  This caught a
leak caused by srch compaction forgetting to put allocator list block
refs.

Signed-off-by: Zach Brown <zab@versity.com>
2021-04-01 13:04:06 -07:00
3 changed files with 3 additions and 83 deletions

View File

@@ -1,82 +0,0 @@
We try to maintain a consistent coding style across the project. It's
admitedly arbitrary and starts with and is based on upstream's
Documentation/CodingStyle. Conventions are added here as they come up
during review. We'll demonstrate each sylistic preference with a diff
snippet.
== Try to make one exit point for reasonably long functions
{
- void *a;
- void *b;
+ void *a = NULL;
+ void *b = NULL;
+ int ret;
a = kalloc();
- if (!a)
- return 1;
+ if (!a) {
+ ret = 1;
+ goto out;
+ }
b = kalloc();
if (!b) {
- kfree(a);
- return 2;
+ ret = 2;
+ goto out;
}
- return 3
+ ret = 3;
+out:
+ kfree(a);
+ kfree(b);
+ return ret;
}
The idea is to initialize all state at the top of the function,
modifying it throughout, and clean it all up at the end. Having one
exit point also gives us a place to add tracing of function exit.
== Multiple declarations on a line
- int i, j;
+ int i;
+ int j;
Declare function variables one per line. The verbose declarations
create pressure to think about excessive stack use or over-long
functions, makes initializers clear, and leaves room for comments.
== Balance braces
- if (IS_ERR(super_block))
+ if (IS_ERR(super_block)) {
return PTR_ERR(super_block);
- else {
+ } else {
*super_res = *super_block;
kfree(super_block);
return 0;
}
*nervous twitch*
== Cute variable defintion waterfalls
+ struct block_device *meta_bdev;
struct scoutfs_sb_info *sbi;
struct mount_options opts;
- struct block_device *meta_bdev;
struct inode *inode;
This isn't strictly necessary, but it's nice to try and make a pretty
descending length of variable distributions. It often has the
accidental effect of sorting definitions by decreasing complexity. I
tend to group types when the name lengths are pretty close, even if
they're not strictly sorted, so that all the ints, u64s, keys, etc, are
all together.

View File

@@ -396,6 +396,7 @@ static void block_remove_all(struct super_block *sb)
if (block_get_if_inserted(bp)) {
block_remove(sb, bp);
WARN_ON_ONCE(atomic_read(&bp->refcount) != 1);
block_put(sb, bp);
}
}

View File

@@ -2156,7 +2156,8 @@ static void scoutfs_srch_compact_worker(struct work_struct *work)
if (ret < 0)
goto commit;
ret = scoutfs_block_writer_write(sb, &wri);
ret = scoutfs_alloc_prepare_commit(sb, &alloc, &wri) ?:
scoutfs_block_writer_write(sb, &wri);
commit:
/* the server won't use our partial compact if _ERROR is set */
sc->meta_avail = alloc.avail;