diff mbox series

ceph: wake waiters after failed async create

Message ID 20220208194648.190652-1-jlayton@kernel.org
State New
Headers show
Series ceph: wake waiters after failed async create | expand

Commit Message

Jeff Layton Feb. 8, 2022, 7:46 p.m. UTC
Currently, we only wake the waiters if we got a req->r_target_inode
out of the reply. In the case where the create fails though, we may not
have one.

If there is a non-zero result from the create, then ensure that we wake
anything waiting on the inode after we shut it down.

URL: https://tracker.ceph.com/issues/54067
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/ceph/file.c | 51 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 18 deletions(-)

Comments

Xiubo Li Feb. 9, 2022, 11:57 a.m. UTC | #1
On 2/9/22 3:46 AM, Jeff Layton wrote:
> Currently, we only wake the waiters if we got a req->r_target_inode
> out of the reply. In the case where the create fails though, we may not
> have one.
>
> If there is a non-zero result from the create, then ensure that we wake
> anything waiting on the inode after we shut it down.
>
> URL: https://tracker.ceph.com/issues/54067
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>   fs/ceph/file.c | 51 ++++++++++++++++++++++++++++++++------------------
>   1 file changed, 33 insertions(+), 18 deletions(-)
>
> diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> index 22ca724aef36..feb75eb1cd82 100644
> --- a/fs/ceph/file.c
> +++ b/fs/ceph/file.c
> @@ -532,52 +532,67 @@ static void restore_deleg_ino(struct inode *dir, u64 ino)
>   	}
>   }
>   
> +static void wake_async_create_waiters(struct inode *inode,
> +				      struct ceph_mds_session *session)
> +{
> +	struct ceph_inode_info *ci = ceph_inode(inode);
> +
> +	spin_lock(&ci->i_ceph_lock);
> +	if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
> +		ci->i_ceph_flags &= ~CEPH_I_ASYNC_CREATE;
> +		wake_up_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT);
> +	}
> +	ceph_kick_flushing_inode_caps(session, ci);
> +	spin_unlock(&ci->i_ceph_lock);
> +}
> +
>   static void ceph_async_create_cb(struct ceph_mds_client *mdsc,
>                                    struct ceph_mds_request *req)
>   {
> +	struct dentry *dentry = req->r_dentry;
> +	struct inode *dinode = d_inode(dentry);
> +	struct inode *tinode = req->r_target_inode;
>   	int result = req->r_err ? req->r_err :
>   			le32_to_cpu(req->r_reply_info.head->result);
>   
> +	WARN_ON_ONCE(dinode && tinode && dinode != tinode);
> +
> +	/* MDS changed -- caller must resubmit */
>   	if (result == -EJUKEBOX)
>   		goto out;
>   
>   	mapping_set_error(req->r_parent->i_mapping, result);
>   
>   	if (result) {
> -		struct dentry *dentry = req->r_dentry;
> -		struct inode *inode = d_inode(dentry);
>   		int pathlen = 0;
>   		u64 base = 0;
>   		char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
>   						  &base, 0);
>   
> +		pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n",
> +			base, IS_ERR(path) ? "<<bad>>" : path, result);
> +		ceph_mdsc_free_path(path, pathlen);
> +
>   		ceph_dir_clear_complete(req->r_parent);
>   		if (!d_unhashed(dentry))
>   			d_drop(dentry);
>   
> -		ceph_inode_shutdown(inode);
> -
> -		pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n",
> -			base, IS_ERR(path) ? "<<bad>>" : path, result);
> -		ceph_mdsc_free_path(path, pathlen);
> +		if (dinode) {
> +			mapping_set_error(dinode->i_mapping, result);
> +			ceph_inode_shutdown(dinode);
> +			wake_async_create_waiters(dinode, req->r_session);
> +		}
>   	}
>   
> -	if (req->r_target_inode) {
> -		struct ceph_inode_info *ci = ceph_inode(req->r_target_inode);
> -		u64 ino = ceph_vino(req->r_target_inode).ino;
> +	if (tinode) {
> +		u64 ino = ceph_vino(tinode).ino;
>   
>   		if (req->r_deleg_ino != ino)
>   			pr_warn("%s: inode number mismatch! err=%d deleg_ino=0x%llx target=0x%llx\n",
>   				__func__, req->r_err, req->r_deleg_ino, ino);
> -		mapping_set_error(req->r_target_inode->i_mapping, result);
>   
> -		spin_lock(&ci->i_ceph_lock);
> -		if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
> -			ci->i_ceph_flags &= ~CEPH_I_ASYNC_CREATE;
> -			wake_up_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT);
> -		}
> -		ceph_kick_flushing_inode_caps(req->r_session, ci);
> -		spin_unlock(&ci->i_ceph_lock);
> +		mapping_set_error(tinode->i_mapping, result);
> +		wake_async_create_waiters(tinode, req->r_session);
>   	} else if (!result) {
>   		pr_warn("%s: no req->r_target_inode for 0x%llx\n", __func__,
>   			req->r_deleg_ino);

LGTM.

Reviewed-by: Xiubo Li <xiubli@redhat.com>
diff mbox series

Patch

diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 22ca724aef36..feb75eb1cd82 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -532,52 +532,67 @@  static void restore_deleg_ino(struct inode *dir, u64 ino)
 	}
 }
 
