Sage Weil [Tue, 11 Dec 2012 00:41:19 +0000 (16:41 -0800)]
config: do not always print config file missing errors
Do not generate errors each time we fail to open a config file; only
generate one at the end if a search path was specified and none were
usable, right before we (already) exit. This avoids spamming stderr
about each path we tried in the search list before we found a good one.
Samuel Just [Mon, 10 Dec 2012 21:38:24 +0000 (13:38 -0800)]
config_opts.h: adjust recovery defaults
osd max backfills: 5 was too low for a default, 10
seems to work better in testing. The message
priority system should minimize disruption of
push and pull operations anyway.
osd recovery max chunk: 1MB was too small for a
default. 8MB is reasonable for a single push
and will allow us to recover an rbd block in
one push rather then 4 reducing client io
latency during log-based recovery.
osd recovery op priority: 10 rather than 30 will
further reduce the client io latency impact of
push and pull operations.
Sage Weil [Sun, 9 Dec 2012 05:44:54 +0000 (21:44 -0800)]
mon: fix leak of pool op reply data
We pass a pointer because it is an optional argument, but we shouldn't
put the bufferlist on the heap or else we have to manage it's life
cycle, and that's fragile (and previously broken).
Sage Weil [Fri, 7 Dec 2012 00:18:07 +0000 (16:18 -0800)]
filestore: simplify op quescing
The delicate balancing with op_apply_start() and that fact that it can
block was making it very hard to determine how long commit_start() should
wait, since requests in the workqueue threads could op_apply_start() in
any order. For example,
threadA: gets osr1 from wq
threadA: gets osr2 from wq
threadA: dequeue seq 11 from osr1, op_apply_start
threadC: commit_start on 11
threadA: op_apply_finish on seq 11
threadC: commit_started, commit_finish
threadB: dequeue seq 10 from osr2
<failed assert, badness>
Instead, rip out all this code, and use the ThreadPool pause() method to
quiesce operations. Keep some of the (now unnecessary) fields around
for sanity checks (blocked, open_ops, max_applying_seq, etc.).
Samuel Just [Tue, 4 Dec 2012 19:36:58 +0000 (11:36 -0800)]
PG: remove last_epoch_started asserts in proc_primary_info
These asserts are valid for a uniform cluster, but they won't hold
for a replica running a version without the info.last_epoch_started
patch.
Signed-off-by: Samuel Just <sam.just@inktank.com> Reviewed-by: Greg Farnum <greg@inktank.com>
(cherry picked from commit 0756052cff542ab02d653b40c37a645b395f31b3)
Sage Weil [Wed, 5 Dec 2012 13:56:37 +0000 (05:56 -0800)]
mds: move from EXCL to SYNC if nobody wants to write
We were moving to the MIX even if nobody wanted to write; that is not
useful, since if we only want to read SYNC will let us cache those reads.
SYNC is also a more friendly place (all things equal) to be.
mon: Monitor: rework 'paxos' to a list instead of a vector
After adding the gv patches, during Monitor::recovered_leader() we started
waking up contexts following the order of the 'paxos' vector. However,
given that the mdsmon has a forgotten dependency on the osdmon paxos
machine, we were incurring in a situation in which we proposed a value
through the osdmon before creating a new pending value (but by being
active, the mdsmon would go through with it nonetheless).
This is easily fixed by making sure that the mdsmon callbacks are only
awaken *after* the osdmon has been taken care of.
Fixes: #3495 Signed-off-by: Joao Eduardo Luis <joao.luis@inktank.com>
Samuel Just [Thu, 6 Dec 2012 22:52:13 +0000 (14:52 -0800)]
librados: watch() should set the WRITE flag on the op
This caused a bug where the watch operation bypassed the is_degraded()
check in the write path and the repop got sent to the replica where the
replica crashed due to the is_missing() assert in sub_op_modify.
Signed-off-by: Samuel Just <sam.just@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Samuel Just [Thu, 6 Dec 2012 21:57:01 +0000 (13:57 -0800)]
HashIndex: fix list_by_hash handling of next->is_max()
get_path_str() should not handle hobject_t::get_max(). get_path_str()
now asserts that the passed object is not max and the callers now check
for is_max(). This caused HashIndex.cc to incorrectly scan an entire
collection before returning no objects rather than scanning the top
level and returning no objects. It did not actually list_by_hash to
return an incorrect answer, however.
Signed-off-by: Samuel Just <sam.just@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Sam Lang [Thu, 6 Dec 2012 05:11:10 +0000 (21:11 -0800)]
client: Allow cap release timeout to be configured
The delay for releasing an inode's capability is
hardcoded to 5 seconds. This patch takes the timeout
value from a config parameter, which defaults presently
to 5 seconds.
Dan Mick [Tue, 4 Dec 2012 04:59:17 +0000 (20:59 -0800)]
librbd: hold AioCompletion lock while modifying global state
C_AioRead::finish needs to add in each chunk of a partial read
request to the 'partial' map in the AioCompletion's state
(in destriper, of type StripedReadResult). That map is global
and must be protected from simultaneous access. Use the
AioCompletion lock; could create a separate lock if contention is an
issue.
Dan Mick [Sat, 1 Dec 2012 02:11:09 +0000 (18:11 -0800)]
librbd: handle parent change while async I/Os are in flight
During a test_librbd_fsx run including flatten, ImageCtx->parent
was being dereferenced while null. Between the time the parent
overlap is calculated and the time the guard+write completes
with ENOENT and submits the copyup+write, the parent image
could have changed (by resize) or been made irrelevant (by
child flatten) such that the parent overlap is now incorrect.
Handle "no parent" by just sending the copyup+write; the copyup
part will be a no-op. Move to WRITE_FLAT state in this case
because there's no more child to deal with.
Handle "overlap changed" by recalculating overlap before
reading parent data; if none is left, don't read, but rather
just clear m_object_image_extents, in which case the copyup
will again be a no-op because it will be of zero length.
However we still have a parent, so stay in WRITE_COPYUP state
and come back through as usual.
Dan Mick [Tue, 4 Dec 2012 04:59:17 +0000 (20:59 -0800)]
librbd: hold AioCompletion lock while modifying global state
C_AioRead::finish needs to add in each chunk of a partial read
request to the 'partial' map in the AioCompletion's state
(in destriper, of type StripedReadResult). That map is global
and must be protected from simultaneous access. Use the
AioCompletion lock; could create a separate lock if contention is an
issue.
Fixes: #3567 Signed-off-by: Dan Mick <dan.mick@inktank.com>
Dan Mick [Sat, 1 Dec 2012 02:11:09 +0000 (18:11 -0800)]
librbd: handle parent change while async I/Os are in flight
During a test_librbd_fsx run including flatten, ImageCtx->parent
was being dereferenced while null. Between the time the parent
overlap is calculated and the time the guard+write completes
with ENOENT and submits the copyup+write, the parent image
could have changed (by resize) or been made irrelevant (by
child flatten) such that the parent overlap is now incorrect.
Handle "no parent" by just sending the copyup+write; the copyup
part will be a no-op. Move to WRITE_FLAT state in this case
because there's no more child to deal with.
Handle "overlap changed" by recalculating overlap before
reading parent data; if none is left, don't read, but rather
just clear m_object_image_extents, in which case the copyup
will again be a no-op because it will be of zero length.
However we still have a parent, so stay in WRITE_COPYUP state
and come back through as usual.
Signed-off-by: Dan Mick <dan.mick@inktank.com> Fixes: #3524
Yan, Zheng [Tue, 4 Dec 2012 08:09:48 +0000 (16:09 +0800)]
mds: journal remote inode's projected parent
Server::_rename_prepare() adds remote inode's parent instead of
projected parent to the journal. So during journal replay, the
journal entry for the rename operation will wrongly revert the
remote inode's projected rename. This issue can be reproduced by:
Yan, Zheng [Tue, 4 Dec 2012 08:09:47 +0000 (16:09 +0800)]
mds: don't create bloom filter for incomplete dir
Creating bloom filter for incomplete dir that was added by log
replay will confuse subsequent dir lookup and can create null
dentry for existing file. The erroneous null dentry confuses the
fragstat accounting and causes undeletable empty directory.
The fix is check if the dir is complete before creating the bloom
filter. For the MDCache::trim_non_auth{,_subtree} cases, just do
not call CDir::add_to_bloom because bloom filter is useless for
replica.
Yan, Zheng [Tue, 4 Dec 2012 08:09:48 +0000 (16:09 +0800)]
mds: journal remote inode's projected parent
Server::_rename_prepare() adds remote inode's parent instead of
projected parent to the journal. So during journal replay, the
journal entry for the rename operation will wrongly revert the
remote inode's projected rename. This issue can be reproduced by:
Yan, Zheng [Tue, 4 Dec 2012 08:09:47 +0000 (16:09 +0800)]
mds: don't create bloom filter for incomplete dir
Creating bloom filter for incomplete dir that was added by log
replay will confuse subsequent dir lookup and can create null
dentry for existing file. The erroneous null dentry confuses the
fragstat accounting and causes undeletable empty directory.
The fix is check if the dir is complete before creating the bloom
filter. For the MDCache::trim_non_auth{,_subtree} cases, just do
not call CDir::add_to_bloom because bloom filter is useless for
replica.
Sam Lang [Thu, 29 Nov 2012 20:32:32 +0000 (14:32 -0600)]
client: Fix ceph_mount() when subdir is specified
If a subdirectory is specified to ceph_mount, the
root inode does not have an ino of CEPH_INO_ROOT, so
cwd will fail to ever find root and eventially hits
an assertion in in->get_first_parent(). This fix uses
the inode stored in the root member instead, ensuring
that we stop wherever the mount is rooted.
Sage Weil [Wed, 28 Nov 2012 04:43:38 +0000 (20:43 -0800)]
mds: use TMAP_RMSLOPPY op when removing dentries
After replay, we don't know if the dentry removal has already been
committed. Use a sloppy removal so that we succeed even if we are
repeating the operation.
Conveniently, the previous implementation (pre v0.55) silently ignored
tmap op codes it did not understand, which means this new RMSLOPPY will
be interpreted the same as an actual RMSLOPPY. That means an v0.55
mds can run against an older osd (say, argonaut) without problems.
Rename applied_seq to max_applied_seq, since it is a bound; there may be
seq's < max_applied_seq that are not applied. This aligns the naming with
max_applying_seq.
Sage Weil [Sun, 2 Dec 2012 15:29:46 +0000 (07:29 -0800)]
os/FileStore: only wait for applying ops to complete before commit
We can have a large number of operations in the op_wq waiting to be applied
to the fs. Currently, when we want to commit, we want for them *all* to
apply. This can take a very long time (the default queue length is 500
operations!).
Instead, mark an Op as started ("applying") when the thread pool actually
starts to apply it. At that point, only wait for applying ops to complete.
We let any threads with an op seq < max_applying_seq begin as well so that
we have a proper ordering/barrier. When those flush, applied_seq will ==
max_applying_seq, and that becomes the committing_seq value.
Note that 'applied_seq' is still maintain, but serves no real purpose
except to populate our asserts with sanity checks. max_applying_seq serves
the purpose applied_seq used to.
This removes once unnecessary source of latency associated with fs
commits.
Sage Weil [Sat, 1 Dec 2012 05:43:06 +0000 (21:43 -0800)]
OutputDataSocket: fix uninit var
CID 745933 (#1 of 1): Uninitialized scalar field (UNINIT_CTOR)
At (2): Non-static class member "data_size" is not initialized in this constructor nor in any functions that it calls.
Sage Weil [Sat, 1 Dec 2012 05:41:54 +0000 (21:41 -0800)]
rgw: fix uninit var
CID 745935 (#1 of 1): Uninitialized scalar field (UNINIT_CTOR)
At (2): Non-static class member "expiration" is not initialized in this constructor nor in any functions that it calls.
At (2): Non-static class member "min_len" is not initialized in this constructor nor in any functions that it calls.
At (4): Non-static class member "max_len" is not initialized in this constructor nor in any functions that it calls.
At (6): Non-static class member "ret" is not initialized in this constructor nor in any functions that it calls.
At (8): Non-static class member "len" is not initialized in this constructor nor in any functions that it calls.
At (10): Non-static class member "ofs" is not initialized in this constructor nor in any functions that it calls.
At (12): Non-static class member "supplied_md5_b64" is not initialized in this constructor nor in any functions that it calls.
At (14): Non-static class member "supplied_etag" is not initialized in this constructor nor in any functions that it calls.
CID 745934 (#1 of 1): Uninitialized pointer field (UNINIT_CTOR)
At (16): Non-static class member "data_pending" is not initialized in this constructor nor in any functions that it calls.
Sage Weil [Sat, 1 Dec 2012 05:39:05 +0000 (21:39 -0800)]
test/osdc/FakeWriteback: fix uninit var
CID 745936 (#1 of 1): Uninitialized scalar field (UNINIT_CTOR)
At (2): Non-static class member "m_off" is not initialized in this constructor nor in any functions that it calls.
Yan, Zheng [Mon, 19 Nov 2012 02:43:46 +0000 (10:43 +0800)]
mds: fix freeze inode deadlock
CInode::freeze_inode() is used in the case of cross authority rename.
Server::handle_slave_rename_prep() calls it to wait for all other
operations on source inode to complete. This happens after all locks
for the rename operation are acquired. But to acquire locks, we need
auth pin locks' parent objects first. So there is an ABBA deadlock
if someone auth pins the source inode after locks for rename are
acquired and before Server::handle_slave_rename_prep() is called.
The fix is freeze and auth pin the source inode at the same time.
This patch introduces CInode::freeze_auth_pin(), it waits for all
other MDRequests to release auth pins, then change the inode to
FROZENAUTHPIN state, this state prevents other MDRequests from
getting new auth pins.
Yan, Zheng [Mon, 19 Nov 2012 02:43:48 +0000 (10:43 +0800)]
mds: use rdlock_try() when checking NULL dentry
Use rdlock_try() instead can_read() when path_traverse encounters
a NULL dentry. This can partly avoid infinitely waiting for the
dentry to become readable when the dentry is replica.
Strictly speaking, use rdlock_try() is still enough because auth
MDS may drop the REQRDLOCK message in some cases.
Yan, Zheng [Mon, 19 Nov 2012 02:43:47 +0000 (10:43 +0800)]
mds: allow open_remote_ino() to open xlocked dentry
discover_ino() has a parameter want_xlocked. The parameter indicates
if remote discover handler can proceed when xlocked dentry is
encountered. open_remote_ino() uses discover_ino() to find non-auth
inode, but always set 'want_xlocked' to false. This may cause
dead lock in some corner cases. For example:
we rename a inode's primary dentry to one of its remote dentry and
send slave request to one witness MDS. but before the slave request
reaches the witness MDS, the inode is trimmed from the witness MDS'
cache. Then when the slave request arrives, open_remote_ino() will
be called during traversing the destpath. open_remote_ino() calls
discover_ino() with 'want_xlocled=false' to find the inode.
discover_ino() sends MDiscover message to the inode's authority MDS.
The handler of MDiscover message finds the inode's primary dentry
is xlocked and it sleeps.
The fix is add a parameter 'want_xlocked' to open_remote_ino() and
make open_remote_ino() pass the parameter to discover_ino().
Yan, Zheng [Mon, 19 Nov 2012 02:43:44 +0000 (10:43 +0800)]
mds: fix open_remote_inode race
discover_ino() may return -ENOENT if it races with other FS activities.
so use C_MDC_RetryOpenRemoteIno instead of C_MDC_OpenRemoteIno as
onfinish callback.
Yan, Zheng [Mon, 19 Nov 2012 02:43:43 +0000 (10:43 +0800)]
mds: consider revoking caps in imported caps as issued
The clients may already send caps release message to the exporting
MDS, so the importing MDS waits for the release message forever.
consider revoking caps as issued can avoid this issue.
Yan, Zheng [Mon, 19 Nov 2012 02:43:42 +0000 (10:43 +0800)]
mds: drop locks if requiring auth pinning new objects.
Locker::acquire_locks() skip auth pinning replica object if we only
request a rdlock and the lock is read-lockable. To get all locks,
we may call Locker::acquire_locks() several times, locks in replca
objects may become not read-lockable between calls. So it is
possible we need auth pin new objects after already take some locks.
Yan, Zheng [Mon, 19 Nov 2012 02:43:40 +0000 (10:43 +0800)]
mds: don't forward client request from MDS
Forwarding client request that was from MDS will trigger assertion
in MDS::forward_message_mds(). MDS only send client requests for
stray migration/reintegration, so it's safe to drop them.
Yan, Zheng [Mon, 19 Nov 2012 02:43:39 +0000 (10:43 +0800)]
mds: call eval() after caps are exported
For an inode just changed authority, if the new auth MDS want to
change a lock in the inode from 'sync' to 'lock' state before caps
are exported. The lock in replica can be in 'sync->lock' state
because client caps prevent it from transitting to 'lock' state.
So we should call eval() after clearing client caps.
Yan, Zheng [Mon, 19 Nov 2012 02:43:37 +0000 (10:43 +0800)]
mds: Don't acquire replica object's versionlock
Both CInode and CDentry's versionlocks are of type LocalLock.
Acquiring LocalLock in replica object is useless and problematic.
For example, if two requests try acquiring a replica object's
versionlock, the first request succeeds, the second request
is added to wait queue. Later when the first request finishes,
MDCache::request_drop_foreign_locks() finds the lock's parent is
non-auth, it skips waking requests in the wait queue. So the
second request hangs.
Yan, Zheng [Mon, 19 Nov 2012 02:43:36 +0000 (10:43 +0800)]
mds: allow try_eval to eval unstable locks in freezing object
Unstable locks hold auth_pins on the object, it prevents the freezing
object become frozen and then unfreeze. So try_eval() should not wait
for freezing object
Sage Weil [Sat, 1 Dec 2012 04:23:52 +0000 (20:23 -0800)]
msg/Pipe: flush delayed messages when stealing/failing pipes
If we are failing a pipe, flush the incoming messages before we try to
reconnect. Similarly, flush queued messages on an existing pipe beore we
replace it. This ensures that when we get a socket failure and reconnect
the delayed messages are handled in the normal fashion.
Specifically, it fixes a situation like:
- read msg, update in_seq etc.
- delay msg
- pipe faults
- peer reconnects, we replace existing pipe, discard delayed msgs
- peer resends msgs
- we discard, because they are < in_seq