Commit Graph
53 Commits
Author SHA1 Message Date
Zach Brown 65c3ac5043 scoutfs: Add cluster locking to node/file ops
This gives us cluster locking for the overwhelming majority of metadata ops
that scoutfs supports. In particular, we can create and modify file metadata
from one node and immediately see the changes reflected on another node.

In addition to synchonrization the cluster locks here are providing an I/O
endpoint for our item cache, ensuring that it doesn't read stale items.

Readdir and file read/write are notable exception - they require a more
specific approach and will be implemented in a future patch.

Signed-off-by: Mark Fasheh <mfasheh@versity.com>
[fixed iget unlock and truncated commit message summary]
Signed-off-by: Zach Brown <zab@versity.com>
2017-08-03 11:16:35 -07:00
Zach Brown 47b26d7888 scoutfs: add end to _item_delete
Add the end argument to scoutfs_item_delete() to limit how many items it
will read into the cache.

Signed-off-by: Zach Brown <zab@versity.com>
2017-07-19 13:30:03 -07:00
Zach Brown d5b4677e7f scoutfs: add end to _dirty, _delete_many, _update
These transformations are mechanical and there aren't many callers of
these so we combine them into one commit.

Signed-off-by: Zach Brown <zab@versity.com>
2017-07-19 13:30:03 -07:00
Zach Brown f611c769e2 scoutfs: add 'end' to item_next to limit reads
Add an end key to the item_next calls to limit how many items will be
read into the cache.  Callers typically get this from the lock they hold
that covers the iteration.  We differentiate between iteration and
caching so that a series of small iterations (listxattr on inodes,
namespace walk in small dirs) can be satisfied by a single read of
adjacent items from segments.

Signed-off-by: Zach Brown <zab@versity.com>
2017-07-19 13:30:03 -07:00
Zach Brown 19171f7a25 scoutfs: add end to _item_lookup
The item cache can only be populated with items that are covered by
locks.  Require callers to provide the farthest key that can be covered
by the locks.  Locks provide a key for exactly this purpose.

Signed-off-by: Zach Brown <zab@versity.com>
2017-07-19 13:30:03 -07:00
Zach Brown 8d29c82306 scoutfs: sort keys by zone, then inode, then type
Holding a DLM lock protects a range of the key space.  The DLM locks
span inodes or regions of inodes.  We need the sort order in LSM items
to match the DLM range keys so that we can read all the items covered by
a lock into the cache from a region of LSM segments.  If their orders
differered then we'd have to jump around segments to find all the items
covered by a given DLM lock.

Previously we were sorting by type then, within types, by inode.  Now we
want to sort by inode then by type.  But there are structures which
previously had a type but weren't then sorted by inode.  We introduce
zones as the primary sort key.  Inode index and node zones are sorted by
the inode fields and node ids respectively.  Then comes the fs zone
first sorted by inode then the type of the key.

The bulk of this is the mechanical introduction of the zone field to the
keys, moving the type field down, and a bulk rename of _KEY to _TYPE.
But there are some more substantial changes.

The orphan keys needed to be put in a zone.   They fit in the NODE zone
which is all about resources that nodes hold and would need to be
cleaned up if the node went away.

The key formatting is significantly changed to match the new formatting.
Formatted keys are now generally of the form "zone.primary.type..."

And finally with the keys now properly sorted by inodes we can correctly
construct a single range of item cache keys to invalidate when unlocking
the inode group locks.

Signed-off-by: Zach Brown <zab@versity.com>
2017-07-19 13:30:03 -07:00
Zach Brown 1724bab8ea scoutfs: store large symlinks in multiple items
We're shrinking the max item value size so we need to store symlinks
with large target paths in multiple items.  The arbitrary max value size
defined here will be replaced in the future with the new global maximum
value size.

Signed-off-by: Zach Brown <zab@versity.com>
2017-06-27 14:04:38 -07:00
Zach Brown b7bbad1fba scoutfs: add precise transation item reservations
We had a simple mechanism for ensuring that transaction didn't create
more items than would fit in a single written segment.  We calculated
the most dirty items that a holder could generate and assumed that all
holders dirtied that much.