+static void wake_async_create_waiters(struct inode *inode,
+				      struct ceph_mds_session *session)
+{
+	struct ceph_inode_info *ci = ceph_inode(inode);
+
+	spin_lock(&ci->i_ceph_lock);
+	if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
+		ci->i_ceph_flags &= ~CEPH_I_ASYNC_CREATE;
+		wake_up_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT);
+	}
+	ceph_kick_flushing_inode_caps(session, ci);
+	spin_unlock(&ci->i_ceph_lock);
+}
+
 static void ceph_async_create_cb(struct ceph_mds_client *mdsc,
                                  struct ceph_mds_request *req)
 {
+	struct dentry *dentry = req->r_dentry;
+	struct inode *dinode = d_inode(dentry);
+	struct inode *tinode = req->r_target_inode;
 	int result = req->r_err ? req->r_err :
 			le32_to_cpu(req->r_reply_info.head->result);
 
+	WARN_ON_ONCE(dinode && tinode && dinode != tinode);
+
+	/* MDS changed -- caller must resubmit */
 	if (result == -EJUKEBOX)
 		goto out;
 
 	mapping_set_error(req->r_parent->i_mapping, result);
 
 	if (result) {
-		struct dentry *dentry = req->r_dentry;
-		struct inode *inode = d_inode(dentry);
 		int pathlen = 0;
 		u64 base = 0;
 		char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
 						  &base, 0);
 
+		pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n",
+			base, IS_ERR(path) ? "<<bad>>" : path, result);
+		ceph_mdsc_free_path(path, pathlen);
+
 		ceph_dir_clear_complete(req->r_parent);
 		if (!d_unhashed(dentry))
 			d_drop(dentry);
 
-		ceph_inode_shutdown(inode);
-
-		pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n",
-			base, IS_ERR(path) ? "<<bad>>" : path, result);
-		ceph_mdsc_free_path(path, pathlen);
+		if (dinode) {
+			mapping_set_error(dinode->i_mapping, result);
+			ceph_inode_shutdown(dinode);
+			wake_async_create_waiters(dinode, req->r_session);
+		}
 	}
 
-	if (req->r_target_inode) {
-		struct ceph_inode_info *ci = ceph_inode(req->r_target_inode);
-		u64 ino = ceph_vino(req->r_target_inode).ino;
+	if (tinode) {
+		u64 ino = ceph_vino(tinode).ino;
 
 		if (req->r_deleg_ino != ino)
 			pr_warn("%s: inode number mismatch! err=%d deleg_ino=0x%llx target=0x%llx\n",
 				__func__, req->r_err, req->r_deleg_ino, ino);
-		mapping_set_error(req->r_target_inode->i_mapping, result);
 
-		spin_lock(&ci->i_ceph_lock);
-		if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
-			ci->i_ceph_flags &= ~CEPH_I_ASYNC_CREATE;
-			wake_up_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT);
-		}
-		ceph_kick_flushing_inode_caps(req->r_session, ci);
-		spin_unlock(&ci->i_ceph_lock);
+		mapping_set_error(tinode->i_mapping, result);
+		wake_async_create_waiters(tinode, req->r_session);
 	} else if (!result) {
 		pr_warn("%s: no req->r_target_inode for 0x%llx\n", __func__,
 			req->r_deleg_ino);