mds: acquire scatter locks when exporting dir

If auth MDS of the subtree root inode is neither the exporter MDS
nor the importer MDS and it gathers subtree root's fragstat/neststat
while the subtree is exporting. It's possible that the exporter MDS
and the importer MDS both are auth MDS of the subtree root or both
are not auth MDS of the subtree root at the time they receive the
lock messages. So the auth MDS of the subtree root inode may get no
or duplicated fragstat/neststat for the subtree root dirfrag.

The fix is, during exporting a subtree, both the exporter MDS and
the importer MDS hold locks on scatter locks of the subtree root
inode. For the importer MDS, it tries acquiring locks on the scatter
locks when handling the MExportDirPrep message. If fails to acquire
all locks, it sends a NACK to the exporter MDS. The exporter MDS
cancels the exporting when receiving the NACK.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: revert commit 15a5d37a

commit 15a5d37a (mds: fix race between scatter gather and dirfrag export)
is incomplete, it doesn't handles the race that no fragstat/neststat is
gathered. Previous commit prevents scatter gather during exporting dir,
which eliminates races of this type.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: introduce fine-grained discover dirfrag wait queue

Current discover dirfrag code only allows discover one dirfrag at
a time. This can cause deadlock if there are directories that are
fragmented to several dirfrags. For example:

mds.0                        mds.1
-----------------------------------------------------------------
                             freeze subtree (1.*) with bound (2.1*)
discover (2.0*) ->
                             handle discover (2.0*), frozen tree, wait
                          <- export subtree (1.*) to with bound (2.1*)
discover (2.1*), wait

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: use discover_path to open remote inode

MDCache::discover_ino() doesn't work well for directories that are
fragmented to several dirfrags. Because MDCache::handle_discover()
doesn't know which dirfrags the inode lives in when the sender has
outdatad frag information.

This patch replaces all use of MDCache::discover_ino() with
MDCache::discover_path().

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: remove discover ino

MDCache::discover_path() can replace MDCache::discover_ino() in
almost all cases, it also handles dirfrags better. This patch
removes discover ino related code.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: handle frag mismatch for discover

When handle discover dirfrag message, choose an approximate frag if
the requested dirfrag doesn't exist. When handling discover dirfrag
replay, wake up appropriate waiters if the reply is different from
the the requested dirfrag.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: fix MDCache::get_force_dirfrag_bound_set()

don't force dir fragments according to the subtree bounds in resolve
message. The resolve message was not sent by the auth MDS of these
subtree bounds dirfrags.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: fix MDCache::adjust_subtree_after_rename()

process subtree dirfrags first, then process nested dirfrags. because
the code that processes nested dirfrags treats unprocessed subtree
dirfrags as child directories' dirfrags.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: fix CInode::get_dirfrags_under()

make the function work when opened dirfrags don't match the
dirfragtree.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: properly set COMPLETE flag when merging dirfrags

don't keep the COMPLETE flag when merging dirfrags during journal
replay, because it's inconvenience to check if the all dirfrags
under the 'basefrag' are in the cache and complete. One special case
is that newly created dirfrag get fragmented, then the fragment
operation get rolled back. The COMPLETE flag should be preserved in
this case because the dirfrag still doesn't exist on object store.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: fix open undef dirfrags

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: handle frag mismatch for cache rejoin weak

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: handle frag mismatch for cache expire

When sending MDSFragmentNotify to peers, also replicate the new
dirfrags. This guarantees peers get new replica nonces for the
new dirfrags. So it's safe to ignore mismatched/old dirfrags in
the cache expire message.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: improve freeze tree deadlock detection

Current code uses the start time of freezing tree to detect deadlock.
It is better to check how long the auth pin count of freezing tree
stays unchanged to decide if there is potential deadlock.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: freeze dir deadlock detection

freezing dir and freezing tree have the same deadlock cases.
This patch adds freeze dir deadlock detection, which imitates
commit ab93aa59 (mds: freeze tree deadlock detection)

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: minor cleanup for EFragment and MMDSFragmentNotify

pass dirfrag_t to their constructors, instead of passing inode_t
and frag_t separately.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: preserve dir_auth when spliting/merging dirfrags

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: allow fragmenting subtree dirfrags

We can't wait until object becomes auth pinnable after freezing a
dirfrag/subtree, because it can cause deadlock. Current fragmenting
dirfrag code checks if the directory inode is auth pinnable, then
calls Locker::acquire_locks(). It avoids deadlock, but also forbids
fragmenting subtree dirfrags. We can get rid of the limitation by
using 'nonlocking auth pin' mode of Locker::acquire_locks().

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: journal dirfragtree change

Introduce new flag DIRTYDFT to CDir and EMetaBlob::dirlump, the new
flag indicates the dirfrag is newly fragmented and the corresponding
dirfragtree change hasn't been propagate to the directory inode.

After fragmenting subtree dirfrags, make sure DIRTYDFT flag is set
on EMetaBlob::dirlump that correspond to the resulting dirfrags.
Journal replay code uses DIRTYDFT frag to decide if dirfragtree is
scattered dirty.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
mds: fix CInode::force_dirfrag() during journal replay

For rename operation, null dentry is first replayed, it detaches
the inode from the FS hierarchy. Then primary dentry is replayed,
it updates the inode and re-attaches the inode to the FS hierarchy.
We may call CInode::force_dirfrag() when updating the inode. But
CInode::force_dirfrag() doesn't work well when inode is detached
from the FS hierarchy because adjusting fragments may also adjust
subtree map. The fix is don't detach the inode when replaying the
null dentry.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>