]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: _readdir_cache_cb() may use the readdir_cache already clear 30934/head
authorhuanwen ren <ren.huanwen@zte.com.cn>
Wed, 7 Aug 2019 16:49:23 +0000 (00:49 +0800)
committerNathan Cutler <ncutler@suse.com>
Tue, 15 Oct 2019 09:41:16 +0000 (11:41 +0200)
Calling function _readdir_cache_cb() means to get dir information from the cache, but in the while loop,
the contents of readdir_cache are not static.

For example, _getattr() will trigger insert_trace to update readdir_cache, such as:
1. insert_trace()->clear_dir_complete_and_ordered() or
2. insert_trace()->add_update_inode()->add_update_cap()-> check_cap_issue()->clear_dir_complete_and_ordered()
So, there is a possibility that dn is empty after the _getattr() call.

Fixes: http://tracker.ceph.com/issues/41148
Signed-off-by: huanwen ren <ren.huanwen@zte.com.cn>
(cherry picked from commit 404c06784e46016703104db59ea73f36d09b578b)

src/client/Client.cc

index e9e862d37cdbe7ca930c98e1ecde1d72d98e3647..f3a9380179909c27f88ad0347480f5601cf431d9 100644 (file)
@@ -7819,9 +7819,15 @@ int Client::_readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p,
       continue;
     }
 
+    int idx = pd - dir->readdir_cache.begin();
     int r = _getattr(dn->inode, caps, dirp->perms);
     if (r < 0)
       return r;
+    
+    // the content of readdir_cache may change after _getattr(), so pd may be invalid iterator    
+    pd = dir->readdir_cache.begin() + idx;
+    if (pd >= dir->readdir_cache.end() || *pd != dn)
+      return -EAGAIN;
 
     struct ceph_statx stx;
     struct dirent de;