diff options
| author | Sage Weil <sage@newdream.net> | 2010-05-04 01:08:02 -0400 |
|---|---|---|
| committer | Sage Weil <sage@newdream.net> | 2010-05-17 18:25:28 -0400 |
| commit | 1cd3935bedccf592d44343890251452a6dd74fc4 (patch) | |
| tree | b088e425d19dbca7d7702e9f1bfa0b2dfa85eba0 | |
| parent | 1b7facc41b42c2ab904b2f88b64b1f8ca0ca6cb7 (diff) | |
ceph: set dn offset when spliced
We want to assign an offset when the dentry goes from null to linked, which
is always done by splice_dentry(). Notably, we should NOT assign an
offset when a dentry is first created and is still null.
BUG if we try to splice a non-null dentry (we shouldn't).
Signed-off-by: Sage Weil <sage@newdream.net>
| -rw-r--r-- | fs/ceph/dir.c | 13 | ||||
| -rw-r--r-- | fs/ceph/inode.c | 71 |
2 files changed, 44 insertions, 40 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 0b0a39d05ca6..d3bb8132a1aa 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -128,7 +128,8 @@ more: | |||
| 128 | dentry = list_entry(p, struct dentry, d_u.d_child); | 128 | dentry = list_entry(p, struct dentry, d_u.d_child); |
| 129 | di = ceph_dentry(dentry); | 129 | di = ceph_dentry(dentry); |
| 130 | while (1) { | 130 | while (1) { |
| 131 | dout(" p %p/%p d_subdirs %p/%p\n", p->prev, p->next, | 131 | dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next, |
| 132 | d_unhashed(dentry) ? "!hashed" : "hashed", | ||
| 132 | parent->d_subdirs.prev, parent->d_subdirs.next); | 133 | parent->d_subdirs.prev, parent->d_subdirs.next); |
| 133 | if (p == &parent->d_subdirs) { | 134 | if (p == &parent->d_subdirs) { |
| 134 | fi->at_end = 1; | 135 | fi->at_end = 1; |
| @@ -571,7 +572,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, | |||
| 571 | !is_root_ceph_dentry(dir, dentry) && | 572 | !is_root_ceph_dentry(dir, dentry) && |
| 572 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && | 573 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && |
| 573 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { | 574 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { |
| 574 | di->offset = ci->i_max_offset++; | ||
| 575 | spin_unlock(&dir->i_lock); | 575 | spin_unlock(&dir->i_lock); |
| 576 | dout(" dir %p complete, -ENOENT\n", dir); | 576 | dout(" dir %p complete, -ENOENT\n", dir); |
| 577 | d_add(dentry, NULL); | 577 | d_add(dentry, NULL); |
| @@ -984,8 +984,9 @@ static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 984 | { | 984 | { |
| 985 | struct inode *dir = dentry->d_parent->d_inode; | 985 | struct inode *dir = dentry->d_parent->d_inode; |
| 986 | 986 | ||
| 987 | dout("d_revalidate %p '%.*s' inode %p\n", dentry, | 987 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, |
| 988 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | 988 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, |
| 989 | ceph_dentry(dentry)->offset); | ||
| 989 | 990 | ||
| 990 | /* always trust cached snapped dentries, snapdir dentry */ | 991 | /* always trust cached snapped dentries, snapdir dentry */ |
| 991 | if (ceph_snap(dir) != CEPH_NOSNAP) { | 992 | if (ceph_snap(dir) != CEPH_NOSNAP) { |
| @@ -1177,8 +1178,8 @@ void ceph_dentry_lru_touch(struct dentry *dn) | |||
| 1177 | struct ceph_dentry_info *di = ceph_dentry(dn); | 1178 | struct ceph_dentry_info *di = ceph_dentry(dn); |
| 1178 | struct ceph_mds_client *mdsc; | 1179 | struct ceph_mds_client *mdsc; |
| 1179 | 1180 | ||
| 1180 | dout("dentry_lru_touch %p %p '%.*s'\n", di, dn, | 1181 | dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn, |
| 1181 | dn->d_name.len, dn->d_name.name); | 1182 | dn->d_name.len, dn->d_name.name, di->offset); |
| 1182 | if (di) { | 1183 | if (di) { |
| 1183 | mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc; | 1184 | mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc; |
| 1184 | spin_lock(&mdsc->dentry_lru_lock); | 1185 | spin_lock(&mdsc->dentry_lru_lock); |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index aa22a0bce52f..1bcf98bd0255 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
| @@ -804,6 +804,37 @@ out_unlock: | |||
| 804 | } | 804 | } |
| 805 | 805 | ||
| 806 | /* | 806 | /* |
| 807 | * Set dentry's directory position based on the current dir's max, and | ||
| 808 | * order it in d_subdirs, so that dcache_readdir behaves. | ||
| 809 | */ | ||
| 810 | static void ceph_set_dentry_offset(struct dentry *dn) | ||
| 811 | { | ||
| 812 | struct dentry *dir = dn->d_parent; | ||
| 813 | struct inode *inode = dn->d_parent->d_inode; | ||
| 814 | struct ceph_dentry_info *di; | ||
| 815 | |||
| 816 | BUG_ON(!inode); | ||
| 817 | |||
| 818 | di = ceph_dentry(dn); | ||
| 819 | |||
| 820 | spin_lock(&inode->i_lock); | ||
| 821 | if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) { | ||
| 822 | spin_unlock(&inode->i_lock); | ||
| 823 | return; | ||
| 824 | } | ||
| 825 | di->offset = ceph_inode(inode)->i_max_offset++; | ||
| 826 | spin_unlock(&inode->i_lock); | ||
| 827 | |||
| 828 | spin_lock(&dcache_lock); | ||
| 829 | spin_lock(&dn->d_lock); | ||
| 830 | list_move_tail(&dir->d_subdirs, &dn->d_u.d_child); | ||
| 831 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, | ||
| 832 | dn->d_u.d_child.prev, dn->d_u.d_child.next); | ||
| 833 | spin_unlock(&dn->d_lock); | ||
| 834 | spin_unlock(&dcache_lock); | ||
| 835 | } | ||
| 836 | |||
| 837 | /* | ||
| 807 | * splice a dentry to an inode. | 838 | * splice a dentry to an inode. |
| 808 | * caller must hold directory i_mutex for this to be safe. | 839 | * caller must hold directory i_mutex for this to be safe. |
| 809 | * | 840 | * |
| @@ -816,6 +847,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | |||
| 816 | { | 847 | { |
| 817 | struct dentry *realdn; | 848 | struct dentry *realdn; |
| 818 | 849 | ||
| 850 | BUG_ON(dn->d_inode); | ||
| 851 | |||
| 819 | /* dn must be unhashed */ | 852 | /* dn must be unhashed */ |
| 820 | if (!d_unhashed(dn)) | 853 | if (!d_unhashed(dn)) |
| 821 | d_drop(dn); | 854 | d_drop(dn); |
| @@ -837,48 +870,17 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | |||
| 837 | dn = realdn; | 870 | dn = realdn; |
| 838 | } else { | 871 | } else { |
| 839 | BUG_ON(!ceph_dentry(dn)); | 872 | BUG_ON(!ceph_dentry(dn)); |
| 840 | |||
| 841 | dout("dn %p attached to %p ino %llx.%llx\n", | 873 | dout("dn %p attached to %p ino %llx.%llx\n", |
| 842 | dn, dn->d_inode, ceph_vinop(dn->d_inode)); | 874 | dn, dn->d_inode, ceph_vinop(dn->d_inode)); |
| 843 | } | 875 | } |
| 844 | if ((!prehash || *prehash) && d_unhashed(dn)) | 876 | if ((!prehash || *prehash) && d_unhashed(dn)) |
| 845 | d_rehash(dn); | 877 | d_rehash(dn); |
| 878 | ceph_set_dentry_offset(dn); | ||
| 846 | out: | 879 | out: |
| 847 | return dn; | 880 | return dn; |
| 848 | } | 881 | } |
| 849 | 882 | ||
| 850 | /* | 883 | /* |
| 851 | * Set dentry's directory position based on the current dir's max, and | ||
| 852 | * order it in d_subdirs, so that dcache_readdir behaves. | ||
| 853 | */ | ||
| 854 | static void ceph_set_dentry_offset(struct dentry *dn) | ||
| 855 | { | ||
| 856 | struct dentry *dir = dn->d_parent; | ||
| 857 | struct inode *inode = dn->d_parent->d_inode; | ||
| 858 | struct ceph_dentry_info *di; | ||
| 859 | |||
| 860 | BUG_ON(!inode); | ||
| 861 | |||
| 862 | di = ceph_dentry(dn); | ||
| 863 | |||
| 864 | spin_lock(&inode->i_lock); | ||
| 865 | if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) { | ||
| 866 | spin_unlock(&inode->i_lock); | ||
| 867 | return; | ||
| 868 | } | ||
| 869 | di->offset = ceph_inode(inode)->i_max_offset++; | ||
| 870 | spin_unlock(&inode->i_lock); | ||
| 871 | |||
| 872 | spin_lock(&dcache_lock); | ||
| 873 | spin_lock(&dn->d_lock); | ||
| 874 | list_move_tail(&dir->d_subdirs, &dn->d_u.d_child); | ||
| 875 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, | ||
| 876 | dn->d_u.d_child.prev, dn->d_u.d_child.next); | ||
| 877 | spin_unlock(&dn->d_lock); | ||
| 878 | spin_unlock(&dcache_lock); | ||
| 879 | } | ||
| 880 | |||
| 881 | /* | ||
| 882 | * Incorporate results into the local cache. This is either just | 884 | * Incorporate results into the local cache. This is either just |
| 883 | * one inode, or a directory, dentry, and possibly linked-to inode (e.g., | 885 | * one inode, or a directory, dentry, and possibly linked-to inode (e.g., |
| 884 | * after a lookup). | 886 | * after a lookup). |
| @@ -1030,6 +1032,9 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 1030 | ceph_invalidate_dentry_lease(dn); | 1032 | ceph_invalidate_dentry_lease(dn); |
| 1031 | 1033 | ||
| 1032 | /* take overwritten dentry's readdir offset */ | 1034 | /* take overwritten dentry's readdir offset */ |
| 1035 | dout("dn %p gets %p offset %lld (old offset %lld)\n", | ||
| 1036 | req->r_old_dentry, dn, ceph_dentry(dn)->offset, | ||
| 1037 | ceph_dentry(req->r_old_dentry)->offset); | ||
| 1033 | ceph_dentry(req->r_old_dentry)->offset = | 1038 | ceph_dentry(req->r_old_dentry)->offset = |
| 1034 | ceph_dentry(dn)->offset; | 1039 | ceph_dentry(dn)->offset; |
| 1035 | 1040 | ||
| @@ -1074,7 +1079,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 1074 | goto done; | 1079 | goto done; |
| 1075 | } | 1080 | } |
| 1076 | req->r_dentry = dn; /* may have spliced */ | 1081 | req->r_dentry = dn; /* may have spliced */ |
| 1077 | ceph_set_dentry_offset(dn); | ||
| 1078 | igrab(in); | 1082 | igrab(in); |
| 1079 | } else if (ceph_ino(in) == vino.ino && | 1083 | } else if (ceph_ino(in) == vino.ino && |
| 1080 | ceph_snap(in) == vino.snap) { | 1084 | ceph_snap(in) == vino.snap) { |
| @@ -1117,7 +1121,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 1117 | err = PTR_ERR(dn); | 1121 | err = PTR_ERR(dn); |
| 1118 | goto done; | 1122 | goto done; |
| 1119 | } | 1123 | } |
| 1120 | ceph_set_dentry_offset(dn); | ||
| 1121 | req->r_dentry = dn; /* may have spliced */ | 1124 | req->r_dentry = dn; /* may have spliced */ |
| 1122 | igrab(in); | 1125 | igrab(in); |
| 1123 | rinfo->head->is_dentry = 1; /* fool notrace handlers */ | 1126 | rinfo->head->is_dentry = 1; /* fool notrace handlers */ |