This had two big problems.

The first was that it wasn't accounting for nested holds.
write_begin/end calls the generic inode dirtying path whild holding a
transaction.  This ended up deadlocking as the dirty inode waited to be
able to write while its trans held back in write_begin prevented
writeout.

The second was that the worst case (full size xattr) item dirtying is
enormous and meaningfully restricts concurrent transaction holders.
With no currently dirty items you can have less than 16 full size xattr
writes.  This concurrency limit only gets worse as the transaction fills
up with dirty items.

This fixes those problems.  It adds precise accounting of the dirty
items that can be created while a transaction is held.  These
reservations are tracked in journal_info so that they can be used by
nested holds.  The precision allows much greater concurrency as
something like a create will try to reserve a few hundreds bytes instead
of 64k.  Normal sized xattr operations won't try to reserve the largest
possible space.

We add some feedback from the item cache to the transaction to issue
warnings if a holder dirties more items than it reserved.

Now that we have precise item/key/value counts (segment space
consumption is a function of all three :/) we can't have a single atomic
track transaction holders.  We add a long-overdue trans_info and put a
proper lock and fields there and much more clearly track transaction
serialization amongst the holders and writer.

Signed-off-by: Zach Brown <zab@versity.com>
2017-05-23 12:15:13 -07:00
Zach Brown 5f11cdbfe5 scoutfs: add and index inode meta and data seqs
For each transaction we send a message to to the server asking for a
unique sequence number to associate with the transaction.  When we
change metadata or data of an inode we store the current transaction seq
in the inode and we index it with index items like the other inode
fields.

The server remembers the sequences it gives out.  When we go to walk the
inode sequence indexes we ask the server for the largest stable seq and
limit results to that seq.  This ensures that we never return seqs that
are past dirty items so never have inodes and seqs appear in the past.

Nodes use the sync timer to regularly cycle through seqs and ensure that
inode seq index walks don't get stuck on their otherwise idle seq.

Signed-off-by: Zach Brown <zab@versity.com>
2017-05-23 12:12:24 -07:00
Zach Brown b97587b8fa scoutfs: add indexing of inodes by fields
Add items for indexing inodes by their fields.  When we update the inode
item we also delete the old index items and create the new items.  We
rename and refactor the old inode since ioctl to now walk the inode
index items.

Signed-off-by: Zach Brown <zab@versity.com>
2017-05-16 10:48:12 -07:00
Zach Brown 4084d3d9dc scoutfs: add offline flag, releasing, and fiemap
Now that we have basic file extents we can add a flag to extents to
track offline extents.  We have to initialize and test the flags as we
work with extents.  Truncation can be told to leave removed extents
around with no block mapping and the offline bit set.  Only staging with
the correct data version can write to the offline regions.  Demand
staging isn't implemented yet.  Reads from offline extents are treated
like sparse regions.

Truncation is a straight forward iteration over the portions of existing
extents which overlap with the truncated blocks.

Writing to offline extents has to first remove the existing offline
extent before then adding the new allocated extents.  The 'changes'
mechanism relied on being able to search the current items to find the
changes that should be made before making any changes.  This doesn't
work for finding merge candidates for the new allocated insertion
because the old offline extent change won't have been applied yet.  We
replace the change mechanism with straight forward item modification and
unwinding.

The generic block fiemap can't communicate offline extents and iterates
over blocks instead of extents.  We add our fiemap that iterates
over extents and sets the 'UNKNOWN' flag on offline extents.

Signed-off-by: Zach Brown <zab@versity.com>
2017-05-16 10:48:12 -07:00
Zach Brown 6afeb97802 scoutfs: reference file data with extent items
Our first attempt at storing file data put them in items.  This was easy
to implement but won't be acceptable in the long term.  The cost of the
power of LSM indexing is compaction overhead.  That's acceptable for
fine grained metadata but is totally unacceptable for bulk file data.

This switches to storing file data in seperate block allocations which
are referenced by extent items.

