Commit eb6bb1c5 authored by Sage Weil's avatar Sage Weil

ceph: direct requests in snapped namespace based on nonsnap parent

When making a request in the virtual snapdir or a snapped portion of the
namespace, we should choose the MDS based on the first nonsnap parent (and
its caps).  If that is not the best place, we will get forward hints to
find the right MDS in the cluster.  This fixes ESTALE errors when using
the .snap directory and namespace with multiple MDSs.
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent ed326044
...@@ -560,6 +560,13 @@ static void __unregister_request(struct ceph_mds_client *mdsc, ...@@ -560,6 +560,13 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
* *
* Called under mdsc->mutex. * Called under mdsc->mutex.
*/ */
struct dentry *get_nonsnap_parent(struct dentry *dentry)
{
while (!IS_ROOT(dentry) && ceph_snap(dentry->d_inode) != CEPH_NOSNAP)
dentry = dentry->d_parent;
return dentry;
}
static int __choose_mds(struct ceph_mds_client *mdsc, static int __choose_mds(struct ceph_mds_client *mdsc,
struct ceph_mds_request *req) struct ceph_mds_request *req)
{ {
...@@ -590,14 +597,29 @@ static int __choose_mds(struct ceph_mds_client *mdsc, ...@@ -590,14 +597,29 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
if (req->r_inode) { if (req->r_inode) {
inode = req->r_inode; inode = req->r_inode;
} else if (req->r_dentry) { } else if (req->r_dentry) {
if (req->r_dentry->d_inode) { struct inode *dir = req->r_dentry->d_parent->d_inode;
if (dir->i_sb != mdsc->client->sb) {
/* not this fs! */
inode = req->r_dentry->d_inode;
} else if (ceph_snap(dir) != CEPH_NOSNAP) {
/* direct snapped/virtual snapdir requests
* based on parent dir inode */
struct dentry *dn =
get_nonsnap_parent(req->r_dentry->d_parent);
inode = dn->d_inode;
dout("__choose_mds using nonsnap parent %p\n", inode);
} else if (req->r_dentry->d_inode) {
/* dentry target */
inode = req->r_dentry->d_inode; inode = req->r_dentry->d_inode;
} else { } else {
inode = req->r_dentry->d_parent->d_inode; /* dir + name */
inode = dir;
hash = req->r_dentry->d_name.hash; hash = req->r_dentry->d_name.hash;
is_hash = true; is_hash = true;
} }
} }
dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash, dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash,
(int)hash, mode); (int)hash, mode);
if (!inode) if (!inode)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment