diff options
author | Yan, Zheng <zyan@redhat.com> | 2019-01-28 07:43:55 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2019-03-05 12:55:17 -0500 |
commit | 1e9c2eb6811e8e017b589b483f6ff2b7c065eef5 (patch) | |
tree | da13ff7c0874e6872cfda880dcb48b42e1233120 /fs/ceph | |
parent | 8d9c0906acef6c281ead4e353c93d54d08c994c8 (diff) |
ceph: delete stale dentry when last reference is dropped
introduce ceph_d_delete(), which checks if dentry has valid lease.
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/dir.c | 130 | ||||
-rw-r--r-- | fs/ceph/inode.c | 2 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 2 | ||||
-rw-r--r-- | fs/ceph/super.h | 2 |
4 files changed, 104 insertions, 32 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 82928cea0209..f34a57f56c72 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -1139,45 +1139,59 @@ void ceph_invalidate_dentry_lease(struct dentry *dentry) | |||
1139 | * Check if dentry lease is valid. If not, delete the lease. Try to | 1139 | * Check if dentry lease is valid. If not, delete the lease. Try to |
1140 | * renew if the least is more than half up. | 1140 | * renew if the least is more than half up. |
1141 | */ | 1141 | */ |
1142 | static bool __dentry_lease_is_valid(struct ceph_dentry_info *di) | ||
1143 | { | ||
1144 | struct ceph_mds_session *session; | ||
1145 | |||
1146 | if (!di->lease_gen) | ||
1147 | return false; | ||
1148 | |||
1149 | session = di->lease_session; | ||
1150 | if (session) { | ||
1151 | u32 gen; | ||
1152 | unsigned long ttl; | ||
1153 | |||
1154 | spin_lock(&session->s_gen_ttl_lock); | ||
1155 | gen = session->s_cap_gen; | ||
1156 | ttl = session->s_cap_ttl; | ||
1157 | spin_unlock(&session->s_gen_ttl_lock); | ||
1158 | |||
1159 | if (di->lease_gen == gen && | ||
1160 | time_before(jiffies, ttl) && | ||
1161 | time_before(jiffies, di->time)) | ||
1162 | return true; | ||
1163 | } | ||
1164 | di->lease_gen = 0; | ||
1165 | return false; | ||
1166 | } | ||
1167 | |||
1142 | static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags, | 1168 | static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags, |
1143 | struct inode *dir) | 1169 | struct inode *dir) |
1144 | { | 1170 | { |
1145 | struct ceph_dentry_info *di; | 1171 | struct ceph_dentry_info *di; |
1146 | struct ceph_mds_session *s; | ||
1147 | int valid = 0; | ||
1148 | u32 gen; | ||
1149 | unsigned long ttl; | ||
1150 | struct ceph_mds_session *session = NULL; | 1172 | struct ceph_mds_session *session = NULL; |
1151 | u32 seq = 0; | 1173 | u32 seq = 0; |
1174 | int valid = 0; | ||
1152 | 1175 | ||
1153 | spin_lock(&dentry->d_lock); | 1176 | spin_lock(&dentry->d_lock); |
1154 | di = ceph_dentry(dentry); | 1177 | di = ceph_dentry(dentry); |
1155 | if (di && di->lease_session) { | 1178 | if (di && __dentry_lease_is_valid(di)) { |
1156 | s = di->lease_session; | 1179 | valid = 1; |
1157 | spin_lock(&s->s_gen_ttl_lock); | ||
1158 | gen = s->s_cap_gen; | ||
1159 | ttl = s->s_cap_ttl; | ||
1160 | spin_unlock(&s->s_gen_ttl_lock); | ||
1161 | 1180 | ||
1162 | if (di->lease_gen == gen && | 1181 | if (di->lease_renew_after && |
1163 | time_before(jiffies, di->time) && | 1182 | time_after(jiffies, di->lease_renew_after)) { |
1164 | time_before(jiffies, ttl)) { | 1183 | /* |
1165 | valid = 1; | 1184 | * We should renew. If we're in RCU walk mode |
1166 | if (di->lease_renew_after && | 1185 | * though, we can't do that so just return |
1167 | time_after(jiffies, di->lease_renew_after)) { | 1186 | * -ECHILD. |
1168 | /* | 1187 | */ |
1169 | * We should renew. If we're in RCU walk mode | 1188 | if (flags & LOOKUP_RCU) { |
1170 | * though, we can't do that so just return | 1189 | valid = -ECHILD; |
1171 | * -ECHILD. | 1190 | } else { |
1172 | */ | 1191 | session = ceph_get_mds_session(di->lease_session); |
1173 | if (flags & LOOKUP_RCU) { | 1192 | seq = di->lease_seq; |
1174 | valid = -ECHILD; | 1193 | di->lease_renew_after = 0; |
1175 | } else { | 1194 | di->lease_renew_from = jiffies; |
1176 | session = ceph_get_mds_session(s); | ||
1177 | seq = di->lease_seq; | ||
1178 | di->lease_renew_after = 0; | ||
1179 | di->lease_renew_from = jiffies; | ||
1180 | } | ||
1181 | } | 1195 | } |
1182 | } | 1196 | } |
1183 | } | 1197 | } |
@@ -1193,6 +1207,38 @@ static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags, | |||
1193 | } | 1207 | } |
1194 | 1208 | ||
1195 | /* | 1209 | /* |
1210 | * Called under dentry->d_lock. | ||
1211 | */ | ||
1212 | static int __dir_lease_try_check(const struct dentry *dentry) | ||
1213 | { | ||
1214 | struct ceph_dentry_info *di = ceph_dentry(dentry); | ||
1215 | struct inode *dir; | ||
1216 | struct ceph_inode_info *ci; | ||
1217 | int valid = 0; | ||
1218 | |||
1219 | if (!di->lease_shared_gen) | ||
1220 | return 0; | ||
1221 | if (IS_ROOT(dentry)) | ||
1222 | return 0; | ||
1223 | |||
1224 | dir = d_inode(dentry->d_parent); | ||
1225 | ci = ceph_inode(dir); | ||
1226 | |||
1227 | if (spin_trylock(&ci->i_ceph_lock)) { | ||
1228 | if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen && | ||
1229 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 0)) | ||
1230 | valid = 1; | ||
1231 | spin_unlock(&ci->i_ceph_lock); | ||
1232 | } else { | ||
1233 | valid = -EBUSY; | ||
1234 | } | ||
1235 | |||
1236 | if (!valid) | ||
1237 | di->lease_shared_gen = 0; | ||
1238 | return valid; | ||
1239 | } | ||
1240 | |||
1241 | /* | ||
1196 | * Check if directory-wide content lease/cap is valid. | 1242 | * Check if directory-wide content lease/cap is valid. |
1197 | */ | 1243 | */ |
1198 | static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry) | 1244 | static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry) |
@@ -1309,6 +1355,31 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) | |||
1309 | } | 1355 | } |
1310 | 1356 | ||
1311 | /* | 1357 | /* |
1358 | * Delete unused dentry that doesn't have valid lease | ||
1359 | * | ||
1360 | * Called under dentry->d_lock. | ||
1361 | */ | ||
1362 | static int ceph_d_delete(const struct dentry *dentry) | ||
1363 | { | ||
1364 | struct ceph_dentry_info *di; | ||
1365 | |||
1366 | /* won't release caps */ | ||
1367 | if (d_really_is_negative(dentry)) | ||
1368 | return 0; | ||
1369 | if (ceph_snap(d_inode(dentry)) != CEPH_NOSNAP) | ||
1370 | return 0; | ||
1371 | /* vaild lease? */ | ||
1372 | di = ceph_dentry(dentry); | ||
1373 | if (di) { | ||
1374 | if (__dentry_lease_is_valid(di)) | ||
1375 | return 0; | ||
1376 | if (__dir_lease_try_check(dentry)) | ||
1377 | return 0; | ||
1378 | } | ||
1379 | return 1; | ||
1380 | } | ||
1381 | |||
1382 | /* | ||
1312 | * Release our ceph_dentry_info. | 1383 | * Release our ceph_dentry_info. |
1313 | */ | 1384 | */ |
1314 | static void ceph_d_release(struct dentry *dentry) | 1385 | static void ceph_d_release(struct dentry *dentry) |
@@ -1531,6 +1602,7 @@ const struct inode_operations ceph_snapdir_iops = { | |||
1531 | 1602 | ||
1532 | const struct dentry_operations ceph_dentry_ops = { | 1603 | const struct dentry_operations ceph_dentry_ops = { |
1533 | .d_revalidate = ceph_d_revalidate, | 1604 | .d_revalidate = ceph_d_revalidate, |
1605 | .d_delete = ceph_d_delete, | ||
1534 | .d_release = ceph_d_release, | 1606 | .d_release = ceph_d_release, |
1535 | .d_prune = ceph_d_prune, | 1607 | .d_prune = ceph_d_prune, |
1536 | .d_init = ceph_d_init, | 1608 | .d_init = ceph_d_init, |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index f588b2d7b598..f75476e94d75 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -497,7 +497,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | |||
497 | ci->i_wrbuffer_ref = 0; | 497 | ci->i_wrbuffer_ref = 0; |
498 | ci->i_wrbuffer_ref_head = 0; | 498 | ci->i_wrbuffer_ref_head = 0; |
499 | atomic_set(&ci->i_filelock_ref, 0); | 499 | atomic_set(&ci->i_filelock_ref, 0); |
500 | atomic_set(&ci->i_shared_gen, 0); | 500 | atomic_set(&ci->i_shared_gen, 1); |
501 | ci->i_rdcache_gen = 0; | 501 | ci->i_rdcache_gen = 0; |
502 | ci->i_rdcache_revoking = 0; | 502 | ci->i_rdcache_revoking = 0; |
503 | 503 | ||
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index c9d4561336fc..99d6e805668c 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -621,7 +621,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, | |||
621 | ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr); | 621 | ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr); |
622 | 622 | ||
623 | spin_lock_init(&s->s_gen_ttl_lock); | 623 | spin_lock_init(&s->s_gen_ttl_lock); |
624 | s->s_cap_gen = 0; | 624 | s->s_cap_gen = 1; |
625 | s->s_cap_ttl = jiffies - 1; | 625 | s->s_cap_ttl = jiffies - 1; |
626 | 626 | ||
627 | spin_lock_init(&s->s_cap_lock); | 627 | spin_lock_init(&s->s_cap_lock); |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c4a79eadc55a..c0654e613fc0 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -594,7 +594,7 @@ extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v, | |||
594 | struct ceph_inode_frag *pfrag, | 594 | struct ceph_inode_frag *pfrag, |
595 | int *found); | 595 | int *found); |
596 | 596 | ||
597 | static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry) | 597 | static inline struct ceph_dentry_info *ceph_dentry(const struct dentry *dentry) |
598 | { | 598 | { |
599 | return (struct ceph_dentry_info *)dentry->d_fsdata; | 599 | return (struct ceph_dentry_info *)dentry->d_fsdata; |
600 | } | 600 | } |