The bulk of the change is the mechanics of working with extents.  We
have high level callers which add or remove logical extents and then
underlying mechanisms that insert, merge, or split the items that
the extents are stored in.

We have three types of extent items.  The primary type maps logical file
regions to physical block extents.  The next two store free extents
per-node so that clients don't create lock and LSM contention as they
try and allocate extents.

To fill those per-node free extents we add messages that communcate free
extents in the form of lists of segment allocations from the server.

We don't do any fancy multi-block allocation yet.  We only allocate
blocks in get_blocks as writes find unmapped blocks.  We do use some
per-task cursors to cache block allocation positions so that these
single block allocations are very likely to merge into larger extents as
tasks stream wites.

This is just the first chunk of the extent work that's coming.  A later
patch adds offline flags and fixes up the change nonsense that seemed
like a good idea here.

The final moving part is that we initiate writeback on all newly
allocated extents before we commit the metadata that references the new
blocks.  We do this with our own dirty inode tracking because the high
level vfs methods are unusably slow in some upstream kernels (they walk
all inodes, not just dirty inodes.)

Signed-off-by: Zach Brown <zab@versity.com>
2017-05-16 10:48:11 -07:00
Zach Brown 8b82aa7f18 Consistently initialize inode fields
Inode info struct initialization spread out over three places:
 - once for the memory of a slab obect
 - when reading an existing inode from items
 - when initializing a newly allocated inode

Over time field initializtion got out of sync with these rules.  This
makes it more clear which fields get initialized where.  In the inode
info struct we group fields by where there initialized.  We order the
fields by size and location in the inode struct.

Then we make sure that all the initialization sites have everything
covered.  Doing everything in consistent struct order makes it easier
to audit that we haven't missed anything.

What lead to this was realizing that we missed initializing the seqcount
when reading existing inodes.  It should have been initialized in the
slab object constructor.  The 'staging' boolean has the same problem.

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
2017-04-18 14:17:55 -07:00
Zach Brown 2aa274b38b Add xattr iops for special files
xfstests generic/062 was failing because it was getting an unexpected
error code when trying to work with xattrs on special files.  Adding our
ops gives it the errnos it expects.

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
2017-04-18 14:06:29 -07:00
Zach Brown 78d15a019c Print inode nr and err on inode upate error
We're currently excessively freaking out if inode updates fail.  Let's
add a little more context to help us track down what goes wrong.

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
2017-04-18 14:06:26 -07:00
Zach Brown b50de90196 Alloc inodes from pool from server
Inode allocation was always modifying the in-memory super block.  This
doesn't work when the server is solely responsible for modifying the
super blocks.  We add network messages to have mounts send a message to
the server to request inodes that they can use to satisfy allocation.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:51:10 -07:00
Zach Brown 97cb75bd88 Remove dead btree, block, and buddy code
Remove all the unused dead code from the previous btree block design.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:44:55 -07:00
Zach Brown 02af35a98e Convert inode since ioctl to the item API
The inode since ioctl was the last user of the btree.  It doesn't yet
work because the item cache doesn't know how to search for items by
sequence yet.

It's not yet clear exactly how we'll build the data since ioctls.  It'll
be easy enough to refactor the inode since item walk if they follow a
similar pattern again.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:44:54 -07:00
Zach Brown 9f5e42f7dd Add simple data items
Add basic file data support by managing file data items from the page
cache address space callbacks.

Data is read by copying from cached items into page contents in
readpage.

Writes create new ephemeral items which reference dirty pages.  The
items are deleted once they're written in a transaction or if
invalidatepage removes the dirty page they reference.

There's a lot more to do to remove data copies, avoid compaction bw
overhead, and add support for truncate, o_direct, and mmap.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:44:54 -07:00
Zach Brown 67aec72c77 Add readdir items
Restore readdir functionality by adding readdir items.

