mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
bcache: A block layer cache
Does writethrough and writeback caching, handles unclean shutdown, and has a bunch of other nifty features motivated by real world usage. See the wiki at http://bcache.evilpiepirate.org for more. Signed-off-by: Kent Overstreet <koverstreet@google.com>
This commit is contained in:
156
Documentation/ABI/testing/sysfs-block-bcache
Normal file
156
Documentation/ABI/testing/sysfs-block-bcache
Normal file
@@ -0,0 +1,156 @@
|
||||
What: /sys/block/<disk>/bcache/unregister
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
A write to this file causes the backing device or cache to be
|
||||
unregistered. If a backing device had dirty data in the cache,
|
||||
writeback mode is automatically disabled and all dirty data is
|
||||
flushed before the device is unregistered. Caches unregister
|
||||
all associated backing devices before unregistering themselves.
|
||||
|
||||
What: /sys/block/<disk>/bcache/clear_stats
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
Writing to this file resets all the statistics for the device.
|
||||
|
||||
What: /sys/block/<disk>/bcache/cache
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a backing device that has cache, a symlink to
|
||||
the bcache/ dir of that cache.
|
||||
|
||||
What: /sys/block/<disk>/bcache/cache_hits
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: integer number of full cache hits,
|
||||
counted per bio. A partial cache hit counts as a miss.
|
||||
|
||||
What: /sys/block/<disk>/bcache/cache_misses
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: integer number of cache misses.
|
||||
|
||||
What: /sys/block/<disk>/bcache/cache_hit_ratio
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: cache hits as a percentage.
|
||||
|
||||
What: /sys/block/<disk>/bcache/sequential_cutoff
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: Threshold past which sequential IO will
|
||||
skip the cache. Read and written as bytes in human readable
|
||||
units (i.e. echo 10M > sequntial_cutoff).
|
||||
|
||||
What: /sys/block/<disk>/bcache/bypassed
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
Sum of all reads and writes that have bypassed the cache (due
|
||||
to the sequential cutoff). Expressed as bytes in human
|
||||
readable units.
|
||||
|
||||
What: /sys/block/<disk>/bcache/writeback
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: When on, writeback caching is enabled and
|
||||
writes will be buffered in the cache. When off, caching is in
|
||||
writethrough mode; reads and writes will be added to the
|
||||
cache but no write buffering will take place.
|
||||
|
||||
What: /sys/block/<disk>/bcache/writeback_running
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: when off, dirty data will not be written
|
||||
from the cache to the backing device. The cache will still be
|
||||
used to buffer writes until it is mostly full, at which point
|
||||
writes transparently revert to writethrough mode. Intended only
|
||||
for benchmarking/testing.
|
||||
|
||||
What: /sys/block/<disk>/bcache/writeback_delay
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: In writeback mode, when dirty data is
|
||||
written to the cache and the cache held no dirty data for that
|
||||
backing device, writeback from cache to backing device starts
|
||||
after this delay, expressed as an integer number of seconds.
|
||||
|
||||
What: /sys/block/<disk>/bcache/writeback_percent
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For backing devices: If nonzero, writeback from cache to
|
||||
backing device only takes place when more than this percentage
|
||||
of the cache is used, allowing more write coalescing to take
|
||||
place and reducing total number of writes sent to the backing
|
||||
device. Integer between 0 and 40.
|
||||
|
||||
What: /sys/block/<disk>/bcache/synchronous
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, a boolean that allows synchronous mode to be
|
||||
switched on and off. In synchronous mode all writes are ordered
|
||||
such that the cache can reliably recover from unclean shutdown;
|
||||
if disabled bcache will not generally wait for writes to
|
||||
complete but if the cache is not shut down cleanly all data
|
||||
will be discarded from the cache. Should not be turned off with
|
||||
writeback caching enabled.
|
||||
|
||||
What: /sys/block/<disk>/bcache/discard
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, a boolean allowing discard/TRIM to be turned off
|
||||
or back on if the device supports it.
|
||||
|
||||
What: /sys/block/<disk>/bcache/bucket_size
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, bucket size in human readable units, as set at
|
||||
cache creation time; should match the erase block size of the
|
||||
SSD for optimal performance.
|
||||
|
||||
What: /sys/block/<disk>/bcache/nbuckets
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, the number of usable buckets.
|
||||
|
||||
What: /sys/block/<disk>/bcache/tree_depth
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, height of the btree excluding leaf nodes (i.e. a
|
||||
one node tree will have a depth of 0).
|
||||
|
||||
What: /sys/block/<disk>/bcache/btree_cache_size
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
Number of btree buckets/nodes that are currently cached in
|
||||
memory; cache dynamically grows and shrinks in response to
|
||||
memory pressure from the rest of the system.
|
||||
|
||||
What: /sys/block/<disk>/bcache/written
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, total amount of data in human readable units
|
||||
written to the cache, excluding all metadata.
|
||||
|
||||
What: /sys/block/<disk>/bcache/btree_written
|
||||
Date: November 2010
|
||||
Contact: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Description:
|
||||
For a cache, sum of all btree writes in human readable units.
|
||||
343
Documentation/bcache.txt
Normal file
343
Documentation/bcache.txt
Normal file
@@ -0,0 +1,343 @@
|
||||
Say you've got a big slow raid 6, and an X-25E or three. Wouldn't it be
|
||||
nice if you could use them as cache... Hence bcache.
|
||||
|
||||
Wiki and git repositories are at:
|
||||
http://bcache.evilpiepirate.org
|
||||
http://evilpiepirate.org/git/linux-bcache.git
|
||||
http://evilpiepirate.org/git/bcache-tools.git
|
||||
|
||||
It's designed around the performance characteristics of SSDs - it only allocates
|
||||
in erase block sized buckets, and it uses a hybrid btree/log to track cached
|
||||
extants (which can be anywhere from a single sector to the bucket size). It's
|
||||
designed to avoid random writes at all costs; it fills up an erase block
|
||||
sequentially, then issues a discard before reusing it.
|
||||
|
||||
Both writethrough and writeback caching are supported. Writeback defaults to
|
||||
off, but can be switched on and off arbitrarily at runtime. Bcache goes to
|
||||
great lengths to protect your data - it reliably handles unclean shutdown. (It
|
||||
doesn't even have a notion of a clean shutdown; bcache simply doesn't return
|
||||
writes as completed until they're on stable storage).
|
||||
|
||||
Writeback caching can use most of the cache for buffering writes - writing
|
||||
dirty data to the backing device is always done sequentially, scanning from the
|
||||
start to the end of the index.
|
||||
|
||||
Since random IO is what SSDs excel at, there generally won't be much benefit
|
||||
to caching large sequential IO. Bcache detects sequential IO and skips it;
|
||||
it also keeps a rolling average of the IO sizes per task, and as long as the
|
||||
average is above the cutoff it will skip all IO from that task - instead of
|
||||
caching the first 512k after every seek. Backups and large file copies should
|
||||
thus entirely bypass the cache.
|
||||
|
||||
In the event of a data IO error on the flash it will try to recover by reading
|
||||
from disk or invalidating cache entries. For unrecoverable errors (meta data
|
||||
or dirty data), caching is automatically disabled; if dirty data was present
|
||||
in the cache it first disables writeback caching and waits for all dirty data
|
||||
to be flushed.
|
||||
|
||||
Getting started:
|
||||
You'll need make-bcache from the bcache-tools repository. Both the cache device
|
||||
and backing device must be formatted before use.
|
||||
make-bcache -B /dev/sdb
|
||||
make-bcache -C /dev/sdc
|
||||
|
||||
make-bcache has the ability to format multiple devices at the same time - if
|
||||
you format your backing devices and cache device at the same time, you won't
|
||||
have to manually attach:
|
||||
make-bcache -B /dev/sda /dev/sdb -C /dev/sdc
|
||||
|
||||
To make bcache devices known to the kernel, echo them to /sys/fs/bcache/register:
|
||||
|
||||
echo /dev/sdb > /sys/fs/bcache/register
|
||||
echo /dev/sdc > /sys/fs/bcache/register
|
||||
|
||||
To register your bcache devices automatically, you could add something like
|
||||
this to an init script:
|
||||
|
||||
echo /dev/sd* > /sys/fs/bcache/register_quiet
|
||||
|
||||
It'll look for bcache superblocks and ignore everything that doesn't have one.
|
||||
|
||||
Registering the backing device makes the bcache show up in /dev; you can now
|
||||
format it and use it as normal. But the first time using a new bcache device,
|
||||
it'll be running in passthrough mode until you attach it to a cache. See the
|
||||
section on attaching.
|
||||
|
||||
The devices show up at /dev/bcacheN, and can be controlled via sysfs from
|
||||
/sys/block/bcacheN/bcache:
|
||||
|
||||
mkfs.ext4 /dev/bcache0
|
||||
mount /dev/bcache0 /mnt
|
||||
|
||||
Cache devices are managed as sets; multiple caches per set isn't supported yet
|
||||
but will allow for mirroring of metadata and dirty data in the future. Your new
|
||||
cache set shows up as /sys/fs/bcache/<UUID>
|
||||
|
||||
ATTACHING:
|
||||
|
||||
After your cache device and backing device are registered, the backing device
|
||||
must be attached to your cache set to enable caching. Attaching a backing
|
||||
device to a cache set is done thusly, with the UUID of the cache set in
|
||||
/sys/fs/bcache:
|
||||
|
||||
echo <UUID> > /sys/block/bcache0/bcache/attach
|
||||
|
||||
This only has to be done once. The next time you reboot, just reregister all
|
||||
your bcache devices. If a backing device has data in a cache somewhere, the
|
||||
/dev/bcache# device won't be created until the cache shows up - particularly
|
||||
important if you have writeback caching turned on.
|
||||
|
||||
If you're booting up and your cache device is gone and never coming back, you
|
||||
can force run the backing device:
|
||||
|
||||
echo 1 > /sys/block/sdb/bcache/running
|
||||
|
||||
(You need to use /sys/block/sdb (or whatever your backing device is called), not
|
||||
/sys/block/bcache0, because bcache0 doesn't exist yet. If you're using a
|
||||
partition, the bcache directory would be at /sys/block/sdb/sdb2/bcache)
|
||||
|
||||
The backing device will still use that cache set if it shows up in the future,
|
||||
but all the cached data will be invalidated. If there was dirty data in the
|
||||
cache, don't expect the filesystem to be recoverable - you will have massive
|
||||
filesystem corruption, though ext4's fsck does work miracles.
|
||||
|
||||
SYSFS - BACKING DEVICE:
|
||||
|
||||
attach
|
||||
Echo the UUID of a cache set to this file to enable caching.
|
||||
|
||||
cache_mode
|
||||
Can be one of either writethrough, writeback, writearound or none.
|
||||
|
||||
clear_stats
|
||||
Writing to this file resets the running total stats (not the day/hour/5 minute
|
||||
decaying versions).
|
||||
|
||||
detach
|
||||
Write to this file to detach from a cache set. If there is dirty data in the
|
||||
cache, it will be flushed first.
|
||||
|
||||
dirty_data
|
||||
Amount of dirty data for this backing device in the cache. Continuously
|
||||
updated unlike the cache set's version, but may be slightly off.
|
||||
|
||||
label
|
||||
Name of underlying device.
|
||||
|
||||
readahead
|
||||
Size of readahead that should be performed. Defaults to 0. If set to e.g.
|
||||
1M, it will round cache miss reads up to that size, but without overlapping
|
||||
existing cache entries.
|
||||
|
||||
running
|
||||
1 if bcache is running (i.e. whether the /dev/bcache device exists, whether
|
||||
it's in passthrough mode or caching).
|
||||
|
||||
sequential_cutoff
|
||||
A sequential IO will bypass the cache once it passes this threshhold; the
|
||||
most recent 128 IOs are tracked so sequential IO can be detected even when
|
||||
it isn't all done at once.
|
||||
|
||||
sequential_merge
|
||||
If non zero, bcache keeps a list of the last 128 requests submitted to compare
|
||||
against all new requests to determine which new requests are sequential
|
||||
continuations of previous requests for the purpose of determining sequential
|
||||
cutoff. This is necessary if the sequential cutoff value is greater than the
|
||||
maximum acceptable sequential size for any single request.
|
||||
|
||||
state
|
||||
The backing device can be in one of four different states:
|
||||
|
||||
no cache: Has never been attached to a cache set.
|
||||
|
||||
clean: Part of a cache set, and there is no cached dirty data.
|
||||
|
||||
dirty: Part of a cache set, and there is cached dirty data.
|
||||
|
||||
inconsistent: The backing device was forcibly run by the user when there was
|
||||
dirty data cached but the cache set was unavailable; whatever data was on the
|
||||
backing device has likely been corrupted.
|
||||
|
||||
stop
|
||||
Write to this file to shut down the bcache device and close the backing
|
||||
device.
|
||||
|
||||
writeback_delay
|
||||
When dirty data is written to the cache and it previously did not contain
|
||||
any, waits some number of seconds before initiating writeback. Defaults to
|
||||
30.
|
||||
|
||||
writeback_percent
|
||||
If nonzero, bcache tries to keep around this percentage of the cache dirty by
|
||||
throttling background writeback and using a PD controller to smoothly adjust
|
||||
the rate.
|
||||
|
||||
writeback_rate
|
||||
Rate in sectors per second - if writeback_percent is nonzero, background
|
||||
writeback is throttled to this rate. Continuously adjusted by bcache but may
|
||||
also be set by the user.
|
||||
|
||||
writeback_running
|
||||
If off, writeback of dirty data will not take place at all. Dirty data will
|
||||
still be added to the cache until it is mostly full; only meant for
|
||||
benchmarking. Defaults to on.
|
||||
|
||||
SYSFS - BACKING DEVICE STATS:
|
||||
|
||||
There are directories with these numbers for a running total, as well as
|
||||
versions that decay over the past day, hour and 5 minutes; they're also
|
||||
aggregated in the cache set directory as well.
|
||||
|
||||
bypassed
|
||||
Amount of IO (both reads and writes) that has bypassed the cache
|
||||
|
||||
cache_hits
|
||||
cache_misses
|
||||
cache_hit_ratio
|
||||
Hits and misses are counted per individual IO as bcache sees them; a
|
||||
partial hit is counted as a miss.
|
||||
|
||||
cache_bypass_hits
|
||||
cache_bypass_misses
|
||||
Hits and misses for IO that is intended to skip the cache are still counted,
|
||||
but broken out here.
|
||||
|
||||
cache_miss_collisions
|
||||
Counts instances where data was going to be inserted into the cache from a
|
||||
cache miss, but raced with a write and data was already present (usually 0
|
||||
since the synchronization for cache misses was rewritten)
|
||||
|
||||
cache_readaheads
|
||||
Count of times readahead occured.
|
||||
|
||||
SYSFS - CACHE SET:
|
||||
|
||||
average_key_size
|
||||
Average data per key in the btree.
|
||||
|
||||
bdev<0..n>
|
||||
Symlink to each of the attached backing devices.
|
||||
|
||||
block_size
|
||||
Block size of the cache devices.
|
||||
|
||||
btree_cache_size
|
||||
Amount of memory currently used by the btree cache
|
||||
|
||||
bucket_size
|
||||
Size of buckets
|
||||
|
||||
cache<0..n>
|
||||
Symlink to each of the cache devices comprising this cache set.
|
||||
|
||||
cache_available_percent
|
||||
Percentage of cache device free.
|
||||
|
||||
clear_stats
|
||||
Clears the statistics associated with this cache
|
||||
|
||||
dirty_data
|
||||
Amount of dirty data is in the cache (updated when garbage collection runs).
|
||||
|
||||
flash_vol_create
|
||||
Echoing a size to this file (in human readable units, k/M/G) creates a thinly
|
||||
provisioned volume backed by the cache set.
|
||||
|
||||
io_error_halflife
|
||||
io_error_limit
|
||||
These determines how many errors we accept before disabling the cache.
|
||||
Each error is decayed by the half life (in # ios). If the decaying count
|
||||
reaches io_error_limit dirty data is written out and the cache is disabled.
|
||||
|
||||
journal_delay_ms
|
||||
Journal writes will delay for up to this many milliseconds, unless a cache
|
||||
flush happens sooner. Defaults to 100.
|
||||
|
||||
root_usage_percent
|
||||
Percentage of the root btree node in use. If this gets too high the node
|
||||
will split, increasing the tree depth.
|
||||
|
||||
stop
|
||||
Write to this file to shut down the cache set - waits until all attached
|
||||
backing devices have been shut down.
|
||||
|
||||
tree_depth
|
||||
Depth of the btree (A single node btree has depth 0).
|
||||
|
||||
unregister
|
||||
Detaches all backing devices and closes the cache devices; if dirty data is
|
||||
present it will disable writeback caching and wait for it to be flushed.
|
||||
|
||||
SYSFS - CACHE SET INTERNAL:
|
||||
|
||||
This directory also exposes timings for a number of internal operations, with
|
||||
separate files for average duration, average frequency, last occurence and max
|
||||
duration: garbage collection, btree read, btree node sorts and btree splits.
|
||||
|
||||
active_journal_entries
|
||||
Number of journal entries that are newer than the index.
|
||||
|
||||
btree_nodes
|
||||
Total nodes in the btree.
|
||||
|
||||
btree_used_percent
|
||||
Average fraction of btree in use.
|
||||
|
||||
bset_tree_stats
|
||||
Statistics about the auxiliary search trees
|
||||
|
||||
btree_cache_max_chain
|
||||
Longest chain in the btree node cache's hash table
|
||||
|
||||
cache_read_races
|
||||
Counts instances where while data was being read from the cache, the bucket
|
||||
was reused and invalidated - i.e. where the pointer was stale after the read
|
||||
completed. When this occurs the data is reread from the backing device.
|
||||
|
||||
trigger_gc
|
||||
Writing to this file forces garbage collection to run.
|
||||
|
||||
SYSFS - CACHE DEVICE:
|
||||
|
||||
block_size
|
||||
Minimum granularity of writes - should match hardware sector size.
|
||||
|
||||
btree_written
|
||||
Sum of all btree writes, in (kilo/mega/giga) bytes
|
||||
|
||||
bucket_size
|
||||
Size of buckets
|
||||
|
||||
cache_replacement_policy
|
||||
One of either lru, fifo or random.
|
||||
|
||||
discard
|
||||
Boolean; if on a discard/TRIM will be issued to each bucket before it is
|
||||
reused. Defaults to off, since SATA TRIM is an unqueued command (and thus
|
||||
slow).
|
||||
|
||||
freelist_percent
|
||||
Size of the freelist as a percentage of nbuckets. Can be written to to
|
||||
increase the number of buckets kept on the freelist, which lets you
|
||||
artificially reduce the size of the cache at runtime. Mostly for testing
|
||||
purposes (i.e. testing how different size caches affect your hit rate), but
|
||||
since buckets are discarded when they move on to the freelist will also make
|
||||
the SSD's garbage collection easier by effectively giving it more reserved
|
||||
space.
|
||||
|
||||
io_errors
|
||||
Number of errors that have occured, decayed by io_error_halflife.
|
||||
|
||||
metadata_written
|
||||
Sum of all non data writes (btree writes and all other metadata).
|
||||
|
||||
nbuckets
|
||||
Total buckets in this cache
|
||||
|
||||
priority_stats
|
||||
Statistics about how recently data in the cache has been accessed. This can
|
||||
reveal your working set size.
|
||||
|
||||
written
|
||||
Sum of all data that has been written to the cache; comparison with
|
||||
btree_written gives the amount of write inflation in bcache.
|
||||
@@ -1616,6 +1616,13 @@ W: http://www.baycom.org/~tom/ham/ham.html
|
||||
S: Maintained
|
||||
F: drivers/net/hamradio/baycom*
|
||||
|
||||
BCACHE (BLOCK LAYER CACHE)
|
||||
M: Kent Overstreet <koverstreet@google.com>
|
||||
L: linux-bcache@vger.kernel.org
|
||||
W: http://bcache.evilpiepirate.org
|
||||
S: Maintained:
|
||||
F: drivers/md/bcache/
|
||||
|
||||
BEFS FILE SYSTEM
|
||||
S: Orphan
|
||||
F: Documentation/filesystems/befs.txt
|
||||
|
||||
@@ -174,6 +174,8 @@ config MD_FAULTY
|
||||
|
||||
In unsure, say N.
|
||||
|
||||
source "drivers/md/bcache/Kconfig"
|
||||
|
||||
config BLK_DEV_DM
|
||||
tristate "Device mapper support"
|
||||
---help---
|
||||
|
||||
@@ -29,6 +29,7 @@ obj-$(CONFIG_MD_RAID10) += raid10.o
|
||||
obj-$(CONFIG_MD_RAID456) += raid456.o
|
||||
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
|
||||
obj-$(CONFIG_MD_FAULTY) += faulty.o
|
||||
obj-$(CONFIG_BCACHE) += bcache/
|
||||
obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
|
||||
obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
|
||||
obj-$(CONFIG_DM_BUFIO) += dm-bufio.o
|
||||
|
||||
42
drivers/md/bcache/Kconfig
Normal file
42
drivers/md/bcache/Kconfig
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
config BCACHE
|
||||
tristate "Block device as cache"
|
||||
select CLOSURES
|
||||
---help---
|
||||
Allows a block device to be used as cache for other devices; uses
|
||||
a btree for indexing and the layout is optimized for SSDs.
|
||||
|
||||
See Documentation/bcache.txt for details.
|
||||
|
||||
config BCACHE_DEBUG
|
||||
bool "Bcache debugging"
|
||||
depends on BCACHE
|
||||
---help---
|
||||
Don't select this option unless you're a developer
|
||||
|
||||
Enables extra debugging tools (primarily a fuzz tester)
|
||||
|
||||
config BCACHE_EDEBUG
|
||||
bool "Extended runtime checks"
|
||||
depends on BCACHE
|
||||
---help---
|
||||
Don't select this option unless you're a developer
|
||||
|
||||
Enables extra runtime checks which significantly affect performance
|
||||
|
||||
config BCACHE_CLOSURES_DEBUG
|
||||
bool "Debug closures"
|
||||
depends on BCACHE
|
||||
select DEBUG_FS
|
||||
---help---
|
||||
Keeps all active closures in a linked list and provides a debugfs
|
||||
interface to list them, which makes it possible to see asynchronous
|
||||
operations that get stuck.
|
||||
|
||||
# cgroup code needs to be updated:
|
||||
#
|
||||
#config CGROUP_BCACHE
|
||||
# bool "Cgroup controls for bcache"
|
||||
# depends on BCACHE && BLK_CGROUP
|
||||
# ---help---
|
||||
# TODO
|
||||
7
drivers/md/bcache/Makefile
Normal file
7
drivers/md/bcache/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
obj-$(CONFIG_BCACHE) += bcache.o
|
||||
|
||||
bcache-y := alloc.o btree.o bset.o io.o journal.o writeback.o\
|
||||
movinggc.o request.o super.o sysfs.o debug.o util.o trace.o stats.o closure.o
|
||||
|
||||
CFLAGS_request.o += -Iblock
|
||||
583
drivers/md/bcache/alloc.c
Normal file
583
drivers/md/bcache/alloc.c
Normal file
File diff suppressed because it is too large
Load Diff
1232
drivers/md/bcache/bcache.h
Normal file
1232
drivers/md/bcache/bcache.h
Normal file
File diff suppressed because it is too large
Load Diff
1190
drivers/md/bcache/bset.c
Normal file
1190
drivers/md/bcache/bset.c
Normal file
File diff suppressed because it is too large
Load Diff
379
drivers/md/bcache/bset.h
Normal file
379
drivers/md/bcache/bset.h
Normal file
@@ -0,0 +1,379 @@
|
||||
#ifndef _BCACHE_BSET_H
|
||||
#define _BCACHE_BSET_H
|
||||
|
||||
/*
|
||||
* BKEYS:
|
||||
*
|
||||
* A bkey contains a key, a size field, a variable number of pointers, and some
|
||||
* ancillary flag bits.
|
||||
*
|
||||
* We use two different functions for validating bkeys, bch_ptr_invalid and
|
||||
* bch_ptr_bad().
|
||||
*
|
||||
* bch_ptr_invalid() primarily filters out keys and pointers that would be
|
||||
* invalid due to some sort of bug, whereas bch_ptr_bad() filters out keys and
|
||||
* pointer that occur in normal practice but don't point to real data.
|
||||
*
|
||||
* The one exception to the rule that ptr_invalid() filters out invalid keys is
|
||||
* that it also filters out keys of size 0 - these are keys that have been
|
||||
* completely overwritten. It'd be safe to delete these in memory while leaving
|
||||
* them on disk, just unnecessary work - so we filter them out when resorting
|
||||
* instead.
|
||||
*
|
||||
* We can't filter out stale keys when we're resorting, because garbage
|
||||
* collection needs to find them to ensure bucket gens don't wrap around -
|
||||
* unless we're rewriting the btree node those stale keys still exist on disk.
|
||||
*
|
||||
* We also implement functions here for removing some number of sectors from the
|
||||
* front or the back of a bkey - this is mainly used for fixing overlapping
|
||||
* extents, by removing the overlapping sectors from the older key.
|
||||
*
|
||||
* BSETS:
|
||||
*
|
||||
* A bset is an array of bkeys laid out contiguously in memory in sorted order,
|
||||
* along with a header. A btree node is made up of a number of these, written at
|
||||
* different times.
|
||||
*
|
||||
* There could be many of them on disk, but we never allow there to be more than
|
||||
* 4 in memory - we lazily resort as needed.
|
||||
*
|
||||
* We implement code here for creating and maintaining auxiliary search trees
|
||||
* (described below) for searching an individial bset, and on top of that we
|
||||
* implement a btree iterator.
|
||||
*
|
||||
* BTREE ITERATOR:
|
||||
*
|
||||
* Most of the code in bcache doesn't care about an individual bset - it needs
|
||||
* to search entire btree nodes and iterate over them in sorted order.
|
||||
*
|
||||
* The btree iterator code serves both functions; it iterates through the keys
|
||||
* in a btree node in sorted order, starting from either keys after a specific
|
||||
* point (if you pass it a search key) or the start of the btree node.
|
||||
*
|
||||
* AUXILIARY SEARCH TREES:
|
||||
*
|
||||
* Since keys are variable length, we can't use a binary search on a bset - we
|
||||
* wouldn't be able to find the start of the next key. But binary searches are
|
||||
* slow anyways, due to terrible cache behaviour; bcache originally used binary
|
||||
* searches and that code topped out at under 50k lookups/second.
|
||||
*
|
||||
* So we need to construct some sort of lookup table. Since we only insert keys
|
||||
* into the last (unwritten) set, most of the keys within a given btree node are
|
||||
* usually in sets that are mostly constant. We use two different types of
|
||||
* lookup tables to take advantage of this.
|
||||
*
|
||||
* Both lookup tables share in common that they don't index every key in the
|
||||
* set; they index one key every BSET_CACHELINE bytes, and then a linear search
|
||||
* is used for the rest.
|
||||
*
|
||||
* For sets that have been written to disk and are no longer being inserted
|
||||
* into, we construct a binary search tree in an array - traversing a binary
|
||||
* search tree in an array gives excellent locality of reference and is very
|
||||
* fast, since both children of any node are adjacent to each other in memory
|
||||
* (and their grandchildren, and great grandchildren...) - this means
|
||||
* prefetching can be used to great effect.
|
||||
*
|
||||
* It's quite useful performance wise to keep these nodes small - not just
|
||||
* because they're more likely to be in L2, but also because we can prefetch
|
||||
* more nodes on a single cacheline and thus prefetch more iterations in advance
|
||||
* when traversing this tree.
|
||||
*
|
||||
* Nodes in the auxiliary search tree must contain both a key to compare against
|
||||
* (we don't want to fetch the key from the set, that would defeat the purpose),
|
||||
* and a pointer to the key. We use a few tricks to compress both of these.
|
||||
*
|
||||
* To compress the pointer, we take advantage of the fact that one node in the
|
||||
* search tree corresponds to precisely BSET_CACHELINE bytes in the set. We have
|
||||
* a function (to_inorder()) that takes the index of a node in a binary tree and
|
||||
* returns what its index would be in an inorder traversal, so we only have to
|
||||
* store the low bits of the offset.
|
||||
*
|
||||
* The key is 84 bits (KEY_DEV + key->key, the offset on the device). To
|
||||
* compress that, we take advantage of the fact that when we're traversing the
|
||||
* search tree at every iteration we know that both our search key and the key
|
||||
* we're looking for lie within some range - bounded by our previous
|
||||
* comparisons. (We special case the start of a search so that this is true even
|
||||
* at the root of the tree).
|
||||
*
|
||||
* So we know the key we're looking for is between a and b, and a and b don't
|
||||
* differ higher than bit 50, we don't need to check anything higher than bit
|
||||
* 50.
|
||||
*
|
||||
* We don't usually need the rest of the bits, either; we only need enough bits
|
||||
* to partition the key range we're currently checking. Consider key n - the
|
||||
* key our auxiliary search tree node corresponds to, and key p, the key
|
||||
* immediately preceding n. The lowest bit we need to store in the auxiliary
|
||||
* search tree is the highest bit that differs between n and p.
|
||||
*
|
||||
* Note that this could be bit 0 - we might sometimes need all 80 bits to do the
|
||||
* comparison. But we'd really like our nodes in the auxiliary search tree to be
|
||||
* of fixed size.
|
||||
*
|
||||
* The solution is to make them fixed size, and when we're constructing a node
|
||||
* check if p and n differed in the bits we needed them to. If they don't we
|
||||
* flag that node, and when doing lookups we fallback to comparing against the
|
||||
* real key. As long as this doesn't happen to often (and it seems to reliably
|
||||
* happen a bit less than 1% of the time), we win - even on failures, that key
|
||||
* is then more likely to be in cache than if we were doing binary searches all
|
||||
* the way, since we're touching so much less memory.
|
||||
*
|
||||
* The keys in the auxiliary search tree are stored in (software) floating
|
||||
* point, with an exponent and a mantissa. The exponent needs to be big enough
|
||||
* to address all the bits in the original key, but the number of bits in the
|
||||
* mantissa is somewhat arbitrary; more bits just gets us fewer failures.
|
||||
*
|
||||
* We need 7 bits for the exponent and 3 bits for the key's offset (since keys
|
||||
* are 8 byte aligned); using 22 bits for the mantissa means a node is 4 bytes.
|
||||
* We need one node per 128 bytes in the btree node, which means the auxiliary
|
||||
* search trees take up 3% as much memory as the btree itself.
|
||||
*
|
||||
* Constructing these auxiliary search trees is moderately expensive, and we
|
||||
* don't want to be constantly rebuilding the search tree for the last set
|
||||
* whenever we insert another key into it. For the unwritten set, we use a much
|
||||
* simpler lookup table - it's just a flat array, so index i in the lookup table
|
||||
* corresponds to the i range of BSET_CACHELINE bytes in the set. Indexing
|
||||
* within each byte range works the same as with the auxiliary search trees.
|
||||
*
|
||||
* These are much easier to keep up to date when we insert a key - we do it
|
||||
* somewhat lazily; when we shift a key up we usually just increment the pointer
|
||||
* to it, only when it would overflow do we go to the trouble of finding the
|
||||
* first key in that range of bytes again.
|
||||
*/
|
||||
|
||||
/* Btree key comparison/iteration */
|
||||
|
||||
struct btree_iter {
|
||||
size_t size, used;
|
||||
struct btree_iter_set {
|
||||
struct bkey *k, *end;
|
||||
} data[MAX_BSETS];
|
||||
};
|
||||
|
||||
struct bset_tree {
|
||||
/*
|
||||
* We construct a binary tree in an array as if the array
|
||||
* started at 1, so that things line up on the same cachelines
|
||||
* better: see comments in bset.c at cacheline_to_bkey() for
|
||||
* details
|
||||
*/
|
||||
|
||||
/* size of the binary tree and prev array */
|
||||
unsigned size;
|
||||
|
||||
/* function of size - precalculated for to_inorder() */
|
||||
unsigned extra;
|
||||
|
||||
/* copy of the last key in the set */
|
||||
struct bkey end;
|
||||
struct bkey_float *tree;
|
||||
|
||||
/*
|
||||
* The nodes in the bset tree point to specific keys - this
|
||||
* array holds the sizes of the previous key.
|
||||
*
|
||||
* Conceptually it's a member of struct bkey_float, but we want
|
||||
* to keep bkey_float to 4 bytes and prev isn't used in the fast
|
||||
* path.
|
||||
*/
|
||||
uint8_t *prev;
|
||||
|
||||
/* The actual btree node, with pointers to each sorted set */
|
||||
struct bset *data;
|
||||
};
|
||||
|
||||
static __always_inline int64_t bkey_cmp(const struct bkey *l,
|
||||
const struct bkey *r)
|
||||
{
|
||||
return unlikely(KEY_INODE(l) != KEY_INODE(r))
|
||||
? (int64_t) KEY_INODE(l) - (int64_t) KEY_INODE(r)
|
||||
: (int64_t) KEY_OFFSET(l) - (int64_t) KEY_OFFSET(r);
|
||||
}
|
||||
|
||||
static inline size_t bkey_u64s(const struct bkey *k)
|
||||
{
|
||||
BUG_ON(KEY_CSUM(k) > 1);
|
||||
return 2 + KEY_PTRS(k) + (KEY_CSUM(k) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline size_t bkey_bytes(const struct bkey *k)
|
||||
{
|
||||
return bkey_u64s(k) * sizeof(uint64_t);
|
||||
}
|
||||
|
||||
static inline void bkey_copy(struct bkey *dest, const struct bkey *src)
|
||||
{
|
||||
memcpy(dest, src, bkey_bytes(src));
|
||||
}
|
||||
|
||||
static inline void bkey_copy_key(struct bkey *dest, const struct bkey *src)
|
||||
{
|
||||
if (!src)
|
||||
src = &KEY(0, 0, 0);
|
||||
|
||||
SET_KEY_INODE(dest, KEY_INODE(src));
|
||||
SET_KEY_OFFSET(dest, KEY_OFFSET(src));
|
||||
}
|
||||
|
||||
static inline struct bkey *bkey_next(const struct bkey *k)
|
||||
{
|
||||
uint64_t *d = (void *) k;
|
||||
return (struct bkey *) (d + bkey_u64s(k));
|
||||
}
|
||||
|
||||
/* Keylists */
|
||||
|
||||
struct keylist {
|
||||
struct bkey *top;
|
||||
union {
|
||||
uint64_t *list;
|
||||
struct bkey *bottom;
|
||||
};
|
||||
|
||||
/* Enough room for btree_split's keys without realloc */
|
||||
#define KEYLIST_INLINE 16
|
||||
uint64_t d[KEYLIST_INLINE];
|
||||
};
|
||||
|
||||
static inline void bch_keylist_init(struct keylist *l)
|
||||
{
|
||||
l->top = (void *) (l->list = l->d);
|
||||
}
|
||||
|
||||
static inline void bch_keylist_push(struct keylist *l)
|
||||
{
|
||||
l->top = bkey_next(l->top);
|
||||
}
|
||||
|
||||
static inline void bch_keylist_add(struct keylist *l, struct bkey *k)
|
||||
{
|
||||
bkey_copy(l->top, k);
|
||||
bch_keylist_push(l);
|
||||
}
|
||||
|
||||
static inline bool bch_keylist_empty(struct keylist *l)
|
||||
{
|
||||
return l->top == (void *) l->list;
|
||||
}
|
||||
|
||||
static inline void bch_keylist_free(struct keylist *l)
|
||||
{
|
||||
if (l->list != l->d)
|
||||
kfree(l->list);
|
||||
}
|
||||
|
||||
void bch_keylist_copy(struct keylist *, struct keylist *);
|
||||
struct bkey *bch_keylist_pop(struct keylist *);
|
||||
int bch_keylist_realloc(struct keylist *, int, struct cache_set *);
|
||||
|
||||
void bch_bkey_copy_single_ptr(struct bkey *, const struct bkey *,
|
||||
unsigned);
|
||||
bool __bch_cut_front(const struct bkey *, struct bkey *);
|
||||
bool __bch_cut_back(const struct bkey *, struct bkey *);
|
||||
|
||||
static inline bool bch_cut_front(const struct bkey *where, struct bkey *k)
|
||||
{
|
||||
BUG_ON(bkey_cmp(where, k) > 0);
|
||||
return __bch_cut_front(where, k);
|
||||
}
|
||||
|
||||
static inline bool bch_cut_back(const struct bkey *where, struct bkey *k)
|
||||
{
|
||||
BUG_ON(bkey_cmp(where, &START_KEY(k)) < 0);
|
||||
return __bch_cut_back(where, k);
|
||||
}
|
||||
|
||||
const char *bch_ptr_status(struct cache_set *, const struct bkey *);
|
||||
bool __bch_ptr_invalid(struct cache_set *, int level, const struct bkey *);
|
||||
bool bch_ptr_bad(struct btree *, const struct bkey *);
|
||||
|
||||
static inline uint8_t gen_after(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint8_t r = a - b;
|
||||
return r > 128U ? 0 : r;
|
||||
}
|
||||
|
||||
static inline uint8_t ptr_stale(struct cache_set *c, const struct bkey *k,
|
||||
unsigned i)
|
||||
{
|
||||
return gen_after(PTR_BUCKET(c, k, i)->gen, PTR_GEN(k, i));
|
||||
}
|
||||
|
||||
static inline bool ptr_available(struct cache_set *c, const struct bkey *k,
|
||||
unsigned i)
|
||||
{
|
||||
return (PTR_DEV(k, i) < MAX_CACHES_PER_SET) && PTR_CACHE(c, k, i);
|
||||
}
|
||||
|
||||
|
||||
typedef bool (*ptr_filter_fn)(struct btree *, const struct bkey *);
|
||||
|
||||
struct bkey *bch_next_recurse_key(struct btree *, struct bkey *);
|
||||
struct bkey *bch_btree_iter_next(struct btree_iter *);
|
||||
struct bkey *bch_btree_iter_next_filter(struct btree_iter *,
|
||||
struct btree *, ptr_filter_fn);
|
||||
|
||||
void bch_btree_iter_push(struct btree_iter *, struct bkey *, struct bkey *);
|
||||
struct bkey *__bch_btree_iter_init(struct btree *, struct btree_iter *,
|
||||
struct bkey *, struct bset_tree *);
|
||||
|
||||
/* 32 bits total: */
|
||||
#define BKEY_MID_BITS 3
|
||||
#define BKEY_EXPONENT_BITS 7
|
||||
#define BKEY_MANTISSA_BITS 22
|
||||
#define BKEY_MANTISSA_MASK ((1 << BKEY_MANTISSA_BITS) - 1)
|
||||
|
||||
struct bkey_float {
|
||||
unsigned exponent:BKEY_EXPONENT_BITS;
|
||||
unsigned m:BKEY_MID_BITS;
|
||||
unsigned mantissa:BKEY_MANTISSA_BITS;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* BSET_CACHELINE was originally intended to match the hardware cacheline size -
|
||||
* it used to be 64, but I realized the lookup code would touch slightly less
|
||||
* memory if it was 128.
|
||||
*
|
||||
* It definites the number of bytes (in struct bset) per struct bkey_float in
|
||||
* the auxiliar search tree - when we're done searching the bset_float tree we
|
||||
* have this many bytes left that we do a linear search over.
|
||||
*
|
||||
* Since (after level 5) every level of the bset_tree is on a new cacheline,
|
||||
* we're touching one fewer cacheline in the bset tree in exchange for one more
|
||||
* cacheline in the linear search - but the linear search might stop before it
|
||||
* gets to the second cacheline.
|
||||
*/
|
||||
|
||||
#define BSET_CACHELINE 128
|
||||
#define bset_tree_space(b) (btree_data_space(b) / BSET_CACHELINE)
|
||||
|
||||
#define bset_tree_bytes(b) (bset_tree_space(b) * sizeof(struct bkey_float))
|
||||
#define bset_prev_bytes(b) (bset_tree_space(b) * sizeof(uint8_t))
|
||||
|
||||
void bch_bset_init_next(struct btree *);
|
||||
|
||||
void bch_bset_fix_invalidated_key(struct btree *, struct bkey *);
|
||||
void bch_bset_fix_lookup_table(struct btree *, struct bkey *);
|
||||
|
||||
struct bkey *__bch_bset_search(struct btree *, struct bset_tree *,
|
||||
const struct bkey *);
|
||||
|
||||
static inline struct bkey *bch_bset_search(struct btree *b, struct bset_tree *t,
|
||||
const struct bkey *search)
|
||||
{
|
||||
return search ? __bch_bset_search(b, t, search) : t->data->start;
|
||||
}
|
||||
|
||||
bool bch_bkey_try_merge(struct btree *, struct bkey *, struct bkey *);
|
||||
void bch_btree_sort_lazy(struct btree *);
|
||||
void bch_btree_sort_into(struct btree *, struct btree *);
|
||||
void bch_btree_sort_and_fix_extents(struct btree *, struct btree_iter *);
|
||||
void bch_btree_sort_partial(struct btree *, unsigned);
|
||||
|
||||
static inline void bch_btree_sort(struct btree *b)
|
||||
{
|
||||
bch_btree_sort_partial(b, 0);
|
||||
}
|
||||
|
||||
int bch_bset_print_stats(struct cache_set *, char *);
|
||||
|
||||
#endif
|
||||
2503
drivers/md/bcache/btree.c
Normal file
2503
drivers/md/bcache/btree.c
Normal file
File diff suppressed because it is too large
Load Diff
405
drivers/md/bcache/btree.h
Normal file
405
drivers/md/bcache/btree.h
Normal file
@@ -0,0 +1,405 @@
|
||||
#ifndef _BCACHE_BTREE_H
|
||||
#define _BCACHE_BTREE_H
|
||||
|
||||
/*
|
||||
* THE BTREE:
|
||||
*
|
||||
* At a high level, bcache's btree is relatively standard b+ tree. All keys and
|
||||
* pointers are in the leaves; interior nodes only have pointers to the child
|
||||
* nodes.
|
||||
*
|
||||
* In the interior nodes, a struct bkey always points to a child btree node, and
|
||||
* the key is the highest key in the child node - except that the highest key in
|
||||
* an interior node is always MAX_KEY. The size field refers to the size on disk
|
||||
* of the child node - this would allow us to have variable sized btree nodes
|
||||
* (handy for keeping the depth of the btree 1 by expanding just the root).
|
||||
*
|
||||
* Btree nodes are themselves log structured, but this is hidden fairly
|
||||
* thoroughly. Btree nodes on disk will in practice have extents that overlap
|
||||
* (because they were written at different times), but in memory we never have
|
||||
* overlapping extents - when we read in a btree node from disk, the first thing
|
||||
* we do is resort all the sets of keys with a mergesort, and in the same pass
|
||||
* we check for overlapping extents and adjust them appropriately.
|
||||
*
|
||||
* struct btree_op is a central interface to the btree code. It's used for
|
||||
* specifying read vs. write locking, and the embedded closure is used for
|
||||
* waiting on IO or reserve memory.
|
||||
*
|
||||
* BTREE CACHE:
|
||||
*
|
||||
* Btree nodes are cached in memory; traversing the btree might require reading
|
||||
* in btree nodes which is handled mostly transparently.
|
||||
*
|
||||
* bch_btree_node_get() looks up a btree node in the cache and reads it in from
|
||||
* disk if necessary. This function is almost never called directly though - the
|
||||
* btree() macro is used to get a btree node, call some function on it, and
|
||||
* unlock the node after the function returns.
|
||||
*
|
||||
* The root is special cased - it's taken out of the cache's lru (thus pinning
|
||||
* it in memory), so we can find the root of the btree by just dereferencing a
|
||||
* pointer instead of looking it up in the cache. This makes locking a bit
|
||||
* tricky, since the root pointer is protected by the lock in the btree node it
|
||||
* points to - the btree_root() macro handles this.
|
||||
*
|
||||
* In various places we must be able to allocate memory for multiple btree nodes
|
||||
* in order to make forward progress. To do this we use the btree cache itself
|
||||
* as a reserve; if __get_free_pages() fails, we'll find a node in the btree
|
||||
* cache we can reuse. We can't allow more than one thread to be doing this at a
|
||||
* time, so there's a lock, implemented by a pointer to the btree_op closure -
|
||||
* this allows the btree_root() macro to implicitly release this lock.
|
||||
*
|
||||
* BTREE IO:
|
||||
*
|
||||
* Btree nodes never have to be explicitly read in; bch_btree_node_get() handles
|
||||
* this.
|
||||
*
|
||||
* For writing, we have two btree_write structs embeddded in struct btree - one
|
||||
* write in flight, and one being set up, and we toggle between them.
|
||||
*
|
||||
* Writing is done with a single function - bch_btree_write() really serves two
|
||||
* different purposes and should be broken up into two different functions. When
|
||||
* passing now = false, it merely indicates that the node is now dirty - calling
|
||||
* it ensures that the dirty keys will be written at some point in the future.
|
||||
*
|
||||
* When passing now = true, bch_btree_write() causes a write to happen
|
||||
* "immediately" (if there was already a write in flight, it'll cause the write
|
||||
* to happen as soon as the previous write completes). It returns immediately
|
||||
* though - but it takes a refcount on the closure in struct btree_op you passed
|
||||
* to it, so a closure_sync() later can be used to wait for the write to
|
||||
* complete.
|
||||
*
|
||||
* This is handy because btree_split() and garbage collection can issue writes
|
||||
* in parallel, reducing the amount of time they have to hold write locks.
|
||||
*
|
||||
* LOCKING:
|
||||
*
|
||||
* When traversing the btree, we may need write locks starting at some level -
|
||||
* inserting a key into the btree will typically only require a write lock on
|
||||
* the leaf node.
|
||||
*
|
||||
* This is specified with the lock field in struct btree_op; lock = 0 means we
|
||||
* take write locks at level <= 0, i.e. only leaf nodes. bch_btree_node_get()
|
||||
* checks this field and returns the node with the appropriate lock held.
|
||||
*
|
||||
* If, after traversing the btree, the insertion code discovers it has to split
|
||||
* then it must restart from the root and take new locks - to do this it changes
|
||||
* the lock field and returns -EINTR, which causes the btree_root() macro to
|
||||
* loop.
|
||||
*
|
||||
* Handling cache misses require a different mechanism for upgrading to a write
|
||||
* lock. We do cache lookups with only a read lock held, but if we get a cache
|
||||
* miss and we wish to insert this data into the cache, we have to insert a
|
||||
* placeholder key to detect races - otherwise, we could race with a write and
|
||||
* overwrite the data that was just written to the cache with stale data from
|
||||
* the backing device.
|
||||
*
|
||||
* For this we use a sequence number that write locks and unlocks increment - to
|
||||
* insert the check key it unlocks the btree node and then takes a write lock,
|
||||
* and fails if the sequence number doesn't match.
|
||||
*/
|
||||
|
||||
#include "bset.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct btree_write {
|
||||
struct closure *owner;
|
||||
atomic_t *journal;
|
||||
|
||||
/* If btree_split() frees a btree node, it writes a new pointer to that
|
||||
* btree node indicating it was freed; it takes a refcount on
|
||||
* c->prio_blocked because we can't write the gens until the new
|
||||
* pointer is on disk. This allows btree_write_endio() to release the
|
||||
* refcount that btree_split() took.
|
||||
*/
|
||||
int prio_blocked;
|
||||
};
|
||||
|
||||
struct btree {
|
||||
/* Hottest entries first */
|
||||
struct hlist_node hash;
|
||||
|
||||
/* Key/pointer for this btree node */
|
||||
BKEY_PADDED(key);
|
||||
|
||||
/* Single bit - set when accessed, cleared by shrinker */
|
||||
unsigned long accessed;
|
||||
unsigned long seq;
|
||||
struct rw_semaphore lock;
|
||||
struct cache_set *c;
|
||||
|
||||
unsigned long flags;
|
||||
uint16_t written; /* would be nice to kill */
|
||||
uint8_t level;
|
||||
uint8_t nsets;
|
||||
uint8_t page_order;
|
||||
|
||||
/*
|
||||
* Set of sorted keys - the real btree node - plus a binary search tree
|
||||
*
|
||||
* sets[0] is special; set[0]->tree, set[0]->prev and set[0]->data point
|
||||
* to the memory we have allocated for this btree node. Additionally,
|
||||
* set[0]->data points to the entire btree node as it exists on disk.
|
||||
*/
|
||||
struct bset_tree sets[MAX_BSETS];
|
||||
|
||||
/* Used to refcount bio splits, also protects b->bio */
|
||||
struct closure_with_waitlist io;
|
||||
|
||||
/* Gets transferred to w->prio_blocked - see the comment there */
|
||||
int prio_blocked;
|
||||
|
||||
struct list_head list;
|
||||
struct delayed_work work;
|
||||
|
||||
uint64_t io_start_time;
|
||||
struct btree_write writes[2];
|
||||
struct bio *bio;
|
||||
};
|
||||
|
||||
#define BTREE_FLAG(flag) \
|
||||
static inline bool btree_node_ ## flag(struct btree *b) \
|
||||
{ return test_bit(BTREE_NODE_ ## flag, &b->flags); } \
|
||||
\
|
||||
static inline void set_btree_node_ ## flag(struct btree *b) \
|
||||
{ set_bit(BTREE_NODE_ ## flag, &b->flags); } \
|
||||
|
||||
enum btree_flags {
|
||||
BTREE_NODE_read_done,
|
||||
BTREE_NODE_io_error,
|
||||
BTREE_NODE_dirty,
|
||||
BTREE_NODE_write_idx,
|
||||
};
|
||||
|
||||
BTREE_FLAG(read_done);
|
||||
BTREE_FLAG(io_error);
|
||||
BTREE_FLAG(dirty);
|
||||
BTREE_FLAG(write_idx);
|
||||
|
||||
static inline struct btree_write *btree_current_write(struct btree *b)
|
||||
{
|
||||
return b->writes + btree_node_write_idx(b);
|
||||
}
|
||||
|
||||
static inline struct btree_write *btree_prev_write(struct btree *b)
|
||||
{
|
||||
return b->writes + (btree_node_write_idx(b) ^ 1);
|
||||
}
|
||||
|
||||
static inline unsigned bset_offset(struct btree *b, struct bset *i)
|
||||
{
|
||||
return (((size_t) i) - ((size_t) b->sets->data)) >> 9;
|
||||
}
|
||||
|
||||
static inline struct bset *write_block(struct btree *b)
|
||||
{
|
||||
return ((void *) b->sets[0].data) + b->written * block_bytes(b->c);
|
||||
}
|
||||
|
||||
static inline bool bset_written(struct btree *b, struct bset_tree *t)
|
||||
{
|
||||
return t->data < write_block(b);
|
||||
}
|
||||
|
||||
static inline bool bkey_written(struct btree *b, struct bkey *k)
|
||||
{
|
||||
return k < write_block(b)->start;
|
||||
}
|
||||
|
||||
static inline void set_gc_sectors(struct cache_set *c)
|
||||
{
|
||||
atomic_set(&c->sectors_to_gc, c->sb.bucket_size * c->nbuckets / 8);
|
||||
}
|
||||
|
||||
static inline bool bch_ptr_invalid(struct btree *b, const struct bkey *k)
|
||||
{
|
||||
return __bch_ptr_invalid(b->c, b->level, k);
|
||||
}
|
||||
|
||||
static inline struct bkey *bch_btree_iter_init(struct btree *b,
|
||||
struct btree_iter *iter,
|
||||
struct bkey *search)
|
||||
{
|
||||
return __bch_btree_iter_init(b, iter, search, b->sets);
|
||||
}
|
||||
|
||||
/* Looping macros */
|
||||
|
||||
#define for_each_cached_btree(b, c, iter) \
|
||||
for (iter = 0; \
|
||||
iter < ARRAY_SIZE((c)->bucket_hash); \
|
||||
iter++) \
|
||||
hlist_for_each_entry_rcu((b), (c)->bucket_hash + iter, hash)
|
||||
|
||||
#define for_each_key_filter(b, k, iter, filter) \
|
||||
for (bch_btree_iter_init((b), (iter), NULL); \
|
||||
((k) = bch_btree_iter_next_filter((iter), b, filter));)
|
||||
|
||||
#define for_each_key(b, k, iter) \
|
||||
for (bch_btree_iter_init((b), (iter), NULL); \
|
||||
((k) = bch_btree_iter_next(iter));)
|
||||
|
||||
/* Recursing down the btree */
|
||||
|
||||
struct btree_op {
|
||||
struct closure cl;
|
||||
struct cache_set *c;
|
||||
|
||||
/* Journal entry we have a refcount on */
|
||||
atomic_t *journal;
|
||||
|
||||
/* Bio to be inserted into the cache */
|
||||
struct bio *cache_bio;
|
||||
|
||||
unsigned inode;
|
||||
|
||||
uint16_t write_prio;
|
||||
|
||||
/* Btree level at which we start taking write locks */
|
||||
short lock;
|
||||
|
||||
/* Btree insertion type */
|
||||
enum {
|
||||
BTREE_INSERT,
|
||||
BTREE_REPLACE
|
||||
} type:8;
|
||||
|
||||
unsigned csum:1;
|
||||
unsigned skip:1;
|
||||
unsigned flush_journal:1;
|
||||
|
||||
unsigned insert_data_done:1;
|
||||
unsigned lookup_done:1;
|
||||
unsigned insert_collision:1;
|
||||
|
||||
/* Anything after this point won't get zeroed in do_bio_hook() */
|
||||
|
||||
/* Keys to be inserted */
|
||||
struct keylist keys;
|
||||
BKEY_PADDED(replace);
|
||||
};
|
||||
|
||||
void bch_btree_op_init_stack(struct btree_op *);
|
||||
|
||||
static inline void rw_lock(bool w, struct btree *b, int level)
|
||||
{
|
||||
w ? down_write_nested(&b->lock, level + 1)
|
||||
: down_read_nested(&b->lock, level + 1);
|
||||
if (w)
|
||||
b->seq++;
|
||||
}
|
||||
|
||||
static inline void rw_unlock(bool w, struct btree *b)
|
||||
{
|
||||
#ifdef CONFIG_BCACHE_EDEBUG
|
||||
unsigned i;
|
||||
|
||||
if (w &&
|
||||
b->key.ptr[0] &&
|
||||
btree_node_read_done(b))
|
||||
for (i = 0; i <= b->nsets; i++)
|
||||
bch_check_key_order(b, b->sets[i].data);
|
||||
#endif
|
||||
|
||||
if (w)
|
||||
b->seq++;
|
||||
(w ? up_write : up_read)(&b->lock);
|
||||
}
|
||||
|
||||
#define insert_lock(s, b) ((b)->level <= (s)->lock)
|
||||
|
||||
/*
|
||||
* These macros are for recursing down the btree - they handle the details of
|
||||
* locking and looking up nodes in the cache for you. They're best treated as
|
||||
* mere syntax when reading code that uses them.
|
||||
*
|
||||
* op->lock determines whether we take a read or a write lock at a given depth.
|
||||
* If you've got a read lock and find that you need a write lock (i.e. you're
|
||||
* going to have to split), set op->lock and return -EINTR; btree_root() will
|
||||
* call you again and you'll have the correct lock.
|
||||
*/
|
||||
|
||||
/**
|
||||
* btree - recurse down the btree on a specified key
|
||||
* @fn: function to call, which will be passed the child node
|
||||
* @key: key to recurse on
|
||||
* @b: parent btree node
|
||||
* @op: pointer to struct btree_op
|
||||
*/
|
||||
#define btree(fn, key, b, op, ...) \
|
||||
({ \
|
||||
int _r, l = (b)->level - 1; \
|
||||
bool _w = l <= (op)->lock; \
|
||||
struct btree *_b = bch_btree_node_get((b)->c, key, l, op); \
|
||||
if (!IS_ERR(_b)) { \
|
||||
_r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__); \
|
||||
rw_unlock(_w, _b); \
|
||||
} else \
|
||||
_r = PTR_ERR(_b); \
|
||||
_r; \
|
||||
})
|
||||
|
||||
/**
|
||||
* btree_root - call a function on the root of the btree
|
||||
* @fn: function to call, which will be passed the child node
|
||||
* @c: cache set
|
||||
* @op: pointer to struct btree_op
|
||||
*/
|
||||
#define btree_root(fn, c, op, ...) \
|
||||
({ \
|
||||
int _r = -EINTR; \
|
||||
do { \
|
||||
struct btree *_b = (c)->root; \
|
||||
bool _w = insert_lock(op, _b); \
|
||||
rw_lock(_w, _b, _b->level); \
|
||||
if (_b == (c)->root && \
|
||||
_w == insert_lock(op, _b)) \
|
||||
_r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__); \
|
||||
rw_unlock(_w, _b); \
|
||||
bch_cannibalize_unlock(c, &(op)->cl); \
|
||||
} while (_r == -EINTR); \
|
||||
\
|
||||
_r; \
|
||||
})
|
||||
|
||||
static inline bool should_split(struct btree *b)
|
||||
{
|
||||
struct bset *i = write_block(b);
|
||||
return b->written >= btree_blocks(b) ||
|
||||
(i->seq == b->sets[0].data->seq &&
|
||||
b->written + __set_blocks(i, i->keys + 15, b->c)
|
||||
> btree_blocks(b));
|
||||
}
|
||||
|
||||
void bch_btree_read_done(struct closure *);
|
||||
void bch_btree_read(struct btree *);
|
||||
void bch_btree_write(struct btree *b, bool now, struct btree_op *op);
|
||||
|
||||
void bch_cannibalize_unlock(struct cache_set *, struct closure *);
|
||||
void bch_btree_set_root(struct btree *);
|
||||
struct btree *bch_btree_node_alloc(struct cache_set *, int, struct closure *);
|
||||
struct btree *bch_btree_node_get(struct cache_set *, struct bkey *,
|
||||
int, struct btree_op *);
|
||||
|
||||
bool bch_btree_insert_keys(struct btree *, struct btree_op *);
|
||||
bool bch_btree_insert_check_key(struct btree *, struct btree_op *,
|
||||
struct bio *);
|
||||
int bch_btree_insert(struct btree_op *, struct cache_set *);
|
||||
|
||||
int bch_btree_search_recurse(struct btree *, struct btree_op *);
|
||||
|
||||
void bch_queue_gc(struct cache_set *);
|
||||
size_t bch_btree_gc_finish(struct cache_set *);
|
||||
void bch_moving_gc(struct closure *);
|
||||
int bch_btree_check(struct cache_set *, struct btree_op *);
|
||||
uint8_t __bch_btree_mark_key(struct cache_set *, int, struct bkey *);
|
||||
|
||||
void bch_keybuf_init(struct keybuf *, keybuf_pred_fn *);
|
||||
void bch_refill_keybuf(struct cache_set *, struct keybuf *, struct bkey *);
|
||||
bool bch_keybuf_check_overlapping(struct keybuf *, struct bkey *,
|
||||
struct bkey *);
|
||||
void bch_keybuf_del(struct keybuf *, struct keybuf_key *);
|
||||
struct keybuf_key *bch_keybuf_next(struct keybuf *);
|
||||
struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *,
|
||||
struct keybuf *, struct bkey *);
|
||||
|
||||
#endif
|
||||
348
drivers/md/bcache/closure.c
Normal file
348
drivers/md/bcache/closure.c
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Asynchronous refcounty things
|
||||
*
|
||||
* Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
|
||||
* Copyright 2012 Google, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "closure.h"
|
||||
|
||||
void closure_queue(struct closure *cl)
|
||||
{
|
||||
struct workqueue_struct *wq = cl->wq;
|
||||
if (wq) {
|
||||
INIT_WORK(&cl->work, cl->work.func);
|
||||
BUG_ON(!queue_work(wq, &cl->work));
|
||||
} else
|
||||
cl->fn(cl);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_queue);
|
||||
|
||||
#define CL_FIELD(type, field) \
|
||||
case TYPE_ ## type: \
|
||||
return &container_of(cl, struct type, cl)->field
|
||||
|
||||
static struct closure_waitlist *closure_waitlist(struct closure *cl)
|
||||
{
|
||||
switch (cl->type) {
|
||||
CL_FIELD(closure_with_waitlist, wait);
|
||||
CL_FIELD(closure_with_waitlist_and_timer, wait);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct timer_list *closure_timer(struct closure *cl)
|
||||
{
|
||||
switch (cl->type) {
|
||||
CL_FIELD(closure_with_timer, timer);
|
||||
CL_FIELD(closure_with_waitlist_and_timer, timer);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void closure_put_after_sub(struct closure *cl, int flags)
|
||||
{
|
||||
int r = flags & CLOSURE_REMAINING_MASK;
|
||||
|
||||
BUG_ON(flags & CLOSURE_GUARD_MASK);
|
||||
BUG_ON(!r && (flags & ~(CLOSURE_DESTRUCTOR|CLOSURE_BLOCKING)));
|
||||
|
||||
/* Must deliver precisely one wakeup */
|
||||
if (r == 1 && (flags & CLOSURE_SLEEPING))
|
||||
wake_up_process(cl->task);
|
||||
|
||||
if (!r) {
|
||||
if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
|
||||
/* CLOSURE_BLOCKING might be set - clear it */
|
||||
atomic_set(&cl->remaining,
|
||||
CLOSURE_REMAINING_INITIALIZER);
|
||||
closure_queue(cl);
|
||||
} else {
|
||||
struct closure *parent = cl->parent;
|
||||
struct closure_waitlist *wait = closure_waitlist(cl);
|
||||
|
||||
closure_debug_destroy(cl);
|
||||
|
||||
atomic_set(&cl->remaining, -1);
|
||||
|
||||
if (wait)
|
||||
closure_wake_up(wait);
|
||||
|
||||
if (cl->fn)
|
||||
cl->fn(cl);
|
||||
|
||||
if (parent)
|
||||
closure_put(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For clearing flags with the same atomic op as a put */
|
||||
void closure_sub(struct closure *cl, int v)
|
||||
{
|
||||
closure_put_after_sub(cl, atomic_sub_return(v, &cl->remaining));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_sub);
|
||||
|
||||
void closure_put(struct closure *cl)
|
||||
{
|
||||
closure_put_after_sub(cl, atomic_dec_return(&cl->remaining));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_put);
|
||||
|
||||
static void set_waiting(struct closure *cl, unsigned long f)
|
||||
{
|
||||
#ifdef CONFIG_BCACHE_CLOSURES_DEBUG
|
||||
cl->waiting_on = f;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __closure_wake_up(struct closure_waitlist *wait_list)
|
||||
{
|
||||
struct llist_node *list;
|
||||
struct closure *cl;
|
||||
struct llist_node *reverse = NULL;
|
||||
|
||||
list = llist_del_all(&wait_list->list);
|
||||
|
||||
/* We first reverse the list to preserve FIFO ordering and fairness */
|
||||
|
||||
while (list) {
|
||||
struct llist_node *t = list;
|
||||
list = llist_next(list);
|
||||
|
||||
t->next = reverse;
|
||||
reverse = t;
|
||||
}
|
||||
|
||||
/* Then do the wakeups */
|
||||
|
||||
while (reverse) {
|
||||
cl = container_of(reverse, struct closure, list);
|
||||
reverse = llist_next(reverse);
|
||||
|
||||
set_waiting(cl, 0);
|
||||
closure_sub(cl, CLOSURE_WAITING + 1);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__closure_wake_up);
|
||||
|
||||
bool closure_wait(struct closure_waitlist *list, struct closure *cl)
|
||||
{
|
||||
if (atomic_read(&cl->remaining) & CLOSURE_WAITING)
|
||||
return false;
|
||||
|
||||
set_waiting(cl, _RET_IP_);
|
||||
atomic_add(CLOSURE_WAITING + 1, &cl->remaining);
|
||||
llist_add(&cl->list, &list->list);
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_wait);
|
||||
|
||||
/**
|
||||
* closure_sync() - sleep until a closure a closure has nothing left to wait on
|
||||
*
|
||||
* Sleeps until the refcount hits 1 - the thread that's running the closure owns
|
||||
* the last refcount.
|
||||
*/
|
||||
void closure_sync(struct closure *cl)
|
||||
{
|
||||
while (1) {
|
||||
__closure_start_sleep(cl);
|
||||
closure_set_ret_ip(cl);
|
||||
|
||||
if ((atomic_read(&cl->remaining) &
|
||||
CLOSURE_REMAINING_MASK) == 1)
|
||||
break;
|
||||
|
||||
schedule();
|
||||
}
|
||||
|
||||
__closure_end_sleep(cl);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_sync);
|
||||
|
||||
/**
|
||||
* closure_trylock() - try to acquire the closure, without waiting
|
||||
* @cl: closure to lock
|
||||
*
|
||||
* Returns true if the closure was succesfully locked.
|
||||
*/
|
||||
bool closure_trylock(struct closure *cl, struct closure *parent)
|
||||
{
|
||||
if (atomic_cmpxchg(&cl->remaining, -1,
|
||||
CLOSURE_REMAINING_INITIALIZER) != -1)
|
||||
return false;
|
||||
|
||||
closure_set_ret_ip(cl);
|
||||
|
||||
smp_mb();
|
||||
cl->parent = parent;
|
||||
if (parent)
|
||||
closure_get(parent);
|
||||
|
||||
closure_debug_create(cl);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_trylock);
|
||||
|
||||
void __closure_lock(struct closure *cl, struct closure *parent,
|
||||
struct closure_waitlist *wait_list)
|
||||
{
|
||||
struct closure wait;
|
||||
closure_init_stack(&wait);
|
||||
|
||||
while (1) {
|
||||
if (closure_trylock(cl, parent))
|
||||
return;
|
||||
|
||||
closure_wait_event_sync(wait_list, &wait,
|
||||
atomic_read(&cl->remaining) == -1);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__closure_lock);
|
||||
|
||||
static void closure_delay_timer_fn(unsigned long data)
|
||||
{
|
||||
struct closure *cl = (struct closure *) data;
|
||||
closure_sub(cl, CLOSURE_TIMER + 1);
|
||||
}
|
||||
|
||||
void do_closure_timer_init(struct closure *cl)
|
||||
{
|
||||
struct timer_list *timer = closure_timer(cl);
|
||||
|
||||
init_timer(timer);
|
||||
timer->data = (unsigned long) cl;
|
||||
timer->function = closure_delay_timer_fn;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(do_closure_timer_init);
|
||||
|
||||
bool __closure_delay(struct closure *cl, unsigned long delay,
|
||||
struct timer_list *timer)
|
||||
{
|
||||
if (atomic_read(&cl->remaining) & CLOSURE_TIMER)
|
||||
return false;
|
||||
|
||||
BUG_ON(timer_pending(timer));
|
||||
|
||||
timer->expires = jiffies + delay;
|
||||
|
||||
atomic_add(CLOSURE_TIMER + 1, &cl->remaining);
|
||||
add_timer(timer);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__closure_delay);
|
||||
|
||||
void __closure_flush(struct closure *cl, struct timer_list *timer)
|
||||
{
|
||||
if (del_timer(timer))
|
||||
closure_sub(cl, CLOSURE_TIMER + 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__closure_flush);
|
||||
|
||||
void __closure_flush_sync(struct closure *cl, struct timer_list *timer)
|
||||
{
|
||||
if (del_timer_sync(timer))
|
||||
closure_sub(cl, CLOSURE_TIMER + 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__closure_flush_sync);
|
||||
|
||||
#ifdef CONFIG_BCACHE_CLOSURES_DEBUG
|
||||
|
||||
static LIST_HEAD(closure_list);
|
||||
static DEFINE_SPINLOCK(closure_list_lock);
|
||||
|
||||
void closure_debug_create(struct closure *cl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(cl->magic == CLOSURE_MAGIC_ALIVE);
|
||||
cl->magic = CLOSURE_MAGIC_ALIVE;
|
||||
|
||||
spin_lock_irqsave(&closure_list_lock, flags);
|
||||
list_add(&cl->all, &closure_list);
|
||||
spin_unlock_irqrestore(&closure_list_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_debug_create);
|
||||
|
||||
void closure_debug_destroy(struct closure *cl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(cl->magic != CLOSURE_MAGIC_ALIVE);
|
||||
cl->magic = CLOSURE_MAGIC_DEAD;
|
||||
|
||||
spin_lock_irqsave(&closure_list_lock, flags);
|
||||
list_del(&cl->all);
|
||||
spin_unlock_irqrestore(&closure_list_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(closure_debug_destroy);
|
||||
|
||||
static struct dentry *debug;
|
||||
|
||||
#define work_data_bits(work) ((unsigned long *)(&(work)->data))
|
||||
|
||||
static int debug_seq_show(struct seq_file *f, void *data)
|
||||
{
|
||||
struct closure *cl;
|
||||
spin_lock_irq(&closure_list_lock);
|
||||
|
||||
list_for_each_entry(cl, &closure_list, all) {
|
||||
int r = atomic_read(&cl->remaining);
|
||||
|
||||
seq_printf(f, "%p: %pF -> %pf p %p r %i ",
|
||||
cl, (void *) cl->ip, cl->fn, cl->parent,
|
||||
r & CLOSURE_REMAINING_MASK);
|
||||
|
||||
seq_printf(f, "%s%s%s%s%s%s\n",
|
||||
test_bit(WORK_STRUCT_PENDING,
|
||||
work_data_bits(&cl->work)) ? "Q" : "",
|
||||
r & CLOSURE_RUNNING ? "R" : "",
|
||||
r & CLOSURE_BLOCKING ? "B" : "",
|
||||
r & CLOSURE_STACK ? "S" : "",
|
||||
r & CLOSURE_SLEEPING ? "Sl" : "",
|
||||
r & CLOSURE_TIMER ? "T" : "");
|
||||
|
||||
if (r & CLOSURE_WAITING)
|
||||
seq_printf(f, " W %pF\n",
|
||||
(void *) cl->waiting_on);
|
||||
|
||||
seq_printf(f, "\n");
|
||||
}
|
||||
|
||||
spin_unlock_irq(&closure_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int debug_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, debug_seq_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations debug_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = debug_seq_open,
|
||||
.read = seq_read,
|
||||
.release = single_release
|
||||
};
|
||||
|
||||
int __init closure_debug_init(void)
|
||||
{
|
||||
debug = debugfs_create_file("closures", 0400, NULL, NULL, &debug_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(closure_debug_init);
|
||||
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Kent Overstreet <koverstreet@google.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
670
drivers/md/bcache/closure.h
Normal file
670
drivers/md/bcache/closure.h
Normal file
File diff suppressed because it is too large
Load Diff
563
drivers/md/bcache/debug.c
Normal file
563
drivers/md/bcache/debug.c
Normal file
File diff suppressed because it is too large
Load Diff
54
drivers/md/bcache/debug.h
Normal file
54
drivers/md/bcache/debug.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _BCACHE_DEBUG_H
|
||||
#define _BCACHE_DEBUG_H
|
||||
|
||||
/* Btree/bkey debug printing */
|
||||
|
||||
#define KEYHACK_SIZE 80
|
||||
struct keyprint_hack {
|
||||
char s[KEYHACK_SIZE];
|
||||
};
|
||||
|
||||
struct keyprint_hack bch_pkey(const struct bkey *k);
|
||||
struct keyprint_hack bch_pbtree(const struct btree *b);
|
||||
#define pkey(k) (&bch_pkey(k).s[0])
|
||||
#define pbtree(b) (&bch_pbtree(b).s[0])
|
||||
|
||||
#ifdef CONFIG_BCACHE_EDEBUG
|
||||
|
||||
unsigned bch_count_data(struct btree *);
|
||||
void bch_check_key_order_msg(struct btree *, struct bset *, const char *, ...);
|
||||
void bch_check_keys(struct btree *, const char *, ...);
|
||||
|
||||
#define bch_check_key_order(b, i) \
|
||||
bch_check_key_order_msg(b, i, "keys out of order")
|
||||
#define EBUG_ON(cond) BUG_ON(cond)
|
||||
|
||||
#else /* EDEBUG */
|
||||
|
||||
#define bch_count_data(b) 0
|
||||
#define bch_check_key_order(b, i) do {} while (0)
|
||||
#define bch_check_key_order_msg(b, i, ...) do {} while (0)
|
||||
#define bch_check_keys(b, ...) do {} while (0)
|
||||
#define EBUG_ON(cond) do {} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BCACHE_DEBUG
|
||||
|
||||
void bch_btree_verify(struct btree *, struct bset *);
|
||||
void bch_data_verify(struct search *);
|
||||
|
||||
#else /* DEBUG */
|
||||
|
||||
static inline void bch_btree_verify(struct btree *b, struct bset *i) {}
|
||||
static inline void bch_data_verify(struct search *s) {};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void bch_debug_init_cache_set(struct cache_set *);
|
||||
#else
|
||||
static inline void bch_debug_init_cache_set(struct cache_set *c) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
390
drivers/md/bcache/io.c
Normal file
390
drivers/md/bcache/io.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Some low level IO code, and hacks for various block layer limitations
|
||||
*
|
||||
* Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
|
||||
* Copyright 2012 Google, Inc.
|
||||
*/
|
||||
|
||||
#include "bcache.h"
|
||||
#include "bset.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void bch_bi_idx_hack_endio(struct bio *bio, int error)
|
||||
{
|
||||
struct bio *p = bio->bi_private;
|
||||
|
||||
bio_endio(p, error);
|
||||
bio_put(bio);
|
||||
}
|
||||
|
||||
static void bch_generic_make_request_hack(struct bio *bio)
|
||||
{
|
||||
if (bio->bi_idx) {
|
||||
struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio));
|
||||
|
||||
memcpy(clone->bi_io_vec,
|
||||
bio_iovec(bio),
|
||||
bio_segments(bio) * sizeof(struct bio_vec));
|
||||
|
||||
clone->bi_sector = bio->bi_sector;
|
||||
clone->bi_bdev = bio->bi_bdev;
|
||||
clone->bi_rw = bio->bi_rw;
|
||||
clone->bi_vcnt = bio_segments(bio);
|
||||
clone->bi_size = bio->bi_size;
|
||||
|
||||
clone->bi_private = bio;
|
||||
clone->bi_end_io = bch_bi_idx_hack_endio;
|
||||
|
||||
bio = clone;
|
||||
}
|
||||
|
||||
generic_make_request(bio);
|
||||
}
|
||||
|
||||
/**
|
||||
* bch_bio_split - split a bio
|
||||
* @bio: bio to split
|
||||
* @sectors: number of sectors to split from the front of @bio
|
||||
* @gfp: gfp mask
|
||||
* @bs: bio set to allocate from
|
||||
*
|
||||
* Allocates and returns a new bio which represents @sectors from the start of
|
||||
* @bio, and updates @bio to represent the remaining sectors.
|
||||
*
|
||||
* If bio_sectors(@bio) was less than or equal to @sectors, returns @bio
|
||||
* unchanged.
|
||||
*
|
||||
* The newly allocated bio will point to @bio's bi_io_vec, if the split was on a
|
||||
* bvec boundry; it is the caller's responsibility to ensure that @bio is not
|
||||
* freed before the split.
|
||||
*
|
||||
* If bch_bio_split() is running under generic_make_request(), it's not safe to
|
||||
* allocate more than one bio from the same bio set. Therefore, if it is running
|
||||
* under generic_make_request() it masks out __GFP_WAIT when doing the
|
||||
* allocation. The caller must check for failure if there's any possibility of
|
||||
* it being called from under generic_make_request(); it is then the caller's
|
||||
* responsibility to retry from a safe context (by e.g. punting to workqueue).
|
||||
*/
|
||||
struct bio *bch_bio_split(struct bio *bio, int sectors,
|
||||
gfp_t gfp, struct bio_set *bs)
|
||||
{
|
||||
unsigned idx = bio->bi_idx, vcnt = 0, nbytes = sectors << 9;
|
||||
struct bio_vec *bv;
|
||||
struct bio *ret = NULL;
|
||||
|
||||
BUG_ON(sectors <= 0);
|
||||
|
||||
/*
|
||||
* If we're being called from underneath generic_make_request() and we
|
||||
* already allocated any bios from this bio set, we risk deadlock if we
|
||||
* use the mempool. So instead, we possibly fail and let the caller punt
|
||||
* to workqueue or somesuch and retry in a safe context.
|
||||
*/
|
||||
if (current->bio_list)
|
||||
gfp &= ~__GFP_WAIT;
|
||||
|
||||
if (sectors >= bio_sectors(bio))
|
||||
return bio;
|
||||
|
||||
if (bio->bi_rw & REQ_DISCARD) {
|
||||
ret = bio_alloc_bioset(gfp, 1, bs);
|
||||
idx = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bio_for_each_segment(bv, bio, idx) {
|
||||
vcnt = idx - bio->bi_idx;
|
||||
|
||||
if (!nbytes) {
|
||||
ret = bio_alloc_bioset(gfp, vcnt, bs);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
memcpy(ret->bi_io_vec, bio_iovec(bio),
|
||||
sizeof(struct bio_vec) * vcnt);
|
||||
|
||||
break;
|
||||
} else if (nbytes < bv->bv_len) {
|
||||
ret = bio_alloc_bioset(gfp, ++vcnt, bs);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
memcpy(ret->bi_io_vec, bio_iovec(bio),
|
||||
sizeof(struct bio_vec) * vcnt);
|
||||
|
||||
ret->bi_io_vec[vcnt - 1].bv_len = nbytes;
|
||||
bv->bv_offset += nbytes;
|
||||
bv->bv_len -= nbytes;
|
||||
break;
|
||||
}
|
||||
|
||||
nbytes -= bv->bv_len;
|
||||
}
|
||||
out:
|
||||
ret->bi_bdev = bio->bi_bdev;
|
||||
ret->bi_sector = bio->bi_sector;
|
||||
ret->bi_size = sectors << 9;
|
||||
ret->bi_rw = bio->bi_rw;
|
||||
ret->bi_vcnt = vcnt;
|
||||
ret->bi_max_vecs = vcnt;
|
||||
|
||||
bio->bi_sector += sectors;
|
||||
bio->bi_size -= sectors << 9;
|
||||
bio->bi_idx = idx;
|
||||
|
||||
if (bio_integrity(bio)) {
|
||||
if (bio_integrity_clone(ret, bio, gfp)) {
|
||||
bio_put(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bio_integrity_trim(ret, 0, bio_sectors(ret));
|
||||
bio_integrity_trim(bio, bio_sectors(ret), bio_sectors(bio));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned bch_bio_max_sectors(struct bio *bio)
|
||||
{
|
||||
unsigned ret = bio_sectors(bio);
|
||||
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
|
||||
struct bio_vec *bv, *end = bio_iovec(bio) +
|
||||
min_t(int, bio_segments(bio), queue_max_segments(q));
|
||||
|
||||
struct bvec_merge_data bvm = {
|
||||
.bi_bdev = bio->bi_bdev,
|
||||
.bi_sector = bio->bi_sector,
|
||||
.bi_size = 0,
|
||||
.bi_rw = bio->bi_rw,
|
||||
};
|
||||
|
||||
if (bio->bi_rw & REQ_DISCARD)
|
||||
return min(ret, q->limits.max_discard_sectors);
|
||||
|
||||
if (bio_segments(bio) > queue_max_segments(q) ||
|
||||
q->merge_bvec_fn) {
|
||||
ret = 0;
|
||||
|
||||
for (bv = bio_iovec(bio); bv < end; bv++) {
|
||||
if (q->merge_bvec_fn &&
|
||||
q->merge_bvec_fn(q, &bvm, bv) < (int) bv->bv_len)
|
||||
break;
|
||||
|
||||
ret += bv->bv_len >> 9;
|
||||
bvm.bi_size += bv->bv_len;
|
||||
}
|
||||
|
||||
if (ret >= (BIO_MAX_PAGES * PAGE_SIZE) >> 9)
|
||||
return (BIO_MAX_PAGES * PAGE_SIZE) >> 9;
|
||||
}
|
||||
|
||||
ret = min(ret, queue_max_sectors(q));
|
||||
|
||||
WARN_ON(!ret);
|
||||
ret = max_t(int, ret, bio_iovec(bio)->bv_len >> 9);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bch_bio_submit_split_done(struct closure *cl)
|
||||
{
|
||||
struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl);
|
||||
|
||||
s->bio->bi_end_io = s->bi_end_io;
|
||||
s->bio->bi_private = s->bi_private;
|
||||
bio_endio(s->bio, 0);
|
||||
|
||||
closure_debug_destroy(&s->cl);
|
||||
mempool_free(s, s->p->bio_split_hook);
|
||||
}
|
||||
|
||||
static void bch_bio_submit_split_endio(struct bio *bio, int error)
|
||||
{
|
||||
struct closure *cl = bio->bi_private;
|
||||
struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl);
|
||||
|
||||
if (error)
|
||||
clear_bit(BIO_UPTODATE, &s->bio->bi_flags);
|
||||
|
||||
bio_put(bio);
|
||||
closure_put(cl);
|
||||
}
|
||||
|
||||
static void __bch_bio_submit_split(struct closure *cl)
|
||||
{
|
||||
struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl);
|
||||
struct bio *bio = s->bio, *n;
|
||||
|
||||
do {
|
||||
n = bch_bio_split(bio, bch_bio_max_sectors(bio),
|
||||
GFP_NOIO, s->p->bio_split);
|
||||
if (!n)
|
||||
continue_at(cl, __bch_bio_submit_split, system_wq);
|
||||
|
||||
n->bi_end_io = bch_bio_submit_split_endio;
|
||||
n->bi_private = cl;
|
||||
|
||||
closure_get(cl);
|
||||
bch_generic_make_request_hack(n);
|
||||
} while (n != bio);
|
||||
|
||||
continue_at(cl, bch_bio_submit_split_done, NULL);
|
||||
}
|
||||
|
||||
void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
|
||||
{
|
||||
struct bio_split_hook *s;
|
||||
|
||||
if (!bio_has_data(bio) && !(bio->bi_rw & REQ_DISCARD))
|
||||
goto submit;
|
||||
|
||||
if (bio_sectors(bio) <= bch_bio_max_sectors(bio))
|
||||
goto submit;
|
||||
|
||||
s = mempool_alloc(p->bio_split_hook, GFP_NOIO);
|
||||
|
||||
s->bio = bio;
|
||||
s->p = p;
|
||||
s->bi_end_io = bio->bi_end_io;
|
||||
s->bi_private = bio->bi_private;
|
||||
bio_get(bio);
|
||||
|
||||
closure_call(&s->cl, __bch_bio_submit_split, NULL, NULL);
|
||||
return;
|
||||
submit:
|
||||
bch_generic_make_request_hack(bio);
|
||||
}
|
||||
|
||||
/* Bios with headers */
|
||||
|
||||
void bch_bbio_free(struct bio *bio, struct cache_set *c)
|
||||
{
|
||||
struct bbio *b = container_of(bio, struct bbio, bio);
|
||||
mempool_free(b, c->bio_meta);
|
||||
}
|
||||
|
||||
struct bio *bch_bbio_alloc(struct cache_set *c)
|
||||
{
|
||||
struct bbio *b = mempool_alloc(c->bio_meta, GFP_NOIO);
|
||||
struct bio *bio = &b->bio;
|
||||
|
||||
bio_init(bio);
|
||||
bio->bi_flags |= BIO_POOL_NONE << BIO_POOL_OFFSET;
|
||||
bio->bi_max_vecs = bucket_pages(c);
|
||||
bio->bi_io_vec = bio->bi_inline_vecs;
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
void __bch_submit_bbio(struct bio *bio, struct cache_set *c)
|
||||
{
|
||||
struct bbio *b = container_of(bio, struct bbio, bio);
|
||||
|
||||
bio->bi_sector = PTR_OFFSET(&b->key, 0);
|
||||
bio->bi_bdev = PTR_CACHE(c, &b->key, 0)->bdev;
|
||||
|
||||
b->submit_time_us = local_clock_us();
|
||||
closure_bio_submit(bio, bio->bi_private, PTR_CACHE(c, &b->key, 0));
|
||||
}
|
||||
|
||||
void bch_submit_bbio(struct bio *bio, struct cache_set *c,
|
||||
struct bkey *k, unsigned ptr)
|
||||
{
|
||||
struct bbio *b = container_of(bio, struct bbio, bio);
|
||||
bch_bkey_copy_single_ptr(&b->key, k, ptr);
|
||||
__bch_submit_bbio(bio, c);
|
||||
}
|
||||
|
||||
/* IO errors */
|
||||
|
||||
void bch_count_io_errors(struct cache *ca, int error, const char *m)
|
||||
{
|
||||
/*
|
||||
* The halflife of an error is:
|
||||
* log2(1/2)/log2(127/128) * refresh ~= 88 * refresh
|
||||
*/
|
||||
|
||||
if (ca->set->error_decay) {
|
||||
unsigned count = atomic_inc_return(&ca->io_count);
|
||||
|
||||
while (count > ca->set->error_decay) {
|
||||
unsigned errors;
|
||||
unsigned old = count;
|
||||
unsigned new = count - ca->set->error_decay;
|
||||
|
||||
/*
|
||||
* First we subtract refresh from count; each time we
|
||||
* succesfully do so, we rescale the errors once:
|
||||
*/
|
||||
|
||||
count = atomic_cmpxchg(&ca->io_count, old, new);
|
||||
|
||||
if (count == old) {
|
||||
count = new;
|
||||
|
||||
errors = atomic_read(&ca->io_errors);
|
||||
do {
|
||||
old = errors;
|
||||
new = ((uint64_t) errors * 127) / 128;
|
||||
errors = atomic_cmpxchg(&ca->io_errors,
|
||||
old, new);
|
||||
} while (old != errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
char buf[BDEVNAME_SIZE];
|
||||
unsigned errors = atomic_add_return(1 << IO_ERROR_SHIFT,
|
||||
&ca->io_errors);
|
||||
errors >>= IO_ERROR_SHIFT;
|
||||
|
||||
if (errors < ca->set->error_limit)
|
||||
pr_err("%s: IO error on %s, recovering",
|
||||
bdevname(ca->bdev, buf), m);
|
||||
else
|
||||
bch_cache_set_error(ca->set,
|
||||
"%s: too many IO errors %s",
|
||||
bdevname(ca->bdev, buf), m);
|
||||
}
|
||||
}
|
||||
|
||||
void bch_bbio_count_io_errors(struct cache_set *c, struct bio *bio,
|
||||
int error, const char *m)
|
||||
{
|
||||
struct bbio *b = container_of(bio, struct bbio, bio);
|
||||
struct cache *ca = PTR_CACHE(c, &b->key, 0);
|
||||
|
||||
unsigned threshold = bio->bi_rw & REQ_WRITE
|
||||
? c->congested_write_threshold_us
|
||||
: c->congested_read_threshold_us;
|
||||
|
||||
if (threshold) {
|
||||
unsigned t = local_clock_us();
|
||||
|
||||
int us = t - b->submit_time_us;
|
||||
int congested = atomic_read(&c->congested);
|
||||
|
||||
if (us > (int) threshold) {
|
||||
int ms = us / 1024;
|
||||
c->congested_last_us = t;
|
||||
|
||||
ms = min(ms, CONGESTED_MAX + congested);
|
||||
atomic_sub(ms, &c->congested);
|
||||
} else if (congested < 0)
|
||||
atomic_inc(&c->congested);
|
||||
}
|
||||
|
||||
bch_count_io_errors(ca, error, m);
|
||||
}
|
||||
|
||||
void bch_bbio_endio(struct cache_set *c, struct bio *bio,
|
||||
int error, const char *m)
|
||||
{
|
||||
struct closure *cl = bio->bi_private;
|
||||
|
||||
bch_bbio_count_io_errors(c, bio, error, m);
|
||||
bio_put(bio);
|
||||
closure_put(cl);
|
||||
}
|
||||
785
drivers/md/bcache/journal.c
Normal file
785
drivers/md/bcache/journal.c
Normal file
File diff suppressed because it is too large
Load Diff
215
drivers/md/bcache/journal.h
Normal file
215
drivers/md/bcache/journal.h
Normal file
@@ -0,0 +1,215 @@
|
||||
#ifndef _BCACHE_JOURNAL_H
|
||||
#define _BCACHE_JOURNAL_H
|
||||
|
||||
/*
|
||||
* THE JOURNAL:
|
||||
*
|
||||
* The journal is treated as a circular buffer of buckets - a journal entry
|
||||
* never spans two buckets. This means (not implemented yet) we can resize the
|
||||
* journal at runtime, and will be needed for bcache on raw flash support.
|
||||
*
|
||||
* Journal entries contain a list of keys, ordered by the time they were
|
||||
* inserted; thus journal replay just has to reinsert the keys.
|
||||
*
|
||||
* We also keep some things in the journal header that are logically part of the
|
||||
* superblock - all the things that are frequently updated. This is for future
|
||||
* bcache on raw flash support; the superblock (which will become another
|
||||
* journal) can't be moved or wear leveled, so it contains just enough
|
||||
* information to find the main journal, and the superblock only has to be
|
||||
* rewritten when we want to move/wear level the main journal.
|
||||
*
|
||||
* Currently, we don't journal BTREE_REPLACE operations - this will hopefully be
|
||||
* fixed eventually. This isn't a bug - BTREE_REPLACE is used for insertions
|
||||
* from cache misses, which don't have to be journaled, and for writeback and
|
||||
* moving gc we work around it by flushing the btree to disk before updating the
|
||||
* gc information. But it is a potential issue with incremental garbage
|
||||
* collection, and it's fragile.
|
||||
*
|
||||
* OPEN JOURNAL ENTRIES:
|
||||
*
|
||||
* Each journal entry contains, in the header, the sequence number of the last
|
||||
* journal entry still open - i.e. that has keys that haven't been flushed to
|
||||
* disk in the btree.
|
||||
*
|
||||
* We track this by maintaining a refcount for every open journal entry, in a
|
||||
* fifo; each entry in the fifo corresponds to a particular journal
|
||||
* entry/sequence number. When the refcount at the tail of the fifo goes to
|
||||
* zero, we pop it off - thus, the size of the fifo tells us the number of open
|
||||
* journal entries
|
||||
*
|
||||
* We take a refcount on a journal entry when we add some keys to a journal
|
||||
* entry that we're going to insert (held by struct btree_op), and then when we
|
||||
* insert those keys into the btree the btree write we're setting up takes a
|
||||
* copy of that refcount (held by struct btree_write). That refcount is dropped
|
||||
* when the btree write completes.
|
||||
*
|
||||
* A struct btree_write can only hold a refcount on a single journal entry, but
|
||||
* might contain keys for many journal entries - we handle this by making sure
|
||||
* it always has a refcount on the _oldest_ journal entry of all the journal
|
||||
* entries it has keys for.
|
||||
*
|
||||
* JOURNAL RECLAIM:
|
||||
*
|
||||
* As mentioned previously, our fifo of refcounts tells us the number of open
|
||||
* journal entries; from that and the current journal sequence number we compute
|
||||
* last_seq - the oldest journal entry we still need. We write last_seq in each
|
||||
* journal entry, and we also have to keep track of where it exists on disk so
|
||||
* we don't overwrite it when we loop around the journal.
|
||||
*
|
||||
* To do that we track, for each journal bucket, the sequence number of the
|
||||
* newest journal entry it contains - if we don't need that journal entry we
|
||||
* don't need anything in that bucket anymore. From that we track the last
|
||||
* journal bucket we still need; all this is tracked in struct journal_device
|
||||
* and updated by journal_reclaim().
|
||||
*
|
||||
* JOURNAL FILLING UP:
|
||||
*
|
||||
* There are two ways the journal could fill up; either we could run out of
|
||||
* space to write to, or we could have too many open journal entries and run out
|
||||
* of room in the fifo of refcounts. Since those refcounts are decremented
|
||||
* without any locking we can't safely resize that fifo, so we handle it the
|
||||
* same way.
|
||||
*
|
||||
* If the journal fills up, we start flushing dirty btree nodes until we can
|
||||
* allocate space for a journal write again - preferentially flushing btree
|
||||
* nodes that are pinning the oldest journal entries first.
|
||||
*/
|
||||
|
||||
#define BCACHE_JSET_VERSION_UUIDv1 1
|
||||
/* Always latest UUID format */
|
||||
#define BCACHE_JSET_VERSION_UUID 1
|
||||
#define BCACHE_JSET_VERSION 1
|
||||
|
||||
/*
|
||||
* On disk format for a journal entry:
|
||||
* seq is monotonically increasing; every journal entry has its own unique
|
||||
* sequence number.
|
||||
*
|
||||
* last_seq is the oldest journal entry that still has keys the btree hasn't
|
||||
* flushed to disk yet.
|
||||
*
|
||||
* version is for on disk format changes.
|
||||
*/
|
||||
struct jset {
|
||||
uint64_t csum;
|
||||
uint64_t magic;
|
||||
uint64_t seq;
|
||||
uint32_t version;
|
||||
uint32_t keys;
|
||||
|
||||
uint64_t last_seq;
|
||||
|
||||
BKEY_PADDED(uuid_bucket);
|
||||
BKEY_PADDED(btree_root);
|
||||
uint16_t btree_level;
|
||||
uint16_t pad[3];
|
||||
|
||||
uint64_t prio_bucket[MAX_CACHES_PER_SET];
|
||||
|
||||
union {
|
||||
struct bkey start[0];
|
||||
uint64_t d[0];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Only used for holding the journal entries we read in btree_journal_read()
|
||||
* during cache_registration
|
||||
*/
|
||||
struct journal_replay {
|
||||
struct list_head list;
|
||||
atomic_t *pin;
|
||||
struct jset j;
|
||||
};
|
||||
|
||||
/*
|
||||
* We put two of these in struct journal; we used them for writes to the
|
||||
* journal that are being staged or in flight.
|
||||
*/
|
||||
struct journal_write {
|
||||
struct jset *data;
|
||||
#define JSET_BITS 3
|
||||
|
||||
struct cache_set *c;
|
||||
struct closure_waitlist wait;
|
||||
bool need_write;
|
||||
};
|
||||
|
||||
/* Embedded in struct cache_set */
|
||||
struct journal {
|
||||
spinlock_t lock;
|
||||
/* used when waiting because the journal was full */
|
||||
struct closure_waitlist wait;
|
||||
struct closure_with_timer io;
|
||||
|
||||
/* Number of blocks free in the bucket(s) we're currently writing to */
|
||||
unsigned blocks_free;
|
||||
uint64_t seq;
|
||||
DECLARE_FIFO(atomic_t, pin);
|
||||
|
||||
BKEY_PADDED(key);
|
||||
|
||||
struct journal_write w[2], *cur;
|
||||
};
|
||||
|
||||
/*
|
||||
* Embedded in struct cache. First three fields refer to the array of journal
|
||||
* buckets, in cache_sb.
|
||||
*/
|
||||
struct journal_device {
|
||||
/*
|
||||
* For each journal bucket, contains the max sequence number of the
|
||||
* journal writes it contains - so we know when a bucket can be reused.
|
||||
*/
|
||||
uint64_t seq[SB_JOURNAL_BUCKETS];
|
||||
|
||||
/* Journal bucket we're currently writing to */
|
||||
unsigned cur_idx;
|
||||
|
||||
/* Last journal bucket that still contains an open journal entry */
|
||||
unsigned last_idx;
|
||||
|
||||
/* Next journal bucket to be discarded */
|
||||
unsigned discard_idx;
|
||||
|
||||
#define DISCARD_READY 0
|
||||
#define DISCARD_IN_FLIGHT 1
|
||||
#define DISCARD_DONE 2
|
||||
/* 1 - discard in flight, -1 - discard completed */
|
||||
atomic_t discard_in_flight;
|
||||
|
||||
struct work_struct discard_work;
|
||||
struct bio discard_bio;
|
||||
struct bio_vec discard_bv;
|
||||
|
||||
/* Bio for journal reads/writes to this device */
|
||||
struct bio bio;
|
||||
struct bio_vec bv[8];
|
||||
};
|
||||
|
||||
#define journal_pin_cmp(c, l, r) \
|
||||
(fifo_idx(&(c)->journal.pin, (l)->journal) > \
|
||||
fifo_idx(&(c)->journal.pin, (r)->journal))
|
||||
|
||||
#define JOURNAL_PIN 20000
|
||||
|
||||
#define journal_full(j) \
|
||||
(!(j)->blocks_free || fifo_free(&(j)->pin) <= 1)
|
||||
|
||||
struct closure;
|
||||
struct cache_set;
|
||||
struct btree_op;
|
||||
|
||||
void bch_journal(struct closure *);
|
||||
void bch_journal_next(struct journal *);
|
||||
void bch_journal_mark(struct cache_set *, struct list_head *);
|
||||
void bch_journal_meta(struct cache_set *, struct closure *);
|
||||
int bch_journal_read(struct cache_set *, struct list_head *,
|
||||
struct btree_op *);
|
||||
int bch_journal_replay(struct cache_set *, struct list_head *,
|
||||
struct btree_op *);
|
||||
|
||||
void bch_journal_free(struct cache_set *);
|
||||
int bch_journal_alloc(struct cache_set *);
|
||||
|
||||
#endif /* _BCACHE_JOURNAL_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user