diff options
| -rw-r--r-- | fs/ceph/dir.c | 28 | ||||
| -rw-r--r-- | fs/ceph/super.h | 13 |
2 files changed, 41 insertions, 0 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 382abc9a6a54..97fb155b3242 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -1092,7 +1092,33 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry, | |||
| 1092 | return 1; | 1092 | return 1; |
| 1093 | } | 1093 | } |
| 1094 | 1094 | ||
| 1095 | /* | ||
| 1096 | * When the VFS prunes a dentry from the cache, we need to clear the | ||
| 1097 | * complete flag on the parent directory. | ||
| 1098 | * | ||
| 1099 | * Called under dentry->d_lock. | ||
| 1100 | */ | ||
| 1101 | static void ceph_d_prune(struct dentry *dentry) | ||
| 1102 | { | ||
| 1103 | struct ceph_dentry_info *di; | ||
| 1104 | |||
| 1105 | dout("d_release %p\n", dentry); | ||
| 1106 | |||
| 1107 | /* do we have a valid parent? */ | ||
| 1108 | if (!dentry->d_parent || IS_ROOT(dentry)) | ||
| 1109 | return; | ||
| 1110 | |||
| 1111 | /* if we are not hashed, we don't affect D_COMPLETE */ | ||
| 1112 | if (d_unhashed(dentry)) | ||
| 1113 | return; | ||
| 1095 | 1114 | ||
| 1115 | /* | ||
| 1116 | * we hold d_lock, so d_parent is stable, and d_fsdata is never | ||
| 1117 | * cleared until d_release | ||
| 1118 | */ | ||
| 1119 | di = ceph_dentry(dentry->d_parent); | ||
| 1120 | clear_bit(CEPH_D_COMPLETE, &di->flags); | ||
| 1121 | } | ||
| 1096 | 1122 | ||
| 1097 | /* | 1123 | /* |
| 1098 | * read() on a dir. This weird interface hack only works if mounted | 1124 | * read() on a dir. This weird interface hack only works if mounted |
| @@ -1306,6 +1332,7 @@ const struct inode_operations ceph_dir_iops = { | |||
| 1306 | const struct dentry_operations ceph_dentry_ops = { | 1332 | const struct dentry_operations ceph_dentry_ops = { |
| 1307 | .d_revalidate = ceph_d_revalidate, | 1333 | .d_revalidate = ceph_d_revalidate, |
| 1308 | .d_release = ceph_d_release, | 1334 | .d_release = ceph_d_release, |
| 1335 | .d_prune = ceph_d_prune, | ||
| 1309 | }; | 1336 | }; |
| 1310 | 1337 | ||
| 1311 | const struct dentry_operations ceph_snapdir_dentry_ops = { | 1338 | const struct dentry_operations ceph_snapdir_dentry_ops = { |
| @@ -1315,4 +1342,5 @@ const struct dentry_operations ceph_snapdir_dentry_ops = { | |||
| 1315 | 1342 | ||
| 1316 | const struct dentry_operations ceph_snap_dentry_ops = { | 1343 | const struct dentry_operations ceph_snap_dentry_ops = { |
| 1317 | .d_release = ceph_d_release, | 1344 | .d_release = ceph_d_release, |
| 1345 | .d_prune = ceph_d_prune, | ||
| 1318 | }; | 1346 | }; |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index b01442aaf278..98e60693c9a1 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -203,6 +203,7 @@ struct ceph_inode_xattr { | |||
| 203 | * Ceph dentry state | 203 | * Ceph dentry state |
| 204 | */ | 204 | */ |
| 205 | struct ceph_dentry_info { | 205 | struct ceph_dentry_info { |
| 206 | unsigned long flags; | ||
| 206 | struct ceph_mds_session *lease_session; | 207 | struct ceph_mds_session *lease_session; |
| 207 | u32 lease_gen, lease_shared_gen; | 208 | u32 lease_gen, lease_shared_gen; |
| 208 | u32 lease_seq; | 209 | u32 lease_seq; |
| @@ -213,6 +214,18 @@ struct ceph_dentry_info { | |||
| 213 | u64 offset; | 214 | u64 offset; |
| 214 | }; | 215 | }; |
| 215 | 216 | ||
| 217 | /* | ||
| 218 | * dentry flags | ||
| 219 | * | ||
| 220 | * The locking for D_COMPLETE is a bit odd: | ||
| 221 | * - we can clear it at almost any time (see ceph_d_prune) | ||
| 222 | * - it is only meaningful if: | ||
| 223 | * - we hold dir inode i_lock | ||
| 224 | * - we hold dir FILE_SHARED caps | ||
| 225 | * - the dentry D_COMPLETE is set | ||
| 226 | */ | ||
| 227 | #define CEPH_D_COMPLETE 1 /* if set, d_u.d_subdirs is complete directory */ | ||
| 228 | |||
| 216 | struct ceph_inode_xattrs_info { | 229 | struct ceph_inode_xattrs_info { |
| 217 | /* | 230 | /* |
| 218 | * (still encoded) xattr blob. we avoid the overhead of parsing | 231 | * (still encoded) xattr blob. we avoid the overhead of parsing |