The readdir items are keyed by an increasing position in the parent
dir's inode.  We track it in our inode info.  To delete the readdir
items we restore the dentry_info and put the pos in the dentry so unlink
can build the readdir item key.  And finally we put the pos in the
lookup dirent so that it can populate the dentry info on lookup.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:44:54 -07:00
Zach Brown f139cf4a5e Convert unlink and orphan processing
Restore unlink functionality by converting unlink and orphan item
processing from the old btree interface to the new item cache interface.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:44:54 -07:00
Zach Brown 2bc1617280 Use contiguous key struct instead of kvecs
Using kvecs for keys seemed like a good idea because there were a few
uses that had keys in fragmented memory: dirent keys made up of an
on-stack struct and the file name in the dentry, and keys straddling the
pages that make up a cached segment.

But it hasn't worked out very well.  The code to perform ops on keys
by iterating over vectors is pretty fiddly.  And the raw kvecs only
describe the actively referenced key, they know nothing about the total
size of the buffer that the key resides in.  Some ops can't check that
they're not clobbering things, they're relying on callers not to mess
up.

And critically, the kvec iteration's become a bottleneck.  It turns out
that comparing keys is a very hot path in the item cache.  All the code
to initialize and iterate over two key vectors adds up when each high
level fs operation is a few tree descents and each tree descent is a
bunch of compares.

So let's back off and have a specific struct for tracking keys that are
stored in contiguous memory regions.  Users ensure that keys are
contiguous.  The code ends up being a lot clearer, code now can see how
big the full key buffer is, and the rbtree node comparison fast path is
now just a memcmp.

Almost all of the changes in the patch are mechanical semantic changes
involving types, function names, args, and occasionaly slightly
different return conventions.

A slightly more involved change is that now dirent key users have to
manage an allocated contiguous key with a copy of the path from the
dentry.

Item reading is now a little more clever about calculating the greatest
range it can cache by initially walking all the segments instead of
trying to do it as it runs out of items in each segment.

The largest meaningful change is that now keys can't straddle page
boundaries in memory which means they can't cross block boundaries in
the segment.  We align key offsets to the next block as we write keys to
segments that would have straddled a block.

We then also have to account for that padding when building segments.
We add a helper that calculates if a given number of items will fit in a
segment which is used by item dirtying, segment writing, and compaction.

I left the tracepoint formatting for another patch.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:44:54 -07:00
Zach Brown c4954eb6f4 Add initial LSM write implementation
Add all the core strutural components to be able to modify metadata.  We
modify items in fs write operations, track dirty items in the cache,
allocate free segment block reagions, stream dirty items into segments,
write out the segments, update the manifest to reference the written
segments, and write out a new ring that has the new manifest.

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:42:30 -07:00
Zach Brown 43d0d44e48 Add initial LSM implementation
Add the initial core components of the LSM implementation to be able to
read the root inode:

 - bio.c: read big block regions
 - seg.c: cache logical segments
 - ring.c: read the manifest from storage
 - manifest.c: organize segments into an LSM
 - kvec.c: work with arbitrary memory vectors
 - item.c: cache fs metadata items read from segments

Signed-off-by: Zach Brown <zab@versity.com>
2017-04-18 13:38:50 -07:00
Zach Brown c6b688c2bf Add staging ioctl
This adds the ioctl for writing archived file contents back into the
file if the data_version still matches.

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
2016-11-16 14:45:08 -08:00
Zach Brown df561bbd19 Add offline extent flag and release ioctl
Add the _OFFLINE flag to indicate offline extents.  The release ioctl
frees extents within the release range and sets their _OFFLINE flag if
the data_version still matches.

We tweak the existing truncate item function just a bit to support
making extents offline.  We make it take an explicit range of blocks to
remove instead of just giving it the size and it learns to mark extents
offline and update them instead of always deleting them.

Reads from offline extents return zeros like reading from a sparse
region (later it will trigger demand staging) and writing to offline
extents clears the offline flag (later only staging can do that).

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
2016-11-16 14:45:08 -08:00
Zach Brown f86fab1162 Add an inode data_version field
The data_version field is changed every time the contents of the file
could have changed.

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
2016-11-16 14:45:08 -08:00
Mark FashehandZach Brown 467801de73 scoutfs: use extents for file data
We're very basic here at this stage and simply put a single-block extent
item where we would have previously had a multi-block bmap item.
Multi-block extents will come in future patches.

