diff mbox series

[5/8] ceph: fix dir_lease_is_valid()

Message ID 20190523081345.20410-5-zyan@redhat.com (mailing list archive)
State New, archived
Headers show
Series [1/8] ceph: fix error handling in ceph_get_caps() | expand

Commit Message

Yan, Zheng May 23, 2019, 8:13 a.m. UTC
It should call __ceph_dentry_dir_lease_touch() under dentry->d_lock.
Besides, ceph_dentry(dentry) can be NULL when called by LOOKUP_RCU
d_revalidate()

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
---
 fs/ceph/dir.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

Comments

Jeff Layton May 28, 2019, 1:52 p.m. UTC | #1
On Thu, 2019-05-23 at 16:13 +0800, Yan, Zheng wrote:
> It should call __ceph_dentry_dir_lease_touch() under dentry->d_lock.
> Besides, ceph_dentry(dentry) can be NULL when called by LOOKUP_RCU
> d_revalidate()
> 
> Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
> ---
>  fs/ceph/dir.c | 26 +++++++++++++++++---------
>  1 file changed, 17 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
> index 0637149fb9f9..1271024a3797 100644
> --- a/fs/ceph/dir.c
> +++ b/fs/ceph/dir.c
> @@ -1512,18 +1512,26 @@ static int __dir_lease_try_check(const struct dentry *dentry)
>  static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
>  {
>  	struct ceph_inode_info *ci = ceph_inode(dir);
> -	struct ceph_dentry_info *di = ceph_dentry(dentry);
> -	int valid = 0;
> +	int valid;
> +	int shared_gen;
>  
>  	spin_lock(&ci->i_ceph_lock);
> -	if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen)
> -		valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
> +	valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
> +	shared_gen = atomic_read(&ci->i_shared_gen);
>  	spin_unlock(&ci->i_ceph_lock);
> -	if (valid)
> -		__ceph_dentry_dir_lease_touch(di);
> -	dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
> -	     dir, (unsigned)atomic_read(&ci->i_shared_gen),
> -	     dentry, (unsigned)di->lease_shared_gen, valid);
> +	if (valid) {
> +		struct ceph_dentry_info *di;
> +		spin_lock(&dentry->d_lock);
> +		di = ceph_dentry(dentry);
> +		if (dir == d_inode(dentry->d_parent) &&
> +		    di && di->lease_shared_gen == shared_gen)
> +			__ceph_dentry_dir_lease_touch(di);
> +		else
> +			valid = 0;
> +		spin_unlock(&dentry->d_lock);
> +	}
> +	dout("dir_lease_is_valid dir %p v%u dentry %p = %d\n",
> +	     dir, (unsigned)atomic_read(&ci->i_shared_gen), dentry, valid);
>  	return valid;
>  }
>  

Reviewed-by: Jeff Layton <jlayton@redhat.com>
diff mbox series

Patch

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 0637149fb9f9..1271024a3797 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1512,18 +1512,26 @@  static int __dir_lease_try_check(const struct dentry *dentry)
 static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
 {
 	struct ceph_inode_info *ci = ceph_inode(dir);
-	struct ceph_dentry_info *di = ceph_dentry(dentry);
-	int valid = 0;
+	int valid;
+	int shared_gen;
 
 	spin_lock(&ci->i_ceph_lock);
-	if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen)
-		valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
+	valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
+	shared_gen = atomic_read(&ci->i_shared_gen);
 	spin_unlock(&ci->i_ceph_lock);
-	if (valid)
-		__ceph_dentry_dir_lease_touch(di);
-	dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
-	     dir, (unsigned)atomic_read(&ci->i_shared_gen),
-	     dentry, (unsigned)di->lease_shared_gen, valid);
+	if (valid) {
+		struct ceph_dentry_info *di;
+		spin_lock(&dentry->d_lock);
+		di = ceph_dentry(dentry);
+		if (dir == d_inode(dentry->d_parent) &&
+		    di && di->lease_shared_gen == shared_gen)
+			__ceph_dentry_dir_lease_touch(di);
+		else
+			valid = 0;
+		spin_unlock(&dentry->d_lock);
+	}
+	dout("dir_lease_is_valid dir %p v%u dentry %p = %d\n",
+	     dir, (unsigned)atomic_read(&ci->i_shared_gen), dentry, valid);
 	return valid;
 }