Commit 14303d20 authored by Sage Weil's avatar Sage Weil

ceph: implement DIRLAYOUTHASH feature to get dir layout from MDS

This implements the DIRLAYOUTHASH protocol feature, which passes the dir
layout over the wire from the MDS.  This gives the client knowledge
of the correct hash function to use for mapping dentries among dir
fragments.

Note that if this feature is _not_ present on the client but is on the
MDS, the client may misdirect requests.  This will result in a forward
and degrade performance.  It may also result in inaccurate NFS filehandle
generation, which will prevent fh resolution when the inode is not present
in the client cache and the parent directories have been fragmented.
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 6c0f3af7
...@@ -682,6 +682,8 @@ static int fill_inode(struct inode *inode, ...@@ -682,6 +682,8 @@ static int fill_inode(struct inode *inode,
inode->i_op = &ceph_dir_iops; inode->i_op = &ceph_dir_iops;
inode->i_fop = &ceph_dir_fops; inode->i_fop = &ceph_dir_fops;
ci->i_dir_layout = iinfo->dir_layout;
ci->i_files = le64_to_cpu(info->files); ci->i_files = le64_to_cpu(info->files);
ci->i_subdirs = le64_to_cpu(info->subdirs); ci->i_subdirs = le64_to_cpu(info->subdirs);
ci->i_rbytes = le64_to_cpu(info->rbytes); ci->i_rbytes = le64_to_cpu(info->rbytes);
......
...@@ -60,7 +60,8 @@ static const struct ceph_connection_operations mds_con_ops; ...@@ -60,7 +60,8 @@ static const struct ceph_connection_operations mds_con_ops;
* parse individual inode info * parse individual inode info
*/ */
static int parse_reply_info_in(void **p, void *end, static int parse_reply_info_in(void **p, void *end,
struct ceph_mds_reply_info_in *info) struct ceph_mds_reply_info_in *info,
int features)
{ {
int err = -EIO; int err = -EIO;
...@@ -74,6 +75,12 @@ static int parse_reply_info_in(void **p, void *end, ...@@ -74,6 +75,12 @@ static int parse_reply_info_in(void **p, void *end,
info->symlink = *p; info->symlink = *p;
*p += info->symlink_len; *p += info->symlink_len;
if (features & CEPH_FEATURE_DIRLAYOUTHASH)
ceph_decode_copy_safe(p, end, &info->dir_layout,
sizeof(info->dir_layout), bad);
else
memset(&info->dir_layout, 0, sizeof(info->dir_layout));
ceph_decode_32_safe(p, end, info->xattr_len, bad); ceph_decode_32_safe(p, end, info->xattr_len, bad);
ceph_decode_need(p, end, info->xattr_len, bad); ceph_decode_need(p, end, info->xattr_len, bad);
info->xattr_data = *p; info->xattr_data = *p;
...@@ -88,12 +95,13 @@ static int parse_reply_info_in(void **p, void *end, ...@@ -88,12 +95,13 @@ static int parse_reply_info_in(void **p, void *end,
* target inode. * target inode.
*/ */
static int parse_reply_info_trace(void **p, void *end, static int parse_reply_info_trace(void **p, void *end,
struct ceph_mds_reply_info_parsed *info) struct ceph_mds_reply_info_parsed *info,
int features)
{ {
int err; int err;
if (info->head->is_dentry) { if (info->head->is_dentry) {
err = parse_reply_info_in(p, end, &info->diri); err = parse_reply_info_in(p, end, &info->diri, features);
if (err < 0) if (err < 0)
goto out_bad; goto out_bad;
...@@ -114,7 +122,7 @@ static int parse_reply_info_trace(void **p, void *end, ...@@ -114,7 +122,7 @@ static int parse_reply_info_trace(void **p, void *end,
} }
if (info->head->is_target) { if (info->head->is_target) {
err = parse_reply_info_in(p, end, &info->targeti); err = parse_reply_info_in(p, end, &info->targeti, features);
if (err < 0) if (err < 0)
goto out_bad; goto out_bad;
} }
...@@ -134,7 +142,8 @@ static int parse_reply_info_trace(void **p, void *end, ...@@ -134,7 +142,8 @@ static int parse_reply_info_trace(void **p, void *end,
* parse readdir results * parse readdir results
*/ */
static int parse_reply_info_dir(void **p, void *end, static int parse_reply_info_dir(void **p, void *end,
struct ceph_mds_reply_info_parsed *info) struct ceph_mds_reply_info_parsed *info,
int features)
{ {
u32 num, i = 0; u32 num, i = 0;
int err; int err;
...@@ -182,7 +191,7 @@ static int parse_reply_info_dir(void **p, void *end, ...@@ -182,7 +191,7 @@ static int parse_reply_info_dir(void **p, void *end,
*p += sizeof(struct ceph_mds_reply_lease); *p += sizeof(struct ceph_mds_reply_lease);
/* inode */ /* inode */
err = parse_reply_info_in(p, end, &info->dir_in[i]); err = parse_reply_info_in(p, end, &info->dir_in[i], features);
if (err < 0) if (err < 0)
goto out_bad; goto out_bad;
i++; i++;
...@@ -205,7 +214,8 @@ static int parse_reply_info_dir(void **p, void *end, ...@@ -205,7 +214,8 @@ static int parse_reply_info_dir(void **p, void *end,
* parse fcntl F_GETLK results * parse fcntl F_GETLK results
*/ */
static int parse_reply_info_filelock(void **p, void *end, static int parse_reply_info_filelock(void **p, void *end,
struct ceph_mds_reply_info_parsed *info) struct ceph_mds_reply_info_parsed *info,
int features)
{ {
if (*p + sizeof(*info->filelock_reply) > end) if (*p + sizeof(*info->filelock_reply) > end)
goto bad; goto bad;
...@@ -225,19 +235,21 @@ static int parse_reply_info_filelock(void **p, void *end, ...@@ -225,19 +235,21 @@ static int parse_reply_info_filelock(void **p, void *end,
* parse extra results * parse extra results
*/ */
static int parse_reply_info_extra(void **p, void *end, static int parse_reply_info_extra(void **p, void *end,
struct ceph_mds_reply_info_parsed *info) struct ceph_mds_reply_info_parsed *info,
int features)
{ {
if (info->head->op == CEPH_MDS_OP_GETFILELOCK) if (info->head->op == CEPH_MDS_OP_GETFILELOCK)
return parse_reply_info_filelock(p, end, info); return parse_reply_info_filelock(p, end, info, features);
else else
return parse_reply_info_dir(p, end, info); return parse_reply_info_dir(p, end, info, features);
} }
/* /*
* parse entire mds reply * parse entire mds reply
*/ */
static int parse_reply_info(struct ceph_msg *msg, static int parse_reply_info(struct ceph_msg *msg,
struct ceph_mds_reply_info_parsed *info) struct ceph_mds_reply_info_parsed *info,
int features)
{ {
void *p, *end; void *p, *end;
u32 len; u32 len;
...@@ -250,7 +262,7 @@ static int parse_reply_info(struct ceph_msg *msg, ...@@ -250,7 +262,7 @@ static int parse_reply_info(struct ceph_msg *msg,
/* trace */ /* trace */
ceph_decode_32_safe(&p, end, len, bad); ceph_decode_32_safe(&p, end, len, bad);
if (len > 0) { if (len > 0) {
err = parse_reply_info_trace(&p, p+len, info); err = parse_reply_info_trace(&p, p+len, info, features);
if (err < 0) if (err < 0)
goto out_bad; goto out_bad;
} }
...@@ -258,7 +270,7 @@ static int parse_reply_info(struct ceph_msg *msg, ...@@ -258,7 +270,7 @@ static int parse_reply_info(struct ceph_msg *msg,
/* extra */ /* extra */
ceph_decode_32_safe(&p, end, len, bad); ceph_decode_32_safe(&p, end, len, bad);
if (len > 0) { if (len > 0) {
err = parse_reply_info_extra(&p, p+len, info); err = parse_reply_info_extra(&p, p+len, info, features);
if (err < 0) if (err < 0)
goto out_bad; goto out_bad;
} }
...@@ -654,7 +666,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, ...@@ -654,7 +666,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
} else { } else {
/* dir + name */ /* dir + name */
inode = dir; inode = dir;
hash = req->r_dentry->d_name.hash; hash = ceph_dentry_hash(req->r_dentry);
is_hash = true; is_hash = true;
} }
} }
...@@ -2101,7 +2113,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) ...@@ -2101,7 +2113,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
dout("handle_reply tid %lld result %d\n", tid, result); dout("handle_reply tid %lld result %d\n", tid, result);
rinfo = &req->r_reply_info; rinfo = &req->r_reply_info;
err = parse_reply_info(msg, rinfo); err = parse_reply_info(msg, rinfo, session->s_con.peer_features);
mutex_unlock(&mdsc->mutex); mutex_unlock(&mdsc->mutex);
mutex_lock(&session->s_mutex); mutex_lock(&session->s_mutex);
......
...@@ -35,6 +35,7 @@ struct ceph_cap; ...@@ -35,6 +35,7 @@ struct ceph_cap;
*/ */
struct ceph_mds_reply_info_in { struct ceph_mds_reply_info_in {
struct ceph_mds_reply_inode *in; struct ceph_mds_reply_inode *in;
struct ceph_dir_layout dir_layout;
u32 symlink_len; u32 symlink_len;
char *symlink; char *symlink;
u32 xattr_len; u32 xattr_len;
......
...@@ -428,7 +428,8 @@ struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, ...@@ -428,7 +428,8 @@ struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
goto fail; goto fail;
} }
fsc->client->extra_mon_dispatch = extra_mon_dispatch; fsc->client->extra_mon_dispatch = extra_mon_dispatch;
fsc->client->supported_features |= CEPH_FEATURE_FLOCK; fsc->client->supported_features |= CEPH_FEATURE_FLOCK |
CEPH_FEATURE_DIRLAYOUTHASH;
fsc->client->monc.want_mdsmap = 1; fsc->client->monc.want_mdsmap = 1;
fsc->mount_options = fsopt; fsc->mount_options = fsopt;
......
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