Signed-off-by: Mark Fasheh <mfasheh@versity.com>
Signed-off-by: Zach Brown <zab@versity.com>
2016-11-16 14:45:08 -08:00
Zach Brown 1cbd84eece scoutfs: wire up sop->dirty_inode
We're using the generic block buffer_head write_begin and write_end
functions.  They call sop->dirty_inode() to update the inode i_size.  We
didn't have that method wired up so updates to the inode in the write
path wasn't dirtying the inode item.  Lost i_size updates would
trivially lose data but we first noticed this when looking at inode item
sequence numbers while overwriting.

Signed-off-by: Zach Brown <zab@versity.com>
2016-11-08 16:05:36 -08:00
Mark Fasheh 2fc1b99698 scoutfs: replace some open coded corruption checks
We can trivially do the simple check of value length against what the caller
expects in btree.c.

Signed-off-by: Mark Fasheh <mfasheh@versity.com>
Signed-off-by: Zach Brown <zab@versity.com>
2016-10-27 17:25:05 -05:00
Mark Fasheh ebbb2e842e scoutfs: implement inode orphaning
This is pretty straight forward - we define a new item type,
SCOUTFS_ORPHAN_KEY. We don't need to store any value with this, the inode
and type fields are enough for us to find what inode has been orphaned.

Otherwise this works as one would expect. Unlink sets the item, and
->evict_inode removes it. On mount, we scan for orphan items and remove any
corresponding inodes.

Signed-off-by: Mark Fasheh <mfasheh@versity.com>
Signed-off-by: Zach Brown <zab@versity.com>
2016-10-24 16:41:45 -05:00
Zach Brown 84f23296fd scoutfs: remove btree cursor
The btree cursor was built to address two problems.  First it
accelerates iteration by avoiding full descents down the tree by holding
on to leaf blocks.  Second it lets callers reference item value contents
directly to avoid copies.

But it also has serious complexity costs.  It pushes refcounting and
locking out to the caller.  There have already been a few bugs where
callers did things while holding the cursor without realizing that
they're holding a btree lock and can't perform certain btree operations
or even copies to user space.

Future changes to the allocator to use the btree motivates cleaning up
the tree locking which is complicated by the cursor being a stand alone
lock reference.  Instead of continuing to layer complexity onto this
construct let's remove it.

The iteration acceleration will be addressed the same way we're going to
accelerate the other btree operations: with per-cpu cached leaf block
references.  Unlike the cursor this doesn't push interface changes out
to callers who want repeated btree calls to perform well.

We'll leave the value copying for now.  If it becomes an issue we can
add variants that call a function to operate on the value.  Let's hope
we don't have to go there.

This change replaces the cursor with a vector to memory that the value
should be copied to and from.  The vector has a fixed number of elements
and is wrapped in a struct for easy declaration and initialization.

This change to the interface looks noisy but each caller's change is
pretty mechanical.  They tend to involve:

 - replace the cursor with the value struct and initialization
 - allocate some memory to copy the value in to
 - reading functions return the number of value bytes copied
 - verify copied bytes makes sense for item being read
 - getting rid of confusing ((ret = _next())) looping
 - _next now returns -ENOENT instead of 0 for no next item
 - _next iterators now need to increase the key themselves
 - make sure to free allocated mem

Sometimes the order of operations changes significantly.  Now that we
can't modify in place we need to read, modify, write.  This looks like
changing a modification of the item through the cursor to a
lookup/update pattern.

The symlink item iterators didn't need to use next because they walk a
contiguous set of keys.  They're changed to use simple insert or lookup.

Signed-off-by: Zach Brown <zab@versity.com>
2016-09-21 10:04:07 -07:00
Zach Brown 2bed78c269 scoutfs: specify btree root
The btree functions currently don't take a specific root argument.  They
assume, deep down in btree_walk, that there's only one btree in the
system.  We're going to be adding a few more to support richer
allocation.

To prepare for this we have the btree functions take an explicit btree
argument.  This should make no functional difference.

