diff options
author | Yehuda Sadeh <yehuda@hq.newdream.net> | 2010-01-07 18:36:32 -0500 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-01-14 15:23:14 -0500 |
commit | 4baa75ef0ed29adae03fcbbaa9aca1511a5a8cc9 (patch) | |
tree | f3ba17caa2a8738eff064b611c1d7bb0610f3037 | |
parent | 6a4ef48103a78a46b80e07fcd8ac4edda0c7128f (diff) |
ceph: change dentry offset and position after splice_dentry
This fixes a bug, where we had the parent list have dentries with
offsets that are not monotonically increasing, which caused the ceph
dcache_readdir to skip entries.
Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r-- | fs/ceph/inode.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8774b2811597..518beb628f09 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -817,6 +817,33 @@ out: | |||
817 | } | 817 | } |
818 | 818 | ||
819 | /* | 819 | /* |
820 | * Set dentry's directory position based on the current dir's max, and | ||
821 | * order it in d_subdirs, so that dcache_readdir behaves. | ||
822 | */ | ||
823 | static void ceph_set_dentry_offset(struct dentry *dn) | ||
824 | { | ||
825 | struct dentry *dir = dn->d_parent; | ||
826 | struct inode *inode = dn->d_parent->d_inode; | ||
827 | struct ceph_dentry_info *di; | ||
828 | |||
829 | BUG_ON(!inode); | ||
830 | |||
831 | di = ceph_dentry(dn); | ||
832 | |||
833 | spin_lock(&inode->i_lock); | ||
834 | di->offset = ceph_inode(inode)->i_max_offset++; | ||
835 | spin_unlock(&inode->i_lock); | ||
836 | |||
837 | spin_lock(&dcache_lock); | ||
838 | spin_lock(&dn->d_lock); | ||
839 | list_move_tail(&dir->d_subdirs, &dn->d_u.d_child); | ||
840 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, | ||
841 | dn->d_u.d_child.prev, dn->d_u.d_child.next); | ||
842 | spin_unlock(&dn->d_lock); | ||
843 | spin_unlock(&dcache_lock); | ||
844 | } | ||
845 | |||
846 | /* | ||
820 | * Incorporate results into the local cache. This is either just | 847 | * Incorporate results into the local cache. This is either just |
821 | * one inode, or a directory, dentry, and possibly linked-to inode (e.g., | 848 | * one inode, or a directory, dentry, and possibly linked-to inode (e.g., |
822 | * after a lookup). | 849 | * after a lookup). |
@@ -987,6 +1014,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
987 | goto done; | 1014 | goto done; |
988 | } | 1015 | } |
989 | req->r_dentry = dn; /* may have spliced */ | 1016 | req->r_dentry = dn; /* may have spliced */ |
1017 | ceph_set_dentry_offset(dn); | ||
990 | igrab(in); | 1018 | igrab(in); |
991 | } else if (ceph_ino(in) == vino.ino && | 1019 | } else if (ceph_ino(in) == vino.ino && |
992 | ceph_snap(in) == vino.snap) { | 1020 | ceph_snap(in) == vino.snap) { |
@@ -1029,6 +1057,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1029 | err = PTR_ERR(dn); | 1057 | err = PTR_ERR(dn); |
1030 | goto done; | 1058 | goto done; |
1031 | } | 1059 | } |
1060 | ceph_set_dentry_offset(dn); | ||
1032 | req->r_dentry = dn; /* may have spliced */ | 1061 | req->r_dentry = dn; /* may have spliced */ |
1033 | igrab(in); | 1062 | igrab(in); |
1034 | rinfo->head->is_dentry = 1; /* fool notrace handlers */ | 1063 | rinfo->head->is_dentry = 1; /* fool notrace handlers */ |