diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 2de64c23383b..8a3b03e36e3c 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -801,6 +801,7 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, void ll_finish_md_op_data(struct md_op_data *op_data); int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg); char *ll_get_fsname(struct super_block *sb, char *buf, int buflen); +void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req); /* llite/llite_nfs.c */ extern struct export_operations lustre_export_operations; diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index c60eb46e9c7e..725481d3916e 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1973,6 +1973,47 @@ int ll_remount_fs(struct super_block *sb, int *flags, char *data) return 0; } +/** + * Cleanup the open handle that is cached on MDT-side. + * + * For open case, the client side open handling thread may hit error + * after the MDT grant the open. Under such case, the client should + * send close RPC to the MDT as cleanup; otherwise, the open handle + * on the MDT will be leaked there until the client umount or evicted. + * + * In further, if someone unlinked the file, because the open handle + * holds the reference on such file/object, then it will block the + * subsequent threads that want to locate such object via FID. + * + * \param[in] sb super block for this file-system + * \param[in] open_req pointer to the original open request + */ +void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req) +{ + struct mdt_body *body; + struct md_op_data *op_data; + struct ptlrpc_request *close_req = NULL; + struct obd_export *exp = ll_s2sbi(sb)->ll_md_exp; + + body = req_capsule_server_get(&open_req->rq_pill, &RMF_MDT_BODY); + OBD_ALLOC_PTR(op_data); + if (!op_data) { + CWARN("%s: cannot allocate op_data to release open handle for " + DFID "\n", + ll_get_fsname(sb, NULL, 0), PFID(&body->fid1)); + + return; + } + + op_data->op_fid1 = body->fid1; + op_data->op_ioepoch = body->ioepoch; + op_data->op_handle = body->handle; + op_data->op_mod_time = get_seconds(); + md_close(exp, op_data, NULL, &close_req); + ptlrpc_req_finished(close_req); + ll_finish_md_op_data(op_data); +} + int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, struct super_block *sb, struct lookup_intent *it) { @@ -1985,7 +2026,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp, sbi->ll_md_exp, &md); if (rc) - return rc; + goto cleanup; if (*inode) { ll_update_inode(*inode, &md); @@ -2047,6 +2088,11 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, if (md.lsm != NULL) obd_free_memmd(sbi->ll_dt_exp, &md.lsm); md_free_lustre_md(sbi->ll_md_exp, &md); + +cleanup: + if (rc != 0 && it && it->it_op & IT_OPEN) + ll_open_cleanup(sb ? sb : (*inode)->i_sb, req); + return rc; } diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 05e7dc85989e..2635678e3d60 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -409,7 +409,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, { struct inode *inode = NULL; __u64 bits = 0; - int rc; + int rc = 0; /* NB 1 request reference will be taken away by ll_intent_lock() * when I return */ @@ -439,8 +439,10 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, struct dentry *alias; alias = ll_splice_alias(inode, *de); - if (IS_ERR(alias)) - return PTR_ERR(alias); + if (IS_ERR(alias)) { + rc = PTR_ERR(alias); + goto out; + } *de = alias; } else if (!it_disposition(it, DISP_LOOKUP_NEG) && !it_disposition(it, DISP_OPEN_CREATE)) { @@ -471,7 +473,11 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, } } - return 0; +out: + if (rc != 0 && it->it_op & IT_OPEN) + ll_open_cleanup((*de)->d_sb, request); + + return rc; } static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,