Signed-off-by: Zach Brown <zab@versity.com>
2016-09-21 10:04:07 -07:00
Zach Brown 06c718e16a scoutfs: remove unlinked inode items
Wire up the inode callbacks that let us remove all the persistent items
associated with an unlinked inode as its final reference is dropped.
This is the first part of full truncate and orphan inode support.

Signed-off-by: Zach Brown <zab@versity.com>
2016-08-31 09:31:23 -07:00
Zach Brown 64b82e1ac3 scoutfs: add symlink support
Symlinks are easily implemented by storing the target path in btree
items.

Signed-off-by: Zach Brown <zab@versity.com>
2016-08-29 10:21:27 -07:00
Zach Brown cb318982c9 scoutfs: add support for statfs
To do a credible job of this we need to track the number of free blocks.
We add counters of order allocations free to the indirect blocks so that
we can quickly scan them.  We also need a bit of help to count inodes.

Finally I noticed that we were miscalculating the number of slots in the
indirect blocks because we were using the size of the buddy block
header, not the size of the indirect block header.

Signed-off-by: Zach Brown <zab@versity.com>
2016-08-24 15:52:54 -07:00
Zach Brown 0991622a21 scoutfs: add inode_paths ioctl
This adds the ioctl that returns all the paths from the root to a given
inode.  The implementation only traverses btree items to keep it
isolated from the vfs object locking and life cycles, but that could be
a performance problem.  This is another motivation to accelerate the
btree code.

Signed-off-by: Zach Brown <zab@versity.com>
2016-08-11 16:46:18 -07:00
Zach Brown 198ec2ed5b scoutfs: have btree_update return errors
We can certainly have btree update callers that haven't yet dirtied the
blocks but who can deal with errors.  So make it return errors and have
its only current caller freak out if it fails.  This will let the file
data block mapping code attempt to get a dirty item without first
dirtying.

Signed-off-by: Zach Brown <zab@versity.com>
2016-08-09 17:03:30 -07:00
Zach Brown 59b1f62df8 scoutfs: add basic xattr support
Add basic support for extended attributes.  The next steps are
to add support for more prefixes, including ACLs, and to properly
delete them on unlink.

Signed-off-by: Zach Brown <zab@versity.com>
2016-07-04 10:59:43 -07:00
Zach Brown 5c7ba5ed39 scoutfs: remove wrlock and roster
These were interesting experiments in how to manage locks across the
cluster but we'll be going in a more flexible direction.

Signed-off-by: Zach Brown <zab@versity.com>
2016-07-01 21:03:40 -07:00
Zach Brown 0820a7b5bd scoutfs: introduce write locking
Introduce the concept of acquiring write locks around write operations.

The core idea is that reads are unlocked and that write lock contention
between nodes should be rare.  This first pass simply broadcasts write
lock requests to all the mounts in the volume.  It achieves a reasonable
degree of fairness and doesn't require centralizing state in a lock
server.

We have to flesh out a bit of initial infrastructure to support the
write locking protocol.  The roster manages cluster membership and
messaging and only understands mounts in the same kernel for now.
Creation needs to know which inodes to try and lock so we see the start
of per-mount free inode reservations.

The transformation of users is straight forward: they aquire the write
lock on the inodes they're working with instead of holding a
transaction.  The write lock machinery now manages transactions.

This passes single mount testing but that isn't saying much.  The next
step is to run multi-mount tests.

Signed-off-by: Zach Brown <zab@versity.com>
2016-05-23 17:25:06 -07:00
Zach Brown 4163236fc1 scoutfs: dirent hashes use linear probing
The current mechanism for dealing with dirent name hash collisions is to
use multiple hash functions.  This won't work great with the btree where
it's expensive to search multiple distant items for a given entry.

Instead of having multiple full precision functions we linearly probe a
given number of hash values after the initial name hash.  Now the slow
colliding path walks adjacent items in the tree instead of bouncing
around the tree.

