aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2019-01-28 07:43:55 -0500
committerIlya Dryomov <idryomov@gmail.com>2019-03-05 12:55:17 -0500
commit1e9c2eb6811e8e017b589b483f6ff2b7c065eef5 (patch)
treeda13ff7c0874e6872cfda880dcb48b42e1233120 /fs/ceph
parent8d9c0906acef6c281ead4e353c93d54d08c994c8 (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.c130
-rw-r--r--fs/ceph/inode.c2
-rw-r--r--fs/ceph/mds_client.c2
-rw-r--r--fs/ceph/super.h2
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 */
1142static 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
1142static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags, 1168static 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 */
1212static 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 */
1198static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry) 1244static 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 */
1362static 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 */
1314static void ceph_d_release(struct dentry *dentry) 1385static void ceph_d_release(struct dentry *dentry)
@@ -1531,6 +1602,7 @@ const struct inode_operations ceph_snapdir_iops = {
1531 1602
1532const struct dentry_operations ceph_dentry_ops = { 1603const 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
597static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry) 597static 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}