Browse Source

ceph: check inode caps in ceph_d_revalidate

Some inodes in readdir reply may have no caps. Getattr mds request
for these inodes can return -ESTALE. The fix is consider dentry that
links to inode with no caps as invalid. Invalid dentry causes a
lookup request to send to the mds, the MDS will send caps back.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Yan, Zheng 11 years ago
parent
commit
9215aeea62
3 changed files with 21 additions and 3 deletions
  1. 12 0
      fs/ceph/caps.c
  2. 8 3
      fs/ceph/dir.c
  3. 1 0
      fs/ceph/super.h

+ 12 - 0
fs/ceph/caps.c

@@ -891,6 +891,18 @@ static int __ceph_is_any_caps(struct ceph_inode_info *ci)
 	return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_mds >= 0;
 	return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_mds >= 0;
 }
 }
 
 
+int ceph_is_any_caps(struct inode *inode)
+{
+	struct ceph_inode_info *ci = ceph_inode(inode);
+	int ret;
+
+	spin_lock(&ci->i_ceph_lock);
+	ret = __ceph_is_any_caps(ci);
+	spin_unlock(&ci->i_ceph_lock);
+
+	return ret;
+}
+
 /*
 /*
  * Remove a cap.  Take steps to deal with a racing iterate_session_caps.
  * Remove a cap.  Take steps to deal with a racing iterate_session_caps.
  *
  *

+ 8 - 3
fs/ceph/dir.c

@@ -1041,14 +1041,19 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
 		valid = 1;
 		valid = 1;
 	} else if (dentry_lease_is_valid(dentry) ||
 	} else if (dentry_lease_is_valid(dentry) ||
 		   dir_lease_is_valid(dir, dentry)) {
 		   dir_lease_is_valid(dir, dentry)) {
-		valid = 1;
+		if (dentry->d_inode)
+			valid = ceph_is_any_caps(dentry->d_inode);
+		else
+			valid = 1;
 	}
 	}
 
 
 	dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
 	dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
-	if (valid)
+	if (valid) {
 		ceph_dentry_lru_touch(dentry);
 		ceph_dentry_lru_touch(dentry);
-	else
+	} else {
+		ceph_dir_clear_complete(dir);
 		d_drop(dentry);
 		d_drop(dentry);
+	}
 	iput(dir);
 	iput(dir);
 	return valid;
 	return valid;
 }
 }

+ 1 - 0
fs/ceph/super.h

@@ -782,6 +782,7 @@ extern int ceph_add_cap(struct inode *inode,
 extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
 extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
 extern void ceph_put_cap(struct ceph_mds_client *mdsc,
 extern void ceph_put_cap(struct ceph_mds_client *mdsc,
 			 struct ceph_cap *cap);
 			 struct ceph_cap *cap);
+extern int ceph_is_any_caps(struct inode *inode);
 
 
 extern void __queue_cap_release(struct ceph_mds_session *session, u64 ino,
 extern void __queue_cap_release(struct ceph_mds_session *session, u64 ino,
 				u64 cap_id, u32 migrate_seq, u32 issue_seq);
 				u64 cap_id, u32 migrate_seq, u32 issue_seq);