diff options
author | Yan, Zheng <zheng.z.yan@intel.com> | 2013-09-17 21:44:13 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-09-30 17:49:53 -0400 |
commit | 81c6aea5275eae453719d7f3924da07e668265c5 (patch) | |
tree | 97fab33034d7b3f99cf4e875c1ed5c50bff54b78 /fs/ceph | |
parent | 53e879a485f9def0e55c404dbc7187470a01602d (diff) |
ceph: handle frag mismatch between readdir request and reply
If client has outdated directory fragments information, it may request
readdir an non-existent directory fragment. In this case, the MDS finds
an approximate directory fragment and sends its contents back to the
client. When receiving a reply with fragment that is different than the
requested one, the client need to reset the 'readdir offset'.
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Reviewed-by: Sage Weil <sage@inktank.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/dir.c | 11 | ||||
-rw-r--r-- | fs/ceph/inode.c | 16 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 3 |
3 files changed, 25 insertions, 5 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 868b61d56cac..2a0bcaeb189a 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -352,8 +352,18 @@ more: | |||
352 | } | 352 | } |
353 | 353 | ||
354 | /* note next offset and last dentry name */ | 354 | /* note next offset and last dentry name */ |
355 | rinfo = &req->r_reply_info; | ||
356 | if (le32_to_cpu(rinfo->dir_dir->frag) != frag) { | ||
357 | frag = le32_to_cpu(rinfo->dir_dir->frag); | ||
358 | if (ceph_frag_is_leftmost(frag)) | ||
359 | fi->next_offset = 2; | ||
360 | else | ||
361 | fi->next_offset = 0; | ||
362 | off = fi->next_offset; | ||
363 | } | ||
355 | fi->offset = fi->next_offset; | 364 | fi->offset = fi->next_offset; |
356 | fi->last_readdir = req; | 365 | fi->last_readdir = req; |
366 | fi->frag = frag; | ||
357 | 367 | ||
358 | if (req->r_reply_info.dir_end) { | 368 | if (req->r_reply_info.dir_end) { |
359 | kfree(fi->last_name); | 369 | kfree(fi->last_name); |
@@ -363,7 +373,6 @@ more: | |||
363 | else | 373 | else |
364 | fi->next_offset = 0; | 374 | fi->next_offset = 0; |
365 | } else { | 375 | } else { |
366 | rinfo = &req->r_reply_info; | ||
367 | err = note_last_dentry(fi, | 376 | err = note_last_dentry(fi, |
368 | rinfo->dir_dname[rinfo->dir_nr-1], | 377 | rinfo->dir_dname[rinfo->dir_nr-1], |
369 | rinfo->dir_dname_len[rinfo->dir_nr-1]); | 378 | rinfo->dir_dname_len[rinfo->dir_nr-1]); |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 1c9fea0c9834..9a8e396aed89 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -1275,8 +1275,20 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, | |||
1275 | int err = 0, i; | 1275 | int err = 0, i; |
1276 | struct inode *snapdir = NULL; | 1276 | struct inode *snapdir = NULL; |
1277 | struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; | 1277 | struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; |
1278 | u64 frag = le32_to_cpu(rhead->args.readdir.frag); | ||
1279 | struct ceph_dentry_info *di; | 1278 | struct ceph_dentry_info *di; |
1279 | u64 r_readdir_offset = req->r_readdir_offset; | ||
1280 | u32 frag = le32_to_cpu(rhead->args.readdir.frag); | ||
1281 | |||
1282 | if (rinfo->dir_dir && | ||
1283 | le32_to_cpu(rinfo->dir_dir->frag) != frag) { | ||
1284 | dout("readdir_prepopulate got new frag %x -> %x\n", | ||
1285 | frag, le32_to_cpu(rinfo->dir_dir->frag)); | ||
1286 | frag = le32_to_cpu(rinfo->dir_dir->frag); | ||
1287 | if (ceph_frag_is_leftmost(frag)) | ||
1288 | r_readdir_offset = 2; | ||
1289 | else | ||
1290 | r_readdir_offset = 0; | ||
1291 | } | ||
1280 | 1292 | ||
1281 | if (req->r_aborted) | 1293 | if (req->r_aborted) |
1282 | return readdir_prepopulate_inodes_only(req, session); | 1294 | return readdir_prepopulate_inodes_only(req, session); |
@@ -1340,7 +1352,7 @@ retry_lookup: | |||
1340 | } | 1352 | } |
1341 | 1353 | ||
1342 | di = dn->d_fsdata; | 1354 | di = dn->d_fsdata; |
1343 | di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset); | 1355 | di->offset = ceph_make_fpos(frag, i + r_readdir_offset); |
1344 | 1356 | ||
1345 | /* inode */ | 1357 | /* inode */ |
1346 | if (dn->d_inode) { | 1358 | if (dn->d_inode) { |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b7bda5d9611d..f51ab2627b41 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -2238,8 +2238,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
2238 | err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); | 2238 | err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); |
2239 | if (err == 0) { | 2239 | if (err == 0) { |
2240 | if (result == 0 && (req->r_op == CEPH_MDS_OP_READDIR || | 2240 | if (result == 0 && (req->r_op == CEPH_MDS_OP_READDIR || |
2241 | req->r_op == CEPH_MDS_OP_LSSNAP) && | 2241 | req->r_op == CEPH_MDS_OP_LSSNAP)) |
2242 | rinfo->dir_nr) | ||
2243 | ceph_readdir_prepopulate(req, req->r_session); | 2242 | ceph_readdir_prepopulate(req, req->r_session); |
2244 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); | 2243 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); |
2245 | } | 2244 | } |