Signed-off-by: Zach Brown <zab@versity.com>
2016-05-02 21:55:39 -07:00
Zach Brown e0f38231b3 scoutfs: store next allocated inode in super
The next inode number to be allocated has been stored only in the
in-memory super block and hasn't survived across mounts.  This sometimes
accidentally worked if the tests removed the initial inodes but often
would cause failures when inode allocation returned existing inodes.

This tracks the next inode to allocate in the super block and maintains
it across mounts.  Tests now consistently pass as inode allocations
consistently return free inode numbers.

Signed-off-by: Zach Brown <zab@versity.com>
2016-05-01 09:16:40 -07:00
Zach Brown 5651d48c18 scoutfs: add core btree functionality
Previously we had stubbed out the btree item API with static inlines.
Those are replaced with real functions in a reasonably functional btree
implementation.

The btree implementation itself is pretty straight forward.  Operations
are performed top-down and we dirty, lock, and split/merge blocks as we
go.  Callers are given a cursor to give them full access to the item.
Items in the btree blocks are stored in a treap.  There are a lot of
comments in the code to help make things clear.

We add the notion of block references and some block functions for
reading and dirtying blocks by reference.

This passes tests up to the point where unmount tries to write out data
and the world catches fire.  That's far enough to commit what we have
and iterate from there.

Signed-off-by: Zach Brown <zab@versity.com>
2016-04-12 19:33:09 -07:00
Zach Brown 5369fa1e05 scoutfs: first step towards multiple btrees
Starting to implement LSM merging made me really question if it is the
right approach.  I'd like to try an experiment to see if we can get our
concurrent writes done with much simpler btrees.

This commit removes all the functionality that derives from the large
LSM segments and distributing the manifest.

What's left is a multi-page block layer and the husk of the btree
implementation which will give people access to items.  Callers that
work with items get translated to the btree interface.

This gets as far as reading the super block but the format changes and
large block size mean that the crc check fails and the mount returns an
error.

Signed-off-by: Zach Brown <zab@versity.com>
2016-04-11 11:35:37 -07:00
Zach Brown 9c3918b576 scoutfs: remove accidentally committed notes
Some brainstorming notes in a comment accdentally made their way in to a
commit.

Signed-off-by: Zach Brown <zab@versity.com>
2016-03-27 16:19:19 -07:00
Zach Brown 059212d50e scoutfs: add some basic tracepoints
I added these tracepoints to verify that file data isn't reachable after
mount because we're not writing out the inode with the current i_size.

Signed-off-by: Zach Brown <zab@versity.com>
2016-03-26 22:28:42 -07:00
Zach Brown 9cf87ee571 scoutfs: add basic file page cache read and write
Add basic file data support by implementing the address space file and
page read and write methods.  This passis basic read/write tests but is
only the seed of a final implementation.

Signed-off-by: Zach Brown <zab@versity.com>
2016-03-26 10:58:06 -07:00
Zach Brown 434cbb9c78 scoutfs: create dirty items for inode updates
Inode updates weren't persistent because they were being stored in clean
segments in memory.  This was triggered by the new hashed dirent
mechanism returning -ENOENT when the inode still had a 0 max dirent hash
nr.

We make sure that there is a dirty item in the dirty segment at the
start of inode modification so that later updates will store in the
dirty segment.  Nothing ensures that the dirty segment won't be written
out today but that will be added soon.

Signed-off-by: Zach Brown <zab@versity.com>
2016-03-25 10:08:34 -07:00
Zach Brown 3755adddd5 scoutfs: store dirents at multiple hash values
Previously we dealt with colliding dirent hash values by storing all the
dirents that share a hash value in a big item with multiple dirents.

This complicated the code and strongly encouraged resizing items as
dirents come and go.  Resizing items isn't very easy with our simple log
segment item creation mechanism.

Instead let's deal with collisions by allowing a dirent to be stored at
multiple hash values.  The code is much simpler.

Lookup has to iterate over all possible hash values.  We can track the
greatest hash iteration stored in the directory inode to limit the
overhead of negative lookups in small directories.

Signed-off-by: Zach Brown <zab@versity.com>
2016-03-24 20:11:58 -07:00